@mearl/native-host 3.0.0-beta.2 → 3.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ ${bytes.toString("utf8")}
17
17
  `);return}if(!isProviderActionRequest(parsed)){socket.end(`${JSON.stringify({id:id2,success:!1,error:"Invalid request envelope"})}
18
18
  `);return}let request=parsed;dispatch(request).then(data2=>socket.end(`${JSON.stringify({id:request.id,success:!0,data:data2})}
19
19
  `)).catch(error62=>socket.end(`${JSON.stringify({id:request.id,success:!1,error:errorMessage(error62)})}
20
- `))})}return{socketPath,runtime,async start(){if(state!=="idle")throw new Error(`Provider server is already ${state}`);let providerId=descriptor.providerId;if(activeProviderIds.has(providerId))throw new Error(`Provider ${providerId} is already running in this process`);state="starting",activeProviderIds.add(providerId);let startToken=process.env[PROVIDER_START_TOKEN_ENV]||randomUUID6(),existing=readLiveProvider(descriptor.providerId);if(existing)throw state="idle",activeProviderIds.delete(providerId),new Error(`Provider ${descriptor.providerId} is already running (pid ${existing.pid})`);if(!claimProviderStart(providerId,startToken))throw state="idle",activeProviderIds.delete(providerId),new Error(`Provider ${providerId} start is already in progress`);try{let competing=readLiveProvider(providerId);if(competing)throw new Error(`Provider ${providerId} is already running (pid ${competing.pid})`);removeStaleProviderSocket(providerId,socketPath),process.platform!=="win32"&&ensureDir(dirname3(socketPath)),server=net.createServer(handleConnection),await new Promise((resolve16,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.off("error",reject),resolve16()})}),process.platform!=="win32"&&chmodSync(socketPath,384),publishLiveProvider(descriptor,socketPath),releaseProviderStart(providerId,startToken),state="running"}catch(error62){let active=server;server=null;for(let connection of connections)connection.destroy();throw connections.clear(),active?.listening&&await new Promise(resolve16=>active.close(()=>resolve16())),unpublishLiveProvider(providerId),process.platform!=="win32"&&rmSync4(socketPath,{force:!0}),releaseProviderStart(providerId,startToken),activeProviderIds.delete(providerId),state="idle",error62}},updateBrowsers(nextBrowsers){if(state!=="running")throw new Error("Provider server is not running");runtime.updateBrowsers(nextBrowsers),browsers=[...nextBrowsers],browserIds=publishProviderBrowsers(descriptor,socketPath,browsers,browserIds)},touchBrowser(browserId){if(state!=="running")throw new Error("Provider server is not running");if(!browsers.some(browser=>browser.browserId===browserId))throw new Error(`Provider browser not found: ${browserId}`);touchProviderBrowser(providerBrowserKey(descriptor.providerId,browserId))},async stop(){if(state!=="idle"){if(state==="starting")throw new Error("Provider server is still starting");return state==="stopping"&&stopPromise||(state="stopping",stopPromise=(async()=>{let active=server;server=null;for(let connection of connections)connection.destroy();connections.clear(),active&&await new Promise(resolve16=>active.close(()=>resolve16())),unpublishProviderBrowsers(browserIds),browserIds.clear(),browsers=[],process.platform!=="win32"&&rmSync4(socketPath,{force:!0}),unpublishLiveProvider(descriptor.providerId)})().finally(()=>{activeProviderIds.delete(descriptor.providerId),stopPromise=null,state="idle"})),stopPromise}}}}var MAX_REQUEST_BYTES,activeProviderIds,init_server=__esm({"../provider/dist/server.js"(){"use strict";init_dist();init_actions();init_provider_runtime();init_registry2();init_types();init_protocol();MAX_REQUEST_BYTES=16*1024*1024,activeProviderIds=new Set}});var dist_exports3={};__export(dist_exports3,{MEARL_PROVIDER_PROTOCOL_VERSION:()=>MEARL_PROVIDER_PROTOCOL_VERSION,PROVIDER_ACTIONS:()=>PROVIDER_ACTIONS,assertProviderProtocolVersion:()=>assertProviderProtocolVersion,createProviderRuntime:()=>createProviderRuntime,createProviderServer:()=>createProviderServer,isProviderAction:()=>isProviderAction,providerDataDir:()=>providerDataDir,validateProviderBrowser:()=>validateProviderBrowser,validateProviderInput:()=>validateProviderInput,validateProviderLaunchForm:()=>validateProviderLaunchForm});var init_dist4=__esm({"../provider/dist/index.js"(){"use strict";init_types();init_protocol();init_actions();init_registry2();init_provider_runtime();init_server()}});import fs2 from"node:fs";import path3 from"node:path";function normalizePath(filePath){return filePath.replaceAll("\\","/").replace(/\/+$/,"")}function firstExisting(candidates,existsSync14){return candidates.find(candidate=>existsSync14(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,existsSync14=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))],existsSync14)??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)),existsSync14)??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))],existsSync14)??findExecutable("yarn",{env,existsSync:existsSync14,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)),existsSync14)??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))],existsSync14)??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))],existsSync14)??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,existsSync14=options.existsSync??fs2.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",sibling2=firstExisting(executableNames(manager,platform).map(name=>path3.join(path3.dirname(processExecPath),name)),existsSync14);return{manager,command:sibling2??fallbackCommand(manager,platform)}}function readPackageName(packageRoot,readFileSync20){try{let parsed=JSON.parse(readFileSync20(path3.join(packageRoot,"package.json"),"utf8"));return typeof parsed.name=="string"?parsed.name:null}catch{return null}}function findPackageRoot(entryPath,packageName,readFileSync20){let current2=path3.dirname(entryPath);for(let depth=0;depth<12;depth+=1){if(readPackageName(current2,readFileSync20)===packageName)return current2;let parent=path3.dirname(current2);if(parent===current2)break;current2=parent}return null}function packageRootFromWrapper(executable,packageName,readFileSync20){try{let content=readFileSync20(executable,"utf8").slice(0,32e3).replaceAll("\\","/"),packageSuffix=`node_modules/${packageName.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`,wrapperDirectory=path3.dirname(executable),candidates=[],relativePattern=new RegExp(`(?:\\$basedir|%~?dp0%?)/([^"'\\r\\n]*?${packageSuffix})(?=/|["'\\s])`,"gi");for(let match of content.matchAll(relativePattern))candidates.push(path3.resolve(wrapperDirectory,match[1].replaceAll("/",path3.sep)));let absolutePattern=new RegExp(`((?:[A-Za-z]:)?/[^"'\\r\\n:]*?${packageSuffix})(?=/|["'\\s:])`,"gi");for(let match of content.matchAll(absolutePattern))candidates.push(path3.resolve(match[1].replaceAll("/",path3.sep)));for(let candidate of new Set(candidates))if(readPackageName(candidate,readFileSync20)===packageName)return candidate;return null}catch{return null}}function detectCliPackage(packageName,binNames,options={}){let env=options.env??process.env,platform=options.platform??process.platform,existsSync14=options.existsSync??(candidate=>isExecutable(candidate,platform)),readFileSync20=options.readFileSync??fs2.readFileSync,realpathSync6=options.realpathSync??fs2.realpathSync,processExecPath=options.processExecPath??process.execPath,extraDirectories=[path3.dirname(processExecPath)];for(let binName of binNames){let executable=findExecutable(binName,{env,existsSync:existsSync14,platform,extraDirectories});if(!executable)continue;let packageRoot=null;try{packageRoot=findPackageRoot(realpathSync6(executable),packageName,readFileSync20)}catch{}if(packageRoot??=packageRootFromWrapper(executable,packageName,readFileSync20),!!packageRoot)return{packageName,packageRoot,executable}}return null}function detectGlobalPackage(packageName,binNames,options={}){for(let binName of binNames){let cli=detectCliPackage(packageName,[binName],options);if(!cli)continue;let installation=resolvePackageManagerInstallation(cli.packageRoot,packageName,options);if(!installation&&options.includeLinked){let linkedRoot=path3.resolve(path3.dirname(cli.executable),"../lib/node_modules",packageName);try{(options.realpathSync??fs2.realpathSync)(linkedRoot)===cli.packageRoot&&(installation=resolvePackageManagerInstallation(linkedRoot,packageName,options))}catch{}}if(installation)return{...cli,...installation,binDirectory:path3.dirname(cli.executable)}}return null}var init_packageManager=__esm({"../setup/dist/packageManager.js"(){"use strict";init_dist()}});import{createRequire as createRequire2}from"node:module";var require2,SETUP_VERSION,SETUP_COMMAND,init_setupVersion=__esm({"../setup/dist/setupVersion.js"(){"use strict";require2=createRequire2(import.meta.url),SETUP_VERSION=require2("../package.json").version,SETUP_COMMAND=`npx @mearl/setup${SETUP_VERSION.includes("-beta.")?"@"+SETUP_VERSION:""}`}});function record2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function invalid4(path28){throw new Error(`Invalid app profile: ${path28}`)}function text2(value){return typeof value=="string"&&value.length<=4096&&Array.from(value).every(character=>character.charCodeAt(0)>8)}function strings(value){return Array.isArray(value)&&value.length<=200&&value.every(text2)}function fields4(value,required2,optional2,path28){(!record2(value)||required2.some(key=>!Object.hasOwn(value,key))||Object.keys(value).some(key=>!required2.includes(key)&&!optional2.includes(key)))&&invalid4(path28)}function stringMap(value){return record2(value)&&Object.keys(value).length<=200&&Object.values(value).every(text2)}function json2(value,depth=0){return depth>25?!1:value===null||typeof value=="boolean"||text2(value)?!0:typeof value=="number"?Number.isFinite(value):Array.isArray(value)?value.length<=1e3&&value.every(item=>json2(item,depth+1)):record2(value)&&Object.entries(value).every(([key,item])=>!["__proto__","prototype","constructor"].includes(key)&&json2(item,depth+1))}function validateActions(value){let arrays=["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext","noop","silent"];fields4(value,["open","close","title","systemInfo","mtop","noop"],[...arrays,"responses","behaviors"],"actions");for(let key of arrays)value[key]!==void 0&&!strings(value[key])&&invalid4(`actions.${key}`);value.responses!==void 0&&!record2(value.responses)&&invalid4("actions.responses"),value.behaviors!==void 0&&(!stringMap(value.behaviors)||!Object.values(value.behaviors).every(item=>BEHAVIORS.has(item)))&&invalid4("actions.behaviors")}function validateAppProfileDefinition(value){json2(value)||invalid4("JSON"),JSON.stringify(value).length>65536&&invalid4("definition exceeds 64 KiB"),fields4(value,["name","label","appName","defaultAppVersion","uaTokens","globals","bridges","activeEvents","actions","schemes"],["pageRuntime","uaFamily","uaTemplate","policies","settings","settingsGroup","miniProgram","imagePicker","geolocation","urlSyncHostSuffixes","overlay","popBeforeOpenParam","messageEvent","nativeBack","layerUrlProxy","rootContainer","titleBarHiddenPathnames","statusBarBackgroundColors","titleBarHostStyles","forceH5Mtop"],"definition");for(let key of["name","label","appName","defaultAppVersion"])(!text2(value[key])||!value[key])&&invalid4(key);if(/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(value.name)||invalid4("name"),value.pageRuntime!==void 0){fields4(value.pageRuntime,["id","sha256"],[],"pageRuntime");let runtime=value.pageRuntime;(typeof runtime.id!="string"||!/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(runtime.id)||typeof runtime.sha256!="string"||!/^[a-f0-9]{64}$/.test(runtime.sha256))&&invalid4("pageRuntime")}for(let key of["uaTokens","activeEvents","urlSyncHostSuffixes","titleBarHiddenPathnames"])value[key]!==void 0&&!strings(value[key])&&invalid4(key);stringMap(value.globals)||invalid4("globals"),(!Array.isArray(value.bridges)||value.bridges.length>20)&&invalid4("bridges");let globals=new Set;for(let bridge of value.bridges)fields4(bridge,["global","style"],["persistent"],"bridges"),(!text2(bridge.global)||!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(bridge.global)||bridge.global.split(".").some(part=>["__proto__","prototype","constructor"].includes(part))||globals.has(bridge.global)||!BRIDGE_STYLES.has(bridge.style)||bridge.persistent!==void 0&&typeof bridge.persistent!="boolean")&&invalid4("bridge"),globals.add(bridge.global);if(validateActions(value.actions),value.settingsGroup!==void 0&&!["fliggy","alipay"].includes(value.settingsGroup)&&invalid4("settingsGroup"),value.uaFamily!==void 0&&!["aliapp","wechatMiniProgram"].includes(value.uaFamily)&&invalid4("uaFamily"),value.uaTemplate!==void 0&&(fields4(value.uaTemplate,["ios","android"],[],"uaTemplate"),(!text2(value.uaTemplate.ios)||!text2(value.uaTemplate.android))&&invalid4("uaTemplate")),value.policies!==void 0){fields4(value.policies,[],["titleBar","navigatorLanguage","networkResult","languages","defaultLanguage"],"policies");let p=value.policies;p.titleBar!==void 0&&!["default","taobao","fliggy","alipay","wechat"].includes(p.titleBar)&&invalid4("policies.titleBar"),p.networkResult!==void 0&&!["default","alipay"].includes(p.networkResult)&&invalid4("policies.networkResult"),p.navigatorLanguage!==void 0&&typeof p.navigatorLanguage!="boolean"&&invalid4("policies.navigatorLanguage"),p.languages!==void 0&&(!strings(p.languages)||!p.languages.length)&&invalid4("policies.languages"),p.defaultLanguage!==void 0&&(!text2(p.defaultLanguage)||p.languages&&!p.languages.includes(p.defaultLanguage))&&invalid4("policies.defaultLanguage")}(!Array.isArray(value.schemes)||value.schemes.length>100)&&invalid4("schemes");for(let rule of value.schemes){fields4(rule,["match"],["hostSuffixes","param","useCurrentOrigin","targetPath","targetHostPrefix","targetParams"],"scheme");for(let key of["match","param","targetPath","targetHostPrefix"])rule[key]!==void 0&&!text2(rule[key])&&invalid4(`scheme.${key}`);rule.hostSuffixes!==void 0&&!strings(rule.hostSuffixes)&&invalid4("scheme.hostSuffixes"),rule.useCurrentOrigin!==void 0&&typeof rule.useCurrentOrigin!="boolean"&&invalid4("scheme.useCurrentOrigin"),rule.targetParams!==void 0&&!stringMap(rule.targetParams)&&invalid4("scheme.targetParams")}if(value.settings!==void 0){(!Array.isArray(value.settings)||value.settings.length>30)&&invalid4("settings");let ids=new Set;for(let setting of value.settings){if(fields4(setting,["id","label","type","target"],["choices","minimum","maximum"],"setting"),(!text2(setting.id)||!/^[a-z][a-zA-Z0-9-]*$/.test(setting.id)||ids.has(setting.id)||!text2(setting.label)||!["select","boolean","number","text","json"].includes(setting.type))&&invalid4("setting"),ids.add(setting.id),record2(setting.target)&&setting.target.option!==void 0)fields4(setting.target,["option"],[],"setting.target"),setting.target.option!=="language"&&invalid4("setting.target.option");else{fields4(setting.target,["method"],["field"],"setting.target"),(!text2(setting.target.method)||!setting.target.method||["__proto__","prototype","constructor"].includes(setting.target.method)||setting.target.field!==void 0&&(!text2(setting.target.field)||["__proto__","prototype","constructor"].includes(setting.target.field)))&&invalid4("setting.target.method");let method=setting.target.method;["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext"].some(key=>value.actions[key]?.includes(method))&&invalid4("setting targets a structural method")}setting.choices!==void 0&&(!Array.isArray(setting.choices)||!setting.choices.length||setting.choices.some(choice=>!record2(choice)||!text2(choice.label)||!text2(choice.value)))&&invalid4("setting.choices");for(let key of["minimum","maximum"])setting[key]!==void 0&&typeof setting[key]!="number"&&invalid4(`setting.${key}`);setting.type==="select"&&!Array.isArray(setting.choices)&&invalid4("setting.choices required"),setting.minimum!==void 0&&setting.maximum!==void 0&&setting.minimum>setting.maximum&&invalid4("setting range"),"option"in setting.target&&!["select","text"].includes(setting.type)&&invalid4("setting.option type")}}for(let key of["forceH5Mtop"])value[key]!==void 0&&typeof value[key]!="boolean"&&invalid4(key);for(let key of["popBeforeOpenParam","messageEvent"])value[key]!==void 0&&!text2(value[key])&&invalid4(key);return value.statusBarBackgroundColors!==void 0&&!stringMap(value.statusBarBackgroundColors)&&invalid4("statusBarBackgroundColors"),validateStructuredOptions(value),JSON.parse(JSON.stringify(value))}function validateStructuredOptions(value){let shapes={nativeBack:[[],["event","controlFunction","handler"]],geolocation:[["reverseGeocodeApi","version"],[]],layerUrlProxy:[["sourceHostPrefix","pathPrefix","targetHostSuffixes"],["defaultTargetHost"]],imagePicker:[["schemes","api","version","fcId","fcGroup","uploadUrlFunction","prefix","region"],[]],overlay:[["enabledParam","topRatioParam","radiusParam","maskAlphaParam","tapCloseParam","defaultTopRatio","defaultRadius","defaultMaskAlpha","defaultTapClose"],["heightRatioParam","tapCloseSelectors","silentTapClose","maxWidthPx","maxWidthMinAppVersion"]]};for(let[key,[required2,optional2]]of Object.entries(shapes))if(value[key]!==void 0){fields4(value[key],required2,optional2,key);for(let[field,item]of Object.entries(value[key]))(field==="maxWidthPx"?typeof item=="number"&&Number.isFinite(item)&&item>0:field==="maxWidthMinAppVersion"?typeof item=="string"&&/^\d+(?:\.\d+)*$/.test(item):field.startsWith("default")&&field!=="defaultTargetHost"?field==="defaultTapClose"?typeof item=="boolean":typeof item=="number":field==="silentTapClose"?typeof item=="boolean":["schemes","targetHostSuffixes","tapCloseSelectors"].includes(field)?strings(item):text2(item))||invalid4(`${key}.${field}`)}if(value.rootContainer!==void 0&&(fields4(value.rootContainer,[],["statusBarHeightCookie"],"rootContainer"),value.rootContainer.statusBarHeightCookie!==void 0&&(fields4(value.rootContainer.statusBarHeightCookie,["name"],["domain","path"],"rootContainer.statusBarHeightCookie"),Object.values(value.rootContainer.statusBarHeightCookie).every(text2)||invalid4("rootContainer.statusBarHeightCookie"))),value.titleBarHostStyles!==void 0&&(!Array.isArray(value.titleBarHostStyles)||value.titleBarHostStyles.some(rule=>(fields4(rule,["hostSuffix"],["titleBarBackgroundColor","statusBarBackgroundColor"],"titleBarHostStyle"),!Object.values(rule).every(text2))))&&invalid4("titleBarHostStyles"),value.miniProgram!==void 0){fields4(value.miniProgram,[],["paymentRoutes","nativeRoutes","messageRules"],"miniProgram");let shapes2={paymentRoutes:[["pathname","paymentParamsParam","successUrlParams","failureUrlParams"],["hostSuffixes","successResultParam","forwardParams","useCurrentOrigin"]],nativeRoutes:[["pathname","actions"],["hostSuffixes"]],messageRules:[["type","action"],["hostSuffixes"]]};for(let[key,list2]of Object.entries(value.miniProgram)){(!Array.isArray(list2)||list2.length>100)&&invalid4(`miniProgram.${key}`);for(let rule of list2){fields4(rule,...shapes2[key],`miniProgram.${key}`);for(let[field,item]of Object.entries(rule))(["hostSuffixes","successUrlParams","failureUrlParams","forwardParams","actions"].includes(field)?!strings(item):field==="useCurrentOrigin"?typeof item!="boolean":!text2(item))&&invalid4(`miniProgram.${key}.${field}`);key==="messageRules"&&!["stageBackData","closeAll"].includes(rule.action)&&invalid4("miniProgram.messageRules.action"),key==="nativeRoutes"&&!rule.actions.every(action=>["navigateMiniProgram","subscribeMessage"].includes(action))&&invalid4("miniProgram.nativeRoutes.actions")}}}}function validateAppProfileContribution(value){if(value===void 0)return;fields4(value,["version","profiles"],[],"contribution"),(value.version!==1||!Array.isArray(value.profiles)||!value.profiles.length||value.profiles.length>20)&&invalid4("contribution");let profiles=value.profiles.map(validateAppProfileDefinition);return JSON.stringify(profiles).length>256e3&&invalid4("contribution exceeds 256 KiB"),profiles.some(profile=>profile.name.includes("/"))&&invalid4("contribution names must be local identifiers"),new Set(profiles.map(profile=>profile.name)).size!==profiles.length&&invalid4("duplicate profile name"),{version:1,profiles}}function appProfileRevision(definition){let canonical=value=>Array.isArray(value)?`[${value.map(canonical).join(",")}]`:record2(value)?`{${Object.keys(value).sort().map(key=>`${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`:JSON.stringify(value),source=canonical(definition),left=2166136261,right=5381;for(let i2=0;i2<source.length;i2++)left=Math.imul(left^source.charCodeAt(i2),16777619),right=Math.imul(right,33)^source.charCodeAt(i2);return`v1-${(left>>>0).toString(16).padStart(8,"0")}${(right>>>0).toString(16).padStart(8,"0")}`}var BRIDGE_STYLES,APP_BRIDGE_BEHAVIORS,BEHAVIORS,init_appProfileDefinition=__esm({"../browser-core/dist/appProfileDefinition.js"(){"use strict";BRIDGE_STYLES=new Set(["windvane","fliggy","alipay","callback","btrip","invoke","callHandler","amap","didi","easybikeNative","mega","wechat","wechatMiniProgram"]),APP_BRIDGE_BEHAVIORS=["navigate","closeAll","closeBackData","postMessage","notifySubscribe","notifyUnsubscribe","notifyPost","sharedFileRead","sharedFileWrite","sharedDataGet","sharedDataSet","legacyBroadcastCreate","legacyBroadcastPost","legacyBroadcastClose","memoryGet","memorySet","memoryDelete","availabilityMap","userInfo","authCode","networkInfo","geolocation","permission","imagePicker","prefetch","fptTrack","mtopStream","previewFile","toast","unsupportedNativeInput","payment","userTrack","calendar","networkQualityMonitor","beaconRequest","voiceRecognition"],BEHAVIORS=new Set(APP_BRIDGE_BEHAVIORS)}});var init_types2=__esm({"../browser-core/dist/types.js"(){"use strict"}});function createCaptureGeneration(){return crypto.randomUUID()}function encodeCaptureCursor(cursor){return`${CURSOR_PREFIX}:${cursor.tabId}:${cursor.generation}:${cursor.scope}:${cursor.sequence}`}function decodeCaptureCursor(value){let match=value.match(/^mearl-capture-v1:(\d+):([^:]+):(all|logs|requests|events):(\d+)$/);if(!match)throw new Error("Invalid capture cursor");let tabId=Number(match[1]),sequence=Number(match[4]);if(!Number.isSafeInteger(tabId)||!Number.isSafeInteger(sequence))throw new Error("Invalid capture cursor");return{tabId,generation:match[2],scope:match[3],sequence}}function captureCheckpoint(state){return encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:state.currentSequence,scope:"all"})}function nextCaptureSequence(state){return state.currentSequence+=1,state.currentSequence}function resolveAfterSequence(after,state,scope){if(!after)return 0;let cursor=decodeCaptureCursor(after);if(cursor.tabId!==state.tabId)throw new Error(`Capture cursor belongs to tab ${cursor.tabId}, not tab ${state.tabId}`);if(cursor.generation!==state.generation)throw new Error("Capture cursor expired because the tab collector was restarted");if(cursor.scope!=="all"&&cursor.scope!==scope)throw new Error(`Capture cursor is scoped to ${cursor.scope}, not ${scope}`);if(cursor.sequence>state.currentSequence)throw new Error("Capture cursor is ahead of the current collector state");return cursor.sequence}function queryCapturedEntries(buffer,state,options,matches,droppedThroughSequence=0,scope="all"){let{after,since,now=Date.now()}=options,limit=Math.max(1,Math.floor(options.limit??100)),afterSequence=resolveAfterSequence(after,state,scope),sinceTimestampMs=since===void 0?void 0:now-since*1e3,matched=buffer.filter(entry=>entry.captureSequence>afterSequence&&(sinceTimestampMs===void 0||entry.timestampMs>=sinceTimestampMs)&&matches(entry)),hasMore=matched.length>limit,entries=after?matched.slice(0,limit):matched.slice(-limit),nextSequence=after&&hasMore&&entries.length>0?entries[entries.length-1].captureSequence:state.currentSequence;return{entries,totalMatched:matched.length,nextCursor:encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:nextSequence,scope}),hasMore,gap:after!==void 0&&afterSequence<droppedThroughSequence}}var CURSOR_PREFIX,init_capture=__esm({"../browser-core/dist/capture.js"(){"use strict";CURSOR_PREFIX="mearl-capture-v1"}});function compileTextPattern(value){try{return{regex:new RegExp(value,"i"),fallback:""}}catch{return{regex:null,fallback:value.toLowerCase()}}}function matchesTextPattern(value,pattern2){return value?pattern2.regex?pattern2.regex.test(value):value.toLowerCase().includes(pattern2.fallback):!1}function compactEventUrl(value){if(value)try{let url2=new URL(value);return url2.origin==="null"?value.split(/[?#]/,1)[0]:`${url2.origin}${url2.pathname}`}catch{return value.split(/[?#]/,1)[0]}}function formatTrackingEvent(event,includeRaw=!1){let{captureSequence:_discardedCaptureSequence,...publicEvent}=event;if(includeRaw)return publicEvent;let{_raw:_discardedRaw,_context,url:url2,...summary}=publicEvent,compactUrl=compactEventUrl(url2??_context.requestUrl);return{...summary,...compactUrl?{url:compactUrl}:{}}}function matchesTrackingEvent(event,options){let{source="all",event_type,filter}=options;if(source!=="all"&&event.source!==source||event_type&&!matchesTextPattern(event.event_type,compileTextPattern(event_type)))return!1;if(filter){let pattern2=compileTextPattern(filter);if(!matchesTextPattern(event.name,pattern2)&&!matchesTextPattern(event.url,pattern2))return!1}return!0}function queryTrackingEvents(buffer,options={}){let{source="all",event_type,filter,since,limit=20,now=Date.now()}=options,events=[...buffer].reverse();if(source!=="all"&&(events=events.filter(event=>event.source===source)),since!==void 0){let sinceTimestamp=now-since*1e3;events=events.filter(event=>event.batchTimestampMs>=sinceTimestamp)}if(event_type){let pattern2=compileTextPattern(event_type);events=events.filter(event=>matchesTextPattern(event.event_type,pattern2))}if(filter){let pattern2=compileTextPattern(filter);events=events.filter(event=>matchesTextPattern(event.name,pattern2)||matchesTextPattern(event.url,pattern2))}return{events:events.slice(0,limit),totalMatched:events.length,totalInBuffer:buffer.length}}function appendCapturedTrackingBatch(buffer,events,maxSize){if(events.length===0)return[];let captureSequence=events[0].captureSequence,insertionIndex=Number.isSafeInteger(captureSequence)?buffer.findIndex(event=>Number.isSafeInteger(event.captureSequence)&&event.captureSequence>captureSequence):-1;if(buffer.splice(insertionIndex<0?buffer.length:insertionIndex,0,...events),buffer.length<=maxSize)return[];let removeCount=buffer.length-maxSize,boundarySequence=buffer[removeCount-1]?.captureSequence;for(;boundarySequence!==void 0&&buffer[removeCount]?.captureSequence===boundarySequence;)removeCount+=1;return buffer.splice(0,removeCount)}function queryCapturedTrackingEvents(buffer,state,options={},droppedThroughSequence=0){let limit=Math.max(1,Math.floor(options.limit??20));if(!options.after){let snapshot=queryTrackingEvents(buffer,options);return{...snapshot,nextCursor:encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:state.currentSequence,scope:"events"}),hasMore:snapshot.totalMatched>limit,gap:!1}}let sinceTimestampMs=options.since===void 0?void 0:(options.now??Date.now())-options.since*1e3,batchesBySequence=new Map;for(let event of buffer){if(!Number.isSafeInteger(event.captureSequence)||sinceTimestampMs!==void 0&&event.batchTimestampMs<sinceTimestampMs||!matchesTrackingEvent(event,options))continue;let captureSequence=event.captureSequence,batch=batchesBySequence.get(captureSequence);batch?batch.events.push(event):batchesBySequence.set(captureSequence,{captureSequence,timestampMs:event.batchTimestampMs,events:[event]})}let batches=[...batchesBySequence.values()].sort((left,right)=>left.captureSequence-right.captureSequence),captured=queryCapturedEntries(batches,state,{after:options.after,limit:Number.MAX_SAFE_INTEGER},()=>!0,droppedThroughSequence,"events"),selected=[],selectedCount=0;for(let batch of captured.entries){if(selected.length>0&&selectedCount+batch.events.length>limit)break;selected.push(batch),selectedCount+=batch.events.length}let hasMore=selected.length<captured.entries.length,nextSequence=hasMore?selected[selected.length-1].captureSequence:state.currentSequence;return{events:selected.flatMap(batch=>batch.events),totalMatched:captured.entries.reduce((total,batch)=>total+batch.events.length,0),totalInBuffer:buffer.length,nextCursor:encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:nextSequence,scope:"events"}),hasMore,gap:captured.gap}}var TRACKING_CAPTURE_ARMED_HINT,init_eventFilters=__esm({"../browser-core/dist/eventFilters.js"(){"use strict";init_capture();TRACKING_CAPTURE_ARMED_HINT="Event capture is active, but this tab has no captured history yet. Reload the current tab or repeat the triggering action, then call get_events again."}});function parsePath(path28){if(path28.length>1e3)throw new Error("Path too long: maximum 1000 characters allowed");let keys=[],current2="";for(let i2=0;i2<path28.length;i2++){let char=path28[i2];if(char===".")current2&&(keys.push(current2),current2="");else if(char==="["){current2&&(keys.push(current2),current2="");let j=i2+1;for(;j<path28.length&&path28[j]!=="]";)j++;if(j<path28.length){let index=parseInt(path28.substring(i2+1,j),10);if(!isNaN(index)){if(index<0||index>1e5)throw new Error(`Array index out of safe range: ${index}`);keys.push(index)}i2=j}}else current2+=char}if(current2&&keys.push(current2),keys.length>50)throw new Error("Path too deep: maximum 50 levels allowed");return keys}function getValueByPath(obj,path28){let keys=parsePath(path28),current2=obj;for(let key of keys){if(current2==null)return;current2=current2[key]}return current2}function setValueByPath(obj,path28,value){let keys=parsePath(path28),current2=obj;for(let i2=0;i2<keys.length-1;i2++){let key=keys[i2],nextKey=keys[i2+1];(current2[key]===null||current2[key]===void 0)&&(current2[key]=typeof nextKey=="number"?[]:{}),current2=current2[key]}current2[keys[keys.length-1]]=value}function getStructure(data2,maxDepth=5,currentDepth=0){if(currentDepth>=maxDepth)return"<max depth reached>";if(data2===null)return"null";if(data2===void 0)return"undefined";let type=typeof data2;if(type==="string"||type==="number"||type==="boolean")return type;if(Array.isArray(data2))return data2.length===0?"array[0]":{_type:`array[${data2.length}]`,_sample:getStructure(data2[0],maxDepth,currentDepth+1)};if(type==="object"){let structure={};for(let key in data2)Object.prototype.hasOwnProperty.call(data2,key)&&(structure[key]=getStructure(data2[key],maxDepth,currentDepth+1));return structure}return type}function truncateData(data2,maxSize){let str=JSON.stringify(data2);if(str.length<=maxSize)return data2;let truncated=str.substring(0,maxSize);return`<truncated: ${str.length} bytes, showing first ${maxSize} chars>
20
+ `))})}return{socketPath,runtime,async start(){if(state!=="idle")throw new Error(`Provider server is already ${state}`);let providerId=descriptor.providerId;if(activeProviderIds.has(providerId))throw new Error(`Provider ${providerId} is already running in this process`);state="starting",activeProviderIds.add(providerId);let startToken=process.env[PROVIDER_START_TOKEN_ENV]||randomUUID6(),existing=readLiveProvider(descriptor.providerId);if(existing)throw state="idle",activeProviderIds.delete(providerId),new Error(`Provider ${descriptor.providerId} is already running (pid ${existing.pid})`);if(!claimProviderStart(providerId,startToken))throw state="idle",activeProviderIds.delete(providerId),new Error(`Provider ${providerId} start is already in progress`);try{let competing=readLiveProvider(providerId);if(competing)throw new Error(`Provider ${providerId} is already running (pid ${competing.pid})`);removeStaleProviderSocket(providerId,socketPath),process.platform!=="win32"&&ensureDir(dirname3(socketPath)),server=net.createServer(handleConnection),await new Promise((resolve16,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.off("error",reject),resolve16()})}),process.platform!=="win32"&&chmodSync(socketPath,384),publishLiveProvider(descriptor,socketPath),releaseProviderStart(providerId,startToken),state="running"}catch(error62){let active=server;server=null;for(let connection of connections)connection.destroy();throw connections.clear(),active?.listening&&await new Promise(resolve16=>active.close(()=>resolve16())),unpublishLiveProvider(providerId),process.platform!=="win32"&&rmSync4(socketPath,{force:!0}),releaseProviderStart(providerId,startToken),activeProviderIds.delete(providerId),state="idle",error62}},updateBrowsers(nextBrowsers){if(state!=="running")throw new Error("Provider server is not running");runtime.updateBrowsers(nextBrowsers),browsers=[...nextBrowsers],browserIds=publishProviderBrowsers(descriptor,socketPath,browsers,browserIds)},touchBrowser(browserId){if(state!=="running")throw new Error("Provider server is not running");if(!browsers.some(browser=>browser.browserId===browserId))throw new Error(`Provider browser not found: ${browserId}`);touchProviderBrowser(providerBrowserKey(descriptor.providerId,browserId))},async stop(){if(state!=="idle"){if(state==="starting")throw new Error("Provider server is still starting");return state==="stopping"&&stopPromise||(state="stopping",stopPromise=(async()=>{let active=server;server=null;for(let connection of connections)connection.destroy();connections.clear(),active&&await new Promise(resolve16=>active.close(()=>resolve16())),unpublishProviderBrowsers(browserIds),browserIds.clear(),browsers=[],process.platform!=="win32"&&rmSync4(socketPath,{force:!0}),unpublishLiveProvider(descriptor.providerId)})().finally(()=>{activeProviderIds.delete(descriptor.providerId),stopPromise=null,state="idle"})),stopPromise}}}}var MAX_REQUEST_BYTES,activeProviderIds,init_server=__esm({"../provider/dist/server.js"(){"use strict";init_dist();init_actions();init_provider_runtime();init_registry2();init_types();init_protocol();MAX_REQUEST_BYTES=16*1024*1024,activeProviderIds=new Set}});var dist_exports3={};__export(dist_exports3,{MEARL_PROVIDER_PROTOCOL_VERSION:()=>MEARL_PROVIDER_PROTOCOL_VERSION,PROVIDER_ACTIONS:()=>PROVIDER_ACTIONS,assertProviderProtocolVersion:()=>assertProviderProtocolVersion,createProviderRuntime:()=>createProviderRuntime,createProviderServer:()=>createProviderServer,isProviderAction:()=>isProviderAction,providerDataDir:()=>providerDataDir,validateProviderBrowser:()=>validateProviderBrowser,validateProviderInput:()=>validateProviderInput,validateProviderLaunchForm:()=>validateProviderLaunchForm});var init_dist4=__esm({"../provider/dist/index.js"(){"use strict";init_types();init_protocol();init_actions();init_registry2();init_provider_runtime();init_server()}});import fs2 from"node:fs";import path3 from"node:path";function normalizePath(filePath){return filePath.replaceAll("\\","/").replace(/\/+$/,"")}function firstExisting(candidates,existsSync14){return candidates.find(candidate=>existsSync14(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,existsSync14=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))],existsSync14)??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)),existsSync14)??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))],existsSync14)??findExecutable("yarn",{env,existsSync:existsSync14,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)),existsSync14)??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))],existsSync14)??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))],existsSync14)??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,existsSync14=options.existsSync??fs2.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",sibling2=firstExisting(executableNames(manager,platform).map(name=>path3.join(path3.dirname(processExecPath),name)),existsSync14);return{manager,command:sibling2??fallbackCommand(manager,platform)}}function readPackageName(packageRoot,readFileSync20){try{let parsed=JSON.parse(readFileSync20(path3.join(packageRoot,"package.json"),"utf8"));return typeof parsed.name=="string"?parsed.name:null}catch{return null}}function findPackageRoot(entryPath,packageName,readFileSync20){let current2=path3.dirname(entryPath);for(let depth=0;depth<12;depth+=1){if(readPackageName(current2,readFileSync20)===packageName)return current2;let parent=path3.dirname(current2);if(parent===current2)break;current2=parent}return null}function packageRootFromWrapper(executable,packageName,readFileSync20){try{let content=readFileSync20(executable,"utf8").slice(0,32e3).replaceAll("\\","/"),packageSuffix=`node_modules/${packageName.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`,wrapperDirectory=path3.dirname(executable),candidates=[],relativePattern=new RegExp(`(?:\\$basedir|%~?dp0%?)/([^"'\\r\\n]*?${packageSuffix})(?=/|["'\\s])`,"gi");for(let match of content.matchAll(relativePattern))candidates.push(path3.resolve(wrapperDirectory,match[1].replaceAll("/",path3.sep)));let absolutePattern=new RegExp(`((?:[A-Za-z]:)?/[^"'\\r\\n:]*?${packageSuffix})(?=/|["'\\s:])`,"gi");for(let match of content.matchAll(absolutePattern))candidates.push(path3.resolve(match[1].replaceAll("/",path3.sep)));for(let candidate of new Set(candidates))if(readPackageName(candidate,readFileSync20)===packageName)return candidate;return null}catch{return null}}function detectCliPackage(packageName,binNames,options={}){let env=options.env??process.env,platform=options.platform??process.platform,existsSync14=options.existsSync??(candidate=>isExecutable(candidate,platform)),readFileSync20=options.readFileSync??fs2.readFileSync,realpathSync6=options.realpathSync??fs2.realpathSync,processExecPath=options.processExecPath??process.execPath,extraDirectories=[path3.dirname(processExecPath)];for(let binName of binNames){let executable=findExecutable(binName,{env,existsSync:existsSync14,platform,extraDirectories});if(!executable)continue;let packageRoot=null;try{packageRoot=findPackageRoot(realpathSync6(executable),packageName,readFileSync20)}catch{}if(packageRoot??=packageRootFromWrapper(executable,packageName,readFileSync20),!!packageRoot)return{packageName,packageRoot,executable}}return null}function detectGlobalPackage(packageName,binNames,options={}){for(let binName of binNames){let cli=detectCliPackage(packageName,[binName],options);if(!cli)continue;let installation=resolvePackageManagerInstallation(cli.packageRoot,packageName,options);if(!installation&&options.includeLinked){let linkedRoot=path3.resolve(path3.dirname(cli.executable),"../lib/node_modules",packageName);try{(options.realpathSync??fs2.realpathSync)(linkedRoot)===cli.packageRoot&&(installation=resolvePackageManagerInstallation(linkedRoot,packageName,options))}catch{}}if(installation)return{...cli,...installation,binDirectory:path3.dirname(cli.executable)}}return null}var init_packageManager=__esm({"../setup/dist/packageManager.js"(){"use strict";init_dist()}});import{createRequire as createRequire2}from"node:module";var require2,SETUP_VERSION,SETUP_COMMAND,init_setupVersion=__esm({"../setup/dist/setupVersion.js"(){"use strict";require2=createRequire2(import.meta.url),SETUP_VERSION=require2("../package.json").version,SETUP_COMMAND=`npx --@mearl:registry=https://registry.npmjs.org @mearl/setup${SETUP_VERSION.includes("-beta.")?"@"+SETUP_VERSION:""}`}});function record2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function invalid4(path28){throw new Error(`Invalid app profile: ${path28}`)}function text2(value){return typeof value=="string"&&value.length<=4096&&Array.from(value).every(character=>character.charCodeAt(0)>8)}function strings(value){return Array.isArray(value)&&value.length<=200&&value.every(text2)}function fields4(value,required2,optional2,path28){(!record2(value)||required2.some(key=>!Object.hasOwn(value,key))||Object.keys(value).some(key=>!required2.includes(key)&&!optional2.includes(key)))&&invalid4(path28)}function stringMap(value){return record2(value)&&Object.keys(value).length<=200&&Object.values(value).every(text2)}function json2(value,depth=0){return depth>25?!1:value===null||typeof value=="boolean"||text2(value)?!0:typeof value=="number"?Number.isFinite(value):Array.isArray(value)?value.length<=1e3&&value.every(item=>json2(item,depth+1)):record2(value)&&Object.entries(value).every(([key,item])=>!["__proto__","prototype","constructor"].includes(key)&&json2(item,depth+1))}function validateActions(value){let arrays=["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext","noop","silent"];fields4(value,["open","close","title","systemInfo","mtop","noop"],[...arrays,"responses","behaviors"],"actions");for(let key of arrays)value[key]!==void 0&&!strings(value[key])&&invalid4(`actions.${key}`);value.responses!==void 0&&!record2(value.responses)&&invalid4("actions.responses"),value.behaviors!==void 0&&(!stringMap(value.behaviors)||!Object.values(value.behaviors).every(item=>BEHAVIORS.has(item)))&&invalid4("actions.behaviors")}function validateAppProfileDefinition(value){json2(value)||invalid4("JSON"),JSON.stringify(value).length>65536&&invalid4("definition exceeds 64 KiB"),fields4(value,["name","label","appName","defaultAppVersion","uaTokens","globals","bridges","activeEvents","actions","schemes"],["pageRuntime","uaFamily","uaTemplate","policies","settings","settingsGroup","miniProgram","imagePicker","geolocation","urlSyncHostSuffixes","overlay","popBeforeOpenParam","messageEvent","nativeBack","layerUrlProxy","rootContainer","titleBarHiddenPathnames","statusBarBackgroundColors","titleBarHostStyles","forceH5Mtop"],"definition");for(let key of["name","label","appName","defaultAppVersion"])(!text2(value[key])||!value[key])&&invalid4(key);if(/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(value.name)||invalid4("name"),value.pageRuntime!==void 0){fields4(value.pageRuntime,["id","sha256"],[],"pageRuntime");let runtime=value.pageRuntime;(typeof runtime.id!="string"||!/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(runtime.id)||typeof runtime.sha256!="string"||!/^[a-f0-9]{64}$/.test(runtime.sha256))&&invalid4("pageRuntime")}for(let key of["uaTokens","activeEvents","urlSyncHostSuffixes","titleBarHiddenPathnames"])value[key]!==void 0&&!strings(value[key])&&invalid4(key);stringMap(value.globals)||invalid4("globals"),(!Array.isArray(value.bridges)||value.bridges.length>20)&&invalid4("bridges");let globals=new Set;for(let bridge of value.bridges)fields4(bridge,["global","style"],["persistent"],"bridges"),(!text2(bridge.global)||!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(bridge.global)||bridge.global.split(".").some(part=>["__proto__","prototype","constructor"].includes(part))||globals.has(bridge.global)||!BRIDGE_STYLES.has(bridge.style)||bridge.persistent!==void 0&&typeof bridge.persistent!="boolean")&&invalid4("bridge"),globals.add(bridge.global);if(validateActions(value.actions),value.settingsGroup!==void 0&&!["fliggy","alipay"].includes(value.settingsGroup)&&invalid4("settingsGroup"),value.uaFamily!==void 0&&!["aliapp","wechatMiniProgram"].includes(value.uaFamily)&&invalid4("uaFamily"),value.uaTemplate!==void 0&&(fields4(value.uaTemplate,["ios","android"],[],"uaTemplate"),(!text2(value.uaTemplate.ios)||!text2(value.uaTemplate.android))&&invalid4("uaTemplate")),value.policies!==void 0){fields4(value.policies,[],["titleBar","navigatorLanguage","networkResult","languages","defaultLanguage"],"policies");let p=value.policies;p.titleBar!==void 0&&!["default","taobao","fliggy","alipay","wechat"].includes(p.titleBar)&&invalid4("policies.titleBar"),p.networkResult!==void 0&&!["default","alipay"].includes(p.networkResult)&&invalid4("policies.networkResult"),p.navigatorLanguage!==void 0&&typeof p.navigatorLanguage!="boolean"&&invalid4("policies.navigatorLanguage"),p.languages!==void 0&&(!strings(p.languages)||!p.languages.length)&&invalid4("policies.languages"),p.defaultLanguage!==void 0&&(!text2(p.defaultLanguage)||p.languages&&!p.languages.includes(p.defaultLanguage))&&invalid4("policies.defaultLanguage")}(!Array.isArray(value.schemes)||value.schemes.length>100)&&invalid4("schemes");for(let rule of value.schemes){fields4(rule,["match"],["hostSuffixes","param","useCurrentOrigin","targetPath","targetHostPrefix","targetParams"],"scheme");for(let key of["match","param","targetPath","targetHostPrefix"])rule[key]!==void 0&&!text2(rule[key])&&invalid4(`scheme.${key}`);rule.hostSuffixes!==void 0&&!strings(rule.hostSuffixes)&&invalid4("scheme.hostSuffixes"),rule.useCurrentOrigin!==void 0&&typeof rule.useCurrentOrigin!="boolean"&&invalid4("scheme.useCurrentOrigin"),rule.targetParams!==void 0&&!stringMap(rule.targetParams)&&invalid4("scheme.targetParams")}if(value.settings!==void 0){(!Array.isArray(value.settings)||value.settings.length>30)&&invalid4("settings");let ids=new Set;for(let setting of value.settings){if(fields4(setting,["id","label","type","target"],["choices","minimum","maximum"],"setting"),(!text2(setting.id)||!/^[a-z][a-zA-Z0-9-]*$/.test(setting.id)||ids.has(setting.id)||!text2(setting.label)||!["select","boolean","number","text","json"].includes(setting.type))&&invalid4("setting"),ids.add(setting.id),record2(setting.target)&&setting.target.option!==void 0)fields4(setting.target,["option"],[],"setting.target"),setting.target.option!=="language"&&invalid4("setting.target.option");else{fields4(setting.target,["method"],["field"],"setting.target"),(!text2(setting.target.method)||!setting.target.method||["__proto__","prototype","constructor"].includes(setting.target.method)||setting.target.field!==void 0&&(!text2(setting.target.field)||["__proto__","prototype","constructor"].includes(setting.target.field)))&&invalid4("setting.target.method");let method=setting.target.method;["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext"].some(key=>value.actions[key]?.includes(method))&&invalid4("setting targets a structural method")}setting.choices!==void 0&&(!Array.isArray(setting.choices)||!setting.choices.length||setting.choices.some(choice=>!record2(choice)||!text2(choice.label)||!text2(choice.value)))&&invalid4("setting.choices");for(let key of["minimum","maximum"])setting[key]!==void 0&&typeof setting[key]!="number"&&invalid4(`setting.${key}`);setting.type==="select"&&!Array.isArray(setting.choices)&&invalid4("setting.choices required"),setting.minimum!==void 0&&setting.maximum!==void 0&&setting.minimum>setting.maximum&&invalid4("setting range"),"option"in setting.target&&!["select","text"].includes(setting.type)&&invalid4("setting.option type")}}for(let key of["forceH5Mtop"])value[key]!==void 0&&typeof value[key]!="boolean"&&invalid4(key);for(let key of["popBeforeOpenParam","messageEvent"])value[key]!==void 0&&!text2(value[key])&&invalid4(key);return value.statusBarBackgroundColors!==void 0&&!stringMap(value.statusBarBackgroundColors)&&invalid4("statusBarBackgroundColors"),validateStructuredOptions(value),JSON.parse(JSON.stringify(value))}function validateStructuredOptions(value){let shapes={nativeBack:[[],["event","controlFunction","handler"]],geolocation:[["reverseGeocodeApi","version"],[]],layerUrlProxy:[["sourceHostPrefix","pathPrefix","targetHostSuffixes"],["defaultTargetHost"]],imagePicker:[["schemes","api","version","fcId","fcGroup","uploadUrlFunction","prefix","region"],[]],overlay:[["enabledParam","topRatioParam","radiusParam","maskAlphaParam","tapCloseParam","defaultTopRatio","defaultRadius","defaultMaskAlpha","defaultTapClose"],["heightRatioParam","tapCloseSelectors","silentTapClose","maxWidthPx","maxWidthMinAppVersion"]]};for(let[key,[required2,optional2]]of Object.entries(shapes))if(value[key]!==void 0){fields4(value[key],required2,optional2,key);for(let[field,item]of Object.entries(value[key]))(field==="maxWidthPx"?typeof item=="number"&&Number.isFinite(item)&&item>0:field==="maxWidthMinAppVersion"?typeof item=="string"&&/^\d+(?:\.\d+)*$/.test(item):field.startsWith("default")&&field!=="defaultTargetHost"?field==="defaultTapClose"?typeof item=="boolean":typeof item=="number":field==="silentTapClose"?typeof item=="boolean":["schemes","targetHostSuffixes","tapCloseSelectors"].includes(field)?strings(item):text2(item))||invalid4(`${key}.${field}`)}if(value.rootContainer!==void 0&&(fields4(value.rootContainer,[],["statusBarHeightCookie"],"rootContainer"),value.rootContainer.statusBarHeightCookie!==void 0&&(fields4(value.rootContainer.statusBarHeightCookie,["name"],["domain","path"],"rootContainer.statusBarHeightCookie"),Object.values(value.rootContainer.statusBarHeightCookie).every(text2)||invalid4("rootContainer.statusBarHeightCookie"))),value.titleBarHostStyles!==void 0&&(!Array.isArray(value.titleBarHostStyles)||value.titleBarHostStyles.some(rule=>(fields4(rule,["hostSuffix"],["titleBarBackgroundColor","statusBarBackgroundColor"],"titleBarHostStyle"),!Object.values(rule).every(text2))))&&invalid4("titleBarHostStyles"),value.miniProgram!==void 0){fields4(value.miniProgram,[],["paymentRoutes","nativeRoutes","messageRules"],"miniProgram");let shapes2={paymentRoutes:[["pathname","paymentParamsParam","successUrlParams","failureUrlParams"],["hostSuffixes","successResultParam","forwardParams","useCurrentOrigin"]],nativeRoutes:[["pathname","actions"],["hostSuffixes"]],messageRules:[["type","action"],["hostSuffixes"]]};for(let[key,list2]of Object.entries(value.miniProgram)){(!Array.isArray(list2)||list2.length>100)&&invalid4(`miniProgram.${key}`);for(let rule of list2){fields4(rule,...shapes2[key],`miniProgram.${key}`);for(let[field,item]of Object.entries(rule))(["hostSuffixes","successUrlParams","failureUrlParams","forwardParams","actions"].includes(field)?!strings(item):field==="useCurrentOrigin"?typeof item!="boolean":!text2(item))&&invalid4(`miniProgram.${key}.${field}`);key==="messageRules"&&!["stageBackData","closeAll"].includes(rule.action)&&invalid4("miniProgram.messageRules.action"),key==="nativeRoutes"&&!rule.actions.every(action=>["navigateMiniProgram","subscribeMessage"].includes(action))&&invalid4("miniProgram.nativeRoutes.actions")}}}}function validateAppProfileContribution(value){if(value===void 0)return;fields4(value,["version","profiles"],[],"contribution"),(value.version!==1||!Array.isArray(value.profiles)||!value.profiles.length||value.profiles.length>20)&&invalid4("contribution");let profiles=value.profiles.map(validateAppProfileDefinition);return JSON.stringify(profiles).length>256e3&&invalid4("contribution exceeds 256 KiB"),profiles.some(profile=>profile.name.includes("/"))&&invalid4("contribution names must be local identifiers"),new Set(profiles.map(profile=>profile.name)).size!==profiles.length&&invalid4("duplicate profile name"),{version:1,profiles}}function appProfileRevision(definition){let canonical=value=>Array.isArray(value)?`[${value.map(canonical).join(",")}]`:record2(value)?`{${Object.keys(value).sort().map(key=>`${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`:JSON.stringify(value),source=canonical(definition),left=2166136261,right=5381;for(let i2=0;i2<source.length;i2++)left=Math.imul(left^source.charCodeAt(i2),16777619),right=Math.imul(right,33)^source.charCodeAt(i2);return`v1-${(left>>>0).toString(16).padStart(8,"0")}${(right>>>0).toString(16).padStart(8,"0")}`}var BRIDGE_STYLES,APP_BRIDGE_BEHAVIORS,BEHAVIORS,init_appProfileDefinition=__esm({"../browser-core/dist/appProfileDefinition.js"(){"use strict";BRIDGE_STYLES=new Set(["windvane","fliggy","alipay","callback","btrip","invoke","callHandler","amap","didi","easybikeNative","mega","wechat","wechatMiniProgram"]),APP_BRIDGE_BEHAVIORS=["navigate","closeAll","closeBackData","postMessage","notifySubscribe","notifyUnsubscribe","notifyPost","sharedFileRead","sharedFileWrite","sharedDataGet","sharedDataSet","legacyBroadcastCreate","legacyBroadcastPost","legacyBroadcastClose","memoryGet","memorySet","memoryDelete","availabilityMap","userInfo","authCode","networkInfo","geolocation","permission","imagePicker","prefetch","fptTrack","mtopStream","previewFile","toast","unsupportedNativeInput","payment","userTrack","calendar","networkQualityMonitor","beaconRequest","voiceRecognition"],BEHAVIORS=new Set(APP_BRIDGE_BEHAVIORS)}});var init_types2=__esm({"../browser-core/dist/types.js"(){"use strict"}});function createCaptureGeneration(){return crypto.randomUUID()}function encodeCaptureCursor(cursor){return`${CURSOR_PREFIX}:${cursor.tabId}:${cursor.generation}:${cursor.scope}:${cursor.sequence}`}function decodeCaptureCursor(value){let match=value.match(/^mearl-capture-v1:(\d+):([^:]+):(all|logs|requests|events):(\d+)$/);if(!match)throw new Error("Invalid capture cursor");let tabId=Number(match[1]),sequence=Number(match[4]);if(!Number.isSafeInteger(tabId)||!Number.isSafeInteger(sequence))throw new Error("Invalid capture cursor");return{tabId,generation:match[2],scope:match[3],sequence}}function captureCheckpoint(state){return encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:state.currentSequence,scope:"all"})}function nextCaptureSequence(state){return state.currentSequence+=1,state.currentSequence}function resolveAfterSequence(after,state,scope){if(!after)return 0;let cursor=decodeCaptureCursor(after);if(cursor.tabId!==state.tabId)throw new Error(`Capture cursor belongs to tab ${cursor.tabId}, not tab ${state.tabId}`);if(cursor.generation!==state.generation)throw new Error("Capture cursor expired because the tab collector was restarted");if(cursor.scope!=="all"&&cursor.scope!==scope)throw new Error(`Capture cursor is scoped to ${cursor.scope}, not ${scope}`);if(cursor.sequence>state.currentSequence)throw new Error("Capture cursor is ahead of the current collector state");return cursor.sequence}function queryCapturedEntries(buffer,state,options,matches,droppedThroughSequence=0,scope="all"){let{after,since,now=Date.now()}=options,limit=Math.max(1,Math.floor(options.limit??100)),afterSequence=resolveAfterSequence(after,state,scope),sinceTimestampMs=since===void 0?void 0:now-since*1e3,matched=buffer.filter(entry=>entry.captureSequence>afterSequence&&(sinceTimestampMs===void 0||entry.timestampMs>=sinceTimestampMs)&&matches(entry)),hasMore=matched.length>limit,entries=after?matched.slice(0,limit):matched.slice(-limit),nextSequence=after&&hasMore&&entries.length>0?entries[entries.length-1].captureSequence:state.currentSequence;return{entries,totalMatched:matched.length,nextCursor:encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:nextSequence,scope}),hasMore,gap:after!==void 0&&afterSequence<droppedThroughSequence}}var CURSOR_PREFIX,init_capture=__esm({"../browser-core/dist/capture.js"(){"use strict";CURSOR_PREFIX="mearl-capture-v1"}});function compileTextPattern(value){try{return{regex:new RegExp(value,"i"),fallback:""}}catch{return{regex:null,fallback:value.toLowerCase()}}}function matchesTextPattern(value,pattern2){return value?pattern2.regex?pattern2.regex.test(value):value.toLowerCase().includes(pattern2.fallback):!1}function compactEventUrl(value){if(value)try{let url2=new URL(value);return url2.origin==="null"?value.split(/[?#]/,1)[0]:`${url2.origin}${url2.pathname}`}catch{return value.split(/[?#]/,1)[0]}}function formatTrackingEvent(event,includeRaw=!1){let{captureSequence:_discardedCaptureSequence,...publicEvent}=event;if(includeRaw)return publicEvent;let{_raw:_discardedRaw,_context,url:url2,...summary}=publicEvent,compactUrl=compactEventUrl(url2??_context.requestUrl);return{...summary,...compactUrl?{url:compactUrl}:{}}}function matchesTrackingEvent(event,options){let{source="all",event_type,filter}=options;if(source!=="all"&&event.source!==source||event_type&&!matchesTextPattern(event.event_type,compileTextPattern(event_type)))return!1;if(filter){let pattern2=compileTextPattern(filter);if(!matchesTextPattern(event.name,pattern2)&&!matchesTextPattern(event.url,pattern2))return!1}return!0}function queryTrackingEvents(buffer,options={}){let{source="all",event_type,filter,since,limit=20,now=Date.now()}=options,events=[...buffer].reverse();if(source!=="all"&&(events=events.filter(event=>event.source===source)),since!==void 0){let sinceTimestamp=now-since*1e3;events=events.filter(event=>event.batchTimestampMs>=sinceTimestamp)}if(event_type){let pattern2=compileTextPattern(event_type);events=events.filter(event=>matchesTextPattern(event.event_type,pattern2))}if(filter){let pattern2=compileTextPattern(filter);events=events.filter(event=>matchesTextPattern(event.name,pattern2)||matchesTextPattern(event.url,pattern2))}return{events:events.slice(0,limit),totalMatched:events.length,totalInBuffer:buffer.length}}function appendCapturedTrackingBatch(buffer,events,maxSize){if(events.length===0)return[];let captureSequence=events[0].captureSequence,insertionIndex=Number.isSafeInteger(captureSequence)?buffer.findIndex(event=>Number.isSafeInteger(event.captureSequence)&&event.captureSequence>captureSequence):-1;if(buffer.splice(insertionIndex<0?buffer.length:insertionIndex,0,...events),buffer.length<=maxSize)return[];let removeCount=buffer.length-maxSize,boundarySequence=buffer[removeCount-1]?.captureSequence;for(;boundarySequence!==void 0&&buffer[removeCount]?.captureSequence===boundarySequence;)removeCount+=1;return buffer.splice(0,removeCount)}function queryCapturedTrackingEvents(buffer,state,options={},droppedThroughSequence=0){let limit=Math.max(1,Math.floor(options.limit??20));if(!options.after){let snapshot=queryTrackingEvents(buffer,options);return{...snapshot,nextCursor:encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:state.currentSequence,scope:"events"}),hasMore:snapshot.totalMatched>limit,gap:!1}}let sinceTimestampMs=options.since===void 0?void 0:(options.now??Date.now())-options.since*1e3,batchesBySequence=new Map;for(let event of buffer){if(!Number.isSafeInteger(event.captureSequence)||sinceTimestampMs!==void 0&&event.batchTimestampMs<sinceTimestampMs||!matchesTrackingEvent(event,options))continue;let captureSequence=event.captureSequence,batch=batchesBySequence.get(captureSequence);batch?batch.events.push(event):batchesBySequence.set(captureSequence,{captureSequence,timestampMs:event.batchTimestampMs,events:[event]})}let batches=[...batchesBySequence.values()].sort((left,right)=>left.captureSequence-right.captureSequence),captured=queryCapturedEntries(batches,state,{after:options.after,limit:Number.MAX_SAFE_INTEGER},()=>!0,droppedThroughSequence,"events"),selected=[],selectedCount=0;for(let batch of captured.entries){if(selected.length>0&&selectedCount+batch.events.length>limit)break;selected.push(batch),selectedCount+=batch.events.length}let hasMore=selected.length<captured.entries.length,nextSequence=hasMore?selected[selected.length-1].captureSequence:state.currentSequence;return{events:selected.flatMap(batch=>batch.events),totalMatched:captured.entries.reduce((total,batch)=>total+batch.events.length,0),totalInBuffer:buffer.length,nextCursor:encodeCaptureCursor({tabId:state.tabId,generation:state.generation,sequence:nextSequence,scope:"events"}),hasMore,gap:captured.gap}}var TRACKING_CAPTURE_ARMED_HINT,init_eventFilters=__esm({"../browser-core/dist/eventFilters.js"(){"use strict";init_capture();TRACKING_CAPTURE_ARMED_HINT="Event capture is active, but this tab has no captured history yet. Reload the current tab or repeat the triggering action, then call get_events again."}});function parsePath(path28){if(path28.length>1e3)throw new Error("Path too long: maximum 1000 characters allowed");let keys=[],current2="";for(let i2=0;i2<path28.length;i2++){let char=path28[i2];if(char===".")current2&&(keys.push(current2),current2="");else if(char==="["){current2&&(keys.push(current2),current2="");let j=i2+1;for(;j<path28.length&&path28[j]!=="]";)j++;if(j<path28.length){let index=parseInt(path28.substring(i2+1,j),10);if(!isNaN(index)){if(index<0||index>1e5)throw new Error(`Array index out of safe range: ${index}`);keys.push(index)}i2=j}}else current2+=char}if(current2&&keys.push(current2),keys.length>50)throw new Error("Path too deep: maximum 50 levels allowed");return keys}function getValueByPath(obj,path28){let keys=parsePath(path28),current2=obj;for(let key of keys){if(current2==null)return;current2=current2[key]}return current2}function setValueByPath(obj,path28,value){let keys=parsePath(path28),current2=obj;for(let i2=0;i2<keys.length-1;i2++){let key=keys[i2],nextKey=keys[i2+1];(current2[key]===null||current2[key]===void 0)&&(current2[key]=typeof nextKey=="number"?[]:{}),current2=current2[key]}current2[keys[keys.length-1]]=value}function getStructure(data2,maxDepth=5,currentDepth=0){if(currentDepth>=maxDepth)return"<max depth reached>";if(data2===null)return"null";if(data2===void 0)return"undefined";let type=typeof data2;if(type==="string"||type==="number"||type==="boolean")return type;if(Array.isArray(data2))return data2.length===0?"array[0]":{_type:`array[${data2.length}]`,_sample:getStructure(data2[0],maxDepth,currentDepth+1)};if(type==="object"){let structure={};for(let key in data2)Object.prototype.hasOwnProperty.call(data2,key)&&(structure[key]=getStructure(data2[key],maxDepth,currentDepth+1));return structure}return type}function truncateData(data2,maxSize){let str=JSON.stringify(data2);if(str.length<=maxSize)return data2;let truncated=str.substring(0,maxSize);return`<truncated: ${str.length} bytes, showing first ${maxSize} chars>
21
21
  ${truncated}...`}function extractFields(data2,fields5){if(fields5.length>100)throw new Error("Too many fields: maximum 100 fields allowed");let result={};for(let fieldPath of fields5)try{result[fieldPath]=getValueByPath(data2,fieldPath)}catch(error62){result[fieldPath]=`<error: ${error62 instanceof Error?error62.message:"field not found"}>`}return result}function serializeRequest(request,options={}){let{fields:fields5,includeBody=!fields5?.length,includeHeaders=!1,maxBodySize=5e4,keysOnly=!1}=options,result={id:request.id,timestamp:request.timestamp,timestampMs:request.timestampMs,method:request.method,url:request.url,apiName:request.apiName,status:request.status,statusText:request.statusText,queryString:request.queryString,duration:request.duration,captureSequence:request.captureSequence,isPending:request.isPending,isSSE:request.isSSE,source:request.source,resourceType:request.resourceType};return includeHeaders&&(result.headers=request.headers,result.responseHeaders=request.responseHeaders),keysOnly?(result.postDataStructure=request.postData?getStructure(request.postData):null,result.responseBodyStructure=request.responseBody?getStructure(request.responseBody):null,result):(includeBody&&(result.postData=request.postData==null?request.postData:truncateData(request.postData,maxBodySize),result.responseBody=request.responseBody==null?request.responseBody:truncateData(request.responseBody,maxBodySize)),fields5&&fields5.length>0&&(result.extractedFields=extractFields(request.responseBody,fields5)),result)}var init_requestSerializer=__esm({"../browser-core/dist/requestSerializer.js"(){"use strict"}});function byteLength(value){return textEncoder.encode(value).byteLength}function serializeForStorage(value){if(typeof value=="string")return value;try{return JSON.stringify(value)}catch{return String(value)}}function truncateUtf8(value,maxBytes){if(byteLength(value)<=maxBytes)return value;let low=0,high=Math.min(value.length,maxBytes);for(;low<high;){let middle=Math.ceil((low+high)/2);byteLength(value.slice(0,middle))<=maxBytes?low=middle:high=middle-1}return value.slice(0,low)}function limitBufferedField(value,maxBytes){if(value==null)return value;let serialized=serializeForStorage(value),originalBytes=byteLength(serialized);if(originalBytes<=maxBytes)return value;let marker=`<truncated: ${originalBytes} bytes, buffered preview>
22
22
  `;if(byteLength(marker)+3>maxBytes)return truncateUtf8(`${marker}...`,maxBytes);let previewBudget=Math.max(0,maxBytes-byteLength(marker)-3);return`${marker}${truncateUtf8(serialized,previewBudget)}...`}function estimateRequestBufferBytes(request){try{return byteLength(JSON.stringify(request))}catch{return byteLength(String(request))}}function createRequestBufferAccounting(){return{sizes:[],totalBytes:0}}function synchronizeAccounting(requests,accounting){accounting.sizes.length!==requests.length&&(accounting.sizes=requests.map(estimateRequestBufferBytes),accounting.totalBytes=accounting.sizes.reduce((total,size)=>total+size,0))}function applyFieldLimits(request,maxFieldBytes){request.postData=limitBufferedField(request.postData,maxFieldBytes),request.responseBody=limitBufferedField(request.responseBody,maxFieldBytes)}function trimRequestBuffer(requests,accounting,maxEntries,maxBytes){let removed=[];for(;requests.length>1&&(requests.length>maxEntries||accounting.totalBytes>maxBytes);){let request=requests.shift();request&&removed.push(request),accounting.totalBytes-=accounting.sizes.shift()??0}return removed}function appendRequestToBuffer(requests,accounting,request,limits={}){let{maxEntries=500,maxBytes=33554432,maxFieldBytes=8388608}=limits;synchronizeAccounting(requests,accounting),applyFieldLimits(request,maxFieldBytes);let size=estimateRequestBufferBytes(request);return requests.push(request),accounting.sizes.push(size),accounting.totalBytes+=size,trimRequestBuffer(requests,accounting,maxEntries,maxBytes)}function refreshRequestInBuffer(requests,accounting,request,limits={}){let{maxEntries=500,maxBytes=33554432,maxFieldBytes=8388608}=limits,index=requests.indexOf(request);if(index===-1)return[];synchronizeAccounting(requests,accounting),applyFieldLimits(request,maxFieldBytes);let previousSize=accounting.sizes[index]??0,nextSize=estimateRequestBufferBytes(request);return accounting.sizes[index]=nextSize,accounting.totalBytes+=nextSize-previousSize,trimRequestBuffer(requests,accounting,maxEntries,maxBytes)}var textEncoder,init_boundedRequestBuffer=__esm({"../browser-core/dist/boundedRequestBuffer.js"(){"use strict";textEncoder=new TextEncoder}});var DomainPermissionError,ALLOWED_ORIGINS,ALLOWED_ORIGINS_LIST,init_proxyPermissions=__esm({"../browser-core/dist/proxyPermissions.js"(){"use strict";DomainPermissionError=class extends Error{action;domain;code="DOMAIN_PERMISSION_REQUIRED";requestDispatched=!1;constructor(action,domain2,message=`${action}: Access to "${domain2}" is not authorized. Call request_domain_permission with domain="${domain2}" to request user authorization, then retry.`){super(message),this.action=action,this.domain=domain2,this.name="DomainPermissionError"}},ALLOWED_ORIGINS=["*://localhost/*","*://127.0.0.1/*"],ALLOWED_ORIGINS_LIST=[...ALLOWED_ORIGINS]}});function typeIntoElement(el,inputValue,shouldClear){if(!el)return{typed:!1,tag:"",error:"Element is null"};if(!el.isConnected)return{typed:!1,tag:"",error:"Element is detached from the document"};let tagName=el.tagName?el.tagName.toLowerCase():"",isInput=el instanceof HTMLInputElement,isTextArea=el instanceof HTMLTextAreaElement,isFormField=isInput||isTextArea,htmlEl=el,isEditable=!isFormField&&(htmlEl.isContentEditable||el.getAttribute("contenteditable")==="true");if(!isFormField&&!isEditable)return{typed:!1,tag:tagName,error:"Element <"+tagName+"> is neither an input/textarea nor contenteditable"};if(isFormField){let f=el;if(f.disabled)return{typed:!1,tag:tagName,error:"Element is disabled"};if(f.readOnly)return{typed:!1,tag:tagName,error:"Element is readOnly"}}if(htmlEl.scrollIntoView({block:"center",behavior:"instant"}),htmlEl.focus(),isFormField){let f=el,proto=isTextArea?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,nativeSetter=Object.getOwnPropertyDescriptor(proto,"value")?.set,setVal=v=>{nativeSetter?nativeSetter.call(f,v):f.value=v};return shouldClear&&f.value!==""&&(setVal(""),f.dispatchEvent(new Event("input",{bubbles:!0}))),setVal(inputValue),f.dispatchEvent(new InputEvent("beforeinput",{bubbles:!0,cancelable:!0,data:inputValue,inputType:"insertText"})),f.dispatchEvent(new InputEvent("input",{bubbles:!0,data:inputValue,inputType:"insertText"})),f.dispatchEvent(new Event("change",{bubbles:!0})),{typed:!0,tag:tagName}}let selection2=window.getSelection();if(shouldClear){if(selection2){let range2=document.createRange();range2.selectNodeContents(htmlEl),selection2.removeAllRanges(),selection2.addRange(range2)}let cleared;try{cleared=document.execCommand("delete")}catch{cleared=!1}cleared||(htmlEl.textContent="")}else if(selection2){let range2=document.createRange();range2.selectNodeContents(htmlEl),range2.collapse(!1),selection2.removeAllRanges(),selection2.addRange(range2)}htmlEl.dispatchEvent(new InputEvent("beforeinput",{bubbles:!0,cancelable:!0,data:inputValue,inputType:"insertText"}));let inserted;try{inserted=document.execCommand("insertText",!1,inputValue)}catch{inserted=!1}return inserted||(htmlEl.textContent=(htmlEl.textContent??"")+inputValue),htmlEl.dispatchEvent(new InputEvent("input",{bubbles:!0,data:inputValue,inputType:"insertText"})),{typed:!0,tag:tagName}}var init_domTyping=__esm({"../browser-core/dist/domTyping.js"(){"use strict"}});function validatePageElementSelector(selector,toolName){if(!selector||typeof selector!="string")throw new Error(`${toolName}: "selector" must be a non-empty string. Pass a native CSS selector (e.g. "[aria-label='提交']") or a snapshot ref like "@e3". Note: the field name is "selector", not "ref".`);if(/^e\d+$/.test(selector))throw new Error(`${toolName}: selector "${selector}" looks like a snapshot ref but is missing the "@" prefix. Use "@${selector}" instead. If you don't have refs yet, call page_snapshot first.`);for(let pseudo of UNSUPPORTED_NATIVE_SELECTOR_PSEUDOS)if(selector.includes(pseudo))throw new Error(`${toolName}: selector contains unsupported pseudo "${pseudo}". Only native CSS selectors are supported (no Playwright/jQuery extensions). For text-based matching, run page_snapshot and use the returned "@eN" ref. For attribute matching, prefer "[aria-label='...']", "[title='...']", "[data-testid='...']" etc.`)}var UNSUPPORTED_NATIVE_SELECTOR_PSEUDOS,INVALID_NATIVE_SELECTOR_HINT,init_domSelectors=__esm({"../browser-core/dist/domSelectors.js"(){"use strict";UNSUPPORTED_NATIVE_SELECTOR_PSEUDOS=[":has-text",":text(",":text-is(",":text-matches(",":visible",":hidden",":nth-match(",":light(",":above(",":below(",":near(",":left-of(",":right-of(",":contains("],INVALID_NATIVE_SELECTOR_HINT='Only native CSS is supported (no Playwright extensions like :has-text/:visible). Use page_snapshot to get an "@eN" ref for complex matching.'}});function resolvePageScrollInput(data2){let{direction,distance,selector,containerPolicy="self"}=data2;if(typeof direction!="string"||!["up","down","top","bottom"].includes(direction))throw new Error("Invalid direction: must be one of up, down, top, bottom");if(distance!==void 0&&(typeof distance!="number"||!Number.isFinite(distance)))throw new Error('"distance" must be a finite number');if(selector!==void 0&&validatePageElementSelector(selector,"page_scroll"),containerPolicy!=="self"&&containerPolicy!=="nearest")throw new Error('"containerPolicy" must be one of self, nearest');return{direction,distance:Math.abs(distance??600),containerPolicy,...selector!==void 0?{selector}:{}}}function scrollElementInPage(direction,distance,targetLabel,containerPolicy="self"){let element=this?.nodeType===3?this.parentElement:this,targetDocument=element?.nodeType===9?element:null;if(targetDocument&&(element=targetDocument.scrollingElement),!element||element.isConnected===!1)return{error:"Cannot resolve scroll container: "+targetLabel};let startingElement=element,ancestorDistance=0;function scrollMetrics(candidate){let scrollTop=Number(candidate?.scrollTop),scrollHeight=Number(candidate?.scrollHeight),clientHeight=Number(candidate?.clientHeight);if(!Number.isFinite(scrollTop)||!Number.isFinite(scrollHeight)||!Number.isFinite(clientHeight))return null;let ownerDocument=candidate.ownerDocument,isRootScroller=!!ownerDocument&&candidate===ownerDocument.scrollingElement,maxScrollTop=Math.max(0,scrollHeight-clientHeight),overflowAllowsScroll=!0;try{let overflowY=ownerDocument?.defaultView?.getComputedStyle(candidate).overflowY;!isRootScroller&&(overflowY==="visible"||overflowY==="clip")&&(overflowAllowsScroll=!1)}catch{}return{scrollTop,scrollHeight,clientHeight,maxScrollTop,isRootScroller,usable:isRootScroller||maxScrollTop>0&&overflowAllowsScroll}}function documentFallback(documentRef){let windowRef=documentRef.defaultView,visited=new Set,viewportWidth=Number(windowRef?.innerWidth)||Number(element?.clientWidth)||0,viewportHeight=Number(windowRef?.innerHeight)||Number(element?.clientHeight)||0,points=[[viewportWidth/2,viewportHeight/2],[viewportWidth/2,viewportHeight*.75],[viewportWidth/2,viewportHeight*.25]];function containerDepth(candidate){if(candidate===documentRef.body||candidate===documentRef.documentElement)return 0;let depth=0,cursor=candidate;for(;cursor&&cursor!==documentRef.body&&cursor!==documentRef.documentElement;)depth+=1,cursor=cursor.parentElement;return depth}function canMove(metrics2){return direction==="up"||direction==="top"?metrics2.scrollTop>0:metrics2.scrollTop<metrics2.maxScrollTop}let sampledPageContainer;for(let[x,y]of points){let candidate=null;try{candidate=documentRef.elementFromPoint?.(x,y)??null}catch{}for(;candidate&&candidate.nodeType===1;){if(!visited.has(candidate)){visited.add(candidate);let candidateMetrics=scrollMetrics(candidate);if(candidateMetrics?.usable&&candidateMetrics.maxScrollTop>0&&canMove(candidateMetrics)){let resolved={element:candidate,metrics:candidateMetrics,distance:containerDepth(candidate)};if(candidate===documentRef.body||candidate===documentRef.documentElement)sampledPageContainer??=resolved;else return resolved}}candidate=candidate.parentElement}}if(sampledPageContainer)return sampledPageContainer;let best,candidates=Array.from(documentRef.querySelectorAll?.("*")??[]).slice(0,1e4);for(let candidate of candidates){let candidateMetrics=scrollMetrics(candidate);if(!candidateMetrics?.usable||candidateMetrics.maxScrollTop<=0||!canMove(candidateMetrics))continue;let rect,style;try{rect=candidate.getBoundingClientRect(),style=windowRef?.getComputedStyle(candidate)}catch{continue}if(!rect||rect.width<=0||rect.height<=0||style?.display==="none"||style?.visibility==="hidden"||style?.visibility==="collapse")continue;let visibleWidth=Math.max(0,Math.min(rect.right,viewportWidth)-Math.max(rect.left,0)),visibleHeight=Math.max(0,Math.min(rect.bottom,viewportHeight)-Math.max(rect.top,0)),area=visibleWidth*visibleHeight;if(area<=0)continue;let depth=containerDepth(candidate);(!best||depth<best.distance||depth===best.distance&&area>best.area)&&(best={element:candidate,metrics:candidateMetrics,distance:depth,area})}return best?{element:best.element,metrics:best.metrics,distance:best.distance}:null}function selectorFor(candidate){let documentRef=candidate?.ownerDocument;if(!documentRef||candidate.nodeType!==1)return"";if(candidate===documentRef.documentElement)return"html";if(candidate===documentRef.body)return"body";let escapeCss=value=>documentRef.defaultView?.CSS?.escape?documentRef.defaultView.CSS.escape(value):value.replace(/[^a-zA-Z0-9_-]/g,character=>"\\"+character);if(candidate.id){let idSelector="#"+escapeCss(String(candidate.id));try{if(documentRef.querySelectorAll(idSelector).length===1)return idSelector}catch{}}let path28=[],cursor=candidate;for(;cursor&&cursor.nodeType===1&&path28.length<8;){let tag=String(cursor.tagName||"").toLowerCase();if(!tag)break;let parent=cursor.parentElement;if(!parent){path28.unshift(tag);break}let siblings=Array.from(parent.children).filter(sibling2=>sibling2.tagName===cursor.tagName),index=siblings.indexOf(cursor)+1;if(path28.unshift(siblings.length>1?tag+":nth-of-type("+index+")":tag),cursor=parent,cursor===documentRef.documentElement){path28.unshift("html");break}}return path28.join(" > ")}let metrics=scrollMetrics(element);if(!metrics)return{error:"Element is not scrollable: "+targetLabel};if(targetDocument){let fallback=documentFallback(targetDocument);fallback&&(element=fallback.element,metrics=fallback.metrics,ancestorDistance=fallback.distance)}if(!metrics.usable&&containerPolicy==="nearest"){let candidate=element.parentElement;for(;candidate;){ancestorDistance+=1;let candidateMetrics=scrollMetrics(candidate);if(candidateMetrics?.usable){element=candidate,metrics=candidateMetrics;break}candidate=candidate.parentElement}}if(!metrics.usable&&!metrics.isRootScroller)return{error:"Element is not scrollable: "+targetLabel+(containerPolicy==="nearest"?" (no scrollable ancestor found)":"")};let targetTop;switch(direction){case"top":targetTop=0;break;case"bottom":targetTop=metrics.maxScrollTop;break;case"up":targetTop=Math.max(0,metrics.scrollTop-Math.abs(distance));break;default:targetTop=Math.min(metrics.maxScrollTop,metrics.scrollTop+Math.abs(distance));break}if(typeof element.scrollTo=="function")try{element.scrollTo({top:targetTop,left:Number(element.scrollLeft)||0,behavior:"instant"})}catch{element.scrollTop=targetTop}else element.scrollTop=targetTop;let actualScrollTop=Number(element.scrollTop);return!metrics.isRootScroller&&targetTop!==metrics.scrollTop&&actualScrollTop===metrics.scrollTop?{error:"Element is not scrollable: "+targetLabel}:{scrollY:Math.round(actualScrollTop),scrollHeight:metrics.scrollHeight,clientHeight:metrics.clientHeight,maxScrollY:Math.round(metrics.maxScrollTop),scrollYBefore:Math.round(metrics.scrollTop),scrollYAfter:Math.round(actualScrollTop),moved:actualScrollTop!==metrics.scrollTop,atTop:actualScrollTop<=0,atBottom:actualScrollTop>=metrics.maxScrollTop,target:targetLabel,resolvedContainer:targetDocument&&element===targetDocument.body&&element!==startingElement?"document-body":targetDocument&&element!==startingElement?"document-descendant":element===startingElement?"self":"nearest-scrollable-ancestor",ancestorDistance,...targetDocument&&element!==startingElement?{containerSelector:selectorFor(element)}:{}}}function buildPageScrollExpression(input3){return`(() => {
23
23
  const dir = ${JSON.stringify(input3.direction)};
@@ -96,10 +96,10 @@ ${SOURCE_BADGES[source]}
96
96
  `}}});function parseSseDataValue(value){try{return JSON.parse(value)}catch{return value}}function createSseEventParser(){let buffer="",eventName="",lastEventId,dataLines=[],hasData=!1,dispatch=()=>{if(!hasData)return eventName="",dataLines=[],[];let rawData=dataLines.join(`
97
97
  `);if(eventName=eventName||"message",dataLines=[],hasData=!1,rawData==="[DONE]")return eventName="",[];let event={event:eventName,data:parseSseDataValue(rawData),...lastEventId!==void 0?{eventId:lastEventId}:{}};return eventName="",[event]},consumeLine=line=>{if(line==="")return dispatch();if(line.startsWith(":"))return[];let separator=line.indexOf(":"),field=separator===-1?line:line.slice(0,separator),value=separator===-1?"":line.slice(separator+1);return value.startsWith(" ")&&(value=value.slice(1)),field==="data"?(dataLines.push(value),hasData=!0):field==="event"?eventName=value:field==="id"&&!value.includes("\0")&&(lastEventId=value),[]},drain=final=>{let events=[];for(;buffer.length>0;){let newlineIndex=-1;for(let index=0;index<buffer.length;index++)if(buffer[index]===`
98
98
  `||buffer[index]==="\r"){newlineIndex=index;break}if(newlineIndex===-1){final&&(events.push(...consumeLine(buffer)),buffer="");break}if(buffer[newlineIndex]==="\r"&&newlineIndex===buffer.length-1&&!final)break;let line=buffer.slice(0,newlineIndex),separatorLength=buffer[newlineIndex]==="\r"&&buffer[newlineIndex+1]===`
99
- `?2:1;buffer=buffer.slice(newlineIndex+separatorLength),events.push(...consumeLine(line))}return final&&events.push(...dispatch()),events};return{push(chunk){return buffer+=chunk,drain(!1)},finish(){return drain(!0)}}}var init_sseParser=__esm({"../browser-core/dist/sseParser.js"(){"use strict"}});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 json4=JSON.stringify(responseData)??"null";if(typeof responseData=="string")try{JSON.parse(responseData),json4=responseData}catch{}return{body:`${callback}(${json4});`,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 JSONP_CALLBACK_RE,JSONP_CONTENT_TYPE,init_mockResponse=__esm({"../browser-core/dist/mockResponse.js"(){"use strict";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"}});var init_pluginState=__esm({"../browser-core/dist/pluginState.js"(){"use strict"}});var init_pluginModels=__esm({"../browser-core/dist/pluginModels.js"(){"use strict"}});var init_pluginRecovery=__esm({"../browser-core/dist/pluginRecovery.js"(){"use strict"}});var init_pluginDiagnostics=__esm({"../browser-core/dist/pluginDiagnostics.js"(){"use strict"}});function installRootWebViewDocumentTransport(){let browser=window,prefix="/.mearl-document/";if(browser.name==="__mearl_root__"&&location.pathname.startsWith(prefix))try{let original=new URL(decodeURIComponent(location.hash.slice(1)));original.origin===location.origin&&/^https?:$/.test(original.protocol)&&history.replaceState(history.state,"",original.href)}catch{}browser.__mearlRootDocumentUrl__=url2=>{let token=performance.getEntriesByType("navigation")[0]?.serverTiming?.find(entry=>entry.name==="mearl-document")?.description;if(!token||!/^[a-zA-Z0-9-]+$/.test(token))return url2;let original=new URL(url2);return`${original.origin}${prefix}${token}#${encodeURIComponent(original.href)}`}}var init_rootWebViewDocument=__esm({"../browser-core/dist/rootWebViewDocument.js"(){"use strict"}});function isBrowserManagementAction(value){return typeof value=="string"&&Object.hasOwn(BROWSER_MANAGEMENT_ACTIONS,value)}function isCloudConnectorAction(value){return typeof value=="string"&&Object.hasOwn(CLOUD_CONNECTOR_ACTIONS,value)}function isExtensionUiServiceAction(value){return isAgentServiceAction(value)||isToolboxServiceAction(value)||isBrowserManagementAction(value)||isCloudConnectorAction(value)}function isHostToExtensionAction(value){return typeof value=="string"&&Object.hasOwn(HOST_TO_EXTENSION_ACTIONS,value)}function isPrivateExtensionServiceAction(value){return isToolboxServiceAction(value)||isAgentServiceAction(value)&&value!=="agent_chat_run"||typeof value=="string"&&["browser_sessions","browser_instances","browser_providers"].includes(value)||typeof value=="string"&&Object.hasOwn(EXTENSION_BACKGROUND_ACTIONS,value)}function extensionRpcErrorCode(error62){let code=error62&&typeof error62=="object"&&"code"in error62?error62.code:void 0;return code==="PROTOCOL_MISMATCH"||code==="UNSUPPORTED_ACTION"||code==="EXTENSION_UI_REQUIRED"?code:void 0}var EXTENSION_RPC_VERSION,BROWSER_MANAGEMENT_ACTIONS,CLOUD_CONNECTOR_ACTIONS,HOST_TO_EXTENSION_ACTIONS,EXTENSION_BACKGROUND_ACTIONS,ExtensionRpcError,init_extensionServiceProtocol=__esm({"../browser-core/dist/extensionServiceProtocol.js"(){"use strict";init_agentServiceProtocol();init_toolbox();EXTENSION_RPC_VERSION=1,BROWSER_MANAGEMENT_ACTIONS={browser_sessions:!0,browser_instances:!0,browser_providers:!0,browser_list:!0,browser_launch:!0,browser_close:!0,get_browser_access_url:!0};CLOUD_CONNECTOR_ACTIONS={start_cloud_connector:!0,stop_cloud_connector:!0,list_cloud_connectors:!0};HOST_TO_EXTENSION_ACTIONS={__preset_installation:!0,__preset_browser:!0,__export_cookies:!0,__capture_download:!0,__control_cleanup:!0,__control_deactivate:!0,__send_request_files:!0};EXTENSION_BACKGROUND_ACTIONS={preset_installation:!0,preset_browser_transfer:!0,app_profile_catalog:!0,plugin_page_call:!0,plugin_page_event:!0};ExtensionRpcError=class extends Error{code;constructor(code,message){super(message),this.code=code,this.name="ExtensionRpcError"}}}});var init_requestStreamCapture=__esm({"../browser-core/dist/requestStreamCapture.js"(){"use strict"}});var init_responseText=__esm({"../browser-core/dist/responseText.js"(){"use strict"}});var init_consumeSseResponse=__esm({"../browser-core/dist/consumeSseResponse.js"(){"use strict";init_sseParser()}});var init_queryString=__esm({"../browser-core/dist/queryString.js"(){"use strict"}});function extensionManifestVersion(release){let match=RELEASE.exec(release);if(!match)throw new Error("Invalid extension release version");let parts=match.slice(1,4).map(Number),build=match[4]===void 0?65535:Number(match[4]);if(parts.some(value=>value>65535)||build>65535||match[4]!==void 0&&build===65535)throw new Error("Extension release version exceeds Chrome numeric limits");return{version:[...parts,build].join("."),version_name:release}}function readExtensionReleaseVersion(manifest){if(typeof manifest.version!="string")return null;if(manifest.version_name===void 0){let match=RELEASE.exec(manifest.version);return match&&match[4]===void 0&&match.slice(1,4).every(value=>Number(value)<=65535)?manifest.version:null}if(typeof manifest.version_name!="string")return null;try{return extensionManifestVersion(manifest.version_name).version===manifest.version?manifest.version_name:null}catch{return null}}var RELEASE,init_extensionVersion=__esm({"../browser-core/dist/extensionVersion.js"(){"use strict";RELEASE=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-beta\.(0|[1-9]\d*))?$/}});var MEARL_NATIVE_HOST_NAMES,init_nativeHostNames=__esm({"../browser-core/dist/nativeHostNames.js"(){"use strict";MEARL_NATIVE_HOST_NAMES={skills:"ai.mearl.skills",mcp:"ai.mearl.mcp"}}});var init_dist5=__esm({"../browser-core/dist/index.js"(){"use strict";init_appProfileDefinition();init_types2();init_eventFilters();init_requestSerializer();init_boundedRequestBuffer();init_proxyPermissions();init_domTyping();init_domSelectors();init_domScrolling();init_domInspection();init_domSnapshot();init_deviceEmulation();init_debuggerTarget();init_rootWebViewNavigation();init_axTextMatch();init_domClicking();init_pageDragging();init_pagePressing();init_axSnapshot();init_pageObserver();init_navigationTracker();init_pageAct();init_backendNodeRefs();init_pageEffectRefs();init_pageWait();init_pageNavigation();init_tabMatching();init_agentChat();init_agentSkills();init_agentServiceProtocol();init_toolbox();init_toolboxIcon();init_pluginExecution();init_pluginTasks();init_pluginPages();init_pluginPageRuntime();init_pluginPageHost();init_browserActionProtocol();init_runActions();init_sendRequestFiles();init_sendRequestHeaders();init_cookie();init_controlledFavicon();init_capture();init_sseParser();init_mockResponse();init_pluginState();init_pluginModels();init_pluginRecovery();init_pluginDiagnostics();init_rootWebViewDocument();init_extensionServiceProtocol();init_requestStreamCapture();init_responseText();init_consumeSseResponse();init_queryString();init_extensionVersion();init_nativeHostNames()}});import fs3 from"node:fs";import os from"node:os";import path4 from"node:path";function resolveNativeHostDirectory(options={}){let env=options.env??process.env,home=(options.homedir??os.homedir)();switch(options.platform??process.platform){case"darwin":return path4.join(home,"Library/Application Support/Google/Chrome/NativeMessagingHosts");case"linux":return path4.join(home,".config/google-chrome/NativeMessagingHosts");case"win32":return path4.join(env.PROGRAMDATA||"C:\\ProgramData","Google\\Chrome\\NativeMessagingHosts");default:throw new Error(`Unsupported platform: ${String(options.platform??process.platform)}`)}}function readLauncherMetadata(content){let metadata=content.match(/^(?:#|rem) mearl-native-host-launcher: (.+)\r?$/m);if(metadata){let parsed=JSON.parse(metadata[1]);if(parsed.version===1&&Array.isArray(parsed.nodePaths)&&parsed.nodePaths.length>0&&parsed.nodePaths.every(value=>typeof value=="string"&&path4.isAbsolute(value))&&typeof parsed.hostPath=="string"&&path4.isAbsolute(parsed.hostPath))return{version:1,nodePaths:parsed.nodePaths,hostPath:parsed.hostPath};throw new Error("Invalid native host launcher metadata")}let node2=content.match(/^NODE_BIN=(".*")\r?$/m),host=content.match(/^HOST_SCRIPT=(".*")\r?$/m);if(!node2||!host)return null;let nodePath=JSON.parse(node2[1]),hostPath=JSON.parse(host[1]);if(typeof nodePath!="string"||!path4.isAbsolute(nodePath)||typeof hostPath!="string"||!path4.isAbsolute(hostPath))throw new Error("Invalid native host launcher paths");return{version:1,nodePaths:[nodePath],hostPath}}function inspectNativeHostInstallation(options={}){let platform=options.platform??process.platform;if(!["darwin","linux","win32"].includes(platform))return[];let hostDir=options.hostDir??resolveNativeHostDirectory(options),diagnostics=[],isUsable=(filePath,executable)=>{try{return fs3.accessSync(filePath,executable&&platform!=="win32"?fs3.constants.X_OK:fs3.constants.R_OK),fs3.statSync(filePath).isFile()}catch{return!1}};for(let hostName of Object.values(MEARL_NATIVE_HOST_NAMES)){let manifestPath=path4.join(hostDir,`${hostName}.json`),details=[];try{let manifest=JSON.parse(fs3.readFileSync(manifestPath,"utf-8"));if(typeof manifest?.path!="string"||!path4.isAbsolute(manifest.path))details.push(`Invalid launcher path in ${manifestPath}`);else if(!isUsable(manifest.path,!0))details.push(`Launcher is missing or not executable: ${manifest.path}`);else{let metadata=readLauncherMetadata(fs3.readFileSync(manifest.path,"utf-8"));metadata&&(metadata.nodePaths.some(candidate=>isUsable(candidate,!0))||details.push(`No executable Node.js found. Launcher candidates: ${metadata.nodePaths.join(", ")}`),isUsable(metadata.hostPath,!1)||details.push(`Native host runtime script is missing or unreadable: ${metadata.hostPath}`))}}catch(error62){if(error62.code==="ENOENT"&&!fs3.existsSync(manifestPath))continue;details.push(`Cannot inspect ${manifestPath}: ${error62 instanceof Error?error62.message:String(error62)}`)}details.length&&diagnostics.push({label:`Native Messaging registration needs repair: ${hostName}`,details:[...details,`Registration: ${manifestPath}`,"Run `mearl-native-host init` with a working Node.js, then reopen the extension. If the runtime package is missing, run `npx @mearl/setup update --local`."]})}return diagnostics}var init_nativeHost=__esm({"../client/dist/nativeHost.js"(){"use strict";init_dist5()}});import{randomUUID as randomUUID7}from"node:crypto";async function invokePageEvalWithArgs(invoke3,params){if(!Number.isSafeInteger(params.tabId)||params.tabId<0)throw new Error("Invalid target tab");if(resolvePageEvalExpression({expression:params.expression,args:[]}),!Array.isArray(params.args))throw new Error("page_eval args must be an array");if(params.executionWorld!==void 0&&!["main","isolated"].includes(params.executionWorld))throw new Error("Invalid page executionWorld");params.executionWorld==="isolated"&&validatePageUserScriptParams({tabId:params.tabId,worldId:params.worldId??"",code:params.expression});let args=JSON.stringify(params.args);if(args.length>64*1024*1024)throw new Error("Page script arguments must fit within 64 MiB characters");let{args:_args,...request}=params,evaluate=async(expression,transfer=!1)=>{let payload={...request,...transfer?{observe:!1,diagnostics:!1}:{},expression},result=await(transfer?invoke3(payload,!0):invoke3(payload));if(transfer&&result?.action?.success===!1)throw new Error(result.action.error||"page_eval failed");return result};if(args.length+params.expression.length<=CHUNK_CHARACTERS)return evaluate(resolvePageEvalExpression(params));let key=JSON.stringify("__mearlPageScriptTransfer_"+randomUUID7());try{for(let offset2=0;offset2<args.length;offset2+=CHUNK_CHARACTERS)await evaluate(`void (window[${key}] = (window[${key}] || '') + ${JSON.stringify(args.slice(offset2,offset2+CHUNK_CHARACTERS))})`,!0);return await evaluate(`(() => { const args = JSON.parse(window[${key}]); delete window[${key}]; return (${params.expression})(...args); })()`)}finally{await evaluate(`delete window[${key}]`,!0).catch(()=>{})}}var CHUNK_CHARACTERS,init_pageEvalArguments=__esm({"../client/dist/pageEvalArguments.js"(){"use strict";init_dist5();CHUNK_CHARACTERS=48*1024}});import{open as open2,mkdir,rename,rm,stat}from"node:fs/promises";import path5 from"node:path";import{randomUUID as randomUUID8}from"node:crypto";async function stageFile(client2,filePath,options){if(!path5.isAbsolute(filePath))throw new Error("Caller-local file paths must be absolute");let source=await open2(filePath,"r"),id2,pinned=options;try{let metadata=await source.stat();if(!metadata.isFile()||metadata.size>256*1024*1024)throw new Error("Upload requires a regular file of at most 256 MiB");let created=await client2.invoke("__artifact_init",{filename:path5.basename(filePath)},options);pinned={...options,browser:created.browserId},id2=created.artifact.artifactId;let offset2=0;for await(let chunk of source.createReadStream({highWaterMark:CHUNK_BYTES,autoClose:!1}))await client2.invoke("__artifact_write",{artifactId:id2,offset:offset2,base64:chunk.toString("base64")},pinned),offset2+=chunk.length;return await client2.invoke("__artifact_complete",{artifactId:id2,bytes:offset2},pinned),{artifactId:id2,options:pinned}}catch(error62){throw id2&&await client2.invoke("__artifact_remove",{artifactId:id2},pinned).catch(()=>{}),error62}finally{await source.close()}}async function exportArtifact(client2,artifact,outputPath2,options={}){if(!Number.isSafeInteger(artifact.bytes)||artifact.bytes<0)throw new Error("Invalid artifact size");if(!path5.isAbsolute(outputPath2))throw new Error("Artifact output paths must be absolute");if(!options.session&&!artifact.browserId&&!options.browser)throw new Error("An artifact requires its originating browser");let pinned={...options,...artifact.browserId?{browser:artifact.browserId}:{}};await mkdir(path5.dirname(outputPath2),{recursive:!0});let temporary=`${outputPath2}.${randomUUID8()}.part`,target=await open2(temporary,"wx",384);try{let offset2=0;if(artifact.bytes===0){let empty2=await client2.invoke("__artifact_read",{artifactId:artifact.artifactId,offset:0},pinned);if(empty2.totalBytes!==0||empty2.bytes!==0||empty2.base64!=="")throw new Error("Artifact export size mismatch")}for(;offset2<artifact.bytes;){let chunk=await client2.invoke("__artifact_read",{artifactId:artifact.artifactId,offset:offset2},pinned),bytes=Buffer.from(chunk.base64,"base64");if(!bytes.length||bytes.length!==chunk.bytes||chunk.totalBytes!==artifact.bytes||offset2+bytes.length>artifact.bytes)throw new Error("Invalid artifact chunk or truncated transfer");await target.write(bytes),offset2+=bytes.length}if(await target.sync(),await target.close(),(await stat(temporary)).size!==artifact.bytes)throw new Error("Artifact export size mismatch");return await rename(temporary,outputPath2),{outputPath:outputPath2,bytes:artifact.bytes}}catch(error62){throw await target.close().catch(()=>{}),await rm(temporary,{force:!0}),error62}}var CHUNK_BYTES,init_artifacts=__esm({"../client/dist/artifacts.js"(){"use strict";CHUNK_BYTES=256*1024}});function resolveCloudConnectorSelector(connectors,selector){let normalized=selector.trim().toLowerCase();if(!normalized)return{status:"not_found"};let resolveMatches=matches=>matches.length===1?{status:"matched",connector:matches[0]}:matches.length>1?{status:"ambiguous"}:null,exactId=resolveMatches(connectors.filter(connector=>connector.connectorId.toLowerCase()===normalized));if(exactId)return exactId;let exactName=resolveMatches(connectors.filter(connector=>connector.name.toLowerCase()===normalized));return exactName||(resolveMatches(connectors.filter(connector=>connector.connectorId.toLowerCase().includes(normalized)||connector.name.toLowerCase().includes(normalized)))??{status:"not_found"})}function isHeartbeatMessage(msg){return msg&&(msg.type==="ping"||msg.type==="pong")}var init_dist6=__esm({"../cloud/cloud-types/dist/index.js"(){"use strict"}});function boundedNumber2(value,fallback,minimum,maximum){let numeric=Number(value);return Number.isFinite(numeric)?Math.min(Math.max(numeric,minimum),maximum):fallback}function resolveObservedActionTimeoutSec(data2){let observe=data2.observe??{},observationMs=boundedNumber2(observe.timeoutMs,3e3,500,3e4),navigationGraceMs=boundedNumber2(observe.navigationGraceMs,1e3,0,5e3),navigationTimeoutMs=boundedNumber2(observe.navigationTimeoutMs,15e3,1e3,3e4),totalMs=observationMs+navigationGraceMs+4e3+navigationTimeoutMs+5e3;return Math.max(20,Math.ceil(totalMs/1e3))}function resolveActionTimeoutSec(action,data2,fallback=15){if(action==="send_request"){let transferTimeoutMs=data2.bodyFile!==void 0||Array.isArray(data2.files)&&data2.files.length>0?SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS:0;return Math.max(fallback,Math.ceil(((data2.timeout??3e4)+transferTimeoutMs+5e3)/1e3))}if(action==="send_mtop_request")return Math.max(fallback,Math.ceil(((data2.timeout??1e4)+5e3)/1e3));if(action==="page_download")return Math.max(fallback,Math.ceil((Number(data2.timeout??3e4)+1e4)/1e3));if(action==="page_wait"){let waitMs=data2.time??data2.timeout??1e4;return Math.max(fallback,Math.ceil((Number(waitMs)+5e3)/1e3))}if(action==="tab_open"||action==="set_cookie"&&data2.reload===!0)return Math.max(fallback,40);if(action==="browser_launch")return Math.max(fallback,90);if(action==="browser_close")return Math.max(fallback,BROWSER_CLOSE_TIMEOUT_SEC);if(action==="run_actions"){let timeoutSec=(Array.isArray(data2.actions)?data2.actions:[{}]).reduce((total,step)=>{let stepAction=String(step?.action??"");return!stepAction||stepAction==="run_actions"?total+15:total+resolveActionTimeoutSec(stepAction,step?.data??{},15)},0);return Math.max(fallback,timeoutSec)}let observedAction=OBSERVED_PAGE_ACTIONS.has(action),observationEnabled=action==="page_eval"?data2.observe!==null&&typeof data2.observe=="object"&&!Array.isArray(data2.observe):data2.observe!==!1;if(action==="page_upload"){let actionTimeoutSec=observationEnabled?resolveObservedActionTimeoutSec(data2):fallback;return Math.max(fallback,actionTimeoutSec+Math.ceil(PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS/1e3))}return observedAction&&observationEnabled?Math.max(fallback,resolveObservedActionTimeoutSec(data2)):fallback}var SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS,PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS,BROWSER_CLOSE_TIMEOUT_SEC,OBSERVED_PAGE_ACTIONS,init_actionTimeouts=__esm({"../client/dist/actionTimeouts.js"(){"use strict";init_dist5();SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS=12e4,PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS=18e4,BROWSER_CLOSE_TIMEOUT_SEC=1080;OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS)}});import{createRequire as createRequire3}from"node:module";import{fileURLToPath}from"node:url";var require3,CLIENT_VERSION,PLUGIN_TASK_HOST_PATH,PLUGIN_WORKER_PATH,PLUGIN_MODEL_SESSION_WORKER_PATH,init_runtimePaths=__esm({"../client/dist/runtimePaths.js"(){"use strict";require3=createRequire3(import.meta.url),CLIENT_VERSION=require3("../package.json").version,PLUGIN_TASK_HOST_PATH=fileURLToPath(new URL("./plugin-task-host.js",import.meta.url)),PLUGIN_WORKER_PATH=fileURLToPath(new URL("./plugin-worker.js",import.meta.url)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath(new URL("./pluginModelSessionWorker.js",import.meta.url))}});import fs4 from"node:fs";function resolveValue(value){if(typeof value!="string"||!value.startsWith(FILE_REF_PREFIX))return value;let filePath=value.slice(FILE_REF_PREFIX.length);if(!filePath)return value;let content;try{content=fs4.readFileSync(filePath,"utf-8")}catch{return value}try{return JSON.parse(content)}catch{return content}}function resolveFileRefs(data2){if(data2===null||typeof data2!="object"||Array.isArray(data2))return data2;let out={};for(let[key,value]of Object.entries(data2))out[key]=resolveValue(value);return out}var FILE_REF_PREFIX,init_fileRefs=__esm({"../client/dist/fileRefs.js"(){"use strict";FILE_REF_PREFIX="@"}});import fs5 from"node:fs";import os2 from"node:os";import path6 from"node:path";function isAlive2(pid){if(!pid||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(error62){return error62.code==="EPERM"}}function listLiveBrowsers(){let files;try{files=fs5.readdirSync(BROWSERS_DIR).filter(name=>name.endsWith(".json"))}catch{return[]}let out=[];for(let name of files){let rec;try{rec=JSON.parse(fs5.readFileSync(path6.join(BROWSERS_DIR,name),"utf-8"))}catch{continue}rec&&typeof rec.pid=="number"&&rec.socketPath&&isAlive2(rec.pid)&&out.push(rec)}return out.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0))}function findBrowser(browsers,selector){let sel=selector.trim().toLowerCase();if(!sel)return null;let byId=browsers.find(b=>b.browserId.toLowerCase()===sel);if(byId)return byId;let exactNameMatches=browsers.filter(b=>b.browserName.toLowerCase()===sel);if(exactNameMatches.length>1)throw new Error(`Browser name "${selector.trim()}" is ambiguous. Use a full browserId: ${exactNameMatches.map(browser=>browser.browserId).join(", ")}`);return exactNameMatches[0]?exactNameMatches[0]:browsers.find(b=>b.browserId.toLowerCase().includes(sel)||b.browserName.toLowerCase().includes(sel))??null}function describeBrowser(b){let idShort=b.browserId.length>12?`${b.browserId.slice(0,8)}…`:b.browserId;return`${b.browserName} [${idShort}]`}var BROWSERS_DIR,init_browserRegistry=__esm({"../client/dist/browserRegistry.js"(){"use strict";BROWSERS_DIR=path6.join(os2.homedir(),".mearl","browsers")}});import net2 from"node:net";import fs6 from"node:fs";import os3 from"node:os";import path7 from"node:path";import{StringDecoder}from"node:string_decoder";function toControlSourceWireValue2(source){return source==="remote"||source==="cloud"?"cloud":"local"}function setDefaultBrowser(selector){defaultBrowser=selector&&selector.trim()?selector.trim():void 0}function getDefaultBrowser(){return defaultBrowser}function findConnectedBrowser(items,selector){let normalized=selector.trim().toLowerCase(),connected=items.filter(item=>item.status==="connected"),byId=connected.find(item=>String(item.browserId).toLowerCase()===normalized);if(byId)return byId;let exactNameMatches=connected.filter(item=>String(item.name).toLowerCase()===normalized);if(exactNameMatches.length>1)throw new Error(`Browser name "${selector.trim()}" is ambiguous. Use a full browserId: ${exactNameMatches.map(item=>String(item.browserId)).join(", ")}`);return exactNameMatches[0]??connected.find(item=>String(item.browserId).toLowerCase().includes(normalized)||String(item.name).toLowerCase().includes(normalized))??null}function decorateBrowserListResult(result){let browsers=Array.isArray(result?.browsers)?result.browsers:[],selector=getDefaultBrowser()??process.env.MEARL_BROWSER,selected=selector?findConnectedBrowser(browsers,selector):browsers.find(browser=>browser.status==="connected")??null;return{...result,defaultBrowserId:selected?.browserId??null}}function browserListFromProviderRecords(browsers){let providerBrowsers=browsers.filter(browser=>browser.transport==="provider").map(browser=>({browserId:browser.browserId,name:browser.browserName,type:"managed",status:browser.status??"running_disconnected",transport:"provider",provider:browser.provider,ownership:browser.ownership,persistence:browser.persistence,operations:browser.operations,pairing:browser.pairing,references:browser.references,details:browser.details}));return{count:providerBrowsers.length,connectedCount:providerBrowsers.filter(browser=>browser.status==="connected").length,browsers:providerBrowsers}}function withDiscoveryWarning(result,error62){let detail=(error62.cause??error62)?.code??(error62 instanceof Error?error62.message.split(`
99
+ `?2:1;buffer=buffer.slice(newlineIndex+separatorLength),events.push(...consumeLine(line))}return final&&events.push(...dispatch()),events};return{push(chunk){return buffer+=chunk,drain(!1)},finish(){return drain(!0)}}}var init_sseParser=__esm({"../browser-core/dist/sseParser.js"(){"use strict"}});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 json4=JSON.stringify(responseData)??"null";if(typeof responseData=="string")try{JSON.parse(responseData),json4=responseData}catch{}return{body:`${callback}(${json4});`,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 JSONP_CALLBACK_RE,JSONP_CONTENT_TYPE,init_mockResponse=__esm({"../browser-core/dist/mockResponse.js"(){"use strict";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"}});var init_pluginState=__esm({"../browser-core/dist/pluginState.js"(){"use strict"}});var init_pluginModels=__esm({"../browser-core/dist/pluginModels.js"(){"use strict"}});var init_pluginRecovery=__esm({"../browser-core/dist/pluginRecovery.js"(){"use strict"}});var init_pluginDiagnostics=__esm({"../browser-core/dist/pluginDiagnostics.js"(){"use strict"}});function installRootWebViewDocumentTransport(){let browser=window,prefix="/.mearl-document/";if(browser.name==="__mearl_root__"&&location.pathname.startsWith(prefix))try{let original=new URL(decodeURIComponent(location.hash.slice(1)));original.origin===location.origin&&/^https?:$/.test(original.protocol)&&history.replaceState(history.state,"",original.href)}catch{}browser.__mearlRootDocumentUrl__=url2=>{let token=performance.getEntriesByType("navigation")[0]?.serverTiming?.find(entry=>entry.name==="mearl-document")?.description;if(!token||!/^[a-zA-Z0-9-]+$/.test(token))return url2;let original=new URL(url2);return`${original.origin}${prefix}${token}#${encodeURIComponent(original.href)}`}}var init_rootWebViewDocument=__esm({"../browser-core/dist/rootWebViewDocument.js"(){"use strict"}});function isBrowserManagementAction(value){return typeof value=="string"&&Object.hasOwn(BROWSER_MANAGEMENT_ACTIONS,value)}function isCloudConnectorAction(value){return typeof value=="string"&&Object.hasOwn(CLOUD_CONNECTOR_ACTIONS,value)}function isExtensionUiServiceAction(value){return isAgentServiceAction(value)||isToolboxServiceAction(value)||isBrowserManagementAction(value)||isCloudConnectorAction(value)}function isHostToExtensionAction(value){return typeof value=="string"&&Object.hasOwn(HOST_TO_EXTENSION_ACTIONS,value)}function isPrivateExtensionServiceAction(value){return isToolboxServiceAction(value)||isAgentServiceAction(value)&&value!=="agent_chat_run"||typeof value=="string"&&["browser_sessions","browser_instances","browser_providers"].includes(value)||typeof value=="string"&&Object.hasOwn(EXTENSION_BACKGROUND_ACTIONS,value)}function extensionRpcErrorCode(error62){let code=error62&&typeof error62=="object"&&"code"in error62?error62.code:void 0;return code==="PROTOCOL_MISMATCH"||code==="UNSUPPORTED_ACTION"||code==="EXTENSION_UI_REQUIRED"?code:void 0}var EXTENSION_RPC_VERSION,BROWSER_MANAGEMENT_ACTIONS,CLOUD_CONNECTOR_ACTIONS,HOST_TO_EXTENSION_ACTIONS,EXTENSION_BACKGROUND_ACTIONS,ExtensionRpcError,init_extensionServiceProtocol=__esm({"../browser-core/dist/extensionServiceProtocol.js"(){"use strict";init_agentServiceProtocol();init_toolbox();EXTENSION_RPC_VERSION=1,BROWSER_MANAGEMENT_ACTIONS={browser_sessions:!0,browser_instances:!0,browser_providers:!0,browser_list:!0,browser_launch:!0,browser_close:!0,get_browser_access_url:!0};CLOUD_CONNECTOR_ACTIONS={start_cloud_connector:!0,stop_cloud_connector:!0,list_cloud_connectors:!0};HOST_TO_EXTENSION_ACTIONS={__preset_installation:!0,__preset_browser:!0,__export_cookies:!0,__capture_download:!0,__control_cleanup:!0,__control_deactivate:!0,__send_request_files:!0};EXTENSION_BACKGROUND_ACTIONS={preset_installation:!0,preset_browser_transfer:!0,app_profile_catalog:!0,plugin_page_call:!0,plugin_page_event:!0};ExtensionRpcError=class extends Error{code;constructor(code,message){super(message),this.code=code,this.name="ExtensionRpcError"}}}});var init_requestStreamCapture=__esm({"../browser-core/dist/requestStreamCapture.js"(){"use strict"}});var init_responseText=__esm({"../browser-core/dist/responseText.js"(){"use strict"}});var init_consumeSseResponse=__esm({"../browser-core/dist/consumeSseResponse.js"(){"use strict";init_sseParser()}});var init_queryString=__esm({"../browser-core/dist/queryString.js"(){"use strict"}});function extensionManifestVersion(release){let match=RELEASE.exec(release);if(!match)throw new Error("Invalid extension release version");let parts=match.slice(1,4).map(Number),build=match[4]===void 0?65535:Number(match[4]);if(parts.some(value=>value>65535)||build>65535||match[4]!==void 0&&build===65535)throw new Error("Extension release version exceeds Chrome numeric limits");return{version:[...parts,build].join("."),version_name:release}}function readExtensionReleaseVersion(manifest){if(typeof manifest.version!="string")return null;if(manifest.version_name===void 0){let match=RELEASE.exec(manifest.version);return match&&match[4]===void 0&&match.slice(1,4).every(value=>Number(value)<=65535)?manifest.version:null}if(typeof manifest.version_name!="string")return null;try{return extensionManifestVersion(manifest.version_name).version===manifest.version?manifest.version_name:null}catch{return null}}var RELEASE,init_extensionVersion=__esm({"../browser-core/dist/extensionVersion.js"(){"use strict";RELEASE=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-beta\.(0|[1-9]\d*))?$/}});var MEARL_NATIVE_HOST_NAMES,init_nativeHostNames=__esm({"../browser-core/dist/nativeHostNames.js"(){"use strict";MEARL_NATIVE_HOST_NAMES={skills:"ai.mearl.skills",mcp:"ai.mearl.mcp"}}});var init_dist5=__esm({"../browser-core/dist/index.js"(){"use strict";init_appProfileDefinition();init_types2();init_eventFilters();init_requestSerializer();init_boundedRequestBuffer();init_proxyPermissions();init_domTyping();init_domSelectors();init_domScrolling();init_domInspection();init_domSnapshot();init_deviceEmulation();init_debuggerTarget();init_rootWebViewNavigation();init_axTextMatch();init_domClicking();init_pageDragging();init_pagePressing();init_axSnapshot();init_pageObserver();init_navigationTracker();init_pageAct();init_backendNodeRefs();init_pageEffectRefs();init_pageWait();init_pageNavigation();init_tabMatching();init_agentChat();init_agentSkills();init_agentServiceProtocol();init_toolbox();init_toolboxIcon();init_pluginExecution();init_pluginTasks();init_pluginPages();init_pluginPageRuntime();init_pluginPageHost();init_browserActionProtocol();init_runActions();init_sendRequestFiles();init_sendRequestHeaders();init_cookie();init_controlledFavicon();init_capture();init_sseParser();init_mockResponse();init_pluginState();init_pluginModels();init_pluginRecovery();init_pluginDiagnostics();init_rootWebViewDocument();init_extensionServiceProtocol();init_requestStreamCapture();init_responseText();init_consumeSseResponse();init_queryString();init_extensionVersion();init_nativeHostNames()}});import fs3 from"node:fs";import os from"node:os";import path4 from"node:path";function resolveNativeHostDirectory(options={}){let env=options.env??process.env,home=(options.homedir??os.homedir)();switch(options.platform??process.platform){case"darwin":return path4.join(home,"Library/Application Support/Google/Chrome/NativeMessagingHosts");case"linux":return path4.join(home,".config/google-chrome/NativeMessagingHosts");case"win32":return path4.join(env.PROGRAMDATA||"C:\\ProgramData","Google\\Chrome\\NativeMessagingHosts");default:throw new Error(`Unsupported platform: ${String(options.platform??process.platform)}`)}}function readLauncherMetadata(content){let metadata=content.match(/^(?:#|rem) mearl-native-host-launcher: (.+)\r?$/m);if(metadata){let parsed=JSON.parse(metadata[1]);if(parsed.version===1&&Array.isArray(parsed.nodePaths)&&parsed.nodePaths.length>0&&parsed.nodePaths.every(value=>typeof value=="string"&&path4.isAbsolute(value))&&typeof parsed.hostPath=="string"&&path4.isAbsolute(parsed.hostPath))return{version:1,nodePaths:parsed.nodePaths,hostPath:parsed.hostPath};throw new Error("Invalid native host launcher metadata")}let node2=content.match(/^NODE_BIN=(".*")\r?$/m),host=content.match(/^HOST_SCRIPT=(".*")\r?$/m);if(!node2||!host)return null;let nodePath=JSON.parse(node2[1]),hostPath=JSON.parse(host[1]);if(typeof nodePath!="string"||!path4.isAbsolute(nodePath)||typeof hostPath!="string"||!path4.isAbsolute(hostPath))throw new Error("Invalid native host launcher paths");return{version:1,nodePaths:[nodePath],hostPath}}function inspectNativeHostInstallation(options={}){let platform=options.platform??process.platform;if(!["darwin","linux","win32"].includes(platform))return[];let hostDir=options.hostDir??resolveNativeHostDirectory(options),diagnostics=[],isUsable=(filePath,executable)=>{try{return fs3.accessSync(filePath,executable&&platform!=="win32"?fs3.constants.X_OK:fs3.constants.R_OK),fs3.statSync(filePath).isFile()}catch{return!1}};for(let hostName of Object.values(MEARL_NATIVE_HOST_NAMES)){let manifestPath=path4.join(hostDir,`${hostName}.json`),details=[];try{let manifest=JSON.parse(fs3.readFileSync(manifestPath,"utf-8"));if(typeof manifest?.path!="string"||!path4.isAbsolute(manifest.path))details.push(`Invalid launcher path in ${manifestPath}`);else if(!isUsable(manifest.path,!0))details.push(`Launcher is missing or not executable: ${manifest.path}`);else{let metadata=readLauncherMetadata(fs3.readFileSync(manifest.path,"utf-8"));metadata&&(metadata.nodePaths.some(candidate=>isUsable(candidate,!0))||details.push(`No executable Node.js found. Launcher candidates: ${metadata.nodePaths.join(", ")}`),isUsable(metadata.hostPath,!1)||details.push(`Native host runtime script is missing or unreadable: ${metadata.hostPath}`))}}catch(error62){if(error62.code==="ENOENT"&&!fs3.existsSync(manifestPath))continue;details.push(`Cannot inspect ${manifestPath}: ${error62 instanceof Error?error62.message:String(error62)}`)}details.length&&diagnostics.push({label:`Native Messaging registration needs repair: ${hostName}`,details:[...details,`Registration: ${manifestPath}`,"Run `mearl-native-host init` with a working Node.js, then reopen the extension. If the runtime package is missing, run `npx --@mearl:registry=https://registry.npmjs.org @mearl/setup update --local`."]})}return diagnostics}var init_nativeHost=__esm({"../client/dist/nativeHost.js"(){"use strict";init_dist5()}});import{randomUUID as randomUUID7}from"node:crypto";async function invokePageEvalWithArgs(invoke3,params){if(!Number.isSafeInteger(params.tabId)||params.tabId<0)throw new Error("Invalid target tab");if(resolvePageEvalExpression({expression:params.expression,args:[]}),!Array.isArray(params.args))throw new Error("page_eval args must be an array");if(params.executionWorld!==void 0&&!["main","isolated"].includes(params.executionWorld))throw new Error("Invalid page executionWorld");params.executionWorld==="isolated"&&validatePageUserScriptParams({tabId:params.tabId,worldId:params.worldId??"",code:params.expression});let args=JSON.stringify(params.args);if(args.length>64*1024*1024)throw new Error("Page script arguments must fit within 64 MiB characters");let{args:_args,...request}=params,evaluate=async(expression,transfer=!1)=>{let payload={...request,...transfer?{observe:!1,diagnostics:!1}:{},expression},result=await(transfer?invoke3(payload,!0):invoke3(payload));if(transfer&&result?.action?.success===!1)throw new Error(result.action.error||"page_eval failed");return result};if(args.length+params.expression.length<=CHUNK_CHARACTERS)return evaluate(resolvePageEvalExpression(params));let key=JSON.stringify("__mearlPageScriptTransfer_"+randomUUID7());try{for(let offset2=0;offset2<args.length;offset2+=CHUNK_CHARACTERS)await evaluate(`void (window[${key}] = (window[${key}] || '') + ${JSON.stringify(args.slice(offset2,offset2+CHUNK_CHARACTERS))})`,!0);return await evaluate(`(() => { const args = JSON.parse(window[${key}]); delete window[${key}]; return (${params.expression})(...args); })()`)}finally{await evaluate(`delete window[${key}]`,!0).catch(()=>{})}}var CHUNK_CHARACTERS,init_pageEvalArguments=__esm({"../client/dist/pageEvalArguments.js"(){"use strict";init_dist5();CHUNK_CHARACTERS=48*1024}});import{open as open2,mkdir,rename,rm,stat}from"node:fs/promises";import path5 from"node:path";import{randomUUID as randomUUID8}from"node:crypto";async function stageFile(client2,filePath,options){if(!path5.isAbsolute(filePath))throw new Error("Caller-local file paths must be absolute");let source=await open2(filePath,"r"),id2,pinned=options;try{let metadata=await source.stat();if(!metadata.isFile()||metadata.size>256*1024*1024)throw new Error("Upload requires a regular file of at most 256 MiB");let created=await client2.invoke("__artifact_init",{filename:path5.basename(filePath)},options);pinned={...options,browser:created.browserId},id2=created.artifact.artifactId;let offset2=0;for await(let chunk of source.createReadStream({highWaterMark:CHUNK_BYTES,autoClose:!1}))await client2.invoke("__artifact_write",{artifactId:id2,offset:offset2,base64:chunk.toString("base64")},pinned),offset2+=chunk.length;return await client2.invoke("__artifact_complete",{artifactId:id2,bytes:offset2},pinned),{artifactId:id2,options:pinned}}catch(error62){throw id2&&await client2.invoke("__artifact_remove",{artifactId:id2},pinned).catch(()=>{}),error62}finally{await source.close()}}async function exportArtifact(client2,artifact,outputPath2,options={}){if(!Number.isSafeInteger(artifact.bytes)||artifact.bytes<0)throw new Error("Invalid artifact size");if(!path5.isAbsolute(outputPath2))throw new Error("Artifact output paths must be absolute");if(!options.session&&!artifact.browserId&&!options.browser)throw new Error("An artifact requires its originating browser");let pinned={...options,...artifact.browserId?{browser:artifact.browserId}:{}};await mkdir(path5.dirname(outputPath2),{recursive:!0});let temporary=`${outputPath2}.${randomUUID8()}.part`,target=await open2(temporary,"wx",384);try{let offset2=0;if(artifact.bytes===0){let empty2=await client2.invoke("__artifact_read",{artifactId:artifact.artifactId,offset:0},pinned);if(empty2.totalBytes!==0||empty2.bytes!==0||empty2.base64!=="")throw new Error("Artifact export size mismatch")}for(;offset2<artifact.bytes;){let chunk=await client2.invoke("__artifact_read",{artifactId:artifact.artifactId,offset:offset2},pinned),bytes=Buffer.from(chunk.base64,"base64");if(!bytes.length||bytes.length!==chunk.bytes||chunk.totalBytes!==artifact.bytes||offset2+bytes.length>artifact.bytes)throw new Error("Invalid artifact chunk or truncated transfer");await target.write(bytes),offset2+=bytes.length}if(await target.sync(),await target.close(),(await stat(temporary)).size!==artifact.bytes)throw new Error("Artifact export size mismatch");return await rename(temporary,outputPath2),{outputPath:outputPath2,bytes:artifact.bytes}}catch(error62){throw await target.close().catch(()=>{}),await rm(temporary,{force:!0}),error62}}var CHUNK_BYTES,init_artifacts=__esm({"../client/dist/artifacts.js"(){"use strict";CHUNK_BYTES=256*1024}});function resolveCloudConnectorSelector(connectors,selector){let normalized=selector.trim().toLowerCase();if(!normalized)return{status:"not_found"};let resolveMatches=matches=>matches.length===1?{status:"matched",connector:matches[0]}:matches.length>1?{status:"ambiguous"}:null,exactId=resolveMatches(connectors.filter(connector=>connector.connectorId.toLowerCase()===normalized));if(exactId)return exactId;let exactName=resolveMatches(connectors.filter(connector=>connector.name.toLowerCase()===normalized));return exactName||(resolveMatches(connectors.filter(connector=>connector.connectorId.toLowerCase().includes(normalized)||connector.name.toLowerCase().includes(normalized)))??{status:"not_found"})}function isHeartbeatMessage(msg){return msg&&(msg.type==="ping"||msg.type==="pong")}var init_dist6=__esm({"../cloud/cloud-types/dist/index.js"(){"use strict"}});function boundedNumber2(value,fallback,minimum,maximum){let numeric=Number(value);return Number.isFinite(numeric)?Math.min(Math.max(numeric,minimum),maximum):fallback}function resolveObservedActionTimeoutSec(data2){let observe=data2.observe??{},observationMs=boundedNumber2(observe.timeoutMs,3e3,500,3e4),navigationGraceMs=boundedNumber2(observe.navigationGraceMs,1e3,0,5e3),navigationTimeoutMs=boundedNumber2(observe.navigationTimeoutMs,15e3,1e3,3e4),totalMs=observationMs+navigationGraceMs+4e3+navigationTimeoutMs+5e3;return Math.max(20,Math.ceil(totalMs/1e3))}function resolveActionTimeoutSec(action,data2,fallback=15){if(action==="send_request"){let transferTimeoutMs=data2.bodyFile!==void 0||Array.isArray(data2.files)&&data2.files.length>0?SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS:0;return Math.max(fallback,Math.ceil(((data2.timeout??3e4)+transferTimeoutMs+5e3)/1e3))}if(action==="send_mtop_request")return Math.max(fallback,Math.ceil(((data2.timeout??1e4)+5e3)/1e3));if(action==="page_download")return Math.max(fallback,Math.ceil((Number(data2.timeout??3e4)+1e4)/1e3));if(action==="page_wait"){let waitMs=data2.time??data2.timeout??1e4;return Math.max(fallback,Math.ceil((Number(waitMs)+5e3)/1e3))}if(action==="tab_open"||action==="set_cookie"&&data2.reload===!0)return Math.max(fallback,40);if(action==="browser_launch")return Math.max(fallback,90);if(action==="browser_close")return Math.max(fallback,BROWSER_CLOSE_TIMEOUT_SEC);if(action==="run_actions"){let timeoutSec=(Array.isArray(data2.actions)?data2.actions:[{}]).reduce((total,step)=>{let stepAction=String(step?.action??"");return!stepAction||stepAction==="run_actions"?total+15:total+resolveActionTimeoutSec(stepAction,step?.data??{},15)},0);return Math.max(fallback,timeoutSec)}let observedAction=OBSERVED_PAGE_ACTIONS.has(action),observationEnabled=action==="page_eval"?data2.observe!==null&&typeof data2.observe=="object"&&!Array.isArray(data2.observe):data2.observe!==!1;if(action==="page_upload"){let actionTimeoutSec=observationEnabled?resolveObservedActionTimeoutSec(data2):fallback;return Math.max(fallback,actionTimeoutSec+Math.ceil(PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS/1e3))}return observedAction&&observationEnabled?Math.max(fallback,resolveObservedActionTimeoutSec(data2)):fallback}var SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS,PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS,BROWSER_CLOSE_TIMEOUT_SEC,OBSERVED_PAGE_ACTIONS,init_actionTimeouts=__esm({"../client/dist/actionTimeouts.js"(){"use strict";init_dist5();SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS=12e4,PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS=18e4,BROWSER_CLOSE_TIMEOUT_SEC=1080;OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS)}});import{createRequire as createRequire3}from"node:module";import{fileURLToPath}from"node:url";var require3,CLIENT_VERSION,PLUGIN_TASK_HOST_PATH,PLUGIN_WORKER_PATH,PLUGIN_MODEL_SESSION_WORKER_PATH,init_runtimePaths=__esm({"../client/dist/runtimePaths.js"(){"use strict";require3=createRequire3(import.meta.url),CLIENT_VERSION=require3("../package.json").version,PLUGIN_TASK_HOST_PATH=fileURLToPath(new URL("./plugin-task-host.js",import.meta.url)),PLUGIN_WORKER_PATH=fileURLToPath(new URL("./plugin-worker.js",import.meta.url)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath(new URL("./pluginModelSessionWorker.js",import.meta.url))}});import fs4 from"node:fs";function resolveValue(value){if(typeof value!="string"||!value.startsWith(FILE_REF_PREFIX))return value;let filePath=value.slice(FILE_REF_PREFIX.length);if(!filePath)return value;let content;try{content=fs4.readFileSync(filePath,"utf-8")}catch{return value}try{return JSON.parse(content)}catch{return content}}function resolveFileRefs(data2){if(data2===null||typeof data2!="object"||Array.isArray(data2))return data2;let out={};for(let[key,value]of Object.entries(data2))out[key]=resolveValue(value);return out}var FILE_REF_PREFIX,init_fileRefs=__esm({"../client/dist/fileRefs.js"(){"use strict";FILE_REF_PREFIX="@"}});import fs5 from"node:fs";import os2 from"node:os";import path6 from"node:path";function isAlive2(pid){if(!pid||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(error62){return error62.code==="EPERM"}}function listLiveBrowsers(){let files;try{files=fs5.readdirSync(BROWSERS_DIR).filter(name=>name.endsWith(".json"))}catch{return[]}let out=[];for(let name of files){let rec;try{rec=JSON.parse(fs5.readFileSync(path6.join(BROWSERS_DIR,name),"utf-8"))}catch{continue}rec&&typeof rec.pid=="number"&&rec.socketPath&&isAlive2(rec.pid)&&out.push(rec)}return out.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0))}function findBrowser(browsers,selector){let sel=selector.trim().toLowerCase();if(!sel)return null;let byId=browsers.find(b=>b.browserId.toLowerCase()===sel);if(byId)return byId;let exactNameMatches=browsers.filter(b=>b.browserName.toLowerCase()===sel);if(exactNameMatches.length>1)throw new Error(`Browser name "${selector.trim()}" is ambiguous. Use a full browserId: ${exactNameMatches.map(browser=>browser.browserId).join(", ")}`);return exactNameMatches[0]?exactNameMatches[0]:browsers.find(b=>b.browserId.toLowerCase().includes(sel)||b.browserName.toLowerCase().includes(sel))??null}function describeBrowser(b){let idShort=b.browserId.length>12?`${b.browserId.slice(0,8)}…`:b.browserId;return`${b.browserName} [${idShort}]`}var BROWSERS_DIR,init_browserRegistry=__esm({"../client/dist/browserRegistry.js"(){"use strict";BROWSERS_DIR=path6.join(os2.homedir(),".mearl","browsers")}});import net2 from"node:net";import fs6 from"node:fs";import os3 from"node:os";import path7 from"node:path";import{StringDecoder}from"node:string_decoder";function toControlSourceWireValue2(source){return source==="remote"||source==="cloud"?"cloud":"local"}function setDefaultBrowser(selector){defaultBrowser=selector&&selector.trim()?selector.trim():void 0}function getDefaultBrowser(){return defaultBrowser}function findConnectedBrowser(items,selector){let normalized=selector.trim().toLowerCase(),connected=items.filter(item=>item.status==="connected"),byId=connected.find(item=>String(item.browserId).toLowerCase()===normalized);if(byId)return byId;let exactNameMatches=connected.filter(item=>String(item.name).toLowerCase()===normalized);if(exactNameMatches.length>1)throw new Error(`Browser name "${selector.trim()}" is ambiguous. Use a full browserId: ${exactNameMatches.map(item=>String(item.browserId)).join(", ")}`);return exactNameMatches[0]??connected.find(item=>String(item.browserId).toLowerCase().includes(normalized)||String(item.name).toLowerCase().includes(normalized))??null}function decorateBrowserListResult(result){let browsers=Array.isArray(result?.browsers)?result.browsers:[],selector=getDefaultBrowser()??process.env.MEARL_BROWSER,selected=selector?findConnectedBrowser(browsers,selector):browsers.find(browser=>browser.status==="connected")??null;return{...result,defaultBrowserId:selected?.browserId??null}}function browserListFromProviderRecords(browsers){let providerBrowsers=browsers.filter(browser=>browser.transport==="provider").map(browser=>({browserId:browser.browserId,name:browser.browserName,type:"managed",status:browser.status??"running_disconnected",transport:"provider",provider:browser.provider,ownership:browser.ownership,persistence:browser.persistence,operations:browser.operations,pairing:browser.pairing,references:browser.references,details:browser.details}));return{count:providerBrowsers.length,connectedCount:providerBrowsers.filter(browser=>browser.status==="connected").length,browsers:providerBrowsers}}function withDiscoveryWarning(result,error62){let detail=(error62.cause??error62)?.code??(error62 instanceof Error?error62.message.split(`
100
100
  `)[0]:String(error62));return{...result,warnings:[...Array.isArray(result.warnings)?result.warnings:[],`Local CDP discovery could not complete: ${detail}`]}}function cdpOnlyBrowserList(result){let cdpBrowsers=(Array.isArray(result.browsers)?result.browsers:[]).filter(browser=>browser.transport==="cdp");return{...result,count:cdpBrowsers.length,connectedCount:cdpBrowsers.filter(browser=>browser.status==="connected").length,browsers:cdpBrowsers}}function areInstalledProvidersRunning(){return listInstalledProviders().every(provider=>readLiveProvider(provider.providerId))}function isConnectedBrowser(browser){return browser.status===void 0||browser.status==="connected"}function isOrdinaryLocalBrowser(browser){return!browser.browserId.startsWith("managed:")&&(browser.transport==="extension"||browser.transport==="cdp")}function supportsAction(browser,action,data2){if(browser.transport==="provider"){if(action==="browser_control"||action==="browser_release"&&data2[SESSION_OPTION])return!0;if(action.startsWith("__artifact_"))return browser.capabilities?.actions.includes("page_upload")===!0||(action==="__artifact_read"||action==="__artifact_remove")&&browser.capabilities?.actions.includes("page_download")===!0;if(action==="run_actions"&&data2[SESSION_OPTION])return!0}if(action==="get_versions")return!0;if(action==="get_browser_access_url")return browser.transport!=="provider"||browser.operations?.includes("access")===!0;if(action==="browser_close"){if(browser.transport!=="provider")return!0;let required2=data2.deleteProfile===!0?"deleteData":"close";return browser.operations?.includes(required2)===!0}return action==="browser_release"?browser.transport!=="provider"||browser.operations?.includes("detach")===!0:isConnectedBrowser(browser)?browser.transport!=="provider"||browser.capabilities?.actions.some(capability=>capability===action)===!0:!1}function routableBrowsers(browsers,action,data2,transport){return browsers.filter(browser=>isConnectedBrowser(browser)&&(action!=="browser_list"||browser.transport!=="provider")&&!(transport==="cdp"&&browser.transport==="provider")&&supportsAction(browser,action,data2))}function resolveLocalActionTarget(action,data2,options={}){let selector=options.browser??defaultBrowser??process.env.MEARL_BROWSER??void 0,socketPath=options.socketPath??process.env.MEARL_SOCKET_PATH?.trim();if(socketPath&&(options.socketPath||!selector))return{socketPath};let browsers=listLiveBrowsers(),target=selector?findBrowser(browsers,selector):routableBrowsers(browsers,action,data2,options.transport)[0];return target?{browser:target.browserId}:void 0}function selectBrowserResult(data2){let selector=typeof data2.browser=="string"?data2.browser.trim():"";if(!selector)return setDefaultBrowser(void 0),{selected:null,note:"Cleared: default target is now the most-recently focused browser."};let browsers=listLiveBrowsers(),controllableBrowsers=browsers.filter(isConnectedBrowser),match=findBrowser(controllableBrowsers,selector);if(!match)throw new Error(formatNoMatchError(selector,browsers));return setDefaultBrowser(match.browserId),{selected:{browserId:match.browserId,name:match.browserName}}}function instanceSocketPath(pid){return process.platform==="win32"?`\\\\.\\pipe\\mearl-agent-${pid}`:path7.join(os3.tmpdir(),`mearl-agent-${pid}.sock`)}function discoveryCacheKey(){let browsers=listLiveBrowsers().map(browser=>[browser.browserId,browser.pid,browser.socketPath,browser.status,browser.updatedAt]).sort((a,b)=>String(a[0]).localeCompare(String(b[0]))),providers=listInstalledProviders().map(provider=>provider.providerId).sort();return JSON.stringify({browsers,providers})}async function spawnNativeHost(args){let{spawn:spawn13}=await import("node:child_process");return new Promise((resolve16,reject)=>{let child=spawn13("mearl-native-host",args,{detached:!0,stdio:"ignore",windowsHide:!0});child.once("error",reject),child.once("spawn",()=>{child.unref(),resolve16(child.pid)})})}async function trySpawnNativeHost(){if(persistentSpawnPromise)return persistentSpawnPromise;let spawnPromise=(async()=>{try{return await spawnNativeHost(["--daemon"]),!0}catch{return!1}})();persistentSpawnPromise=spawnPromise;try{return await spawnPromise}finally{persistentSpawnPromise===spawnPromise&&(persistentSpawnPromise=null)}}async function discoverLocalBrowserList(timeoutSec,controlSource){if(discoveryListPromise)return discoveryListPromise;let cacheKey=discoveryCacheKey();if(discoveryListCache&&discoveryListCache.key===cacheKey&&Date.now()<discoveryListCache.until){if(discoveryListCache.error)throw discoveryListCache.error;return discoveryListCache.result}discoveryListCache=null;let request=(async()=>{let pid=await spawnNativeHost(["--daemon","--discover-cdp"]);if(pid===void 0)throw new Error("Native host did not report its process id");let socketPath=instanceSocketPath(pid),deadline=Date.now()+Math.min(timeoutSec*1e3,DISCOVERY_STARTUP_TIMEOUT_MS);for(;;)try{return await invokeOnce("browser_list",{},timeoutSec,void 0,socketPath,controlSource)}catch(error62){if(!isConnError(error62)||Date.now()>=deadline)throw error62;await new Promise(resolve16=>setTimeout(resolve16,DISCOVERY_RETRY_INTERVAL_MS))}})();discoveryListPromise=request;try{let result=await request;return result.browsers?.some(browser=>browser.transport==="cdp"&&browser.status==="connected"&&!browser.browserId?.startsWith("managed:"))||(discoveryListCache={key:cacheKey,result,until:Date.now()+DISCOVERY_MISS_CACHE_MS}),result}catch(error62){throw discoveryListCache={key:cacheKey,error:error62,until:Date.now()+DISCOVERY_MISS_CACHE_MS},error62}finally{discoveryListPromise===request&&(discoveryListPromise=null)}}function readOwnedLegacySocketIdentity(){if(process.platform==="win32")return null;try{let stat5=fs6.lstatSync(SOCKET_PATH);return!stat5.isSocket()||process.getuid&&stat5.uid!==process.getuid()?null:{dev:stat5.dev,ino:stat5.ino}}catch{return null}}function removeStaleLegacySocket(identity3){if(identity3)try{let current2=fs6.lstatSync(SOCKET_PATH);if(!current2.isSocket()||current2.dev!==identity3.dev||current2.ino!==identity3.ino)return;fs6.unlinkSync(SOCKET_PATH)}catch{}}function invoke(action,data2={},options={}){if(action==="__resolve_action_target"){if(!isBrowserCapabilityAction(data2.action))return Promise.reject(new Error("Invalid browser capability action"));let target=resolveLocalActionTarget(data2.action,data2.data??{},options),browser2=target?.browser??(target?.socketPath?listLiveBrowsers().find(item=>item.socketPath===target.socketPath&&supportsAction(item,data2.action,data2.data??{}))?.browserId:void 0);return Promise.resolve(browser2?{browser:browser2}:null)}if(action==="browser_select_browser")try{return Promise.resolve(selectBrowserResult(data2))}catch(error62){return Promise.reject(error62)}let{timeoutSec=resolveActionTimeoutSec(action,data2),transport,browser,controlSource="local"}=options;if(action==="__control_session_resolve")return resolveControlSession(data2.sessionId,timeoutSec,controlSource);let resolvedData=resolveFileRefs(data2);if(Object.defineProperty(resolvedData,SESSION_OPTION,{value:options.controlSessionId}),action==="browser_list")return dispatchInvoke(action,resolvedData,timeoutSec,transport,void 0,controlSource,options.socketPath).then(result=>decorateBrowserListResult(transport==="cdp"?cdpOnlyBrowserList(result):result));let selector=browser??defaultBrowser??process.env.MEARL_BROWSER??void 0;return dispatchInvoke(action,resolvedData,timeoutSec,transport,selector,controlSource,options.socketPath)}function invokeLocalHost(action,data2={},options={}){let timeoutSec=options.timeoutSec??resolveActionTimeoutSec(action,data2),socketPath=options.socketPath??process.env.MEARL_SOCKET_PATH?.trim(),accepted=resolveFileRefs(data2);return socketPath?invokeOnce(action,accepted,timeoutSec,void 0,socketPath,"local"):invokeViaLegacy(action,accepted,timeoutSec,void 0,"local",!1,!0)}async function resolveControlSession(sessionId,timeoutSec,controlSource){let browsers=listLiveBrowsers(),configuredSocketPath=process.env.MEARL_SOCKET_PATH?.trim(),sockets=configuredSocketPath?[configuredSocketPath]:[...new Set(browsers.filter(browser=>browser.transport!=="provider").map(browser=>browser.socketPath))],provider=configuredSocketPath?void 0:browsers.find(browser=>browser.transport==="provider");!sockets.length&&!provider&&sockets.push(SOCKET_PATH);let requests=sockets.map(socketPath=>invokeOnce("__control_session_resolve",{sessionId},timeoutSec,void 0,socketPath,controlSource));provider&&requests.push(invokeOnce("__control_session_resolve",{sessionId},timeoutSec,void 0,provider.socketPath,controlSource,provider.browserId));let results=await Promise.allSettled(requests),sessions=results.flatMap(result=>result.status==="fulfilled"&&result.value?.session?.sessionId===sessionId?[result.value.session]:[]);if(sessions.length>1)throw new Error("CONTROL_SESSION_AMBIGUOUS: multiple hosts own this id");if(sessions.length)return{session:sessions[0]};let failure2=results.find(result=>result.status==="rejected"&&!isConnError(result.reason));if(failure2?.status==="rejected")throw failure2.reason;return{session:null}}function isConnError(error62){let code=error62?.code;return code==="ENOENT"||code==="ECONNREFUSED"}function isSocketSandboxError(error62){return error62?.code==="EPERM"}function isUnavailableConnection(error62){let cause=error62.cause??error62,code=cause?.code;return isConnError(cause)||isSocketSandboxError(cause)||code==="EACCES"}async function dispatchInvoke(action,data2,timeoutSec,transport,selector,controlSource,socketPath){let configuredSocketPath=socketPath??process.env.MEARL_SOCKET_PATH?.trim();if(configuredSocketPath&&(socketPath||!selector))try{return await invokeOnce(action,data2,timeoutSec,transport,configuredSocketPath,controlSource)}catch(error62){throw isConnError(error62)||isSocketSandboxError(error62)?new Error(formatConnectError(error62,configuredSocketPath),{cause:error62}):error62}let browsers=listLiveBrowsers(),controllableBrowsers=browsers.filter(isConnectedBrowser);if(action==="browser_list"&&transport==="cdp"){let registeredCdp=controllableBrowsers.find(browser=>browser.transport==="cdp"&&isOrdinaryLocalBrowser(browser));if(registeredCdp)try{return await invokeOnce(action,data2,timeoutSec,transport,registeredCdp.socketPath,controlSource)}catch(error62){if(!isConnError(error62))throw error62}try{return await discoverLocalBrowserList(timeoutSec,controlSource)}catch(error62){if(isUnavailableConnection(error62)&&browsers.some(browser=>browser.transport==="provider")&&areInstalledProvidersRunning())return withDiscoveryWarning(browserListFromProviderRecords(browsers),error62);throw error62}}if(action==="browser_list"&&!controllableBrowsers.some(isOrdinaryLocalBrowser))try{return await discoverLocalBrowserList(timeoutSec,controlSource)}catch(error62){if(isUnavailableConnection(error62)&&browsers.some(browser=>browser.transport==="provider")&&areInstalledProvidersRunning())return withDiscoveryWarning(browserListFromProviderRecords(browsers),error62);throw error62}if(selector){let match=findBrowser(browsers,selector);if(!match)throw new Error(formatNoMatchError(selector,browsers));if(transport==="cdp"&&match.transport==="provider")throw new Error(`Browser ${describeBrowser(match)} does not support the CDP transport`);if(match.status==="pairing"&&action!=="get_versions"&&action!=="browser_close"&&action!=="browser_release"&&action!=="browser_control")throw new Error(`Browser ${describeBrowser(match)} is waiting for device pairing`);if(!supportsAction(match,action,data2))throw new Error(`Browser ${describeBrowser(match)} does not support ${action}`);try{return await invokeOnce(action,data2,timeoutSec,transport,match.socketPath,controlSource,match.transport==="provider"?match.browserId:void 0)}catch(error62){throw isConnError(error62)||isSocketSandboxError(error62)?new Error(formatConnectError(error62,match.socketPath),{cause:error62}):error62}}let candidates=routableBrowsers(browsers,action,data2,transport);if(candidates.length>0){let target=candidates[0];try{return await invokeOnce(action,data2,timeoutSec,transport,target.socketPath,controlSource,target.transport==="provider"?target.browserId:void 0)}catch(error62){if(isSocketSandboxError(error62))throw new Error(formatConnectError(error62,target.socketPath),{cause:error62});if(!isConnError(error62))throw error62}}if(action==="browser_list")try{return await discoverLocalBrowserList(timeoutSec,controlSource)}catch(error62){if(isUnavailableConnection(error62)&&browsers.some(browser=>browser.transport==="provider")&&areInstalledProvidersRunning())return withDiscoveryWarning(browserListFromProviderRecords(browsers),error62);throw error62}return invokeViaLegacy(action,data2,timeoutSec,transport,controlSource,!1)}async function invokeViaLegacy(action,data2,timeoutSec,transport,controlSource,isRetry,localOnly=!1){let legacySocketIdentity=readOwnedLegacySocketIdentity();try{return await invokeOnce(action,data2,timeoutSec,transport,SOCKET_PATH,controlSource)}catch(error62){let err=error62;if((err.code==="ENOENT"||err.code==="ECONNREFUSED")&&!isRetry&&(err.code==="ECONNREFUSED"&&removeStaleLegacySocket(legacySocketIdentity),await trySpawnNativeHost())){await new Promise(r=>setTimeout(r,1200));let target=listLiveBrowsers().find(browser=>isConnectedBrowser(browser)&&(!localOnly||browser.transport!=="provider")&&!(transport==="cdp"&&browser.transport==="provider")&&supportsAction(browser,action,data2));return target?invokeOnce(action,data2,timeoutSec,transport,target.socketPath,controlSource,target.transport==="provider"?target.browserId:void 0):invokeViaLegacy(action,data2,timeoutSec,transport,controlSource,!0,localOnly)}throw err instanceof Error&&!isConnError(err)&&!isSocketSandboxError(err)?err:new Error(formatConnectError(err,SOCKET_PATH),{cause:error62})}}async function invokeOnce(action,data2,timeoutSec,transport,socketPath,controlSource,providerTarget){providerTarget&&(socketPath=(await ensureProviderControlHost(Math.min(timeoutSec*1e3,1e4))).socketPath);let id2=`${Date.now()}_${Math.random().toString(36).slice(2,10)}`,deadline=Date.now()+Math.ceil(timeoutSec*1e3);return new Promise((resolve16,reject)=>{if(process.platform!=="win32"&&fs6.existsSync(socketPath)&&process.getuid&&fs6.statSync(socketPath).uid!==process.getuid()){let error62=new Error(`拒绝连接不属于当前用户的 Socket: ${socketPath}`);Object.assign(error62,{code:"EACCES"}),reject(error62);return}let socket=net2.createConnection(socketPath),settled=!1,buffer="",decoder=new StringDecoder("utf8"),settle2=(error62,result)=>{settled||(settled=!0,clearTimeout(timer),socket.removeAllListeners(),socket.end(),error62?reject(error62 instanceof Error?error62:new Error(String(error62))):resolve16(result))},timer=setTimeout(()=>{settle2(new Error(`请求超时,已等待 ${timeoutSec} 秒`))},timeoutSec*1e3);socket.on("connect",()=>{let message={id:id2,action,data:data2,version:CLIENT_VERSION,protocolVersion:3,controlSource:toControlSourceWireValue2(controlSource)};data2[SESSION_OPTION]&&(message.controlSessionId=data2[SESSION_OPTION]),transport&&(message.transport=transport),providerTarget&&(message.providerTarget=providerTarget,message.deadline=deadline),socket.write(JSON.stringify(message)+`
101
101
  `)}),socket.on("data",chunk=>{if(buffer+=decoder.write(chunk),Buffer.byteLength(buffer,"utf-8")>MAX_SOCKET_BUFFER_SIZE){settle2(new Error(`Socket 响应超过 ${MAX_SOCKET_BUFFER_SIZE} 字节限制`));return}let newlineIndex;for(;(newlineIndex=buffer.indexOf(`
102
- `))!==-1;){let line=buffer.slice(0,newlineIndex);if(buffer=buffer.slice(newlineIndex+1),!!line.trim())try{let response=JSON.parse(line);if(response.id!==id2)continue;response.versionWarning&&console.warn(response.versionWarning),response.success?settle2(null,response.data):settle2(new Error(response.error||"Socket 服务端返回未知错误"));return}catch{settle2(new Error(`无效的 JSON 响应: ${line}`));return}}}),socket.on("error",error62=>settle2(error62)),socket.on("end",()=>{settled||settle2(new Error("在收到响应前 Socket 已关闭"))})})}function formatConnectError(error62,socketPath){let installHint=`如果尚未安装浏览器插件,请先前往: ${EXTENSION_INSTALL_URL}`;return error62.code==="ENOENT"?[`未找到 Socket: ${socketPath}`,"native host 自动拉起失败。先运行 mearl check --local;缺少命令时运行 npx @mearl/setup --local --yes。","自动拉起只使用默认 daemon 参数;自定义 CDP/Profile/浏览器参数需手工启动,参见 mearl-native-host --help。","","【方式一:浏览器插件模式】",`1. 确认已安装 Mearl 浏览器插件(${EXTENSION_INSTALL_URL})`,"2. 确认已执行 Native Messaging 初始化(安装 @mearl/native-host 时会自动完成)","3. 确认 Chrome 浏览器正在运行,如仍无法连接可在 chrome://extensions 重新加载插件","","【方式二:CDP 远程调试模式(Chrome 145+,无需插件)】",' 访问 chrome://inspect/#remote-debugging,勾选 "Allow remote debugging for this browser instance"'," Chrome 会弹出授权提示,点击允许,native host 自动读取 DevToolsActivePort 文件连接"," 确认有普通网页已打开(非 chrome:// 页面)"].join(`
102
+ `))!==-1;){let line=buffer.slice(0,newlineIndex);if(buffer=buffer.slice(newlineIndex+1),!!line.trim())try{let response=JSON.parse(line);if(response.id!==id2)continue;response.versionWarning&&console.warn(response.versionWarning),response.success?settle2(null,response.data):settle2(new Error(response.error||"Socket 服务端返回未知错误"));return}catch{settle2(new Error(`无效的 JSON 响应: ${line}`));return}}}),socket.on("error",error62=>settle2(error62)),socket.on("end",()=>{settled||settle2(new Error("在收到响应前 Socket 已关闭"))})})}function formatConnectError(error62,socketPath){let installHint=`如果尚未安装浏览器插件,请先前往: ${EXTENSION_INSTALL_URL}`;return error62.code==="ENOENT"?[`未找到 Socket: ${socketPath}`,"native host 自动拉起失败。先运行 mearl check --local;缺少命令时运行 npx --@mearl:registry=https://registry.npmjs.org @mearl/setup --local --yes。","自动拉起只使用默认 daemon 参数;自定义 CDP/Profile/浏览器参数需手工启动,参见 mearl-native-host --help。","","【方式一:浏览器插件模式】",`1. 确认已安装 Mearl 浏览器插件(${EXTENSION_INSTALL_URL})`,"2. 确认已执行 Native Messaging 初始化(安装 @mearl/native-host 时会自动完成)","3. 确认 Chrome 浏览器正在运行,如仍无法连接可在 chrome://extensions 重新加载插件","","【方式二:CDP 远程调试模式(Chrome 145+,无需插件)】",' 访问 chrome://inspect/#remote-debugging,勾选 "Allow remote debugging for this browser instance"'," Chrome 会弹出授权提示,点击允许,native host 自动读取 DevToolsActivePort 文件连接"," 确认有普通网页已打开(非 chrome:// 页面)"].join(`
103
103
  `):error62.code==="ECONNREFUSED"?[`Socket 连接被拒绝: ${socketPath}`,"已尝试处理 stale socket,但 native host 自动恢复仍失败。请运行 mearl check --local 定位故障。","请确认 Chrome 浏览器正在运行,可尝试在 chrome://extensions 重新加载插件。","",installHint].join(`
104
104
  `):error62.code==="EPERM"?[`Socket 连接被执行环境拦截: ${socketPath}`,"当前进程没有访问该 Mearl Unix Socket 的权限(EPERM)。","如果命令运行在 Agent 沙箱中,请为这个 Socket 配置精确的 Unix Socket 白名单后重试。","无需重新安装浏览器插件,也不要使用 sudo 或改写 Socket 权限。"].join(`
105
105
  `):[`Socket 连接失败: ${error62.message}`,"",installHint].join(`
@@ -753,7 +753,7 @@ body {
753
753
  button, input, select, textarea { font: inherit; }
754
754
  </style>`,PLUGIN_PAGE_RUNTIME_HASH=createHash6("sha256").update(PAGE_BRIDGE_SCRIPT).update(PAGE_SECURITY_META).update(PAGE_THEME_STYLE).digest("hex")}});import{randomUUID as randomUUID9}from"node:crypto";import{closeSync as closeSync5,mkdirSync as mkdirSync4,openSync as openSync5,readFileSync as readFileSync9,readSync as readSync2,readdirSync as readdirSync5,renameSync as renameSync6,rmSync as rmSync5,statSync as statSync7,writeFileSync as writeFileSync4}from"node:fs";import{homedir as homedir3}from"node:os";import{isAbsolute as isAbsolute4,join as join12,resolve as resolve4}from"node:path";function pluginRegistrationNeedsRefresh(registration,includePage=!1){return!registration.source||pluginFileVersion(registration.entry)!==registration.source.entry||Object.entries(registration.source.profiles??{}).some(([path28,version3])=>{try{return pluginFileVersion(path28)!==version3}catch{return!0}})?!0:!includePage||!registration.toolbox?!1:registration.source.pageRuntime!==PLUGIN_PAGE_RUNTIME_HASH||!registration.source.page?!0:Object.entries(registration.source.page).some(([path28,version3])=>pluginFileVersion(path28)!==version3)}function pluginDirectory(){return resolve4(process.env.MEARL_PLUGIN_DIR||join12(homedir3(),".mearl","plugins"))}function pluginPageDirectory(){return join12(pluginDirectory(),".pages")}function pluginPageBundlePath(name,hash3){return join12(pluginPageDirectory(),`${name}-${hash3}.html`)}function removePluginPageBundles(name,exceptHash){let files;try{files=readdirSync5(pluginPageDirectory())}catch(error62){if(error62.code==="ENOENT")return;throw error62}let keep=exceptHash?`${name}-${exceptHash}.html`:void 0;for(let file2 of files)file2===keep||!file2.startsWith(`${name}-`)||!file2.endsWith(".html")||rmSync5(join12(pluginPageDirectory(),file2),{force:!0})}function normalizePageBundle(value){if(!value||typeof value!="object"||Array.isArray(value))throw new Error("invalid page bundle");let candidate=value;if(typeof candidate.hash!="string"||!/^[a-f0-9]{64}$/.test(candidate.hash)||!Number.isInteger(candidate.size)||(candidate.size??0)<=0||!Number.isInteger(candidate.chunks)||candidate.chunks!==Math.ceil((candidate.size??0)/PLUGIN_PAGE_CHUNK_BYTES))throw new Error("invalid page bundle");return{hash:candidate.hash,size:candidate.size,chunks:candidate.chunks}}function persistPluginPageBundle(name,bundle){let directory=pluginPageDirectory();mkdirSync4(directory,{recursive:!0,mode:448});let target=pluginPageBundlePath(name,bundle.hash);try{if(statSync7(target).isFile())return}catch{}let temporary=`${target}.${randomUUID9()}.tmp`;try{writeFileSync4(temporary,bundle.content,{mode:384,flag:"wx"}),renameSync6(temporary,target)}finally{rmSync5(temporary,{force:!0})}}function assertPluginName(name){if(!/^[a-z][a-z0-9-]*$/.test(name)||RESERVED_NAMES.has(name)||COMMAND_MAP.has(name))throw new PluginError("PLUGIN_INVALID_NAME",`不可用的插件名称: ${name}`)}function normalizePluginToolboxContribution(value){if(value===void 0)return;if(!value||typeof value!="object"||Array.isArray(value))throw new Error("toolbox 必须是对象");let candidate=value;if(candidate.displayMode!==void 0&&!["popup","tab","both"].includes(candidate.displayMode))throw new Error("toolbox.displayMode 必须是 popup、tab 或 both");let title=typeof candidate.title=="string"?candidate.title.trim():"",description=typeof candidate.description=="string"?candidate.description.trim():void 0,icon=typeof candidate.icon=="string"?candidate.icon.trim():void 0;if(candidate.version!==1)throw new Error("toolbox.version 必须为 1");if(!title||title.length>80)throw new Error("toolbox.title 必须是 1-80 个字符");if(description&&description.length>240)throw new Error("toolbox.description 不能超过 240 个字符");if(icon&&!parseToolboxIcon(icon))throw new Error("toolbox.icon 必须是图标名称、SVG、图片 Data URL 或 HTTP(S) 图片地址,最多 32768 个字符");let locales;if(candidate.locales!==void 0){if(!candidate.locales||typeof candidate.locales!="object"||Array.isArray(candidate.locales))throw new Error("toolbox.locales 必须是对象");let entries=Object.entries(candidate.locales);if(entries.length===0||entries.length>20)throw new Error("toolbox.locales 必须包含 1-20 个语言");locales=Object.fromEntries(entries.map(([locale,localized])=>{if(!/^[a-z]{2,3}(?:[_-][A-Za-z0-9]{2,8})*$/.test(locale))throw new Error(`toolbox.locales 包含无效语言: ${locale}`);if(!localized||typeof localized!="object"||Array.isArray(localized))throw new Error(`toolbox.locales.${locale} 必须是对象`);let localizedTitle=typeof localized.title=="string"?localized.title.trim():void 0,localizedDescription=typeof localized.description=="string"?localized.description.trim():void 0;if(localizedTitle!==void 0&&(!localizedTitle||localizedTitle.length>80))throw new Error(`toolbox.locales.${locale}.title 必须是 1-80 个字符`);if(localizedDescription!==void 0&&localizedDescription.length>240)throw new Error(`toolbox.locales.${locale}.description 不能超过 240 个字符`);if(!localizedTitle&&!localizedDescription)throw new Error(`toolbox.locales.${locale} 至少声明 title 或 description`);return[locale,{...localizedTitle?{title:localizedTitle}:{},...localizedDescription?{description:localizedDescription}:{}}]}))}if(!candidate.page||typeof candidate.page!="object"||Array.isArray(candidate.page))throw new Error("toolbox.page 必须是对象");let pageCandidate=candidate.page;if(pageCandidate.type!=="sandbox")throw new Error("toolbox.page.type 必须为 sandbox");if(pageCandidate.runtime!==void 0&&pageCandidate.runtime!=="preact")throw new Error("toolbox.page.runtime 仅支持 preact");let pageEntry=typeof pageCandidate.entry=="string"?pageCandidate.entry.trim():"";if(!pageEntry||pageEntry.length>240||isAbsolute4(pageEntry)||pageEntry.includes("\\")||pageEntry.split("/").some(segment=>!segment||segment==="."||segment===".."))throw new Error("toolbox.page.entry 必须是插件目录内的相对 HTML 路径");if(!Array.isArray(pageCandidate.commands))throw new Error("toolbox.page.commands 必须是命令名称数组");let commands=pageCandidate.commands.map(command=>typeof command=="string"?command.trim():"");if(commands.length===0||commands.length>64||new Set(commands).size!==commands.length||commands.some(command=>!/^[a-z][a-z0-9-]*$/.test(command)))throw new Error("toolbox.page.commands 必须包含 1-64 个不重复的插件命令名称");let page={type:"sandbox",...pageCandidate.runtime?{runtime:pageCandidate.runtime}:{},entry:pageEntry,commands};if("lifecycle"in pageCandidate)throw new Error("toolbox.page.lifecycle is unsupported; declare pageRuntime and activation rules");let agent2;if(candidate.agent!==void 0){if(!candidate.agent||typeof candidate.agent!="object"||Array.isArray(candidate.agent))throw new Error("toolbox.agent 必须是对象");let agentCandidate=candidate.agent,skill=typeof agentCandidate.skill=="string"?agentCandidate.skill.trim():"";if(!skill||skill.length>128||!/^[A-Za-z0-9][A-Za-z0-9._:@/-]*$/.test(skill))throw new Error("toolbox.agent.skill 必须是有效的 Skill 名称");let layout=agentCandidate.layout;if(layout!==void 0&&layout!=="drawer"&&layout!=="workspace")throw new Error("toolbox.agent.layout 必须是 drawer 或 workspace");agent2={skill,...layout?{layout}:{}}}if(candidate.order!==void 0&&(!Number.isInteger(candidate.order)||candidate.order<0||candidate.order>1e4))throw new Error("toolbox.order 必须是 0-10000 的整数");return{version:1,title,...candidate.displayMode!==void 0?{displayMode:candidate.displayMode}:{},...description?{description}:{},...icon?{icon}:{},...locales?{locales}:{},...agent2?{agent:agent2}:{},page,...candidate.order!==void 0?{order:candidate.order}:{}}}function findPluginDirectoryEntry(directory){for(let filename of["main.mjs","main.py"]){let entry=join12(directory,"scripts",filename);try{if(statSync7(entry).isFile())return entry}catch{}}}function resolvePluginEntry(target){let absolute=resolve4(target);try{let entry=statSync7(absolute).isDirectory()?findPluginDirectoryEntry(absolute):absolute;if(!entry)throw new Error("not a file");if(!statSync7(entry).isFile())throw new Error("not a file");return entry}catch{throw new PluginError("PLUGIN_ENTRY_MISSING",`入口不存在: ${absolute}(目录默认使用 scripts/main.mjs 或 scripts/main.py)`)}}function registerPlugin(name,target,description,options={}){assertPluginName(name);let entry=resolvePluginEntry(target),entryVersion=pluginFileVersion(entry),directory=pluginDirectory();mkdirSync4(directory,{recursive:!0,mode:448});let file2=join12(directory,`${name}.json`),temporary=`${file2}.${randomUUID9()}.tmp`,summary=description?.trim(),managedBy=options.managedBy?.trim(),toolbox;try{toolbox=normalizePluginToolboxContribution(options.toolbox)}catch(error62){throw new PluginError("PLUGIN_INVALID_TOOLBOX",error62 instanceof Error?error62.message:String(error62))}let builtPage;if(toolbox){try{builtPage=buildPluginPageBundle(entry,toolbox.page.entry)}catch(error62){throw new PluginError("PLUGIN_INVALID_TOOLBOX_PAGE",error62 instanceof Error?error62.message:String(error62))}persistPluginPageBundle(name,builtPage)}let record5={entry,...options.hasPublicCommands!==void 0?{hasPublicCommands:options.hasPublicCommands}:{},source:{entry:entryVersion,...options.profileSources?{profiles:options.profileSources}:{},...builtPage?{page:builtPage.sources,pageRuntime:PLUGIN_PAGE_RUNTIME_HASH}:{}},...summary?{description:summary}:{},...managedBy?{managedBy}:{},...toolbox?{toolbox}:{},...options.appProfiles?{appProfiles:validateAppProfileContribution(options.appProfiles)}:{},...builtPage?{pageBundle:{hash:builtPage.hash,size:builtPage.size,chunks:builtPage.chunks}}:{}};try{writeFileSync4(temporary,`${JSON.stringify(record5)}
755
755
  `,{mode:384,flag:"wx"}),renameSync6(temporary,file2)}finally{rmSync5(temporary,{force:!0})}return removePluginPageBundles(name,builtPage?.hash),entry}function unregisterPlugin(name){assertPluginName(name);let file2=join12(pluginDirectory(),`${name}.json`);try{return rmSync5(file2),rmSync5(join12(pluginDirectory(),".host","installations",`${name}.json`),{force:!0}),removePluginPageBundles(name),!0}catch(error62){if(error62.code==="ENOENT")return!1;throw new PluginError("PLUGIN_UNINSTALL_FAILED",`无法移除插件注册: ${file2}`)}}function findPluginRegistration(name){if(!/^[a-z][a-z0-9-]*$/.test(name))return;let file2=join12(pluginDirectory(),`${name}.json`),content;try{content=readFileSync9(file2,"utf8")}catch(error62){if(error62.code==="ENOENT")return;throw new PluginError("PLUGIN_REGISTRY_INVALID",`无法读取插件记录: ${file2}`)}try{let record5=JSON.parse(content);if(typeof record5?.entry!="string"||!isAbsolute4(record5.entry))throw new Error("invalid entry");if(record5.hasPublicCommands!==void 0&&typeof record5.hasPublicCommands!="boolean")throw new Error("invalid public commands");let description=typeof record5.description=="string"&&record5.description.trim()?record5.description.trim():void 0,managedBy=typeof record5.managedBy=="string"&&record5.managedBy.trim()?record5.managedBy.trim():void 0,toolbox=normalizePluginToolboxContribution(record5.toolbox),pageBundle=toolbox?normalizePageBundle(record5.pageBundle):void 0,appProfiles=validateAppProfileContribution(record5.appProfiles),source=record5.source;if(source!==void 0&&(!source||typeof source!="object"||Array.isArray(source)||typeof source.entry!="string"||source.profiles!==void 0&&(!source.profiles||typeof source.profiles!="object"||Array.isArray(source.profiles)||Object.entries(source.profiles).some(([path28,version3])=>!isAbsolute4(path28)||typeof version3!="string"))||source.pageRuntime!==void 0&&(typeof source.pageRuntime!="string"||!/^[a-f0-9]{64}$/.test(source.pageRuntime))||source.page!==void 0&&(!source.page||typeof source.page!="object"||Array.isArray(source.page)||Object.entries(source.page).some(([path28,version3])=>!isAbsolute4(path28)||typeof version3!="string"))))throw new Error("invalid source");return{entry:record5.entry,...record5.hasPublicCommands!==void 0?{hasPublicCommands:record5.hasPublicCommands}:{},...description?{description}:{},...managedBy?{managedBy}:{},...toolbox?{toolbox}:{},...pageBundle?{pageBundle}:{},...appProfiles?{appProfiles}:{},...source?{source}:{}}}catch{throw new PluginError("PLUGIN_REGISTRY_INVALID",`无效的插件记录: ${file2}`)}}function readPluginPageBundleChunk(name,hash3,index){assertPluginName(name);let bundle=findPluginRegistration(name)?.pageBundle;if(!bundle||bundle.hash!==hash3)throw new PluginError("PLUGIN_PAGE_CHANGED",`插件页面已更新: ${name}`);if(!Number.isInteger(index)||index<0||index>=bundle.chunks)throw new PluginError("PLUGIN_PAGE_CHUNK_INVALID",`插件页面分块无效: ${index}`);let path28=pluginPageBundlePath(name,hash3),size;try{size=statSync7(path28).size}catch{throw new PluginError("PLUGIN_PAGE_INVALID",`插件页面产物不存在: ${name}`)}if(size!==bundle.size)throw new PluginError("PLUGIN_PAGE_INVALID",`插件页面产物损坏: ${name}`);let start=index*PLUGIN_PAGE_CHUNK_BYTES,content=Buffer.allocUnsafe(Math.min(PLUGIN_PAGE_CHUNK_BYTES,bundle.size-start)),descriptor;try{descriptor=openSync5(path28,"r")}catch{throw new PluginError("PLUGIN_PAGE_INVALID",`插件页面产物无法读取: ${name}`)}let bytesRead;try{bytesRead=readSync2(descriptor,content,0,content.byteLength,start)}finally{closeSync5(descriptor)}if(bytesRead!==content.byteLength)throw new PluginError("PLUGIN_PAGE_INVALID",`插件页面产物损坏: ${name}`);return{data:content.toString("base64"),hash:hash3,index,total:bundle.chunks}}function findPluginEntry(name){return findPluginRegistration(name)?.entry}function listPluginNames(){try{return readdirSync5(pluginDirectory()).filter(file2=>/^[a-z][a-z0-9-]*\.json$/.test(file2)).map(file2=>file2.slice(0,-5)).sort()}catch(error62){if(error62.code==="ENOENT")return[];throw new PluginError("PLUGIN_REGISTRY_INVALID","无法读取插件目录")}}var RESERVED_NAMES,PluginError,init_pluginRegistry=__esm({"../client/dist/plugins/pluginRegistry.js"(){"use strict";init_dist5();init_dist5();init_commands();init_pluginPageBundle();init_pluginSource();RESERVED_NAMES=new Set(["check","help","connector_list","capture_checkpoint","plugin","plugins"]),PluginError=class extends Error{code;constructor(code,message){super(`${code}: ${message}`),this.code=code}}}});import{constants as constants3,closeSync as closeSync6,fstatSync as fstatSync2,lstatSync as lstatSync2,mkdirSync as mkdirSync5,openSync as openSync6,readSync as readSync3,readFileSync as readFileSync10,renameSync as renameSync7,rmSync as rmSync6,writeFileSync as writeFileSync5}from"node:fs";import{createHash as createHash7,randomUUID as randomUUID10}from"node:crypto";import{isAbsolute as isAbsolute5,join as join13}from"node:path";function validateOfficialPluginCatalog(value){if(!value||typeof value!="object"||Array.isArray(value))throw new Error("Invalid managed plugin catalog");let input3=value;if(input3.schemaVersion!==1||typeof input3.revision!="string"||!/^[a-f0-9]{64}$/.test(input3.revision)||!input3.plugins||typeof input3.plugins!="object"||Array.isArray(input3.plugins)||Object.keys(input3).some(key=>!["schemaVersion","revision","plugins","selection"].includes(key))||Object.keys(input3.plugins).length>200)throw new Error("Invalid managed plugin catalog");let selection2=input3.selection;if(selection2!==void 0&&(!selection2||typeof selection2!="object"||Array.isArray(selection2)||Object.keys(selection2).some(key=>!["path","sha256"].includes(key))||typeof selection2.path!="string"||!isAbsolute5(selection2.path)||selection2.path.length>4096||/[\0\r\n]/.test(selection2.path)||typeof selection2.sha256!="string"||!/^[a-f0-9]{64}$/.test(selection2.sha256)))throw new Error("Invalid plugin catalog selection");let plugins={};for(let[name,value2]of Object.entries(input3.plugins)){if(assertPluginName(name),!value2||typeof value2!="object"||Array.isArray(value2))throw new Error("Invalid managed plugin declaration");let item=value2;if(Object.keys(item).some(key=>!["description","installArgs","setup","skill"].includes(key))||typeof item.description!="string"||item.description.length>1e3||typeof item.skill!="string"||!/^[a-z][a-z0-9-]*$/.test(item.skill)||!Array.isArray(item.installArgs)||item.installArgs.length===0||item.installArgs.length>32||item.installArgs.some(arg=>typeof arg!="string"||arg.length>2048||/[\0\r\n]/.test(arg))||item.setup!==void 0&&(typeof item.setup!="string"||!/^[a-z][a-z0-9-]*$/.test(item.setup)))throw new Error("Invalid managed plugin declaration");plugins[name]={description:item.description,skill:item.skill,installArgs:[...item.installArgs],...item.setup!==void 0&&{setup:item.setup}}}let catalog={schemaVersion:1,revision:input3.revision,plugins,...selection2?{selection:{path:selection2.path,sha256:selection2.sha256}}:{}};if(Buffer.byteLength(JSON.stringify(catalog))>MAX_CATALOG_BYTES)throw new Error("Managed plugin catalog exceeds 256 KiB");return catalog}function selectionMatches(selection2){try{let before=lstatSync2(selection2.path);if(!before.isFile()||before.isSymbolicLink()||before.size>1024*1024)return!1;let fd=openSync6(selection2.path,constants3.O_RDONLY|(constants3.O_NOFOLLOW??0));try{let stat5=fstatSync2(fd);if(!stat5.isFile()||stat5.size>1024*1024)return!1;let bytes=Buffer.alloc(stat5.size+1),size=0;for(;size<bytes.length;){let count=readSync3(fd,bytes,size,bytes.length-size,null);if(!count)break;size+=count}return size===stat5.size&&createHash7("sha256").update(bytes.subarray(0,size)).digest("hex")===selection2.sha256}finally{closeSync6(fd)}}catch(error62){if(error62.code==="ENOENT")return!1;throw error62}}function readOfficialPluginCatalog(){let source;try{source=readFileSync10(catalogPath(),"utf8")}catch(error62){if(error62.code==="ENOENT")return;throw error62}if(Buffer.byteLength(source)>MAX_CATALOG_BYTES)throw new Error("Managed plugin catalog exceeds 256 KiB");let catalog=validateOfficialPluginCatalog(JSON.parse(source));return catalog.selection&&!selectionMatches(catalog.selection)?void 0:catalog}function replaceOfficialPluginCatalog(revision2,plugins,selection2){let catalog=validateOfficialPluginCatalog({schemaVersion:1,revision:revision2,plugins,...selection2?{selection:selection2}:{}}),content=JSON.stringify(catalog);if(Buffer.byteLength(content)>MAX_CATALOG_BYTES)throw new Error("Managed plugin catalog exceeds 256 KiB");if(catalog.selection&&!selectionMatches(catalog.selection))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");mkdirSync5(pluginDirectory(),{recursive:!0,mode:448});let file2=catalogPath(),temporary=`${file2}.${randomUUID10()}.tmp`;try{if(writeFileSync5(temporary,content,{mode:384,flag:"wx"}),catalog.selection&&!selectionMatches(catalog.selection))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");renameSync7(temporary,file2)}finally{rmSync6(temporary,{force:!0})}refreshOfficialPlugins()}function refreshOfficialPlugins(){let plugins={};try{plugins=readOfficialPluginCatalog()?.plugins??{}}catch{}for(let name of Object.keys(OFFICIAL_PLUGINS))delete OFFICIAL_PLUGINS[name];return Object.assign(OFFICIAL_PLUGINS,plugins),OFFICIAL_PLUGINS}function findOfficialPlugin(name){let plugins=refreshOfficialPlugins();return Object.hasOwn(plugins,name)?plugins[name]:void 0}function listOfficialPluginNames(setup){return Object.entries(refreshOfficialPlugins()).filter(([,item])=>setup===void 0||item.setup===setup).map(([name])=>name)}var OFFICIAL_PLUGIN_MANAGER,OFFICIAL_PLUGINS,MAX_CATALOG_BYTES,catalogPath,init_officialPluginCatalog=__esm({"../client/dist/plugins/officialPluginCatalog.js"(){"use strict";init_pluginRegistry();OFFICIAL_PLUGIN_MANAGER="@mearl/setup:official",OFFICIAL_PLUGINS={},MAX_CATALOG_BYTES=256*1024,catalogPath=()=>join13(pluginDirectory(),".official-catalog.json");refreshOfficialPlugins()}});import{closeSync as closeSync7,mkdirSync as mkdirSync6,openSync as openSync7,rmSync as rmSync7,statSync as statSync8,writeFileSync as writeFileSync6}from"node:fs";import{join as join14}from"node:path";import{spawn as spawn5}from"node:child_process";function delay2(milliseconds){return new Promise(resolve16=>setTimeout(resolve16,milliseconds))}function installLockPath(name){return join14(pluginDirectory(),`.official-${name}.install.lock`)}async function acquireInstallLock(name){let directory=pluginDirectory();mkdirSync6(directory,{recursive:!0,mode:448});let lockPath=installLockPath(name),deadline=Date.now()+INSTALL_TIMEOUT_MS;for(;;){let descriptor;try{return descriptor=openSync7(lockPath,"wx",384),writeFileSync6(descriptor,`${process.pid}
756
- `),closeSync7(descriptor),()=>rmSync7(lockPath,{force:!0})}catch(error62){if(descriptor!==void 0&&closeSync7(descriptor),error62.code!=="EEXIST")throw error62}if(findPluginRegistration(name))return()=>{};try{if(Date.now()-statSync8(lockPath).mtimeMs>INSTALL_LOCK_STALE_MS){rmSync7(lockPath,{force:!0});continue}}catch(error62){if(error62.code==="ENOENT")continue;throw error62}if(Date.now()>=deadline)throw new Error(`等待安装官方插件 ${name} 超时`);await delay2(250)}}function appendOutput(current2,chunk){return current2.length>=MAX_INSTALL_OUTPUT?current2:(current2+chunk.toString("utf8")).slice(0,MAX_INSTALL_OUTPUT)}function installWithSetup(name){return new Promise((resolve16,reject)=>{let command=process.platform==="win32"?"npx.cmd":"npx",child=spawn5(command,["-y",`@mearl/setup@${CLIENT_VERSION}`,"plugin","ensure",name],{stdio:["ignore","pipe","pipe"],windowsHide:!0}),stdout="",stderr="",settled=!1,finish=error62=>{settled||(settled=!0,clearTimeout(timer),error62?reject(error62):resolve16())},timer=setTimeout(()=>{child.kill("SIGTERM"),finish(new Error(`安装官方插件 ${name} 超时`))},INSTALL_TIMEOUT_MS);child.stdout.on("data",chunk=>stdout=appendOutput(stdout,chunk)),child.stderr.on("data",chunk=>stderr=appendOutput(stderr,chunk)),child.once("error",error62=>finish(error62)),child.once("exit",code=>{if(code===0){finish();return}let detail=(stderr||stdout).replace(/[\r\n]+/g," ").trim().slice(-1e3);finish(new Error(detail?`安装官方插件 ${name} 失败 (exit ${code}): ${detail}`:`安装官方插件 ${name} 失败 (exit ${code})`))})})}async function installOfficialPlugin(name,progress){if(findPluginRegistration(name))return;if(!findOfficialPlugin(name))throw new Error(`未知官方插件: ${name}`);let releaseLock=await acquireInstallLock(name);try{if(findPluginRegistration(name))return;let accepted=JSON.stringify(readOfficialPluginCatalog());if(!findOfficialPlugin(name))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(progress?.(`正在安装官方插件 ${name}...`),await installWithSetup(name),JSON.stringify(readOfficialPluginCatalog())!==accepted)throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(!findPluginRegistration(name))throw new Error(`官方插件 ${name} 安装完成后仍未注册`);progress?.(`官方插件 ${name} 已安装。`)}finally{releaseLock()}}var INSTALL_TIMEOUT_MS,INSTALL_LOCK_STALE_MS,MAX_INSTALL_OUTPUT,activeInstallations,ensureOfficialPluginRegistered,init_officialPluginInstaller=__esm({"../client/dist/plugins/officialPluginInstaller.js"(){"use strict";init_runtimePaths();init_officialPluginCatalog();init_pluginRegistry();INSTALL_TIMEOUT_MS=18e4,INSTALL_LOCK_STALE_MS=5*6e4,MAX_INSTALL_OUTPUT=1024*1024,activeInstallations=new Map;ensureOfficialPluginRegistered=(name,progress)=>{let active=activeInstallations.get(name);if(active)return active;let installation=installOfficialPlugin(name,progress).finally(()=>{activeInstallations.delete(name)});return activeInstallations.set(name,installation),installation}}});function serializePluginExecutionError(error62){let value=error62,metadata=Object.fromEntries(Object.entries(value&&typeof value=="object"?value:{}).filter(([key,field])=>!["__proto__","prototype","constructor","message","stack","code","details"].includes(key)&&(field===null||["string","number","boolean"].includes(typeof field)))),serialized={message:typeof value?.message=="string"?value.message:String(error62),...typeof value?.code=="string"?{code:value.code}:{},...value?.details&&typeof value.details=="object"&&!Array.isArray(value.details)?{details:value.details}:{},...Object.keys(metadata).length?{metadata}:{}};try{if(Buffer.byteLength(JSON.stringify(serialized))<=64*1024)return serialized}catch{}return{message:Buffer.from(serialized.message).subarray(0,8192).toString("utf8"),...serialized.code?{code:serialized.code.slice(0,256)}:{},details:{diagnosticTruncated:!0},metadata:Object.fromEntries(Object.entries(metadata).slice(0,32).map(([key,field])=>[key.slice(0,128),typeof field=="string"?field.slice(0,512):field]))}}function pluginExecutionError(value){return Object.assign(new Error(value.message),{...Object.fromEntries(Object.entries(value.metadata??{}).filter(([key])=>!["__proto__","prototype","constructor","message","stack","code","details"].includes(key))),...value.code?{code:value.code}:{},...value.details?{details:value.details}:{}})}var init_pluginExecutorProtocol=__esm({"../client/dist/plugins/runtime/pluginExecutorProtocol.js"(){"use strict"}});import{spawn as spawn6}from"node:child_process";import{createInterface}from"node:readline";function pythonExecutable(){return process.env.MEARL_PYTHON?.trim()||"python3"}function isObject(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function parseDescriptor(message){if(!Array.isArray(message.commands))throw new Error("Python 插件未返回命令列表");let commands=message.commands.map(value=>{if(!isObject(value)||typeof value.signature!="string"||typeof value.description!="string"||typeof value.toolboxOnly!="boolean"||typeof value.runtimeOnly!="boolean")throw new Error("Python 插件返回了无效的命令描述");return{signature:value.signature,description:value.description,toolboxOnly:value.toolboxOnly,runtimeOnly:value.runtimeOnly,recoveryOnly:value.recoveryOnly===!0,migrationOnly:value.migrationOnly===!0}});if(message.name!==void 0&&typeof message.name!="string")throw new Error("Python 插件返回了无效的 name");if(message.description!==void 0&&typeof message.description!="string")throw new Error("Python 插件返回了无效的 description");return{commands,...typeof message.name=="string"?{name:message.name}:{},...typeof message.description=="string"?{description:message.description}:{},...message.toolbox!==void 0?{toolbox:message.toolbox}:{},...message.pageRuntime!==void 0?{pageRuntime:message.pageRuntime}:{},...message.stateStorage!==void 0?{stateStorage:message.stateStorage}:{},...message.taskRecovery!==void 0?{taskRecovery:message.taskRecovery}:{},...message.appProfiles!==void 0?{appProfiles:message.appProfiles}:{}}}function bridgedError(message){let detail=typeof message.message=="string"?message.message:"Python 插件执行失败",restored=pluginExecutionError({message:detail,...typeof message.code=="string"?{code:message.code}:{},...isObject(message.details)?{details:message.details}:{},...isObject(message.metadata)?{metadata:message.metadata}:{}});return typeof message.code=="string"&&/^PLUGIN_[A-Z0-9_]+$/.test(message.code)?Object.assign(new PluginError(message.code,detail),restored):restored}function errorResponse(error62){let serialized=serializePluginExecutionError(error62);if(error62 instanceof PluginError){let prefix=`${error62.code}: `;return{...serialized,code:error62.code,message:error62.message.startsWith(prefix)?error62.message.slice(prefix.length):error62.message}}return serialized}async function runPythonWorker(entry,initial,app,signal,expectedDescriptor){return new Promise((resolve16,reject)=>{let executable=pythonExecutable(),child=spawn6(executable,["-u","-c",PYTHON_BOOTSTRAP,entry],{stdio:["pipe","pipe","pipe"],windowsHide:!0}),lines=createInterface({input:child.stdout}),descriptor,outcome,protocolError,stderr="",failProtocol=error62=>{protocolError||(protocolError=error62 instanceof Error?error62:new Error(String(error62)),cancel())},write=message=>{try{child.stdin.write(`${JSON.stringify(message)}
756
+ `),closeSync7(descriptor),()=>rmSync7(lockPath,{force:!0})}catch(error62){if(descriptor!==void 0&&closeSync7(descriptor),error62.code!=="EEXIST")throw error62}if(findPluginRegistration(name))return()=>{};try{if(Date.now()-statSync8(lockPath).mtimeMs>INSTALL_LOCK_STALE_MS){rmSync7(lockPath,{force:!0});continue}}catch(error62){if(error62.code==="ENOENT")continue;throw error62}if(Date.now()>=deadline)throw new Error(`等待安装官方插件 ${name} 超时`);await delay2(250)}}function appendOutput(current2,chunk){return current2.length>=MAX_INSTALL_OUTPUT?current2:(current2+chunk.toString("utf8")).slice(0,MAX_INSTALL_OUTPUT)}function installWithSetup(name){return new Promise((resolve16,reject)=>{let command=process.platform==="win32"?"npx.cmd":"npx",child=spawn5(command,["-y","--@mearl:registry=https://registry.npmjs.org",`@mearl/setup@${CLIENT_VERSION}`,"plugin","ensure",name],{stdio:["ignore","pipe","pipe"],windowsHide:!0}),stdout="",stderr="",settled=!1,finish=error62=>{settled||(settled=!0,clearTimeout(timer),error62?reject(error62):resolve16())},timer=setTimeout(()=>{child.kill("SIGTERM"),finish(new Error(`安装官方插件 ${name} 超时`))},INSTALL_TIMEOUT_MS);child.stdout.on("data",chunk=>stdout=appendOutput(stdout,chunk)),child.stderr.on("data",chunk=>stderr=appendOutput(stderr,chunk)),child.once("error",error62=>finish(error62)),child.once("exit",code=>{if(code===0){finish();return}let detail=(stderr||stdout).replace(/[\r\n]+/g," ").trim().slice(-1e3);finish(new Error(detail?`安装官方插件 ${name} 失败 (exit ${code}): ${detail}`:`安装官方插件 ${name} 失败 (exit ${code})`))})})}async function installOfficialPlugin(name,progress){if(findPluginRegistration(name))return;if(!findOfficialPlugin(name))throw new Error(`未知官方插件: ${name}`);let releaseLock=await acquireInstallLock(name);try{if(findPluginRegistration(name))return;let accepted=JSON.stringify(readOfficialPluginCatalog());if(!findOfficialPlugin(name))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(progress?.(`正在安装官方插件 ${name}...`),await installWithSetup(name),JSON.stringify(readOfficialPluginCatalog())!==accepted)throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(!findPluginRegistration(name))throw new Error(`官方插件 ${name} 安装完成后仍未注册`);progress?.(`官方插件 ${name} 已安装。`)}finally{releaseLock()}}var INSTALL_TIMEOUT_MS,INSTALL_LOCK_STALE_MS,MAX_INSTALL_OUTPUT,activeInstallations,ensureOfficialPluginRegistered,init_officialPluginInstaller=__esm({"../client/dist/plugins/officialPluginInstaller.js"(){"use strict";init_runtimePaths();init_officialPluginCatalog();init_pluginRegistry();INSTALL_TIMEOUT_MS=18e4,INSTALL_LOCK_STALE_MS=5*6e4,MAX_INSTALL_OUTPUT=1024*1024,activeInstallations=new Map;ensureOfficialPluginRegistered=(name,progress)=>{let active=activeInstallations.get(name);if(active)return active;let installation=installOfficialPlugin(name,progress).finally(()=>{activeInstallations.delete(name)});return activeInstallations.set(name,installation),installation}}});function serializePluginExecutionError(error62){let value=error62,metadata=Object.fromEntries(Object.entries(value&&typeof value=="object"?value:{}).filter(([key,field])=>!["__proto__","prototype","constructor","message","stack","code","details"].includes(key)&&(field===null||["string","number","boolean"].includes(typeof field)))),serialized={message:typeof value?.message=="string"?value.message:String(error62),...typeof value?.code=="string"?{code:value.code}:{},...value?.details&&typeof value.details=="object"&&!Array.isArray(value.details)?{details:value.details}:{},...Object.keys(metadata).length?{metadata}:{}};try{if(Buffer.byteLength(JSON.stringify(serialized))<=64*1024)return serialized}catch{}return{message:Buffer.from(serialized.message).subarray(0,8192).toString("utf8"),...serialized.code?{code:serialized.code.slice(0,256)}:{},details:{diagnosticTruncated:!0},metadata:Object.fromEntries(Object.entries(metadata).slice(0,32).map(([key,field])=>[key.slice(0,128),typeof field=="string"?field.slice(0,512):field]))}}function pluginExecutionError(value){return Object.assign(new Error(value.message),{...Object.fromEntries(Object.entries(value.metadata??{}).filter(([key])=>!["__proto__","prototype","constructor","message","stack","code","details"].includes(key))),...value.code?{code:value.code}:{},...value.details?{details:value.details}:{}})}var init_pluginExecutorProtocol=__esm({"../client/dist/plugins/runtime/pluginExecutorProtocol.js"(){"use strict"}});import{spawn as spawn6}from"node:child_process";import{createInterface}from"node:readline";function pythonExecutable(){return process.env.MEARL_PYTHON?.trim()||"python3"}function isObject(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function parseDescriptor(message){if(!Array.isArray(message.commands))throw new Error("Python 插件未返回命令列表");let commands=message.commands.map(value=>{if(!isObject(value)||typeof value.signature!="string"||typeof value.description!="string"||typeof value.toolboxOnly!="boolean"||typeof value.runtimeOnly!="boolean")throw new Error("Python 插件返回了无效的命令描述");return{signature:value.signature,description:value.description,toolboxOnly:value.toolboxOnly,runtimeOnly:value.runtimeOnly,recoveryOnly:value.recoveryOnly===!0,migrationOnly:value.migrationOnly===!0}});if(message.name!==void 0&&typeof message.name!="string")throw new Error("Python 插件返回了无效的 name");if(message.description!==void 0&&typeof message.description!="string")throw new Error("Python 插件返回了无效的 description");return{commands,...typeof message.name=="string"?{name:message.name}:{},...typeof message.description=="string"?{description:message.description}:{},...message.toolbox!==void 0?{toolbox:message.toolbox}:{},...message.pageRuntime!==void 0?{pageRuntime:message.pageRuntime}:{},...message.stateStorage!==void 0?{stateStorage:message.stateStorage}:{},...message.taskRecovery!==void 0?{taskRecovery:message.taskRecovery}:{},...message.appProfiles!==void 0?{appProfiles:message.appProfiles}:{}}}function bridgedError(message){let detail=typeof message.message=="string"?message.message:"Python 插件执行失败",restored=pluginExecutionError({message:detail,...typeof message.code=="string"?{code:message.code}:{},...isObject(message.details)?{details:message.details}:{},...isObject(message.metadata)?{metadata:message.metadata}:{}});return typeof message.code=="string"&&/^PLUGIN_[A-Z0-9_]+$/.test(message.code)?Object.assign(new PluginError(message.code,detail),restored):restored}function errorResponse(error62){let serialized=serializePluginExecutionError(error62);if(error62 instanceof PluginError){let prefix=`${error62.code}: `;return{...serialized,code:error62.code,message:error62.message.startsWith(prefix)?error62.message.slice(prefix.length):error62.message}}return serialized}async function runPythonWorker(entry,initial,app,signal,expectedDescriptor){return new Promise((resolve16,reject)=>{let executable=pythonExecutable(),child=spawn6(executable,["-u","-c",PYTHON_BOOTSTRAP,entry],{stdio:["pipe","pipe","pipe"],windowsHide:!0}),lines=createInterface({input:child.stdout}),descriptor,outcome,protocolError,stderr="",failProtocol=error62=>{protocolError||(protocolError=error62 instanceof Error?error62:new Error(String(error62)),cancel())},write=message=>{try{child.stdin.write(`${JSON.stringify(message)}
757
757
  `)}catch(error62){failProtocol(error62)}};child.stderr.setEncoding("utf8"),child.stderr.on("data",chunk=>{stderr=`${stderr}${chunk}`.slice(-STDERR_LIMIT)}),child.stdin.on("error",()=>{});let killTimer,terminalStopRequested=!1,armKill=()=>{killTimer||(killTimer=setTimeout(()=>{terminalStopRequested=!protocolError&&!signal?.aborted&&!!(outcome||initial.mode==="describe"&&descriptor),child.kill("SIGKILL")},1e3),killTimer.unref())},cancel=()=>{child.kill("SIGTERM"),armKill()};signal?.addEventListener("abort",cancel,{once:!0}),signal?.aborted&&cancel(),child.once("error",error62=>{error62.code==="ENOENT"?reject(new Error(`未找到 ${executable},Python 插件需要 Python 3.9 或更高版本(可通过 MEARL_PYTHON 指定解释器)`)):reject(error62)}),lines.on("line",line=>{if(protocolError)return;let message;try{let value=JSON.parse(line);if(!isObject(value)||typeof value.type!="string")throw new Error("消息不是对象");message=value}catch(error62){failProtocol(new Error(`Python 插件输出了无效协议消息: ${line.slice(0,200)}`,error62 instanceof Error?{cause:error62}:void 0));return}if(message.type==="ready"){try{if(descriptor)throw new Error("Python 插件重复发送 ready");if(descriptor=parseDescriptor(message),initial.mode==="run"&&expectedDescriptor&&pluginRecoverySignature(descriptor)!==pluginRecoverySignature(expectedDescriptor))throw new PluginError("PLUGIN_DECLARATION_CHANGED","Python execution declaration differs from its loaded metadata");write({type:"ready_ack"}),initial.mode==="describe"&&armKill()}catch(error62){failProtocol(error62)}return}if(message.type==="progress"){if(!app||typeof message.message!="string"){failProtocol(new Error("Python 插件发送了无效的 progress 消息"));return}try{app.progress(message.message)}catch(error62){failProtocol(error62)}return}if(message.type==="invoke"){if(!app||typeof message.id!="number"||typeof message.action!="string"||!isObject(message.payload)||!isObject(message.options)){failProtocol(new Error("Python 插件发送了无效的 invoke 消息"));return}let{action,payload,options}=message;Promise.resolve().then(()=>action==="plugin_task_checkpoint"&&app.checkpoint?app.checkpoint(payload.data,payload.expectedSequence):action==="plugin_model"&&payload.operation==="run"&&app.model?app.model(payload.request,message.stream?{onProgress:progress=>{!signal?.aborted&&!outcome&&write({type:"invoke-progress",id:message.id,progress})}}:void 0):action==="plugin_state"&&app.state?app.state(payload.collection,payload.operation,payload):action==="plugin_page"&&app.page?app.page(payload.operation,payload):app.invoke(action,payload,options)).then(result=>{write({type:"response",id:message.id,result:result===void 0?null:result})}).catch(error62=>{write({type:"response",id:message.id,error:errorResponse(error62)})});return}if(message.type==="result"){outcome||(outcome={hasResult:!0,result:message.result}),write({type:"terminal_ack"}),armKill();return}if(message.type==="error"){outcome||(outcome={error:bridgedError(message)}),write({type:"terminal_ack"}),armKill();return}failProtocol(new Error(`Python 插件发送了未知消息类型: ${message.type}`))});let finished=!1,finish=code=>{if(!finished){if(finished=!0,signal?.removeEventListener("abort",cancel),killTimer&&clearTimeout(killTimer),lines.close(),child.stdin.destroy(),child.stdout.destroy(),child.stderr.destroy(),signal?.aborted){reject(signal.reason??new Error("Plugin command cancelled"));return}if(protocolError){reject(protocolError);return}if(outcome?.error){reject(outcome.error);return}if(code!==0&&!terminalStopRequested){reject(new Error(stderr.trim()||`Python 插件进程异常退出${code===null?"":` (exit ${code})`}`));return}if(!descriptor){reject(new Error("Python 插件未返回注册信息"));return}if(initial.mode==="run"&&!outcome?.hasResult){reject(new Error("Python 插件未返回执行结果"));return}resolve16({descriptor,...outcome?.hasResult?{result:outcome.result}:{}})}};child.once("exit",finish),child.once("close",finish),write(initial)})}async function describePythonPlugin(entry,options){let{descriptor}=await runPythonWorker(entry,{mode:"describe",options});return descriptor}async function runPythonPluginCommand(entry,command,input3,app,context,recovery=!1,expectedDescriptor,runtimeOnly=!1){let{result}=await runPythonWorker(entry,{mode:"run",command,input:input3,options:app.options,identity:context.identity,recovery,runtime:runtimeOnly},app,context.signal,expectedDescriptor);return result}var STDERR_LIMIT,PYTHON_BOOTSTRAP,init_pythonPlugin=__esm({"../client/dist/plugins/runtime/pythonPlugin.js"(){"use strict";init_pluginRecoveryDefinition();init_pluginRegistry();init_pluginExecutorProtocol();STDERR_LIMIT=64*1024,PYTHON_BOOTSTRAP=String.raw`
758
758
  import asyncio
759
759
  import importlib.util
@@ -1086,7 +1086,7 @@ except BaseException as error:
1086
1086
  sys.exit(1)
1087
1087
  `}});import{randomUUID as randomUUID11}from"node:crypto";import{linkSync as linkSync2,mkdirSync as mkdirSync7,readFileSync as readFileSync11,rmSync as rmSync8,writeFileSync as writeFileSync7}from"node:fs";import{join as join15}from"node:path";function localPluginExecutionHost(){let directory=pluginDirectory(),hostId=hostIds.get(directory);if(!hostId){mkdirSync7(directory,{recursive:!0,mode:448});let file2=join15(directory,".execution-host-id"),proposed=randomUUID11(),temporary=`${file2}.${proposed}.tmp`;try{writeFileSync7(temporary,proposed,{flag:"wx",mode:384}),linkSync2(temporary,file2)}catch(error62){if(error62.code!=="EEXIST")throw error62}finally{rmSync8(temporary,{force:!0})}if(hostId=readFileSync11(file2,"utf8").trim(),!UUID.test(hostId))throw new Error("Invalid plugin execution host identity");hostIds.set(directory,hostId)}return Object.freeze({hostId,epoch})}function createPluginInvocationIdentity(plugin,source,parent){return Object.freeze({invocationId:randomUUID11(),host:parent?.host??localPluginExecutionHost(),plugin,source,...parent?{parentInvocationId:parent.invocationId}:{}})}var epoch,hostIds,UUID,init_pluginExecution2=__esm({"../client/dist/plugins/runtime/pluginExecution.js"(){"use strict";init_pluginRegistry();epoch=randomUUID11(),hostIds=new Map,UUID=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i}});import{execFile}from"node:child_process";async function stopPluginProcessTree(pid){if(!Number.isSafeInteger(pid)||pid<1)throw new Error("Invalid plugin process group");if(process.platform==="win32")return new Promise((resolve16,reject)=>{execFile("taskkill",["/PID",String(pid),"/T","/F"],{windowsHide:!0,timeout:5e3},error62=>{error62?reject(error62):resolve16()})});try{process.kill(-pid,"SIGKILL")}catch(error62){if(error62.code==="ESRCH")return;throw error62}let deadline=Date.now()+5e3;for(;isProcessGroupAlive(pid);){if(Date.now()>=deadline)throw new Error("Unable to confirm plugin process group stopped");await new Promise(resolve16=>setTimeout(resolve16,20))}}var init_pluginProcessTree=__esm({"../client/dist/plugins/runtime/pluginProcessTree.js"(){"use strict";init_dist()}});import{fork}from"node:child_process";async function executeRegisteredPlugin(plugin,invocation2,context,options={},dependencies={}){let{signal,onProgress,source,access="public",executionTimeoutMs,cancellationGraceMs=1e3,workerPath,cwd,environment,describe:describe3,model,recovery,migration,expectedRecovery,onExecutorStarted,onExecutorStopped,onDiagnostic,...invokeOptions}=options;for(let[name,value]of[["executionTimeoutMs",executionTimeoutMs],["cancellationGraceMs",cancellationGraceMs]])if(value!==void 0&&(!Number.isSafeInteger(value)||value<1||value>2147483647))throw new Error(`${name} must be a positive integer within the timer range`);signal?.throwIfAborted();let registration=dependencies.registration??findPluginRegistration(plugin);if(!registration)throw new PluginError("PLUGIN_NOT_REGISTERED",`插件未注册: ${plugin}`);let identity3=context.invocation??createPluginInvocationIdentity(plugin,source??context.source??"sdk",context.parentInvocation),entryVersion=pluginFileVersion(registration.entry);return new Promise((resolve16,reject)=>{let child=fork(workerPath??PLUGIN_WORKER_PATH,[],{stdio:["ignore","ignore","pipe","ipc"],serialization:"advanced",execArgv:[],detached:process.platform!=="win32",...cwd?{cwd}:{},...environment?{env:environment}:{}}),stderr="",outcome,stopping,cleanupError,treeStopRequested=!1,treeCleanup=Promise.resolve(),exited=!1,graceTimer,deadlineTimer,pendingActions=new Map;child.stderr?.setEncoding("utf8"),child.stderr?.on("data",chunk=>{stderr=`${stderr}${chunk}`.slice(-65536)});let send=message=>{if(!(!child.connected||exited))try{child.send(message,error62=>{error62&&!exited&&stop(error62)})}catch(error62){stop(error62 instanceof Error?error62:new Error(String(error62)))}},kill=()=>{if(!child.pid||exited||treeStopRequested)return;treeStopRequested=!0;let pid=child.pid;treeCleanup=Promise.resolve().then(()=>(dependencies.stopProcessTree??stopPluginProcessTree)(pid)).catch(()=>{cleanupError=Object.assign(new Error("Unable to confirm plugin process-tree cleanup"),{code:"PLUGIN_EXECUTOR_CLEANUP_FAILED",details:{executionStopped:!1}}),child.kill("SIGKILL")})},stop=error62=>{stopping||outcome||exited||(stopping=error62,send({type:"cancel",error:serializePluginExecutionError(error62)}),graceTimer=setTimeout(kill,cancellationGraceMs))},abort=()=>stop(Object.assign(new Error("Plugin execution cancelled"),{code:"PLUGIN_EXECUTION_CANCELLED"}));signal?.addEventListener("abort",abort,{once:!0}),signal?.aborted&&abort(),executionTimeoutMs!==void 0&&(deadlineTimer=setTimeout(()=>stop(Object.assign(new Error("Plugin execution deadline exceeded"),{code:"PLUGIN_EXECUTION_DEADLINE"})),executionTimeoutMs)),child.on("message",raw=>{if(!(exited||!raw||typeof raw!="object")){if(raw.type==="result"||raw.type==="error"){if(!outcome&&!stopping)try{outcome=raw.type==="result"?{value:JSON.parse(raw.json).value}:{error:pluginExecutionError(raw.error)},raw.type==="result"&&pendingActions.size&&(outcome={error:Object.assign(new Error("Plugin returned with pending host calls"),{code:"PLUGIN_PENDING_HOST_CALLS",details:{pendingActions:[...pendingActions.values()]}})})}catch(error62){stop(error62 instanceof Error?error62:new Error(String(error62)))}kill();return}if(!(stopping||outcome))if(raw.type==="diagnostic"&&model)try{onDiagnostic?.(raw.metadata)}catch(error62){stop(error62 instanceof Error?error62:new Error(String(error62)))}else if(raw.type==="progress")try{onProgress?.(raw.progress)}catch(error62){stop(error62 instanceof Error?error62:new Error(String(error62)))}else raw.type==="invoke"&&(pendingActions.set(raw.id,raw.action),Promise.resolve().then(()=>{if(stopping||exited)throw stopping??new Error("Plugin execution ended");let options2={...invokeOptions,...raw.options};return raw.stream?context.invoke(raw.action,raw.payload,options2,progress=>{!stopping&&!outcome&&pendingActions.has(raw.id)&&send({type:"invoke-progress",id:raw.id,progress})}):context.invoke(raw.action,raw.payload,options2)}).then(result=>send({type:"response",id:raw.id,result}),error62=>send({type:"response",id:raw.id,error:serializePluginExecutionError(error62)})).finally(()=>pendingActions.delete(raw.id)))}});let cleanup=()=>{exited=!0,signal?.removeEventListener("abort",abort),graceTimer&&clearTimeout(graceTimer),deadlineTimer&&clearTimeout(deadlineTimer)};child.once("error",error62=>{cleanup(),reject(error62)}),child.once("exit",()=>{kill(),child.stderr?.destroy()}),child.once("close",(code,exitSignal)=>{cleanup(),treeCleanup.then(()=>{if(!cleanupError&&treeStopRequested)try{onExecutorStopped?.()}catch(error62){reject(error62);return}cleanupError?reject(cleanupError):stopping?(Object.assign(stopping,{details:{pendingActions:[...pendingActions.values()],executionStopped:!0}}),reject(stopping)):outcome?.error?reject(outcome.error):outcome?resolve16(outcome.value):reject(Object.assign(new Error(stderr.trim()||`Plugin executor exited (${code??exitSignal})`),{code:"PLUGIN_EXECUTOR_EXITED"}))})});try{child.pid&&onExecutorStarted?.({pid:child.pid,processIdentity:processIdentity(child.pid)}),send({type:"start",plugin,invocation:invocation2,options:invokeOptions,identity:identity3,entry:registration.entry,entryVersion,access,describe:describe3,model,recovery,migration,expectedRecovery,...dependencies.registration?{registration}:{}})}catch(error62){stop(error62 instanceof Error?error62:new Error(String(error62)))}})}var init_pluginExecutor=__esm({"../client/dist/plugins/runtime/pluginExecutor.js"(){"use strict";init_runtimePaths();init_pluginRegistry();init_pluginSource();init_pluginExecution2();init_pluginExecutorProtocol();init_pluginProcessTree();init_dist()}});import{createHash as createHash8}from"node:crypto";import{tmpdir as tmpdir2}from"node:os";import{join as join16}from"node:path";function pluginHostPaths(){let registry3=pluginDirectory(),key=createHash8("sha256").update(registry3).digest("hex").slice(0,16),home=join16(registry3,".host");return{registry:registry3,home,lease:join16(home,"service.json"),log:join16(home,"service.log"),installations:join16(home,"installations"),revisions:join16(home,"revisions"),tasks:join16(home,"tasks"),state:join16(home,"state"),socket:process.platform==="win32"?`\\\\.\\pipe\\mearl-plugin-${key}`:join16(tmpdir2(),`mp-${key}.sock`)}}var init_pluginHostPaths=__esm({"../client/dist/plugins/runtime/pluginHostPaths.js"(){"use strict";init_pluginRegistry()}});import{StringDecoder as StringDecoder2}from"node:string_decoder";function readPluginTaskMessages(socket,receive){let decoder=new StringDecoder2("utf8"),buffer="";socket.on("data",chunk=>{try{buffer+=decoder.write(chunk);let end;for(;(end=buffer.indexOf(`
1088
1088
  `))>=0;){let line=buffer.slice(0,end);if(buffer=buffer.slice(end+1),Buffer.byteLength(line)>MAX_MESSAGE_BYTES)throw new Error("Plugin host message is too large");let message=JSON.parse(line);if(!message||typeof message!="object"||!Number.isSafeInteger(message.id))throw new Error("Invalid plugin host message");receive(message)}if(Buffer.byteLength(buffer)>MAX_MESSAGE_BYTES)throw new Error("Plugin host message buffer exceeded its limit")}catch(error62){socket.destroy(error62 instanceof Error?error62:new Error(String(error62)))}})}function writePluginTaskMessage(socket,message){return new Promise((resolve16,reject)=>{try{let text3=JSON.stringify(message)+`
1089
- `;if(Buffer.byteLength(text3)>MAX_MESSAGE_BYTES)throw new Error("Plugin host message is too large");if(socket.destroyed)throw new Error("Plugin host connection is closed");socket.write(text3,error62=>error62?reject(error62):resolve16())}catch(error62){reject(error62)}})}var MAX_MESSAGE_BYTES,init_pluginTaskWire=__esm({"../client/dist/plugins/pluginTaskWire.js"(){"use strict";MAX_MESSAGE_BYTES=96*1024*1024}});var pluginHostConnection_exports={};__export(pluginHostConnection_exports,{PluginHostConnection:()=>PluginHostConnection});import{spawn as spawn7}from"node:child_process";import{closeSync as closeSync8,mkdirSync as mkdirSync8,openSync as openSync8}from"node:fs";import{createConnection}from"node:net";async function ensureHost(runtimePath){let paths=pluginHostPaths(),work=starting.get(paths.registry);work||(work=(async()=>{let lease=readRecord(paths.lease);if(lease&&isProcessOwnerAlive(lease)){if(lease.protocolVersion!==5)throw new Error("Plugin execution service protocol differs; stop the service before updating");return}let lock=`${paths.lease}.start`,existing=readRecord(lock);if(!(existing&&isProcessOwnerAlive(existing))&&(existing?removeRecordIfPid(lock,existing.pid):removeInvalidRecord(lock),!!claimRecord(lock,{pid:process.pid,processIdentity:processIdentity(process.pid)})))try{let owner=readRecord(paths.lease);if(owner&&isProcessOwnerAlive(owner))return;mkdirSync8(paths.home,{recursive:!0,mode:448}),rotateLogIfNeeded(paths.log);let log2=openSync8(paths.log,"a",384);try{let child=spawn7(process.execPath,[runtimePath],{detached:!0,stdio:["ignore",log2,log2],windowsHide:!0});await new Promise((resolve16,reject)=>{child.once("spawn",resolve16),child.once("error",reject)}),child.unref()}finally{closeSync8(log2)}let deadline=Date.now()+1e4;for(;Date.now()<deadline;){if(await new Promise(resolve16=>{let probe=createConnection(paths.socket),finish=value=>{probe.destroy(),resolve16(value)};probe.once("connect",()=>finish(!0)),probe.once("error",()=>finish(!1)),probe.setTimeout(200,()=>finish(!1))}))return;await new Promise(resolve16=>setTimeout(resolve16,50))}throw new Error("Plugin execution service startup timed out")}finally{removeRecordIfPid(lock,process.pid)}})().finally(()=>starting.delete(paths.registry)),starting.set(paths.registry,work)),await work}var starting,PluginHostConnection,init_pluginHostConnection=__esm({"../client/dist/plugins/clients/pluginHostConnection.js"(){"use strict";init_runtimePaths();init_dist();init_pluginHostPaths();init_dist5();init_pluginTaskWire();init_pluginExecutorProtocol();starting=new Map;PluginHostConnection=class{configuration;get hasInvocationBridge(){return!!this.configuration.invoke}connection;socket;opening=new Set;generation=0;constructor(configuration={}){this.configuration=configuration}async connect(generation){let check2=()=>{if(generation!==this.generation)throw Object.assign(new Error("Plugin task client was disconnected"),{code:"PLUGIN_TASK_CLIENT_DISCONNECTED"})},connectOnce=()=>(check2(),this.open(this.configuration.socketPath??pluginHostPaths().socket,generation));try{return await connectOnce()}catch(error62){if(check2(),this.configuration.autoStart===!1||this.configuration.socketPath)throw error62;let code=error62.code;if(!["ENOENT","ECONNREFUSED","PLUGIN_TASK_CONNECTION_LOST"].includes(code??""))throw error62}await ensureHost(this.configuration.runtimePath??PLUGIN_TASK_HOST_PATH);let deadline=Date.now()+1e4,failure2;do{check2();try{return await connectOnce()}catch(error62){failure2=error62,await new Promise(resolve16=>setTimeout(resolve16,100))}}while(Date.now()<deadline);throw new Error("Plugin execution service did not become ready; inspect its service.log",{cause:failure2})}async open(socketPath,generation){let socket=createConnection(socketPath);this.opening.add(socket);let pending=new Map,sequence=0,fail2=error62=>{for(let request2 of pending.values())clearTimeout(request2.timer),request2.reject(error62);pending.clear()};socket.on("error",fail2),socket.once("close",()=>{fail2(Object.assign(new Error("Plugin execution service connection was lost"),{code:"PLUGIN_TASK_CONNECTION_LOST"})),this.socket===socket&&(this.connection=void 0,this.socket=void 0)});let request=(method,input3={},timeoutMs=15e3)=>new Promise((resolve16,reject)=>{let id2=++sequence,timer=setTimeout(()=>{pending.delete(id2),reject(Object.assign(new Error("Plugin task request timed out; the task may still be running"),{code:"PLUGIN_TASK_REQUEST_TIMEOUT"}))},timeoutMs);pending.set(id2,{resolve:resolve16,reject,timer}),writePluginTaskMessage(socket,{type:"request",id:id2,method,input:input3}).catch(error62=>{clearTimeout(timer),pending.delete(id2),reject(error62)})});readPluginTaskMessages(socket,message=>{if(message.type==="response"){let call=pending.get(message.id);if(!call)return;clearTimeout(call.timer),pending.delete(message.id),message.error?call.reject(pluginExecutionError(message.error)):call.resolve(message.result)}else message.type==="invoke"?Promise.resolve().then(()=>{if(!this.configuration.invoke)throw new Error("Plugin task client has no invocation bridge");return this.configuration.invoke(message.action,message.payload,message.options)}).then(result=>writePluginTaskMessage(socket,{type:"invoke-result",id:message.id,result}),error62=>writePluginTaskMessage(socket,{type:"invoke-result",id:message.id,error:serializePluginExecutionError(error62)})).catch(()=>{}):socket.destroy(new Error("Invalid plugin task response direction"))});try{await new Promise((resolve16,reject)=>{let timer=setTimeout(()=>{socket.destroy(),reject(new Error("Plugin task connection timed out"))},2e3);socket.once("connect",()=>{clearTimeout(timer),resolve16()}),socket.once("error",error62=>{clearTimeout(timer),reject(error62)})});let scope={access:this.configuration.access??"public",source:this.configuration.source??"sdk",bridge:this.configuration.invoke?"caller":"service",...this.configuration.plugin?{plugin:this.configuration.plugin}:{},...this.configuration.scopeId?{scopeId:this.configuration.scopeId}:{}},status=await request("hello",{...scope,protocolVersion:5});if(status.protocolVersion!==5)throw new Error("Plugin task protocol version mismatch");if(generation!==this.generation||socket.destroyed)throw new Error("Plugin task client was disconnected");return this.socket=socket,{socket,request,status}}catch(error62){throw socket.destroy(),error62}finally{this.opening.delete(socket)}}async request(method,input3={},timeoutMs){if(!this.connection){let attempt=this.connect(this.generation);this.connection=attempt,attempt.catch(()=>{this.connection===attempt&&(this.connection=void 0)})}return(await this.connection).request(method,input3,timeoutMs)}disconnect(){this.generation++,this.socket?.destroy();for(let socket of this.opening)socket.destroy();this.socket=void 0,this.connection=void 0}}}});import{createHash as createHash9}from"node:crypto";function localWait(promise2,signal,timeoutMs=1/0){return new Promise((resolve16,reject)=>{let abort=()=>{cleanup(),reject(signal?.reason??new Error("Plugin task wait aborted"))},timer=Number.isFinite(timeoutMs)?setTimeout(()=>{cleanup(),reject(Object.assign(new Error("Waiting for the plugin task timed out; execution continues"),{code:"PLUGIN_TASK_WAIT_TIMEOUT"}))},Math.max(0,timeoutMs)):void 0,cleanup=()=>{clearTimeout(timer),signal?.removeEventListener("abort",abort)};signal?.addEventListener("abort",abort,{once:!0}),promise2.then(value=>{cleanup(),resolve16(value)},error62=>{cleanup(),reject(error62)}),signal?.aborted&&abort()})}var PluginTaskClient,init_pluginTasks2=__esm({"../client/dist/plugins/clients/pluginTasks.js"(){"use strict";init_pluginHostConnection();init_dist();init_pluginHostPaths();init_unified();init_dist5();init_pluginExecutorProtocol();PluginTaskClient=class{configuration;connection;constructor(configuration={}){this.configuration=configuration,this.connection=configuration.connection??new PluginHostConnection(configuration)}request(method,input3={},timeoutMs){return this.connection.request(method,input3,timeoutMs)}status(){return this.request("status")}diagnose(options={}){return this.request("diagnose",{...options})}checkpoint(taskId){return this.request("checkpoint",{taskId})}resume(taskId,options={}){return this.request("resume",{taskId,revision:options.revision,environment:Object.fromEntries(Object.entries(options.environment??process.env).filter(entry=>entry[1]!==void 0))},45e3)}async start(plugin,invocation2,options={}){let{cwd=process.cwd(),environment=process.env,executionTimeoutMs,idempotencyKey,...routing}=options;if(!this.connection.hasInvocationBridge&&routing.browser&&!decodeBrowserTarget(routing.browser)){let client2=new UnifiedClient;try{let selection2=await client2.invoke("browser_select_browser",{browser:routing.browser},routing);if(!selection2?.selected?.browserId)throw new Error("Cannot resolve plugin task browser target");routing.browser=selection2.selected.browserId}finally{client2.disconnect()}}return this.request("start",{plugin,command:invocation2.command,input:invocation2.input,cwd,environment:Object.fromEntries(Object.entries(environment).filter(entry=>entry[1]!==void 0)),options:routing,executionTimeoutMs,idempotencyKey})}get(taskId){return this.request("get",{taskId})}list(activeOnly=!1,page={}){return this.request("list",{activeOnly,...page})}cancel(taskId){return this.request("cancel",{taskId})}events(taskId,cursor=0,waitMs=0){return this.request("events",{taskId,cursor,waitMs},waitMs+15e3)}resultChunk(taskId,index){return this.request("result",{taskId,index})}async result(taskId){let task=await this.get(taskId);if(task.state!=="success"||!task.result)throw new Error("Plugin task has no successful result");let parts=[];for(let index=0;index<task.result.chunks;index++){let chunk=await this.resultChunk(taskId,index);if(chunk.taskId!==taskId||chunk.index!==index||chunk.sha256!==task.result.sha256||chunk.bytes!==task.result.bytes||chunk.chunks!==task.result.chunks)throw new Error("Plugin task result chunk identity mismatch");parts.push(Buffer.from(chunk.data,"base64"))}let bytes=Buffer.concat(parts);if(bytes.length!==task.result.bytes||createHash9("sha256").update(bytes).digest("hex")!==task.result.sha256)throw new Error("Plugin task result integrity check failed");return JSON.parse(bytes.toString("utf8")).value}async*subscribe(taskId,options={}){let cursor=options.cursor??0;for(;;){options.signal?.throwIfAborted();let page=await localWait(this.events(taskId,cursor,25e3),options.signal);if(options.signal?.throwIfAborted(),yield page,cursor=page.nextCursor,!isPluginTaskActive(page.task.state)&&cursor>=page.task.sequence)return}}async wait(taskId,options={}){if(options.timeoutMs!==void 0&&(!Number.isSafeInteger(options.timeoutMs)||options.timeoutMs<1))throw new Error("Invalid plugin task wait timeout");let deadline=options.timeoutMs===void 0?1/0:Date.now()+options.timeoutMs,cursor=0,lastSequence=-1;for(;;){if(options.signal?.throwIfAborted(),Date.now()>=deadline)throw Object.assign(new Error("Waiting for the plugin task timed out; execution continues"),{code:"PLUGIN_TASK_WAIT_TIMEOUT"});let page=await localWait(this.events(taskId,cursor,Math.min(1e3,Math.max(0,deadline-Date.now()))),options.signal,deadline-Date.now());if(options.signal?.throwIfAborted(),cursor=page.nextCursor,page.task.progress&&page.task.sequence!==lastSequence&&options.onProgress?.(page.task.progress,page.task),lastSequence=page.task.sequence,page.task.state==="success")return options.readResult===!1?page.task:localWait(this.result(taskId),options.signal,deadline-Date.now());if(!isPluginTaskActive(page.task.state))throw pluginExecutionError(page.task.error??{message:`Plugin task ended with ${page.task.state}`})}}async stopHost(){let original=await this.status();await this.request("shutdown"),this.disconnect();let deadline=Date.now()+15e3;for(;;){let lease=readRecord(pluginHostPaths().lease);if(!lease||lease.epoch!==original.host.epoch||!isProcessOwnerAlive(lease))return;if(Date.now()>=deadline)throw new Error("Plugin execution service did not finish stopping");await new Promise(resolve16=>setTimeout(resolve16,50))}}disconnect(){this.configuration.connection||this.connection.disconnect()}}}});import{randomUUID as randomUUID12}from"node:crypto";import{closeSync as closeSync9,fsyncSync,mkdirSync as mkdirSync9,openSync as openSync9,renameSync as renameSync8,rmSync as rmSync9,writeFileSync as writeFileSync8}from"node:fs";import{dirname as dirname6}from"node:path";function writePluginHostFile(file2,data2){mkdirSync9(dirname6(file2),{recursive:!0,mode:448});let temporary=`${file2}.${randomUUID12()}.tmp`,descriptor;try{descriptor=openSync9(temporary,"wx",384),writeFileSync8(descriptor,data2),fsyncSync(descriptor),closeSync9(descriptor),descriptor=void 0,renameSync8(temporary,file2)}finally{descriptor!==void 0&&closeSync9(descriptor),rmSync9(temporary,{force:!0})}}var init_pluginHostFiles=__esm({"../client/dist/plugins/runtime/pluginHostFiles.js"(){"use strict"}});import{createHash as createHash10}from"node:crypto";import{closeSync as closeSync10,openSync as openSync10,opendirSync,readFileSync as readFileSync12,readSync as readSync4,readdirSync as readdirSync6,rmSync as rmSync10,statSync as statSync9}from"node:fs";import{join as join17}from"node:path";function pluginTaskExecutionUnconfirmed(record5){let owner=record5.executorOwner;return owner&&(!Number.isSafeInteger(owner.pid)||owner.pid<1)||owner&&isProcessOwnerAlive(owner)||record5.task.error?.details?.executionStopped===!1||process.platform==="win32"&&record5.task.error?.code==="PLUGIN_TASK_HOST_RESTARTED"?!0:owner&&process.platform!=="win32"?isProcessGroupAlive(owner.pid):!1}var PLUGIN_TASK_RESULT_CHUNK_BYTES,MAX_EVENT_BYTES,MAX_RESULT_BYTES,RETENTION_MS,PluginTaskStore,init_pluginTaskStore=__esm({"../client/dist/plugins/runtime/pluginTaskStore.js"(){"use strict";init_dist5();init_pluginHostFiles();init_pluginHostPaths();init_dist();PLUGIN_TASK_RESULT_CHUNK_BYTES=192*1024,MAX_EVENT_BYTES=512*1024,MAX_RESULT_BYTES=64*1024*1024,RETENTION_MS=10080*60*1e3;PluginTaskStore=class{directory;activeTaskIds;dedupeIndex;dedupeKeys=new Map;constructor(directory=pluginHostPaths().tasks){this.directory=directory}forgetDedupe(taskId){let key=this.dedupeKeys.get(taskId);if(!key)return;let ids=this.dedupeIndex?.get(key);ids?.delete(taskId),ids?.size||this.dedupeIndex?.delete(key),this.dedupeKeys.delete(taskId)}indexDedupe(record5){if(!this.dedupeIndex)return;let{dedupeKey:key,task}=record5,keep=key&&(!key.startsWith("active:")||isPluginTaskActive(task.state));if(keep&&this.dedupeKeys.get(task.taskId)===key||(this.forgetDedupe(task.taskId),!keep))return;let ids=this.dedupeIndex.get(key)??new Set;ids.add(task.taskId),this.dedupeIndex.set(key,ids),this.dedupeKeys.set(task.taskId,key)}findDedupe(key,activeOnly=!1){if(!this.dedupeIndex){this.dedupeIndex=new Map;for(let record5 of this.list())this.indexDedupe(record5)}for(let taskId of this.dedupeIndex.get(key)??[]){let record5;try{record5=this.read(taskId)}catch(error62){if(error62.code!=="PLUGIN_TASK_NOT_FOUND")throw error62;this.forgetDedupe(taskId);continue}if(this.indexDedupe(record5),record5.dedupeKey===key&&(!activeOnly||isPluginTaskActive(record5.task.state)))return record5}}path(taskId,file2){if(!isPluginTaskId(taskId))throw Object.assign(new Error("Invalid plugin task ID"),{code:"PLUGIN_TASK_INVALID_ID"});return join17(this.directory,taskId,file2)}read(taskId){let record5;try{record5=JSON.parse(readFileSync12(this.path(taskId,"task.json"),"utf8"))}catch(error62){throw error62.code==="ENOENT"?Object.assign(new Error("Plugin task was not found"),{code:"PLUGIN_TASK_NOT_FOUND"}):error62}if(record5?.task?.taskId!==taskId||!Array.isArray(record5.events))throw new Error("Invalid persistent plugin task record");return record5}write(record5){writePluginHostFile(this.path(record5.task.taskId,"task.json"),JSON.stringify(record5)),this.indexDedupe(record5),this.indexActive(record5)}indexActive(record5){isPluginTaskActive(record5.task.state)?this.activeTaskIds?.add(record5.task.taskId):this.activeTaskIds?.delete(record5.task.taskId)}listActive(){if(!this.activeTaskIds){this.activeTaskIds=new Set;for(let record5 of this.list())this.indexActive(record5)}let records=[];for(let taskId of this.activeTaskIds)try{let record5=this.read(taskId);this.indexActive(record5),isPluginTaskActive(record5.task.state)&&records.push(record5)}catch(error62){if(error62.code!=="PLUGIN_TASK_NOT_FOUND")throw error62;this.activeTaskIds.delete(taskId)}return records}update(taskId,update,type="state",fields5={}){let record5=this.read(taskId);Object.assign(record5,fields5),record5.task={...record5.task,...update,sequence:record5.task.sequence+1,updatedAt:Date.now()};let event={sequence:record5.task.sequence,time:record5.task.updatedAt,type,state:record5.task.state,...type==="progress"?{progress:record5.task.progress}:{},...type==="checkpoint"?{checkpoint:record5.task.checkpoint}:{}};record5.events.push(event);let bytes=Buffer.byteLength(JSON.stringify(record5.events));for(;record5.events.length>256||bytes>MAX_EVENT_BYTES&&record5.events.length>1;)bytes-=Buffer.byteLength(JSON.stringify(record5.events.shift()))+1;return this.write(record5),record5.task}list(){let names;try{names=readdirSync6(this.directory)}catch(error62){if(error62.code==="ENOENT")return[];throw error62}return names.filter(isPluginTaskId).map(name=>this.read(name))}diagnosticRecords(taskId){let records=[],bytes=0,scanned=0,limited=!1;if(taskId){let size;try{size=statSync9(this.path(taskId,"task.json")).size}catch(error62){if(error62.code==="ENOENT")return{records,limited};throw error62}if(size>16*1024*1024)return{records,limited:!0};records.push(this.read(taskId)),bytes+=size}let directory;try{directory=opendirSync(this.directory)}catch(error62){if(error62.code==="ENOENT")return{records,limited};throw error62}try{let item;for(;(item=directory.readSync())!==null;){if(++scanned>2048){limited=!0;break}if(!(!isPluginTaskId(item.name)||item.name===taskId))try{let size=statSync9(this.path(item.name,"task.json")).size;if(records.length>=512||bytes+size>16*1024*1024){limited=!0;break}bytes+=size,records.push(this.read(item.name))}catch{limited=!0}}}finally{directory.closeSync()}return{records,limited}}events(taskId,cursor){let record5=this.read(taskId);if(!Number.isSafeInteger(cursor)||cursor<0||cursor>record5.task.sequence)throw new Error("Invalid plugin task event cursor");let first=record5.events[0]?.sequence??record5.task.sequence+1,events=[],bytes=0;for(let event of record5.events){if(event.sequence<=cursor)continue;let size=Buffer.byteLength(JSON.stringify(event));if(bytes+size>192*1024&&events.length)break;events.push(event),bytes+=size}return{task:record5.task,events,firstAvailableSequence:first,nextCursor:events.at(-1)?.sequence??cursor,gap:cursor<first-1}}saveResult(taskId,value){let bytes=Buffer.from(JSON.stringify({value}));if(bytes.length>MAX_RESULT_BYTES)throw Object.assign(new Error("Plugin task result exceeds 64 MiB"),{code:"PLUGIN_TASK_RESULT_TOO_LARGE"});return writePluginHostFile(this.path(taskId,"result.json"),bytes),{bytes:bytes.length,sha256:createHash10("sha256").update(bytes).digest("hex"),chunks:Math.ceil(bytes.length/PLUGIN_TASK_RESULT_CHUNK_BYTES)}}resultChunk(taskId,index){let task=this.read(taskId).task;if(task.state!=="success"||!task.result)throw new Error("Plugin task result is not available");if(!Number.isSafeInteger(index)||index<0||index>=task.result.chunks)throw new Error("Invalid plugin task result chunk");let file2=this.path(taskId,"result.json");if(statSync9(file2).size!==task.result.bytes)throw new Error("Plugin task result size does not match its record");let offset2=index*PLUGIN_TASK_RESULT_CHUNK_BYTES,buffer=Buffer.alloc(Math.min(PLUGIN_TASK_RESULT_CHUNK_BYTES,task.result.bytes-offset2)),descriptor=openSync10(file2,"r");try{if(readSync4(descriptor,buffer,0,buffer.length,offset2)!==buffer.length)throw new Error("Plugin task result is incomplete")}finally{closeSync10(descriptor)}return{taskId,index,data:buffer.toString("base64"),...task.result}}recover(epoch2){this.activeTaskIds=new Set;for(let record5 of this.list()){this.indexActive(record5);let{task}=record5;isPluginTaskActive(task.state)&&task.host.epoch!==epoch2?this.update(task.taskId,{state:"interrupted",error:{code:"PLUGIN_TASK_HOST_RESTARTED",message:"The plugin execution service restarted; external operations may need reconciliation"}}):!isPluginTaskActive(task.state)&&Date.now()-task.updatedAt>RETENTION_MS&&!pluginTaskExecutionUnconfirmed(record5)&&(rmSync10(join17(this.directory,task.taskId),{recursive:!0,force:!0}),this.forgetDedupe(task.taskId))}}prune(now=Date.now()){for(let record5 of this.list()){let{task}=record5;!isPluginTaskActive(task.state)&&now-task.updatedAt>RETENTION_MS&&!pluginTaskExecutionUnconfirmed(record5)&&(rmSync10(join17(this.directory,task.taskId),{recursive:!0,force:!0}),this.forgetDedupe(task.taskId))}}}}});import{rmSync as rmSync11}from"node:fs";import{randomUUID as randomUUID13}from"node:crypto";async function cleanupPluginRuntime(){let paths=pluginHostPaths();if(listPluginNames().length)throw new Error("Registered plugins still use the execution service");let lock=`${paths.lease}.start`,starter=readRecord(lock);if(starter&&!isProcessOwnerAlive(starter)?removeRecordIfPid(lock,starter.pid):starter||removeInvalidRecord(lock),!claimRecord(lock,{pid:process.pid,processIdentity:processIdentity(process.pid)}))throw new Error("Plugin execution service is starting; caches were retained");try{let lease=readRecord(paths.lease);if(lease&&isProcessOwnerAlive(lease)){let client2=new PluginTaskClient({autoStart:!1});try{await client2.stopHost()}finally{client2.disconnect()}}let current2=readRecord(paths.lease);if(current2&&isProcessOwnerAlive(current2)||listPluginNames().length)throw new Error("Plugin execution service restarted during cleanup; caches were retained");let store=new PluginTaskStore;if(store.list().some(pluginTaskExecutionUnconfirmed))throw new Error("Plugin execution is not confirmed stopped; task records were retained");if(store.recover(randomUUID13()),store.list().some(pluginTaskExecutionUnconfirmed))throw new Error("Plugin execution is not confirmed stopped; task records were retained");let replacement=readRecord(paths.lease);if(replacement&&isProcessOwnerAlive(replacement)||listPluginNames().length)throw new Error("Plugin execution service restarted during cleanup; caches were retained");for(let file2 of[paths.tasks,paths.revisions,paths.log,`${paths.log}.1`])rmSync11(file2,{recursive:!0,force:!0});current2&&removeRecordIfPid(paths.lease,current2.pid),process.platform!=="win32"&&rmSync11(paths.socket,{force:!0})}finally{removeRecordIfPid(lock,process.pid)}}var init_pluginRuntimeCleanup=__esm({"../client/dist/plugins/runtime/pluginRuntimeCleanup.js"(){"use strict";init_dist();init_pluginHostPaths();init_pluginRegistry();init_pluginTasks2();init_pluginTaskStore()}});var pluginPages_exports={};__export(pluginPages_exports,{PluginPageClient:()=>PluginPageClient});var PluginPageClient,init_pluginPages2=__esm({"../client/dist/plugins/clients/pluginPages.js"(){"use strict";init_unified();PluginPageClient=class{connection;client;constructor(configuration={},connection){this.connection=connection,connection||(this.client=new UnifiedClient(configuration))}call(plugin,operation,input3={},options={}){return this.connection?this.connection.request("page.call",{plugin,input:{...input3,operation},options,execution:{cwd:process.cwd(),environment:Object.fromEntries(Object.entries(process.env).filter(entry=>entry[1]!==void 0))}},Math.max(12e4,typeof input3.timeoutSec=="number"&&Number.isFinite(input3.timeoutSec)?(Math.min(300,input3.timeoutSec)+5)*1e3:0)):this.client.invoke("plugin_page",{...input3,plugin,operation},options)}attach(plugin,input3,options={}){return this.call(plugin,"attach",input3,options)}get(plugin,instanceId){return this.call(plugin,"get",{instanceId})}list(plugin){return this.call(plugin,"list")}send(plugin,instanceId,message,options={}){return this.call(plugin,"send",{instanceId,message,...options},options)}detach(plugin,instanceId){return this.call(plugin,"detach",{instanceId})}events(plugin,instanceId,cursor=0,waitMs=0){return this.call(plugin,"events",{instanceId,cursor,waitMs})}disconnect(){this.client?.disconnect()}}}});var pluginState_exports={};__export(pluginState_exports,{PluginStateClient:()=>PluginStateClient});var PluginStateClient,init_pluginState2=__esm({"../client/dist/plugins/clients/pluginState.js"(){"use strict";init_pluginHostConnection();PluginStateClient=class{options;connection;constructor(options={}){this.options=options,this.connection=options.connection??new PluginHostConnection(options)}call(plugin,collection,operation,input3={},options={}){return this.connection.request("state.call",{plugin,input:{...input3,collection,operation},options},3e4)}get(plugin,collection,key,input3={}){return this.call(plugin,collection,"get",{...input3,key})}getMany(plugin,collection,keys,input3={}){return this.call(plugin,collection,"get-many",{...input3,keys})}list(plugin,collection,input3={}){return this.call(plugin,collection,"list",input3)}transact(plugin,collection,transaction,input3={}){return this.call(plugin,collection,"transact",{...input3,transaction})}disconnect(){this.options.connection||this.connection.disconnect()}}}});var pluginModels_exports={};__export(pluginModels_exports,{PluginModelClient:()=>PluginModelClient});var PluginModelClient,init_pluginModels2=__esm({"../client/dist/plugins/clients/pluginModels.js"(){"use strict";init_pluginTasks2();PluginModelClient=class{tasks;constructor(options={}){this.tasks=new PluginTaskClient(options)}capabilities(){return this.tasks.connection.request("model.capabilities")}list(provider="codex"){return this.tasks.connection.request("model.list",{provider},2e4)}async start(plugin,request,options={}){let{cwd=process.cwd(),environment=process.env,executionTimeoutMs,idempotencyKey,...routing}=options;return this.tasks.connection.request("start",{kind:"model",plugin,command:"model",input:{request},cwd,environment:Object.fromEntries(Object.entries(environment).filter(entry=>entry[1]!==void 0)),options:routing,executionTimeoutMs,idempotencyKey})}async run(plugin,request,options={}){let{signal,onProgress,...execution}=options;signal?.throwIfAborted();let started=await this.start(plugin,request,execution),cancel=()=>{this.tasks.cancel(started.taskId).catch(()=>{})};signal?.addEventListener("abort",cancel,{once:!0});try{return signal?.aborted&&cancel(),await this.tasks.wait(started.taskId,{onProgress})}finally{signal?.removeEventListener("abort",cancel)}}disconnect(){this.tasks.disconnect()}}}});var plugin_exports={};__export(plugin_exports,{OFFICIAL_PLUGINS:()=>OFFICIAL_PLUGINS,OFFICIAL_PLUGIN_MANAGER:()=>OFFICIAL_PLUGIN_MANAGER,PluginError:()=>PluginError,PluginModelClient:()=>PluginModelClient,PluginPageClient:()=>PluginPageClient,PluginStateClient:()=>PluginStateClient,PluginTaskClient:()=>PluginTaskClient,assertPluginName:()=>assertPluginName,cleanupPluginRuntime:()=>cleanupPluginRuntime,executeRegisteredPlugin:()=>executeRegisteredPlugin,findOfficialPlugin:()=>findOfficialPlugin,findPluginDirectoryEntry:()=>findPluginDirectoryEntry,findPluginEntry:()=>findPluginEntry,findPluginRegistration:()=>findPluginRegistration,invokePageEvalWithArgs:()=>invokePageEvalWithArgs,invokeRegisteredPlugin:()=>invokeRegisteredPlugin,invokeRegisteredRecoveryPlugin:()=>invokeRegisteredRecoveryPlugin,invokeRegisteredRuntimePlugin:()=>invokeRegisteredRuntimePlugin,invokeRegisteredToolboxPlugin:()=>invokeRegisteredToolboxPlugin,listOfficialPluginNames:()=>listOfficialPluginNames,listPluginNames:()=>listPluginNames,loadPlugin:()=>loadPlugin,loadRegisteredPlugin:()=>loadRegisteredPlugin,pluginDirectory:()=>pluginDirectory,pluginRegistrationNeedsRefresh:()=>pluginRegistrationNeedsRefresh,readOfficialPluginCatalog:()=>readOfficialPluginCatalog,readPluginPageBundleChunk:()=>readPluginPageBundleChunk,refreshRegisteredPlugin:()=>refreshRegisteredPlugin,registerPlugin:()=>registerPlugin,replaceOfficialPluginCatalog:()=>replaceOfficialPluginCatalog,resolvePluginEntry:()=>resolvePluginEntry,unregisterPlugin:()=>unregisterPlugin,validateOfficialPluginCatalog:()=>validateOfficialPluginCatalog});import{dirname as dirname7,extname as extname2,resolve as resolve5}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{return readInstalledSkillMetadata(resolve5(dirname7(entry),".."))?.version}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 data2;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");data2=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data2?{data:data2}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx @mearl/setup plugin uninstall ${name}`].join(`
1089
+ `;if(Buffer.byteLength(text3)>MAX_MESSAGE_BYTES)throw new Error("Plugin host message is too large");if(socket.destroyed)throw new Error("Plugin host connection is closed");socket.write(text3,error62=>error62?reject(error62):resolve16())}catch(error62){reject(error62)}})}var MAX_MESSAGE_BYTES,init_pluginTaskWire=__esm({"../client/dist/plugins/pluginTaskWire.js"(){"use strict";MAX_MESSAGE_BYTES=96*1024*1024}});var pluginHostConnection_exports={};__export(pluginHostConnection_exports,{PluginHostConnection:()=>PluginHostConnection});import{spawn as spawn7}from"node:child_process";import{closeSync as closeSync8,mkdirSync as mkdirSync8,openSync as openSync8}from"node:fs";import{createConnection}from"node:net";async function ensureHost(runtimePath){let paths=pluginHostPaths(),work=starting.get(paths.registry);work||(work=(async()=>{let lease=readRecord(paths.lease);if(lease&&isProcessOwnerAlive(lease)){if(lease.protocolVersion!==5)throw new Error("Plugin execution service protocol differs; stop the service before updating");return}let lock=`${paths.lease}.start`,existing=readRecord(lock);if(!(existing&&isProcessOwnerAlive(existing))&&(existing?removeRecordIfPid(lock,existing.pid):removeInvalidRecord(lock),!!claimRecord(lock,{pid:process.pid,processIdentity:processIdentity(process.pid)})))try{let owner=readRecord(paths.lease);if(owner&&isProcessOwnerAlive(owner))return;mkdirSync8(paths.home,{recursive:!0,mode:448}),rotateLogIfNeeded(paths.log);let log2=openSync8(paths.log,"a",384);try{let child=spawn7(process.execPath,[runtimePath],{detached:!0,stdio:["ignore",log2,log2],windowsHide:!0});await new Promise((resolve16,reject)=>{child.once("spawn",resolve16),child.once("error",reject)}),child.unref()}finally{closeSync8(log2)}let deadline=Date.now()+1e4;for(;Date.now()<deadline;){if(await new Promise(resolve16=>{let probe=createConnection(paths.socket),finish=value=>{probe.destroy(),resolve16(value)};probe.once("connect",()=>finish(!0)),probe.once("error",()=>finish(!1)),probe.setTimeout(200,()=>finish(!1))}))return;await new Promise(resolve16=>setTimeout(resolve16,50))}throw new Error("Plugin execution service startup timed out")}finally{removeRecordIfPid(lock,process.pid)}})().finally(()=>starting.delete(paths.registry)),starting.set(paths.registry,work)),await work}var starting,PluginHostConnection,init_pluginHostConnection=__esm({"../client/dist/plugins/clients/pluginHostConnection.js"(){"use strict";init_runtimePaths();init_dist();init_pluginHostPaths();init_dist5();init_pluginTaskWire();init_pluginExecutorProtocol();starting=new Map;PluginHostConnection=class{configuration;get hasInvocationBridge(){return!!this.configuration.invoke}connection;socket;opening=new Set;generation=0;constructor(configuration={}){this.configuration=configuration}async connect(generation){let check2=()=>{if(generation!==this.generation)throw Object.assign(new Error("Plugin task client was disconnected"),{code:"PLUGIN_TASK_CLIENT_DISCONNECTED"})},connectOnce=()=>(check2(),this.open(this.configuration.socketPath??pluginHostPaths().socket,generation));try{return await connectOnce()}catch(error62){if(check2(),this.configuration.autoStart===!1||this.configuration.socketPath)throw error62;let code=error62.code;if(!["ENOENT","ECONNREFUSED","PLUGIN_TASK_CONNECTION_LOST"].includes(code??""))throw error62}await ensureHost(this.configuration.runtimePath??PLUGIN_TASK_HOST_PATH);let deadline=Date.now()+1e4,failure2;do{check2();try{return await connectOnce()}catch(error62){failure2=error62,await new Promise(resolve16=>setTimeout(resolve16,100))}}while(Date.now()<deadline);throw new Error("Plugin execution service did not become ready; inspect its service.log",{cause:failure2})}async open(socketPath,generation){let socket=createConnection(socketPath);this.opening.add(socket);let pending=new Map,sequence=0,fail2=error62=>{for(let request2 of pending.values())clearTimeout(request2.timer),request2.reject(error62);pending.clear()};socket.on("error",fail2),socket.once("close",()=>{fail2(Object.assign(new Error("Plugin execution service connection was lost"),{code:"PLUGIN_TASK_CONNECTION_LOST"})),this.socket===socket&&(this.connection=void 0,this.socket=void 0)});let request=(method,input3={},timeoutMs=15e3)=>new Promise((resolve16,reject)=>{let id2=++sequence,timer=setTimeout(()=>{pending.delete(id2),reject(Object.assign(new Error("Plugin task request timed out; the task may still be running"),{code:"PLUGIN_TASK_REQUEST_TIMEOUT"}))},timeoutMs);pending.set(id2,{resolve:resolve16,reject,timer}),writePluginTaskMessage(socket,{type:"request",id:id2,method,input:input3}).catch(error62=>{clearTimeout(timer),pending.delete(id2),reject(error62)})});readPluginTaskMessages(socket,message=>{if(message.type==="response"){let call=pending.get(message.id);if(!call)return;clearTimeout(call.timer),pending.delete(message.id),message.error?call.reject(pluginExecutionError(message.error)):call.resolve(message.result)}else message.type==="invoke"?Promise.resolve().then(()=>{if(!this.configuration.invoke)throw new Error("Plugin task client has no invocation bridge");return this.configuration.invoke(message.action,message.payload,message.options)}).then(result=>writePluginTaskMessage(socket,{type:"invoke-result",id:message.id,result}),error62=>writePluginTaskMessage(socket,{type:"invoke-result",id:message.id,error:serializePluginExecutionError(error62)})).catch(()=>{}):socket.destroy(new Error("Invalid plugin task response direction"))});try{await new Promise((resolve16,reject)=>{let timer=setTimeout(()=>{socket.destroy(),reject(new Error("Plugin task connection timed out"))},2e3);socket.once("connect",()=>{clearTimeout(timer),resolve16()}),socket.once("error",error62=>{clearTimeout(timer),reject(error62)})});let scope={access:this.configuration.access??"public",source:this.configuration.source??"sdk",bridge:this.configuration.invoke?"caller":"service",...this.configuration.plugin?{plugin:this.configuration.plugin}:{},...this.configuration.scopeId?{scopeId:this.configuration.scopeId}:{}},status=await request("hello",{...scope,protocolVersion:5});if(status.protocolVersion!==5)throw new Error("Plugin task protocol version mismatch");if(generation!==this.generation||socket.destroyed)throw new Error("Plugin task client was disconnected");return this.socket=socket,{socket,request,status}}catch(error62){throw socket.destroy(),error62}finally{this.opening.delete(socket)}}async request(method,input3={},timeoutMs){if(!this.connection){let attempt=this.connect(this.generation);this.connection=attempt,attempt.catch(()=>{this.connection===attempt&&(this.connection=void 0)})}return(await this.connection).request(method,input3,timeoutMs)}disconnect(){this.generation++,this.socket?.destroy();for(let socket of this.opening)socket.destroy();this.socket=void 0,this.connection=void 0}}}});import{createHash as createHash9}from"node:crypto";function localWait(promise2,signal,timeoutMs=1/0){return new Promise((resolve16,reject)=>{let abort=()=>{cleanup(),reject(signal?.reason??new Error("Plugin task wait aborted"))},timer=Number.isFinite(timeoutMs)?setTimeout(()=>{cleanup(),reject(Object.assign(new Error("Waiting for the plugin task timed out; execution continues"),{code:"PLUGIN_TASK_WAIT_TIMEOUT"}))},Math.max(0,timeoutMs)):void 0,cleanup=()=>{clearTimeout(timer),signal?.removeEventListener("abort",abort)};signal?.addEventListener("abort",abort,{once:!0}),promise2.then(value=>{cleanup(),resolve16(value)},error62=>{cleanup(),reject(error62)}),signal?.aborted&&abort()})}var PluginTaskClient,init_pluginTasks2=__esm({"../client/dist/plugins/clients/pluginTasks.js"(){"use strict";init_pluginHostConnection();init_dist();init_pluginHostPaths();init_unified();init_dist5();init_pluginExecutorProtocol();PluginTaskClient=class{configuration;connection;constructor(configuration={}){this.configuration=configuration,this.connection=configuration.connection??new PluginHostConnection(configuration)}request(method,input3={},timeoutMs){return this.connection.request(method,input3,timeoutMs)}status(){return this.request("status")}diagnose(options={}){return this.request("diagnose",{...options})}checkpoint(taskId){return this.request("checkpoint",{taskId})}resume(taskId,options={}){return this.request("resume",{taskId,revision:options.revision,environment:Object.fromEntries(Object.entries(options.environment??process.env).filter(entry=>entry[1]!==void 0))},45e3)}async start(plugin,invocation2,options={}){let{cwd=process.cwd(),environment=process.env,executionTimeoutMs,idempotencyKey,...routing}=options;if(!this.connection.hasInvocationBridge&&routing.browser&&!decodeBrowserTarget(routing.browser)){let client2=new UnifiedClient;try{let selection2=await client2.invoke("browser_select_browser",{browser:routing.browser},routing);if(!selection2?.selected?.browserId)throw new Error("Cannot resolve plugin task browser target");routing.browser=selection2.selected.browserId}finally{client2.disconnect()}}return this.request("start",{plugin,command:invocation2.command,input:invocation2.input,cwd,environment:Object.fromEntries(Object.entries(environment).filter(entry=>entry[1]!==void 0)),options:routing,executionTimeoutMs,idempotencyKey})}get(taskId){return this.request("get",{taskId})}list(activeOnly=!1,page={}){return this.request("list",{activeOnly,...page})}cancel(taskId){return this.request("cancel",{taskId})}events(taskId,cursor=0,waitMs=0){return this.request("events",{taskId,cursor,waitMs},waitMs+15e3)}resultChunk(taskId,index){return this.request("result",{taskId,index})}async result(taskId){let task=await this.get(taskId);if(task.state!=="success"||!task.result)throw new Error("Plugin task has no successful result");let parts=[];for(let index=0;index<task.result.chunks;index++){let chunk=await this.resultChunk(taskId,index);if(chunk.taskId!==taskId||chunk.index!==index||chunk.sha256!==task.result.sha256||chunk.bytes!==task.result.bytes||chunk.chunks!==task.result.chunks)throw new Error("Plugin task result chunk identity mismatch");parts.push(Buffer.from(chunk.data,"base64"))}let bytes=Buffer.concat(parts);if(bytes.length!==task.result.bytes||createHash9("sha256").update(bytes).digest("hex")!==task.result.sha256)throw new Error("Plugin task result integrity check failed");return JSON.parse(bytes.toString("utf8")).value}async*subscribe(taskId,options={}){let cursor=options.cursor??0;for(;;){options.signal?.throwIfAborted();let page=await localWait(this.events(taskId,cursor,25e3),options.signal);if(options.signal?.throwIfAborted(),yield page,cursor=page.nextCursor,!isPluginTaskActive(page.task.state)&&cursor>=page.task.sequence)return}}async wait(taskId,options={}){if(options.timeoutMs!==void 0&&(!Number.isSafeInteger(options.timeoutMs)||options.timeoutMs<1))throw new Error("Invalid plugin task wait timeout");let deadline=options.timeoutMs===void 0?1/0:Date.now()+options.timeoutMs,cursor=0,lastSequence=-1;for(;;){if(options.signal?.throwIfAborted(),Date.now()>=deadline)throw Object.assign(new Error("Waiting for the plugin task timed out; execution continues"),{code:"PLUGIN_TASK_WAIT_TIMEOUT"});let page=await localWait(this.events(taskId,cursor,Math.min(1e3,Math.max(0,deadline-Date.now()))),options.signal,deadline-Date.now());if(options.signal?.throwIfAborted(),cursor=page.nextCursor,page.task.progress&&page.task.sequence!==lastSequence&&options.onProgress?.(page.task.progress,page.task),lastSequence=page.task.sequence,page.task.state==="success")return options.readResult===!1?page.task:localWait(this.result(taskId),options.signal,deadline-Date.now());if(!isPluginTaskActive(page.task.state))throw pluginExecutionError(page.task.error??{message:`Plugin task ended with ${page.task.state}`})}}async stopHost(){let original=await this.status();await this.request("shutdown"),this.disconnect();let deadline=Date.now()+15e3;for(;;){let lease=readRecord(pluginHostPaths().lease);if(!lease||lease.epoch!==original.host.epoch||!isProcessOwnerAlive(lease))return;if(Date.now()>=deadline)throw new Error("Plugin execution service did not finish stopping");await new Promise(resolve16=>setTimeout(resolve16,50))}}disconnect(){this.configuration.connection||this.connection.disconnect()}}}});import{randomUUID as randomUUID12}from"node:crypto";import{closeSync as closeSync9,fsyncSync,mkdirSync as mkdirSync9,openSync as openSync9,renameSync as renameSync8,rmSync as rmSync9,writeFileSync as writeFileSync8}from"node:fs";import{dirname as dirname6}from"node:path";function writePluginHostFile(file2,data2){mkdirSync9(dirname6(file2),{recursive:!0,mode:448});let temporary=`${file2}.${randomUUID12()}.tmp`,descriptor;try{descriptor=openSync9(temporary,"wx",384),writeFileSync8(descriptor,data2),fsyncSync(descriptor),closeSync9(descriptor),descriptor=void 0,renameSync8(temporary,file2)}finally{descriptor!==void 0&&closeSync9(descriptor),rmSync9(temporary,{force:!0})}}var init_pluginHostFiles=__esm({"../client/dist/plugins/runtime/pluginHostFiles.js"(){"use strict"}});import{createHash as createHash10}from"node:crypto";import{closeSync as closeSync10,openSync as openSync10,opendirSync,readFileSync as readFileSync12,readSync as readSync4,readdirSync as readdirSync6,rmSync as rmSync10,statSync as statSync9}from"node:fs";import{join as join17}from"node:path";function pluginTaskExecutionUnconfirmed(record5){let owner=record5.executorOwner;return owner&&(!Number.isSafeInteger(owner.pid)||owner.pid<1)||owner&&isProcessOwnerAlive(owner)||record5.task.error?.details?.executionStopped===!1||process.platform==="win32"&&record5.task.error?.code==="PLUGIN_TASK_HOST_RESTARTED"?!0:owner&&process.platform!=="win32"?isProcessGroupAlive(owner.pid):!1}var PLUGIN_TASK_RESULT_CHUNK_BYTES,MAX_EVENT_BYTES,MAX_RESULT_BYTES,RETENTION_MS,PluginTaskStore,init_pluginTaskStore=__esm({"../client/dist/plugins/runtime/pluginTaskStore.js"(){"use strict";init_dist5();init_pluginHostFiles();init_pluginHostPaths();init_dist();PLUGIN_TASK_RESULT_CHUNK_BYTES=192*1024,MAX_EVENT_BYTES=512*1024,MAX_RESULT_BYTES=64*1024*1024,RETENTION_MS=10080*60*1e3;PluginTaskStore=class{directory;activeTaskIds;dedupeIndex;dedupeKeys=new Map;constructor(directory=pluginHostPaths().tasks){this.directory=directory}forgetDedupe(taskId){let key=this.dedupeKeys.get(taskId);if(!key)return;let ids=this.dedupeIndex?.get(key);ids?.delete(taskId),ids?.size||this.dedupeIndex?.delete(key),this.dedupeKeys.delete(taskId)}indexDedupe(record5){if(!this.dedupeIndex)return;let{dedupeKey:key,task}=record5,keep=key&&(!key.startsWith("active:")||isPluginTaskActive(task.state));if(keep&&this.dedupeKeys.get(task.taskId)===key||(this.forgetDedupe(task.taskId),!keep))return;let ids=this.dedupeIndex.get(key)??new Set;ids.add(task.taskId),this.dedupeIndex.set(key,ids),this.dedupeKeys.set(task.taskId,key)}findDedupe(key,activeOnly=!1){if(!this.dedupeIndex){this.dedupeIndex=new Map;for(let record5 of this.list())this.indexDedupe(record5)}for(let taskId of this.dedupeIndex.get(key)??[]){let record5;try{record5=this.read(taskId)}catch(error62){if(error62.code!=="PLUGIN_TASK_NOT_FOUND")throw error62;this.forgetDedupe(taskId);continue}if(this.indexDedupe(record5),record5.dedupeKey===key&&(!activeOnly||isPluginTaskActive(record5.task.state)))return record5}}path(taskId,file2){if(!isPluginTaskId(taskId))throw Object.assign(new Error("Invalid plugin task ID"),{code:"PLUGIN_TASK_INVALID_ID"});return join17(this.directory,taskId,file2)}read(taskId){let record5;try{record5=JSON.parse(readFileSync12(this.path(taskId,"task.json"),"utf8"))}catch(error62){throw error62.code==="ENOENT"?Object.assign(new Error("Plugin task was not found"),{code:"PLUGIN_TASK_NOT_FOUND"}):error62}if(record5?.task?.taskId!==taskId||!Array.isArray(record5.events))throw new Error("Invalid persistent plugin task record");return record5}write(record5){writePluginHostFile(this.path(record5.task.taskId,"task.json"),JSON.stringify(record5)),this.indexDedupe(record5),this.indexActive(record5)}indexActive(record5){isPluginTaskActive(record5.task.state)?this.activeTaskIds?.add(record5.task.taskId):this.activeTaskIds?.delete(record5.task.taskId)}listActive(){if(!this.activeTaskIds){this.activeTaskIds=new Set;for(let record5 of this.list())this.indexActive(record5)}let records=[];for(let taskId of this.activeTaskIds)try{let record5=this.read(taskId);this.indexActive(record5),isPluginTaskActive(record5.task.state)&&records.push(record5)}catch(error62){if(error62.code!=="PLUGIN_TASK_NOT_FOUND")throw error62;this.activeTaskIds.delete(taskId)}return records}update(taskId,update,type="state",fields5={}){let record5=this.read(taskId);Object.assign(record5,fields5),record5.task={...record5.task,...update,sequence:record5.task.sequence+1,updatedAt:Date.now()};let event={sequence:record5.task.sequence,time:record5.task.updatedAt,type,state:record5.task.state,...type==="progress"?{progress:record5.task.progress}:{},...type==="checkpoint"?{checkpoint:record5.task.checkpoint}:{}};record5.events.push(event);let bytes=Buffer.byteLength(JSON.stringify(record5.events));for(;record5.events.length>256||bytes>MAX_EVENT_BYTES&&record5.events.length>1;)bytes-=Buffer.byteLength(JSON.stringify(record5.events.shift()))+1;return this.write(record5),record5.task}list(){let names;try{names=readdirSync6(this.directory)}catch(error62){if(error62.code==="ENOENT")return[];throw error62}return names.filter(isPluginTaskId).map(name=>this.read(name))}diagnosticRecords(taskId){let records=[],bytes=0,scanned=0,limited=!1;if(taskId){let size;try{size=statSync9(this.path(taskId,"task.json")).size}catch(error62){if(error62.code==="ENOENT")return{records,limited};throw error62}if(size>16*1024*1024)return{records,limited:!0};records.push(this.read(taskId)),bytes+=size}let directory;try{directory=opendirSync(this.directory)}catch(error62){if(error62.code==="ENOENT")return{records,limited};throw error62}try{let item;for(;(item=directory.readSync())!==null;){if(++scanned>2048){limited=!0;break}if(!(!isPluginTaskId(item.name)||item.name===taskId))try{let size=statSync9(this.path(item.name,"task.json")).size;if(records.length>=512||bytes+size>16*1024*1024){limited=!0;break}bytes+=size,records.push(this.read(item.name))}catch{limited=!0}}}finally{directory.closeSync()}return{records,limited}}events(taskId,cursor){let record5=this.read(taskId);if(!Number.isSafeInteger(cursor)||cursor<0||cursor>record5.task.sequence)throw new Error("Invalid plugin task event cursor");let first=record5.events[0]?.sequence??record5.task.sequence+1,events=[],bytes=0;for(let event of record5.events){if(event.sequence<=cursor)continue;let size=Buffer.byteLength(JSON.stringify(event));if(bytes+size>192*1024&&events.length)break;events.push(event),bytes+=size}return{task:record5.task,events,firstAvailableSequence:first,nextCursor:events.at(-1)?.sequence??cursor,gap:cursor<first-1}}saveResult(taskId,value){let bytes=Buffer.from(JSON.stringify({value}));if(bytes.length>MAX_RESULT_BYTES)throw Object.assign(new Error("Plugin task result exceeds 64 MiB"),{code:"PLUGIN_TASK_RESULT_TOO_LARGE"});return writePluginHostFile(this.path(taskId,"result.json"),bytes),{bytes:bytes.length,sha256:createHash10("sha256").update(bytes).digest("hex"),chunks:Math.ceil(bytes.length/PLUGIN_TASK_RESULT_CHUNK_BYTES)}}resultChunk(taskId,index){let task=this.read(taskId).task;if(task.state!=="success"||!task.result)throw new Error("Plugin task result is not available");if(!Number.isSafeInteger(index)||index<0||index>=task.result.chunks)throw new Error("Invalid plugin task result chunk");let file2=this.path(taskId,"result.json");if(statSync9(file2).size!==task.result.bytes)throw new Error("Plugin task result size does not match its record");let offset2=index*PLUGIN_TASK_RESULT_CHUNK_BYTES,buffer=Buffer.alloc(Math.min(PLUGIN_TASK_RESULT_CHUNK_BYTES,task.result.bytes-offset2)),descriptor=openSync10(file2,"r");try{if(readSync4(descriptor,buffer,0,buffer.length,offset2)!==buffer.length)throw new Error("Plugin task result is incomplete")}finally{closeSync10(descriptor)}return{taskId,index,data:buffer.toString("base64"),...task.result}}recover(epoch2){this.activeTaskIds=new Set;for(let record5 of this.list()){this.indexActive(record5);let{task}=record5;isPluginTaskActive(task.state)&&task.host.epoch!==epoch2?this.update(task.taskId,{state:"interrupted",error:{code:"PLUGIN_TASK_HOST_RESTARTED",message:"The plugin execution service restarted; external operations may need reconciliation"}}):!isPluginTaskActive(task.state)&&Date.now()-task.updatedAt>RETENTION_MS&&!pluginTaskExecutionUnconfirmed(record5)&&(rmSync10(join17(this.directory,task.taskId),{recursive:!0,force:!0}),this.forgetDedupe(task.taskId))}}prune(now=Date.now()){for(let record5 of this.list()){let{task}=record5;!isPluginTaskActive(task.state)&&now-task.updatedAt>RETENTION_MS&&!pluginTaskExecutionUnconfirmed(record5)&&(rmSync10(join17(this.directory,task.taskId),{recursive:!0,force:!0}),this.forgetDedupe(task.taskId))}}}}});import{rmSync as rmSync11}from"node:fs";import{randomUUID as randomUUID13}from"node:crypto";async function cleanupPluginRuntime(){let paths=pluginHostPaths();if(listPluginNames().length)throw new Error("Registered plugins still use the execution service");let lock=`${paths.lease}.start`,starter=readRecord(lock);if(starter&&!isProcessOwnerAlive(starter)?removeRecordIfPid(lock,starter.pid):starter||removeInvalidRecord(lock),!claimRecord(lock,{pid:process.pid,processIdentity:processIdentity(process.pid)}))throw new Error("Plugin execution service is starting; caches were retained");try{let lease=readRecord(paths.lease);if(lease&&isProcessOwnerAlive(lease)){let client2=new PluginTaskClient({autoStart:!1});try{await client2.stopHost()}finally{client2.disconnect()}}let current2=readRecord(paths.lease);if(current2&&isProcessOwnerAlive(current2)||listPluginNames().length)throw new Error("Plugin execution service restarted during cleanup; caches were retained");let store=new PluginTaskStore;if(store.list().some(pluginTaskExecutionUnconfirmed))throw new Error("Plugin execution is not confirmed stopped; task records were retained");if(store.recover(randomUUID13()),store.list().some(pluginTaskExecutionUnconfirmed))throw new Error("Plugin execution is not confirmed stopped; task records were retained");let replacement=readRecord(paths.lease);if(replacement&&isProcessOwnerAlive(replacement)||listPluginNames().length)throw new Error("Plugin execution service restarted during cleanup; caches were retained");for(let file2 of[paths.tasks,paths.revisions,paths.log,`${paths.log}.1`])rmSync11(file2,{recursive:!0,force:!0});current2&&removeRecordIfPid(paths.lease,current2.pid),process.platform!=="win32"&&rmSync11(paths.socket,{force:!0})}finally{removeRecordIfPid(lock,process.pid)}}var init_pluginRuntimeCleanup=__esm({"../client/dist/plugins/runtime/pluginRuntimeCleanup.js"(){"use strict";init_dist();init_pluginHostPaths();init_pluginRegistry();init_pluginTasks2();init_pluginTaskStore()}});var pluginPages_exports={};__export(pluginPages_exports,{PluginPageClient:()=>PluginPageClient});var PluginPageClient,init_pluginPages2=__esm({"../client/dist/plugins/clients/pluginPages.js"(){"use strict";init_unified();PluginPageClient=class{connection;client;constructor(configuration={},connection){this.connection=connection,connection||(this.client=new UnifiedClient(configuration))}call(plugin,operation,input3={},options={}){return this.connection?this.connection.request("page.call",{plugin,input:{...input3,operation},options,execution:{cwd:process.cwd(),environment:Object.fromEntries(Object.entries(process.env).filter(entry=>entry[1]!==void 0))}},Math.max(12e4,typeof input3.timeoutSec=="number"&&Number.isFinite(input3.timeoutSec)?(Math.min(300,input3.timeoutSec)+5)*1e3:0)):this.client.invoke("plugin_page",{...input3,plugin,operation},options)}attach(plugin,input3,options={}){return this.call(plugin,"attach",input3,options)}get(plugin,instanceId){return this.call(plugin,"get",{instanceId})}list(plugin){return this.call(plugin,"list")}send(plugin,instanceId,message,options={}){return this.call(plugin,"send",{instanceId,message,...options},options)}detach(plugin,instanceId){return this.call(plugin,"detach",{instanceId})}events(plugin,instanceId,cursor=0,waitMs=0){return this.call(plugin,"events",{instanceId,cursor,waitMs})}disconnect(){this.client?.disconnect()}}}});var pluginState_exports={};__export(pluginState_exports,{PluginStateClient:()=>PluginStateClient});var PluginStateClient,init_pluginState2=__esm({"../client/dist/plugins/clients/pluginState.js"(){"use strict";init_pluginHostConnection();PluginStateClient=class{options;connection;constructor(options={}){this.options=options,this.connection=options.connection??new PluginHostConnection(options)}call(plugin,collection,operation,input3={},options={}){return this.connection.request("state.call",{plugin,input:{...input3,collection,operation},options},3e4)}get(plugin,collection,key,input3={}){return this.call(plugin,collection,"get",{...input3,key})}getMany(plugin,collection,keys,input3={}){return this.call(plugin,collection,"get-many",{...input3,keys})}list(plugin,collection,input3={}){return this.call(plugin,collection,"list",input3)}transact(plugin,collection,transaction,input3={}){return this.call(plugin,collection,"transact",{...input3,transaction})}disconnect(){this.options.connection||this.connection.disconnect()}}}});var pluginModels_exports={};__export(pluginModels_exports,{PluginModelClient:()=>PluginModelClient});var PluginModelClient,init_pluginModels2=__esm({"../client/dist/plugins/clients/pluginModels.js"(){"use strict";init_pluginTasks2();PluginModelClient=class{tasks;constructor(options={}){this.tasks=new PluginTaskClient(options)}capabilities(){return this.tasks.connection.request("model.capabilities")}list(provider="codex"){return this.tasks.connection.request("model.list",{provider},2e4)}async start(plugin,request,options={}){let{cwd=process.cwd(),environment=process.env,executionTimeoutMs,idempotencyKey,...routing}=options;return this.tasks.connection.request("start",{kind:"model",plugin,command:"model",input:{request},cwd,environment:Object.fromEntries(Object.entries(environment).filter(entry=>entry[1]!==void 0)),options:routing,executionTimeoutMs,idempotencyKey})}async run(plugin,request,options={}){let{signal,onProgress,...execution}=options;signal?.throwIfAborted();let started=await this.start(plugin,request,execution),cancel=()=>{this.tasks.cancel(started.taskId).catch(()=>{})};signal?.addEventListener("abort",cancel,{once:!0});try{return signal?.aborted&&cancel(),await this.tasks.wait(started.taskId,{onProgress})}finally{signal?.removeEventListener("abort",cancel)}}disconnect(){this.tasks.disconnect()}}}});var plugin_exports={};__export(plugin_exports,{OFFICIAL_PLUGINS:()=>OFFICIAL_PLUGINS,OFFICIAL_PLUGIN_MANAGER:()=>OFFICIAL_PLUGIN_MANAGER,PluginError:()=>PluginError,PluginModelClient:()=>PluginModelClient,PluginPageClient:()=>PluginPageClient,PluginStateClient:()=>PluginStateClient,PluginTaskClient:()=>PluginTaskClient,assertPluginName:()=>assertPluginName,cleanupPluginRuntime:()=>cleanupPluginRuntime,executeRegisteredPlugin:()=>executeRegisteredPlugin,findOfficialPlugin:()=>findOfficialPlugin,findPluginDirectoryEntry:()=>findPluginDirectoryEntry,findPluginEntry:()=>findPluginEntry,findPluginRegistration:()=>findPluginRegistration,invokePageEvalWithArgs:()=>invokePageEvalWithArgs,invokeRegisteredPlugin:()=>invokeRegisteredPlugin,invokeRegisteredRecoveryPlugin:()=>invokeRegisteredRecoveryPlugin,invokeRegisteredRuntimePlugin:()=>invokeRegisteredRuntimePlugin,invokeRegisteredToolboxPlugin:()=>invokeRegisteredToolboxPlugin,listOfficialPluginNames:()=>listOfficialPluginNames,listPluginNames:()=>listPluginNames,loadPlugin:()=>loadPlugin,loadRegisteredPlugin:()=>loadRegisteredPlugin,pluginDirectory:()=>pluginDirectory,pluginRegistrationNeedsRefresh:()=>pluginRegistrationNeedsRefresh,readOfficialPluginCatalog:()=>readOfficialPluginCatalog,readPluginPageBundleChunk:()=>readPluginPageBundleChunk,refreshRegisteredPlugin:()=>refreshRegisteredPlugin,registerPlugin:()=>registerPlugin,replaceOfficialPluginCatalog:()=>replaceOfficialPluginCatalog,resolvePluginEntry:()=>resolvePluginEntry,unregisterPlugin:()=>unregisterPlugin,validateOfficialPluginCatalog:()=>validateOfficialPluginCatalog});import{dirname as dirname7,extname as extname2,resolve as resolve5}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{return readInstalledSkillMetadata(resolve5(dirname7(entry),".."))?.version}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 data2;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");data2=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data2?{data:data2}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx --@mearl:registry=https://registry.npmjs.org @mearl/setup plugin uninstall ${name}`].join(`
1090
1090
  `)}async function refreshRegisteredPlugin(name,includePage=!1){let key=`${pluginDirectory()}/${name}`,pending=registrationRefreshes.get(key);if(pending)return await pending,refreshRegisteredPlugin(name,includePage);let registration=findPluginRegistration(name);if(!registration)return;let entryChanged=pluginRegistrationNeedsRefresh(registration);if(!entryChanged&&(!includePage||!pluginRegistrationNeedsRefresh(registration,!0)))return registration;let refresh=(async()=>{let entryVersion=pluginFileVersion(registration.entry),loaded=entryChanged?await loadPlugin(registration.entry,{options:{},invoke:async()=>{throw new Error("注册时不能执行浏览器操作")},progress:()=>{throw new Error("注册时不能报告执行进度")}},name):registration,current2=findPluginRegistration(name);if(JSON.stringify(current2)!==JSON.stringify(registration))return current2;if(pluginFileVersion(registration.entry)!==entryVersion)throw new PluginError("PLUGIN_SOURCE_CHANGED",`插件更新进行中,请重新打开工具: ${name}`);return registerPlugin(name,registration.entry,loaded.description,{hasPublicCommands:"commandHelp"in loaded?!!loaded.commandHelp(name):loaded.hasPublicCommands,toolbox:loaded.toolbox,appProfiles:loaded.appProfiles,profileSources:"profileSources"in loaded?loaded.profileSources:loaded.source?.profiles,...registration.managedBy?{managedBy:registration.managedBy}:{}}),findPluginRegistration(name)})();registrationRefreshes.set(key,refresh);try{return await refresh}finally{registrationRefreshes.delete(key)}}async function loadPlugin(entry,context,pluginName){let entryVersion;try{entryVersion=pluginFileVersion(entry)}catch{throw new PluginError("PLUGIN_ENTRY_MISSING",missingPluginEntryMessage(entry,pluginName))}let commands=new Map,recoveries=new Map,migrations=new Map,executing=!1,checkpointDeclaration,invocationGeneration=0,registering=!0,name,description,toolbox,pageRuntime,stateStorage,taskRecovery,appProfiles,profileSources,registerCommand=(signature,handler,description2="",examples=[],toolboxOnly=!1,runtimeOnly=!1)=>{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"||!Array.isArray(examples)||examples.some(example=>typeof example!="string"||!example.trim()))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,examples:[...examples],toolboxOnly,runtimeOnly})},app=Object.freeze({options:Object.freeze({...context.options}),command:(signature,handler,description2="",examples=[])=>registerCommand(signature,handler,description2,examples),runtimeCommand:(signature,handler,description2="",examples=[])=>registerCommand(signature,handler,description2,examples,!1,!0),recoveryCommand(command,handler){if(!registering||!/^[a-z][a-z0-9-]*$/.test(command)||typeof handler!="function"||recoveries.has(command))throw new Error("Invalid or duplicate recovery command");recoveries.set(command,handler)},checkpointMigration(command,handler){if(!registering||!/^[a-z][a-z0-9-]*$/.test(command)||typeof handler!="function"||migrations.has(command))throw new Error("Invalid or duplicate checkpoint migration");migrations.set(command,(input3,commandContext)=>handler(input3,commandContext))},checkpoint(data2,expectedSequence){if(!executing||!context.invocation?.taskId)throw new PluginError("PLUGIN_TASK_REQUIRED","Checkpoints require a managed task");return context.signal?.throwIfAborted(),context.invoke("plugin_task_checkpoint",{plugin:pluginName??name,data:data2,expectedSequence,expectedDeclaration:checkpointDeclaration})},state(collection,operation,input3={}){if(!executing)throw new Error("app.state is only available during command execution");if(context.signal?.throwIfAborted(),!stateStorage||!Object.hasOwn(stateStorage.collections,collection))throw new PluginError("PLUGIN_STATE_NOT_DECLARED","Plugin state collection is not declared");return context.invoke("plugin_state",{...input3,plugin:pluginName??name,collection,operation,expectedDeclaration:pluginStateSignature(stateStorage.collections[collection])})},model(request,options={}){if(!executing)throw new Error("app.model is only available during command execution");context.signal?.throwIfAborted();let generation=invocationGeneration,observing=()=>executing&&generation===invocationGeneration&&!context.signal?.aborted;if(context.runModel)return context.runModel(pluginName??name,request,{signal:context.signal,onProgress:progress=>{observing()&&(context.progress(progress),options.onProgress?.(progress))}});let payload={plugin:pluginName??name,operation:"run",request};return options.onProgress?context.invoke("plugin_model",payload,{},progress=>{observing()&&options.onProgress?.(progress)}):context.invoke("plugin_model",payload)},page(operation,input3={}){if(!executing)throw new Error("app.page is only available during command execution");return context.signal?.throwIfAborted(),context.invoke("plugin_page",{...input3,plugin:pluginName??name,operation})},toolboxCommand:(signature,handler,description2="",examples=[])=>registerCommand(signature,handler,description2,examples,!0),invoke(action,payload={},options={}){if(!executing)throw new Error("app.invoke 只能在命令执行期间调用");return context.signal?.throwIfAborted(),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),pageRuntime=normalizePluginPageRuntime(descriptor.pageRuntime),stateStorage=normalizePluginState(descriptor.stateStorage),taskRecovery=normalizePluginTaskRecovery(descriptor.taskRecovery),{appProfiles,profileSources}=loadPluginAppProfiles(entry,descriptor.appProfiles);for(let command of descriptor.commands){let commandName=command.signature.trim().split(/\s+/)[0];if(command.migrationOnly){app.checkpointMigration(commandName,(input3,commandContext)=>runPythonPluginCommand(entry,commandName,input3,app,commandContext,"migration",descriptor));continue}if(command.recoveryOnly){app.recoveryCommand(commandName,(input3,commandContext)=>runPythonPluginCommand(entry,commandName,input3,app,commandContext,!0,descriptor));continue}(command.runtimeOnly?app.runtimeCommand:command.toolboxOnly?app.toolboxCommand:app.command)(command.signature,(input3,commandContext)=>runPythonPluginCommand(entry,commandName,input3,app,commandContext,!1,descriptor,command.runtimeOnly),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),pageRuntime=normalizePluginPageRuntime(module.pageRuntime),stateStorage=normalizePluginState(module.stateStorage),taskRecovery=normalizePluginTaskRecovery(module.taskRecovery),{appProfiles,profileSources}=loadPluginAppProfiles(entry,module.appProfiles),module.default!==void 0&&typeof module.default!="function")throw new Error("入口必须默认导出 register(app) 函数");if(typeof module.default=="function")await module.default(app);else if(!appProfiles)throw new Error("入口必须默认导出 register(app) 函数")}if(commands.size===0&&!appProfiles)throw new Error("入口未注册任何命令");for(let command of Object.keys(taskRecovery?.commands??{}))if(!commands.has(command)||commands.get(command)?.runtimeOnly||commands.get(command)?.toolboxOnly||!recoveries.has(command))throw new Error(`Recovery requires a command and recoveryCommand: ${command}`);for(let command of recoveries.keys())if(!Object.hasOwn(taskRecovery?.commands??{},command))throw new Error(`Undeclared recovery command: ${command}`);for(let[command,definition]of Object.entries(taskRecovery?.commands??{}))if(!!definition.migrateFrom?.length!==migrations.has(command))throw new Error(`Checkpoint migrations require a declaration and checkpointMigration: ${command}`);for(let command of migrations.keys())if(!Object.hasOwn(taskRecovery?.commands??{},command))throw new Error(`Undeclared checkpoint migration: ${command}`);let runtimeCommands=new Set(Object.values(pageRuntime?.events??{}).map(event=>event.command));pageRuntime?.initialize&&runtimeCommands.add(pageRuntime.initialize);for(let[name2,command]of commands)if(command.runtimeOnly&&!runtimeCommands.has(name2))throw new Error(`runtimeCommand is not declared in pageRuntime.events: ${name2}`);for(let name2 of runtimeCommands)if(!commands.has(name2)||commands.get(name2)?.toolboxOnly)throw new Error(`Invalid page runtime command: ${name2}`);let toolboxCommands=toolbox?.page.commands??[];for(let[name2,command]of commands)if(command.toolboxOnly&&!toolboxCommands.includes(name2))throw new Error(`toolboxCommand 未声明在 toolbox.page.commands 中: ${name2}`);for(let command of toolboxCommands)if(!commands.has(command))throw new Error(`toolbox 命令未注册: ${command}`)}catch(error62){throw new PluginError("PLUGIN_LOAD_FAILED",`${entry}: ${error62 instanceof Error?error62.message:String(error62)}`)}finally{registering=!1}let find=(name2,toolboxPage=!1)=>{let command=commands.get(name2);if(!command)throw new PluginError("PLUGIN_COMMAND_NOT_FOUND",`未知子命令: ${name2}`);if(toolboxPage==="runtime"){if(!(pageRuntime?.initialize===name2||Object.values(pageRuntime?.events??{}).some(event=>event.command===name2))||command.toolboxOnly)throw new PluginError("PLUGIN_COMMAND_NOT_ALLOWED","Page runtime command is not declared")}else{if(command.runtimeOnly)throw new PluginError("PLUGIN_COMMAND_RUNTIME_ONLY",`命令仅供页面运行时调用: ${name2}`);if(toolboxPage){if(!toolbox?.page.commands.includes(name2))throw new PluginError("PLUGIN_COMMAND_NOT_ALLOWED",`工具页面不允许调用命令: ${name2}`)}else if(command.toolboxOnly)throw new PluginError("PLUGIN_COMMAND_TOOLBOX_ONLY",`命令仅供工具页面调用: ${name2}`)}return command},publicCommands=()=>[...commands.values()].filter(command=>!command.toolboxOnly&&!command.runtimeOnly),run=async(positionals,payload,namedInput={},toolboxPage=!1)=>{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,commandName=envelope?.command??positionals[0]??"",hidden=toolboxPage==="recovery"||toolboxPage==="migration",selected=find(commandName,hidden?!1:toolboxPage),command=selected.command,handler=toolboxPage==="recovery"?recoveries.get(commandName):toolboxPage==="migration"?migrations.get(commandName):selected.handler;if(!handler||toolboxPage==="recovery"&&!context.invocation?.recovery)throw new PluginError("PLUGIN_TASK_RECOVERY_UNAVAILABLE","Recovery handler requires a managed recovery attempt");if(toolboxPage==="recovery"&&context.invocation?.recovery?.declarationHash!==pluginRecoverySignature(taskRecovery.commands[commandName]))throw new PluginError("PLUGIN_RECOVERY_DECLARATION_CHANGED","Recovery declaration differs from the admitted format");let 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 input3={...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 hidden?[]:command.registeredArguments){let value=Object.hasOwn(input3,argument.name())?input3[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()} 必须为数组`)}if(executing)throw new PluginError("PLUGIN_BUSY","同一命令实例不能并发执行");let signal=context.signal??new AbortController().signal;signal.throwIfAborted();let identity3=context.invocation??createPluginInvocationIdentity(pluginName??name??"unregistered",context.source??"sdk",context.parentInvocation),generation=++invocationGeneration,assertActive=()=>{if(!executing||generation!==invocationGeneration)throw new PluginError("PLUGIN_INVOCATION_ENDED","命令调用已结束");signal.throwIfAborted()},commandContext=Object.freeze({identity:identity3,signal,...identity3.recovery?{recovery:structuredClone(identity3.recovery)}:{},checkpoint:(data2,expectedSequence)=>(assertActive(),app.checkpoint(data2,expectedSequence)),...identity3.page?{page:Object.freeze({send:(message,options={})=>(assertActive(),app.page("send",{instanceId:identity3.page.instanceId,message,...options.timeoutSec!==void 0?{timeoutSec:options.timeoutSec}:{}})),get:()=>(assertActive(),app.page("get",{instanceId:identity3.page.instanceId}))})}:{},invoke:(action,payload2,options)=>(assertActive(),app.invoke(action,payload2,options)),state:(collection,operation,input4)=>(assertActive(),app.state(collection,operation,{...identity3.page?{instanceId:identity3.page.instanceId}:{},...input4})),model:(request,options)=>(assertActive(),app.model(request,options)),progress:progress=>{assertActive(),app.progress(progress)}});checkpointDeclaration=taskRecovery&&Object.hasOwn(taskRecovery.commands,commandName)?pluginRecoverySignature(taskRecovery.commands[commandName]):void 0,executing=!0,context.onInvocation?.(identity3);try{return await handler(input3,commandContext)}finally{executing=!1,checkpointDeclaration=void 0,context.onInvocation?.(void 0)}};return{name,description,toolbox,pageRuntime,stateStorage,taskRecovery,appProfiles,profileSources,version:readPluginVersion(entry),commandHelp(namespace){return publicCommands().map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`).join(`
1091
1091
  `)},help(namespace,name2){let selected=name2?[find(name2)]:publicCommands();if(!selected.length){let location2=toolbox?`请在 Mearl ${toolbox.displayMode==="popup"?"Popup":"工具箱"} 中打开「${toolbox.title}」使用。`:"此插件未提供公开 CLI 命令。";return`${namespace} 未提供 CLI 命令。
1092
1092
  ${location2}`}let examples=selected.flatMap(({examples:examples2})=>examples2);return["用法:",...selected.map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`),...examples.length?["","示例:",...examples.map(example=>` ${namespace} ${example}`)]:[]].join(`
@@ -1095,7 +1095,7 @@ ${location2}`}let examples=selected.flatMap(({examples:examples2})=>examples2);r
1095
1095
  `)},this.options.heartbeatInterval*1e3)}handleMessage(data2){if(this.messageBuffer+=data2.toString("utf8"),this.messageBuffer.length>10485760){this.disconnect();return}let newlineIndex;for(;(newlineIndex=this.messageBuffer.indexOf(`
1096
1096
  `))!==-1;){let line=this.messageBuffer.slice(0,newlineIndex);if(this.messageBuffer=this.messageBuffer.slice(newlineIndex+1),!!line.trim())try{let message=JSON.parse(line);isHeartbeatMessage(message)||this.handleResponse(message)}catch{}}}handleResponse(response){let pending=this.pendingRequests.get(response.id);pending&&(this.pendingRequests.delete(response.id),clearTimeout(pending.timer),response.versionWarning&&console.warn(response.versionWarning),response.success?pending.resolve(response.data):pending.reject(new Error(response.error||"Unknown error from cloud-server")))}async requestRemote(action,data2,timeoutSec,browser,connector,controlSessionId){await this.ensureConnected();let ws=this.ws;if(!ws||ws.readyState!==WebSocket.OPEN)throw new Error("Connection is not open");let id2=`${Date.now()}_${Math.random().toString(36).slice(2,10)}`,message={id:id2,action,data:data2,timeoutSec};browser&&(message.browser=browser),connector&&(message.connector=connector),controlSessionId&&(message.controlSessionId=controlSessionId);let serialized=`${JSON.stringify(message)}
1097
1097
  `,bytes=Buffer.byteLength(serialized,"utf8");if(bytes>10485760)throw new Error(`Cloud request exceeds ${10485760} byte message limit (${bytes} bytes)`);return new Promise((resolve16,reject)=>{let timer=setTimeout(()=>{this.pendingRequests.delete(id2),reject(new Error(`Request timeout after ${timeoutSec}s`))},timeoutSec*1e3+RESPONSE_GRACE_MS);this.pendingRequests.set(id2,{resolve:resolve16,reject,timer}),ws.send(serialized)})}rejectAllPending(error62){for(let pending of this.pendingRequests.values())clearTimeout(pending.timer),pending.reject(error62);this.pendingRequests.clear()}}}});function parseReleaseVersion(value){if(typeof value!="string")return null;let match=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-beta\.(0|[1-9]\d*))?$/.exec(value);if(!match)return null;let parts=[Number(match[1]),Number(match[2]),Number(match[3]),Number(match[4]??0)];return parts.every(Number.isSafeInteger)?[...parts.slice(0,3),match[4]===void 0?1:0,parts[3]]:null}function isNewerRelease(latest,installed){let latestParts=parseReleaseVersion(latest),installedParts=parseReleaseVersion(installed);if(!latestParts||!installedParts)return!1;for(let index=0;index<latestParts.length;index++)if(latestParts[index]!==installedParts[index])return latestParts[index]>installedParts[index];return!1}async function fetchLatestVersion(component2){let source=component2==="extension"?process.env.MEARL_EXTENSION_CONFIG_URL||UPDATE_SOURCES.extension:UPDATE_SOURCES[component2],response=await fetch(source,{signal:AbortSignal.timeout(1500)});if(!response.ok)throw new Error(`HTTP ${response.status}`);let payload=await response.json(),version3=component2==="extension"?payload.latestVersion??payload.version:payload.version;if(!parseReleaseVersion(version3))throw new Error("Invalid release version");return version3}function formatError(error62){return error62 instanceof Error?error62.message:String(error62)}function browserAccessLabel(access){return access.kind==="sandbox-novnc"&&"environment"in access?access.environment==="opensandbox"?"OpenSandbox noVNC":"AONE Sandbox noVNC":access.kind}async function getBrowserAccess(client2,browser,capability,timeoutSec){let result=await client2.invoke("get_browser_access_url",{},{timeoutSec,browser:browser.browserId});if(!result.browserAccess?.url)throw new Error("Browser host did not return an access URL");if(capability&&result.browserAccess.kind!==capability.kind)throw new Error("Browser host returned an unexpected access URL type");return result.browserAccess}function redactServerUrl(serverUrl){try{let parsed=new URL(serverUrl);for(let key of parsed.searchParams.keys())key.toLowerCase().includes("token")&&parsed.searchParams.set(key,"redacted");return parsed.toString()}catch{return serverUrl.replace(/([?&][^=&\s]*token[^=&\s]*=)[^&\s]*/gi,"$1redacted")}}function browserMatches2(browser,selector){let normalized=normalizeBrowserSelector(selector);return browser.browserId.toLowerCase()===normalized||browser.originalBrowserId?.toLowerCase()===normalized||browser.name.toLowerCase()===normalized||browser.originalName?.toLowerCase()===normalized}function findBrowsers2(browsers,selector){let exact=browsers.filter(browser=>browserMatches2(browser,selector));if(exact.length>0)return exact;let normalized=normalizeBrowserSelector(selector);return browsers.filter(browser=>browser.browserId.toLowerCase().includes(normalized)||browser.originalBrowserId?.toLowerCase().includes(normalized)||browser.name.toLowerCase().includes(normalized)||browser.originalName?.toLowerCase().includes(normalized))}function shortBrowserId(browserId){let parts=browserId.split(":"),raw=decodeURIComponent(parts.at(-1)??browserId);return raw.length>12?`${raw.slice(0,8)}…`:raw}function formatBrowser(browser,isDefault){let transport=browser.transport==="cdp"?" [CDP]":browser.transport==="extension"?" [Extension]":browser.transport==="provider"?` [Provider: ${browser.provider?.name||browser.provider?.id||"external"}]`:"",type=browser.type==="managed"?" [Managed]":"";return` ${isDefault?"★":" "} ${browser.name} [${shortBrowserId(browser.browserId)}]${type}${transport}`}function formatConnector(connector){let id2=connector.connectorId.length>12?`${connector.connectorId.slice(0,8)}…`:connector.connectorId,version3=connector.version?` [v${connector.version}]`:"";return` ${connector.name} [${id2}]${version3}`}function printSection(writeLine,title,items){writeLine(title);for(let item of items){let marker=item.status==="ok"?"✅":item.status==="warning"?"⚠️ ":"❌";writeLine(` ${marker} ${item.label}`);for(let detail of item.details??[])writeLine(` ${detail}`)}writeLine("")}async function runUnifiedCheck(options,dependencies={}){let timeoutSec=options.timeoutSec??5,writeLine=dependencies.writeLine??(line=>console.error(line)),writeJson=dependencies.writeJson??(json4=>process.stdout.write(`${json4}
1098
- `)),client2=(dependencies.createClient??(clientOptions=>new UnifiedClient(clientOptions)))({...options.serverUrl?{serverUrl:options.serverUrl}:{},connectTimeoutSec:timeoutSec,requestTimeoutSec:timeoutSec}),latestVersions=options.checkUpdates?Promise.allSettled(Object.keys(UPDATE_SOURCES).map(component2=>(dependencies.fetchLatestVersion??fetchLatestVersion)(component2))):null,environment=[{status:"ok",label:`Unified client v${options.clientVersion}`}],connectors=[],browserList=null;try{if(options.local)environment.push({status:"ok",label:options.transport==="cdp"?"Browser scope: this machine (forced CDP)":"Browser scope: this machine"});else if(options.serverUrl){let source=options.serverUrlSource?` (${options.serverUrlSource})`:"";try{let connectorList=await client2.invoke("connector_list",{},{timeoutSec});connectors=Array.isArray(connectorList?.connectors)?connectorList.connectors:[],environment.push({status:"ok",label:`Cloud server${source}`,details:[redactServerUrl(options.serverUrl),`${connectors.length} connector${connectors.length===1?"":"s"} connected`]})}catch(error62){environment.push({status:"error",label:`Cloud server or connector discovery failed${source}`,details:[formatError(error62),redactServerUrl(options.serverUrl),"On the Agent machine, run `mearl-cloud-server status` to verify the server and current connection command. Use `mearl check --local` to isolate this machine."]})}}else environment.push({status:"ok",label:"Local mode (no cloud-server configuration)"});let inventoryOptions={timeoutSec,...options.local?{local:!0}:{},...options.transport?{transport:options.transport}:{},...!options.local&&options.connector?{connector:options.connector}:{}};try{options.serverUrl&&!options.local&&environment.some(item=>item.status==="error")?browserList=await client2.invoke("browser_list",{},{timeoutSec,local:!0}):browserList=await client2.invoke("browser_list",{},inventoryOptions),environment.push({status:"ok",label:"Browser inventory"}),browserList.warnings?.length&&environment.push({status:"warning",label:"Some browser sources could not be inspected",details:browserList.warnings})}catch(error62){environment.push({status:"error",label:"Browser inventory failed",details:[formatError(error62)]})}let connected=(browserList?.browsers??[]).filter(browser=>browser.status==="connected"&&(options.transport!=="cdp"||browser.transport==="cdp"));if((options.local||!options.serverUrl)&&options.transport!=="cdp"&&!connected.some(browser=>browser.transport==="extension")){let diagnostics=(dependencies.inspectNativeHostInstallation??inspectNativeHostInstallation)();environment.push(...diagnostics.map(item=>({status:"warning",...item})))}let targets=connected;if(options.browser){let matches=findBrowsers2(connected,options.browser);matches.length===0?(environment.push({status:"error",label:`Browser "${options.browser}" is not connected`,details:["Run `mearl browser_list` and use an exact global browserId."]}),targets=[]):matches.length>1?(environment.push({status:"error",label:`Browser selector "${options.browser}" is ambiguous`,details:matches.map(browser=>browser.browserId)}),targets=[]):targets=matches}!options.browser&&connected.length===0&&browserList&&environment.push({status:"error",label:options.transport==="cdp"?"No connected CDP browser":"No connected browser",details:[options.transport==="cdp"?"Enable a local CDP endpoint (see `mearl-native-host --help`) and run `mearl browser_list --cdp` to inspect discovery.":"Open Chrome with the Mearl extension, start a managed browser, or connect a browser host.",...!options.local&&connectors.length>0?["Connectors are connected but expose no ready browser. On the browser machine, run `mearl check --local`; use `mearl connector_list` for versions and heartbeat details."]:[]]});let browserChecks=[];await Promise.all(targets.map(async browser=>{try{options.transport==="cdp"&&await client2.invoke("tab_list",{},{timeoutSec,browser:browser.browserId,transport:"cdp"});let versions=await client2.invoke("get_versions",{},{timeoutSec,browser:browser.browserId,...options.transport?{transport:options.transport}:{}}),publicVersions={...versions.nativeHost?{nativeHost:versions.nativeHost}:{},...versions.extension!==void 0?{extension:versions.extension}:{},...versions.browser!==void 0?{browser:versions.browser}:{},...versions.provider?{provider:versions.provider}:{}},details=[versions.nativeHost?`native-host v${versions.nativeHost}`:null,versions.extension?`extension v${versions.extension}`:null,versions.browser?`Chrome ${versions.browser}`:null,versions.provider?`${versions.provider.name} v${versions.provider.version} (protocol v${versions.provider.protocolVersion})`:null].filter(value=>value!==null),capabilities=options.browser?versions.capabilities:void 0;capabilities&&details.push(`capabilities (${capabilities.actions.length}): ${capabilities.actions.join(", ")||"none"}`,`screenshot: ${capabilities.screenshot}`);let extensionInstallation;options.local&&browser.transport==="extension"&&typeof versions.extensionId=="string"&&typeof versions.extension=="string"&&(typeof versions.setupManagedPath=="string"||versions.setupManagedPath===null)&&(extensionInstallation={extensionId:versions.extensionId,setupManagedPath:versions.setupManagedPath});let browserAccess,accessUrlWarning,browserAccessCapability=versions.browserAccess,providerAccess=browser.operations?.includes("access")===!0;if((providerAccess||browserAccessCapability)&&options.browser)try{browserAccess=await getBrowserAccess(client2,browser,providerAccess?void 0:browserAccessCapability,timeoutSec),details.push(`Browser access URL (${browserAccessLabel(browserAccess)}; sensitive): ${browserAccess.url}`)}catch(error62){accessUrlWarning=formatError(error62),details.push(`Browser access URL unavailable: ${accessUrlWarning}`)}browserChecks.push({...browserAccess?{browserAccess}:{},browser,...capabilities?{capabilities}:{},...extensionInstallation?{extensionInstallation}:{},item:{status:accessUrlWarning?"warning":"ok",label:accessUrlWarning?"Browser command path ready; browser access URL unavailable":options.transport==="cdp"?"CDP command path":"Browser command path",details},versions:publicVersions,...accessUrlWarning?{warnings:[accessUrlWarning]}:{}})}catch(error62){let message=formatError(error62);browserChecks.push({browser,...message.includes("Unknown action")?{warnings:["Update @mearl/native-host for complete diagnostics."]}:{errors:[message]},item:message.includes("Unknown action")?{status:"warning",label:"Browser is reachable but runtime version details are unavailable",details:["Update @mearl/native-host for complete diagnostics."]}:{status:"error",label:"Browser command path failed",details:[message]}})}}));let updates;if(latestVersions){let latestResults=await latestVersions,components=Object.keys(UPDATE_SOURCES),installed=new Map,addInstalled=(component2,version3)=>{if(!version3)return;let versions=installed.get(component2)??new Set;versions.add(version3),installed.set(component2,versions)};addInstalled("client",options.clientVersion);for(let check2 of browserChecks)addInstalled("native-host",check2.versions?.nativeHost),addInstalled("extension",check2.versions?.extension);for(let connector of connectors)addInstalled("cloud-connector",connector.version);updates=components.flatMap((component2,index)=>{let result=latestResults[index];return[...installed.get(component2)??[]].map(version3=>({component:component2,installed:version3,...result.status==="fulfilled"?{latest:result.value}:{},status:result.status==="rejected"||!parseReleaseVersion(version3)||!parseReleaseVersion(result.value)?"unavailable":isNewerRelease(result.value,version3)?"available":"current"}))});let available=updates.filter(update=>update.status==="available"),unavailable=updates.filter(update=>update.status==="unavailable"),packageUpdateAvailable=available.some(update=>update.component==="client"||update.component==="native-host"),extensionUpdateAvailable=available.some(update=>update.component==="extension"),connectorUpdateAvailable=available.some(update=>update.component==="cloud-connector");environment.push({status:available.length||unavailable.length?"warning":"ok",label:available.length?`${available.length} Mearl update${available.length===1?"":"s"} available`:unavailable.length?"Mearl update check incomplete":"Mearl packages are current",details:[...available.map(update=>`${update.component}: ${update.installed} → ${update.latest}`),...packageUpdateAvailable?["Update on the affected machine: npx @mearl/setup update"]:[],...extensionUpdateAvailable?["Update a setup-managed extension: npx @mearl/setup extension"]:[],...connectorUpdateAvailable?["Update cloud-connector with its package manager on the connector machine."]:[],...unavailable.map(update=>`${update.component}: latest version unavailable`)]})}let hasError=environment.some(item=>item.status==="error")||browserChecks.some(check2=>check2.item.status==="error"),listedBrowsers=browserList?.browsers??[];if(options.json){let result={browsers:listedBrowsers.map(browser=>{let check2=browserChecks.find(item=>item.browser.browserId===browser.browserId),browserIdentity={...browser};return delete browserIdentity.extensionVersion,delete browserIdentity.nativeHostVersion,{...browserIdentity,selected:targets.some(target=>target.browserId===browser.browserId),...check2?.browserAccess?{browserAccess:check2.browserAccess}:{},...check2?.capabilities?{capabilities:check2.capabilities}:{},...check2?.item?{check:{label:check2.item.label,status:check2.item.status,...check2.errors?{errors:check2.errors}:{},...check2.warnings?{warnings:check2.warnings}:{}}}:{},...check2?.extensionInstallation?{extensionInstallation:check2.extensionInstallation}:{},...check2?.versions?{versions:check2.versions}:{}}}),clientVersion:options.clientVersion,connectors,environment,ok:!hasError,...updates?{updates}:{}};return writeJson(JSON.stringify(result,null,2)),result}if(writeLine(""),printSection(writeLine,"Environment",environment),connectors.length>0){writeLine("Cloud connectors");for(let connector of connectors)writeLine(formatConnector(connector));writeLine("")}if(listedBrowsers.length>0){writeLine("Browsers");for(let browser of listedBrowsers){writeLine(formatBrowser(browser,browser.browserId===browserList?.defaultBrowserId));let check2=browserChecks.find(item=>item.browser.browserId===browser.browserId);if(check2){let marker=check2.item.status==="ok"?"✅":check2.item.status==="warning"?"⚠️ ":"❌";writeLine(` ${marker} ${check2.item.label}`);for(let detail of check2.item.details??[])writeLine(` ${detail}`)}else browser.status!=="connected"&&writeLine(` ⚪ ${browser.status}`)}writeLine("")}return hasError?(writeLine("⚠️ Mearl checks failed. See the browser or source details above."),!1):(writeLine(options.browser?"🎉 Selected browser is ready!":`🎉 All ${targets.length} connected browser${targets.length===1?"":"s"} are ready!`),!0)}finally{client2.disconnect()}}var UPDATE_SOURCES,init_check=__esm({"../client/dist/check.js"(){"use strict";init_nativeHost();init_unified();UPDATE_SOURCES={client:"https://registry.npmjs.org/@mearl%2Fclient/latest","native-host":"https://registry.npmjs.org/@mearl%2Fnative-host/latest","cloud-connector":"https://registry.npmjs.org/@mearl%2Fcloud-connector/latest",extension:"https://github.com/F-loat/mearl/releases/latest/download/config.json"}}});var init_local=__esm({"../client/dist/local.js"(){"use strict";init_socket();init_browserRegistry()}});var require_ms=__commonJS({"../../node_modules/.pnpm/ms@2.1.3/node_modules/ms/index.js"(exports,module){var s=1e3,m=s*60,h=m*60,d=h*24,w=d*7,y=d*365.25;module.exports=function(val,options){options=options||{};var type=typeof val;if(type==="string"&&val.length>0)return parse6(val);if(type==="number"&&isFinite(val))return options.long?fmtLong(val):fmtShort(val);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(val))};function parse6(str){if(str=String(str),!(str.length>100)){var match=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);if(match){var n=parseFloat(match[1]),type=(match[2]||"ms").toLowerCase();switch(type){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"weeks":case"week":case"w":return n*w;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}}}function fmtShort(ms){var msAbs=Math.abs(ms);return msAbs>=d?Math.round(ms/d)+"d":msAbs>=h?Math.round(ms/h)+"h":msAbs>=m?Math.round(ms/m)+"m":msAbs>=s?Math.round(ms/s)+"s":ms+"ms"}function fmtLong(ms){var msAbs=Math.abs(ms);return msAbs>=d?plural2(ms,msAbs,d,"day"):msAbs>=h?plural2(ms,msAbs,h,"hour"):msAbs>=m?plural2(ms,msAbs,m,"minute"):msAbs>=s?plural2(ms,msAbs,s,"second"):ms+" ms"}function plural2(ms,msAbs,n,name){var isPlural=msAbs>=n*1.5;return Math.round(ms/n)+" "+name+(isPlural?"s":"")}}});var require_common=__commonJS({"../../node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/common.js"(exports,module){function setup(env){createDebug.debug=createDebug,createDebug.default=createDebug,createDebug.coerce=coerce,createDebug.disable=disable,createDebug.enable=enable,createDebug.enabled=enabled,createDebug.humanize=require_ms(),createDebug.destroy=destroy,Object.keys(env).forEach(key=>{createDebug[key]=env[key]}),createDebug.names=[],createDebug.skips=[],createDebug.formatters={};function selectColor(namespace){let hash3=0;for(let i2=0;i2<namespace.length;i2++)hash3=(hash3<<5)-hash3+namespace.charCodeAt(i2),hash3|=0;return createDebug.colors[Math.abs(hash3)%createDebug.colors.length]}createDebug.selectColor=selectColor;function createDebug(namespace){let prevTime,enableOverride=null,namespacesCache,enabledCache;function debug(...args){if(!debug.enabled)return;let self=debug,curr=Number(new Date),ms=curr-(prevTime||curr);self.diff=ms,self.prev=prevTime,self.curr=curr,prevTime=curr,args[0]=createDebug.coerce(args[0]),typeof args[0]!="string"&&args.unshift("%O");let index=0;args[0]=args[0].replace(/%([a-zA-Z%])/g,(match,format)=>{if(match==="%%")return"%";index++;let formatter=createDebug.formatters[format];if(typeof formatter=="function"){let val=args[index];match=formatter.call(self,val),args.splice(index,1),index--}return match}),createDebug.formatArgs.call(self,args),(self.log||createDebug.log).apply(self,args)}return debug.namespace=namespace,debug.useColors=createDebug.useColors(),debug.color=createDebug.selectColor(namespace),debug.extend=extend3,debug.destroy=createDebug.destroy,Object.defineProperty(debug,"enabled",{enumerable:!0,configurable:!1,get:()=>enableOverride!==null?enableOverride:(namespacesCache!==createDebug.namespaces&&(namespacesCache=createDebug.namespaces,enabledCache=createDebug.enabled(namespace)),enabledCache),set:v=>{enableOverride=v}}),typeof createDebug.init=="function"&&createDebug.init(debug),debug}function extend3(namespace,delimiter){let newDebug=createDebug(this.namespace+(typeof delimiter>"u"?":":delimiter)+namespace);return newDebug.log=this.log,newDebug}function enable(namespaces){createDebug.save(namespaces),createDebug.namespaces=namespaces,createDebug.names=[],createDebug.skips=[];let split=(typeof namespaces=="string"?namespaces:"").trim().replace(/\s+/g,",").split(",").filter(Boolean);for(let ns of split)ns[0]==="-"?createDebug.skips.push(ns.slice(1)):createDebug.names.push(ns)}function matchesTemplate(search,template){let searchIndex=0,templateIndex=0,starIndex=-1,matchIndex=0;for(;searchIndex<search.length;)if(templateIndex<template.length&&(template[templateIndex]===search[searchIndex]||template[templateIndex]==="*"))template[templateIndex]==="*"?(starIndex=templateIndex,matchIndex=searchIndex,templateIndex++):(searchIndex++,templateIndex++);else if(starIndex!==-1)templateIndex=starIndex+1,matchIndex++,searchIndex=matchIndex;else return!1;for(;templateIndex<template.length&&template[templateIndex]==="*";)templateIndex++;return templateIndex===template.length}function disable(){let namespaces=[...createDebug.names,...createDebug.skips.map(namespace=>"-"+namespace)].join(",");return createDebug.enable(""),namespaces}function enabled(name){for(let skip of createDebug.skips)if(matchesTemplate(name,skip))return!1;for(let ns of createDebug.names)if(matchesTemplate(name,ns))return!0;return!1}function coerce(val){return val instanceof Error?val.stack||val.message:val}function destroy(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return createDebug.enable(createDebug.load()),createDebug}module.exports=setup}});var require_browser=__commonJS({"../../node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/browser.js"(exports,module){exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.storage=localstorage();exports.destroy=(()=>{let warned=!1;return()=>{warned||(warned=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();exports.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs))return!0;if(typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let m;return typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&(m=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(m[1],10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(args){if(args[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+args[0]+(this.useColors?"%c ":" ")+"+"+module.exports.humanize(this.diff),!this.useColors)return;let c="color: "+this.color;args.splice(1,0,c,"color: inherit");let index=0,lastC=0;args[0].replace(/%[a-zA-Z%]/g,match=>{match!=="%%"&&(index++,match==="%c"&&(lastC=index))}),args.splice(lastC,0,c)}exports.log=console.debug||console.log||(()=>{});function save(namespaces){try{namespaces?exports.storage.setItem("debug",namespaces):exports.storage.removeItem("debug")}catch{}}function load(){let r;try{r=exports.storage.getItem("debug")||exports.storage.getItem("DEBUG")}catch{}return!r&&typeof process<"u"&&"env"in process&&(r=process.env.DEBUG),r}function localstorage(){try{return localStorage}catch{}}module.exports=require_common()(exports);var{formatters}=module.exports;formatters.j=function(v){try{return JSON.stringify(v)}catch(error62){return"[UnexpectedJSONParseError]: "+error62.message}}}});var require_has_flag=__commonJS({"../../node_modules/.pnpm/has-flag@3.0.0/node_modules/has-flag/index.js"(exports,module){"use strict";module.exports=(flag,argv)=>{argv=argv||process.argv;let prefix=flag.startsWith("-")?"":flag.length===1?"-":"--",pos=argv.indexOf(prefix+flag),terminatorPos=argv.indexOf("--");return pos!==-1&&(terminatorPos===-1?!0:pos<terminatorPos)}}});var require_supports_color=__commonJS({"../../node_modules/.pnpm/supports-color@5.5.0/node_modules/supports-color/index.js"(exports,module){"use strict";var os12=__require("os"),hasFlag=require_has_flag(),env=process.env,forceColor;hasFlag("no-color")||hasFlag("no-colors")||hasFlag("color=false")?forceColor=!1:(hasFlag("color")||hasFlag("colors")||hasFlag("color=true")||hasFlag("color=always"))&&(forceColor=!0);"FORCE_COLOR"in env&&(forceColor=env.FORCE_COLOR.length===0||parseInt(env.FORCE_COLOR,10)!==0);function translateLevel(level){return level===0?!1:{level,hasBasic:!0,has256:level>=2,has16m:level>=3}}function supportsColor(stream){if(forceColor===!1)return 0;if(hasFlag("color=16m")||hasFlag("color=full")||hasFlag("color=truecolor"))return 3;if(hasFlag("color=256"))return 2;if(stream&&!stream.isTTY&&forceColor!==!0)return 0;let min=forceColor?1:0;if(process.platform==="win32"){let osRelease=os12.release().split(".");return Number(process.versions.node.split(".")[0])>=8&&Number(osRelease[0])>=10&&Number(osRelease[2])>=10586?Number(osRelease[2])>=14931?3:2:1}if("CI"in env)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some(sign=>sign in env)||env.CI_NAME==="codeship"?1:min;if("TEAMCITY_VERSION"in env)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION)?1:0;if(env.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in env){let version3=parseInt((env.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(env.TERM_PROGRAM){case"iTerm.app":return version3>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(env.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)||"COLORTERM"in env?1:(env.TERM==="dumb",min)}function getSupportLevel(stream){let level=supportsColor(stream);return translateLevel(level)}module.exports={supportsColor:getSupportLevel,stdout:getSupportLevel(process.stdout),stderr:getSupportLevel(process.stderr)}}});var require_node=__commonJS({"../../node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/node.js"(exports,module){var tty=__require("tty"),util=__require("util");exports.init=init;exports.log=log2;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.destroy=util.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");exports.colors=[6,2,3,4,5,1];try{let supportsColor=require_supports_color();supportsColor&&(supportsColor.stderr||supportsColor).level>=2&&(exports.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}exports.inspectOpts=Object.keys(process.env).filter(key=>/^debug_/i.test(key)).reduce((obj,key)=>{let prop=key.substring(6).toLowerCase().replace(/_([a-z])/g,(_,k)=>k.toUpperCase()),val=process.env[key];return/^(yes|on|true|enabled)$/i.test(val)?val=!0:/^(no|off|false|disabled)$/i.test(val)?val=!1:val==="null"?val=null:val=Number(val),obj[prop]=val,obj},{});function useColors(){return"colors"in exports.inspectOpts?!!exports.inspectOpts.colors:tty.isatty(process.stderr.fd)}function formatArgs(args){let{namespace:name,useColors:useColors2}=this;if(useColors2){let c=this.color,colorCode="\x1B[3"+(c<8?c:"8;5;"+c),prefix=` ${colorCode};1m${name} \x1B[0m`;args[0]=prefix+args[0].split(`
1098
+ `)),client2=(dependencies.createClient??(clientOptions=>new UnifiedClient(clientOptions)))({...options.serverUrl?{serverUrl:options.serverUrl}:{},connectTimeoutSec:timeoutSec,requestTimeoutSec:timeoutSec}),latestVersions=options.checkUpdates?Promise.allSettled(Object.keys(UPDATE_SOURCES).map(component2=>(dependencies.fetchLatestVersion??fetchLatestVersion)(component2))):null,environment=[{status:"ok",label:`Unified client v${options.clientVersion}`}],connectors=[],browserList=null;try{if(options.local)environment.push({status:"ok",label:options.transport==="cdp"?"Browser scope: this machine (forced CDP)":"Browser scope: this machine"});else if(options.serverUrl){let source=options.serverUrlSource?` (${options.serverUrlSource})`:"";try{let connectorList=await client2.invoke("connector_list",{},{timeoutSec});connectors=Array.isArray(connectorList?.connectors)?connectorList.connectors:[],environment.push({status:"ok",label:`Cloud server${source}`,details:[redactServerUrl(options.serverUrl),`${connectors.length} connector${connectors.length===1?"":"s"} connected`]})}catch(error62){environment.push({status:"error",label:`Cloud server or connector discovery failed${source}`,details:[formatError(error62),redactServerUrl(options.serverUrl),"On the Agent machine, run `mearl-cloud-server status` to verify the server and current connection command. Use `mearl check --local` to isolate this machine."]})}}else environment.push({status:"ok",label:"Local mode (no cloud-server configuration)"});let inventoryOptions={timeoutSec,...options.local?{local:!0}:{},...options.transport?{transport:options.transport}:{},...!options.local&&options.connector?{connector:options.connector}:{}};try{options.serverUrl&&!options.local&&environment.some(item=>item.status==="error")?browserList=await client2.invoke("browser_list",{},{timeoutSec,local:!0}):browserList=await client2.invoke("browser_list",{},inventoryOptions),environment.push({status:"ok",label:"Browser inventory"}),browserList.warnings?.length&&environment.push({status:"warning",label:"Some browser sources could not be inspected",details:browserList.warnings})}catch(error62){environment.push({status:"error",label:"Browser inventory failed",details:[formatError(error62)]})}let connected=(browserList?.browsers??[]).filter(browser=>browser.status==="connected"&&(options.transport!=="cdp"||browser.transport==="cdp"));if((options.local||!options.serverUrl)&&options.transport!=="cdp"&&!connected.some(browser=>browser.transport==="extension")){let diagnostics=(dependencies.inspectNativeHostInstallation??inspectNativeHostInstallation)();environment.push(...diagnostics.map(item=>({status:"warning",...item})))}let targets=connected;if(options.browser){let matches=findBrowsers2(connected,options.browser);matches.length===0?(environment.push({status:"error",label:`Browser "${options.browser}" is not connected`,details:["Run `mearl browser_list` and use an exact global browserId."]}),targets=[]):matches.length>1?(environment.push({status:"error",label:`Browser selector "${options.browser}" is ambiguous`,details:matches.map(browser=>browser.browserId)}),targets=[]):targets=matches}!options.browser&&connected.length===0&&browserList&&environment.push({status:"error",label:options.transport==="cdp"?"No connected CDP browser":"No connected browser",details:[options.transport==="cdp"?"Enable a local CDP endpoint (see `mearl-native-host --help`) and run `mearl browser_list --cdp` to inspect discovery.":"Open Chrome with the Mearl extension, start a managed browser, or connect a browser host.",...!options.local&&connectors.length>0?["Connectors are connected but expose no ready browser. On the browser machine, run `mearl check --local`; use `mearl connector_list` for versions and heartbeat details."]:[]]});let browserChecks=[];await Promise.all(targets.map(async browser=>{try{options.transport==="cdp"&&await client2.invoke("tab_list",{},{timeoutSec,browser:browser.browserId,transport:"cdp"});let versions=await client2.invoke("get_versions",{},{timeoutSec,browser:browser.browserId,...options.transport?{transport:options.transport}:{}}),publicVersions={...versions.nativeHost?{nativeHost:versions.nativeHost}:{},...versions.extension!==void 0?{extension:versions.extension}:{},...versions.browser!==void 0?{browser:versions.browser}:{},...versions.provider?{provider:versions.provider}:{}},details=[versions.nativeHost?`native-host v${versions.nativeHost}`:null,versions.extension?`extension v${versions.extension}`:null,versions.browser?`Chrome ${versions.browser}`:null,versions.provider?`${versions.provider.name} v${versions.provider.version} (protocol v${versions.provider.protocolVersion})`:null].filter(value=>value!==null),capabilities=options.browser?versions.capabilities:void 0;capabilities&&details.push(`capabilities (${capabilities.actions.length}): ${capabilities.actions.join(", ")||"none"}`,`screenshot: ${capabilities.screenshot}`);let extensionInstallation;options.local&&browser.transport==="extension"&&typeof versions.extensionId=="string"&&typeof versions.extension=="string"&&(typeof versions.setupManagedPath=="string"||versions.setupManagedPath===null)&&(extensionInstallation={extensionId:versions.extensionId,setupManagedPath:versions.setupManagedPath});let browserAccess,accessUrlWarning,browserAccessCapability=versions.browserAccess,providerAccess=browser.operations?.includes("access")===!0;if((providerAccess||browserAccessCapability)&&options.browser)try{browserAccess=await getBrowserAccess(client2,browser,providerAccess?void 0:browserAccessCapability,timeoutSec),details.push(`Browser access URL (${browserAccessLabel(browserAccess)}; sensitive): ${browserAccess.url}`)}catch(error62){accessUrlWarning=formatError(error62),details.push(`Browser access URL unavailable: ${accessUrlWarning}`)}browserChecks.push({...browserAccess?{browserAccess}:{},browser,...capabilities?{capabilities}:{},...extensionInstallation?{extensionInstallation}:{},item:{status:accessUrlWarning?"warning":"ok",label:accessUrlWarning?"Browser command path ready; browser access URL unavailable":options.transport==="cdp"?"CDP command path":"Browser command path",details},versions:publicVersions,...accessUrlWarning?{warnings:[accessUrlWarning]}:{}})}catch(error62){let message=formatError(error62);browserChecks.push({browser,...message.includes("Unknown action")?{warnings:["Update @mearl/native-host for complete diagnostics."]}:{errors:[message]},item:message.includes("Unknown action")?{status:"warning",label:"Browser is reachable but runtime version details are unavailable",details:["Update @mearl/native-host for complete diagnostics."]}:{status:"error",label:"Browser command path failed",details:[message]}})}}));let updates;if(latestVersions){let latestResults=await latestVersions,components=Object.keys(UPDATE_SOURCES),installed=new Map,addInstalled=(component2,version3)=>{if(!version3)return;let versions=installed.get(component2)??new Set;versions.add(version3),installed.set(component2,versions)};addInstalled("client",options.clientVersion);for(let check2 of browserChecks)addInstalled("native-host",check2.versions?.nativeHost),addInstalled("extension",check2.versions?.extension);for(let connector of connectors)addInstalled("cloud-connector",connector.version);updates=components.flatMap((component2,index)=>{let result=latestResults[index];return[...installed.get(component2)??[]].map(version3=>({component:component2,installed:version3,...result.status==="fulfilled"?{latest:result.value}:{},status:result.status==="rejected"||!parseReleaseVersion(version3)||!parseReleaseVersion(result.value)?"unavailable":isNewerRelease(result.value,version3)?"available":"current"}))});let available=updates.filter(update=>update.status==="available"),unavailable=updates.filter(update=>update.status==="unavailable"),packageUpdateAvailable=available.some(update=>update.component==="client"||update.component==="native-host"),extensionUpdateAvailable=available.some(update=>update.component==="extension"),connectorUpdateAvailable=available.some(update=>update.component==="cloud-connector");environment.push({status:available.length||unavailable.length?"warning":"ok",label:available.length?`${available.length} Mearl update${available.length===1?"":"s"} available`:unavailable.length?"Mearl update check incomplete":"Mearl packages are current",details:[...available.map(update=>`${update.component}: ${update.installed} → ${update.latest}`),...packageUpdateAvailable?["Update on the affected machine: npx --@mearl:registry=https://registry.npmjs.org @mearl/setup update"]:[],...extensionUpdateAvailable?["Update a setup-managed extension: npx --@mearl:registry=https://registry.npmjs.org @mearl/setup extension"]:[],...connectorUpdateAvailable?["Update cloud-connector with its package manager on the connector machine."]:[],...unavailable.map(update=>`${update.component}: latest version unavailable`)]})}let hasError=environment.some(item=>item.status==="error")||browserChecks.some(check2=>check2.item.status==="error"),listedBrowsers=browserList?.browsers??[];if(options.json){let result={browsers:listedBrowsers.map(browser=>{let check2=browserChecks.find(item=>item.browser.browserId===browser.browserId),browserIdentity={...browser};return delete browserIdentity.extensionVersion,delete browserIdentity.nativeHostVersion,{...browserIdentity,selected:targets.some(target=>target.browserId===browser.browserId),...check2?.browserAccess?{browserAccess:check2.browserAccess}:{},...check2?.capabilities?{capabilities:check2.capabilities}:{},...check2?.item?{check:{label:check2.item.label,status:check2.item.status,...check2.errors?{errors:check2.errors}:{},...check2.warnings?{warnings:check2.warnings}:{}}}:{},...check2?.extensionInstallation?{extensionInstallation:check2.extensionInstallation}:{},...check2?.versions?{versions:check2.versions}:{}}}),clientVersion:options.clientVersion,connectors,environment,ok:!hasError,...updates?{updates}:{}};return writeJson(JSON.stringify(result,null,2)),result}if(writeLine(""),printSection(writeLine,"Environment",environment),connectors.length>0){writeLine("Cloud connectors");for(let connector of connectors)writeLine(formatConnector(connector));writeLine("")}if(listedBrowsers.length>0){writeLine("Browsers");for(let browser of listedBrowsers){writeLine(formatBrowser(browser,browser.browserId===browserList?.defaultBrowserId));let check2=browserChecks.find(item=>item.browser.browserId===browser.browserId);if(check2){let marker=check2.item.status==="ok"?"✅":check2.item.status==="warning"?"⚠️ ":"❌";writeLine(` ${marker} ${check2.item.label}`);for(let detail of check2.item.details??[])writeLine(` ${detail}`)}else browser.status!=="connected"&&writeLine(` ⚪ ${browser.status}`)}writeLine("")}return hasError?(writeLine("⚠️ Mearl checks failed. See the browser or source details above."),!1):(writeLine(options.browser?"🎉 Selected browser is ready!":`🎉 All ${targets.length} connected browser${targets.length===1?"":"s"} are ready!`),!0)}finally{client2.disconnect()}}var UPDATE_SOURCES,init_check=__esm({"../client/dist/check.js"(){"use strict";init_nativeHost();init_unified();UPDATE_SOURCES={client:"https://registry.npmjs.org/@mearl%2Fclient/latest","native-host":"https://registry.npmjs.org/@mearl%2Fnative-host/latest","cloud-connector":"https://registry.npmjs.org/@mearl%2Fcloud-connector/latest",extension:"https://github.com/F-loat/mearl/releases/latest/download/config.json"}}});var init_local=__esm({"../client/dist/local.js"(){"use strict";init_socket();init_browserRegistry()}});var require_ms=__commonJS({"../../node_modules/.pnpm/ms@2.1.3/node_modules/ms/index.js"(exports,module){var s=1e3,m=s*60,h=m*60,d=h*24,w=d*7,y=d*365.25;module.exports=function(val,options){options=options||{};var type=typeof val;if(type==="string"&&val.length>0)return parse6(val);if(type==="number"&&isFinite(val))return options.long?fmtLong(val):fmtShort(val);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(val))};function parse6(str){if(str=String(str),!(str.length>100)){var match=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);if(match){var n=parseFloat(match[1]),type=(match[2]||"ms").toLowerCase();switch(type){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"weeks":case"week":case"w":return n*w;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}}}function fmtShort(ms){var msAbs=Math.abs(ms);return msAbs>=d?Math.round(ms/d)+"d":msAbs>=h?Math.round(ms/h)+"h":msAbs>=m?Math.round(ms/m)+"m":msAbs>=s?Math.round(ms/s)+"s":ms+"ms"}function fmtLong(ms){var msAbs=Math.abs(ms);return msAbs>=d?plural2(ms,msAbs,d,"day"):msAbs>=h?plural2(ms,msAbs,h,"hour"):msAbs>=m?plural2(ms,msAbs,m,"minute"):msAbs>=s?plural2(ms,msAbs,s,"second"):ms+" ms"}function plural2(ms,msAbs,n,name){var isPlural=msAbs>=n*1.5;return Math.round(ms/n)+" "+name+(isPlural?"s":"")}}});var require_common=__commonJS({"../../node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/common.js"(exports,module){function setup(env){createDebug.debug=createDebug,createDebug.default=createDebug,createDebug.coerce=coerce,createDebug.disable=disable,createDebug.enable=enable,createDebug.enabled=enabled,createDebug.humanize=require_ms(),createDebug.destroy=destroy,Object.keys(env).forEach(key=>{createDebug[key]=env[key]}),createDebug.names=[],createDebug.skips=[],createDebug.formatters={};function selectColor(namespace){let hash3=0;for(let i2=0;i2<namespace.length;i2++)hash3=(hash3<<5)-hash3+namespace.charCodeAt(i2),hash3|=0;return createDebug.colors[Math.abs(hash3)%createDebug.colors.length]}createDebug.selectColor=selectColor;function createDebug(namespace){let prevTime,enableOverride=null,namespacesCache,enabledCache;function debug(...args){if(!debug.enabled)return;let self=debug,curr=Number(new Date),ms=curr-(prevTime||curr);self.diff=ms,self.prev=prevTime,self.curr=curr,prevTime=curr,args[0]=createDebug.coerce(args[0]),typeof args[0]!="string"&&args.unshift("%O");let index=0;args[0]=args[0].replace(/%([a-zA-Z%])/g,(match,format)=>{if(match==="%%")return"%";index++;let formatter=createDebug.formatters[format];if(typeof formatter=="function"){let val=args[index];match=formatter.call(self,val),args.splice(index,1),index--}return match}),createDebug.formatArgs.call(self,args),(self.log||createDebug.log).apply(self,args)}return debug.namespace=namespace,debug.useColors=createDebug.useColors(),debug.color=createDebug.selectColor(namespace),debug.extend=extend3,debug.destroy=createDebug.destroy,Object.defineProperty(debug,"enabled",{enumerable:!0,configurable:!1,get:()=>enableOverride!==null?enableOverride:(namespacesCache!==createDebug.namespaces&&(namespacesCache=createDebug.namespaces,enabledCache=createDebug.enabled(namespace)),enabledCache),set:v=>{enableOverride=v}}),typeof createDebug.init=="function"&&createDebug.init(debug),debug}function extend3(namespace,delimiter){let newDebug=createDebug(this.namespace+(typeof delimiter>"u"?":":delimiter)+namespace);return newDebug.log=this.log,newDebug}function enable(namespaces){createDebug.save(namespaces),createDebug.namespaces=namespaces,createDebug.names=[],createDebug.skips=[];let split=(typeof namespaces=="string"?namespaces:"").trim().replace(/\s+/g,",").split(",").filter(Boolean);for(let ns of split)ns[0]==="-"?createDebug.skips.push(ns.slice(1)):createDebug.names.push(ns)}function matchesTemplate(search,template){let searchIndex=0,templateIndex=0,starIndex=-1,matchIndex=0;for(;searchIndex<search.length;)if(templateIndex<template.length&&(template[templateIndex]===search[searchIndex]||template[templateIndex]==="*"))template[templateIndex]==="*"?(starIndex=templateIndex,matchIndex=searchIndex,templateIndex++):(searchIndex++,templateIndex++);else if(starIndex!==-1)templateIndex=starIndex+1,matchIndex++,searchIndex=matchIndex;else return!1;for(;templateIndex<template.length&&template[templateIndex]==="*";)templateIndex++;return templateIndex===template.length}function disable(){let namespaces=[...createDebug.names,...createDebug.skips.map(namespace=>"-"+namespace)].join(",");return createDebug.enable(""),namespaces}function enabled(name){for(let skip of createDebug.skips)if(matchesTemplate(name,skip))return!1;for(let ns of createDebug.names)if(matchesTemplate(name,ns))return!0;return!1}function coerce(val){return val instanceof Error?val.stack||val.message:val}function destroy(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return createDebug.enable(createDebug.load()),createDebug}module.exports=setup}});var require_browser=__commonJS({"../../node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/browser.js"(exports,module){exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.storage=localstorage();exports.destroy=(()=>{let warned=!1;return()=>{warned||(warned=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();exports.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs))return!0;if(typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let m;return typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&(m=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(m[1],10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(args){if(args[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+args[0]+(this.useColors?"%c ":" ")+"+"+module.exports.humanize(this.diff),!this.useColors)return;let c="color: "+this.color;args.splice(1,0,c,"color: inherit");let index=0,lastC=0;args[0].replace(/%[a-zA-Z%]/g,match=>{match!=="%%"&&(index++,match==="%c"&&(lastC=index))}),args.splice(lastC,0,c)}exports.log=console.debug||console.log||(()=>{});function save(namespaces){try{namespaces?exports.storage.setItem("debug",namespaces):exports.storage.removeItem("debug")}catch{}}function load(){let r;try{r=exports.storage.getItem("debug")||exports.storage.getItem("DEBUG")}catch{}return!r&&typeof process<"u"&&"env"in process&&(r=process.env.DEBUG),r}function localstorage(){try{return localStorage}catch{}}module.exports=require_common()(exports);var{formatters}=module.exports;formatters.j=function(v){try{return JSON.stringify(v)}catch(error62){return"[UnexpectedJSONParseError]: "+error62.message}}}});var require_has_flag=__commonJS({"../../node_modules/.pnpm/has-flag@3.0.0/node_modules/has-flag/index.js"(exports,module){"use strict";module.exports=(flag,argv)=>{argv=argv||process.argv;let prefix=flag.startsWith("-")?"":flag.length===1?"-":"--",pos=argv.indexOf(prefix+flag),terminatorPos=argv.indexOf("--");return pos!==-1&&(terminatorPos===-1?!0:pos<terminatorPos)}}});var require_supports_color=__commonJS({"../../node_modules/.pnpm/supports-color@5.5.0/node_modules/supports-color/index.js"(exports,module){"use strict";var os12=__require("os"),hasFlag=require_has_flag(),env=process.env,forceColor;hasFlag("no-color")||hasFlag("no-colors")||hasFlag("color=false")?forceColor=!1:(hasFlag("color")||hasFlag("colors")||hasFlag("color=true")||hasFlag("color=always"))&&(forceColor=!0);"FORCE_COLOR"in env&&(forceColor=env.FORCE_COLOR.length===0||parseInt(env.FORCE_COLOR,10)!==0);function translateLevel(level){return level===0?!1:{level,hasBasic:!0,has256:level>=2,has16m:level>=3}}function supportsColor(stream){if(forceColor===!1)return 0;if(hasFlag("color=16m")||hasFlag("color=full")||hasFlag("color=truecolor"))return 3;if(hasFlag("color=256"))return 2;if(stream&&!stream.isTTY&&forceColor!==!0)return 0;let min=forceColor?1:0;if(process.platform==="win32"){let osRelease=os12.release().split(".");return Number(process.versions.node.split(".")[0])>=8&&Number(osRelease[0])>=10&&Number(osRelease[2])>=10586?Number(osRelease[2])>=14931?3:2:1}if("CI"in env)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some(sign=>sign in env)||env.CI_NAME==="codeship"?1:min;if("TEAMCITY_VERSION"in env)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION)?1:0;if(env.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in env){let version3=parseInt((env.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(env.TERM_PROGRAM){case"iTerm.app":return version3>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(env.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)||"COLORTERM"in env?1:(env.TERM==="dumb",min)}function getSupportLevel(stream){let level=supportsColor(stream);return translateLevel(level)}module.exports={supportsColor:getSupportLevel,stdout:getSupportLevel(process.stdout),stderr:getSupportLevel(process.stderr)}}});var require_node=__commonJS({"../../node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/node.js"(exports,module){var tty=__require("tty"),util=__require("util");exports.init=init;exports.log=log2;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.destroy=util.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");exports.colors=[6,2,3,4,5,1];try{let supportsColor=require_supports_color();supportsColor&&(supportsColor.stderr||supportsColor).level>=2&&(exports.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}exports.inspectOpts=Object.keys(process.env).filter(key=>/^debug_/i.test(key)).reduce((obj,key)=>{let prop=key.substring(6).toLowerCase().replace(/_([a-z])/g,(_,k)=>k.toUpperCase()),val=process.env[key];return/^(yes|on|true|enabled)$/i.test(val)?val=!0:/^(no|off|false|disabled)$/i.test(val)?val=!1:val==="null"?val=null:val=Number(val),obj[prop]=val,obj},{});function useColors(){return"colors"in exports.inspectOpts?!!exports.inspectOpts.colors:tty.isatty(process.stderr.fd)}function formatArgs(args){let{namespace:name,useColors:useColors2}=this;if(useColors2){let c=this.color,colorCode="\x1B[3"+(c<8?c:"8;5;"+c),prefix=` ${colorCode};1m${name} \x1B[0m`;args[0]=prefix+args[0].split(`
1099
1099
  `).join(`
1100
1100
  `+prefix),args.push(colorCode+"m+"+module.exports.humanize(this.diff)+"\x1B[0m")}else args[0]=getDate()+name+" "+args[0]}function getDate(){return exports.inspectOpts.hideDate?"":new Date().toISOString()+" "}function log2(...args){return process.stderr.write(util.formatWithOptions(exports.inspectOpts,...args)+`
1101
1101
  `)}function save(namespaces){namespaces?process.env.DEBUG=namespaces:delete process.env.DEBUG}function load(){return process.env.DEBUG}function init(debug){debug.inspectOpts={};let keys=Object.keys(exports.inspectOpts);for(let i2=0;i2<keys.length;i2++)debug.inspectOpts[keys[i2]]=exports.inspectOpts[keys[i2]]}module.exports=require_common()(exports);var{formatters}=module.exports;formatters.o=function(v){return this.inspectOpts.colors=this.useColors,util.inspect(v,this.inspectOpts).split(`
@@ -1105,14 +1105,14 @@ ${result.stderr}`).trim();if(detail&&writeLine(detail),/Failed to (?:update|remo
1105
1105
  ${removed.stderr}`))||existsSync10(skillDirectory))throw new Error(`skills remove ${skillName2} 未完成;插件注册已保留。`);for(let pluginName of unregisteredNames)unregisterPlugin(pluginName);return{...entryMissing?{entryMissing:!0}:{},removed:!0,skillName:skillName2,unregisteredNames}}function parseInstalledPluginPaths(output3,listed=[]){let paths=[],expected=0,inResult=!1;for(let line of stripAnsi(output3).split(/\r?\n/)){let heading=line.match(/\bInstalled (\d+) skills?\b/);if(heading){expected+=Number(heading[1]),inResult=!0;continue}if(!inResult)continue;if(/[╰└├]/.test(line)){inResult=!1;continue}let item=line.trim().match(/^[│|]?\s*✓\s+(.+?)\s*[│|]?$/);if(!item)continue;let value=item[1].trim().replaceAll("\\","/"),copied=value.match(/^(.+?) \(copied\)$/),matches=copied?listed.filter(skill=>skill.scope==="global"&&skill.name===copied[1]):[];if(copied&&matches.length!==1)throw new Error("无法从 Skills JSON 清单确认复制的 Skill 安装路径。");let installedPath=copied?matches[0].path:value,skillPath=resolve9(installedPath.startsWith("~/")?join23(homedir9(),installedPath.slice(2)):installedPath);if(dirname9(skillPath)!==join23(homedir9(),".agents","skills"))throw new Error(`无法识别全局 skill 安装路径: ${item[1]}。请使用 setup plugin [name] <path> 注册。`);paths.push(skillPath)}if(paths.length!==expected)throw new Error("Skills 安装结果格式无法识别,请使用 setup plugin [name] <path> 注册。");return[...new Set(paths)]}function permitsEmptyInstallResult(args,output3){return args.length===0||args.some(argument=>["--help","-h","--list"].includes(argument))||/\b(?:installation\s+)?cancel(?:led|ed)\b/i.test(output3)}async function installPlugins(args,runner=runCommand,options={}){if(args.includes("--"))throw new Error("plugin install 不支持 -- 参数分隔符,以确保全局安装选项生效。");let cli=await captureSkillsCli({env:options.env,runCommand:runner});if(!cli)throw new Error("未找到 skills 或 npx,请检查 Node.js 安装。");if(options.selection&&(cli.selection?.path!==options.selection.path||cli.selection.sha256!==options.selection.sha256))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");let declaration=options.expectedSkill?cli.managedSkills[options.expectedSkill]:void 0;if(options.expectedSkill&&(!declaration?.source||declaration.source!==args[0]))throw new Error("PLUGIN_CATALOG_SKILL_UNDECLARED");let verifySkill=(registered=!1)=>{if(!options.expectedSkill||!declaration)return;let status=cli.inspectGlobal(declaration.source,options.expectedSkill,declaration.version);if(status.state!=="ready"&&(registered||status.state!=="registration"))throw new Error(`${status.reason}: ${options.expectedSkill}`)},assertSource=()=>{if(!options.expectedSkill||!declaration)return;let status=cli.inspectGlobal(declaration.source,options.expectedSkill,declaration.version,{migrateFrom:options.registrationManagedBy===OFFICIAL_PLUGIN_MANAGER?declaration.migrateFrom:void 0});if(status.state==="conflict")throw new Error(`${status.reason}: ${options.expectedSkill}`)};assertSource(),await options.confirm?.(),assertSource();let runInstall=()=>cli.run(["add",...args,"--global"],{tee:!0}),installed=await(options.expectedSkill?preserveSkillDisabled(join23(homedir9(),".agents","skills",options.expectedSkill),runInstall):runInstall());if(installed.code!==0)return installed.code;await options.confirm?.();let output3=`${installed.stdout??""}
1106
1106
  ${installed.stderr??""}`,listed=[];if(/✓[^\n]*\(copied\)/.test(stripAnsi(output3))){let result=await cli.run(["list","--global","--json"],{capture:!0});if(result.code!==0)throw new Error("无法读取 Skills JSON 清单;插件尚未注册。");listed=parseInstalledSkills(result.stdout)}let paths=parseInstalledPluginPaths(output3,listed);if(options.expectedSkill){if(paths.length!==1||paths[0]!==join23(homedir9(),".agents","skills",options.expectedSkill))throw new Error("PLUGIN_CATALOG_SKILL_RESULT_MISMATCH");verifySkill()}if(paths.length===0){if(permitsEmptyInstallResult(args,output3))return 0;throw new Error("Skills 安装成功但无法识别安装结果,请使用 setup plugin [name] <path> 注册。")}let plugins=new Map;for(let skillPath of paths){if(!statSync12(skillManifestPath(skillPath)??join23(skillPath,"SKILL.md")).isFile())throw new Error(`安装结果缺少 SKILL.md: ${skillPath}`);let entry=findPluginDirectoryEntry(skillPath);if(!entry)continue;let plugin=await loadPlugin(entry,registrationContext),name=plugin.name||basename4(skillPath);if(assertPluginName(name),options.expectedPluginName&&name!==options.expectedPluginName)throw new Error("PLUGIN_CATALOG_ALIAS_MISMATCH");if(plugins.has(name))throw new Error(`多个 skill 使用插件名称 ${name},请调整入口的 name metadata。`);plugins.set(name,{entry,hasPublicCommands:!!plugin.commandHelp(name),description:plugin.description,...plugin.toolbox?{toolbox:plugin.toolbox}:{},appProfiles:plugin.appProfiles,profileSources:plugin.profileSources})}if(plugins.size===0)return console.error("未找到 scripts/main.mjs 或 scripts/main.py 插件入口;自定义入口可用 setup plugin [name] <path> 注册。"),0;await ensurePluginRuntime(runner);for(let[name,{entry,description,toolbox,appProfiles,profileSources,hasPublicCommands}]of plugins){await options.confirm?.(),verifySkill();let existing=findPluginRegistration(name);if(options.registrationManagedBy&&existing&&existing.managedBy!==options.registrationManagedBy){console.error(`Plugin ${name}: existing user registration kept.`);continue}registerPlugin(name,entry,description,{hasPublicCommands,managedBy:options.registrationManagedBy??(cli.id==="skills"?void 0:cli.id),...toolbox?{toolbox}:{},appProfiles,profileSources}),console.error(`Plugin ${name} registered: ${entry}${hasPublicCommands?`
1107
1107
  Run: mearl ${name} --help`:toolbox?`
1108
- Open in Mearl toolbox.`:""}`)}return verifySkill(!0),0}var registrationContext,init_plugin3=__esm({"../setup/dist/plugin.js"(){"use strict";init_plugin2();init_skillSources();init_presetInstallationLease();init_pluginRuntime();init_skills();init_dist();registrationContext={options:{},invoke:async()=>{throw new Error("注册时不能执行浏览器操作")},progress:()=>{throw new Error("注册时不能报告执行进度")}}}});async function installManagedPlugins(options={},dependencies={}){let writeLine=options.writeLine??(line=>console.error(line));try{let catalog=(dependencies.readCatalog??readOfficialPluginCatalog)();if(!catalog||Object.keys(catalog.plugins).length===0)return"skipped";let registrationFor=dependencies.findPluginRegistration??findPluginRegistration,candidates=Object.entries(catalog.plugins).filter(([name])=>{let registration=registrationFor(name);return registration&&registration.managedBy!==OFFICIAL_PLUGIN_MANAGER?(writeLine(`${name} plugin: existing user registration kept.`),!1):!0});if(candidates.length===0)return"skipped";if(options.includeMearlSkill&&!await(dependencies.runSkillOperation??runGlobalMearlSkillOperation)(options.mearlSkillOperation??"install",{env:options.env,runCommand:options.runCommand,writeLine,yes:!0}))return"failed";for(let[name,definition]of candidates){let code=await(dependencies.installPlugins??installPlugins)([...definition.installArgs],options.runCommand??runCommand,{registrationManagedBy:OFFICIAL_PLUGIN_MANAGER,env:options.env});if(code!==0)return writeLine(`${name} plugin: install failed (exit ${code}).`),"failed";if(registrationFor(name)?.managedBy!==OFFICIAL_PLUGIN_MANAGER)return writeLine(`${name} plugin: installation did not create its managed registration.`),"failed";writeLine(`${name} plugin: installed and registered.`)}return"installed"}catch(error62){return writeLine(`Managed plugin batch: ${error62 instanceof Error?error62.message:String(error62)}; failed.`),"failed"}}async function uninstallManagedPlugins(options={},dependencies={}){let writeLine=options.writeLine??(line=>console.error(line));try{let catalog=(dependencies.readCatalog??readOfficialPluginCatalog)();if(!catalog)return"skipped";let registrationFor=dependencies.findPluginRegistration??findPluginRegistration;for(let name of Object.keys(catalog.plugins)){let registration=registrationFor(name);if(registration){if(registration.managedBy!==OFFICIAL_PLUGIN_MANAGER){writeLine(`${name} plugin: existing user registration kept.`);continue}if(await(dependencies.uninstallPlugin??uninstallPlugin)(name,options.runCommand??runCommand,{preserveRegistrationsOutsideManager:OFFICIAL_PLUGIN_MANAGER,env:options.env}),registrationFor(name))return writeLine(`${name} plugin: uninstall did not clear its registration.`),"failed";writeLine(`${name} plugin: uninstalled.`)}}return options.includeMearlSkill&&!await(dependencies.runSkillOperation??runGlobalMearlSkillOperation)("uninstall",{env:options.env,runCommand:options.runCommand,writeLine,yes:!0})?"failed":"uninstalled"}catch(error62){return writeLine(`Managed plugin batch: ${error62 instanceof Error?error62.message:String(error62)}; failed.`),"failed"}}var init_managedPlugins=__esm({"../setup/dist/managedPlugins.js"(){"use strict";init_plugin2();init_plugin3();init_skills();init_dist()}});import{existsSync as existsSync11,readFileSync as readFileSync15,statSync as statSync13}from"node:fs";import{join as join24,resolve as resolve10}from"node:path";function inspectProviderPackage(manifest){if(validateInstalledProviderManifest(manifest))return!1;try{let file2=join24(manifest.packageRoot,"package.json"),stat5=statSync13(file2);if(!stat5.isFile()||stat5.size>1024*1024)return!1;let metadata=JSON.parse(readFileSync15(file2,"utf8")),provider=metadata.mearl?.provider;return metadata.name===manifest.packageName&&metadata.version===manifest.version&&provider?.providerId===manifest.providerId&&provider.protocolVersion===manifest.protocolVersion&&typeof provider.entry=="string"&&resolve10(manifest.packageRoot,provider.entry)===manifest.entryPath}catch{return!1}}async function stopProviderBeforePackageChange(providerId){if(readProviderStart(providerId))throw new Error(`Provider ${providerId} is still starting`);let live=readLiveProvider(providerId);if(!live)return;let owner={pid:live.pid,processIdentity:processIdentity(live.pid)};stopProvider(providerId);let deadline=Date.now()+5e3;for(;isProcessOwnerAlive(owner);){if(Date.now()>=deadline)throw new Error(`Provider ${providerId} did not finish stopping`);await new Promise(resolve16=>setTimeout(resolve16,50))}if(readLiveProvider(providerId)||readProviderStart(providerId))throw new Error(`Provider ${providerId} restarted during shutdown`)}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(output3){return output3.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=>join24(value,"node_modules");break;case"bun":args=["pm","bin","-g"],toNodeModules=value=>resolve10(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 join24(toNodeModules(root),...packageName.split("/"))}function findRegisteredProvider(selector,listProviders){let matches=listProviders().filter(provider=>provider.providerId===selector||provider.packageName===selector);if(matches.length===0)throw new Error(`Provider is not registered: ${selector}`);if(matches.length>1)throw new Error(`Provider selector is ambiguous: ${selector}`);return matches[0]}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),previous=(dependencies.listProviders??listInstalledProviders)().filter(provider=>provider.packageName===packageName);for(let provider of previous)await(dependencies.stopProvider??stopProviderBeforePackageChange)(provider.providerId);await runPackageCommand(installation,"install",packageName,target,runner,env);let packageRoot=await(dependencies.resolvePackageRoot??resolveGlobalProviderPackageRoot)(installation,packageName,runner,env);if(!(dependencies.existsSync??existsSync11)(join24(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}}async function updateProviderPackage(selector,dependencies={}){let listProviders=dependencies.listProviders??listInstalledProviders,current2=findRegisteredProvider(selector,listProviders),env=process.env,runner=dependencies.runCommand??runCommand,detectedManager=(dependencies.resolvePackageManager??resolvePackageManagerInstallation)(current2.packageRoot,current2.packageName)??void 0,installation=providerManager(env,dependencies,detectedManager);return await(dependencies.stopProvider??stopProviderBeforePackageChange)(current2.providerId),await runPackageCommand(installation,"update",current2.packageName,"latest",runner,env),{manifest:(dependencies.registerPackage??registerProviderPackage)(current2.packageRoot),manager:installation.manager}}async function uninstallProviderPackage(selector,dependencies={}){let listProviders=dependencies.listProviders??listInstalledProviders,manifest=findRegisteredProvider(selector,listProviders),env=process.env,installation=(dependencies.resolvePackageManager??resolvePackageManagerInstallation)(manifest.packageRoot,manifest.packageName)??providerManager(env,dependencies);return await(dependencies.stopProvider??stopProviderBeforePackageChange)(manifest.providerId),await runPackageCommand(installation,"uninstall",manifest.packageName,"latest",dependencies.runCommand??runCommand,env),(dependencies.unregisterProvider??uninstallProvider)(manifest.providerId),{manifest,manager:installation.manager}}var init_provider=__esm({"../setup/dist/provider.js"(){"use strict";init_host();init_packageManager();init_npmRegistry();init_dist()}});import{readdirSync as readdirSync9}from"node:fs";import{basename as basename5,join as join25,resolve as resolve11}from"node:path";import{homedir as homedir10}from"node:os";async function cleanupUninstalledRuntime(){await cleanupPluginRuntime();let root=join25(homedir10(),".mearl");if(resolve11(pluginDirectory())!==resolve11(join25(root,"plugins")))return;if(listRecordFiles(join25(root,"providers/installed")).length)throw new Error("Registered Providers still use runtime caches; caches were retained");for(let directory of["providers/live","providers/starting"])if(listRecordFiles(join25(root,directory)).some(file2=>{let record5=readRecord(file2);return record5&&isProcessOwnerAlive(record5)}))throw new Error("Providers still use runtime caches; caches were retained");pruneOrphanLogs(join25(root,"managed-browsers"),0),pruneOrphanLogs(join25(root,"providers/logs"),0);let entries;try{entries=readdirSync9(join25(root,"plugin-pages"),{withFileTypes:!0})}catch(error62){if(error62.code==="ENOENT")return;throw error62}for(let entry of entries)if(!(!entry.isDirectory()||!/^[a-f0-9]{16}\.json\.d$/.test(entry.name)))for(let file2 of listRecordFiles(join25(root,"plugin-pages",entry.name))){if(!/^session-[a-f0-9]{16}\.json$/.test(basename5(file2)))continue;let record5=readRecord(file2);record5&&!isProcessOwnerAlive(record5)&&removeRecordIfPid(file2,record5.pid)}}var init_runtimeCleanup=__esm({"../setup/dist/runtimeCleanup.js"(){"use strict";init_plugin2();init_dist()}});import{createHash as createHash14,randomUUID as randomUUID17}from"node:crypto";var digest3,PresetBrowserTransfer,init_presetBrowserTransfer=__esm({"../setup/dist/presetBrowserTransfer.js"(){"use strict";init_bundles();init_presetStore();digest3=bytes=>createHash14("sha256").update(bytes).digest("hex"),PresetBrowserTransfer=class{store;now;session;constructor(store=new PresetInstallationStore,now=Date.now){this.store=store,this.now=now}async selectedRevision(acceptedNodeRevision){let current2=await this.store.current({verifyResources:!1});return current2.receipt?.browserSyncRequired&&current2.receipt.revision===acceptedNodeRevision?current2.receipt.revision:null}async handle(input3){if(!input3||typeof input3!="object")throw new BundleError("BUNDLE_INVALID","Expected a browser transfer operation");if(this.session&&this.now()-this.session.touched>12e4&&(this.session=void 0),input3.operation==="open"){if(this.session)throw new BundleError("BUNDLE_CONFLICT","A browser preset transfer is already running");if(typeof input3.installationRevision!="string"||!/^[a-f0-9]{64}$/.test(input3.installationRevision))throw new BundleError("BUNDLE_INVALID","Expected an installation revision");let current2=await this.store.current();if(!current2.receipt||!current2.prepared||current2.receipt.revision!==input3.installationRevision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed before browser transfer");let header={schemaVersion:1,installationRevision:current2.receipt.revision,snapshot:current2.prepared.browser.snapshot,bundles:current2.prepared.browser.bundles.map(({source,revision:revision2,manifest})=>({source,revision:revision2,manifest})),overrides:current2.receipt.overrides},bytes=Buffer.from(JSON.stringify(header));if(bytes.byteLength>MAX_PRESET_TRANSFER_HEADER_BYTES)throw new BundleError("BUNDLE_QUOTA","Browser transfer metadata exceeds 16 MiB");let sha2562=digest3(bytes),resources=new Map([[sha2562,bytes]]);for(let bundle of current2.prepared.browser.bundles)for(let[name,entry]of Object.entries(bundle.manifest.resources))resources.set(entry.sha256,bundle.resources[name]);if(this.session)throw new BundleError("BUNDLE_CONFLICT","A browser preset transfer is already running");return this.session={id:randomUUID17(),revision:current2.receipt.revision,touched:this.now(),resources},{session:this.session.id,sha256:sha2562,byteLength:bytes.byteLength}}let session=this.session;if(!session||input3.session!==session.id)throw new BundleError("BUNDLE_CONFLICT","Browser preset transfer expired or changed");if(session.touched=this.now(),input3.operation==="release")return this.session=void 0,{released:!0};if(input3.operation==="confirm"){if((await this.store.current({verifyResources:!1})).receipt?.revision!==session.revision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed during browser transfer");return{installationRevision:session.revision}}if(input3.operation==="read"){let bytes=session.resources.get(input3.sha256);if(!bytes||!Number.isSafeInteger(input3.offset)||input3.offset<0||input3.offset>=bytes.byteLength||input3.offset%PRESET_TRANSFER_CHUNK_BYTES!==0)throw new BundleError("BUNDLE_INVALID","Invalid browser transfer resource or offset");return{data:Buffer.from(bytes.subarray(input3.offset,input3.offset+PRESET_TRANSFER_CHUNK_BYTES)).toString("base64")}}throw new BundleError("BUNDLE_INVALID","Unsupported browser preset transfer operation")}}}});import{lstat as lstat2,open as open3}from"node:fs/promises";import{constants as constants5}from"node:fs";import{resolve as resolve12}from"node:path";import{fileURLToPath as fileURLToPath3,pathToFileURL as pathToFileURL2}from"node:url";function createNodePresetLoader(){let network=createBundleFetchLoader();return async(source,options)=>{let url2=new URL(source);if(url2.protocol==="file:"){options.signal?.throwIfAborted();let file2=fileURLToPath3(url2),before=await lstat2(file2);if(!before.isFile()||before.isSymbolicLink()||before.size>options.maxBytes)throw new BundleError("BUNDLE_QUOTA","Invalid local preset resource file or size");let handle=await open3(file2,constants5.O_RDONLY|(constants5.O_NOFOLLOW??0));try{let stat5=await handle.stat();if(!stat5.isFile()||stat5.size>options.maxBytes)throw new BundleError("BUNDLE_QUOTA","Local preset resource exceeds its size limit");let bytes=Buffer.alloc(stat5.size+1),length=0;for(;length<bytes.byteLength;){options.signal?.throwIfAborted();let result=await handle.read(bytes,length,bytes.byteLength-length,null);if(!result.bytesRead)break;length+=result.bytesRead}if(length>stat5.size)throw new BundleError("BUNDLE_INTEGRITY","Local preset resource changed while reading");return bytes.subarray(0,length)}finally{await handle.close()}}if(url2.protocol!=="https:"&&!(url2.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(url2.hostname)))throw new BundleError("BUNDLE_INVALID","Preset sources require HTTPS, local files or loopback HTTP");return network(source,options)}}function sourceUrl2(source){try{return new URL(source).href}catch{return pathToFileURL2(resolve12(source)).href}}function localHosts(allowStart=!1){let configured=process.env.MEARL_SOCKET_PATH?.trim(),hosts=configured?[{id:"local",socketPath:configured}]:listLiveBrowsers().filter(browser=>!browser.provider).map(browser=>({id:browser.browserId,socketPath:browser.socketPath}));return hosts.length?Array.from(new Map(hosts.map(host=>[host.socketPath,host])).values()):[{id:"local",...allowStart?{}:{socketPath:SOCKET_PATH}}]}async function runPresetCommand(command,source){let installer=new PresetInstaller;return command==="status"?installer.status():command==="update"?installer.update():installer.apply(source)}var PresetInstaller,init_preset2=__esm({"../setup/dist/preset.js"(){"use strict";init_local();init_dist2();init_bundles();init_presetStore();init_presetInstallationLease();init_presetStore();init_presetBrowserTransfer();PresetInstaller=class{store;options;constructor(options={}){this.options=options,this.store=new PresetInstallationStore(options)}invokeHost(action,data2,target,timeoutSec,allowStart=!1){return!this.options.invoke&&!target.socketPath&&!allowStart?Promise.reject(new Error("HOST_UNAVAILABLE")):(this.options.invoke??(target.socketPath?invoke:invokeLocalHost))(action,data2,{socketPath:target.socketPath,timeoutSec})}async hostStatus(reload,nodeRevision,installationRevision){let targets=this.options.hosts?.()??localHosts(reload);return Promise.all(targets.map(async target=>{try{let result=await this.invokeHost(reload?"node_capabilities_reload":"node_capabilities_status",reload?{structured:!0}:{},target,15,reload);return reload&&result?.accepted===!1?{id:target.id,state:"rejected",error:typeof result.error=="string"?result.error:"Node capability activation was rejected"}:{id:target.id,state:result?.revision===nodeRevision&&result?.installationRevision===installationRevision?"active":"pending"}}catch{return{id:target.id,state:"pending",error:"HOST_UNAVAILABLE"}}}))}async browserStatus(reload,browserRevision,installationRevision){let targets=this.options.hosts?.()??localHosts(reload);return Promise.all(targets.map(async target=>{try{let result=await this.invokeHost(reload?"preset_browser_sync":"preset_browser_status",reload?{installationRevision}:{},target,reload?130:15,reload);return result?.accepted===!1?{id:target.id,state:"rejected",settingsReady:!1,error:typeof result.error=="string"?result.error:"Browser preset activation rejected"}:{id:target.id,state:result?.ready===!0&&result?.browserRevision===browserRevision&&result?.installationRevision===installationRevision?"active":"pending",settingsReady:result?.settingsReady===!0,...Array.isArray(result?.permissionPending)&&result.permissionPending.length?{error:"PRESET_DOMAIN_PERMISSION_REQUIRED: Open extension settings and authorize preset domains"}:{}}}catch{return{id:target.id,state:"pending",settingsReady:!1,error:"BROWSER_UNAVAILABLE"}}}))}async componentStatus(install,receipt){let target=(this.options.hosts?.()??localHosts(install))[0];if(!target)return{};try{let result=await this.invokeHost(install?"preset_components_install":"preset_components_status",{installationRevision:receipt.revision},target,install?900:15,install);if(result?.installationRevision!==receipt.revision||result?.nodeRevision!==receipt.nodeRevision||!Array.isArray(result?.components))throw new Error("Component installation host requires an update");if(result.catalogReady!==void 0&&typeof result.catalogReady!="boolean")throw new Error("Invalid plugin catalog readiness");let seen=new Set;for(let entry of result.components){if(!entry||!["skills","providers"].includes(entry.kind)||typeof entry.id!="string"||!["ready","pending","conflict"].includes(entry.state)||entry.reason!==void 0&&typeof entry.reason!="string")throw new Error("Invalid component installation status");let key=`${entry.kind}:${entry.id}`;if(seen.has(key))throw new Error("Duplicate component installation status");seen.add(key)}return{status:result}}catch(error62){return{error:error62 instanceof Error?error62.message:String(error62)}}}async status(){let current2=await this.store.current(),result={revision:presetSelectionRevision(current2),ready:!1,hosts:[],browsers:[],pending:[],warnings:[]};if(!current2.receipt||!current2.prepared)return result;let{preset}=current2.prepared,receipt=current2.receipt;result.id=preset.id,result.version=preset.version,result.overrides=receipt.overrides,result.settings=mergePresetDefaults(preset.defaults,receipt.overrides),result.nodeRevision=receipt.nodeRevision,result.browserRevision=receipt.browserRevision,result.browserSyncRequired=receipt.browserSyncRequired===!0,result.localComponentCount=Object.values(preset.packages).filter(entry=>entry.enabled!==!1&&entry.runtimes?.includes("node")).length+[...Object.values(preset.skills),...Object.values(preset.providers)].filter(entry=>entry.enabled!==!1).length,result.hosts=await this.hostStatus(!1,receipt.nodeRevision,receipt.revision);let nodeReady=result.hosts.length>0&&result.hosts.every(host=>host.state==="active");receipt.browserSyncRequired&&(result.browsers=await this.browserStatus(!1,receipt.browserRevision,receipt.revision));let browserReady=result.browsers.length>0&&result.browsers.every(host=>host.state==="active");for(let[id2,entry]of Object.entries(preset.packages))if(entry.enabled!==!1)for(let runtime of entry.runtimes??[])runtime==="browser"?browserReady||result.pending.push({kind:"packages",id:id2,runtime,reason:"BROWSER_SYNC_REQUIRED"}):receipt.managedModules.includes(id2)?nodeReady||result.pending.push({kind:"packages",id:id2,runtime,reason:"HOST_SYNC_REQUIRED"}):result.pending.push({kind:"packages",id:id2,runtime,reason:"NODE_HOST_NOT_SUPPORTED"});let hasExternal=["skills","providers"].some(kind=>Object.values(preset[kind]).some(entry=>entry.enabled!==!1)),hasCatalog=!!current2.activation?.bindings["plugins.catalog"],components=hasExternal||hasCatalog?await this.componentStatus(!1,receipt):{};hasCatalog&&components.status?.catalogReady!==!0&&result.pending.push({kind:"preset",id:preset.id,runtime:"node",reason:"PLUGIN_CATALOG_SYNC_REQUIRED"}),components.error&&result.warnings.push(`Component readiness check failed: ${components.error}`);for(let kind of["skills","providers"])for(let[id2,entry]of Object.entries(preset[kind])){if(entry.enabled===!1)continue;let actual=components.status?.components.find(component2=>component2.kind===kind&&component2.id===id2);actual?.state!=="ready"&&result.pending.push({kind,id:id2,runtime:"node",reason:actual?.reason??"INSTALL_REQUIRED"})}return receipt.nodeSyncRequired&&!nodeReady&&!result.pending.some(entry=>entry.reason==="HOST_SYNC_REQUIRED")&&result.pending.push({kind:"preset",id:preset.id,runtime:"node",reason:"HOST_SYNC_REQUIRED"}),receipt.browserSyncRequired&&!browserReady&&!result.pending.some(entry=>entry.reason==="BROWSER_SYNC_REQUIRED")&&result.pending.push({kind:"preset",id:preset.id,runtime:"browser",reason:"BROWSER_SYNC_REQUIRED"}),receipt.browserSyncRequired&&browserReady&&Object.keys(result.settings??{}).length&&!result.browsers.every(host=>host.settingsReady)&&result.pending.push({kind:"preset",id:preset.id,runtime:"browser",reason:"SETTINGS_APPLY_REQUIRED"}),result.ready=result.pending.length===0,result}async synchronize(receipt,previousRevision){let rejection=(await this.hostStatus(!0,receipt.nodeRevision,receipt.revision)).find(host=>host.state==="rejected");if(rejection){if(previousRevision===receipt.revision)throw new Error(`Node activation rejected; installed selection retained: ${rejection.error}`);await this.store.rollback(receipt.revision);let previous=await this.store.current({verifyResources:!1});throw await this.hostStatus(!0,previous.activation?.revision??"",previous.activation?.installationRevision??""),new Error(`Node activation rejected; previous selection restored: ${rejection.error}`)}if(receipt.browserSyncRequired){let rejected=(await this.browserStatus(!0,receipt.browserRevision,receipt.revision)).find(host=>host.state==="rejected");if(rejected)throw new Error(`Browser activation rejected; installed selection retained for retry: ${rejected.error}`)}let installed=await this.store.current({verifyResources:!1});if(installed.receipt?.revision!==receipt.revision||!installed.preset)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed before component installation");let components=[...Object.values(installed.preset.skills),...Object.values(installed.preset.providers)].some(entry=>entry.enabled!==!1)||installed.activation?.bindings["plugins.catalog"]?await this.componentStatus(!0,receipt):{},status=await this.status();if(components.error&&status.warnings.push(`Component installation failed; completed assets retained for retry: ${components.error}`),status.revision!==receipt.revision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed while hosts were synchronizing");try{await this.store.collectGarbage()}catch(error62){status.warnings.push(`Preset resource cleanup failed: ${error62 instanceof Error?error62.message:String(error62)}`)}return status}async stageSource(source,expectedRevision,options){let prepared=await preparePreset(sourceUrl2(source),{mearlApiVersion:this.store.mearlApiVersion,load:this.options.load??createNodePresetLoader(),signal:options.signal});if(options.expectedId!==void 0&&prepared.preset.id!==options.expectedId)throw new BundleError("BUNDLE_INVALID","The preset identity differs from the accepted installation");let receipt=await this.store.apply(prepared,{...options,expectedRevision}),activated=!1;return{revision:receipt.revision,activate:async()=>{if(activated)throw new Error("Staged installation was already activated; use resume with its revision to retry");activated=!0;let current2=await this.store.current();if(current2.receipt?.revision!==receipt.revision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed before runtime setup completed");return this.synchronize(current2.receipt,expectedRevision)}}}async stage(source,options={}){let accepted={...options,...options.overrides===void 0?{}:{overrides:mergePresetDefaults({},options.overrides)},...options.nodeConfig===void 0?{}:{nodeConfig:mergePresetDefaults({},options.nodeConfig)}},current2=await this.store.current({verifyResources:!1}),revision2=presetSelectionRevision(current2);if(accepted.expectedRevision!==void 0&&accepted.expectedRevision!==revision2)throw new BundleError("BUNDLE_CONFLICT","The installed preset changed before preparation");return this.stageSource(source,revision2,accepted)}async apply(source,options={}){return(await this.stage(source,options)).activate()}async update(){let current2=await this.store.current({verifyResources:!1});if(!current2.receipt)throw new Error("No preset is installed");return this.apply(current2.receipt.snapshot.source,{expectedRevision:presetSelectionRevision(current2)})}async resume(expectedRevision){let current2=await this.store.current();if(!current2.receipt||current2.receipt.revision!==expectedRevision)throw new BundleError("BUNDLE_CONFLICT","The installed preset changed before resuming");return this.synchronize(current2.receipt,expectedRevision)}async configure(value){let current2=await this.store.current();if(!current2.prepared)throw new Error("No preset is installed");let receipt=await this.store.apply(current2.prepared,{expectedRevision:presetSelectionRevision(current2),overrides:value});return this.synchronize(receipt,presetSelectionRevision(current2))}}}});import{readFileSync as readFileSync16}from"node:fs";import{join as join26}from"node:path";function isLegacyPackage(installation){try{let manifest=JSON.parse(readFileSync16(join26(installation.packageRoot,"package.json"),"utf8"));return manifest.name===installation.packageName&&typeof manifest.version=="string"&&/^[0-2]\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(manifest.version)}catch{return!1}}async function prepareSetupPreset(options,dependencies={}){let env=options.env??process.env,installer=dependencies.installer??new PresetInstaller({directory:env.MEARL_CAPABILITY_DIR});if(options.source)return installer.stage(options.source);let current2=await installer.store.current();if(current2.receipt)return{revision:current2.receipt.revision,activate:()=>installer.resume(current2.receipt.revision)};if(current2.activation)return;let client2=options.installed===void 0?detectGlobalPackage("@mearl/client",["mearl"],{env}):null;if(!(options.installed??[...detectMearlProfiles({env}).values(),...client2?[client2]:[]]).some(isLegacyPackage))return;let config2=await(dependencies.configuration??(()=>{let url2=new URL(env.MEARL_INSTALLATION_CONFIG_URL||MEARL_INSTALLATION_CONFIG_URL);if(url2.protocol!=="https:"&&!(url2.protocol==="http:"&&["127.0.0.1","localhost","[::1]"].includes(url2.hostname)))throw new Error("Installation configuration requires HTTPS or loopback HTTP");return loadInstallationConfig(url2,url2.origin,AbortSignal.timeout(5e3))}))();if(!config2.legacyPreset)throw new Error("Legacy upgrade preset is unavailable. Retry when the installation catalog is available, or select a preset with --preset.");return installer.stage(config2.presets[config2.legacyPreset].source,{expectedRevision:null,expectedId:config2.legacyPreset})}var MEARL_INSTALLATION_CONFIG_URL,init_presetUpgrade=__esm({"../setup/dist/presetUpgrade.js"(){"use strict";init_installation();init_preset2();init_packageManager();init_profiles();MEARL_INSTALLATION_CONFIG_URL="https://f-loat.github.io/mearl/installation.json"}});import fs10 from"node:fs";import path12 from"node:path";import{createInterface as createInterface2}from"node:readline/promises";import{stdin as input,stdout as output}from"node:process";function autoUpdateClientInstallation(env){let root=env.MEARL_AUTO_UPDATE_CLIENT_ROOT;if(!root)return null;try{let packageRoot=fs10.realpathSync(root);return JSON.parse(fs10.readFileSync(path12.join(packageRoot,"package.json"),"utf8")).name!==UNIFIED_CLIENT?null:resolvePackageManagerInstallation(packageRoot,UNIFIED_CLIENT,{env})}catch{return null}}function autoUpdateProfiles(env){let value=env.MEARL_AUTO_UPDATE_PROFILES;if(value===void 0)return;let requested=value.split(",");if(requested.length===0||new Set(requested).size!==requested.length||requested.some(profile=>!PROFILE_ORDER.includes(profile)))throw new Error("Invalid automatic update profiles");return PROFILE_ORDER.filter(profile=>requested.includes(profile))}async function confirmInTerminal(message){if(!input.isTTY||!output.isTTY)return!1;let readline2=createInterface2({input,output});try{let answer=(await readline2.question(`${message} [y/N] `)).trim().toLowerCase();return answer==="y"||answer==="yes"}finally{readline2.close()}}function siblingExecutable(anchor2,name,existsSync14){for(let executableName of executableNames(name)){let candidate=path12.join(path12.dirname(anchor2),executableName);if(existsSync14(candidate))return candidate}return null}async function runLifecycleCommand(runner,command,args,env,label,writeLine,capture=!1){try{return await runner(command,args,{capture,env:prependCommandPath(command,env)})}catch(error62){return writeLine(`${label}: ${error62 instanceof Error?error62.message:String(error62)}`),null}}async function runPackageOperation(installation,operation,packages,targetLine,runner,env,label,writeLine){let command=buildGlobalPackageCommand(installation,operation,packages,targetLine);writeLine(`${label}: ${command.manager}`);let result=await runLifecycleCommand(runner,command.command,command.args,operation==="uninstall"?env:packages.reduce((childEnv,name)=>packageRegistryEnvironment(name,childEnv),env),label,writeLine);return result?result.code!==0?(writeLine(`${label}: failed (exit ${result.code}).`),{command,ok:!1}):{command,ok:!0}:{command,ok:!1}}async function runHook(profile,operation,detected,runner,existsSync14,env,writeLine,yes,cloudMode){let executable,args,hookEnv=env;if(profile==="local"&&operation!=="uninstall")executable=detected.executable,args=["--init","--mode","skills"];else if(profile==="mcp"&&operation==="uninstall")executable=siblingExecutable(detected.executable,"mearl-mcp-uninstall",existsSync14),args=["--managed-by-setup",...yes?["--yes"]:[]];else if(profile==="mcp"&&operation==="install")executable=siblingExecutable(detected.executable,"mearl-mcp-configure",existsSync14),args=["--global-install",...yes?["--yes"]:[]];else if(profile==="mcp"&&operation==="update")executable=siblingExecutable(detected.executable,"mearl-mcp-configure",existsSync14),args=["--skip-mcp","--global-install"];else if(profile==="cloud"){if(executable=siblingExecutable(detected.executable,"mearl-cloud-server",existsSync14),!executable)return writeLine(`Hook: ${profile} ${operation} command was not found.`),!1;let requestedMode=operation==="uninstall"?"websocket":cloudMode,commandEnv=requestedMode?{...env,MEARL_CLOUD_MODE:requestedMode}:env;if(hookEnv=commandEnv,operation==="uninstall")args=["stop"];else{let status=await runLifecycleCommand(runner,executable,["status"],commandEnv,"Hook: cloud status",writeLine,!0);if(!status)return!1;if(status.code!==0)return writeLine(`Hook: cloud status failed (exit ${status.code}).`),!1;let running=/\[CloudServer\]\s+Status:\s+running\b/.test(status.stdout),qoderMode=cloudMode==="qoder"||/\[CloudServer\]\s+Mode:\s+qoder\b/.test(status.stdout);if(operation==="update"&&!running&&!qoderMode)return writeLine("Hook: cloud update skipped because cloud-server is not running."),!0;args=[running&&!qoderMode?"restart":"start"]}}else return!0;if(!executable)return writeLine(`Hook: ${profile} ${operation} command was not found.`),!1;let result=await runLifecycleCommand(runner,executable,args,hookEnv,`Hook: ${profile} ${operation}`,writeLine);return result?result.code!==0?(writeLine(`Hook: ${profile} ${operation} failed (exit ${result.code}).`),!1):!0:!1}function selectedProfiles(operation,requested,detected){if(requested?.length){let requestedSet=new Set(requested);return PROFILE_ORDER.filter(profile=>requestedSet.has(profile))}return operation==="install"?["local"]:PROFILE_ORDER.filter(profile=>detected.has(profile))}function operationVerb(operation){return operation==="uninstall"?"uninstall":operation==="update"?"update":"install"}async function runMearlLifecycle(options,dependencies={}){if(options.targetLine&&!isMearlReleaseLine(options.targetLine))throw new Error("targetLine must be a valid Mearl release line such as 2.3.x");let env=options.env??process.env,writeLine=dependencies.writeLine??(line=>console.error(line)),existsSync14=dependencies.existsSync??fs10.existsSync,runner=dependencies.runCommand??runCommand,cleanupNativeHost=dependencies.cleanupNativeHost??uninstallNativeHostArtifacts,detectPackage=dependencies.detectPackage??detectGlobalPackage,detectProfiles=dependencies.detectProfiles??((childEnv,detectionOptions)=>detectMearlProfiles({env:childEnv,...detectionOptions})),resolveInvokingManager=dependencies.resolveInvokingManager??(childEnv=>resolveInvokingPackageManager({env:childEnv})),runSkill=dependencies.runSkillOperation??runGlobalMearlSkillOperation,confirm=dependencies.confirm??confirmInTerminal,detectionEnv=options.operation==="update"&&env.MEARL_AUTO_UPDATE_SEARCH_PATH!==void 0?{...env,PATH:env.MEARL_AUTO_UPDATE_SEARCH_PATH}:env,detected=options.operation==="uninstall"?detectProfiles(detectionEnv,{includeLinked:!0}):detectProfiles(detectionEnv),packageDetectionOptions={env,...options.operation==="uninstall"?{includeLinked:!0}:{}},requestedProfiles=options.profiles??(options.profile?[options.profile]:void 0)??(options.operation==="update"?autoUpdateProfiles(env):void 0),autoUpdateClient=options.operation==="update"?autoUpdateClientInstallation(env):null,clientOnly=options.operation==="update"&&env.MEARL_AUTO_UPDATE_CLIENT_ONLY==="1";if(clientOnly&&!autoUpdateClient)return writeLine("A valid global client installation is required for a client-only update."),!1;let selected=clientOnly?[]:selectedProfiles(options.operation,requestedProfiles,detected),lifecycleSelected=options.operation==="uninstall"?selected.filter(profile=>detected.has(profile)):selected,fullPluginNames=[],fullProviders=[];if(options.operation==="uninstall"&&options.full){try{fullPluginNames=(dependencies.listPlugins??listPluginNames)()}catch(error62){return writeLine(`CLI plugins: unable to list registrations: ${error62 instanceof Error?error62.message:String(error62)}`),!1}try{fullProviders=(dependencies.listProviders??listInstalledProviders)()}catch(error62){return writeLine(`Providers: unable to list registrations: ${error62 instanceof Error?error62.message:String(error62)}`),!1}}if(selected.length===0&&!autoUpdateClient&&!(options.operation==="uninstall"&&options.full))return writeLine("No installed Mearl environment was detected on the current PATH."),options.operation==="uninstall"?!0:(writeLine("Run: npx @mearl/setup"),!1);if(options.operation==="update"){let missing=selected.filter(profile=>!detected.has(profile));if(missing.length>0)return writeLine(`Not installed: ${missing.join(", ")}. Run the install command first.`),!1}if(options.operation==="uninstall"){if(lifecycleSelected.length===0&&!options.full)return writeLine(`Nothing to uninstall for ${selected.join(", ")}.`),!0;if(options.full&&(writeLine(`CLI plugins: ${fullPluginNames.length>0?fullPluginNames.join(", "):"none detected"}.`),writeLine(`Providers: ${fullProviders.length>0?fullProviders.map(provider=>provider.providerId).join(", "):"none detected"}.`)),!options.yes&&!await confirm(options.full?`Uninstall ${lifecycleSelected.length>0?`Mearl environments (${lifecycleSelected.join(", ")}) and `:""}all CLI plugins and Providers?`:`Uninstall Mearl environments: ${lifecycleSelected.join(", ")}?`))return writeLine("Uninstall cancelled."),!1}lifecycleSelected.length>0&&writeLine(`${operationVerb(options.operation)} targets: ${lifecycleSelected.map(profile=>MEARL_PROFILES[profile].label).join(", ")}`),autoUpdateClient&&lifecycleSelected.length===0&&writeLine("update targets: client CLI");let selectedUsesClient=autoUpdateClient!==null||lifecycleSelected.some(profile=>CLIENT_PROFILES.includes(profile)),detectedClientCandidate=selectedUsesClient&&!autoUpdateClient?detectPackage(UNIFIED_CLIENT,["mearl"],packageDetectionOptions):null,detectedClient=detectedClientCandidate?.packageName===UNIFIED_CLIENT?detectedClientCandidate:null,stagedPreset;if(options.operation!=="uninstall"&&(options.presetSource||!options.targetLine||Number(options.targetLine.split(".")[0])>=3)&&!dependencies.prepareSkills)try{stagedPreset=await(dependencies.preparePreset??prepareSetupPreset)({source:options.presetSource,env,installed:[...lifecycleSelected.flatMap(profile=>detected.get(profile)?[detected.get(profile)]:[]),...detectedClient?[detectedClient]:[],...autoUpdateClient&&env.MEARL_AUTO_UPDATE_CLIENT_ROOT?[{packageName:UNIFIED_CLIENT,packageRoot:env.MEARL_AUTO_UPDATE_CLIENT_ROOT}]:[]]})}catch(error62){return writeLine(`Preset preparation: ${error62 instanceof Error?error62.message:String(error62)}`),!1}let packagesOk=!0;if(lifecycleSelected.includes("cloud")){let legacyCloudClient=detectPackage(LEGACY_CLOUD_CLIENT,["mearl-cloud"],packageDetectionOptions);if(legacyCloudClient?.packageName===LEGACY_CLOUD_CLIENT){let command=buildGlobalPackageCommand(legacyCloudClient,"uninstall",[LEGACY_CLOUD_CLIENT]);writeLine(`Migration (cloud): removing ${LEGACY_CLOUD_CLIENT}.`);let result=await runLifecycleCommand(runner,command.command,command.args,env,"Migration (cloud)",writeLine);if(!result||result.code!==0)return result&&writeLine(`Migration (cloud): failed (exit ${result.code}).`),writeLine("Mearl setup incomplete. Review the messages above."),!1}}let remainingClientProfiles=selectedUsesClient&&options.operation==="uninstall"?CLIENT_PROFILES.filter(profile=>detected.has(profile)&&!lifecycleSelected.includes(profile)):[];if(selectedUsesClient&&options.operation!=="uninstall"){let clientInstallation=autoUpdateClient??detectedClient??detected.get("local")??detected.get("cloud")??resolveInvokingManager(env);if(!(await runPackageOperation(clientInstallation,options.operation,[UNIFIED_CLIENT],mearlPackageSelector(SETUP_VERSION,options.targetLine),runner,env,"Packages (shared client)",writeLine)).ok)return writeLine("Mearl setup incomplete. Review the messages above."),!1}for(let profile of lifecycleSelected){let config2=MEARL_PROFILES[profile],current2=detected.get(profile);if(options.operation==="uninstall"&&!current2)continue;let installation=current2??resolveInvokingManager(env);if(options.operation==="uninstall"&&profile==="local"){let keepsMcp=detected.has("mcp")&&!selected.includes("mcp"),cleanupOk=!1;try{cleanupOk=cleanupNativeHost({mode:keepsMcp?"skills":"both",silent:!0})}catch(error62){writeLine(`Native host: ${error62 instanceof Error?error62.message:String(error62)}`)}if(writeLine(`Native host: ${cleanupOk?"cleaned.":"cleanup failed."}`),!cleanupOk){packagesOk=!1;continue}}if(options.operation==="uninstall"&&!await runHook(profile,options.operation,current2,runner,existsSync14,env,writeLine,options.yes===!0,options.cloudMode)){packagesOk=!1;continue}let packageOperation=options.operation,packages=config2.packages.filter(packageName=>packageName!==UNIFIED_CLIENT);if(packages.length===0)continue;let packageResult=await runPackageOperation(installation,packageOperation,packages,mearlPackageSelector(SETUP_VERSION,options.targetLine),runner,env,`Packages (${profile})`,writeLine);if(!packageResult.ok){packagesOk=!1;continue}if(options.operation!=="uninstall"&&(profile==="local"||profile==="cloud"||profile==="mcp")){let refreshed=detectPackage(config2.anchorPackage,config2.anchorBins,{env:prependCommandPath(packageResult.command.command,env)})??current2;(!refreshed||!await runHook(profile,options.operation,refreshed,runner,existsSync14,env,writeLine,options.yes===!0,options.cloudMode))&&(packagesOk=!1)}}selectedUsesClient&&options.operation==="uninstall"&&(remainingClientProfiles.length>0?writeLine(`Packages (shared client): kept for ${remainingClientProfiles.join(", ")}.`):packagesOk&&detectedClient&&((await runPackageOperation(detectedClient,"uninstall",[UNIFIED_CLIENT],void 0,runner,env,"Packages (shared client)",writeLine)).ok||(packagesOk=!1)));let fullOk=!0;if(options.operation==="uninstall"&&options.full){let pendingPlugins=new Set(fullPluginNames),removePlugin=dependencies.uninstallPlugin??uninstallPlugin;for(;pendingPlugins.size>0;){let name=pendingPlugins.values().next().value;pendingPlugins.delete(name);try{let result=await removePlugin(name,runner);for(let removedName of result.unregisteredNames)pendingPlugins.delete(removedName);result.removed&&writeLine(`CLI plugin ${name}: uninstalled.`)}catch(error62){fullOk=!1,writeLine(`CLI plugin ${name}: ${error62 instanceof Error?error62.message:String(error62)}`)}}let removeProvider=dependencies.uninstallProvider??uninstallProviderPackage;for(let provider of fullProviders)try{await removeProvider(provider.providerId),writeLine(`Provider ${provider.providerId}: uninstalled.`)}catch(error62){fullOk=!1,writeLine(`Provider ${provider.providerId}: ${error62 instanceof Error?error62.message:String(error62)}`)}}if(packagesOk&&options.operation!=="uninstall"&&(stagedPreset||dependencies.prepareSkills))try{if(stagedPreset){let status=await stagedPreset.activate();dependencies.onPresetStatus?.(status)}else await dependencies.prepareSkills()}catch(error62){writeLine(`Skill preparation: ${error62 instanceof Error?error62.message:String(error62)}`),packagesOk=!1}let selectedUsesSkill=lifecycleSelected.some(profile=>MEARL_PROFILES[profile].usesSkill),remainingSkillProfiles=["local","cloud"].filter(profile=>detected.has(profile)&&!lifecycleSelected.includes(profile)),runStandaloneSkill=!0,skillOk=!0;if(packagesOk&&selectedUsesSkill&&selectedUsesClient&&options.skipSkill!==!0&&(options.operation==="uninstall"&&remainingSkillProfiles.length===0||options.operation!=="uninstall"&&options.targetLine===void 0))try{if(options.operation==="uninstall"){let result=await(dependencies.uninstallManagedPlugins??uninstallManagedPlugins)({env,includeMearlSkill:!0,runCommand:runner,writeLine});result==="uninstalled"?runStandaloneSkill=!1:result==="failed"&&(runStandaloneSkill=!1,skillOk=!1)}else{let result=await(dependencies.installManagedPlugins??installManagedPlugins)({env,includeMearlSkill:!0,mearlSkillOperation:options.operation,runCommand:runner,writeLine});result==="installed"?runStandaloneSkill=!1:result==="failed"&&(runStandaloneSkill=!1,skillOk=!1)}}catch(error62){writeLine(`Managed plugin batch: ${error62 instanceof Error?error62.message:String(error62)}; failed.`),runStandaloneSkill=!1,skillOk=!1}if(packagesOk&&skillOk&&selectedUsesSkill&&options.skipSkill!==!0)try{options.operation==="uninstall"?remainingSkillProfiles.length>0?(writeLine(`Skill: kept for ${remainingSkillProfiles.join(", ")}.`),writeLine(`Managed plugins: kept for ${remainingSkillProfiles.join(", ")}.`)):runStandaloneSkill&&(skillOk=await runSkill("uninstall",{env,yes:options.yes,writeLine,runCommand:runner})):runStandaloneSkill&&(skillOk=await runSkill(options.operation,{env,yes:options.yes,writeLine,runCommand:runner}))}catch(error62){writeLine(`Skill: ${error62 instanceof Error?error62.message:String(error62)}`),skillOk=!1}if(packagesOk&&skillOk&&fullOk){if(options.operation==="uninstall"&&options.full&&PROFILE_ORDER.every(profile=>!detected.has(profile)||lifecycleSelected.includes(profile)))try{await(dependencies.cleanupRuntime??cleanupUninstalledRuntime)(),writeLine("Runtime caches: cleaned; user data and browser profiles were retained.")}catch(error62){return writeLine(`Runtime caches: ${error62 instanceof Error?error62.message:String(error62)}`),!1}return writeLine("Mearl setup complete."),!0}return writeLine("Mearl setup incomplete. Review the messages above."),!1}var LEGACY_CLOUD_CLIENT,UNIFIED_CLIENT,PROFILE_ORDER,CLIENT_PROFILES,init_lifecycle=__esm({"../setup/dist/lifecycle.js"(){"use strict";init_setupVersion();init_plugin2();init_host();init_skills();init_packageManager();init_profiles();init_nativeHost2();init_dist();init_version();init_managedPlugins();init_plugin3();init_provider();init_npmRegistry();init_runtimeCleanup();init_presetUpgrade();LEGACY_CLOUD_CLIENT="@mearl/cloud-client",UNIFIED_CLIENT="@mearl/client",PROFILE_ORDER=["local","cloud","mcp"],CLIENT_PROFILES=["local","cloud"]}});var dist_exports4={};__export(dist_exports4,{BrowserExtensionConflictError:()=>BrowserExtensionConflictError,MEARL_EXTENSION_DIRECTORY_NAME:()=>MEARL_EXTENSION_DIRECTORY_NAME,MEARL_EXTENSION_DOWNLOAD_PAGE:()=>MEARL_EXTENSION_DOWNLOAD_PAGE,MEARL_EXTENSION_ID:()=>MEARL_EXTENSION_ID,MEARL_EXTENSION_REMOTE_CONFIG_URL:()=>MEARL_EXTENSION_REMOTE_CONFIG_URL,MEARL_NATIVE_HOST_NAMES:()=>MEARL_NATIVE_HOST_NAMES,MEARL_PROFILES:()=>MEARL_PROFILES,PresetInstallationStore:()=>PresetInstallationStore,PresetInstaller:()=>PresetInstaller,buildGlobalPackageCommand:()=>buildGlobalPackageCommand,compareMearlReleaseLines:()=>compareMearlReleaseLines,compareMearlReleaseVersions:()=>compareMearlReleaseVersions,createNodePresetLoader:()=>createNodePresetLoader,detectGlobalPackage:()=>detectGlobalPackage,detectMearlProfiles:()=>detectMearlProfiles,extensionArchiveUrl:()=>extensionArchiveUrl,fetchBrowserExtensionRelease:()=>fetchBrowserExtensionRelease,findLatestExtensionVersion:()=>findLatestExtensionVersion,inspectMearlExtensionViaCdp:()=>inspectMearlExtensionViaCdp,inspectProviderPackage:()=>inspectProviderPackage,installMearlBrowserExtension:()=>installMearlBrowserExtension,installProviderPackage:()=>installProviderPackage,isMearlReleaseLine:()=>isMearlReleaseLine,isMearlReleaseVersion:()=>isMearlReleaseVersion,isMearlReleaseVersionInLine:()=>isMearlReleaseVersionInLine,loadUnpackedViaCdp:()=>loadUnpackedViaCdp,mearlReleaseLineForVersion:()=>mearlReleaseLineForVersion,parseMearlReleaseLine:()=>parseMearlReleaseLine,parseMearlReleaseVersion:()=>parseMearlReleaseVersion,parseProviderPackageSpec:()=>parseProviderPackageSpec,resolveChromeUserDataDirectory:()=>resolveChromeUserDataDirectory,resolveInvokingPackageManager:()=>resolveInvokingPackageManager,resolveMearlExtensionDirectory:()=>resolveMearlExtensionDirectory,resolveNativeHostDirectory:()=>resolveNativeHostDirectory,resolvePackageManagerInstallation:()=>resolvePackageManagerInstallation,runMearlLifecycle:()=>runMearlLifecycle,runPresetCommand:()=>runPresetCommand,uninstallNativeHostArtifacts:()=>uninstallNativeHostArtifacts,uninstallProviderPackage:()=>uninstallProviderPackage,updateProviderPackage:()=>updateProviderPackage,updateSetupManagedBrowserExtensionFiles:()=>updateSetupManagedBrowserExtensionFiles});var init_dist7=__esm({"../setup/dist/index.js"(){"use strict";init_packageManager();init_browserExtension();init_lifecycle();init_profiles();init_nativeHost2();init_preset2();init_version();init_provider()}});function initBrowserRegistry(deps){logFn=deps.log}function recordFileFor(browserId){return keyedConfigFile(BROWSERS_SUBDIR2,browserId)}function persist(patch){if(!identity)return!1;let file2=recordFileFor(identity.browserId),previous=readRecord(file2);if(previous&&previous.pid!==process.pid&&isAlive(previous.pid))return!1;let record5={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{return previous?.pid===process.pid?writeRecordIfPid(file2,process.pid,record5):previous&&!removeRecordIfPid(file2,previous.pid)?!1:claimRecord(file2,record5)}catch(error62){return logFn("browser-registry: failed to write record:",String(error62)),!1}}async function retireUnreachableBrowserRecord(browserId,canConnect){let file2=recordFileFor(browserId),existing=readRecord(file2);return!existing||existing.pid===process.pid||!isAlive(existing.pid)||await canConnect(existing.socketPath)?!1:removeRecordIfPid(file2,existing.pid)}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)),registered=persist({lastFocusedAt:info.preserveFocus===!1?info.lastFocusedAt??0:previous?.lastFocusedAt??info.lastFocusedAt??Date.now(),extensionVersion:info.extensionVersion});return logFn(`browser-registry: ${registered?"registered":"registration skipped"} ${info.browserName} (${info.browserId})`),registered}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);removeRecordIfPid(file2,process.pid)}function pruneDeadBrowsers(){let now=Date.now();for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR2))){let rec=readRecord(file2);if(!rec){removeInvalidRecord(file2);continue}isAlive(rec.pid)||now-(rec.updatedAt??0)>STALE_RECORD_TTL_MS&&removeRecordIfPid(file2,rec.pid)}}function listRegisteredBrowsers(){let records=[];for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR2))){let record5=readRecord(file2);record5&&isAlive(record5.pid)&&records.push(record5)}return records.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0)||(b.updatedAt??0)-(a.updatedAt??0))}var BROWSERS_SUBDIR2,STALE_RECORD_TTL_MS,FOCUS_WRITE_THROTTLE_MS,identity,logFn,lastFocusWriteAt,focusFlushTimer,init_browser_registry=__esm({"src/browser-registry.ts"(){"use strict";init_dist();BROWSERS_SUBDIR2="browsers",STALE_RECORD_TTL_MS=5*6e4,FOCUS_WRITE_THROTTLE_MS=1e3,identity=null,logFn=()=>{};lastFocusWriteAt=0,focusFlushTimer=null}});import{StringDecoder as StringDecoder3}from"node:string_decoder";var Utf8LineBuffer,init_socketLines=__esm({"src/socketLines.ts"(){"use strict";Utf8LineBuffer=class{constructor(maxBufferBytes){this.maxBufferBytes=maxBufferBytes}maxBufferBytes;buffer="";decoder=new StringDecoder3("utf8");push(chunk){if(this.buffer+=this.decoder.write(chunk),Buffer.byteLength(this.buffer,"utf8")>this.maxBufferBytes)return this.buffer="",{lines:[],overflow:!0};let lines=[],newlineIndex;for(;(newlineIndex=this.buffer.indexOf(`
1108
+ Open in Mearl toolbox.`:""}`)}return verifySkill(!0),0}var registrationContext,init_plugin3=__esm({"../setup/dist/plugin.js"(){"use strict";init_plugin2();init_skillSources();init_presetInstallationLease();init_pluginRuntime();init_skills();init_dist();registrationContext={options:{},invoke:async()=>{throw new Error("注册时不能执行浏览器操作")},progress:()=>{throw new Error("注册时不能报告执行进度")}}}});async function installManagedPlugins(options={},dependencies={}){let writeLine=options.writeLine??(line=>console.error(line));try{let catalog=(dependencies.readCatalog??readOfficialPluginCatalog)();if(!catalog||Object.keys(catalog.plugins).length===0)return"skipped";let registrationFor=dependencies.findPluginRegistration??findPluginRegistration,candidates=Object.entries(catalog.plugins).filter(([name])=>{let registration=registrationFor(name);return registration&&registration.managedBy!==OFFICIAL_PLUGIN_MANAGER?(writeLine(`${name} plugin: existing user registration kept.`),!1):!0});if(candidates.length===0)return"skipped";if(options.includeMearlSkill&&!await(dependencies.runSkillOperation??runGlobalMearlSkillOperation)(options.mearlSkillOperation??"install",{env:options.env,runCommand:options.runCommand,writeLine,yes:!0}))return"failed";for(let[name,definition]of candidates){let code=await(dependencies.installPlugins??installPlugins)([...definition.installArgs],options.runCommand??runCommand,{registrationManagedBy:OFFICIAL_PLUGIN_MANAGER,env:options.env});if(code!==0)return writeLine(`${name} plugin: install failed (exit ${code}).`),"failed";if(registrationFor(name)?.managedBy!==OFFICIAL_PLUGIN_MANAGER)return writeLine(`${name} plugin: installation did not create its managed registration.`),"failed";writeLine(`${name} plugin: installed and registered.`)}return"installed"}catch(error62){return writeLine(`Managed plugin batch: ${error62 instanceof Error?error62.message:String(error62)}; failed.`),"failed"}}async function uninstallManagedPlugins(options={},dependencies={}){let writeLine=options.writeLine??(line=>console.error(line));try{let catalog=(dependencies.readCatalog??readOfficialPluginCatalog)();if(!catalog)return"skipped";let registrationFor=dependencies.findPluginRegistration??findPluginRegistration;for(let name of Object.keys(catalog.plugins)){let registration=registrationFor(name);if(registration){if(registration.managedBy!==OFFICIAL_PLUGIN_MANAGER){writeLine(`${name} plugin: existing user registration kept.`);continue}if(await(dependencies.uninstallPlugin??uninstallPlugin)(name,options.runCommand??runCommand,{preserveRegistrationsOutsideManager:OFFICIAL_PLUGIN_MANAGER,env:options.env}),registrationFor(name))return writeLine(`${name} plugin: uninstall did not clear its registration.`),"failed";writeLine(`${name} plugin: uninstalled.`)}}return options.includeMearlSkill&&!await(dependencies.runSkillOperation??runGlobalMearlSkillOperation)("uninstall",{env:options.env,runCommand:options.runCommand,writeLine,yes:!0})?"failed":"uninstalled"}catch(error62){return writeLine(`Managed plugin batch: ${error62 instanceof Error?error62.message:String(error62)}; failed.`),"failed"}}var init_managedPlugins=__esm({"../setup/dist/managedPlugins.js"(){"use strict";init_plugin2();init_plugin3();init_skills();init_dist()}});import{existsSync as existsSync11,readFileSync as readFileSync15,statSync as statSync13}from"node:fs";import{join as join24,resolve as resolve10}from"node:path";function inspectProviderPackage(manifest){if(validateInstalledProviderManifest(manifest))return!1;try{let file2=join24(manifest.packageRoot,"package.json"),stat5=statSync13(file2);if(!stat5.isFile()||stat5.size>1024*1024)return!1;let metadata=JSON.parse(readFileSync15(file2,"utf8")),provider=metadata.mearl?.provider;return metadata.name===manifest.packageName&&metadata.version===manifest.version&&provider?.providerId===manifest.providerId&&provider.protocolVersion===manifest.protocolVersion&&typeof provider.entry=="string"&&resolve10(manifest.packageRoot,provider.entry)===manifest.entryPath}catch{return!1}}async function stopProviderBeforePackageChange(providerId){if(readProviderStart(providerId))throw new Error(`Provider ${providerId} is still starting`);let live=readLiveProvider(providerId);if(!live)return;let owner={pid:live.pid,processIdentity:processIdentity(live.pid)};stopProvider(providerId);let deadline=Date.now()+5e3;for(;isProcessOwnerAlive(owner);){if(Date.now()>=deadline)throw new Error(`Provider ${providerId} did not finish stopping`);await new Promise(resolve16=>setTimeout(resolve16,50))}if(readLiveProvider(providerId)||readProviderStart(providerId))throw new Error(`Provider ${providerId} restarted during shutdown`)}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(output3){return output3.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=>join24(value,"node_modules");break;case"bun":args=["pm","bin","-g"],toNodeModules=value=>resolve10(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 join24(toNodeModules(root),...packageName.split("/"))}function findRegisteredProvider(selector,listProviders){let matches=listProviders().filter(provider=>provider.providerId===selector||provider.packageName===selector);if(matches.length===0)throw new Error(`Provider is not registered: ${selector}`);if(matches.length>1)throw new Error(`Provider selector is ambiguous: ${selector}`);return matches[0]}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),previous=(dependencies.listProviders??listInstalledProviders)().filter(provider=>provider.packageName===packageName);for(let provider of previous)await(dependencies.stopProvider??stopProviderBeforePackageChange)(provider.providerId);await runPackageCommand(installation,"install",packageName,target,runner,env);let packageRoot=await(dependencies.resolvePackageRoot??resolveGlobalProviderPackageRoot)(installation,packageName,runner,env);if(!(dependencies.existsSync??existsSync11)(join24(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}}async function updateProviderPackage(selector,dependencies={}){let listProviders=dependencies.listProviders??listInstalledProviders,current2=findRegisteredProvider(selector,listProviders),env=process.env,runner=dependencies.runCommand??runCommand,detectedManager=(dependencies.resolvePackageManager??resolvePackageManagerInstallation)(current2.packageRoot,current2.packageName)??void 0,installation=providerManager(env,dependencies,detectedManager);return await(dependencies.stopProvider??stopProviderBeforePackageChange)(current2.providerId),await runPackageCommand(installation,"update",current2.packageName,"latest",runner,env),{manifest:(dependencies.registerPackage??registerProviderPackage)(current2.packageRoot),manager:installation.manager}}async function uninstallProviderPackage(selector,dependencies={}){let listProviders=dependencies.listProviders??listInstalledProviders,manifest=findRegisteredProvider(selector,listProviders),env=process.env,installation=(dependencies.resolvePackageManager??resolvePackageManagerInstallation)(manifest.packageRoot,manifest.packageName)??providerManager(env,dependencies);return await(dependencies.stopProvider??stopProviderBeforePackageChange)(manifest.providerId),await runPackageCommand(installation,"uninstall",manifest.packageName,"latest",dependencies.runCommand??runCommand,env),(dependencies.unregisterProvider??uninstallProvider)(manifest.providerId),{manifest,manager:installation.manager}}var init_provider=__esm({"../setup/dist/provider.js"(){"use strict";init_host();init_packageManager();init_npmRegistry();init_dist()}});import{readdirSync as readdirSync9}from"node:fs";import{basename as basename5,join as join25,resolve as resolve11}from"node:path";import{homedir as homedir10}from"node:os";async function cleanupUninstalledRuntime(){await cleanupPluginRuntime();let root=join25(homedir10(),".mearl");if(resolve11(pluginDirectory())!==resolve11(join25(root,"plugins")))return;if(listRecordFiles(join25(root,"providers/installed")).length)throw new Error("Registered Providers still use runtime caches; caches were retained");for(let directory of["providers/live","providers/starting"])if(listRecordFiles(join25(root,directory)).some(file2=>{let record5=readRecord(file2);return record5&&isProcessOwnerAlive(record5)}))throw new Error("Providers still use runtime caches; caches were retained");pruneOrphanLogs(join25(root,"managed-browsers"),0),pruneOrphanLogs(join25(root,"providers/logs"),0);let entries;try{entries=readdirSync9(join25(root,"plugin-pages"),{withFileTypes:!0})}catch(error62){if(error62.code==="ENOENT")return;throw error62}for(let entry of entries)if(!(!entry.isDirectory()||!/^[a-f0-9]{16}\.json\.d$/.test(entry.name)))for(let file2 of listRecordFiles(join25(root,"plugin-pages",entry.name))){if(!/^session-[a-f0-9]{16}\.json$/.test(basename5(file2)))continue;let record5=readRecord(file2);record5&&!isProcessOwnerAlive(record5)&&removeRecordIfPid(file2,record5.pid)}}var init_runtimeCleanup=__esm({"../setup/dist/runtimeCleanup.js"(){"use strict";init_plugin2();init_dist()}});import{createHash as createHash14,randomUUID as randomUUID17}from"node:crypto";var digest3,PresetBrowserTransfer,init_presetBrowserTransfer=__esm({"../setup/dist/presetBrowserTransfer.js"(){"use strict";init_bundles();init_presetStore();digest3=bytes=>createHash14("sha256").update(bytes).digest("hex"),PresetBrowserTransfer=class{store;now;session;constructor(store=new PresetInstallationStore,now=Date.now){this.store=store,this.now=now}async selectedRevision(acceptedNodeRevision){let current2=await this.store.current({verifyResources:!1});return current2.receipt?.browserSyncRequired&&current2.receipt.revision===acceptedNodeRevision?current2.receipt.revision:null}async handle(input3){if(!input3||typeof input3!="object")throw new BundleError("BUNDLE_INVALID","Expected a browser transfer operation");if(this.session&&this.now()-this.session.touched>12e4&&(this.session=void 0),input3.operation==="open"){if(this.session)throw new BundleError("BUNDLE_CONFLICT","A browser preset transfer is already running");if(typeof input3.installationRevision!="string"||!/^[a-f0-9]{64}$/.test(input3.installationRevision))throw new BundleError("BUNDLE_INVALID","Expected an installation revision");let current2=await this.store.current();if(!current2.receipt||!current2.prepared||current2.receipt.revision!==input3.installationRevision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed before browser transfer");let header={schemaVersion:1,installationRevision:current2.receipt.revision,snapshot:current2.prepared.browser.snapshot,bundles:current2.prepared.browser.bundles.map(({source,revision:revision2,manifest})=>({source,revision:revision2,manifest})),overrides:current2.receipt.overrides},bytes=Buffer.from(JSON.stringify(header));if(bytes.byteLength>MAX_PRESET_TRANSFER_HEADER_BYTES)throw new BundleError("BUNDLE_QUOTA","Browser transfer metadata exceeds 16 MiB");let sha2562=digest3(bytes),resources=new Map([[sha2562,bytes]]);for(let bundle of current2.prepared.browser.bundles)for(let[name,entry]of Object.entries(bundle.manifest.resources))resources.set(entry.sha256,bundle.resources[name]);if(this.session)throw new BundleError("BUNDLE_CONFLICT","A browser preset transfer is already running");return this.session={id:randomUUID17(),revision:current2.receipt.revision,touched:this.now(),resources},{session:this.session.id,sha256:sha2562,byteLength:bytes.byteLength}}let session=this.session;if(!session||input3.session!==session.id)throw new BundleError("BUNDLE_CONFLICT","Browser preset transfer expired or changed");if(session.touched=this.now(),input3.operation==="release")return this.session=void 0,{released:!0};if(input3.operation==="confirm"){if((await this.store.current({verifyResources:!1})).receipt?.revision!==session.revision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed during browser transfer");return{installationRevision:session.revision}}if(input3.operation==="read"){let bytes=session.resources.get(input3.sha256);if(!bytes||!Number.isSafeInteger(input3.offset)||input3.offset<0||input3.offset>=bytes.byteLength||input3.offset%PRESET_TRANSFER_CHUNK_BYTES!==0)throw new BundleError("BUNDLE_INVALID","Invalid browser transfer resource or offset");return{data:Buffer.from(bytes.subarray(input3.offset,input3.offset+PRESET_TRANSFER_CHUNK_BYTES)).toString("base64")}}throw new BundleError("BUNDLE_INVALID","Unsupported browser preset transfer operation")}}}});import{lstat as lstat2,open as open3}from"node:fs/promises";import{constants as constants5}from"node:fs";import{resolve as resolve12}from"node:path";import{fileURLToPath as fileURLToPath3,pathToFileURL as pathToFileURL2}from"node:url";function createNodePresetLoader(){let network=createBundleFetchLoader();return async(source,options)=>{let url2=new URL(source);if(url2.protocol==="file:"){options.signal?.throwIfAborted();let file2=fileURLToPath3(url2),before=await lstat2(file2);if(!before.isFile()||before.isSymbolicLink()||before.size>options.maxBytes)throw new BundleError("BUNDLE_QUOTA","Invalid local preset resource file or size");let handle=await open3(file2,constants5.O_RDONLY|(constants5.O_NOFOLLOW??0));try{let stat5=await handle.stat();if(!stat5.isFile()||stat5.size>options.maxBytes)throw new BundleError("BUNDLE_QUOTA","Local preset resource exceeds its size limit");let bytes=Buffer.alloc(stat5.size+1),length=0;for(;length<bytes.byteLength;){options.signal?.throwIfAborted();let result=await handle.read(bytes,length,bytes.byteLength-length,null);if(!result.bytesRead)break;length+=result.bytesRead}if(length>stat5.size)throw new BundleError("BUNDLE_INTEGRITY","Local preset resource changed while reading");return bytes.subarray(0,length)}finally{await handle.close()}}if(url2.protocol!=="https:"&&!(url2.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(url2.hostname)))throw new BundleError("BUNDLE_INVALID","Preset sources require HTTPS, local files or loopback HTTP");return network(source,options)}}function sourceUrl2(source){try{return new URL(source).href}catch{return pathToFileURL2(resolve12(source)).href}}function localHosts(allowStart=!1){let configured=process.env.MEARL_SOCKET_PATH?.trim(),hosts=configured?[{id:"local",socketPath:configured}]:listLiveBrowsers().filter(browser=>!browser.provider).map(browser=>({id:browser.browserId,socketPath:browser.socketPath}));return hosts.length?Array.from(new Map(hosts.map(host=>[host.socketPath,host])).values()):[{id:"local",...allowStart?{}:{socketPath:SOCKET_PATH}}]}async function runPresetCommand(command,source){let installer=new PresetInstaller;return command==="status"?installer.status():command==="update"?installer.update():installer.apply(source)}var PresetInstaller,init_preset2=__esm({"../setup/dist/preset.js"(){"use strict";init_local();init_dist2();init_bundles();init_presetStore();init_presetInstallationLease();init_presetStore();init_presetBrowserTransfer();PresetInstaller=class{store;options;constructor(options={}){this.options=options,this.store=new PresetInstallationStore(options)}invokeHost(action,data2,target,timeoutSec,allowStart=!1){return!this.options.invoke&&!target.socketPath&&!allowStart?Promise.reject(new Error("HOST_UNAVAILABLE")):(this.options.invoke??(target.socketPath?invoke:invokeLocalHost))(action,data2,{socketPath:target.socketPath,timeoutSec})}async hostStatus(reload,nodeRevision,installationRevision){let targets=this.options.hosts?.()??localHosts(reload);return Promise.all(targets.map(async target=>{try{let result=await this.invokeHost(reload?"node_capabilities_reload":"node_capabilities_status",reload?{structured:!0}:{},target,15,reload);return reload&&result?.accepted===!1?{id:target.id,state:"rejected",error:typeof result.error=="string"?result.error:"Node capability activation was rejected"}:{id:target.id,state:result?.revision===nodeRevision&&result?.installationRevision===installationRevision?"active":"pending"}}catch{return{id:target.id,state:"pending",error:"HOST_UNAVAILABLE"}}}))}async browserStatus(reload,browserRevision,installationRevision){let targets=this.options.hosts?.()??localHosts(reload);return Promise.all(targets.map(async target=>{try{let result=await this.invokeHost(reload?"preset_browser_sync":"preset_browser_status",reload?{installationRevision}:{},target,reload?130:15,reload);return result?.accepted===!1?{id:target.id,state:"rejected",settingsReady:!1,error:typeof result.error=="string"?result.error:"Browser preset activation rejected"}:{id:target.id,state:result?.ready===!0&&result?.browserRevision===browserRevision&&result?.installationRevision===installationRevision?"active":"pending",settingsReady:result?.settingsReady===!0,...Array.isArray(result?.permissionPending)&&result.permissionPending.length?{error:"PRESET_DOMAIN_PERMISSION_REQUIRED: Open extension settings and authorize preset domains"}:{}}}catch{return{id:target.id,state:"pending",settingsReady:!1,error:"BROWSER_UNAVAILABLE"}}}))}async componentStatus(install,receipt){let target=(this.options.hosts?.()??localHosts(install))[0];if(!target)return{};try{let result=await this.invokeHost(install?"preset_components_install":"preset_components_status",{installationRevision:receipt.revision},target,install?900:15,install);if(result?.installationRevision!==receipt.revision||result?.nodeRevision!==receipt.nodeRevision||!Array.isArray(result?.components))throw new Error("Component installation host requires an update");if(result.catalogReady!==void 0&&typeof result.catalogReady!="boolean")throw new Error("Invalid plugin catalog readiness");let seen=new Set;for(let entry of result.components){if(!entry||!["skills","providers"].includes(entry.kind)||typeof entry.id!="string"||!["ready","pending","conflict"].includes(entry.state)||entry.reason!==void 0&&typeof entry.reason!="string")throw new Error("Invalid component installation status");let key=`${entry.kind}:${entry.id}`;if(seen.has(key))throw new Error("Duplicate component installation status");seen.add(key)}return{status:result}}catch(error62){return{error:error62 instanceof Error?error62.message:String(error62)}}}async status(){let current2=await this.store.current(),result={revision:presetSelectionRevision(current2),ready:!1,hosts:[],browsers:[],pending:[],warnings:[]};if(!current2.receipt||!current2.prepared)return result;let{preset}=current2.prepared,receipt=current2.receipt;result.id=preset.id,result.version=preset.version,result.overrides=receipt.overrides,result.settings=mergePresetDefaults(preset.defaults,receipt.overrides),result.nodeRevision=receipt.nodeRevision,result.browserRevision=receipt.browserRevision,result.browserSyncRequired=receipt.browserSyncRequired===!0,result.localComponentCount=Object.values(preset.packages).filter(entry=>entry.enabled!==!1&&entry.runtimes?.includes("node")).length+[...Object.values(preset.skills),...Object.values(preset.providers)].filter(entry=>entry.enabled!==!1).length,result.hosts=await this.hostStatus(!1,receipt.nodeRevision,receipt.revision);let nodeReady=result.hosts.length>0&&result.hosts.every(host=>host.state==="active");receipt.browserSyncRequired&&(result.browsers=await this.browserStatus(!1,receipt.browserRevision,receipt.revision));let browserReady=result.browsers.length>0&&result.browsers.every(host=>host.state==="active");for(let[id2,entry]of Object.entries(preset.packages))if(entry.enabled!==!1)for(let runtime of entry.runtimes??[])runtime==="browser"?browserReady||result.pending.push({kind:"packages",id:id2,runtime,reason:"BROWSER_SYNC_REQUIRED"}):receipt.managedModules.includes(id2)?nodeReady||result.pending.push({kind:"packages",id:id2,runtime,reason:"HOST_SYNC_REQUIRED"}):result.pending.push({kind:"packages",id:id2,runtime,reason:"NODE_HOST_NOT_SUPPORTED"});let hasExternal=["skills","providers"].some(kind=>Object.values(preset[kind]).some(entry=>entry.enabled!==!1)),hasCatalog=!!current2.activation?.bindings["plugins.catalog"],components=hasExternal||hasCatalog?await this.componentStatus(!1,receipt):{};hasCatalog&&components.status?.catalogReady!==!0&&result.pending.push({kind:"preset",id:preset.id,runtime:"node",reason:"PLUGIN_CATALOG_SYNC_REQUIRED"}),components.error&&result.warnings.push(`Component readiness check failed: ${components.error}`);for(let kind of["skills","providers"])for(let[id2,entry]of Object.entries(preset[kind])){if(entry.enabled===!1)continue;let actual=components.status?.components.find(component2=>component2.kind===kind&&component2.id===id2);actual?.state!=="ready"&&result.pending.push({kind,id:id2,runtime:"node",reason:actual?.reason??"INSTALL_REQUIRED"})}return receipt.nodeSyncRequired&&!nodeReady&&!result.pending.some(entry=>entry.reason==="HOST_SYNC_REQUIRED")&&result.pending.push({kind:"preset",id:preset.id,runtime:"node",reason:"HOST_SYNC_REQUIRED"}),receipt.browserSyncRequired&&!browserReady&&!result.pending.some(entry=>entry.reason==="BROWSER_SYNC_REQUIRED")&&result.pending.push({kind:"preset",id:preset.id,runtime:"browser",reason:"BROWSER_SYNC_REQUIRED"}),receipt.browserSyncRequired&&browserReady&&Object.keys(result.settings??{}).length&&!result.browsers.every(host=>host.settingsReady)&&result.pending.push({kind:"preset",id:preset.id,runtime:"browser",reason:"SETTINGS_APPLY_REQUIRED"}),result.ready=result.pending.length===0,result}async synchronize(receipt,previousRevision){let rejection=(await this.hostStatus(!0,receipt.nodeRevision,receipt.revision)).find(host=>host.state==="rejected");if(rejection){if(previousRevision===receipt.revision)throw new Error(`Node activation rejected; installed selection retained: ${rejection.error}`);await this.store.rollback(receipt.revision);let previous=await this.store.current({verifyResources:!1});throw await this.hostStatus(!0,previous.activation?.revision??"",previous.activation?.installationRevision??""),new Error(`Node activation rejected; previous selection restored: ${rejection.error}`)}if(receipt.browserSyncRequired){let rejected=(await this.browserStatus(!0,receipt.browserRevision,receipt.revision)).find(host=>host.state==="rejected");if(rejected)throw new Error(`Browser activation rejected; installed selection retained for retry: ${rejected.error}`)}let installed=await this.store.current({verifyResources:!1});if(installed.receipt?.revision!==receipt.revision||!installed.preset)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed before component installation");let components=[...Object.values(installed.preset.skills),...Object.values(installed.preset.providers)].some(entry=>entry.enabled!==!1)||installed.activation?.bindings["plugins.catalog"]?await this.componentStatus(!0,receipt):{},status=await this.status();if(components.error&&status.warnings.push(`Component installation failed; completed assets retained for retry: ${components.error}`),status.revision!==receipt.revision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed while hosts were synchronizing");try{await this.store.collectGarbage()}catch(error62){status.warnings.push(`Preset resource cleanup failed: ${error62 instanceof Error?error62.message:String(error62)}`)}return status}async stageSource(source,expectedRevision,options){let prepared=await preparePreset(sourceUrl2(source),{mearlApiVersion:this.store.mearlApiVersion,load:this.options.load??createNodePresetLoader(),signal:options.signal});if(options.expectedId!==void 0&&prepared.preset.id!==options.expectedId)throw new BundleError("BUNDLE_INVALID","The preset identity differs from the accepted installation");let receipt=await this.store.apply(prepared,{...options,expectedRevision}),activated=!1;return{revision:receipt.revision,activate:async()=>{if(activated)throw new Error("Staged installation was already activated; use resume with its revision to retry");activated=!0;let current2=await this.store.current();if(current2.receipt?.revision!==receipt.revision)throw new BundleError("BUNDLE_CONFLICT","The selected preset changed before runtime setup completed");return this.synchronize(current2.receipt,expectedRevision)}}}async stage(source,options={}){let accepted={...options,...options.overrides===void 0?{}:{overrides:mergePresetDefaults({},options.overrides)},...options.nodeConfig===void 0?{}:{nodeConfig:mergePresetDefaults({},options.nodeConfig)}},current2=await this.store.current({verifyResources:!1}),revision2=presetSelectionRevision(current2);if(accepted.expectedRevision!==void 0&&accepted.expectedRevision!==revision2)throw new BundleError("BUNDLE_CONFLICT","The installed preset changed before preparation");return this.stageSource(source,revision2,accepted)}async apply(source,options={}){return(await this.stage(source,options)).activate()}async update(){let current2=await this.store.current({verifyResources:!1});if(!current2.receipt)throw new Error("No preset is installed");return this.apply(current2.receipt.snapshot.source,{expectedRevision:presetSelectionRevision(current2)})}async resume(expectedRevision){let current2=await this.store.current();if(!current2.receipt||current2.receipt.revision!==expectedRevision)throw new BundleError("BUNDLE_CONFLICT","The installed preset changed before resuming");return this.synchronize(current2.receipt,expectedRevision)}async configure(value){let current2=await this.store.current();if(!current2.prepared)throw new Error("No preset is installed");let receipt=await this.store.apply(current2.prepared,{expectedRevision:presetSelectionRevision(current2),overrides:value});return this.synchronize(receipt,presetSelectionRevision(current2))}}}});import{readFileSync as readFileSync16}from"node:fs";import{join as join26}from"node:path";function isLegacyPackage(installation){try{let manifest=JSON.parse(readFileSync16(join26(installation.packageRoot,"package.json"),"utf8"));return manifest.name===installation.packageName&&typeof manifest.version=="string"&&/^[0-2]\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(manifest.version)}catch{return!1}}async function prepareSetupPreset(options,dependencies={}){let env=options.env??process.env,installer=dependencies.installer??new PresetInstaller({directory:env.MEARL_CAPABILITY_DIR});if(options.source)return installer.stage(options.source);let current2=await installer.store.current();if(current2.receipt)return{revision:current2.receipt.revision,activate:()=>installer.resume(current2.receipt.revision)};if(current2.activation)return;let client2=options.installed===void 0?detectGlobalPackage("@mearl/client",["mearl"],{env}):null;if(!(options.installed??[...detectMearlProfiles({env}).values(),...client2?[client2]:[]]).some(isLegacyPackage))return;let config2=await(dependencies.configuration??(()=>{let url2=new URL(env.MEARL_INSTALLATION_CONFIG_URL||MEARL_INSTALLATION_CONFIG_URL);if(url2.protocol!=="https:"&&!(url2.protocol==="http:"&&["127.0.0.1","localhost","[::1]"].includes(url2.hostname)))throw new Error("Installation configuration requires HTTPS or loopback HTTP");return loadInstallationConfig(url2,url2.origin,AbortSignal.timeout(5e3))}))();if(!config2.legacyPreset)throw new Error("Legacy upgrade preset is unavailable. Retry when the installation catalog is available, or select a preset with --preset.");return installer.stage(config2.presets[config2.legacyPreset].source,{expectedRevision:null,expectedId:config2.legacyPreset})}var MEARL_INSTALLATION_CONFIG_URL,init_presetUpgrade=__esm({"../setup/dist/presetUpgrade.js"(){"use strict";init_installation();init_preset2();init_packageManager();init_profiles();MEARL_INSTALLATION_CONFIG_URL="https://f-loat.github.io/mearl/installation.json"}});import fs10 from"node:fs";import path12 from"node:path";import{createInterface as createInterface2}from"node:readline/promises";import{stdin as input,stdout as output}from"node:process";function autoUpdateClientInstallation(env){let root=env.MEARL_AUTO_UPDATE_CLIENT_ROOT;if(!root)return null;try{let packageRoot=fs10.realpathSync(root);return JSON.parse(fs10.readFileSync(path12.join(packageRoot,"package.json"),"utf8")).name!==UNIFIED_CLIENT?null:resolvePackageManagerInstallation(packageRoot,UNIFIED_CLIENT,{env})}catch{return null}}function autoUpdateProfiles(env){let value=env.MEARL_AUTO_UPDATE_PROFILES;if(value===void 0)return;let requested=value.split(",");if(requested.length===0||new Set(requested).size!==requested.length||requested.some(profile=>!PROFILE_ORDER.includes(profile)))throw new Error("Invalid automatic update profiles");return PROFILE_ORDER.filter(profile=>requested.includes(profile))}async function confirmInTerminal(message){if(!input.isTTY||!output.isTTY)return!1;let readline2=createInterface2({input,output});try{let answer=(await readline2.question(`${message} [y/N] `)).trim().toLowerCase();return answer==="y"||answer==="yes"}finally{readline2.close()}}function siblingExecutable(anchor2,name,existsSync14){for(let executableName of executableNames(name)){let candidate=path12.join(path12.dirname(anchor2),executableName);if(existsSync14(candidate))return candidate}return null}async function runLifecycleCommand(runner,command,args,env,label,writeLine,capture=!1){try{return await runner(command,args,{capture,env:prependCommandPath(command,env)})}catch(error62){return writeLine(`${label}: ${error62 instanceof Error?error62.message:String(error62)}`),null}}async function runPackageOperation(installation,operation,packages,targetLine,runner,env,label,writeLine){let command=buildGlobalPackageCommand(installation,operation,packages,targetLine);writeLine(`${label}: ${command.manager}`);let result=await runLifecycleCommand(runner,command.command,command.args,operation==="uninstall"?env:packages.reduce((childEnv,name)=>packageRegistryEnvironment(name,childEnv),env),label,writeLine);return result?result.code!==0?(writeLine(`${label}: failed (exit ${result.code}).`),{command,ok:!1}):{command,ok:!0}:{command,ok:!1}}async function runHook(profile,operation,detected,runner,existsSync14,env,writeLine,yes,cloudMode){let executable,args,hookEnv=env;if(profile==="local"&&operation!=="uninstall")executable=detected.executable,args=["--init","--mode","skills"];else if(profile==="mcp"&&operation==="uninstall")executable=siblingExecutable(detected.executable,"mearl-mcp-uninstall",existsSync14),args=["--managed-by-setup",...yes?["--yes"]:[]];else if(profile==="mcp"&&operation==="install")executable=siblingExecutable(detected.executable,"mearl-mcp-configure",existsSync14),args=["--global-install",...yes?["--yes"]:[]];else if(profile==="mcp"&&operation==="update")executable=siblingExecutable(detected.executable,"mearl-mcp-configure",existsSync14),args=["--skip-mcp","--global-install"];else if(profile==="cloud"){if(executable=siblingExecutable(detected.executable,"mearl-cloud-server",existsSync14),!executable)return writeLine(`Hook: ${profile} ${operation} command was not found.`),!1;let requestedMode=operation==="uninstall"?"websocket":cloudMode,commandEnv=requestedMode?{...env,MEARL_CLOUD_MODE:requestedMode}:env;if(hookEnv=commandEnv,operation==="uninstall")args=["stop"];else{let status=await runLifecycleCommand(runner,executable,["status"],commandEnv,"Hook: cloud status",writeLine,!0);if(!status)return!1;if(status.code!==0)return writeLine(`Hook: cloud status failed (exit ${status.code}).`),!1;let running=/\[CloudServer\]\s+Status:\s+running\b/.test(status.stdout),qoderMode=cloudMode==="qoder"||/\[CloudServer\]\s+Mode:\s+qoder\b/.test(status.stdout);if(operation==="update"&&!running&&!qoderMode)return writeLine("Hook: cloud update skipped because cloud-server is not running."),!0;args=[running&&!qoderMode?"restart":"start"]}}else return!0;if(!executable)return writeLine(`Hook: ${profile} ${operation} command was not found.`),!1;let result=await runLifecycleCommand(runner,executable,args,hookEnv,`Hook: ${profile} ${operation}`,writeLine);return result?result.code!==0?(writeLine(`Hook: ${profile} ${operation} failed (exit ${result.code}).`),!1):!0:!1}function selectedProfiles(operation,requested,detected){if(requested?.length){let requestedSet=new Set(requested);return PROFILE_ORDER.filter(profile=>requestedSet.has(profile))}return operation==="install"?["local"]:PROFILE_ORDER.filter(profile=>detected.has(profile))}function operationVerb(operation){return operation==="uninstall"?"uninstall":operation==="update"?"update":"install"}async function runMearlLifecycle(options,dependencies={}){if(options.targetLine&&!isMearlReleaseLine(options.targetLine))throw new Error("targetLine must be a valid Mearl release line such as 2.3.x");let env=options.env??process.env,writeLine=dependencies.writeLine??(line=>console.error(line)),existsSync14=dependencies.existsSync??fs10.existsSync,runner=dependencies.runCommand??runCommand,cleanupNativeHost=dependencies.cleanupNativeHost??uninstallNativeHostArtifacts,detectPackage=dependencies.detectPackage??detectGlobalPackage,detectProfiles=dependencies.detectProfiles??((childEnv,detectionOptions)=>detectMearlProfiles({env:childEnv,...detectionOptions})),resolveInvokingManager=dependencies.resolveInvokingManager??(childEnv=>resolveInvokingPackageManager({env:childEnv})),runSkill=dependencies.runSkillOperation??runGlobalMearlSkillOperation,confirm=dependencies.confirm??confirmInTerminal,detectionEnv=options.operation==="update"&&env.MEARL_AUTO_UPDATE_SEARCH_PATH!==void 0?{...env,PATH:env.MEARL_AUTO_UPDATE_SEARCH_PATH}:env,detected=options.operation==="uninstall"?detectProfiles(detectionEnv,{includeLinked:!0}):detectProfiles(detectionEnv),packageDetectionOptions={env,...options.operation==="uninstall"?{includeLinked:!0}:{}},requestedProfiles=options.profiles??(options.profile?[options.profile]:void 0)??(options.operation==="update"?autoUpdateProfiles(env):void 0),autoUpdateClient=options.operation==="update"?autoUpdateClientInstallation(env):null,clientOnly=options.operation==="update"&&env.MEARL_AUTO_UPDATE_CLIENT_ONLY==="1";if(clientOnly&&!autoUpdateClient)return writeLine("A valid global client installation is required for a client-only update."),!1;let selected=clientOnly?[]:selectedProfiles(options.operation,requestedProfiles,detected),lifecycleSelected=options.operation==="uninstall"?selected.filter(profile=>detected.has(profile)):selected,fullPluginNames=[],fullProviders=[];if(options.operation==="uninstall"&&options.full){try{fullPluginNames=(dependencies.listPlugins??listPluginNames)()}catch(error62){return writeLine(`CLI plugins: unable to list registrations: ${error62 instanceof Error?error62.message:String(error62)}`),!1}try{fullProviders=(dependencies.listProviders??listInstalledProviders)()}catch(error62){return writeLine(`Providers: unable to list registrations: ${error62 instanceof Error?error62.message:String(error62)}`),!1}}if(selected.length===0&&!autoUpdateClient&&!(options.operation==="uninstall"&&options.full))return writeLine("No installed Mearl environment was detected on the current PATH."),options.operation==="uninstall"?!0:(writeLine("Run: npx --@mearl:registry=https://registry.npmjs.org @mearl/setup"),!1);if(options.operation==="update"){let missing=selected.filter(profile=>!detected.has(profile));if(missing.length>0)return writeLine(`Not installed: ${missing.join(", ")}. Run the install command first.`),!1}if(options.operation==="uninstall"){if(lifecycleSelected.length===0&&!options.full)return writeLine(`Nothing to uninstall for ${selected.join(", ")}.`),!0;if(options.full&&(writeLine(`CLI plugins: ${fullPluginNames.length>0?fullPluginNames.join(", "):"none detected"}.`),writeLine(`Providers: ${fullProviders.length>0?fullProviders.map(provider=>provider.providerId).join(", "):"none detected"}.`)),!options.yes&&!await confirm(options.full?`Uninstall ${lifecycleSelected.length>0?`Mearl environments (${lifecycleSelected.join(", ")}) and `:""}all CLI plugins and Providers?`:`Uninstall Mearl environments: ${lifecycleSelected.join(", ")}?`))return writeLine("Uninstall cancelled."),!1}lifecycleSelected.length>0&&writeLine(`${operationVerb(options.operation)} targets: ${lifecycleSelected.map(profile=>MEARL_PROFILES[profile].label).join(", ")}`),autoUpdateClient&&lifecycleSelected.length===0&&writeLine("update targets: client CLI");let selectedUsesClient=autoUpdateClient!==null||lifecycleSelected.some(profile=>CLIENT_PROFILES.includes(profile)),detectedClientCandidate=selectedUsesClient&&!autoUpdateClient?detectPackage(UNIFIED_CLIENT,["mearl"],packageDetectionOptions):null,detectedClient=detectedClientCandidate?.packageName===UNIFIED_CLIENT?detectedClientCandidate:null,stagedPreset;if(options.operation!=="uninstall"&&(options.presetSource||!options.targetLine||Number(options.targetLine.split(".")[0])>=3)&&!dependencies.prepareSkills)try{stagedPreset=await(dependencies.preparePreset??prepareSetupPreset)({source:options.presetSource,env,installed:[...lifecycleSelected.flatMap(profile=>detected.get(profile)?[detected.get(profile)]:[]),...detectedClient?[detectedClient]:[],...autoUpdateClient&&env.MEARL_AUTO_UPDATE_CLIENT_ROOT?[{packageName:UNIFIED_CLIENT,packageRoot:env.MEARL_AUTO_UPDATE_CLIENT_ROOT}]:[]]})}catch(error62){return writeLine(`Preset preparation: ${error62 instanceof Error?error62.message:String(error62)}`),!1}let packagesOk=!0;if(lifecycleSelected.includes("cloud")){let legacyCloudClient=detectPackage(LEGACY_CLOUD_CLIENT,["mearl-cloud"],packageDetectionOptions);if(legacyCloudClient?.packageName===LEGACY_CLOUD_CLIENT){let command=buildGlobalPackageCommand(legacyCloudClient,"uninstall",[LEGACY_CLOUD_CLIENT]);writeLine(`Migration (cloud): removing ${LEGACY_CLOUD_CLIENT}.`);let result=await runLifecycleCommand(runner,command.command,command.args,env,"Migration (cloud)",writeLine);if(!result||result.code!==0)return result&&writeLine(`Migration (cloud): failed (exit ${result.code}).`),writeLine("Mearl setup incomplete. Review the messages above."),!1}}let remainingClientProfiles=selectedUsesClient&&options.operation==="uninstall"?CLIENT_PROFILES.filter(profile=>detected.has(profile)&&!lifecycleSelected.includes(profile)):[];if(selectedUsesClient&&options.operation!=="uninstall"){let clientInstallation=autoUpdateClient??detectedClient??detected.get("local")??detected.get("cloud")??resolveInvokingManager(env);if(!(await runPackageOperation(clientInstallation,options.operation,[UNIFIED_CLIENT],mearlPackageSelector(SETUP_VERSION,options.targetLine),runner,env,"Packages (shared client)",writeLine)).ok)return writeLine("Mearl setup incomplete. Review the messages above."),!1}for(let profile of lifecycleSelected){let config2=MEARL_PROFILES[profile],current2=detected.get(profile);if(options.operation==="uninstall"&&!current2)continue;let installation=current2??resolveInvokingManager(env);if(options.operation==="uninstall"&&profile==="local"){let keepsMcp=detected.has("mcp")&&!selected.includes("mcp"),cleanupOk=!1;try{cleanupOk=cleanupNativeHost({mode:keepsMcp?"skills":"both",silent:!0})}catch(error62){writeLine(`Native host: ${error62 instanceof Error?error62.message:String(error62)}`)}if(writeLine(`Native host: ${cleanupOk?"cleaned.":"cleanup failed."}`),!cleanupOk){packagesOk=!1;continue}}if(options.operation==="uninstall"&&!await runHook(profile,options.operation,current2,runner,existsSync14,env,writeLine,options.yes===!0,options.cloudMode)){packagesOk=!1;continue}let packageOperation=options.operation,packages=config2.packages.filter(packageName=>packageName!==UNIFIED_CLIENT);if(packages.length===0)continue;let packageResult=await runPackageOperation(installation,packageOperation,packages,mearlPackageSelector(SETUP_VERSION,options.targetLine),runner,env,`Packages (${profile})`,writeLine);if(!packageResult.ok){packagesOk=!1;continue}if(options.operation!=="uninstall"&&(profile==="local"||profile==="cloud"||profile==="mcp")){let refreshed=detectPackage(config2.anchorPackage,config2.anchorBins,{env:prependCommandPath(packageResult.command.command,env)})??current2;(!refreshed||!await runHook(profile,options.operation,refreshed,runner,existsSync14,env,writeLine,options.yes===!0,options.cloudMode))&&(packagesOk=!1)}}selectedUsesClient&&options.operation==="uninstall"&&(remainingClientProfiles.length>0?writeLine(`Packages (shared client): kept for ${remainingClientProfiles.join(", ")}.`):packagesOk&&detectedClient&&((await runPackageOperation(detectedClient,"uninstall",[UNIFIED_CLIENT],void 0,runner,env,"Packages (shared client)",writeLine)).ok||(packagesOk=!1)));let fullOk=!0;if(options.operation==="uninstall"&&options.full){let pendingPlugins=new Set(fullPluginNames),removePlugin=dependencies.uninstallPlugin??uninstallPlugin;for(;pendingPlugins.size>0;){let name=pendingPlugins.values().next().value;pendingPlugins.delete(name);try{let result=await removePlugin(name,runner);for(let removedName of result.unregisteredNames)pendingPlugins.delete(removedName);result.removed&&writeLine(`CLI plugin ${name}: uninstalled.`)}catch(error62){fullOk=!1,writeLine(`CLI plugin ${name}: ${error62 instanceof Error?error62.message:String(error62)}`)}}let removeProvider=dependencies.uninstallProvider??uninstallProviderPackage;for(let provider of fullProviders)try{await removeProvider(provider.providerId),writeLine(`Provider ${provider.providerId}: uninstalled.`)}catch(error62){fullOk=!1,writeLine(`Provider ${provider.providerId}: ${error62 instanceof Error?error62.message:String(error62)}`)}}if(packagesOk&&options.operation!=="uninstall"&&(stagedPreset||dependencies.prepareSkills))try{if(stagedPreset){let status=await stagedPreset.activate();dependencies.onPresetStatus?.(status)}else await dependencies.prepareSkills()}catch(error62){writeLine(`Skill preparation: ${error62 instanceof Error?error62.message:String(error62)}`),packagesOk=!1}let selectedUsesSkill=lifecycleSelected.some(profile=>MEARL_PROFILES[profile].usesSkill),remainingSkillProfiles=["local","cloud"].filter(profile=>detected.has(profile)&&!lifecycleSelected.includes(profile)),runStandaloneSkill=!0,skillOk=!0;if(packagesOk&&selectedUsesSkill&&selectedUsesClient&&options.skipSkill!==!0&&(options.operation==="uninstall"&&remainingSkillProfiles.length===0||options.operation!=="uninstall"&&options.targetLine===void 0))try{if(options.operation==="uninstall"){let result=await(dependencies.uninstallManagedPlugins??uninstallManagedPlugins)({env,includeMearlSkill:!0,runCommand:runner,writeLine});result==="uninstalled"?runStandaloneSkill=!1:result==="failed"&&(runStandaloneSkill=!1,skillOk=!1)}else{let result=await(dependencies.installManagedPlugins??installManagedPlugins)({env,includeMearlSkill:!0,mearlSkillOperation:options.operation,runCommand:runner,writeLine});result==="installed"?runStandaloneSkill=!1:result==="failed"&&(runStandaloneSkill=!1,skillOk=!1)}}catch(error62){writeLine(`Managed plugin batch: ${error62 instanceof Error?error62.message:String(error62)}; failed.`),runStandaloneSkill=!1,skillOk=!1}if(packagesOk&&skillOk&&selectedUsesSkill&&options.skipSkill!==!0)try{options.operation==="uninstall"?remainingSkillProfiles.length>0?(writeLine(`Skill: kept for ${remainingSkillProfiles.join(", ")}.`),writeLine(`Managed plugins: kept for ${remainingSkillProfiles.join(", ")}.`)):runStandaloneSkill&&(skillOk=await runSkill("uninstall",{env,yes:options.yes,writeLine,runCommand:runner})):runStandaloneSkill&&(skillOk=await runSkill(options.operation,{env,yes:options.yes,writeLine,runCommand:runner}))}catch(error62){writeLine(`Skill: ${error62 instanceof Error?error62.message:String(error62)}`),skillOk=!1}if(packagesOk&&skillOk&&fullOk){if(options.operation==="uninstall"&&options.full&&PROFILE_ORDER.every(profile=>!detected.has(profile)||lifecycleSelected.includes(profile)))try{await(dependencies.cleanupRuntime??cleanupUninstalledRuntime)(),writeLine("Runtime caches: cleaned; user data and browser profiles were retained.")}catch(error62){return writeLine(`Runtime caches: ${error62 instanceof Error?error62.message:String(error62)}`),!1}return writeLine("Mearl setup complete."),!0}return writeLine("Mearl setup incomplete. Review the messages above."),!1}var LEGACY_CLOUD_CLIENT,UNIFIED_CLIENT,PROFILE_ORDER,CLIENT_PROFILES,init_lifecycle=__esm({"../setup/dist/lifecycle.js"(){"use strict";init_setupVersion();init_plugin2();init_host();init_skills();init_packageManager();init_profiles();init_nativeHost2();init_dist();init_version();init_managedPlugins();init_plugin3();init_provider();init_npmRegistry();init_runtimeCleanup();init_presetUpgrade();LEGACY_CLOUD_CLIENT="@mearl/cloud-client",UNIFIED_CLIENT="@mearl/client",PROFILE_ORDER=["local","cloud","mcp"],CLIENT_PROFILES=["local","cloud"]}});var dist_exports4={};__export(dist_exports4,{BrowserExtensionConflictError:()=>BrowserExtensionConflictError,MEARL_EXTENSION_DIRECTORY_NAME:()=>MEARL_EXTENSION_DIRECTORY_NAME,MEARL_EXTENSION_DOWNLOAD_PAGE:()=>MEARL_EXTENSION_DOWNLOAD_PAGE,MEARL_EXTENSION_ID:()=>MEARL_EXTENSION_ID,MEARL_EXTENSION_REMOTE_CONFIG_URL:()=>MEARL_EXTENSION_REMOTE_CONFIG_URL,MEARL_NATIVE_HOST_NAMES:()=>MEARL_NATIVE_HOST_NAMES,MEARL_PROFILES:()=>MEARL_PROFILES,PresetInstallationStore:()=>PresetInstallationStore,PresetInstaller:()=>PresetInstaller,buildGlobalPackageCommand:()=>buildGlobalPackageCommand,compareMearlReleaseLines:()=>compareMearlReleaseLines,compareMearlReleaseVersions:()=>compareMearlReleaseVersions,createNodePresetLoader:()=>createNodePresetLoader,detectGlobalPackage:()=>detectGlobalPackage,detectMearlProfiles:()=>detectMearlProfiles,extensionArchiveUrl:()=>extensionArchiveUrl,fetchBrowserExtensionRelease:()=>fetchBrowserExtensionRelease,findLatestExtensionVersion:()=>findLatestExtensionVersion,inspectMearlExtensionViaCdp:()=>inspectMearlExtensionViaCdp,inspectProviderPackage:()=>inspectProviderPackage,installMearlBrowserExtension:()=>installMearlBrowserExtension,installProviderPackage:()=>installProviderPackage,isMearlReleaseLine:()=>isMearlReleaseLine,isMearlReleaseVersion:()=>isMearlReleaseVersion,isMearlReleaseVersionInLine:()=>isMearlReleaseVersionInLine,loadUnpackedViaCdp:()=>loadUnpackedViaCdp,mearlReleaseLineForVersion:()=>mearlReleaseLineForVersion,parseMearlReleaseLine:()=>parseMearlReleaseLine,parseMearlReleaseVersion:()=>parseMearlReleaseVersion,parseProviderPackageSpec:()=>parseProviderPackageSpec,resolveChromeUserDataDirectory:()=>resolveChromeUserDataDirectory,resolveInvokingPackageManager:()=>resolveInvokingPackageManager,resolveMearlExtensionDirectory:()=>resolveMearlExtensionDirectory,resolveNativeHostDirectory:()=>resolveNativeHostDirectory,resolvePackageManagerInstallation:()=>resolvePackageManagerInstallation,runMearlLifecycle:()=>runMearlLifecycle,runPresetCommand:()=>runPresetCommand,uninstallNativeHostArtifacts:()=>uninstallNativeHostArtifacts,uninstallProviderPackage:()=>uninstallProviderPackage,updateProviderPackage:()=>updateProviderPackage,updateSetupManagedBrowserExtensionFiles:()=>updateSetupManagedBrowserExtensionFiles});var init_dist7=__esm({"../setup/dist/index.js"(){"use strict";init_packageManager();init_browserExtension();init_lifecycle();init_profiles();init_nativeHost2();init_preset2();init_version();init_provider()}});function initBrowserRegistry(deps){logFn=deps.log}function recordFileFor(browserId){return keyedConfigFile(BROWSERS_SUBDIR2,browserId)}function persist(patch){if(!identity)return!1;let file2=recordFileFor(identity.browserId),previous=readRecord(file2);if(previous&&previous.pid!==process.pid&&isAlive(previous.pid))return!1;let record5={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{return previous?.pid===process.pid?writeRecordIfPid(file2,process.pid,record5):previous&&!removeRecordIfPid(file2,previous.pid)?!1:claimRecord(file2,record5)}catch(error62){return logFn("browser-registry: failed to write record:",String(error62)),!1}}async function retireUnreachableBrowserRecord(browserId,canConnect){let file2=recordFileFor(browserId),existing=readRecord(file2);return!existing||existing.pid===process.pid||!isAlive(existing.pid)||await canConnect(existing.socketPath)?!1:removeRecordIfPid(file2,existing.pid)}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)),registered=persist({lastFocusedAt:info.preserveFocus===!1?info.lastFocusedAt??0:previous?.lastFocusedAt??info.lastFocusedAt??Date.now(),extensionVersion:info.extensionVersion});return logFn(`browser-registry: ${registered?"registered":"registration skipped"} ${info.browserName} (${info.browserId})`),registered}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);removeRecordIfPid(file2,process.pid)}function pruneDeadBrowsers(){let now=Date.now();for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR2))){let rec=readRecord(file2);if(!rec){removeInvalidRecord(file2);continue}isAlive(rec.pid)||now-(rec.updatedAt??0)>STALE_RECORD_TTL_MS&&removeRecordIfPid(file2,rec.pid)}}function listRegisteredBrowsers(){let records=[];for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR2))){let record5=readRecord(file2);record5&&isAlive(record5.pid)&&records.push(record5)}return records.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0)||(b.updatedAt??0)-(a.updatedAt??0))}var BROWSERS_SUBDIR2,STALE_RECORD_TTL_MS,FOCUS_WRITE_THROTTLE_MS,identity,logFn,lastFocusWriteAt,focusFlushTimer,init_browser_registry=__esm({"src/browser-registry.ts"(){"use strict";init_dist();BROWSERS_SUBDIR2="browsers",STALE_RECORD_TTL_MS=5*6e4,FOCUS_WRITE_THROTTLE_MS=1e3,identity=null,logFn=()=>{};lastFocusWriteAt=0,focusFlushTimer=null}});import{StringDecoder as StringDecoder3}from"node:string_decoder";var Utf8LineBuffer,init_socketLines=__esm({"src/socketLines.ts"(){"use strict";Utf8LineBuffer=class{constructor(maxBufferBytes){this.maxBufferBytes=maxBufferBytes}maxBufferBytes;buffer="";decoder=new StringDecoder3("utf8");push(chunk){if(this.buffer+=this.decoder.write(chunk),Buffer.byteLength(this.buffer,"utf8")>this.maxBufferBytes)return this.buffer="",{lines:[],overflow:!0};let lines=[],newlineIndex;for(;(newlineIndex=this.buffer.indexOf(`
1109
1109
  `))!==-1;)lines.push(this.buffer.slice(0,newlineIndex)),this.buffer=this.buffer.slice(newlineIndex+1);return{lines,overflow:!1}}}}});var browser_socket_request_exports={};__export(browser_socket_request_exports,{requestBrowserSocket:()=>requestBrowserSocket});import net3 from"node:net";function requestBrowserSocket(socketPath,action,data2,version3,timeoutMs=6e4,browserId,host,routing){let id2=`browser_rpc_${Date.now()}_${Math.random().toString(36).slice(2,10)}`;return new Promise((resolve16,reject)=>{let client2=net3.createConnection(socketPath),lines=new Utf8LineBuffer(MAX_RESPONSE_BUFFER_SIZE),settled=!1,finish=(error62,result)=>{settled||(settled=!0,clearTimeout(timer),client2.removeAllListeners(),client2.destroy(),error62?reject(error62):resolve16(result))},timer=setTimeout(()=>finish(new Error(`Browser request timeout after ${timeoutMs}ms`)),timeoutMs),deadline=Date.now()+timeoutMs;client2.on("connect",()=>{client2.write(`${JSON.stringify({id:id2,action,data:data2,version:version3,protocolVersion:3,controlSource:routing?.controlSource??"local",...routing?.providerTarget?{providerTarget:routing.providerTarget,deadline}:{},...browserId?{browserId}:{},...host?{host}:{}})}
1110
- `)}),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===id2){response.success?finish(void 0,response.data):finish(new Error(response.error||"Browser request failed"));return}}}),client2.on("error",error62=>finish(error62)),client2.on("end",()=>finish(new Error("Browser connection closed before responding"))),client2.on("close",()=>finish(new Error("Browser connection closed before responding")))})}var MAX_RESPONSE_BUFFER_SIZE,init_browser_socket_request=__esm({"src/browser-socket-request.ts"(){"use strict";init_socketLines();init_dist4();MAX_RESPONSE_BUFFER_SIZE=64*1024*1024}});var version_exports={};__export(version_exports,{NATIVE_HOST_VERSION:()=>NATIVE_HOST_VERSION});var NATIVE_HOST_VERSION,init_version2=__esm({"src/version.ts"(){"use strict";NATIVE_HOST_VERSION="3.0.0-beta.2"}});function providerRequestTimeoutMs(action,data2,deadline){if(deadline!==void 0){if(!Number.isSafeInteger(deadline)||deadline<=0)throw new Error("Invalid Provider request deadline");let remaining=deadline-Date.now();if(remaining<=0)throw new Error("Provider request deadline exceeded");if(remaining>2147483647)throw new Error("Provider request deadline exceeds the supported range");return remaining}return resolveActionTimeoutSec(action,data2,120)*1e3}var init_provider_request_timeout=__esm({"src/provider-request-timeout.ts"(){"use strict";init_actionTimeouts()}});var browser_provider_exports={};__export(browser_provider_exports,{accessProviderBrowser:()=>accessProviderBrowser,closeProviderBrowser:()=>closeProviderBrowser,configureProvider:()=>configureProvider,detachProviderBrowser:()=>detachProviderBrowser,findProviderBrowser:()=>findProviderBrowser,getProviderLaunchForm:()=>getProviderLaunchForm,launchProviderBrowser:()=>launchProviderBrowser,listExternalBrowserProviders:()=>listExternalBrowserProviders,listProviderControlSessions:()=>listProviderControlSessions,startProviderBrowser:()=>startProviderBrowser,syncProviderBrowserCookies:()=>syncProviderBrowserCookies,updateProviderControlSession:()=>updateProviderControlSession});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 getProviderLaunchForm(providerId,request){if(!listInstalledProviders().find(item=>item.providerId===providerId)?.browserType.dynamicLaunchForm)throw new Error(`Provider does not support dynamic launch forms: ${providerId}`);let live=await requireLiveProvider(providerId),form=await requestBrowserSocket(live.socketPath,"browser_providers",{...request,operation:"launch_form"},NATIVE_HOST_VERSION,12e4);return validateProviderLaunchForm(form),form}async function requireLiveProvider(providerId){let warning=(await ensureInstalledProvidersRunning([providerId])).find(item=>item.startsWith(`provider ${providerId}:`));if(warning)throw new Error(warning);let live=readLiveProvider(providerId);if(!live)throw new Error(`Provider did not start: ${providerId}`);return assertProviderProtocolVersion(live.providerProtocolVersion,providerId),{socketPath:live.socketPath}}async function launchProviderBrowser(input3){let providerId=input3.provider.trim();if(!listInstalledProviders().find(item=>item.providerId===providerId))throw new Error(`Provider is not registered: ${providerId}`);let live=await requireLiveProvider(providerId),result=await(input3.host?requestBrowserSocket(live.socketPath,"browser_launch",input3.providerOptions,NATIVE_HOST_VERSION,providerRequestTimeoutMs("browser_launch",input3.providerOptions),void 0,input3.host):requestBrowserSocket(live.socketPath,"browser_launch",input3.providerOptions,NATIVE_HOST_VERSION,providerRequestTimeoutMs("browser_launch",input3.providerOptions)));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]&&assertProviderProtocolVersion(exact[0].provider?.protocolVersion,exact[0].provider?.id??"Provider"),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 assertProviderProtocolVersion(browser.provider?.protocolVersion,browser.provider?.id??"Provider"),browser.providerBrowserId}function requestControlledProvider(browser,action,data2,host){return requireProviderBrowser(browser),ensureProviderControlHost().then(controlHost=>requestBrowserSocket(controlHost.socketPath,action,data2,NATIVE_HOST_VERSION,providerRequestTimeoutMs(action,data2),void 0,host,{providerTarget:browser.browserId}))}async function listProviderControlSessions(){let host=readProviderControlHost();return host?(await requestBrowserSocket(host.socketPath,"browser_sessions",{operation:"list"},NATIVE_HOST_VERSION)).sessions??[]:[]}async function updateProviderControlSession(sessionId,operation){let host=readProviderControlHost();if(!host)throw new Error("CONTROL_SESSION_NOT_FOUND");return(await requestBrowserSocket(host.socketPath,"browser_sessions",{sessionId,operation},NATIVE_HOST_VERSION)).session}function closeProviderBrowser(browser,options={}){return requestControlledProvider(browser,"browser_close",{deleteProfile:options.deleteProfile===!0})}function detachProviderBrowser(browser){return requestControlledProvider(browser,"browser_instances",{operation:"detach"})}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 requestControlledProvider(browser,"browser_instances",{operation:"start"});return validateProviderBrowser(result),{...result,browserId:browser.browserId}}function syncProviderBrowserCookies(browser,scope,host){return requestControlledProvider(browser,"browser_instances",{operation:"sync_cookies",scope},host)}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_providers",{operation:"configure",options},NATIVE_HOST_VERSION)}var init_browser_provider=__esm({"src/browser-provider.ts"(){"use strict";init_dist4();init_host();init_runtime();init_browser_registry();init_browser_socket_request();init_version2();init_provider_request_timeout()}});import{randomBytes}from"node:crypto";var BROWSER_QUEUE,ControlSessionRegistry,init_control_session=__esm({"src/control-session.ts"(){"use strict";init_dist5();BROWSER_QUEUE=-1,ControlSessionRegistry=class{constructor(browserId){this.browserId=browserId}browserId;sessions=new Map;owners=new Map;queues=new Map;pending=new Map;browserReleasing=!1;resuming=new Set;createSessionId(){for(;;){let id2=`s_${randomBytes(6).toString("base64url")}`;if(!this.sessions.has(id2))return id2}}create(transport){if(this.browserReleasing)throw new Error("BROWSER_CONTROL_RELEASING");let record5={sessionId:this.createSessionId(),browserId:this.browserId(),transport,status:"active",tabs:[],generation:1};return this.sessions.set(record5.sessionId,record5),this.info(record5.sessionId)}info(id2){let record5=this.require(id2);return{...record5,tabs:record5.tabs.map(tab=>({...tab}))}}state(id2){let{tabs:_tabs,...state}=this.require(id2);return state}find(id2){return this.sessions.get(id2)?.browserId===this.browserId()?this.info(id2):void 0}list(){return[...this.sessions.values()].filter(record5=>record5.status!=="released").map(record5=>this.info(record5.sessionId))}require(id2){let record5=this.sessions.get(id2);if(!record5||record5.browserId!==this.browserId())throw new Error("CONTROL_SESSION_NOT_FOUND");return record5}assertActive(id2,generation){let record5=this.require(id2);if(record5.status!=="active"||generation!==void 0&&generation!==record5.generation)throw new Error(`CONTROL_SESSION_PAUSED: ${record5.status}; inspect the page after the user returns control`);return record5}claim(id2,tabId,source){let record5=this.require(id2),owner=this.owners.get(tabId);if(owner&&owner!==id2)throw new Error("TAB_CONTROLLED_BY_SESSION");record5.tabs.some(tab=>tab.tabId===tabId)||record5.tabs.push({tabId,source}),this.owners.set(tabId,id2)}blockedTabs(id2){return[...this.owners].filter(([,owner])=>owner!==id2).map(([tab])=>tab)}assertBrowserRelease(){if(this.list().length)throw new Error("ACTIVE_CONTROL_SESSIONS: release the owning session first")}async releaseBrowser(operation){if(this.assertBrowserRelease(),this.browserReleasing)throw new Error("BROWSER_CONTROL_RELEASING");this.browserReleasing=!0;try{return await Promise.allSettled([...this.pending.values()].flatMap(operations=>[...operations])),await operation()}finally{this.browserReleasing=!1}}async run(id2,action,data2,operation,transport="extension"){if(this.browserReleasing)throw new Error("BROWSER_CONTROL_RELEASING");let generation=id2?this.assertActive(id2).generation:void 0,tabs=new Set;typeof data2.tabId=="number"&&tabs.add(data2.tabId);for(let tab of data2.tabIds??[])typeof tab=="number"&&tabs.add(tab);typeof data2.openerTabId=="number"&&tabs.add(data2.openerTabId);let steps=action==="run_actions"?data2.actions:[{action,data:data2}];if(action==="run_actions"){validateActionBatch(data2);for(let step of data2.actions??[]){typeof step.data?.tabId=="number"&&tabs.add(step.data.tabId);for(let tab of step.data?.tabIds??[])typeof tab=="number"&&tabs.add(tab);typeof step.data?.openerTabId=="number"&&tabs.add(step.data.openerTabId)}}let opensPage=steps.some(step=>step.action==="tab_open"),changesSharedSettings=steps.some(step=>["set_rule","set_cookie"].includes(step.action)||step.action==="set_app_profile"&&transport!=="cdp"&&step.data?.mtopEnv!==void 0),assertSharedResources=()=>{if(action==="run_actions"&&!id2&&this.list().length&&steps.some(step=>["tab_open","browser_close"].includes(step.action)))throw new Error("ACTIVE_CONTROL_SESSIONS: open pages outside run_actions while sessions are active");if(changesSharedSettings&&this.list().some(record5=>record5.sessionId!==id2))throw new Error("BROWSER_RESOURCE_CONFLICT: use an isolated browser to change shared settings");if(data2.closeExisting&&!id2&&this.list().length)throw new Error("ACTIVE_CONTROL_SESSIONS")};assertSharedResources();for(let tab of tabs){if(tab<0)continue;let owner=this.owners.get(tab);if(owner&&owner!==id2)throw new Error("TAB_CONTROLLED_BY_SESSION")}let unlock,tail=new Promise(resolve16=>{unlock=resolve16}),runtimeTransport=action==="page_runtime",predecessors=runtimeTransport?[]:[...tabs].map(tab=>this.queues.get(tab)).filter(Boolean);if(!runtimeTransport&&this.queues.has(BROWSER_QUEUE)&&predecessors.push(this.queues.get(BROWSER_QUEUE)),(changesSharedSettings||action==="page_download"||opensPage)&&(predecessors.push(...this.queues.values()),tabs.add(BROWSER_QUEUE)),!runtimeTransport)for(let tab of tabs)this.queues.set(tab,tail);let promise2=(async()=>{try{await Promise.all(predecessors),id2&&this.assertActive(id2,generation),assertSharedResources();for(let tab of tabs){let owner=this.owners.get(tab);if(owner&&owner!==id2)throw new Error("TAB_CONTROLLED_BY_SESSION");id2&&tab>=0&&this.claim(id2,tab,"attached")}return await operation()}finally{unlock();for(let tab of tabs)this.queues.get(tab)===tail&&this.queues.delete(tab)}})(),pending=this.pending.get(id2)??new Set;pending.add(promise2),this.pending.set(id2,pending);try{return await promise2}finally{pending.delete(promise2),pending.size||this.pending.delete(id2)}}async waitForIdle(id2){await Promise.allSettled([...this.pending.get(id2)??[]])}assertStep(id2,generation){this.assertActive(id2,generation)}recordResult(id2,action,result,data2){action==="tab_open"&&typeof result?.tabId=="number"&&this.claim(id2,result.tabId,result.opened===!0?"created":"attached");for(let tab of result?.observation?.openedTabs??[])typeof tab.tabId=="number"&&this.claim(id2,tab.tabId,"created");let target=this.require(id2).tabs.find(tab=>tab.tabId===(result?.tabId??data2?.tabId));if(target&&typeof result?.title=="string"&&(target.title=result.title),target&&typeof result?.url=="string"&&(target.url=result.url),action==="tab_close"&&typeof data2?.tabId=="number"&&(this.owners.delete(data2.tabId),this.require(id2).tabs=this.require(id2).tabs.filter(tab=>tab.tabId!==data2.tabId)),action==="tab_close")for(let tab of this.require(id2).tabs)(result?.closedTabIds??[]).includes(tab.tabId)&&this.owners.delete(tab.tabId)}handoff(id2,reason){let record5=this.assertActive(id2);return record5.status="user",record5.generation+=1,record5.reason=reason,this.info(id2)}async resume(id2,cleanup=async()=>{}){let record5=this.require(id2);if(record5.status!=="user")throw new Error("Session is not waiting for the user");if(this.resuming.has(id2))throw new Error("CONTROL_SESSION_RESUMING");this.resuming.add(id2);try{return await this.waitForIdle(id2),await cleanup(),record5.status="active",record5.reason=void 0,record5.generation+=1,this.info(id2)}finally{this.resuming.delete(id2)}}async release(id2,params,cleanup){let record5=this.require(id2);if(this.resuming.has(id2))throw new Error("CONTROL_SESSION_RESUMING");if(record5.status==="released")return this.info(id2);if(record5.status==="releasing")throw new Error("CONTROL_SESSION_RELEASING");let previous=record5.status;record5.status="releasing",record5.generation+=1,await Promise.allSettled([...this.pending.get(id2)??[]]);let tabs=record5.tabs.map(tab=>tab.tabId),keep=new Set(params.keepTabIds??[]),close=params.closeCreatedTabs?record5.tabs.filter(tab=>tab.source==="created"&&!keep.has(tab.tabId)).map(tab=>tab.tabId):[];try{await cleanup(tabs,close);for(let tab of tabs)this.owners.get(tab)===id2&&this.owners.delete(tab);record5.status="released";let released=[...this.sessions.values()].filter(session=>session.status==="released"&&session.sessionId!==id2);for(let old of released.slice(0,Math.max(0,released.length-99)))this.sessions.delete(old.sessionId)}catch(error62){throw record5.status=previous,error62}return this.info(id2)}}}});import{rmSync as rmSync14}from"node:fs";import{randomUUID as randomUUID19}from"node:crypto";import{mkdir as mkdir2,open as open4,rm as rm3,stat as stat3,writeFile}from"node:fs/promises";import path14 from"node:path";import os5 from"node:os";var MAX_BYTES,ARTIFACT_CHUNK_BYTES,BrowserArtifactStore,init_browser_artifacts=__esm({"src/browser-artifacts.ts"(){"use strict";MAX_BYTES=256*1024*1024,ARTIFACT_CHUNK_BYTES=256*1024,BrowserArtifactStore=class{constructor(root=path14.join(os5.tmpdir(),`mearl-artifacts-${process.pid}-${randomUUID19()}`)){this.root=root}root;files=new Map;directory;sweeper;async create(filename,sessionId){if(typeof filename!="string"||!filename||[".",".."].includes(filename)||/[\\/]/.test(filename)||filename.length>255)throw new Error("Invalid artifact filename");this.sweeper||(this.sweeper=setInterval(()=>{for(let[id2,file3]of this.files)!file3.sessionId&&!file3.writing&&Date.now()-file3.accessedAt>3600*1e3&&this.remove(id2).catch(()=>{})},6e4),this.sweeper.unref()),await mkdir2(this.root,{recursive:!0,mode:448}),this.directory=this.root;let artifactId=randomUUID19(),directory=path14.join(this.root,artifactId);await mkdir2(directory,{mode:448});let file2={artifactId,filename,bytes:0,location:"browser",path:path14.join(directory,filename),sessionId,ready:!1,accessedAt:Date.now()};return await writeFile(file2.path,"",{mode:384}),this.files.set(artifactId,file2),this.info(file2)}async importFile(filename,sourcePath,sessionId){let source=await open4(sourcePath,"r"),id2;try{let metadata=await source.stat();if(!metadata.isFile()||metadata.size>MAX_BYTES)throw new Error("Download is unavailable or exceeds 256 MiB");id2=(await this.create(filename,sessionId)).artifactId;let file2=this.require(id2,sessionId),target=await open4(file2.path,"w"),copied=0;try{for await(let chunk of source.createReadStream({autoClose:!1})){if(copied+=chunk.length,copied>MAX_BYTES)throw new Error("Download exceeds 256 MiB");let written=0;for(;written<chunk.length;){let result=await target.write(chunk,written,chunk.length-written);if(!result.bytesWritten)throw new Error("Download import made no progress");written+=result.bytesWritten}}}finally{await target.close()}if(copied!==metadata.size)throw new Error("Download changed during import");return file2.bytes=(await stat3(file2.path)).size,file2.ready=!0,this.info(file2)}catch(error62){throw id2&&await this.remove(id2,sessionId),error62}finally{await source.close()}}require(id2,sessionId){let file2=this.files.get(id2);if(!file2||file2.sessionId!==void 0&&file2.sessionId!==sessionId)throw new Error("ARTIFACT_NOT_FOUND");return file2.accessedAt=Date.now(),file2}info(file2){return{artifactId:file2.artifactId,filename:file2.filename,bytes:file2.bytes,location:"browser"}}async write(id2,offset2,base643,sessionId){let file2=this.require(id2,sessionId);if(file2.ready||file2.writing||offset2!==file2.bytes)throw new Error("Invalid artifact write offset or completed transfer");if(typeof base643!="string"||base643.length>Math.ceil(ARTIFACT_CHUNK_BYTES/3)*4||base643.length%4!==0||!/^[A-Za-z0-9+/]*={0,2}$/.test(base643))throw new Error("Invalid artifact chunk");let chunk=Buffer.from(base643,"base64");if(chunk.toString("base64")!==base643)throw new Error("Invalid artifact chunk");if(file2.bytes+chunk.length>MAX_BYTES)throw new Error("Artifact exceeds 256 MiB");file2.writing=!0;try{let handle=await open4(file2.path,"r+");try{let written=0;for(;written<chunk.length;){let result=await handle.write(chunk,written,chunk.length-written,offset2+written);if(!result.bytesWritten)throw new Error("Artifact write made no progress");written+=result.bytesWritten}}finally{await handle.close()}return file2.bytes+=chunk.length,this.info(file2)}finally{file2.writing=!1}}complete(id2,bytes,sessionId){let file2=this.require(id2,sessionId);if(file2.writing||bytes!==file2.bytes)throw new Error("Artifact size mismatch");return file2.ready=!0,this.info(file2)}resolve(id2,sessionId){let file2=this.require(id2,sessionId);if(!file2.ready)throw new Error("Artifact is not ready");return file2.path}async read(id2,offset2,sessionId){let file2=this.require(id2,sessionId);if(!file2.ready||!Number.isSafeInteger(offset2)||offset2<0||offset2>file2.bytes)throw new Error("Invalid artifact read");let handle=await open4(file2.path,"r");try{let buffer=Buffer.alloc(Math.min(ARTIFACT_CHUNK_BYTES,file2.bytes-offset2)),result=await handle.read(buffer,0,buffer.length,offset2);return{base64:buffer.subarray(0,result.bytesRead).toString("base64"),bytes:result.bytesRead,totalBytes:file2.bytes}}finally{await handle.close()}}async remove(id2,sessionId){let file2=this.require(id2,sessionId);await rm3(path14.dirname(file2.path),{recursive:!0,force:!0}),this.files.delete(id2)}async release(sessionId,keep=[]){let retain=new Set(keep);for(let[id2,file2]of this.files)file2.sessionId===sessionId&&(retain.has(id2)?(file2.sessionId=void 0,file2.accessedAt=Date.now()):await this.remove(id2,sessionId))}disposeSync(){this.sweeper&&clearInterval(this.sweeper),this.directory&&rmSync14(this.directory,{recursive:!0,force:!0}),this.files.clear()}async dispose(){this.sweeper&&clearInterval(this.sweeper),this.directory&&await rm3(this.directory,{recursive:!0,force:!0}),this.files.clear()}}}});var ControlSessionManager,init_control_session_manager=__esm({"src/control-session-manager.ts"(){"use strict";init_dist5();init_control_session();init_browser_artifacts();ControlSessionManager=class{constructor(dependencies){this.dependencies=dependencies;this.registry=new ControlSessionRegistry(dependencies.browserId)}dependencies;registry;artifacts=new BrowserArtifactStore;activityQueues=new Map;async withActivity(id2,operation){let pending=(this.activityQueues.get(id2)??Promise.resolve()).catch(()=>{}).then(operation);this.activityQueues.set(id2,pending);try{return await pending}finally{this.activityQueues.get(id2)===pending&&this.activityQueues.delete(id2)}}async closeTabs(tabs,transport,sessionId){for(let tabId of tabs)try{let result=await this.dependencies.invoke("tab_close",{tabId},transport);this.registry.recordResult(sessionId,"tab_close",result,{tabId})}catch(error62){let current2=await this.dependencies.invoke("tab_list",{},transport);if(!Array.isArray(current2.tabs)||current2.tabs.some(tab=>(tab.tabId??tab.id)===tabId))throw error62;this.registry.recordResult(sessionId,"tab_close",{},{tabId})}}async userControl(id2,operation,reason){if(operation==="release")return await this.invoke("browser_release",{},id2),this.registry.info(id2);operation==="resume"&&await this.activityQueues.get(id2)?.catch(()=>{});let current2=this.registry.info(id2),info=operation==="resume"?await this.registry.resume(id2,()=>this.dependencies.cleanup(current2.tabs.map(tab=>tab.tabId),current2.transport,!0)):current2.status==="user"?current2:this.registry.handoff(id2,reason);return this.dependencies.notify(),operation==="handoff"?(await this.withActivity(id2,async()=>{await this.dependencies.deactivate?.(this.registry.info(id2).tabs.map(tab=>tab.tabId),current2.transport)}),this.registry.info(id2)):info}async invoke(action,data2,sessionId,requestedTransport,origin="local"){if(data2&&(Object.keys(data2).some(key=>key.startsWith("__mearl"))||(data2.actions??[]).some(step=>Object.keys(step.data??{}).some(key=>key.startsWith("__mearl")))))throw new Error("Internal session fields are reserved");validateRequiredActionTabId(action,data2);let created=sessionId==="new";if(sessionId==="new"){if(!["tab_open","page_snapshot","page_screenshot"].includes(action))throw new Error("A new session requires tab_open, page_snapshot or page_screenshot");sessionId=this.registry.create(requestedTransport??this.dependencies.transport()).sessionId}let info=sessionId?this.registry.info(sessionId):void 0,transport=info?.transport??requestedTransport??this.dependencies.transport();if(requestedTransport&&transport!==requestedTransport)throw new Error("A session cannot change transport");if(action==="browser_control"){if(!sessionId||!["handoff","resume"].includes(data2.operation))throw new Error("browser_control requires --session and handoff/resume");if(data2.operation==="resume")return{session:await this.userControl(sessionId,"resume")};if(data2.tabId!==void 0&&!info.tabs.some(tab=>tab.tabId===data2.tabId))throw new Error("TAB_NOT_IN_CONTROL_SESSION");return{session:await this.userControl(sessionId,"handoff",data2.reason)}}if(action==="browser_release"&&sessionId){let params=data2;return await this.registry.release(sessionId,params,async(tabs,close)=>{await this.dependencies.cleanup(tabs,transport,params.preserveEnvironment!==!1),await this.closeTabs(close,transport,sessionId),await this.artifacts.release(sessionId,params.keepArtifactIds)}),this.dependencies.notify(),{released:!0,hadActiveControl:!0,transports:[transport],affectedTabIds:info.tabs.map(tab=>tab.tabId),session:this.registry.state(sessionId)}}if((action==="browser_release"||action==="browser_close")&&this.registry.assertBrowserRelease(),(action==="browser_release"||action==="browser_close")&&!sessionId)return this.registry.releaseBrowser(()=>this.dependencies.invoke(action,data2,transport));let performStep=async(name,payload,batch=!1)=>{if(name==="tab_open"&&(sessionId&&payload.closeExisting&&(await this.closeTabs(this.registry.info(sessionId).tabs.filter(tab=>tab.source==="created").map(tab=>tab.tabId),transport,sessionId),payload={...payload,closeExisting:!1}),payload={...payload,__mearlBlockedTabIds:this.registry.blockedTabs(sessionId)}),name==="page_upload"&&payload.files){if(payload.filePaths)throw new Error("Use files or filePaths, not both");payload={...payload,filePaths:payload.files.map(file2=>this.artifacts.resolve(file2.artifactId,sessionId))},delete payload.files}if(batch){if(transport==="provider"){let result4=await this.dependencies.invoke(name,{...payload,__mearlControlSource:origin},transport);return sessionId&&this.registry.recordResult(sessionId,name,result4,payload),result4?.action?.success===!1?{...result4.action,success:!1}:result4?.success===!1?{...result4,success:!1}:{success:!0,data:result4}}let result3=await this.dependencies.invoke("run_actions",{tabId:payload.tabId,actions:[{action:name,data:payload}],__mearlControlSource:origin},transport),outcome=result3.results?.[0]??{success:!1,error:result3.error??"Batch step returned no result",stage:result3.stage,attempt:result3.attempt};return sessionId&&outcome.success&&this.registry.recordResult(sessionId,name,outcome.data,payload),outcome}let result2=await this.dependencies.invoke(name,{...payload,__mearlControlSource:origin},transport);return sessionId&&this.registry.recordResult(sessionId,name,result2,payload),result2},invokeStep=(name,payload,batch=!1)=>sessionId&&name==="tab_open"?this.withActivity(sessionId,async()=>(this.registry.assertStep(sessionId,info.generation),performStep(name,payload,batch))):performStep(name,payload,batch),result;try{result=await this.registry.run(sessionId,action,data2,async()=>{if(transport==="extension"&&this.dependencies.transport()!=="extension")throw new Error("CONTROL_SESSION_TRANSPORT_UNAVAILABLE: extension is disconnected");if(action.startsWith("__artifact_")){let store=this.artifacts;switch(action){case"__artifact_init":return{artifact:await store.create(data2.filename,sessionId),browserId:this.dependencies.browserId()};case"__artifact_write":return store.write(data2.artifactId,data2.offset,data2.base64,sessionId);case"__artifact_complete":return store.complete(data2.artifactId,data2.bytes,sessionId);case"__artifact_read":return store.read(data2.artifactId,data2.offset,sessionId);case"__artifact_remove":return await store.remove(data2.artifactId,sessionId),{removed:!0};default:throw new Error("Unknown artifact operation")}}if(action==="page_download"){let downloaded=await this.dependencies.download(data2,transport,origin);try{return sessionId&&this.registry.recordResult(sessionId,"page_click",downloaded.action,data2),{download:{...await this.artifacts.importFile(downloaded.filename,downloaded.filePath,sessionId),browserId:this.dependencies.browserId()},action:downloaded.action}}finally{if(downloaded.owned){let{rm:rm5,rmdir:rmdir2}=await import("node:fs/promises");await rm5(downloaded.filePath,{force:!0}),downloaded.directory&&await rmdir2(downloaded.directory).catch(()=>{})}}}return action==="run_actions"&&sessionId?runActionBatch(data2,(name,payload)=>invokeStep(name,payload,!0),{beforeStep:()=>this.registry.assertStep(sessionId,info.generation)}):invokeStep(action,data2)},transport)}catch(error62){throw created&&sessionId&&await this.registry.release(sessionId,{},async tabs=>{await this.dependencies.cleanup(tabs,transport,!0),await this.artifacts.release(sessionId)}),this.dependencies.notify(),error62}if(sessionId&&action==="tab_list"&&Array.isArray(result.tabs)){let blocked=new Set(this.registry.blockedTabs(sessionId));result={...result,tabs:result.tabs.filter(tab=>!blocked.has(tab.tabId??tab.id))},result.count=result.tabs.length}return sessionId?(this.dependencies.notify(),{...result,session:this.registry.state(sessionId)}):result}}}});import{isAbsolute as isAbsolute10}from"node:path";import{AsyncLocalStorage as AsyncLocalStorage2}from"node:async_hooks";function identity2(browser){return`${browser.pid}:${browser.startedAt}:${browser.socketPath}`}var ProviderControlService,init_provider_control=__esm({"src/provider-control.ts"(){"use strict";init_dist5();init_control_session_manager();init_dist4();init_provider_request_timeout();ProviderControlService=class{constructor(dependencies){this.dependencies=dependencies}dependencies;deadlines=new AsyncLocalStorage2;controls=new Map;retired=new Set;retire(manager){let cleanup=Promise.all(manager.registry.list().map(session=>manager.registry.waitForIdle(session.sessionId))).then(()=>manager.artifacts.dispose());this.retired.add(cleanup),cleanup.finally(()=>this.retired.delete(cleanup)).catch(()=>{})}reap(){let browsers=this.dependencies.browsers();for(let[browserId,control]of this.controls){let browser=browsers.find(item=>item.browserId===browserId);(!browser||identity2(browser)!==control.identity)&&(this.controls.delete(browserId),this.retire(control.manager))}}browser(browserId){let browser=this.dependencies.browsers().find(item=>item.browserId===browserId);if(browser?.transport!=="provider"||!browser.providerBrowserId)throw new Error("CONTROL_SESSION_NOT_FOUND: Provider browser is unavailable");return assertProviderProtocolVersion(browser.provider?.protocolVersion,browser.provider?.id??"Provider"),browser}list(){return this.reap(),[...this.controls.values()].flatMap(control=>control.manager.registry.list())}find(sessionId){this.reap();let sessions=[...this.controls.values()].map(control=>control.manager.registry.find(sessionId)).filter(session=>session!==void 0);if(sessions.length>1)throw new Error("CONTROL_SESSION_AMBIGUOUS: multiple browsers own this id");return sessions[0]}async userControl(sessionId,operation){this.reap();for(let[browserId,control]of this.controls){try{control.manager.registry.info(sessionId)}catch{continue}if(identity2(this.browser(browserId))!==control.identity)throw new Error("CONTROL_SESSION_NOT_FOUND");return control.manager.userControl(sessionId,operation)}throw new Error("CONTROL_SESSION_NOT_FOUND")}getControl(browser){let previous=this.controls.get(browser.browserId);if(previous?.identity===identity2(browser))return previous;previous&&this.retire(previous.manager);let control={identity:identity2(browser),manager:new ControlSessionManager({browserId:()=>browser.browserId,transport:()=>"provider",invoke:async(action,payload)=>{let current2=this.browser(browser.browserId);if(identity2(current2)!==control.identity)throw new Error("CONTROL_SESSION_NOT_FOUND");let{__mearlControlSource:origin="local",__mearlBlockedTabIds:blocked,...data2}=payload;if(action==="tab_open"&&blocked?.length&&data2.reuse!=="never"){let result=await this.request(current2,"tab_list",{},origin);if(!Array.isArray(result.tabs))throw new Error("Provider did not return its current pages");if(findMatchingTabs(result.tabs,data2.url,data2.match).some(tab=>blocked.includes(tab.tabId??tab.id)))throw new Error("TAB_CONTROLLED_BY_SESSION")}return this.request(current2,action,data2,origin)},cleanup:async(tabs,_transport,preserveEnvironment)=>{preserveEnvironment||await this.clearEnvironment(browser.browserId,tabs)},download:async(data2,_transport,origin)=>{let current2=this.browser(browser.browserId);if(identity2(current2)!==control.identity)throw new Error("CONTROL_SESSION_NOT_FOUND");let result=await this.request(current2,"page_download",data2,origin);if(!result||typeof result.filename!="string"||!result.filename||typeof result.filePath!="string"||!isAbsolute10(result.filePath)||!Object.hasOwn(result,"action")||result.owned!==void 0&&typeof result.owned!="boolean")throw new Error("Provider page_download must return a completed file with filename, absolute filePath and action");return{filename:result.filename,filePath:result.filePath,action:result.action,owned:result.owned===!0}},notify:this.dependencies.notify})};return this.controls.set(browser.browserId,control),control}async request(browser,action,data2,origin,host){action==="browser_release"&&(action="browser_instances",data2={operation:"detach"});let lifecycle=action==="browser_close"?data2.deleteProfile===!0?"deleteData":"close":action==="get_browser_access_url"?"access":action==="browser_instances"?data2.operation==="sync_cookies"?"syncCookies":data2.operation:void 0;if(lifecycle&&!browser.operations?.includes(lifecycle))throw new Error(`Provider browser does not support ${lifecycle}`);if(!lifecycle&&action!=="get_versions"){if(browser.status!=="connected")throw new Error("Provider browser is not connected");if(!browser.capabilities?.actions.some(capability=>capability===action))throw new Error(`Provider browser does not support ${action}`)}let deadline=this.deadlines.getStore();return deadline!==void 0?(providerRequestTimeoutMs(action,data2,deadline),this.dependencies.request(browser,action,data2,origin,host,deadline)):this.dependencies.request(browser,action,data2,origin,host)}async clearEnvironment(browserId,tabs){let browser=this.browser(browserId),actions=new Set(browser.capabilities?.actions??[]);if(actions.has("set_mock")&&!actions.has("get_mocks"))throw new Error("Provider cannot enumerate Mock state for cleanup");let clear=async(action,data2)=>{let result=await this.request(browser,action,data2,"local");if(result?.success===!1||result?.action?.success===!1)throw new Error(result.error??result.action?.error??"Provider environment cleanup failed")};for(let tabId of tabs){if(actions.has("set_mock")){let result=await this.request(browser,"get_mocks",{tabId},"local");if(!Array.isArray(result.mocks))throw new Error("Provider did not return its Mock state");let names=new Set(result.mocks.map(mock=>mock.apiName));for(let apiName of names)await clear("set_mock",{tabId,apiName,enabled:!1})}for(let[action,data2]of[["set_app_profile",{tabId,enabled:!1,mtopEnv:"default"}],["set_device_emulation",{tabId,enabled:!1}],["set_timezone",{tabId,timezone:""}]])actions.has(action)&&await clear(action,data2)}}async invoke(browserId,action,data2={},sessionId,origin="local",host,deadline){return this.deadlines.run(deadline,async()=>{deadline!==void 0&&providerRequestTimeoutMs(action,data2,deadline),this.reap();let browser=this.browser(browserId),{manager}=this.getControl(browser);if(action==="get_versions"||action==="get_browser_access_url")return this.request(browser,action,data2,origin);if(action==="browser_instances"){if(!["start","detach","sync_cookies"].includes(data2.operation))throw new Error("Invalid browser instance operation");return manager.registry.releaseBrowser(()=>this.request(browser,action,data2,origin,host))}return manager.invoke(action,data2,sessionId,void 0,origin)})}async dispose(){await Promise.all([...this.retired,...[...this.controls.values()].map(async({manager})=>{await Promise.all(manager.registry.list().map(session=>manager.registry.waitForIdle(session.sessionId))),await manager.artifacts.dispose()})])}}}});var provider_control_host_exports={};__export(provider_control_host_exports,{runProviderControlHost:()=>runProviderControlHost});import net4 from"node:net";import{chmodSync as chmodSync2,rmSync as rmSync16}from"node:fs";import{randomUUID as randomUUID27}from"node:crypto";async function runProviderControlHost(token){let file2=providerControlHostFile(),owner=readRecord(file2);if(!owner||owner.token!==token)throw new Error("Provider control host startup ownership was lost");let socketPath=providerControlSocketPath(process.pid);if(!writeRecordIfPid(file2,owner.pid,{pid:process.pid,socketPath,token,ready:!1,protocolVersion:3}))throw new Error("Provider control host startup ownership was lost");let connections=new Set,service=new ProviderControlService({browsers:listRegisteredBrowsers,request:(browser,action,data2,origin,host,deadline)=>requestBrowserSocket(browser.socketPath,action,data2,NATIVE_HOST_VERSION,providerRequestTimeoutMs(action,data2,deadline),browser.providerBrowserId,host,{controlSource:origin}),notify:()=>{for(let browser of listRegisteredBrowsers())browser.transport==="extension"&&requestBrowserSocket(browser.socketPath,"provider_control_sessions_changed",{},NATIVE_HOST_VERSION,5e3).catch(()=>{})}}),server=net4.createServer(socket=>{connections.add(socket),socket.on("error",()=>{}),socket.once("close",()=>connections.delete(socket));let lines=new Utf8LineBuffer(16*1024*1024);socket.on("data",chunk=>{let result=lines.push(chunk);if(result.overflow)return socket.destroy();for(let line of result.lines)handle(line,socket)})});async function handle(line,socket){let id2="";try{let request=JSON.parse(line);id2=typeof request.id=="string"?request.id:randomUUID27(),assertProviderProtocolVersion(request.protocolVersion,"Provider control client");let data2=request.data??{},result;if(request.action==="__control_session_resolve")result={session:service.find(data2.sessionId)??null};else if(request.action==="browser_sessions")if(data2.operation==="list")result={sessions:service.list()};else{if(!["handoff","resume","release"].includes(data2.operation)||typeof data2.sessionId!="string"||!data2.sessionId)throw new Error("Invalid browser session operation");result={session:await service.userControl(data2.sessionId,data2.operation)}}else{if(typeof request.providerTarget!="string"||typeof request.action!="string")throw new Error("Provider browser and action are required");if(!data2||typeof data2!="object"||Array.isArray(data2))throw new Error("Invalid action payload");if(request.transport&&request.transport!=="provider")throw new Error("A session cannot change transport");result=await service.invoke(request.providerTarget,request.action,data2,request.controlSessionId,request.controlSource??"local",request.host,request.deadline)}socket.destroyed||socket.write(JSON.stringify({id:id2,success:!0,data:result})+`
1110
+ `)}),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===id2){response.success?finish(void 0,response.data):finish(new Error(response.error||"Browser request failed"));return}}}),client2.on("error",error62=>finish(error62)),client2.on("end",()=>finish(new Error("Browser connection closed before responding"))),client2.on("close",()=>finish(new Error("Browser connection closed before responding")))})}var MAX_RESPONSE_BUFFER_SIZE,init_browser_socket_request=__esm({"src/browser-socket-request.ts"(){"use strict";init_socketLines();init_dist4();MAX_RESPONSE_BUFFER_SIZE=64*1024*1024}});var version_exports={};__export(version_exports,{NATIVE_HOST_VERSION:()=>NATIVE_HOST_VERSION});var NATIVE_HOST_VERSION,init_version2=__esm({"src/version.ts"(){"use strict";NATIVE_HOST_VERSION="3.0.0-beta.4"}});function providerRequestTimeoutMs(action,data2,deadline){if(deadline!==void 0){if(!Number.isSafeInteger(deadline)||deadline<=0)throw new Error("Invalid Provider request deadline");let remaining=deadline-Date.now();if(remaining<=0)throw new Error("Provider request deadline exceeded");if(remaining>2147483647)throw new Error("Provider request deadline exceeds the supported range");return remaining}return resolveActionTimeoutSec(action,data2,120)*1e3}var init_provider_request_timeout=__esm({"src/provider-request-timeout.ts"(){"use strict";init_actionTimeouts()}});var browser_provider_exports={};__export(browser_provider_exports,{accessProviderBrowser:()=>accessProviderBrowser,closeProviderBrowser:()=>closeProviderBrowser,configureProvider:()=>configureProvider,detachProviderBrowser:()=>detachProviderBrowser,findProviderBrowser:()=>findProviderBrowser,getProviderLaunchForm:()=>getProviderLaunchForm,launchProviderBrowser:()=>launchProviderBrowser,listExternalBrowserProviders:()=>listExternalBrowserProviders,listProviderControlSessions:()=>listProviderControlSessions,startProviderBrowser:()=>startProviderBrowser,syncProviderBrowserCookies:()=>syncProviderBrowserCookies,updateProviderControlSession:()=>updateProviderControlSession});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 getProviderLaunchForm(providerId,request){if(!listInstalledProviders().find(item=>item.providerId===providerId)?.browserType.dynamicLaunchForm)throw new Error(`Provider does not support dynamic launch forms: ${providerId}`);let live=await requireLiveProvider(providerId),form=await requestBrowserSocket(live.socketPath,"browser_providers",{...request,operation:"launch_form"},NATIVE_HOST_VERSION,12e4);return validateProviderLaunchForm(form),form}async function requireLiveProvider(providerId){let warning=(await ensureInstalledProvidersRunning([providerId])).find(item=>item.startsWith(`provider ${providerId}:`));if(warning)throw new Error(warning);let live=readLiveProvider(providerId);if(!live)throw new Error(`Provider did not start: ${providerId}`);return assertProviderProtocolVersion(live.providerProtocolVersion,providerId),{socketPath:live.socketPath}}async function launchProviderBrowser(input3){let providerId=input3.provider.trim();if(!listInstalledProviders().find(item=>item.providerId===providerId))throw new Error(`Provider is not registered: ${providerId}`);let live=await requireLiveProvider(providerId),result=await(input3.host?requestBrowserSocket(live.socketPath,"browser_launch",input3.providerOptions,NATIVE_HOST_VERSION,providerRequestTimeoutMs("browser_launch",input3.providerOptions),void 0,input3.host):requestBrowserSocket(live.socketPath,"browser_launch",input3.providerOptions,NATIVE_HOST_VERSION,providerRequestTimeoutMs("browser_launch",input3.providerOptions)));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]&&assertProviderProtocolVersion(exact[0].provider?.protocolVersion,exact[0].provider?.id??"Provider"),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 assertProviderProtocolVersion(browser.provider?.protocolVersion,browser.provider?.id??"Provider"),browser.providerBrowserId}function requestControlledProvider(browser,action,data2,host){return requireProviderBrowser(browser),ensureProviderControlHost().then(controlHost=>requestBrowserSocket(controlHost.socketPath,action,data2,NATIVE_HOST_VERSION,providerRequestTimeoutMs(action,data2),void 0,host,{providerTarget:browser.browserId}))}async function listProviderControlSessions(){let host=readProviderControlHost();return host?(await requestBrowserSocket(host.socketPath,"browser_sessions",{operation:"list"},NATIVE_HOST_VERSION)).sessions??[]:[]}async function updateProviderControlSession(sessionId,operation){let host=readProviderControlHost();if(!host)throw new Error("CONTROL_SESSION_NOT_FOUND");return(await requestBrowserSocket(host.socketPath,"browser_sessions",{sessionId,operation},NATIVE_HOST_VERSION)).session}function closeProviderBrowser(browser,options={}){return requestControlledProvider(browser,"browser_close",{deleteProfile:options.deleteProfile===!0})}function detachProviderBrowser(browser){return requestControlledProvider(browser,"browser_instances",{operation:"detach"})}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 requestControlledProvider(browser,"browser_instances",{operation:"start"});return validateProviderBrowser(result),{...result,browserId:browser.browserId}}function syncProviderBrowserCookies(browser,scope,host){return requestControlledProvider(browser,"browser_instances",{operation:"sync_cookies",scope},host)}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_providers",{operation:"configure",options},NATIVE_HOST_VERSION)}var init_browser_provider=__esm({"src/browser-provider.ts"(){"use strict";init_dist4();init_host();init_runtime();init_browser_registry();init_browser_socket_request();init_version2();init_provider_request_timeout()}});import{randomBytes}from"node:crypto";var BROWSER_QUEUE,ControlSessionRegistry,init_control_session=__esm({"src/control-session.ts"(){"use strict";init_dist5();BROWSER_QUEUE=-1,ControlSessionRegistry=class{constructor(browserId){this.browserId=browserId}browserId;sessions=new Map;owners=new Map;queues=new Map;pending=new Map;browserReleasing=!1;resuming=new Set;createSessionId(){for(;;){let id2=`s_${randomBytes(6).toString("base64url")}`;if(!this.sessions.has(id2))return id2}}create(transport){if(this.browserReleasing)throw new Error("BROWSER_CONTROL_RELEASING");let record5={sessionId:this.createSessionId(),browserId:this.browserId(),transport,status:"active",tabs:[],generation:1};return this.sessions.set(record5.sessionId,record5),this.info(record5.sessionId)}info(id2){let record5=this.require(id2);return{...record5,tabs:record5.tabs.map(tab=>({...tab}))}}state(id2){let{tabs:_tabs,...state}=this.require(id2);return state}find(id2){return this.sessions.get(id2)?.browserId===this.browserId()?this.info(id2):void 0}list(){return[...this.sessions.values()].filter(record5=>record5.status!=="released").map(record5=>this.info(record5.sessionId))}require(id2){let record5=this.sessions.get(id2);if(!record5||record5.browserId!==this.browserId())throw new Error("CONTROL_SESSION_NOT_FOUND");return record5}assertActive(id2,generation){let record5=this.require(id2);if(record5.status!=="active"||generation!==void 0&&generation!==record5.generation)throw new Error(`CONTROL_SESSION_PAUSED: ${record5.status}; inspect the page after the user returns control`);return record5}claim(id2,tabId,source){let record5=this.require(id2),owner=this.owners.get(tabId);if(owner&&owner!==id2)throw new Error("TAB_CONTROLLED_BY_SESSION");record5.tabs.some(tab=>tab.tabId===tabId)||record5.tabs.push({tabId,source}),this.owners.set(tabId,id2)}blockedTabs(id2){return[...this.owners].filter(([,owner])=>owner!==id2).map(([tab])=>tab)}assertBrowserRelease(){if(this.list().length)throw new Error("ACTIVE_CONTROL_SESSIONS: release the owning session first")}async releaseBrowser(operation){if(this.assertBrowserRelease(),this.browserReleasing)throw new Error("BROWSER_CONTROL_RELEASING");this.browserReleasing=!0;try{return await Promise.allSettled([...this.pending.values()].flatMap(operations=>[...operations])),await operation()}finally{this.browserReleasing=!1}}async run(id2,action,data2,operation,transport="extension"){if(this.browserReleasing)throw new Error("BROWSER_CONTROL_RELEASING");let generation=id2?this.assertActive(id2).generation:void 0,tabs=new Set;typeof data2.tabId=="number"&&tabs.add(data2.tabId);for(let tab of data2.tabIds??[])typeof tab=="number"&&tabs.add(tab);typeof data2.openerTabId=="number"&&tabs.add(data2.openerTabId);let steps=action==="run_actions"?data2.actions:[{action,data:data2}];if(action==="run_actions"){validateActionBatch(data2);for(let step of data2.actions??[]){typeof step.data?.tabId=="number"&&tabs.add(step.data.tabId);for(let tab of step.data?.tabIds??[])typeof tab=="number"&&tabs.add(tab);typeof step.data?.openerTabId=="number"&&tabs.add(step.data.openerTabId)}}let opensPage=steps.some(step=>step.action==="tab_open"),changesSharedSettings=steps.some(step=>["set_rule","set_cookie"].includes(step.action)||step.action==="set_app_profile"&&transport!=="cdp"&&step.data?.mtopEnv!==void 0),assertSharedResources=()=>{if(action==="run_actions"&&!id2&&this.list().length&&steps.some(step=>["tab_open","browser_close"].includes(step.action)))throw new Error("ACTIVE_CONTROL_SESSIONS: open pages outside run_actions while sessions are active");if(changesSharedSettings&&this.list().some(record5=>record5.sessionId!==id2))throw new Error("BROWSER_RESOURCE_CONFLICT: use an isolated browser to change shared settings");if(data2.closeExisting&&!id2&&this.list().length)throw new Error("ACTIVE_CONTROL_SESSIONS")};assertSharedResources();for(let tab of tabs){if(tab<0)continue;let owner=this.owners.get(tab);if(owner&&owner!==id2)throw new Error("TAB_CONTROLLED_BY_SESSION")}let unlock,tail=new Promise(resolve16=>{unlock=resolve16}),runtimeTransport=action==="page_runtime",predecessors=runtimeTransport?[]:[...tabs].map(tab=>this.queues.get(tab)).filter(Boolean);if(!runtimeTransport&&this.queues.has(BROWSER_QUEUE)&&predecessors.push(this.queues.get(BROWSER_QUEUE)),(changesSharedSettings||action==="page_download"||opensPage)&&(predecessors.push(...this.queues.values()),tabs.add(BROWSER_QUEUE)),!runtimeTransport)for(let tab of tabs)this.queues.set(tab,tail);let promise2=(async()=>{try{await Promise.all(predecessors),id2&&this.assertActive(id2,generation),assertSharedResources();for(let tab of tabs){let owner=this.owners.get(tab);if(owner&&owner!==id2)throw new Error("TAB_CONTROLLED_BY_SESSION");id2&&tab>=0&&this.claim(id2,tab,"attached")}return await operation()}finally{unlock();for(let tab of tabs)this.queues.get(tab)===tail&&this.queues.delete(tab)}})(),pending=this.pending.get(id2)??new Set;pending.add(promise2),this.pending.set(id2,pending);try{return await promise2}finally{pending.delete(promise2),pending.size||this.pending.delete(id2)}}async waitForIdle(id2){await Promise.allSettled([...this.pending.get(id2)??[]])}assertStep(id2,generation){this.assertActive(id2,generation)}recordResult(id2,action,result,data2){action==="tab_open"&&typeof result?.tabId=="number"&&this.claim(id2,result.tabId,result.opened===!0?"created":"attached");for(let tab of result?.observation?.openedTabs??[])typeof tab.tabId=="number"&&this.claim(id2,tab.tabId,"created");let target=this.require(id2).tabs.find(tab=>tab.tabId===(result?.tabId??data2?.tabId));if(target&&typeof result?.title=="string"&&(target.title=result.title),target&&typeof result?.url=="string"&&(target.url=result.url),action==="tab_close"&&typeof data2?.tabId=="number"&&(this.owners.delete(data2.tabId),this.require(id2).tabs=this.require(id2).tabs.filter(tab=>tab.tabId!==data2.tabId)),action==="tab_close")for(let tab of this.require(id2).tabs)(result?.closedTabIds??[]).includes(tab.tabId)&&this.owners.delete(tab.tabId)}handoff(id2,reason){let record5=this.assertActive(id2);return record5.status="user",record5.generation+=1,record5.reason=reason,this.info(id2)}async resume(id2,cleanup=async()=>{}){let record5=this.require(id2);if(record5.status!=="user")throw new Error("Session is not waiting for the user");if(this.resuming.has(id2))throw new Error("CONTROL_SESSION_RESUMING");this.resuming.add(id2);try{return await this.waitForIdle(id2),await cleanup(),record5.status="active",record5.reason=void 0,record5.generation+=1,this.info(id2)}finally{this.resuming.delete(id2)}}async release(id2,params,cleanup){let record5=this.require(id2);if(this.resuming.has(id2))throw new Error("CONTROL_SESSION_RESUMING");if(record5.status==="released")return this.info(id2);if(record5.status==="releasing")throw new Error("CONTROL_SESSION_RELEASING");let previous=record5.status;record5.status="releasing",record5.generation+=1,await Promise.allSettled([...this.pending.get(id2)??[]]);let tabs=record5.tabs.map(tab=>tab.tabId),keep=new Set(params.keepTabIds??[]),close=params.closeCreatedTabs?record5.tabs.filter(tab=>tab.source==="created"&&!keep.has(tab.tabId)).map(tab=>tab.tabId):[];try{await cleanup(tabs,close);for(let tab of tabs)this.owners.get(tab)===id2&&this.owners.delete(tab);record5.status="released";let released=[...this.sessions.values()].filter(session=>session.status==="released"&&session.sessionId!==id2);for(let old of released.slice(0,Math.max(0,released.length-99)))this.sessions.delete(old.sessionId)}catch(error62){throw record5.status=previous,error62}return this.info(id2)}}}});import{rmSync as rmSync14}from"node:fs";import{randomUUID as randomUUID19}from"node:crypto";import{mkdir as mkdir2,open as open4,rm as rm3,stat as stat3,writeFile}from"node:fs/promises";import path14 from"node:path";import os5 from"node:os";var MAX_BYTES,ARTIFACT_CHUNK_BYTES,BrowserArtifactStore,init_browser_artifacts=__esm({"src/browser-artifacts.ts"(){"use strict";MAX_BYTES=256*1024*1024,ARTIFACT_CHUNK_BYTES=256*1024,BrowserArtifactStore=class{constructor(root=path14.join(os5.tmpdir(),`mearl-artifacts-${process.pid}-${randomUUID19()}`)){this.root=root}root;files=new Map;directory;sweeper;async create(filename,sessionId){if(typeof filename!="string"||!filename||[".",".."].includes(filename)||/[\\/]/.test(filename)||filename.length>255)throw new Error("Invalid artifact filename");this.sweeper||(this.sweeper=setInterval(()=>{for(let[id2,file3]of this.files)!file3.sessionId&&!file3.writing&&Date.now()-file3.accessedAt>3600*1e3&&this.remove(id2).catch(()=>{})},6e4),this.sweeper.unref()),await mkdir2(this.root,{recursive:!0,mode:448}),this.directory=this.root;let artifactId=randomUUID19(),directory=path14.join(this.root,artifactId);await mkdir2(directory,{mode:448});let file2={artifactId,filename,bytes:0,location:"browser",path:path14.join(directory,filename),sessionId,ready:!1,accessedAt:Date.now()};return await writeFile(file2.path,"",{mode:384}),this.files.set(artifactId,file2),this.info(file2)}async importFile(filename,sourcePath,sessionId){let source=await open4(sourcePath,"r"),id2;try{let metadata=await source.stat();if(!metadata.isFile()||metadata.size>MAX_BYTES)throw new Error("Download is unavailable or exceeds 256 MiB");id2=(await this.create(filename,sessionId)).artifactId;let file2=this.require(id2,sessionId),target=await open4(file2.path,"w"),copied=0;try{for await(let chunk of source.createReadStream({autoClose:!1})){if(copied+=chunk.length,copied>MAX_BYTES)throw new Error("Download exceeds 256 MiB");let written=0;for(;written<chunk.length;){let result=await target.write(chunk,written,chunk.length-written);if(!result.bytesWritten)throw new Error("Download import made no progress");written+=result.bytesWritten}}}finally{await target.close()}if(copied!==metadata.size)throw new Error("Download changed during import");return file2.bytes=(await stat3(file2.path)).size,file2.ready=!0,this.info(file2)}catch(error62){throw id2&&await this.remove(id2,sessionId),error62}finally{await source.close()}}require(id2,sessionId){let file2=this.files.get(id2);if(!file2||file2.sessionId!==void 0&&file2.sessionId!==sessionId)throw new Error("ARTIFACT_NOT_FOUND");return file2.accessedAt=Date.now(),file2}info(file2){return{artifactId:file2.artifactId,filename:file2.filename,bytes:file2.bytes,location:"browser"}}async write(id2,offset2,base643,sessionId){let file2=this.require(id2,sessionId);if(file2.ready||file2.writing||offset2!==file2.bytes)throw new Error("Invalid artifact write offset or completed transfer");if(typeof base643!="string"||base643.length>Math.ceil(ARTIFACT_CHUNK_BYTES/3)*4||base643.length%4!==0||!/^[A-Za-z0-9+/]*={0,2}$/.test(base643))throw new Error("Invalid artifact chunk");let chunk=Buffer.from(base643,"base64");if(chunk.toString("base64")!==base643)throw new Error("Invalid artifact chunk");if(file2.bytes+chunk.length>MAX_BYTES)throw new Error("Artifact exceeds 256 MiB");file2.writing=!0;try{let handle=await open4(file2.path,"r+");try{let written=0;for(;written<chunk.length;){let result=await handle.write(chunk,written,chunk.length-written,offset2+written);if(!result.bytesWritten)throw new Error("Artifact write made no progress");written+=result.bytesWritten}}finally{await handle.close()}return file2.bytes+=chunk.length,this.info(file2)}finally{file2.writing=!1}}complete(id2,bytes,sessionId){let file2=this.require(id2,sessionId);if(file2.writing||bytes!==file2.bytes)throw new Error("Artifact size mismatch");return file2.ready=!0,this.info(file2)}resolve(id2,sessionId){let file2=this.require(id2,sessionId);if(!file2.ready)throw new Error("Artifact is not ready");return file2.path}async read(id2,offset2,sessionId){let file2=this.require(id2,sessionId);if(!file2.ready||!Number.isSafeInteger(offset2)||offset2<0||offset2>file2.bytes)throw new Error("Invalid artifact read");let handle=await open4(file2.path,"r");try{let buffer=Buffer.alloc(Math.min(ARTIFACT_CHUNK_BYTES,file2.bytes-offset2)),result=await handle.read(buffer,0,buffer.length,offset2);return{base64:buffer.subarray(0,result.bytesRead).toString("base64"),bytes:result.bytesRead,totalBytes:file2.bytes}}finally{await handle.close()}}async remove(id2,sessionId){let file2=this.require(id2,sessionId);await rm3(path14.dirname(file2.path),{recursive:!0,force:!0}),this.files.delete(id2)}async release(sessionId,keep=[]){let retain=new Set(keep);for(let[id2,file2]of this.files)file2.sessionId===sessionId&&(retain.has(id2)?(file2.sessionId=void 0,file2.accessedAt=Date.now()):await this.remove(id2,sessionId))}disposeSync(){this.sweeper&&clearInterval(this.sweeper),this.directory&&rmSync14(this.directory,{recursive:!0,force:!0}),this.files.clear()}async dispose(){this.sweeper&&clearInterval(this.sweeper),this.directory&&await rm3(this.directory,{recursive:!0,force:!0}),this.files.clear()}}}});var ControlSessionManager,init_control_session_manager=__esm({"src/control-session-manager.ts"(){"use strict";init_dist5();init_control_session();init_browser_artifacts();ControlSessionManager=class{constructor(dependencies){this.dependencies=dependencies;this.registry=new ControlSessionRegistry(dependencies.browserId)}dependencies;registry;artifacts=new BrowserArtifactStore;activityQueues=new Map;async withActivity(id2,operation){let pending=(this.activityQueues.get(id2)??Promise.resolve()).catch(()=>{}).then(operation);this.activityQueues.set(id2,pending);try{return await pending}finally{this.activityQueues.get(id2)===pending&&this.activityQueues.delete(id2)}}async closeTabs(tabs,transport,sessionId){for(let tabId of tabs)try{let result=await this.dependencies.invoke("tab_close",{tabId},transport);this.registry.recordResult(sessionId,"tab_close",result,{tabId})}catch(error62){let current2=await this.dependencies.invoke("tab_list",{},transport);if(!Array.isArray(current2.tabs)||current2.tabs.some(tab=>(tab.tabId??tab.id)===tabId))throw error62;this.registry.recordResult(sessionId,"tab_close",{},{tabId})}}async userControl(id2,operation,reason){if(operation==="release")return await this.invoke("browser_release",{},id2),this.registry.info(id2);operation==="resume"&&await this.activityQueues.get(id2)?.catch(()=>{});let current2=this.registry.info(id2),info=operation==="resume"?await this.registry.resume(id2,()=>this.dependencies.cleanup(current2.tabs.map(tab=>tab.tabId),current2.transport,!0)):current2.status==="user"?current2:this.registry.handoff(id2,reason);return this.dependencies.notify(),operation==="handoff"?(await this.withActivity(id2,async()=>{await this.dependencies.deactivate?.(this.registry.info(id2).tabs.map(tab=>tab.tabId),current2.transport)}),this.registry.info(id2)):info}async invoke(action,data2,sessionId,requestedTransport,origin="local"){if(data2&&(Object.keys(data2).some(key=>key.startsWith("__mearl"))||(data2.actions??[]).some(step=>Object.keys(step.data??{}).some(key=>key.startsWith("__mearl")))))throw new Error("Internal session fields are reserved");validateRequiredActionTabId(action,data2);let created=sessionId==="new";if(sessionId==="new"){if(!["tab_open","page_snapshot","page_screenshot"].includes(action))throw new Error("A new session requires tab_open, page_snapshot or page_screenshot");sessionId=this.registry.create(requestedTransport??this.dependencies.transport()).sessionId}let info=sessionId?this.registry.info(sessionId):void 0,transport=info?.transport??requestedTransport??this.dependencies.transport();if(requestedTransport&&transport!==requestedTransport)throw new Error("A session cannot change transport");if(action==="browser_control"){if(!sessionId||!["handoff","resume"].includes(data2.operation))throw new Error("browser_control requires --session and handoff/resume");if(data2.operation==="resume")return{session:await this.userControl(sessionId,"resume")};if(data2.tabId!==void 0&&!info.tabs.some(tab=>tab.tabId===data2.tabId))throw new Error("TAB_NOT_IN_CONTROL_SESSION");return{session:await this.userControl(sessionId,"handoff",data2.reason)}}if(action==="browser_release"&&sessionId){let params=data2;return await this.registry.release(sessionId,params,async(tabs,close)=>{await this.dependencies.cleanup(tabs,transport,params.preserveEnvironment!==!1),await this.closeTabs(close,transport,sessionId),await this.artifacts.release(sessionId,params.keepArtifactIds)}),this.dependencies.notify(),{released:!0,hadActiveControl:!0,transports:[transport],affectedTabIds:info.tabs.map(tab=>tab.tabId),session:this.registry.state(sessionId)}}if((action==="browser_release"||action==="browser_close")&&this.registry.assertBrowserRelease(),(action==="browser_release"||action==="browser_close")&&!sessionId)return this.registry.releaseBrowser(()=>this.dependencies.invoke(action,data2,transport));let performStep=async(name,payload,batch=!1)=>{if(name==="tab_open"&&(sessionId&&payload.closeExisting&&(await this.closeTabs(this.registry.info(sessionId).tabs.filter(tab=>tab.source==="created").map(tab=>tab.tabId),transport,sessionId),payload={...payload,closeExisting:!1}),payload={...payload,__mearlBlockedTabIds:this.registry.blockedTabs(sessionId)}),name==="page_upload"&&payload.files){if(payload.filePaths)throw new Error("Use files or filePaths, not both");payload={...payload,filePaths:payload.files.map(file2=>this.artifacts.resolve(file2.artifactId,sessionId))},delete payload.files}if(batch){if(transport==="provider"){let result4=await this.dependencies.invoke(name,{...payload,__mearlControlSource:origin},transport);return sessionId&&this.registry.recordResult(sessionId,name,result4,payload),result4?.action?.success===!1?{...result4.action,success:!1}:result4?.success===!1?{...result4,success:!1}:{success:!0,data:result4}}let result3=await this.dependencies.invoke("run_actions",{tabId:payload.tabId,actions:[{action:name,data:payload}],__mearlControlSource:origin},transport),outcome=result3.results?.[0]??{success:!1,error:result3.error??"Batch step returned no result",stage:result3.stage,attempt:result3.attempt};return sessionId&&outcome.success&&this.registry.recordResult(sessionId,name,outcome.data,payload),outcome}let result2=await this.dependencies.invoke(name,{...payload,__mearlControlSource:origin},transport);return sessionId&&this.registry.recordResult(sessionId,name,result2,payload),result2},invokeStep=(name,payload,batch=!1)=>sessionId&&name==="tab_open"?this.withActivity(sessionId,async()=>(this.registry.assertStep(sessionId,info.generation),performStep(name,payload,batch))):performStep(name,payload,batch),result;try{result=await this.registry.run(sessionId,action,data2,async()=>{if(transport==="extension"&&this.dependencies.transport()!=="extension")throw new Error("CONTROL_SESSION_TRANSPORT_UNAVAILABLE: extension is disconnected");if(action.startsWith("__artifact_")){let store=this.artifacts;switch(action){case"__artifact_init":return{artifact:await store.create(data2.filename,sessionId),browserId:this.dependencies.browserId()};case"__artifact_write":return store.write(data2.artifactId,data2.offset,data2.base64,sessionId);case"__artifact_complete":return store.complete(data2.artifactId,data2.bytes,sessionId);case"__artifact_read":return store.read(data2.artifactId,data2.offset,sessionId);case"__artifact_remove":return await store.remove(data2.artifactId,sessionId),{removed:!0};default:throw new Error("Unknown artifact operation")}}if(action==="page_download"){let downloaded=await this.dependencies.download(data2,transport,origin);try{return sessionId&&this.registry.recordResult(sessionId,"page_click",downloaded.action,data2),{download:{...await this.artifacts.importFile(downloaded.filename,downloaded.filePath,sessionId),browserId:this.dependencies.browserId()},action:downloaded.action}}finally{if(downloaded.owned){let{rm:rm5,rmdir:rmdir2}=await import("node:fs/promises");await rm5(downloaded.filePath,{force:!0}),downloaded.directory&&await rmdir2(downloaded.directory).catch(()=>{})}}}return action==="run_actions"&&sessionId?runActionBatch(data2,(name,payload)=>invokeStep(name,payload,!0),{beforeStep:()=>this.registry.assertStep(sessionId,info.generation)}):invokeStep(action,data2)},transport)}catch(error62){throw created&&sessionId&&await this.registry.release(sessionId,{},async tabs=>{await this.dependencies.cleanup(tabs,transport,!0),await this.artifacts.release(sessionId)}),this.dependencies.notify(),error62}if(sessionId&&action==="tab_list"&&Array.isArray(result.tabs)){let blocked=new Set(this.registry.blockedTabs(sessionId));result={...result,tabs:result.tabs.filter(tab=>!blocked.has(tab.tabId??tab.id))},result.count=result.tabs.length}return sessionId?(this.dependencies.notify(),{...result,session:this.registry.state(sessionId)}):result}}}});import{isAbsolute as isAbsolute10}from"node:path";import{AsyncLocalStorage as AsyncLocalStorage2}from"node:async_hooks";function identity2(browser){return`${browser.pid}:${browser.startedAt}:${browser.socketPath}`}var ProviderControlService,init_provider_control=__esm({"src/provider-control.ts"(){"use strict";init_dist5();init_control_session_manager();init_dist4();init_provider_request_timeout();ProviderControlService=class{constructor(dependencies){this.dependencies=dependencies}dependencies;deadlines=new AsyncLocalStorage2;controls=new Map;retired=new Set;retire(manager){let cleanup=Promise.all(manager.registry.list().map(session=>manager.registry.waitForIdle(session.sessionId))).then(()=>manager.artifacts.dispose());this.retired.add(cleanup),cleanup.finally(()=>this.retired.delete(cleanup)).catch(()=>{})}reap(){let browsers=this.dependencies.browsers();for(let[browserId,control]of this.controls){let browser=browsers.find(item=>item.browserId===browserId);(!browser||identity2(browser)!==control.identity)&&(this.controls.delete(browserId),this.retire(control.manager))}}browser(browserId){let browser=this.dependencies.browsers().find(item=>item.browserId===browserId);if(browser?.transport!=="provider"||!browser.providerBrowserId)throw new Error("CONTROL_SESSION_NOT_FOUND: Provider browser is unavailable");return assertProviderProtocolVersion(browser.provider?.protocolVersion,browser.provider?.id??"Provider"),browser}list(){return this.reap(),[...this.controls.values()].flatMap(control=>control.manager.registry.list())}find(sessionId){this.reap();let sessions=[...this.controls.values()].map(control=>control.manager.registry.find(sessionId)).filter(session=>session!==void 0);if(sessions.length>1)throw new Error("CONTROL_SESSION_AMBIGUOUS: multiple browsers own this id");return sessions[0]}async userControl(sessionId,operation){this.reap();for(let[browserId,control]of this.controls){try{control.manager.registry.info(sessionId)}catch{continue}if(identity2(this.browser(browserId))!==control.identity)throw new Error("CONTROL_SESSION_NOT_FOUND");return control.manager.userControl(sessionId,operation)}throw new Error("CONTROL_SESSION_NOT_FOUND")}getControl(browser){let previous=this.controls.get(browser.browserId);if(previous?.identity===identity2(browser))return previous;previous&&this.retire(previous.manager);let control={identity:identity2(browser),manager:new ControlSessionManager({browserId:()=>browser.browserId,transport:()=>"provider",invoke:async(action,payload)=>{let current2=this.browser(browser.browserId);if(identity2(current2)!==control.identity)throw new Error("CONTROL_SESSION_NOT_FOUND");let{__mearlControlSource:origin="local",__mearlBlockedTabIds:blocked,...data2}=payload;if(action==="tab_open"&&blocked?.length&&data2.reuse!=="never"){let result=await this.request(current2,"tab_list",{},origin);if(!Array.isArray(result.tabs))throw new Error("Provider did not return its current pages");if(findMatchingTabs(result.tabs,data2.url,data2.match).some(tab=>blocked.includes(tab.tabId??tab.id)))throw new Error("TAB_CONTROLLED_BY_SESSION")}return this.request(current2,action,data2,origin)},cleanup:async(tabs,_transport,preserveEnvironment)=>{preserveEnvironment||await this.clearEnvironment(browser.browserId,tabs)},download:async(data2,_transport,origin)=>{let current2=this.browser(browser.browserId);if(identity2(current2)!==control.identity)throw new Error("CONTROL_SESSION_NOT_FOUND");let result=await this.request(current2,"page_download",data2,origin);if(!result||typeof result.filename!="string"||!result.filename||typeof result.filePath!="string"||!isAbsolute10(result.filePath)||!Object.hasOwn(result,"action")||result.owned!==void 0&&typeof result.owned!="boolean")throw new Error("Provider page_download must return a completed file with filename, absolute filePath and action");return{filename:result.filename,filePath:result.filePath,action:result.action,owned:result.owned===!0}},notify:this.dependencies.notify})};return this.controls.set(browser.browserId,control),control}async request(browser,action,data2,origin,host){action==="browser_release"&&(action="browser_instances",data2={operation:"detach"});let lifecycle=action==="browser_close"?data2.deleteProfile===!0?"deleteData":"close":action==="get_browser_access_url"?"access":action==="browser_instances"?data2.operation==="sync_cookies"?"syncCookies":data2.operation:void 0;if(lifecycle&&!browser.operations?.includes(lifecycle))throw new Error(`Provider browser does not support ${lifecycle}`);if(!lifecycle&&action!=="get_versions"){if(browser.status!=="connected")throw new Error("Provider browser is not connected");if(!browser.capabilities?.actions.some(capability=>capability===action))throw new Error(`Provider browser does not support ${action}`)}let deadline=this.deadlines.getStore();return deadline!==void 0?(providerRequestTimeoutMs(action,data2,deadline),this.dependencies.request(browser,action,data2,origin,host,deadline)):this.dependencies.request(browser,action,data2,origin,host)}async clearEnvironment(browserId,tabs){let browser=this.browser(browserId),actions=new Set(browser.capabilities?.actions??[]);if(actions.has("set_mock")&&!actions.has("get_mocks"))throw new Error("Provider cannot enumerate Mock state for cleanup");let clear=async(action,data2)=>{let result=await this.request(browser,action,data2,"local");if(result?.success===!1||result?.action?.success===!1)throw new Error(result.error??result.action?.error??"Provider environment cleanup failed")};for(let tabId of tabs){if(actions.has("set_mock")){let result=await this.request(browser,"get_mocks",{tabId},"local");if(!Array.isArray(result.mocks))throw new Error("Provider did not return its Mock state");let names=new Set(result.mocks.map(mock=>mock.apiName));for(let apiName of names)await clear("set_mock",{tabId,apiName,enabled:!1})}for(let[action,data2]of[["set_app_profile",{tabId,enabled:!1,mtopEnv:"default"}],["set_device_emulation",{tabId,enabled:!1}],["set_timezone",{tabId,timezone:""}]])actions.has(action)&&await clear(action,data2)}}async invoke(browserId,action,data2={},sessionId,origin="local",host,deadline){return this.deadlines.run(deadline,async()=>{deadline!==void 0&&providerRequestTimeoutMs(action,data2,deadline),this.reap();let browser=this.browser(browserId),{manager}=this.getControl(browser);if(action==="get_versions"||action==="get_browser_access_url")return this.request(browser,action,data2,origin);if(action==="browser_instances"){if(!["start","detach","sync_cookies"].includes(data2.operation))throw new Error("Invalid browser instance operation");return manager.registry.releaseBrowser(()=>this.request(browser,action,data2,origin,host))}return manager.invoke(action,data2,sessionId,void 0,origin)})}async dispose(){await Promise.all([...this.retired,...[...this.controls.values()].map(async({manager})=>{await Promise.all(manager.registry.list().map(session=>manager.registry.waitForIdle(session.sessionId))),await manager.artifacts.dispose()})])}}}});var provider_control_host_exports={};__export(provider_control_host_exports,{runProviderControlHost:()=>runProviderControlHost});import net4 from"node:net";import{chmodSync as chmodSync2,rmSync as rmSync16}from"node:fs";import{randomUUID as randomUUID27}from"node:crypto";async function runProviderControlHost(token){let file2=providerControlHostFile(),owner=readRecord(file2);if(!owner||owner.token!==token)throw new Error("Provider control host startup ownership was lost");let socketPath=providerControlSocketPath(process.pid);if(!writeRecordIfPid(file2,owner.pid,{pid:process.pid,socketPath,token,ready:!1,protocolVersion:3}))throw new Error("Provider control host startup ownership was lost");let connections=new Set,service=new ProviderControlService({browsers:listRegisteredBrowsers,request:(browser,action,data2,origin,host,deadline)=>requestBrowserSocket(browser.socketPath,action,data2,NATIVE_HOST_VERSION,providerRequestTimeoutMs(action,data2,deadline),browser.providerBrowserId,host,{controlSource:origin}),notify:()=>{for(let browser of listRegisteredBrowsers())browser.transport==="extension"&&requestBrowserSocket(browser.socketPath,"provider_control_sessions_changed",{},NATIVE_HOST_VERSION,5e3).catch(()=>{})}}),server=net4.createServer(socket=>{connections.add(socket),socket.on("error",()=>{}),socket.once("close",()=>connections.delete(socket));let lines=new Utf8LineBuffer(16*1024*1024);socket.on("data",chunk=>{let result=lines.push(chunk);if(result.overflow)return socket.destroy();for(let line of result.lines)handle(line,socket)})});async function handle(line,socket){let id2="";try{let request=JSON.parse(line);id2=typeof request.id=="string"?request.id:randomUUID27(),assertProviderProtocolVersion(request.protocolVersion,"Provider control client");let data2=request.data??{},result;if(request.action==="__control_session_resolve")result={session:service.find(data2.sessionId)??null};else if(request.action==="browser_sessions")if(data2.operation==="list")result={sessions:service.list()};else{if(!["handoff","resume","release"].includes(data2.operation)||typeof data2.sessionId!="string"||!data2.sessionId)throw new Error("Invalid browser session operation");result={session:await service.userControl(data2.sessionId,data2.operation)}}else{if(typeof request.providerTarget!="string"||typeof request.action!="string")throw new Error("Provider browser and action are required");if(!data2||typeof data2!="object"||Array.isArray(data2))throw new Error("Invalid action payload");if(request.transport&&request.transport!=="provider")throw new Error("A session cannot change transport");result=await service.invoke(request.providerTarget,request.action,data2,request.controlSessionId,request.controlSource??"local",request.host,request.deadline)}socket.destroyed||socket.write(JSON.stringify({id:id2,success:!0,data:result})+`
1111
1111
  `)}catch(error62){socket.destroyed||socket.write(JSON.stringify({id:id2,success:!1,error:error62 instanceof Error?error62.message:String(error62)})+`
1112
1112
  `)}}try{if(await new Promise((resolve16,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.removeListener("error",reject),resolve16()})}),process.platform!=="win32"&&chmodSync2(socketPath,384),!writeRecordIfPid(file2,process.pid,{pid:process.pid,socketPath,token,ready:!0,protocolVersion:3}))throw new Error("Provider control host startup ownership was lost");await new Promise(resolve16=>{let stop=()=>{removeRecordIfPid(file2,process.pid);for(let socket of connections)socket.destroy();server.close(()=>resolve16())};process.once("SIGTERM",stop),process.once("SIGINT",stop)})}finally{removeRecordIfPid(file2,process.pid);for(let socket of connections)socket.destroy();server.close(),process.platform!=="win32"&&rmSync16(socketPath,{force:!0}),await service.dispose()}}var init_provider_control_host=__esm({"src/provider-control-host.ts"(){"use strict";init_dist();init_host();init_browser_registry();init_browser_socket_request();init_provider_control();init_socketLines();init_version2();init_dist4();init_provider_request_timeout()}});import fs17 from"node:fs";import path22 from"node:path";function resolveLauncherNodePaths(execPath){let nodePath=path22.resolve(execPath),homebrewNode=nodePath.match(/^(.*)\/Cellar\/(node(?:@\d+(?:\.\d+)*)?)\/[^/]+\/bin\/node$/);if(!homebrewNode)return[nodePath];let[,prefix,formula]=homebrewNode,stablePath=path22.join(prefix,"opt",formula,"bin","node");try{if(fs17.accessSync(stablePath,fs17.constants.X_OK),fs17.statSync(stablePath).isFile()&&fs17.realpathSync(stablePath)===fs17.realpathSync(nodePath))return[stablePath,nodePath]}catch{}return[nodePath,stablePath]}function shellQuote(value){return`'${value.replaceAll("'","'\\''")}'`}function createLauncherScript(hostDir,hostPath,hostName,execPath=process.execPath){let nodePaths=process.platform==="win32"?[path22.resolve(execPath)]:resolveLauncherNodePaths(execPath),metadataLine=`mearl-native-host-launcher: ${JSON.stringify({version:1,nodePaths,hostPath})}`;if(process.platform==="win32"){let launcherPath2=path22.join(hostDir,`${hostName}-launcher.cmd`),content2=`@echo off\r
1113
1113
  rem ${metadataLine}\r
1114
1114
  "${nodePaths[0]}" "${hostPath}" %*\r
1115
- `;return fs17.writeFileSync(launcherPath2,content2,"utf-8"),launcherPath2}let launcherPath=path22.join(hostDir,`${hostName}-launcher.sh`),content=["#!/bin/sh",`# ${metadataLine}`,`HOST_SCRIPT=${shellQuote(hostPath)}`,'if [ ! -f "$HOST_SCRIPT" ] || [ ! -r "$HOST_SCRIPT" ]; then',` printf '%s\\n' "Mearl native host: runtime script is missing or unreadable: $HOST_SCRIPT" >&2`," printf '%s\\n' 'Run npx @mearl/setup update --local to repair the installation.' >&2"," exit 1","fi",`for NODE_BIN in ${nodePaths.map(shellQuote).join(" ")}; do`,' if [ -f "$NODE_BIN" ] && [ -x "$NODE_BIN" ]; then',' PATH="${NODE_BIN%/*}${PATH:+:$PATH}"'," export PATH",' exec "$NODE_BIN" "$HOST_SCRIPT" "$@"'," fi","done",`printf '%s\\n' ${shellQuote(`Mearl native host: no executable Node.js found. Tried: ${nodePaths.join(", ")}`)} >&2`,"printf '%s\\n' 'Run mearl-native-host init with a working Node.js, then reopen the extension.' >&2","exit 127",""].join(`
1115
+ `;return fs17.writeFileSync(launcherPath2,content2,"utf-8"),launcherPath2}let launcherPath=path22.join(hostDir,`${hostName}-launcher.sh`),content=["#!/bin/sh",`# ${metadataLine}`,`HOST_SCRIPT=${shellQuote(hostPath)}`,'if [ ! -f "$HOST_SCRIPT" ] || [ ! -r "$HOST_SCRIPT" ]; then',` printf '%s\\n' "Mearl native host: runtime script is missing or unreadable: $HOST_SCRIPT" >&2`," printf '%s\\n' 'Run npx --@mearl:registry=https://registry.npmjs.org @mearl/setup update --local to repair the installation.' >&2"," exit 1","fi",`for NODE_BIN in ${nodePaths.map(shellQuote).join(" ")}; do`,' if [ -f "$NODE_BIN" ] && [ -x "$NODE_BIN" ]; then',' PATH="${NODE_BIN%/*}${PATH:+:$PATH}"'," export PATH",' exec "$NODE_BIN" "$HOST_SCRIPT" "$@"'," fi","done",`printf '%s\\n' ${shellQuote(`Mearl native host: no executable Node.js found. Tried: ${nodePaths.join(", ")}`)} >&2`,"printf '%s\\n' 'Run mearl-native-host init with a working Node.js, then reopen the extension.' >&2","exit 127",""].join(`
1116
1116
  `);return fs17.writeFileSync(launcherPath,content,"utf-8"),fs17.chmodSync(launcherPath,493),launcherPath}var init_launcher2=__esm({"src/launcher.ts"(){"use strict"}});var install_exports={};__export(install_exports,{installNativeHost:()=>installNativeHost,parseNativeHostInstallArgs:()=>parseNativeHostInstallArgs,resolveHostDir:()=>resolveHostDir,runCli:()=>runCli,uninstallNativeHost:()=>uninstallNativeHost});import fs18 from"node:fs";import path23 from"node:path";import{execFileSync as execFileSync3}from"node:child_process";import{createRequire as createRequire5}from"node:module";import{fileURLToPath as fileURLToPath5}from"node:url";function resolveHostDir(){return resolveNativeHostDirectory()}function resolveNativeHostPath(){let siblingPath=path23.join(__dirname,"index.js");if(fs18.existsSync(siblingPath))return siblingPath;try{return createRequire5(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}`;execFileSync3("reg",["add",regKey,"/ve","/t","REG_SZ","/d",manifestPath,"/f"],{stdio:"pipe"})}async function installNativeHost(options={}){let{mode="both",extensionId=DEFAULT_EXTENSION_ID,silent=!1,skipIfExists=!1}=options;if(mode==="both")return(await Promise.all(ALL_MODES.map(m=>installNativeHost({...options,mode:m})))).every(Boolean);let hostName=MEARL_NATIVE_HOST_NAMES[mode];if(!hostName)throw new Error(`Unknown mode: ${mode}. Expected 'skills' or 'mcp'.`);let log2=(...args)=>{silent||console.error(...args)};try{let hostDir=resolveHostDir();if(skipIfExists){let manifestPath2=path23.join(hostDir,`${hostName}.json`);if(fs18.existsSync(manifestPath2))return log2(`✅ Already installed: ${manifestPath2}`),!0}fs18.existsSync(hostDir)||(fs18.mkdirSync(hostDir,{recursive:!0}),log2(`✅ Created directory: ${hostDir}`));let resolvedHostPath=resolveNativeHostPath();log2(`✅ Native host path: ${resolvedHostPath}`);let launcherPath=createLauncherScript(hostDir,resolvedHostPath,hostName);log2(`✅ Launcher script: ${launcherPath}`);let manifest={name:hostName,description:"Mearl Native Messaging Bridge",path:launcherPath,type:"stdio",allowed_origins:[`chrome-extension://${extensionId}/`]},manifestPath=path23.join(hostDir,`${hostName}.json`);return fs18.writeFileSync(manifestPath,JSON.stringify(manifest,null,2)),process.platform==="win32"?(registerWindowsNativeHost(hostName,manifestPath),log2(`✅ Windows registry key created for: ${hostName}`)):fs18.chmodSync(manifestPath,420),log2(`✅ Manifest installed: ${manifestPath}`),log2(`✅ Extension ID: ${extensionId}`),log2(`✅ Host name: ${hostName}`),!0}catch(error62){return log2(`❌ Installation failed: ${error62 instanceof Error?error62.message:String(error62)}`),error62 instanceof Error&&"code"in error62&&error62.code==="EACCES"&&log2(`
1117
1117
  Permission denied. Try running with sudo.`),!1}}async function uninstallNativeHost(options={},dependencies={}){return uninstallNativeHostArtifacts(options,dependencies)}async function parseNativeHostInstallArgs(argv){let normalizedArgv=argv[0]==="--init"?["init",...argv.slice(1)]:argv[0]==="--uninstall"?["uninstall",...argv.slice(1)]:argv,operation="init",mode="both",extensionId,showHelp=!1,skipIfExists=!1,index=0;if(normalizedArgv[0]==="init"||normalizedArgv[0]==="uninstall")operation=normalizedArgv[0],index=1;else if(normalizedArgv[0]&&!normalizedArgv[0].startsWith("-"))throw new Error(`Unknown command: ${normalizedArgv[0]}`);let readValue=name=>{let argument=normalizedArgv[index];if(argument===name){let value=normalizedArgv[index+1];if(value===void 0||value.startsWith("-"))throw new Error(`argument missing for option '${name}'`);return index+=1,value}return argument?.startsWith(`${name}=`)?argument.slice(name.length+1):null};for(;index<normalizedArgv.length;index+=1){let argument=normalizedArgv[index];if(argument==="--help"||argument==="-h"){showHelp=!0;continue}if(argument==="--skip-if-exists"){skipIfExists=!0;continue}let parsedMode=readValue("--mode");if(parsedMode!==null){if(parsedMode!=="skills"&&parsedMode!=="mcp"&&parsedMode!=="both")throw new Error(`Invalid --mode: ${parsedMode}. Allowed choices are skills, mcp, and both`);mode=parsedMode;continue}let parsedExtensionId=readValue("--extension-id");if(parsedExtensionId!==null){extensionId=parsedExtensionId;continue}throw new Error(argument?.startsWith("-")?`unknown option '${argument}'`:`unexpected argument '${argument}'`)}if(operation==="uninstall"&&extensionId)throw new Error("--extension-id is only available for init");if(operation==="uninstall"&&skipIfExists)throw new Error("--skip-if-exists is only available for init");return{showHelp,uninstall:operation==="uninstall",mode,...extensionId?{extensionId}:{},skipIfExists}}function printHelp(){console.error(`Usage:
1118
1118
  mearl-native-host init [options]
@@ -1831,7 +1831,7 @@ Examples:
1831
1831
  mearl-native-host init --extension-id abcdefghijklmnopqrstuvwxyzabcdef
1832
1832
  mearl-native-host --daemon
1833
1833
  mearl-native-host --version`)}!cliArg&&process.stdin.isTTY&&(printCliHelp(),process.exit(0));var runtimeArgs={browserId:"cdp",browserHeadless:!1,browserName:"CDP",cdpPort:9222,daemon:!1,discoverCdp:!1,help:!1,skipBrowserRegistration:!1,version:!1};if(cliArgs.length>0)try{runtimeArgs=await parseNativeHostRuntimeArgs(cliArgs)}catch(error62){console.error(`Error: ${error62 instanceof Error?error62.message:String(error62)}`),printCliHelp(),process.exit(2)}runtimeArgs.version&&(console.log(NATIVE_HOST_VERSION),process.exit(0));runtimeArgs.help&&(printCliHelp(),process.exit(0));var isDaemonMode=runtimeArgs.daemon,discoverCdp=runtimeArgs.discoverCdp,skipBrowserRegistration=runtimeArgs.skipBrowserRegistration,CDP_ENDPOINT_FILE=runtimeArgs.cdpEndpointFile,CDP_PORT=runtimeArgs.cdpPort,CDP_USER_DATA_DIR=runtimeArgs.cdpUserDataDir,BROWSER_HEADLESS=runtimeArgs.browserHeadless,CDP_BROWSER_ID=runtimeArgs.browserId,CDP_BROWSER_NAME=runtimeArgs.browserName,CDP_ENDPOINT_SOURCE=cliArgs.some(argument=>["--cdp-port","--cdp-user-data-dir","--cdp-endpoint-file"].some(option=>argument===option||argument.startsWith(`${option}=`)))?"command-line":"built-in default";function describeCdpEndpoint(){return CDP_ENDPOINT_FILE?`endpoint-file (source=${CDP_ENDPOINT_SOURCE})`:`127.0.0.1:${CDP_PORT} (source=${CDP_ENDPOINT_SOURCE})`}function oneLineError(value){return value.replace(/[\r\n]+/g," ").trim().slice(0,500)}function socketPathFor(suffix){return process.platform==="win32"?`\\\\.\\pipe\\mearl-agent${suffix}`:path27.join(os11.tmpdir(),`mearl-agent${suffix}.sock`)}function canConnectInstanceSocket(socketPath){return new Promise(resolve16=>{let socket=net5.createConnection(socketPath),settled=!1,timer=setTimeout(()=>finish(!0),300);timer.unref();let finish=reachable=>{settled||(settled=!0,clearTimeout(timer),socket.destroy(),resolve16(reachable))};socket.once("connect",()=>finish(!0)),socket.once("error",error62=>finish(error62.code!=="ENOENT"&&error62.code!=="ECONNREFUSED"))})}var LEGACY_SOCKET_PATH=socketPathFor(""),INSTANCE_SOCKET_PATH=socketPathFor(`-${process.pid}`),LOG_FILE=path27.join(os11.tmpdir(),"mearl-native-host.log"),DEFAULT_TIMEOUT_MS=15e3,INVENTORY_IDLE_EXIT_MS=1e3,DISCOVERY_REQUEST_IDLE_EXIT_MS=5e3,MAX_SOCKET_BUFFER_SIZE2=64*1024*1024,extensionVersion=null,extensionRpcVersion=null,versionWarningEmitted=!1,cdpPermissionNoticeLogged=!1,EXTENSION_INSTALL_URL2="https://chromewebstore.google.com/detail/mearl/aoehhjnofngknnjefamjbplchbolghkm";function majorMinor(version3){let parts=version3.split(".");return parts.length>=2?`${parts[0]}.${parts[1]}`:version3}function extractChromeVersion(input3){let match=/Chrome\/([\d.]+)/.exec(input3);return match?match[1].split(".").slice(0,3).join("."):null}var pluginPageResults=new PluginPageResults;function createNativePluginContext(interactive,pluginScope){let send=(action,payload,timeoutMs,trusted)=>sendRequestToExtension(action,payload,timeoutMs,trusted,"local"),invokeExtension=interactive?createToolboxExtensionInvoker(send):send;return{source:"toolbox",runModel:(plugin,request,execution)=>{if(pluginScope&&plugin!==pluginScope)throw new Error("Plugin model is outside the tool scope");return callPluginModelService(plugin,{operation:"run",request},()=>createNativePluginContext(!1).invoke,execution)},invoke:(pluginAction,payload={},options={})=>{if(pluginAction==="plugin_state"||pluginAction==="plugin_model"){let plugin=pluginScope??String(payload.plugin??"");if(pluginScope&&payload.plugin!==pluginScope)throw new Error("Plugin request is outside the tool scope");return pluginAction==="plugin_state"?callPluginStateService(plugin,payload,()=>createNativePluginContext(!1).invoke):callPluginModelService(plugin,payload,()=>createNativePluginContext(!1).invoke)}if(pluginAction==="plugin_page"){let plugin=pluginScope??String(payload.plugin??"");if(pluginScope&&payload.plugin!==pluginScope)throw new Error("Plugin page is outside the tool scope");return callPluginPageService(plugin,payload,()=>createNativePluginContext(interactive).invoke,!1,interactive)}if(pluginAction==="page_eval"&&payload.args!==void 0)return invokePageEvalWithArgs(request=>invokeExtension("page_eval",request,toTimeoutMs("page_eval",request),!1),payload);if(pluginAction==="agent_chat_run")return getAgentChatManager().runTask(payload);let transfer=(action,data2,timeoutMs2)=>invokeExtension(action,data2,timeoutMs2,!0);if(pluginAction==="send_request"&&hasSendRequestFiles(payload))return sendRequestWithTransferredFiles(payload,transfer);if(pluginAction==="run_actions"&&hasRunActionsSendRequestFiles(payload))return sendRunActionsWithTransferredFiles(payload,transfer,data2=>toTimeoutMs("run_actions",data2));let timeoutMs=options.timeoutSec===void 0?toTimeoutMs(pluginAction,payload):options.timeoutSec*1e3;if(!Number.isFinite(timeoutMs)||timeoutMs<=0||timeoutMs>36e5)throw new Error("Invalid plugin request timeout");return invokeExtension(pluginAction,payload,timeoutMs,!1)}}}async function fetchCdpBrowserVersion(){try{return(await(await getCdpSession().getBrowserClient()).sendCommand("Browser.getVersion",{},5e3)).product??null}catch{return null}}async function getCurrentBrowserUserAgent(){if(extensionVersion!==null)try{let result=await sendRequestToExtension("get_browser_info",{},3e3,!0);if(result.userAgent?.trim())return result.userAgent}catch{}try{let result=await(await getCdpSession().getBrowserClient()).sendCommand("Browser.getVersion",{},5e3);if(result.userAgent?.trim())return result.userAgent}catch{}throw new Error("Could not determine the control browser user agent for userAgentMode=desktop")}function currentBrowserSupportsSandboxAccess(){return!BROWSER_HEADLESS}function resolveBrowserAccessCapability(){return currentBrowserSupportsSandboxAccess()?resolveSandboxBrowserAccessCapability():null}async function resolveBrowserAccess(){if(!resolveBrowserAccessCapability())throw new Error("The selected browser does not expose a browser access URL");return resolveSandboxBrowserAccess()}async function collectVersions(includeInstallationInfo=!1){let browserAccess=resolveBrowserAccessCapability(),info={nativeHost:NATIVE_HOST_VERSION,extension:extensionVersion,browser:null,...browserAccess?{browserAccess}:{}};if(extensionVersion!==null)try{let browserInfo=await sendRequestToExtension("get_browser_info",{},3e3,!0);browserInfo?.userAgent&&(info.browser=extractChromeVersion(browserInfo.userAgent)),browserInfo?.extensionVersion&&(info.extension=browserInfo.extensionVersion),includeInstallationInfo&&(browserInfo?.extensionId&&(info.extensionId=browserInfo.extensionId),(typeof browserInfo?.setupManagedPath=="string"||browserInfo?.setupManagedPath===null)&&(info.setupManagedPath=browserInfo.setupManagedPath))}catch{}if(!info.browser){let cdpBrowser=await fetchCdpBrowserVersion();cdpBrowser&&(info.browser=extractChromeVersion(cdpBrowser))}return info}function buildVersionWarning(clientVersion){let versions=[clientVersion?{name:"client",version:clientVersion}:null,{name:"native-host",version:NATIVE_HOST_VERSION},extensionVersion?{name:"extension",version:extensionVersion}:null].filter(Boolean);return new Set(versions.map(v=>majorMinor(v.version))).size<=1?null:["⚠️ Mearl version mismatch detected:",versions.map(v=>` - ${v.name}: ${v.version}`).join(`
1834
- `),"","This may cause unexpected behavior. To update:"," npx @mearl/setup update --local",` Browser extension: ${EXTENSION_INSTALL_URL2}`].join(`
1834
+ `),"","This may cause unexpected behavior. To update:"," npx --@mearl:registry=https://registry.npmjs.org @mearl/setup update --local",` Browser extension: ${EXTENSION_INSTALL_URL2}`].join(`
1835
1835
  `)}var pendingRequests=new Map,nativeMessageBuffer=Buffer.alloc(0),socketServer=null,legacyServer=null,inventoryExitTimer=null,cdpRegistrationTimer=null,cdpBrowserPublished=!1;function cancelInventoryExit(){inventoryExitTimer&&(clearTimeout(inventoryExitTimer),inventoryExitTimer=null)}function scheduleInventoryExit(delayMs=INVENTORY_IDLE_EXIT_MS){cancelInventoryExit(),inventoryExitTimer=setTimeout(()=>cleanupAndExit(0),delayMs),inventoryExitTimer.unref()}var cdpSession=null,cdpAutoReconnectEnabled=!0,cdpStateKey=`${CDP_BROWSER_ID}:${CDP_USER_DATA_DIR??CDP_ENDPOINT_FILE??CDP_PORT}`;function getCdpSession(){return cdpAutoReconnectEnabled=!0,cdpSession||(cdpSession=CDP_ENDPOINT_FILE?new CdpSession({targetRegistryFile:keyedConfigFile("cdp-targets",cdpStateKey),endpointResolver:async()=>{let endpoint=fs22.readFileSync(CDP_ENDPOINT_FILE,"utf8").trim(),url2=new URL(endpoint);if(url2.protocol!=="ws:"&&url2.protocol!=="wss:")throw new Error(`Unsupported CDP WebSocket protocol: ${url2.protocol}`);return url2.toString()}}):new CdpSession({port:CDP_PORT,userDataDir:CDP_USER_DATA_DIR,targetRegistryFile:keyedConfigFile("cdp-targets",cdpStateKey)}),cdpSession.onBrowserConnected(()=>{getCdpPageHost()})),cdpSession}var controlBrowserId=isDaemonMode?CDP_BROWSER_ID:"default",cdpPageHost;function getCdpPageHost(){return cdpPageHost??=new CdpPluginPageHost(getCdpSession(),(action,data2)=>callPluginPageService(String(data2.plugin??""),data2.input,()=>async(action2,payload)=>(await dispatchHostRequest({action:action2,data:payload??{},transport:"cdp",controlSource:"local"},!0)).data,action==="plugin_page_event",!1,"cdp"),{browserId:cdpStateKey})}var controlSessionManager;function getControlSessionManager(){return controlSessionManager??=new ControlSessionManager({browserId:()=>controlBrowserId,transport:()=>extensionVersion!==null?"extension":"cdp",invoke:async(action,data2,transport)=>{let{__mearlControlSource:origin,...payload}=data2;return(await dispatchHostRequest({action,data:payload,controlSource:origin??"local",transport},!0)).data},deactivate:async(tabs,transport)=>{transport==="extension"&&await sendRequestToExtension("__control_deactivate",{tabIds:tabs},3e4,!0)},cleanup:async(tabs,transport,preserveEnvironment)=>{if(transport==="extension"){let result=await sendRequestToExtension("__control_cleanup",{tabIds:tabs,preserveEnvironment},3e4,!0);if(result.released===!1)throw new Error("Session cleanup failed: "+JSON.stringify(result.failures))}else for(let tabId of tabs){if(!cdpSession?.listRegisteredTabIds().includes(tabId))continue;let page=await cdpSession.getPageSession(tabId);clearPageRefsForNavigation(page),await releaseControlledIndicator(page),preserveEnvironment||(clearCdpPageMocks(page),await dispatchCdpAction(getCdpSession(),"set_app_profile",{tabId,enabled:!1,mtopEnv:"default"},"local"),await dispatchCdpAction(getCdpSession(),"set_device_emulation",{tabId,enabled:!1},"local"),await dispatchCdpAction(getCdpSession(),"set_timezone",{tabId,timezone:""},"local"))}},download:async(data2,transport,origin)=>transport==="extension"?sendRequestToExtension("__capture_download",data2,Number(data2.timeout??3e4)+1e4,!0,normalizeControlSource(origin)):captureCdpDownload(getCdpSession(),data2,CDP_BROWSER_ID.startsWith("managed:"),()=>handleViaCdp("page_click",{...data2.trigger,tabId:data2.tabId},3e4,normalizeControlSource(origin))),notify:()=>{extensionVersion!==null&&sendToExtension({type:"control_sessions_changed"})}})}function log(...args){let msg=`[${new Date().toISOString()}] [NativeHost] ${args.join(" ")}
1836
1836
  `;try{fs22.appendFileSync(LOG_FILE,msg)}catch{}}function sendToExtension(message){let json4=JSON.stringify(message),length=Buffer.byteLength(json4,"utf-8"),header=Buffer.alloc(4);header.writeUInt32LE(length,0),process.stdout.write(header),process.stdout.write(json4)}var presetBrowserTransfer=new PresetBrowserTransfer,presetBrowserSync=Promise.resolve();function requestPresetBrowser(data2){if(extensionVersion===null)return Promise.resolve({installationRevision:null,browserRevision:null,ready:!1,settingsReady:!1,error:"EXTENSION_NOT_CONNECTED"});if(data2.operation==="status")return sendRequestToExtension("__preset_browser",data2,15e3,!0);let next=presetBrowserSync.catch(()=>{}).then(()=>sendRequestToExtension("__preset_browser",data2,12e4,!0));return presetBrowserSync=next,next}var nativeHostUpdateCoordinator=new NativeHostUpdateCoordinator({hostVersion:NATIVE_HOST_VERSION,log,runUpdate:targetVersion=>runNativeHostUpdate(targetVersion),requestRestart:()=>{restartAfterUpdate()}}),agentChatManager=null,agentSkillManager=new AgentSkillManager,presetComponentInstaller=new PresetComponentInstaller({skills:agentSkillManager}),presetInstallation=new NativePresetInstallation({request:(data2,timeoutMs)=>sendRequestToExtension("__preset_installation",data2,timeoutMs,!0),invoke:async(action,data2={})=>{if(action==="node_capabilities_reload")return nativeCapabilities.synchronize();if(action==="node_capabilities_status")return nativeCapabilities.status();if(action==="preset_browser_status")return requestPresetBrowser({operation:"status"});if(action==="preset_components_install"||action==="preset_components_status")return presetComponentInstaller[action==="preset_components_install"?"install":"status"](data2.installationRevision);throw new Error("Unsupported preset installation service")}});function getAgentChatManager(){return agentChatManager||(agentChatManager=new AgentChatManager([{id:"codex",load:async()=>{let{CodexAgentProvider:CodexAgentProvider2}=await Promise.resolve().then(()=>(init_codex(),codex_exports));return new CodexAgentProvider2(log,NATIVE_HOST_VERSION,INSTANCE_SOCKET_PATH)}},{id:"qoder",load:async()=>{let{QoderAgentProvider:QoderAgentProvider2}=await Promise.resolve().then(()=>(init_qoder_provider(),qoder_provider_exports));return new QoderAgentProvider2(log,NATIVE_HOST_VERSION)}}],event=>{sendToExtension({type:"agent_chat_event",data:event})})),agentChatManager}var agentServiceHandlers={agent_chat_pick_directory:async()=>({path:await pickWorkspaceDirectory()}),agent_chat_status:()=>getAgentChatManager().getStatus(),agent_chat_prepare:async data2=>(await getAgentChatManager().prepare(data2),{ok:!0}),agent_chat_list_sessions:data2=>getAgentChatManager().listSessions(data2),agent_chat_start:data2=>getAgentChatManager().startSession(data2),agent_chat_send:data2=>getAgentChatManager().sendMessage(data2),agent_chat_run:data2=>getAgentChatManager().runTask(data2),agent_chat_interrupt:async data2=>(await getAgentChatManager().interrupt(data2),{ok:!0}),agent_chat_close:async data2=>(await getAgentChatManager().closeSession(data2),{ok:!0}),agent_chat_events:data2=>getAgentChatManager().getEvents(data2),agent_chat_refresh:data2=>getAgentChatManager().refreshSession(data2),agent_chat_open_app:async data2=>(await getAgentChatManager().openSession(data2),{ok:!0}),agent_chat_open_workspace:async data2=>(await getAgentChatManager().openWorkspace(data2),{ok:!0}),agent_chat_respond:data2=>(getAgentChatManager().respondToRequest(data2),{ok:!0}),agent_skills_installed:async data2=>({skills:await getAgentChatManager().listSkills(data2)}),agent_skills_read:data2=>getAgentChatManager().readSkill(data2),agent_skills_install:data2=>agentSkillManager.install(data2),agent_skills_check_updates:data2=>agentSkillManager.checkUpdates(data2),agent_skills_update:data2=>agentSkillManager.update(data2),agent_skills_uninstall:data2=>agentSkillManager.uninstall(data2)};function dispatchAgentServiceAction(action,request){let handler=agentServiceHandlers[action];return Promise.resolve(handler(request))}var browserProviderCoordinator=null;function getBrowserProviderCoordinator(){if(browserProviderCoordinator)return browserProviderCoordinator;let runtimes=createBuiltinBrowserProviders({nativeHostScript:fileURLToPath6(import.meta.url),exportCookies:async domains=>extensionVersion!==null?(await sendRequestToExtension("__export_cookies",{domains},2e4,!0)).cookies??[]:cdpExportCookies(getCdpSession(),domains),log});return browserProviderCoordinator=new BrowserProviderCoordinator(runtimes,{exportCookies:async domains=>extensionVersion!==null?(await sendRequestToExtension("__export_cookies",{domains},2e4,!0)).cookies??[]:cdpExportCookies(getCdpSession(),domains),getBrowserUserAgent:getCurrentBrowserUserAgent}),browserProviderCoordinator}async function launchBrowser(data2){return getBrowserProviderCoordinator().launch(data2)}async function closeBrowser(data2){let selector=String(data2?.browser??data2?.browserId??data2?.name??"").trim();if(!selector)throw new Error("browser is required");return getBrowserProviderCoordinator().close(selector,data2?.deleteProfile===!0)}async function getManagedBrowserAccess(data2){let selector=String(data2?.browser??data2?.browserId??"").trim();if(!selector)throw new Error("browser is required");return(await getBrowserProviderCoordinator().access(selector)).browserAccess}function appendWarnings(result,warnings){let merged=[...new Set([...result.warnings??[],...warnings])];return{...result,...merged.length>0?{warnings:merged}:{}}}async function handleExtensionControlMessage(message){let{id:id2,action,data:data2={}}=message;if(isExtensionUiServiceAction(action)&&message.rpcVersion!==EXTENSION_RPC_VERSION)throw new ExtensionRpcError("PROTOCOL_MISMATCH","Update the Mearl extension and local service, then reconnect.");if(action==="preset_installation"){if(message.rpcVersion!==EXTENSION_RPC_VERSION)throw new ExtensionRpcError("PROTOCOL_MISMATCH","Update the Mearl extension and local service, then reconnect.");sendToExtension({id:id2,success:!0,data:await presetInstallation.handle(data2)});return}if(action==="preset_browser_transfer"){sendToExtension({id:id2,success:!0,data:await presetBrowserTransfer.handle(data2)});return}if(action==="preset_components_status"||action==="preset_components_install"){sendToExtension({id:id2,success:!0,data:await presetComponentInstaller[action==="preset_components_install"?"install":"status"](data2.installationRevision)});return}if(action==="node_capabilities_status"||action==="node_capabilities_reload"&&data2?.structured===!0){sendToExtension({id:id2,success:!0,data:action==="node_capabilities_status"?nativeCapabilities.status():await nativeCapabilities.synchronize()});return}if(action==="node_capabilities_reload"){await nativeCapabilities.refresh(),sendToExtension({id:id2,success:!0,data:nativeCapabilities.status()});return}if(action==="browser_sessions"){if(data2.operation==="list"){sendToExtension({id:id2,success:!0,data:{sessions:[...getControlSessionManager().registry.list(),...await listProviderControlSessions()]}});return}if(!["handoff","resume","release"].includes(data2.operation)||typeof data2.sessionId!="string"||!data2.sessionId)throw new Error("Invalid browser session operation");let session;try{getControlSessionManager().registry.info(data2.sessionId),session=await getControlSessionManager().userControl(data2.sessionId,data2.operation)}catch(error62){if(!(error62 instanceof Error)||!error62.message.startsWith("CONTROL_SESSION_NOT_FOUND"))throw error62;session=await updateProviderControlSession(data2.sessionId,data2.operation)}sendToExtension({id:id2,success:!0,data:{session}});return}if(action==="alipay_auth_code_start"){let pairing=await startAlipayAuthCode(data2.params,phase=>{try{sendToExtension({id:id2,type:"progress",data:{phase}})}catch{}});sendToExtension({id:id2,success:!0,data:pairing});return}if(action==="alipay_auth_code_wait"){let browserId=String(data2.browserId??"");try{let response=await waitAlipayAuthCode(browserId,data2.params,phase=>{try{sendToExtension({id:id2,type:"progress",data:{phase}})}catch{}});sendToExtension({id:id2,success:!0,data:response})}finally{await closeAlipayAuthCode(browserId).catch(()=>{})}return}if(action==="alipay_auth_code_close"){await closeAlipayAuthCode(String(data2.browserId??"")),sendToExtension({id:id2,success:!0,data:{}});return}if(isAgentServiceAction(action)){let result=await dispatchAgentServiceAction(action,data2);sendToExtension({id:id2,success:!0,data:result});return}if(action==="app_profile_catalog"){sendToExtension({id:id2,success:!0,data:await listInstalledAppProfiles()});return}if(action==="plugin_page_call"||action==="plugin_page_event"){try{let result=await callPluginPageService(String(data2.plugin??""),data2.input??{},()=>createNativePluginContext(!1).invoke,action==="plugin_page_event");sendToExtension({id:id2,success:!0,data:result})}catch(error62){sendToExtension({id:id2,success:!0,data:{error:{code:error62?.code,message:error62 instanceof Error?error62.message:String(error62)}}})}return}if(isToolboxServiceAction(action)){let context=createNativePluginContext(!0,String(data2?.id??"").replace(/^plugin:/,"")),result;switch(action){case"toolbox_model":{let plugin=String(data2.id??"").replace(/^plugin:/,"");if(!["capabilities","list","start"].includes(data2.operation))throw new Error("Invalid toolbox model operation");result=await callPluginModelService(plugin,{...data2.input??{},operation:data2.operation},()=>createNativePluginContext(!0).invoke);break}case"toolbox_state":{let plugin=String(data2.id??"").replace(/^plugin:/,"");if(["result_chunk","result_release"].includes(data2.operation)){result=pluginPageResults.read(plugin,data2.operation,data2.input??{});break}if(!["get","get-many","list","transact"].includes(data2.operation))throw new Error("Invalid toolbox state operation");result=pluginPageResults.wrap(plugin,await callPluginStateService(plugin,{...data2.input??{},operation:data2.operation},()=>createNativePluginContext(!0).invoke));break}case"toolbox_page":{let plugin=String(data2.id??"").replace(/^plugin:/,"");if(["result_chunk","result_release"].includes(data2.operation)){result=pluginPageResults.read(plugin,data2.operation,data2.input??{});break}if(!["attach","get","list","send","detach","events","activation"].includes(data2.operation))throw new Error("Invalid toolbox page operation");result=pluginPageResults.wrap(plugin,await callPluginPageService(plugin,{...data2.input??{},operation:data2.operation},()=>createNativePluginContext(!0).invoke,!1,!0));break}case"toolbox_tools_list":result=await listToolboxPluginTools();break;case"toolbox_plugin_uninstall":result=await uninstallToolboxPlugin(data2?.id);break;case"toolbox_skill_set_enabled":result=setToolboxSkillEnabled(data2?.id,data2?.enabled);break;case"toolbox_tool_open":result=await openToolboxPluginTool(data2?.id,context);break;case"toolbox_tool_page_chunk":result=readToolboxPluginPageChunk(data2?.id,data2?.hash,data2?.index);break;case"toolbox_task":result=await handleToolboxTask(data2,context);break;case"toolbox_tool_invoke":result=await invokeToolboxPluginTool(data2?.id,data2?.command,data2?.input,context);break;default:{let unhandledAction=action;throw new Error(`Unknown toolbox action: ${unhandledAction}`)}}sendToExtension({id:id2,success:!0,data:result});return}if(action==="browser_list"){let providerWarnings=await ensureInstalledProvidersRunning(),inventory=await listBrowserInventory(getBrowserProviderCoordinator().providerRuntimes);sendToExtension({id:id2,success:!0,data:appendWarnings(inventory,providerWarnings)});return}if(action==="browser_providers"){let coordinator=getBrowserProviderCoordinator(),result;if(data2.operation==="list")result=coordinator.definitions();else if(data2.operation==="configure"||data2.operation==="launch_form"){if(typeof data2.provider!="string"||!data2.provider.trim())throw new Error("provider is required");result=data2.operation==="configure"?await coordinator.configure(data2.provider,data2.options):await coordinator.getLaunchForm(data2.provider,{variant:data2.variant,values:data2.values??{}})}else throw new Error("Invalid browser provider operation");sendToExtension({id:id2,success:!0,data:result});return}if(action==="browser_launch"){let result=await launchBrowser(data2);sendToExtension({id:id2,success:!0,data:result});return}if(action==="browser_close"){let result=await closeBrowser(data2);sendToExtension({id:id2,success:!0,data:result});return}if(action==="browser_instances"){if(!["start","detach","sync_cookies"].includes(data2.operation))throw new Error("Invalid browser instance operation");let selector=typeof data2.browser=="string"?data2.browser.trim():"";if(!selector)throw new Error("browser is required");let coordinator=getBrowserProviderCoordinator(),result=data2.operation==="start"?await coordinator.start(selector):data2.operation==="detach"?await coordinator.detach(selector):await coordinator.syncCookies(selector,data2.scope);sendToExtension({id:id2,success:!0,data:result});return}if(action==="get_browser_access_url"){let browserAccess=await getManagedBrowserAccess(data2);sendToExtension({id:id2,success:!0,data:{browserAccess}});return}if(action==="start_cloud_connector"){let serverUrl=data2?.serverUrl;if(!serverUrl||typeof serverUrl!="string"){sendToExtension({id:id2,success:!1,error:"serverUrl is required"});return}let result=await startCloudConnector(serverUrl);sendToExtension({id:id2,success:result.success,data:result,error:result.error});return}if(action==="stop_cloud_connector"){let serverUrl=data2?.serverUrl;if(!serverUrl||typeof serverUrl!="string"){sendToExtension({id:id2,success:!1,error:"serverUrl is required"});return}let result=stopCloudConnector(serverUrl);sendToExtension({id:id2,success:result.success,data:result,error:result.error});return}if(action==="list_cloud_connectors"){sendToExtension({id:id2,success:!0,data:listCloudConnectors2()});return}if(action==="update_setup_extension"){let result=await updateSetupManagedExtension({currentVersion:data2?.currentVersion,setupManagedPath:data2?.setupManagedPath});sendToExtension({id:id2,success:!0,data:result});return}throw new ExtensionRpcError("UNSUPPORTED_ACTION",`Unknown extension action: ${action}`)}function handleExtensionMessage(message){if(message&&message.type==="ping"){extensionRpcVersion=typeof message.rpcVersion=="number"?message.rpcVersion:null,message.version&&(extensionVersion=message.version,log(`Extension version: ${extensionVersion}, Native Host version: ${NATIVE_HOST_VERSION}`)),setAnalyticsClientId(message.analyticsClientId),controlBrowserId=typeof message.browserId=="string"?message.browserId:"default",registerBrowser({browserId:typeof message.browserId=="string"?message.browserId:"default",socketPath:INSTANCE_SOCKET_PATH,browserName:typeof message.browserName=="string"?message.browserName:"Browser",nativeHostVersion:NATIVE_HOST_VERSION,transport:"extension",extensionVersion:extensionVersion??void 0}),presetBrowserTransfer.selectedRevision(nativeCapabilities.status().installationRevision).catch(error62=>(log("Preset browser selection unavailable:",String(error62)),null)).then(presetInstallationRevision=>sendToExtension({type:"pong",timestamp:Date.now(),version:NATIVE_HOST_VERSION,rpcVersion:EXTENSION_RPC_VERSION,presetInstallationRevision,presetInstallationProtocol:PRESET_INSTALLATION_PROTOCOL})),nativeHostUpdateCoordinator.evaluate(message.version,message.checkForUpdates);return}if(message&&message.type==="browser_focus"){touchFocus();return}if(!message||typeof message!="object"||!message.id)return;let pending=pendingRequests.get(message.id);if(!pending){message.action&&handleExtensionControlMessage(message).catch(error62=>{sendToExtension({id:message.id,success:!1,error:error62 instanceof Error?error62.message:String(error62),code:extensionRpcErrorCode(error62)})});return}clearTimeout(pending.timer),pendingRequests.delete(message.id),message.success?pending.resolve(message.data):pending.reject(extensionResponseError(message))}function processNativeMessages(){for(;nativeMessageBuffer.length>=4;){let length=nativeMessageBuffer.readUInt32LE(0);if(nativeMessageBuffer.length<4+length)return;let jsonBytes=nativeMessageBuffer.subarray(4,4+length);nativeMessageBuffer=nativeMessageBuffer.subarray(4+length);try{let message=JSON.parse(jsonBytes.toString("utf-8"));handleExtensionMessage(message)}catch(error62){log("Failed to parse extension message:",String(error62))}}}function setupNativeMessageInput(){process.stdin.on("readable",()=>{let chunk;for(;(chunk=process.stdin.read())!==null;)nativeMessageBuffer=Buffer.concat([nativeMessageBuffer,chunk]),processNativeMessages()}),process.stdin.on("end",()=>{log("Extension disconnected (stdin end)"),cleanupAndExit(0)}),process.stdin.on("error",error62=>{log("stdin error:",String(error62)),cleanupAndExit(1)})}function sendRequestToExtension(action,data2,timeoutMs,trustedInternal=!1,controlSource="local"){if((trustedInternal||isHostToExtensionAction(action))&&extensionRpcVersion!==EXTENSION_RPC_VERSION)return Promise.reject(new ExtensionRpcError("PROTOCOL_MISMATCH","Update the Mearl extension and local service, then reconnect."));let id2=`${Date.now()}_${Math.random().toString(36).slice(2,10)}`;return new Promise((resolve16,reject)=>{let timer=setTimeout(()=>{pendingRequests.delete(id2),reject(new Error(`Request timeout after ${timeoutMs}ms`))},timeoutMs);pendingRequests.set(id2,{resolve:resolve16,reject,timer}),sendToExtension(createExtensionRequestMessage(id2,action,data2,trustedInternal,controlSource))})}function toTimeoutMs(action,data2){if(action==="page_runtime"&&["send","message_commit"].includes(data2?.operation)&&data2.timeoutSec!==void 0){if(typeof data2.timeoutSec!="number"||!Number.isFinite(data2.timeoutSec)||data2.timeoutSec<=0||data2.timeoutSec>300)throw new Error("Invalid page request timeout");return data2.timeoutSec*1e3}if(action==="send_request")return Number(data2&&data2.timeout?data2.timeout:3e4)+5e3;if(action==="send_mtop_request")return Number(data2&&data2.timeout?data2.timeout:1e4)+5e3;if(action==="page_wait")return Number(data2?.time??data2?.timeout??1e4)+5e3;if(action==="tab_open")return 4e4;if(action==="run_actions"){let timeoutMs=(Array.isArray(data2?.actions)?data2.actions:[{}]).reduce((total,step)=>{let stepAction=String(step?.action??"");return!stepAction||stepAction==="run_actions"?total+DEFAULT_TIMEOUT_MS:total+toTimeoutMs(stepAction,step?.data??{})},0);return Math.max(DEFAULT_TIMEOUT_MS,timeoutMs)}if(shouldObservePageAction(action,data2)){let observationMs=Math.min(Math.max(Number(data2?.observe?.timeoutMs??3e3),500),3e4),navigationGraceMs=Math.min(Math.max(Number(data2?.observe?.navigationGraceMs??1e3),0),5e3),navigationTimeoutMs=Math.min(Math.max(Number(data2?.observe?.navigationTimeoutMs??15e3),1e3),3e4);return Math.max(DEFAULT_TIMEOUT_MS,observationMs+navigationGraceMs+4e3+navigationTimeoutMs+5e3)}return DEFAULT_TIMEOUT_MS}async function dispatchHostRequest(request,managed=!1){let{action,data:data2={}}=request,controlSource=normalizeControlSource(request.controlSource);if(action==="preset_components_status"||action==="preset_components_install")return{data:await presetComponentInstaller[action==="preset_components_install"?"install":"status"](data2.installationRevision)};if(action==="preset_browser_sync"){if(typeof data2.installationRevision!="string"||!/^[a-f0-9]{64}$/.test(data2.installationRevision))throw new Error("Expected a preset installation revision");return{data:await requestPresetBrowser({operation:"sync",installationRevision:data2.installationRevision})}}if(action==="preset_browser_status")return{data:await requestPresetBrowser({operation:"status"})};if(action==="node_capabilities_status")return{data:nativeCapabilities.status()};if(action==="node_capabilities_reload"&&data2.structured===!0)return{data:await nativeCapabilities.synchronize()};if(action==="node_capabilities_reload")return await nativeCapabilities.refresh(),{data:nativeCapabilities.status()};if(action==="__control_session_resolve")return{data:{session:getControlSessionManager().registry.find(data2.sessionId)??null}};if(action==="provider_control_sessions_changed")return sendToExtension({type:"control_sessions_changed"}),{data:{refreshed:!0}};if(!managed&&(isBrowserCommandAction(action)||typeof action=="string"&&action.startsWith("__artifact_")))return{data:await getControlSessionManager().invoke(action,data2,request.controlSessionId,request.transport,controlSource)};if(action==="start_cloud_connector"){if(!data2.serverUrl||typeof data2.serverUrl!="string")throw new Error("serverUrl is required");let result=await startCloudConnector(data2.serverUrl);if(!result.success)throw new Error(result.error??"Cloud connector failed to start");return{data:result}}if(action==="stop_cloud_connector"){if(!data2.serverUrl||typeof data2.serverUrl!="string")throw new Error("serverUrl is required");let result=stopCloudConnector(data2.serverUrl);if(!result.success)throw new Error(result.error??"Cloud connector failed to stop");return{data:result}}if(action==="list_cloud_connectors")return{data:listCloudConnectors2()};if(action==="get_versions")return{data:await collectVersions(controlSource==="local")};if(action==="get_browser_access_url")return{data:{browserAccess:data2.browser?await getManagedBrowserAccess(data2):await resolveBrowserAccess()}};if(isPrivateExtensionAction(action))throw new Error("Internal action is not available to clients");if(action==="agent_chat_run")return{data:await getAgentChatManager().runTask(data2)};if(action==="browser_list"){discoverCdp&&cancelInventoryExit();let providerWarnings=await ensureInstalledProvidersRunning(),shouldDiscover=isDaemonMode&&!skipBrowserRegistration;discoverCdp&&CDP_BROWSER_ID==="cdp"&&await retireUnreachableBrowserRecord(CDP_BROWSER_ID,canConnectInstanceSocket);let discoveryProbeError,discovered=shouldDiscover?await ensureDiscoverableCdpBrowser({isPublished:()=>cdpBrowserPublished,isAvailable:async()=>{let probe=await getCdpSession().probeAvailability();return discoveryProbeError=probe.error?oneLineError(probe.error):void 0,log(`CDP discovery probe ${describeCdpEndpoint()} -> ${probe.available?"ok":`fail (${discoveryProbeError||"unknown error"})`}`),probe.available},publish:publishDaemonBrowser,monitor:monitorConnectedDaemonBrowser}):!1,inventory=await listBrowserInventory(getBrowserProviderCoordinator().providerRuntimes),registeredCdpAvailable=inventory.browsers.some(browser=>browser.browserId===CDP_BROWSER_ID&&browser.transport==="cdp"&&browser.status==="connected"),discoveryWarnings=shouldDiscover&&!discovered&&!registeredCdpAvailable?[`CDP discovery probe ${describeCdpEndpoint()} failed: ${discoveryProbeError||"unknown error"}`]:[],inventoryData=appendWarnings(inventory,[...providerWarnings,...discoveryWarnings]),closeConnection=skipBrowserRegistration||discoverCdp&&!discovered;return closeConnection&&scheduleInventoryExit(),{data:inventoryData,closeConnection}}if(action==="browser_close")return{data:await closeBrowser(data2)};if(action==="browser_launch")return{data:await launchBrowser(data2)};if(action==="browser_release"){let startedAt2=Date.now(),affectedTabIds=new Set,transports=[],failures=[],released=!0,hadActiveControl=!1;try{let releaseErrors=[];if(extensionVersion!==null)try{let result=await sendRequestToExtension(action,data2,toTimeoutMs(action,data2));released=released&&result?.released!==!1,hadActiveControl=hadActiveControl||result?.hadActiveControl===!0,result?.hadActiveControl&&transports.push("extension");for(let tabId of result?.affectedTabIds??[])affectedTabIds.add(tabId);Array.isArray(result?.failures)&&failures.push(...result.failures)}catch(error62){releaseErrors.push(`extension: ${error62 instanceof Error?error62.message:String(error62)}`)}if(cdpSession){let session=cdpSession;cdpSession=null;try{let result=await releaseCdpControl(session);released=released&&result.released,hadActiveControl=hadActiveControl||result.hadActiveControl,result.hadActiveControl&&transports.push("cdp");for(let tabId of result.affectedTabIds)affectedTabIds.add(tabId)}catch(error62){session.close(),releaseErrors.push(`cdp: ${error62 instanceof Error?error62.message:String(error62)}`)}}if(cdpAutoReconnectEnabled=!1,releaseErrors.length>0)throw new Error(`Failed to fully release browser control (${releaseErrors.join("; ")})`);return trackAction(action,{success:released,transport:transports.join("+")||"none",duration_ms:Date.now()-startedAt2,extension_version:extensionVersion??"not_connected"}),{data:{released,hadActiveControl,transports,affectedTabIds:[...affectedTabIds].sort((a,b)=>a-b),...failures.length?{failures}:{}}}}catch(error62){throw trackAction(action,{success:!1,transport:transports.join("+")||(extensionVersion!==null?"extension":"cdp"),duration_ms:Date.now()-startedAt2,error_code:classifyAnalyticsError(error62),extension_version:extensionVersion??"not_connected"}),error62}}if(!isExtensionBrowserAction(action)&&(typeof action!="string"||!action.startsWith("__")))throw new Error(`Unsupported action: ${String(action)}`);if(request.transport==="extension"&&extensionVersion===null)throw new Error("CONTROL_SESSION_TRANSPORT_UNAVAILABLE: extension is disconnected");let useExtension=request.transport!=="cdp"&&extensionVersion!==null,transport=useExtension?"extension":"cdp",startedAt=Date.now();try{validateRequiredActionTabId(action,data2);let result;return useExtension?action==="send_request"&&hasSendRequestFiles(data2)?result=await sendRequestWithTransferredFiles(data2,(internalAction,payload,timeoutMs)=>sendRequestToExtension(internalAction,payload,timeoutMs,!0,controlSource)):action==="run_actions"&&hasRunActionsSendRequestFiles(data2)?result=await sendRunActionsWithTransferredFiles(data2,(internalAction,payload,timeoutMs)=>sendRequestToExtension(internalAction,payload,timeoutMs,!0,controlSource),transformed=>toTimeoutMs("run_actions",transformed)):result=await sendRequestToExtension(action,data2,toTimeoutMs(action,data2),!1,controlSource):(cdpPermissionNoticeLogged||(cdpPermissionNoticeLogged=!0,log("CDP mode: domain permission checks are not enforced — all actions run without domain authorization")),result=await handleViaCdp(action,data2,toTimeoutMs(action,data2),controlSource)),trackAction(action,{success:!0,transport,duration_ms:Date.now()-startedAt,extension_version:extensionVersion??"not_connected"}),{data:result}}catch(error62){throw trackAction(action,{success:!1,transport,duration_ms:Date.now()-startedAt,error_code:classifyAnalyticsError(error62),extension_version:extensionVersion??"not_connected"}),error62}}async function handleSocketRequest(socket,line){let request;try{request=JSON.parse(line)}catch{socket.write(JSON.stringify({id:"",success:!1,error:`Invalid JSON request: ${line}`})+`
1837
1837
  `);return}let id2=request.id??"";try{let result=await dispatchHostRequest(request),response={id:id2,success:!0,data:result.data};if(!versionWarningEmitted){let warning=buildVersionWarning(request.version);warning&&(versionWarningEmitted=!0,response.versionWarning=warning)}let encoded=JSON.stringify(response)+`