@mearl/native-host 2.22.4 → 2.22.5
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 +58 -58
- package/dist/plugin-task-host.js +21 -21
- package/dist/plugin-worker.js +19 -19
- package/package.json +9 -9
package/dist/plugin-worker.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import { createRequire as __mearlCreateRequire } from 'node:module'; const require = __mearlCreateRequire(import.meta.url);
|
|
2
|
-
var __defProp=Object.defineProperty;var __getOwnPropNames=Object.getOwnPropertyNames;var __esm=(fn,res)=>function(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})};import{createHash}from"node:crypto";function normalizePluginTaskRecovery(value){if(value===void 0)return;let declaration=JSON.parse(JSON.stringify(value));if(!declaration||declaration.version!==1||!declaration.commands||typeof declaration.commands!="object"||Array.isArray(declaration.commands)||Object.keys(declaration.commands).length>32||Buffer.byteLength(JSON.stringify(declaration))>128*1024)throw new Error("Invalid taskRecovery declaration");for(let[command,definition]of Object.entries(declaration.commands)){if(!/^[a-z][a-z0-9-]*$/.test(command)||!definition||!Number.isSafeInteger(definition.checkpointVersion)||definition.checkpointVersion<1||!definition.schema||typeof definition.schema!="object"||Array.isArray(definition.schema)||definition.schema.$async)throw new Error("Invalid task checkpoint definition");if(definition.migrateFrom!==void 0){if(!Array.isArray(definition.migrateFrom)||definition.migrateFrom.length<1||definition.migrateFrom.length>16)throw new Error("Invalid checkpoint migration sources");let versions=new Set;for(let source of definition.migrateFrom){if(!source||!Number.isSafeInteger(source.version)||source.version<1||source.version>=definition.checkpointVersion||versions.has(source.version)||!source.schema||typeof source.schema!="object"||Array.isArray(source.schema)||source.schema.$async)throw new Error("Checkpoint migrations require distinct older versions and schemas");versions.add(source.version)}}}return declaration}function pluginRecoverySignature(value){return createHash("sha256").update(JSON.stringify(value,(_key,item)=>item&&typeof item=="object"&&!Array.isArray(item)?Object.fromEntries(Object.entries(item).sort(([a],[b])=>a<b?-1:a>b?1:0)):item)).digest("hex")}var init_pluginRecoveryDefinition=__esm({"../client/src/plugins/sdk/pluginRecoveryDefinition.ts"(){"use strict"}});import{createHash as createHash2}from"node:crypto";function normalizePluginState(value){if(value===void 0)return;let declaration=JSON.parse(JSON.stringify(value));if(!declaration||declaration.version!==1||!declaration.collections||Array.isArray(declaration.collections)||Object.keys(declaration.collections).length>32||Buffer.byteLength(JSON.stringify(declaration))>128*1024)throw new Error("Invalid stateStorage declaration");for(let[name,collection]of Object.entries(declaration.collections)){if(!/^[a-z][a-z0-9-]{0,63}$/.test(name)||!collection||!["installation","host","browser-session","instance"].includes(collection.scope)||!["persistent","cache","memory"].includes(collection.storage)||!Number.isSafeInteger(collection.schemaVersion)||collection.schemaVersion<1||!collection.schema||typeof collection.schema!="object"||Array.isArray(collection.schema)||collection.schema.$async)throw new Error(`Invalid state collection: ${name}`);if(["browser-session","instance"].includes(collection.scope)&&!["cache","memory"].includes(collection.storage))throw new Error("Document state requires cache or memory storage");if(collection.storage==="memory"&&!["browser-session","instance"].includes(collection.scope))throw new Error("Memory state requires a browser session or instance scope");if(collection.maxEntries!==void 0&&(!Number.isSafeInteger(collection.maxEntries)||collection.maxEntries<1||collection.maxEntries>4096))throw new Error("State maxEntries must be between 1 and 4096");if(collection.maxBytes!==void 0&&(!Number.isSafeInteger(collection.maxBytes)||collection.maxBytes<1||collection.maxBytes>(collection.storage==="memory"?128:16)*1024*1024))throw new Error("State maxBytes exceeds its storage limit");if(collection.ttlMs!==void 0&&(!Number.isSafeInteger(collection.ttlMs)||collection.ttlMs<1||collection.ttlMs>7*864e5))throw new Error("State TTL must be between 1 ms and 7 days");if(collection.storage==="persistent"&&collection.ttlMs!==void 0)throw new Error("Persistent state does not accept TTL")}return declaration}function pluginStateSignature(collection){return createHash2("sha256").update(JSON.stringify(collection,(_key,value)=>value&&typeof value=="object"&&!Array.isArray(value)?Object.fromEntries(Object.entries(value).sort(([a],[b])=>a<b?-1:a>b?1:0)):value)).digest("hex")}var init_pluginStateDefinition=__esm({"../client/src/plugins/sdk/pluginStateDefinition.ts"(){"use strict"}});function isPluginPageMatchPattern(value){return typeof value=="string"&&value.length<=2048&&pattern.test(value)}var pattern,init_plugin_pages=__esm({"../client/src/generated/plugin-pages.ts"(){"use strict";pattern=/^(https?|\*):\/\/(\*|\*\.[a-z0-9.-]+|[a-z0-9.-]+|localhost)(:\d+)?(\/[^#]*)$/i}});import{Script}from"node:vm";function normalizePluginPageRuntime(value){if(value===void 0)return;let runtime=value;if(!runtime||runtime.version!==1||!Array.isArray(runtime.matches)||!runtime.matches.length||runtime.matches.length>64||!runtime.matches.every(isPluginPageMatchPattern)||typeof runtime.code!="string"||Buffer.byteLength(runtime.code)>384*1024||Buffer.byteLength(JSON.stringify(runtime))>448*1024)throw new Error("Invalid plugin pageRuntime declaration");if(new Script(`(${runtime.code}
|
|
3
|
-
)`,{filename:"plugin-page-runtime.js"}),runtime.events!==void 0&&(!runtime.events||typeof runtime.events!="object"||Array.isArray(runtime.events)||Object.keys(runtime.events).length>32))throw new Error("Invalid page runtime events");for(let[name,event]of Object.entries(runtime.events??{}))if(!/^[a-z][a-z0-9-]{0,63}$/.test(name)||!event||!/^[a-z][a-z0-9-]*$/.test(event.command)||!event.schema||typeof event.schema!="object"||Array.isArray(event.schema)||event.policy!==void 0&&!["serial","latest","parallel"].includes(event.policy)||event.concurrency!==void 0&&(!Number.isSafeInteger(event.concurrency)||event.concurrency<1||event.concurrency>8)||event.maxPending!==void 0&&(!Number.isSafeInteger(event.maxPending)||event.maxPending<1||event.maxPending>64)||event.schema.$async)throw new Error(`Invalid page event binding: ${name}`);if(runtime.initialize!==void 0&&!/^[a-z][a-z0-9-]*$/.test(runtime.initialize))throw new Error("Invalid page runtime initialize command");return JSON.parse(JSON.stringify(runtime))}var init_pluginPageDefinition=__esm({"../client/src/plugins/sdk/pluginPageDefinition.ts"(){"use strict";init_plugin_pages()}});function record(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function invalid(path8){throw new Error(`Invalid app profile: ${path8}`)}function text(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(text)}function fields(value,required,optional,path8){(!record(value)||required.some(key=>!Object.hasOwn(value,key))||Object.keys(value).some(key=>!required.includes(key)&&!optional.includes(key)))&&invalid(path8)}function stringMap(value){return record(value)&&Object.keys(value).length<=200&&Object.values(value).every(text)}function json(value,depth=0){return depth>25?!1:value===null||typeof value=="boolean"||text(value)?!0:typeof value=="number"?Number.isFinite(value):Array.isArray(value)?value.length<=1e3&&value.every(item=>json(item,depth+1)):record(value)&&Object.entries(value).every(([key,item])=>!["__proto__","prototype","constructor"].includes(key)&&json(item,depth+1))}function validateActions(value){let arrays=["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext","noop","silent"];fields(value,["open","close","title","systemInfo","mtop","noop"],[...arrays,"responses","behaviors"],"actions");for(let key of arrays)value[key]!==void 0&&!strings(value[key])&&invalid(`actions.${key}`);value.responses!==void 0&&!record(value.responses)&&invalid("actions.responses"),value.behaviors!==void 0&&(!stringMap(value.behaviors)||!Object.values(value.behaviors).every(item=>BEHAVIORS.has(item)))&&invalid("actions.behaviors")}function validateAppProfileDefinition(value){json(value)||invalid("JSON"),JSON.stringify(value).length>65536&&invalid("definition exceeds 64 KiB"),fields(value,["name","label","appName","defaultAppVersion","uaTokens","globals","bridges","activeEvents","actions","schemes"],["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"])(!text(value[key])||!value[key])&&invalid(key);/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(value.name)||invalid("name");for(let key of["uaTokens","activeEvents","urlSyncHostSuffixes","titleBarHiddenPathnames"])value[key]!==void 0&&!strings(value[key])&&invalid(key);stringMap(value.globals)||invalid("globals"),(!Array.isArray(value.bridges)||value.bridges.length>20)&&invalid("bridges");let globals=new Set;for(let bridge of value.bridges)fields(bridge,["global","style"],["persistent"],"bridges"),(!text(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")&&invalid("bridge"),globals.add(bridge.global);if(validateActions(value.actions),value.settingsGroup!==void 0&&!["fliggy","alipay"].includes(value.settingsGroup)&&invalid("settingsGroup"),value.uaFamily!==void 0&&!["aliapp","wechatMiniProgram"].includes(value.uaFamily)&&invalid("uaFamily"),value.uaTemplate!==void 0&&(fields(value.uaTemplate,["ios","android"],[],"uaTemplate"),(!text(value.uaTemplate.ios)||!text(value.uaTemplate.android))&&invalid("uaTemplate")),value.policies!==void 0){fields(value.policies,[],["titleBar","navigatorLanguage","networkResult","languages","defaultLanguage"],"policies");let p=value.policies;p.titleBar!==void 0&&!["default","taobao","fliggy","alipay","wechat"].includes(p.titleBar)&&invalid("policies.titleBar"),p.networkResult!==void 0&&!["default","alipay"].includes(p.networkResult)&&invalid("policies.networkResult"),p.navigatorLanguage!==void 0&&typeof p.navigatorLanguage!="boolean"&&invalid("policies.navigatorLanguage"),p.languages!==void 0&&(!strings(p.languages)||!p.languages.length)&&invalid("policies.languages"),p.defaultLanguage!==void 0&&(!text(p.defaultLanguage)||p.languages&&!p.languages.includes(p.defaultLanguage))&&invalid("policies.defaultLanguage")}(!Array.isArray(value.schemes)||value.schemes.length>100)&&invalid("schemes");for(let rule of value.schemes){fields(rule,["match"],["hostSuffixes","param","useCurrentOrigin","targetPath","targetHostPrefix","targetParams"],"scheme");for(let key of["match","param","targetPath","targetHostPrefix"])rule[key]!==void 0&&!text(rule[key])&&invalid(`scheme.${key}`);rule.hostSuffixes!==void 0&&!strings(rule.hostSuffixes)&&invalid("scheme.hostSuffixes"),rule.useCurrentOrigin!==void 0&&typeof rule.useCurrentOrigin!="boolean"&&invalid("scheme.useCurrentOrigin"),rule.targetParams!==void 0&&!stringMap(rule.targetParams)&&invalid("scheme.targetParams")}if(value.settings!==void 0){(!Array.isArray(value.settings)||value.settings.length>30)&&invalid("settings");let ids=new Set;for(let setting of value.settings){if(fields(setting,["id","label","type","target"],["choices","minimum","maximum"],"setting"),(!text(setting.id)||!/^[a-z][a-zA-Z0-9-]*$/.test(setting.id)||ids.has(setting.id)||!text(setting.label)||!["select","boolean","number","text","json"].includes(setting.type))&&invalid("setting"),ids.add(setting.id),record(setting.target)&&setting.target.option!==void 0)fields(setting.target,["option"],[],"setting.target"),setting.target.option!=="language"&&invalid("setting.target.option");else{fields(setting.target,["method"],["field"],"setting.target"),(!text(setting.target.method)||!setting.target.method||["__proto__","prototype","constructor"].includes(setting.target.method)||setting.target.field!==void 0&&(!text(setting.target.field)||["__proto__","prototype","constructor"].includes(setting.target.field)))&&invalid("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))&&invalid("setting targets a structural method")}setting.choices!==void 0&&(!Array.isArray(setting.choices)||!setting.choices.length||setting.choices.some(choice=>!record(choice)||!text(choice.label)||!text(choice.value)))&&invalid("setting.choices");for(let key of["minimum","maximum"])setting[key]!==void 0&&typeof setting[key]!="number"&&invalid(`setting.${key}`);setting.type==="select"&&!Array.isArray(setting.choices)&&invalid("setting.choices required"),setting.minimum!==void 0&&setting.maximum!==void 0&&setting.minimum>setting.maximum&&invalid("setting range"),"option"in setting.target&&!["select","text"].includes(setting.type)&&invalid("setting.option type")}}for(let key of["forceH5Mtop"])value[key]!==void 0&&typeof value[key]!="boolean"&&invalid(key);for(let key of["popBeforeOpenParam","messageEvent"])value[key]!==void 0&&!text(value[key])&&invalid(key);return value.statusBarBackgroundColors!==void 0&&!stringMap(value.statusBarBackgroundColors)&&invalid("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,[required,optional]]of Object.entries(shapes))if(value[key]!==void 0){fields(value[key],required,optional,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):text(item))||invalid(`${key}.${field}`)}if(value.rootContainer!==void 0&&(fields(value.rootContainer,[],["statusBarHeightCookie"],"rootContainer"),value.rootContainer.statusBarHeightCookie!==void 0&&(fields(value.rootContainer.statusBarHeightCookie,["name"],["domain","path"],"rootContainer.statusBarHeightCookie"),Object.values(value.rootContainer.statusBarHeightCookie).every(text)||invalid("rootContainer.statusBarHeightCookie"))),value.titleBarHostStyles!==void 0&&(!Array.isArray(value.titleBarHostStyles)||value.titleBarHostStyles.some(rule=>(fields(rule,["hostSuffix"],["titleBarBackgroundColor","statusBarBackgroundColor"],"titleBarHostStyle"),!Object.values(rule).every(text))))&&invalid("titleBarHostStyles"),value.miniProgram!==void 0){fields(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,list]of Object.entries(value.miniProgram)){(!Array.isArray(list)||list.length>100)&&invalid(`miniProgram.${key}`);for(let rule of list){fields(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":!text(item))&&invalid(`miniProgram.${key}.${field}`);key==="messageRules"&&!["stageBackData","closeAll"].includes(rule.action)&&invalid("miniProgram.messageRules.action"),key==="nativeRoutes"&&!rule.actions.every(action=>["navigateMiniProgram","subscribeMessage"].includes(action))&&invalid("miniProgram.nativeRoutes.actions")}}}}function validateAppProfileContribution(value){if(value===void 0)return;fields(value,["version","profiles"],[],"contribution"),(value.version!==1||!Array.isArray(value.profiles)||!value.profiles.length||value.profiles.length>20)&&invalid("contribution");let profiles=value.profiles.map(validateAppProfileDefinition);return JSON.stringify(profiles).length>256e3&&invalid("contribution exceeds 256 KiB"),profiles.some(profile=>profile.name.includes("/"))&&invalid("contribution names must be local identifiers"),new Set(profiles.map(profile=>profile.name)).size!==profiles.length&&invalid("duplicate profile name"),{version:1,profiles}}var BRIDGE_STYLES,APP_BRIDGE_BEHAVIORS,BEHAVIORS,init_app_profile_definition=__esm({"../client/src/generated/app-profile-definition.ts"(){"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)}});import{statSync}from"node:fs";function pluginFileVersion(path8){let stat2=statSync(path8);if(!stat2.isFile())throw new Error(`插件资源不是文件: ${path8}`);return`${stat2.dev}-${stat2.ino}-${stat2.mtimeMs}-${stat2.ctimeMs}-${stat2.size}`}var init_pluginSource=__esm({"../client/src/plugins/pluginSource.ts"(){"use strict"}});import{readFileSync,realpathSync}from"node:fs";import{basename,dirname,isAbsolute,relative,resolve}from"node:path";function loadPluginAppProfiles(entry,value){if(value===void 0)return{};if(!value||typeof value!="object"||Array.isArray(value))throw new Error("appProfiles must be an object");let declaration=value;if(!Array.isArray(declaration.profiles))throw new Error("appProfiles.profiles must be an array");let root=realpathSync(basename(dirname(entry))==="scripts"?dirname(dirname(entry)):dirname(entry)),sources={},profiles=declaration.profiles.map(profile=>{if(typeof profile!="string")return profile;if(isAbsolute(profile)||!profile.endsWith(".json"))throw new Error("Profile resource must be a relative JSON path");let reference=resolve(root,profile),file=realpathSync(reference),inside=relative(root,file);if(inside.startsWith("..")||isAbsolute(inside))throw new Error("Profile resource must stay inside the Skill directory");let version=pluginFileVersion(file),content=readFileSync(file,"utf8");if(content.length>65536)throw new Error("Profile resource exceeds 64 KiB");let parsed=JSON.parse(content);if(pluginFileVersion(reference)!==version)throw new Error("Profile resource changed during registration");return sources[reference]=version,parsed});return{appProfiles:validateAppProfileContribution({...declaration,profiles}),profileSources:sources}}var init_pluginAppProfiles=__esm({"../client/src/plugins/sdk/pluginAppProfiles.ts"(){"use strict";init_app_profile_definition();init_pluginSource()}});var BROWSER_DEVICE_PRESET_NAMES,APP_PROFILE_NAMES,TAB_ID_REQUIRED_ACTIONS,TAB_ID_REQUIRED_ACTION_SET,PAGE_ACT_ACTIONS,EXTENSION_BROWSER_ACTIONS,BROWSER_CAPABILITY_ACTIONS,init_browser_action_protocol=__esm({"../client/src/generated/browser-action-protocol.ts"(){"use strict";BROWSER_DEVICE_PRESET_NAMES=["iphone-duo-folded","iphone-duo-unfolded","iphone-17-pro","iphone-17e","pixel-11","ipad-mini-a17-pro","galaxy-s26","pura-x-max","iphone-15-pro","iphone-se","pixel-8","ipad-mini","galaxy-s23"],APP_PROFILE_NAMES=["fliggy","taobao","wechat","tmall","alipay","koubei","taobao-tj","taobao-live","xianyu","etao","eleme","damai","btrip","amap","qianwen","lingyou","didi","easybike"],TAB_ID_REQUIRED_ACTIONS=["tab_checkpoint","capture_checkpoint","get_requests","get_logs","get_events","set_mock","get_mocks","page_screenshot","tab_close","page_click","page_drag","page_type","page_scroll","page_hover","page_eval","page_inspect","page_snapshot","page_press","page_wait","page_navigate","page_upload","page_download","page_frames","set_device_emulation","set_app_profile","set_timezone","run_actions"],TAB_ID_REQUIRED_ACTION_SET=new Set(TAB_ID_REQUIRED_ACTIONS),PAGE_ACT_ACTIONS=["page_click","page_drag","page_type","page_hover","page_scroll","page_press","page_upload","page_eval"],EXTENSION_BROWSER_ACTIONS={tab_checkpoint:!0,capture_checkpoint:!0,get_requests:!0,get_logs:!0,get_events:!0,set_mock:!0,get_mocks:!0,set_rule:!0,get_rules:!0,send_request:!0,send_mtop_request:!0,browser_release:!0,page_screenshot:!0,tab_open:!0,tab_close:!0,tab_list:!0,tab_group:!0,page_click:!0,page_drag:!0,page_type:!0,page_scroll:!0,page_hover:!0,page_eval:!0,page_runtime:!0,page_inspect:!0,page_snapshot:!0,page_press:!0,page_wait:!0,page_navigate:!0,page_upload:!0,page_frames:!0,set_device_emulation:!0,set_app_profile:!0,set_timezone:!0,get_cookie:!0,set_cookie:!0,request_domain_permission:!0,run_actions:!0},BROWSER_CAPABILITY_ACTIONS={...EXTENSION_BROWSER_ACTIONS,page_download:!0}}});var CHUNK_CHARACTERS,init_pageEvalArguments=__esm({"../client/src/pageEvalArguments.ts"(){"use strict";init_browser_action_protocol();CHUNK_CHARACTERS=48*1024}});import{existsSync,lstatSync,renameSync}from"node:fs";import{join}from"node:path";function skillManifestPath(directory){for(let name of["SKILL.md",DISABLED_SKILL_MANIFEST]){let file=join(directory,name);if(existsSync(file))return file}}var DISABLED_SKILL_MANIFEST,init_skillManifest=__esm({"../client/src/plugins/skillManifest.ts"(){"use strict";DISABLED_SKILL_MANIFEST="SKILL.md.mearl-disabled"}});var CommanderError,InvalidArgumentError,init_error=__esm({"../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js"(){CommanderError=class extends Error{constructor(exitCode,code,message){super(message),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=code,this.exitCode=exitCode,this.nestedError=void 0}},InvalidArgumentError=class extends CommanderError{constructor(message){super(1,"commander.invalidArgument",message),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}}}});function humanReadableArgName(arg){let nameOutput=arg.name()+(arg.variadic===!0?"...":"");return arg.required?"<"+nameOutput+">":"["+nameOutput+"]"}var Argument,init_argument=__esm({"../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/argument.js"(){init_error();Argument=class{constructor(name,description){switch(this.description=description||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,name[0]){case"<":this.required=!0,this._name=name.slice(1,-1);break;case"[":this.required=!1,this._name=name.slice(1,-1);break;default:this.required=!0,this._name=name;break}this._name.endsWith("...")&&(this.variadic=!0,this._name=this._name.slice(0,-3))}name(){return this._name}_collectValue(value,previous){return previous===this.defaultValue||!Array.isArray(previous)?[value]:(previous.push(value),previous)}default(value,description){return this.defaultValue=value,this.defaultValueDescription=description,this}argParser(fn){return this.parseArg=fn,this}choices(values){return this.argChoices=values.slice(),this.parseArg=(arg,previous)=>{if(!this.argChoices.includes(arg))throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._collectValue(arg,previous):arg},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}}}});import{stripVTControlCharacters}from"node:util";var Help,init_help=__esm({"../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/help.js"(){init_argument();Help=class{constructor(){this.helpWidth=void 0,this.minWidthToWrap=40,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}prepareContext(contextOptions){this.helpWidth=this.helpWidth??contextOptions.helpWidth??80}visibleCommands(cmd){let visibleCommands=cmd.commands.filter(cmd2=>!cmd2._hidden),helpCommand=cmd._getHelpCommand();return helpCommand&&!helpCommand._hidden&&visibleCommands.push(helpCommand),this.sortSubcommands&&visibleCommands.sort((a,b)=>a.name().localeCompare(b.name())),visibleCommands}compareOptions(a,b){let getSortKey=option=>option.short?option.short.replace(/^-/,""):option.long.replace(/^--/,"");return getSortKey(a).localeCompare(getSortKey(b))}visibleOptions(cmd){let visibleOptions=cmd.options.filter(option=>!option.hidden),helpOption=cmd._getHelpOption();if(helpOption&&!helpOption.hidden){let removeShort=helpOption.short&&cmd._findOption(helpOption.short),removeLong=helpOption.long&&cmd._findOption(helpOption.long);!removeShort&&!removeLong?visibleOptions.push(helpOption):helpOption.long&&!removeLong?visibleOptions.push(cmd.createOption(helpOption.long,helpOption.description)):helpOption.short&&!removeShort&&visibleOptions.push(cmd.createOption(helpOption.short,helpOption.description))}return this.sortOptions&&visibleOptions.sort(this.compareOptions),visibleOptions}visibleGlobalOptions(cmd){if(!this.showGlobalOptions)return[];let globalOptions=[];for(let ancestorCmd=cmd.parent;ancestorCmd;ancestorCmd=ancestorCmd.parent){let visibleOptions=ancestorCmd.options.filter(option=>!option.hidden);globalOptions.push(...visibleOptions)}return this.sortOptions&&globalOptions.sort(this.compareOptions),globalOptions}visibleArguments(cmd){return cmd._argsDescription&&cmd.registeredArguments.forEach(argument=>{argument.description=argument.description||cmd._argsDescription[argument.name()]||""}),cmd.registeredArguments.find(argument=>argument.description)?cmd.registeredArguments:[]}subcommandTerm(cmd){let args=cmd.registeredArguments.map(arg=>humanReadableArgName(arg)).join(" ");return cmd._name+(cmd._aliases[0]?"|"+cmd._aliases[0]:"")+(cmd.options.length?" [options]":"")+(args?" "+args:"")}optionTerm(option){return option.flags}argumentTerm(argument){return argument.name()}longestSubcommandTermLength(cmd,helper){return helper.visibleCommands(cmd).reduce((max,command)=>Math.max(max,this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command)))),0)}longestOptionTermLength(cmd,helper){return helper.visibleOptions(cmd).reduce((max,option)=>Math.max(max,this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))),0)}longestGlobalOptionTermLength(cmd,helper){return helper.visibleGlobalOptions(cmd).reduce((max,option)=>Math.max(max,this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))),0)}longestArgumentTermLength(cmd,helper){return helper.visibleArguments(cmd).reduce((max,argument)=>Math.max(max,this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument)))),0)}commandUsage(cmd){let cmdName=cmd._name;cmd._aliases[0]&&(cmdName=cmdName+"|"+cmd._aliases[0]);let ancestorCmdNames="";for(let ancestorCmd=cmd.parent;ancestorCmd;ancestorCmd=ancestorCmd.parent)ancestorCmdNames=ancestorCmd.name()+" "+ancestorCmdNames;return ancestorCmdNames+cmdName+" "+cmd.usage()}commandDescription(cmd){return cmd.description()}subcommandDescription(cmd){return cmd.summary()||cmd.description()}optionDescription(option){let extraInfo=[];if(option.argChoices&&extraInfo.push(`choices: ${option.argChoices.map(choice=>JSON.stringify(choice)).join(", ")}`),option.defaultValue!==void 0&&(option.required||option.optional||option.isBoolean()&&typeof option.defaultValue=="boolean")&&extraInfo.push(`default: ${option.defaultValueDescription||JSON.stringify(option.defaultValue)}`),option.presetArg!==void 0&&option.optional&&extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`),option.envVar!==void 0&&extraInfo.push(`env: ${option.envVar}`),extraInfo.length>0){let extraDescription=`(${extraInfo.join(", ")})`;return option.description?`${option.description} ${extraDescription}`:extraDescription}return option.description}argumentDescription(argument){let extraInfo=[];if(argument.argChoices&&extraInfo.push(`choices: ${argument.argChoices.map(choice=>JSON.stringify(choice)).join(", ")}`),argument.defaultValue!==void 0&&extraInfo.push(`default: ${argument.defaultValueDescription||JSON.stringify(argument.defaultValue)}`),extraInfo.length>0){let extraDescription=`(${extraInfo.join(", ")})`;return argument.description?`${argument.description} ${extraDescription}`:extraDescription}return argument.description}formatItemList(heading,items,helper){return items.length===0?[]:[helper.styleTitle(heading),...items,""]}groupItems(unsortedItems,visibleItems,getGroup){let result=new Map;return unsortedItems.forEach(item=>{let group=getGroup(item);result.has(group)||result.set(group,[])}),visibleItems.forEach(item=>{let group=getGroup(item);result.has(group)||result.set(group,[]),result.get(group).push(item)}),result}formatHelp(cmd,helper){let termWidth=helper.padWidth(cmd,helper),helpWidth=helper.helpWidth??80;function callFormatItem(term,description){return helper.formatItem(term,termWidth,description,helper)}let output=[`${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,""],commandDescription=helper.commandDescription(cmd);commandDescription.length>0&&(output=output.concat([helper.boxWrap(helper.styleCommandDescription(commandDescription),helpWidth),""]));let argumentList=helper.visibleArguments(cmd).map(argument=>callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)),helper.styleArgumentDescription(helper.argumentDescription(argument))));if(output=output.concat(this.formatItemList("Arguments:",argumentList,helper)),this.groupItems(cmd.options,helper.visibleOptions(cmd),option=>option.helpGroupHeading??"Options:").forEach((options,group)=>{let optionList=options.map(option=>callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)),helper.styleOptionDescription(helper.optionDescription(option))));output=output.concat(this.formatItemList(group,optionList,helper))}),helper.showGlobalOptions){let globalOptionList=helper.visibleGlobalOptions(cmd).map(option=>callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)),helper.styleOptionDescription(helper.optionDescription(option))));output=output.concat(this.formatItemList("Global Options:",globalOptionList,helper))}return this.groupItems(cmd.commands,helper.visibleCommands(cmd),sub=>sub.helpGroup()||"Commands:").forEach((commands,group)=>{let commandList=commands.map(sub=>callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)),helper.styleSubcommandDescription(helper.subcommandDescription(sub))));output=output.concat(this.formatItemList(group,commandList,helper))}),output.join(`
|
|
4
|
-
`)}displayWidth(str){return
|
|
2
|
+
var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __require=(x=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(x,{get:(a,b)=>(typeof require<"u"?require:a)[b]}):x)(function(x){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+x+'" is not supported')});var __esm=(fn,res)=>function(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __commonJS=(cb,mod)=>function(){return mod||(0,cb[__getOwnPropNames(cb)[0]])((mod={exports:{}}).exports,mod),mod.exports};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod));import{createHash}from"node:crypto";function normalizePluginTaskRecovery(value){if(value===void 0)return;let declaration=JSON.parse(JSON.stringify(value));if(!declaration||declaration.version!==1||!declaration.commands||typeof declaration.commands!="object"||Array.isArray(declaration.commands)||Object.keys(declaration.commands).length>32||Buffer.byteLength(JSON.stringify(declaration))>128*1024)throw new Error("Invalid taskRecovery declaration");for(let[command,definition]of Object.entries(declaration.commands)){if(!/^[a-z][a-z0-9-]*$/.test(command)||!definition||!Number.isSafeInteger(definition.checkpointVersion)||definition.checkpointVersion<1||!definition.schema||typeof definition.schema!="object"||Array.isArray(definition.schema)||definition.schema.$async)throw new Error("Invalid task checkpoint definition");if(definition.migrateFrom!==void 0){if(!Array.isArray(definition.migrateFrom)||definition.migrateFrom.length<1||definition.migrateFrom.length>16)throw new Error("Invalid checkpoint migration sources");let versions=new Set;for(let source of definition.migrateFrom){if(!source||!Number.isSafeInteger(source.version)||source.version<1||source.version>=definition.checkpointVersion||versions.has(source.version)||!source.schema||typeof source.schema!="object"||Array.isArray(source.schema)||source.schema.$async)throw new Error("Checkpoint migrations require distinct older versions and schemas");versions.add(source.version)}}}return declaration}function pluginRecoverySignature(value){return createHash("sha256").update(JSON.stringify(value,(_key,item)=>item&&typeof item=="object"&&!Array.isArray(item)?Object.fromEntries(Object.entries(item).sort(([a],[b])=>a<b?-1:a>b?1:0)):item)).digest("hex")}var init_pluginRecoveryDefinition=__esm({"../client/src/plugins/sdk/pluginRecoveryDefinition.ts"(){"use strict"}});import{createHash as createHash2}from"node:crypto";function normalizePluginState(value){if(value===void 0)return;let declaration=JSON.parse(JSON.stringify(value));if(!declaration||declaration.version!==1||!declaration.collections||Array.isArray(declaration.collections)||Object.keys(declaration.collections).length>32||Buffer.byteLength(JSON.stringify(declaration))>128*1024)throw new Error("Invalid stateStorage declaration");for(let[name,collection]of Object.entries(declaration.collections)){if(!/^[a-z][a-z0-9-]{0,63}$/.test(name)||!collection||!["installation","host","browser-session","instance"].includes(collection.scope)||!["persistent","cache","memory"].includes(collection.storage)||!Number.isSafeInteger(collection.schemaVersion)||collection.schemaVersion<1||!collection.schema||typeof collection.schema!="object"||Array.isArray(collection.schema)||collection.schema.$async)throw new Error(`Invalid state collection: ${name}`);if(["browser-session","instance"].includes(collection.scope)&&!["cache","memory"].includes(collection.storage))throw new Error("Document state requires cache or memory storage");if(collection.storage==="memory"&&!["browser-session","instance"].includes(collection.scope))throw new Error("Memory state requires a browser session or instance scope");if(collection.maxEntries!==void 0&&(!Number.isSafeInteger(collection.maxEntries)||collection.maxEntries<1||collection.maxEntries>4096))throw new Error("State maxEntries must be between 1 and 4096");if(collection.maxBytes!==void 0&&(!Number.isSafeInteger(collection.maxBytes)||collection.maxBytes<1||collection.maxBytes>(collection.storage==="memory"?128:16)*1024*1024))throw new Error("State maxBytes exceeds its storage limit");if(collection.ttlMs!==void 0&&(!Number.isSafeInteger(collection.ttlMs)||collection.ttlMs<1||collection.ttlMs>7*864e5))throw new Error("State TTL must be between 1 ms and 7 days");if(collection.storage==="persistent"&&collection.ttlMs!==void 0)throw new Error("Persistent state does not accept TTL")}return declaration}function pluginStateSignature(collection){return createHash2("sha256").update(JSON.stringify(collection,(_key,value)=>value&&typeof value=="object"&&!Array.isArray(value)?Object.fromEntries(Object.entries(value).sort(([a],[b])=>a<b?-1:a>b?1:0)):value)).digest("hex")}var init_pluginStateDefinition=__esm({"../client/src/plugins/sdk/pluginStateDefinition.ts"(){"use strict"}});function isPluginPageMatchPattern(value){return typeof value=="string"&&value.length<=2048&&pattern.test(value)}var pattern,init_plugin_pages=__esm({"../client/src/generated/plugin-pages.ts"(){"use strict";pattern=/^(https?|\*):\/\/(\*|\*\.[a-z0-9.-]+|[a-z0-9.-]+|localhost)(:\d+)?(\/[^#]*)$/i}});import{Script}from"node:vm";function normalizePluginPageRuntime(value){if(value===void 0)return;let runtime=value;if(!runtime||runtime.version!==1||!Array.isArray(runtime.matches)||!runtime.matches.length||runtime.matches.length>64||!runtime.matches.every(isPluginPageMatchPattern)||typeof runtime.code!="string"||Buffer.byteLength(runtime.code)>384*1024||Buffer.byteLength(JSON.stringify(runtime))>448*1024)throw new Error("Invalid plugin pageRuntime declaration");if(new Script(`(${runtime.code}
|
|
3
|
+
)`,{filename:"plugin-page-runtime.js"}),runtime.events!==void 0&&(!runtime.events||typeof runtime.events!="object"||Array.isArray(runtime.events)||Object.keys(runtime.events).length>32))throw new Error("Invalid page runtime events");for(let[name,event]of Object.entries(runtime.events??{}))if(!/^[a-z][a-z0-9-]{0,63}$/.test(name)||!event||!/^[a-z][a-z0-9-]*$/.test(event.command)||!event.schema||typeof event.schema!="object"||Array.isArray(event.schema)||event.policy!==void 0&&!["serial","latest","parallel"].includes(event.policy)||event.concurrency!==void 0&&(!Number.isSafeInteger(event.concurrency)||event.concurrency<1||event.concurrency>8)||event.maxPending!==void 0&&(!Number.isSafeInteger(event.maxPending)||event.maxPending<1||event.maxPending>64)||event.schema.$async)throw new Error(`Invalid page event binding: ${name}`);if(runtime.initialize!==void 0&&!/^[a-z][a-z0-9-]*$/.test(runtime.initialize))throw new Error("Invalid page runtime initialize command");return JSON.parse(JSON.stringify(runtime))}var init_pluginPageDefinition=__esm({"../client/src/plugins/sdk/pluginPageDefinition.ts"(){"use strict";init_plugin_pages()}});function record(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function invalid(path7){throw new Error(`Invalid app profile: ${path7}`)}function text(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(text)}function fields(value,required,optional,path7){(!record(value)||required.some(key=>!Object.hasOwn(value,key))||Object.keys(value).some(key=>!required.includes(key)&&!optional.includes(key)))&&invalid(path7)}function stringMap(value){return record(value)&&Object.keys(value).length<=200&&Object.values(value).every(text)}function json(value,depth=0){return depth>25?!1:value===null||typeof value=="boolean"||text(value)?!0:typeof value=="number"?Number.isFinite(value):Array.isArray(value)?value.length<=1e3&&value.every(item=>json(item,depth+1)):record(value)&&Object.entries(value).every(([key,item])=>!["__proto__","prototype","constructor"].includes(key)&&json(item,depth+1))}function validateActions(value){let arrays=["open","close","title","navigationBar","statusBar","systemInfo","mtop","kvGet","kvSet","kvDelete","pageContext","noop","silent"];fields(value,["open","close","title","systemInfo","mtop","noop"],[...arrays,"responses","behaviors"],"actions");for(let key of arrays)value[key]!==void 0&&!strings(value[key])&&invalid(`actions.${key}`);value.responses!==void 0&&!record(value.responses)&&invalid("actions.responses"),value.behaviors!==void 0&&(!stringMap(value.behaviors)||!Object.values(value.behaviors).every(item=>BEHAVIORS.has(item)))&&invalid("actions.behaviors")}function validateAppProfileDefinition(value){json(value)||invalid("JSON"),JSON.stringify(value).length>65536&&invalid("definition exceeds 64 KiB"),fields(value,["name","label","appName","defaultAppVersion","uaTokens","globals","bridges","activeEvents","actions","schemes"],["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"])(!text(value[key])||!value[key])&&invalid(key);/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(value.name)||invalid("name");for(let key of["uaTokens","activeEvents","urlSyncHostSuffixes","titleBarHiddenPathnames"])value[key]!==void 0&&!strings(value[key])&&invalid(key);stringMap(value.globals)||invalid("globals"),(!Array.isArray(value.bridges)||value.bridges.length>20)&&invalid("bridges");let globals=new Set;for(let bridge of value.bridges)fields(bridge,["global","style"],["persistent"],"bridges"),(!text(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")&&invalid("bridge"),globals.add(bridge.global);if(validateActions(value.actions),value.settingsGroup!==void 0&&!["fliggy","alipay"].includes(value.settingsGroup)&&invalid("settingsGroup"),value.uaFamily!==void 0&&!["aliapp","wechatMiniProgram"].includes(value.uaFamily)&&invalid("uaFamily"),value.uaTemplate!==void 0&&(fields(value.uaTemplate,["ios","android"],[],"uaTemplate"),(!text(value.uaTemplate.ios)||!text(value.uaTemplate.android))&&invalid("uaTemplate")),value.policies!==void 0){fields(value.policies,[],["titleBar","navigatorLanguage","networkResult","languages","defaultLanguage"],"policies");let p=value.policies;p.titleBar!==void 0&&!["default","taobao","fliggy","alipay","wechat"].includes(p.titleBar)&&invalid("policies.titleBar"),p.networkResult!==void 0&&!["default","alipay"].includes(p.networkResult)&&invalid("policies.networkResult"),p.navigatorLanguage!==void 0&&typeof p.navigatorLanguage!="boolean"&&invalid("policies.navigatorLanguage"),p.languages!==void 0&&(!strings(p.languages)||!p.languages.length)&&invalid("policies.languages"),p.defaultLanguage!==void 0&&(!text(p.defaultLanguage)||p.languages&&!p.languages.includes(p.defaultLanguage))&&invalid("policies.defaultLanguage")}(!Array.isArray(value.schemes)||value.schemes.length>100)&&invalid("schemes");for(let rule of value.schemes){fields(rule,["match"],["hostSuffixes","param","useCurrentOrigin","targetPath","targetHostPrefix","targetParams"],"scheme");for(let key of["match","param","targetPath","targetHostPrefix"])rule[key]!==void 0&&!text(rule[key])&&invalid(`scheme.${key}`);rule.hostSuffixes!==void 0&&!strings(rule.hostSuffixes)&&invalid("scheme.hostSuffixes"),rule.useCurrentOrigin!==void 0&&typeof rule.useCurrentOrigin!="boolean"&&invalid("scheme.useCurrentOrigin"),rule.targetParams!==void 0&&!stringMap(rule.targetParams)&&invalid("scheme.targetParams")}if(value.settings!==void 0){(!Array.isArray(value.settings)||value.settings.length>30)&&invalid("settings");let ids=new Set;for(let setting of value.settings){if(fields(setting,["id","label","type","target"],["choices","minimum","maximum"],"setting"),(!text(setting.id)||!/^[a-z][a-zA-Z0-9-]*$/.test(setting.id)||ids.has(setting.id)||!text(setting.label)||!["select","boolean","number","text","json"].includes(setting.type))&&invalid("setting"),ids.add(setting.id),record(setting.target)&&setting.target.option!==void 0)fields(setting.target,["option"],[],"setting.target"),setting.target.option!=="language"&&invalid("setting.target.option");else{fields(setting.target,["method"],["field"],"setting.target"),(!text(setting.target.method)||!setting.target.method||["__proto__","prototype","constructor"].includes(setting.target.method)||setting.target.field!==void 0&&(!text(setting.target.field)||["__proto__","prototype","constructor"].includes(setting.target.field)))&&invalid("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))&&invalid("setting targets a structural method")}setting.choices!==void 0&&(!Array.isArray(setting.choices)||!setting.choices.length||setting.choices.some(choice=>!record(choice)||!text(choice.label)||!text(choice.value)))&&invalid("setting.choices");for(let key of["minimum","maximum"])setting[key]!==void 0&&typeof setting[key]!="number"&&invalid(`setting.${key}`);setting.type==="select"&&!Array.isArray(setting.choices)&&invalid("setting.choices required"),setting.minimum!==void 0&&setting.maximum!==void 0&&setting.minimum>setting.maximum&&invalid("setting range"),"option"in setting.target&&!["select","text"].includes(setting.type)&&invalid("setting.option type")}}for(let key of["forceH5Mtop"])value[key]!==void 0&&typeof value[key]!="boolean"&&invalid(key);for(let key of["popBeforeOpenParam","messageEvent"])value[key]!==void 0&&!text(value[key])&&invalid(key);return value.statusBarBackgroundColors!==void 0&&!stringMap(value.statusBarBackgroundColors)&&invalid("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,[required,optional]]of Object.entries(shapes))if(value[key]!==void 0){fields(value[key],required,optional,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):text(item))||invalid(`${key}.${field}`)}if(value.rootContainer!==void 0&&(fields(value.rootContainer,[],["statusBarHeightCookie"],"rootContainer"),value.rootContainer.statusBarHeightCookie!==void 0&&(fields(value.rootContainer.statusBarHeightCookie,["name"],["domain","path"],"rootContainer.statusBarHeightCookie"),Object.values(value.rootContainer.statusBarHeightCookie).every(text)||invalid("rootContainer.statusBarHeightCookie"))),value.titleBarHostStyles!==void 0&&(!Array.isArray(value.titleBarHostStyles)||value.titleBarHostStyles.some(rule=>(fields(rule,["hostSuffix"],["titleBarBackgroundColor","statusBarBackgroundColor"],"titleBarHostStyle"),!Object.values(rule).every(text))))&&invalid("titleBarHostStyles"),value.miniProgram!==void 0){fields(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,list]of Object.entries(value.miniProgram)){(!Array.isArray(list)||list.length>100)&&invalid(`miniProgram.${key}`);for(let rule of list){fields(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":!text(item))&&invalid(`miniProgram.${key}.${field}`);key==="messageRules"&&!["stageBackData","closeAll"].includes(rule.action)&&invalid("miniProgram.messageRules.action"),key==="nativeRoutes"&&!rule.actions.every(action=>["navigateMiniProgram","subscribeMessage"].includes(action))&&invalid("miniProgram.nativeRoutes.actions")}}}}function validateAppProfileContribution(value){if(value===void 0)return;fields(value,["version","profiles"],[],"contribution"),(value.version!==1||!Array.isArray(value.profiles)||!value.profiles.length||value.profiles.length>20)&&invalid("contribution");let profiles=value.profiles.map(validateAppProfileDefinition);return JSON.stringify(profiles).length>256e3&&invalid("contribution exceeds 256 KiB"),profiles.some(profile=>profile.name.includes("/"))&&invalid("contribution names must be local identifiers"),new Set(profiles.map(profile=>profile.name)).size!==profiles.length&&invalid("duplicate profile name"),{version:1,profiles}}var BRIDGE_STYLES,APP_BRIDGE_BEHAVIORS,BEHAVIORS,init_app_profile_definition=__esm({"../client/src/generated/app-profile-definition.ts"(){"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)}});import{statSync}from"node:fs";function pluginFileVersion(path7){let stat2=statSync(path7);if(!stat2.isFile())throw new Error(`插件资源不是文件: ${path7}`);return`${stat2.dev}-${stat2.ino}-${stat2.mtimeMs}-${stat2.ctimeMs}-${stat2.size}`}var init_pluginSource=__esm({"../client/src/plugins/pluginSource.ts"(){"use strict"}});import{readFileSync,realpathSync}from"node:fs";import{basename,dirname,isAbsolute,relative,resolve}from"node:path";function loadPluginAppProfiles(entry,value){if(value===void 0)return{};if(!value||typeof value!="object"||Array.isArray(value))throw new Error("appProfiles must be an object");let declaration=value;if(!Array.isArray(declaration.profiles))throw new Error("appProfiles.profiles must be an array");let root=realpathSync(basename(dirname(entry))==="scripts"?dirname(dirname(entry)):dirname(entry)),sources={},profiles=declaration.profiles.map(profile=>{if(typeof profile!="string")return profile;if(isAbsolute(profile)||!profile.endsWith(".json"))throw new Error("Profile resource must be a relative JSON path");let reference=resolve(root,profile),file=realpathSync(reference),inside=relative(root,file);if(inside.startsWith("..")||isAbsolute(inside))throw new Error("Profile resource must stay inside the Skill directory");let version=pluginFileVersion(file),content=readFileSync(file,"utf8");if(content.length>65536)throw new Error("Profile resource exceeds 64 KiB");let parsed=JSON.parse(content);if(pluginFileVersion(reference)!==version)throw new Error("Profile resource changed during registration");return sources[reference]=version,parsed});return{appProfiles:validateAppProfileContribution({...declaration,profiles}),profileSources:sources}}var init_pluginAppProfiles=__esm({"../client/src/plugins/sdk/pluginAppProfiles.ts"(){"use strict";init_app_profile_definition();init_pluginSource()}});var BROWSER_DEVICE_PRESET_NAMES,APP_PROFILE_NAMES,TAB_ID_REQUIRED_ACTIONS,TAB_ID_REQUIRED_ACTION_SET,PAGE_ACT_ACTIONS,EXTENSION_BROWSER_ACTIONS,BROWSER_CAPABILITY_ACTIONS,init_browser_action_protocol=__esm({"../client/src/generated/browser-action-protocol.ts"(){"use strict";BROWSER_DEVICE_PRESET_NAMES=["iphone-duo-folded","iphone-duo-unfolded","iphone-17-pro","iphone-17e","pixel-11","ipad-mini-a17-pro","galaxy-s26","pura-x-max","iphone-15-pro","iphone-se","pixel-8","ipad-mini","galaxy-s23"],APP_PROFILE_NAMES=["fliggy","taobao","wechat","tmall","alipay","koubei","taobao-tj","taobao-live","xianyu","etao","eleme","damai","btrip","amap","qianwen","lingyou","didi","easybike"],TAB_ID_REQUIRED_ACTIONS=["tab_checkpoint","capture_checkpoint","get_requests","get_logs","get_events","set_mock","get_mocks","page_screenshot","tab_close","page_click","page_drag","page_type","page_scroll","page_hover","page_eval","page_inspect","page_snapshot","page_press","page_wait","page_navigate","page_upload","page_download","page_frames","set_device_emulation","set_app_profile","set_timezone","run_actions"],TAB_ID_REQUIRED_ACTION_SET=new Set(TAB_ID_REQUIRED_ACTIONS),PAGE_ACT_ACTIONS=["page_click","page_drag","page_type","page_hover","page_scroll","page_press","page_upload","page_eval"],EXTENSION_BROWSER_ACTIONS={tab_checkpoint:!0,capture_checkpoint:!0,get_requests:!0,get_logs:!0,get_events:!0,set_mock:!0,get_mocks:!0,set_rule:!0,get_rules:!0,send_request:!0,send_mtop_request:!0,browser_release:!0,page_screenshot:!0,tab_open:!0,tab_close:!0,tab_list:!0,tab_group:!0,page_click:!0,page_drag:!0,page_type:!0,page_scroll:!0,page_hover:!0,page_eval:!0,page_runtime:!0,page_inspect:!0,page_snapshot:!0,page_press:!0,page_wait:!0,page_navigate:!0,page_upload:!0,page_frames:!0,set_device_emulation:!0,set_app_profile:!0,set_timezone:!0,get_cookie:!0,set_cookie:!0,request_domain_permission:!0,run_actions:!0},BROWSER_CAPABILITY_ACTIONS={...EXTENSION_BROWSER_ACTIONS,page_download:!0}}});var CHUNK_CHARACTERS,init_pageEvalArguments=__esm({"../client/src/pageEvalArguments.ts"(){"use strict";init_browser_action_protocol();CHUNK_CHARACTERS=48*1024}});import{existsSync,lstatSync,renameSync}from"node:fs";import{join}from"node:path";function skillManifestPath(directory){for(let name of["SKILL.md",DISABLED_SKILL_MANIFEST]){let file=join(directory,name);if(existsSync(file))return file}}var DISABLED_SKILL_MANIFEST,init_skillManifest=__esm({"../client/src/plugins/skillManifest.ts"(){"use strict";DISABLED_SKILL_MANIFEST="SKILL.md.mearl-disabled"}});var require_error=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/error.js"(exports){var CommanderError2=class extends Error{constructor(exitCode,code,message){super(message),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=code,this.exitCode=exitCode,this.nestedError=void 0}},InvalidArgumentError2=class extends CommanderError2{constructor(message){super(1,"commander.invalidArgument",message),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}};exports.CommanderError=CommanderError2;exports.InvalidArgumentError=InvalidArgumentError2}});var require_argument=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/argument.js"(exports){var{InvalidArgumentError:InvalidArgumentError2}=require_error(),Argument2=class{constructor(name,description){switch(this.description=description||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,name[0]){case"<":this.required=!0,this._name=name.slice(1,-1);break;case"[":this.required=!1,this._name=name.slice(1,-1);break;default:this.required=!0,this._name=name;break}this._name.endsWith("...")&&(this.variadic=!0,this._name=this._name.slice(0,-3))}name(){return this._name}_collectValue(value,previous){return previous===this.defaultValue||!Array.isArray(previous)?[value]:(previous.push(value),previous)}default(value,description){return this.defaultValue=value,this.defaultValueDescription=description,this}argParser(fn){return this.parseArg=fn,this}choices(values){return this.argChoices=values.slice(),this.parseArg=(arg,previous)=>{if(!this.argChoices.includes(arg))throw new InvalidArgumentError2(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._collectValue(arg,previous):arg},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}};function humanReadableArgName(arg){let nameOutput=arg.name()+(arg.variadic===!0?"...":"");return arg.required?"<"+nameOutput+">":"["+nameOutput+"]"}exports.Argument=Argument2;exports.humanReadableArgName=humanReadableArgName}});var require_help=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/help.js"(exports){var{humanReadableArgName}=require_argument(),Help2=class{constructor(){this.helpWidth=void 0,this.minWidthToWrap=40,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}prepareContext(contextOptions){this.helpWidth=this.helpWidth??contextOptions.helpWidth??80}visibleCommands(cmd){let visibleCommands=cmd.commands.filter(cmd2=>!cmd2._hidden),helpCommand=cmd._getHelpCommand();return helpCommand&&!helpCommand._hidden&&visibleCommands.push(helpCommand),this.sortSubcommands&&visibleCommands.sort((a,b)=>a.name().localeCompare(b.name())),visibleCommands}compareOptions(a,b){let getSortKey=option=>option.short?option.short.replace(/^-/,""):option.long.replace(/^--/,"");return getSortKey(a).localeCompare(getSortKey(b))}visibleOptions(cmd){let visibleOptions=cmd.options.filter(option=>!option.hidden),helpOption=cmd._getHelpOption();if(helpOption&&!helpOption.hidden){let removeShort=helpOption.short&&cmd._findOption(helpOption.short),removeLong=helpOption.long&&cmd._findOption(helpOption.long);!removeShort&&!removeLong?visibleOptions.push(helpOption):helpOption.long&&!removeLong?visibleOptions.push(cmd.createOption(helpOption.long,helpOption.description)):helpOption.short&&!removeShort&&visibleOptions.push(cmd.createOption(helpOption.short,helpOption.description))}return this.sortOptions&&visibleOptions.sort(this.compareOptions),visibleOptions}visibleGlobalOptions(cmd){if(!this.showGlobalOptions)return[];let globalOptions=[];for(let ancestorCmd=cmd.parent;ancestorCmd;ancestorCmd=ancestorCmd.parent){let visibleOptions=ancestorCmd.options.filter(option=>!option.hidden);globalOptions.push(...visibleOptions)}return this.sortOptions&&globalOptions.sort(this.compareOptions),globalOptions}visibleArguments(cmd){return cmd._argsDescription&&cmd.registeredArguments.forEach(argument=>{argument.description=argument.description||cmd._argsDescription[argument.name()]||""}),cmd.registeredArguments.find(argument=>argument.description)?cmd.registeredArguments:[]}subcommandTerm(cmd){let args=cmd.registeredArguments.map(arg=>humanReadableArgName(arg)).join(" ");return cmd._name+(cmd._aliases[0]?"|"+cmd._aliases[0]:"")+(cmd.options.length?" [options]":"")+(args?" "+args:"")}optionTerm(option){return option.flags}argumentTerm(argument){return argument.name()}longestSubcommandTermLength(cmd,helper){return helper.visibleCommands(cmd).reduce((max,command)=>Math.max(max,this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command)))),0)}longestOptionTermLength(cmd,helper){return helper.visibleOptions(cmd).reduce((max,option)=>Math.max(max,this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))),0)}longestGlobalOptionTermLength(cmd,helper){return helper.visibleGlobalOptions(cmd).reduce((max,option)=>Math.max(max,this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))),0)}longestArgumentTermLength(cmd,helper){return helper.visibleArguments(cmd).reduce((max,argument)=>Math.max(max,this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument)))),0)}commandUsage(cmd){let cmdName=cmd._name;cmd._aliases[0]&&(cmdName=cmdName+"|"+cmd._aliases[0]);let ancestorCmdNames="";for(let ancestorCmd=cmd.parent;ancestorCmd;ancestorCmd=ancestorCmd.parent)ancestorCmdNames=ancestorCmd.name()+" "+ancestorCmdNames;return ancestorCmdNames+cmdName+" "+cmd.usage()}commandDescription(cmd){return cmd.description()}subcommandDescription(cmd){return cmd.summary()||cmd.description()}optionDescription(option){let extraInfo=[];if(option.argChoices&&extraInfo.push(`choices: ${option.argChoices.map(choice=>JSON.stringify(choice)).join(", ")}`),option.defaultValue!==void 0&&(option.required||option.optional||option.isBoolean()&&typeof option.defaultValue=="boolean")&&extraInfo.push(`default: ${option.defaultValueDescription||JSON.stringify(option.defaultValue)}`),option.presetArg!==void 0&&option.optional&&extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`),option.envVar!==void 0&&extraInfo.push(`env: ${option.envVar}`),extraInfo.length>0){let extraDescription=`(${extraInfo.join(", ")})`;return option.description?`${option.description} ${extraDescription}`:extraDescription}return option.description}argumentDescription(argument){let extraInfo=[];if(argument.argChoices&&extraInfo.push(`choices: ${argument.argChoices.map(choice=>JSON.stringify(choice)).join(", ")}`),argument.defaultValue!==void 0&&extraInfo.push(`default: ${argument.defaultValueDescription||JSON.stringify(argument.defaultValue)}`),extraInfo.length>0){let extraDescription=`(${extraInfo.join(", ")})`;return argument.description?`${argument.description} ${extraDescription}`:extraDescription}return argument.description}formatItemList(heading,items,helper){return items.length===0?[]:[helper.styleTitle(heading),...items,""]}groupItems(unsortedItems,visibleItems,getGroup){let result=new Map;return unsortedItems.forEach(item=>{let group=getGroup(item);result.has(group)||result.set(group,[])}),visibleItems.forEach(item=>{let group=getGroup(item);result.has(group)||result.set(group,[]),result.get(group).push(item)}),result}formatHelp(cmd,helper){let termWidth=helper.padWidth(cmd,helper),helpWidth=helper.helpWidth??80;function callFormatItem(term,description){return helper.formatItem(term,termWidth,description,helper)}let output=[`${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,""],commandDescription=helper.commandDescription(cmd);commandDescription.length>0&&(output=output.concat([helper.boxWrap(helper.styleCommandDescription(commandDescription),helpWidth),""]));let argumentList=helper.visibleArguments(cmd).map(argument=>callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)),helper.styleArgumentDescription(helper.argumentDescription(argument))));if(output=output.concat(this.formatItemList("Arguments:",argumentList,helper)),this.groupItems(cmd.options,helper.visibleOptions(cmd),option=>option.helpGroupHeading??"Options:").forEach((options,group)=>{let optionList=options.map(option=>callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)),helper.styleOptionDescription(helper.optionDescription(option))));output=output.concat(this.formatItemList(group,optionList,helper))}),helper.showGlobalOptions){let globalOptionList=helper.visibleGlobalOptions(cmd).map(option=>callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)),helper.styleOptionDescription(helper.optionDescription(option))));output=output.concat(this.formatItemList("Global Options:",globalOptionList,helper))}return this.groupItems(cmd.commands,helper.visibleCommands(cmd),sub=>sub.helpGroup()||"Commands:").forEach((commands,group)=>{let commandList=commands.map(sub=>callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)),helper.styleSubcommandDescription(helper.subcommandDescription(sub))));output=output.concat(this.formatItemList(group,commandList,helper))}),output.join(`
|
|
4
|
+
`)}displayWidth(str){return stripColor(str).length}styleTitle(str){return str}styleUsage(str){return str.split(" ").map(word=>word==="[options]"?this.styleOptionText(word):word==="[command]"?this.styleSubcommandText(word):word[0]==="["||word[0]==="<"?this.styleArgumentText(word):this.styleCommandText(word)).join(" ")}styleCommandDescription(str){return this.styleDescriptionText(str)}styleOptionDescription(str){return this.styleDescriptionText(str)}styleSubcommandDescription(str){return this.styleDescriptionText(str)}styleArgumentDescription(str){return this.styleDescriptionText(str)}styleDescriptionText(str){return str}styleOptionTerm(str){return this.styleOptionText(str)}styleSubcommandTerm(str){return str.split(" ").map(word=>word==="[options]"?this.styleOptionText(word):word[0]==="["||word[0]==="<"?this.styleArgumentText(word):this.styleSubcommandText(word)).join(" ")}styleArgumentTerm(str){return this.styleArgumentText(str)}styleOptionText(str){return str}styleArgumentText(str){return str}styleSubcommandText(str){return str}styleCommandText(str){return str}padWidth(cmd,helper){return Math.max(helper.longestOptionTermLength(cmd,helper),helper.longestGlobalOptionTermLength(cmd,helper),helper.longestSubcommandTermLength(cmd,helper),helper.longestArgumentTermLength(cmd,helper))}preformatted(str){return/\n[^\S\r\n]/.test(str)}formatItem(term,termWidth,description,helper){let itemIndentStr=" ".repeat(2);if(!description)return itemIndentStr+term;let paddedTerm=term.padEnd(termWidth+term.length-helper.displayWidth(term)),spacerWidth=2,remainingWidth=(this.helpWidth??80)-termWidth-spacerWidth-2,formattedDescription;return remainingWidth<this.minWidthToWrap||helper.preformatted(description)?formattedDescription=description:formattedDescription=helper.boxWrap(description,remainingWidth).replace(/\n/g,`
|
|
5
5
|
`+" ".repeat(termWidth+spacerWidth)),itemIndentStr+paddedTerm+" ".repeat(spacerWidth)+formattedDescription.replace(/\n/g,`
|
|
6
6
|
${itemIndentStr}`)}boxWrap(str,width){if(width<this.minWidthToWrap)return str;let rawLines=str.split(/\r\n|\n/),chunkPattern=/[\s]*[^\s]+/g,wrappedLines=[];return rawLines.forEach(line=>{let chunks=line.match(chunkPattern);if(chunks===null){wrappedLines.push("");return}let sumChunks=[chunks.shift()],sumWidth=this.displayWidth(sumChunks[0]);chunks.forEach(chunk=>{let visibleWidth=this.displayWidth(chunk);if(sumWidth+visibleWidth<=width){sumChunks.push(chunk),sumWidth+=visibleWidth;return}wrappedLines.push(sumChunks.join(""));let nextChunk=chunk.trimStart();sumChunks=[nextChunk],sumWidth=this.displayWidth(nextChunk)}),wrappedLines.push(sumChunks.join(""))}),wrappedLines.join(`
|
|
7
|
-
`)}}}});function camelcase(str){return str.split("-").reduce((str2,word)=>str2+word[0].toUpperCase()+word.slice(1))}function splitOptionFlags(flags){let shortFlag,longFlag,shortFlagExp=/^-[^-]$/,longFlagExp=/^--[^-]/,flagParts=flags.split(/[ |,]+/).concat("guard");if(shortFlagExp.test(flagParts[0])&&(shortFlag=flagParts.shift()),longFlagExp.test(flagParts[0])&&(longFlag=flagParts.shift()),!shortFlag&&shortFlagExp.test(flagParts[0])&&(shortFlag=flagParts.shift()),!shortFlag&&longFlagExp.test(flagParts[0])&&(shortFlag=longFlag,longFlag=flagParts.shift()),flagParts[0].startsWith("-")){let unsupportedFlag=flagParts[0],baseError=`option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;throw/^-[^-][^-]/.test(unsupportedFlag)?new Error(`${baseError}
|
|
7
|
+
`)}};function stripColor(str){let sgrPattern=/\x1b\[\d*(;\d*)*m/g;return str.replace(sgrPattern,"")}exports.Help=Help2;exports.stripColor=stripColor}});var require_option=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/option.js"(exports){var{InvalidArgumentError:InvalidArgumentError2}=require_error(),Option2=class{constructor(flags,description){this.flags=flags,this.description=description||"",this.required=flags.includes("<"),this.optional=flags.includes("["),this.variadic=/\w\.\.\.[>\]]$/.test(flags),this.mandatory=!1;let optionFlags=splitOptionFlags(flags);this.short=optionFlags.shortFlag,this.long=optionFlags.longFlag,this.negate=!1,this.long&&(this.negate=this.long.startsWith("--no-")),this.defaultValue=void 0,this.defaultValueDescription=void 0,this.presetArg=void 0,this.envVar=void 0,this.parseArg=void 0,this.hidden=!1,this.argChoices=void 0,this.conflictsWith=[],this.implied=void 0,this.helpGroupHeading=void 0}default(value,description){return this.defaultValue=value,this.defaultValueDescription=description,this}preset(arg){return this.presetArg=arg,this}conflicts(names){return this.conflictsWith=this.conflictsWith.concat(names),this}implies(impliedOptionValues){let newImplied=impliedOptionValues;return typeof impliedOptionValues=="string"&&(newImplied={[impliedOptionValues]:!0}),this.implied=Object.assign(this.implied||{},newImplied),this}env(name){return this.envVar=name,this}argParser(fn){return this.parseArg=fn,this}makeOptionMandatory(mandatory=!0){return this.mandatory=!!mandatory,this}hideHelp(hide=!0){return this.hidden=!!hide,this}_collectValue(value,previous){return previous===this.defaultValue||!Array.isArray(previous)?[value]:(previous.push(value),previous)}choices(values){return this.argChoices=values.slice(),this.parseArg=(arg,previous)=>{if(!this.argChoices.includes(arg))throw new InvalidArgumentError2(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._collectValue(arg,previous):arg},this}name(){return this.long?this.long.replace(/^--/,""):this.short.replace(/^-/,"")}attributeName(){return this.negate?camelcase(this.name().replace(/^no-/,"")):camelcase(this.name())}helpGroup(heading){return this.helpGroupHeading=heading,this}is(arg){return this.short===arg||this.long===arg}isBoolean(){return!this.required&&!this.optional&&!this.negate}},DualOptions=class{constructor(options){this.positiveOptions=new Map,this.negativeOptions=new Map,this.dualOptions=new Set,options.forEach(option=>{option.negate?this.negativeOptions.set(option.attributeName(),option):this.positiveOptions.set(option.attributeName(),option)}),this.negativeOptions.forEach((value,key)=>{this.positiveOptions.has(key)&&this.dualOptions.add(key)})}valueFromOption(value,option){let optionKey=option.attributeName();if(!this.dualOptions.has(optionKey))return!0;let preset=this.negativeOptions.get(optionKey).presetArg,negativeValue=preset!==void 0?preset:!1;return option.negate===(negativeValue===value)}};function camelcase(str){return str.split("-").reduce((str2,word)=>str2+word[0].toUpperCase()+word.slice(1))}function splitOptionFlags(flags){let shortFlag,longFlag,shortFlagExp=/^-[^-]$/,longFlagExp=/^--[^-]/,flagParts=flags.split(/[ |,]+/).concat("guard");if(shortFlagExp.test(flagParts[0])&&(shortFlag=flagParts.shift()),longFlagExp.test(flagParts[0])&&(longFlag=flagParts.shift()),!shortFlag&&shortFlagExp.test(flagParts[0])&&(shortFlag=flagParts.shift()),!shortFlag&&longFlagExp.test(flagParts[0])&&(shortFlag=longFlag,longFlag=flagParts.shift()),flagParts[0].startsWith("-")){let unsupportedFlag=flagParts[0],baseError=`option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;throw/^-[^-][^-]/.test(unsupportedFlag)?new Error(`${baseError}
|
|
8
8
|
- a short flag is a single dash and a single character
|
|
9
9
|
- either use a single dash and a single character (for a short flag)
|
|
10
10
|
- or use a double dash for a long option (and can have two, like '--ws, --workspace')`):shortFlagExp.test(unsupportedFlag)?new Error(`${baseError}
|
|
11
11
|
- too many short flags`):longFlagExp.test(unsupportedFlag)?new Error(`${baseError}
|
|
12
12
|
- too many long flags`):new Error(`${baseError}
|
|
13
|
-
- unrecognised flag format`)}if(shortFlag===void 0&&longFlag===void 0)throw new Error(`option creation failed due to no flags found in '${flags}'.`);return{shortFlag,longFlag}}
|
|
13
|
+
- unrecognised flag format`)}if(shortFlag===void 0&&longFlag===void 0)throw new Error(`option creation failed due to no flags found in '${flags}'.`);return{shortFlag,longFlag}}exports.Option=Option2;exports.DualOptions=DualOptions}});var require_suggestSimilar=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/suggestSimilar.js"(exports){function editDistance(a,b){if(Math.abs(a.length-b.length)>3)return Math.max(a.length,b.length);let d=[];for(let i=0;i<=a.length;i++)d[i]=[i];for(let j=0;j<=b.length;j++)d[0][j]=j;for(let j=1;j<=b.length;j++)for(let i=1;i<=a.length;i++){let cost=1;a[i-1]===b[j-1]?cost=0:cost=1,d[i][j]=Math.min(d[i-1][j]+1,d[i][j-1]+1,d[i-1][j-1]+cost),i>1&&j>1&&a[i-1]===b[j-2]&&a[i-2]===b[j-1]&&(d[i][j]=Math.min(d[i][j],d[i-2][j-2]+1))}return d[a.length][b.length]}function suggestSimilar(word,candidates){if(!candidates||candidates.length===0)return"";candidates=Array.from(new Set(candidates));let searchingOptions=word.startsWith("--");searchingOptions&&(word=word.slice(2),candidates=candidates.map(candidate=>candidate.slice(2)));let similar=[],bestDistance=3,minSimilarity=.4;return candidates.forEach(candidate=>{if(candidate.length<=1)return;let distance=editDistance(word,candidate),length=Math.max(word.length,candidate.length);(length-distance)/length>minSimilarity&&(distance<bestDistance?(bestDistance=distance,similar=[candidate]):distance===bestDistance&&similar.push(candidate))}),similar.sort((a,b)=>a.localeCompare(b)),searchingOptions&&(similar=similar.map(candidate=>`--${candidate}`)),similar.length>1?`
|
|
14
14
|
(Did you mean one of ${similar.join(", ")}?)`:similar.length===1?`
|
|
15
|
-
(Did you mean ${similar[0]}?)`:""}var
|
|
16
|
-
- specify the name in Command constructor or using .name()`);return opts=opts||{},opts.isDefault&&(this._defaultCommandName=cmd._name),(opts.noHelp||opts.hidden)&&(cmd._hidden=!0),this._registerCommand(cmd),cmd.parent=this,cmd._checkForBrokenPassThrough(),this}createArgument(name,description){return new
|
|
17
|
-
Expecting one of '${allowedValues.join("', '")}'`);return this._lifeCycleHooks[event]?this._lifeCycleHooks[event].push(listener):this._lifeCycleHooks[event]=[listener],this}exitOverride(fn){return fn?this._exitCallback=fn:this._exitCallback=err=>{if(err.code!=="commander.executeSubCommandAsync")throw err},this}_exit(exitCode,code,message){this._exitCallback&&this._exitCallback(new
|
|
18
|
-
- already used by option '${matchingOption.flags}'`)}this._initOptionGroup(option),this.options.push(option)}_registerCommand(command){let knownBy=cmd=>[cmd.name()].concat(cmd.aliases()),alreadyUsed=knownBy(command).find(name=>this._findCommand(name));if(alreadyUsed){let existingCmd=knownBy(this._findCommand(alreadyUsed)).join("|"),newCmd=knownBy(command).join("|");throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`)}this._initCommandGroup(command),this.commands.push(command)}addOption(option){this._registerOption(option);let oname=option.name(),name=option.attributeName();option.defaultValue!==void 0&&this.setOptionValueWithSource(name,option.defaultValue,"default");let handleOptionValue=(val,invalidValueMessage,valueSource)=>{val==null&&option.presetArg!==void 0&&(val=option.presetArg);let oldValue=this.getOptionValue(name);val!==null&&option.parseArg?val=this._callParseArg(option,val,oldValue,invalidValueMessage):val!==null&&option.variadic&&(val=option._collectValue(val,oldValue)),val==null&&(option.negate?val=!1:option.isBoolean()||option.optional?val=!0:val=""),this.setOptionValueWithSource(name,val,valueSource)};return this.on("option:"+oname,val=>{let invalidValueMessage=`error: option '${option.flags}' argument '${val}' is invalid.`;handleOptionValue(val,invalidValueMessage,"cli")}),option.envVar&&this.on("optionEnv:"+oname,val=>{let invalidValueMessage=`error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;handleOptionValue(val,invalidValueMessage,"env")}),this}_optionEx(config,flags,description,fn,defaultValue){if(typeof flags=="object"&&flags instanceof
|
|
19
|
-
- either make a new Command for each call to parse, or stop storing options as properties`);this._name=this._savedState._name,this._scriptPath=null,this.rawArgs=[],this._optionValues={...this._savedState._optionValues},this._optionValueSources={...this._savedState._optionValueSources},this.args=[],this.processedArgs=[]}_checkForMissingExecutable(executableFile,executableDir,subcommandName){if(
|
|
15
|
+
(Did you mean ${similar[0]}?)`:""}exports.suggestSimilar=suggestSimilar}});var require_command=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/command.js"(exports){var EventEmitter=__require("node:events").EventEmitter,childProcess=__require("node:child_process"),path7=__require("node:path"),fs7=__require("node:fs"),process2=__require("node:process"),{Argument:Argument2,humanReadableArgName}=require_argument(),{CommanderError:CommanderError2}=require_error(),{Help:Help2,stripColor}=require_help(),{Option:Option2,DualOptions}=require_option(),{suggestSimilar}=require_suggestSimilar(),Command2=class _Command extends EventEmitter{constructor(name){super(),this.commands=[],this.options=[],this.parent=null,this._allowUnknownOption=!1,this._allowExcessArguments=!1,this.registeredArguments=[],this._args=this.registeredArguments,this.args=[],this.rawArgs=[],this.processedArgs=[],this._scriptPath=null,this._name=name||"",this._optionValues={},this._optionValueSources={},this._storeOptionsAsProperties=!1,this._actionHandler=null,this._executableHandler=!1,this._executableFile=null,this._executableDir=null,this._defaultCommandName=null,this._exitCallback=null,this._aliases=[],this._combineFlagAndOptionalValue=!0,this._description="",this._summary="",this._argsDescription=void 0,this._enablePositionalOptions=!1,this._passThroughOptions=!1,this._lifeCycleHooks={},this._showHelpAfterError=!1,this._showSuggestionAfterError=!0,this._savedState=null,this._outputConfiguration={writeOut:str=>process2.stdout.write(str),writeErr:str=>process2.stderr.write(str),outputError:(str,write)=>write(str),getOutHelpWidth:()=>process2.stdout.isTTY?process2.stdout.columns:void 0,getErrHelpWidth:()=>process2.stderr.isTTY?process2.stderr.columns:void 0,getOutHasColors:()=>useColor()??(process2.stdout.isTTY&&process2.stdout.hasColors?.()),getErrHasColors:()=>useColor()??(process2.stderr.isTTY&&process2.stderr.hasColors?.()),stripColor:str=>stripColor(str)},this._hidden=!1,this._helpOption=void 0,this._addImplicitHelpCommand=void 0,this._helpCommand=void 0,this._helpConfiguration={},this._helpGroupHeading=void 0,this._defaultCommandGroup=void 0,this._defaultOptionGroup=void 0}copyInheritedSettings(sourceCommand){return this._outputConfiguration=sourceCommand._outputConfiguration,this._helpOption=sourceCommand._helpOption,this._helpCommand=sourceCommand._helpCommand,this._helpConfiguration=sourceCommand._helpConfiguration,this._exitCallback=sourceCommand._exitCallback,this._storeOptionsAsProperties=sourceCommand._storeOptionsAsProperties,this._combineFlagAndOptionalValue=sourceCommand._combineFlagAndOptionalValue,this._allowExcessArguments=sourceCommand._allowExcessArguments,this._enablePositionalOptions=sourceCommand._enablePositionalOptions,this._showHelpAfterError=sourceCommand._showHelpAfterError,this._showSuggestionAfterError=sourceCommand._showSuggestionAfterError,this}_getCommandAndAncestors(){let result=[];for(let command=this;command;command=command.parent)result.push(command);return result}command(nameAndArgs,actionOptsOrExecDesc,execOpts){let desc=actionOptsOrExecDesc,opts=execOpts;typeof desc=="object"&&desc!==null&&(opts=desc,desc=null),opts=opts||{};let[,name,args]=nameAndArgs.match(/([^ ]+) *(.*)/),cmd=this.createCommand(name);return desc&&(cmd.description(desc),cmd._executableHandler=!0),opts.isDefault&&(this._defaultCommandName=cmd._name),cmd._hidden=!!(opts.noHelp||opts.hidden),cmd._executableFile=opts.executableFile||null,args&&cmd.arguments(args),this._registerCommand(cmd),cmd.parent=this,cmd.copyInheritedSettings(this),desc?this:cmd}createCommand(name){return new _Command(name)}createHelp(){return Object.assign(new Help2,this.configureHelp())}configureHelp(configuration){return configuration===void 0?this._helpConfiguration:(this._helpConfiguration=configuration,this)}configureOutput(configuration){return configuration===void 0?this._outputConfiguration:(this._outputConfiguration={...this._outputConfiguration,...configuration},this)}showHelpAfterError(displayHelp=!0){return typeof displayHelp!="string"&&(displayHelp=!!displayHelp),this._showHelpAfterError=displayHelp,this}showSuggestionAfterError(displaySuggestion=!0){return this._showSuggestionAfterError=!!displaySuggestion,this}addCommand(cmd,opts){if(!cmd._name)throw new Error(`Command passed to .addCommand() must have a name
|
|
16
|
+
- specify the name in Command constructor or using .name()`);return opts=opts||{},opts.isDefault&&(this._defaultCommandName=cmd._name),(opts.noHelp||opts.hidden)&&(cmd._hidden=!0),this._registerCommand(cmd),cmd.parent=this,cmd._checkForBrokenPassThrough(),this}createArgument(name,description){return new Argument2(name,description)}argument(name,description,parseArg,defaultValue){let argument=this.createArgument(name,description);return typeof parseArg=="function"?argument.default(defaultValue).argParser(parseArg):argument.default(parseArg),this.addArgument(argument),this}arguments(names){return names.trim().split(/ +/).forEach(detail=>{this.argument(detail)}),this}addArgument(argument){let previousArgument=this.registeredArguments.slice(-1)[0];if(previousArgument?.variadic)throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);if(argument.required&&argument.defaultValue!==void 0&&argument.parseArg===void 0)throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);return this.registeredArguments.push(argument),this}helpCommand(enableOrNameAndArgs,description){if(typeof enableOrNameAndArgs=="boolean")return this._addImplicitHelpCommand=enableOrNameAndArgs,enableOrNameAndArgs&&this._defaultCommandGroup&&this._initCommandGroup(this._getHelpCommand()),this;let nameAndArgs=enableOrNameAndArgs??"help [command]",[,helpName,helpArgs]=nameAndArgs.match(/([^ ]+) *(.*)/),helpDescription=description??"display help for command",helpCommand=this.createCommand(helpName);return helpCommand.helpOption(!1),helpArgs&&helpCommand.arguments(helpArgs),helpDescription&&helpCommand.description(helpDescription),this._addImplicitHelpCommand=!0,this._helpCommand=helpCommand,(enableOrNameAndArgs||description)&&this._initCommandGroup(helpCommand),this}addHelpCommand(helpCommand,deprecatedDescription){return typeof helpCommand!="object"?(this.helpCommand(helpCommand,deprecatedDescription),this):(this._addImplicitHelpCommand=!0,this._helpCommand=helpCommand,this._initCommandGroup(helpCommand),this)}_getHelpCommand(){return this._addImplicitHelpCommand??(this.commands.length&&!this._actionHandler&&!this._findCommand("help"))?(this._helpCommand===void 0&&this.helpCommand(void 0,void 0),this._helpCommand):null}hook(event,listener){let allowedValues=["preSubcommand","preAction","postAction"];if(!allowedValues.includes(event))throw new Error(`Unexpected value for event passed to hook : '${event}'.
|
|
17
|
+
Expecting one of '${allowedValues.join("', '")}'`);return this._lifeCycleHooks[event]?this._lifeCycleHooks[event].push(listener):this._lifeCycleHooks[event]=[listener],this}exitOverride(fn){return fn?this._exitCallback=fn:this._exitCallback=err=>{if(err.code!=="commander.executeSubCommandAsync")throw err},this}_exit(exitCode,code,message){this._exitCallback&&this._exitCallback(new CommanderError2(exitCode,code,message)),process2.exit(exitCode)}action(fn){let listener=args=>{let expectedArgsCount=this.registeredArguments.length,actionArgs=args.slice(0,expectedArgsCount);return this._storeOptionsAsProperties?actionArgs[expectedArgsCount]=this:actionArgs[expectedArgsCount]=this.opts(),actionArgs.push(this),fn.apply(this,actionArgs)};return this._actionHandler=listener,this}createOption(flags,description){return new Option2(flags,description)}_callParseArg(target,value,previous,invalidArgumentMessage){try{return target.parseArg(value,previous)}catch(err){if(err.code==="commander.invalidArgument"){let message=`${invalidArgumentMessage} ${err.message}`;this.error(message,{exitCode:err.exitCode,code:err.code})}throw err}}_registerOption(option){let matchingOption=option.short&&this._findOption(option.short)||option.long&&this._findOption(option.long);if(matchingOption){let matchingFlag=option.long&&this._findOption(option.long)?option.long:option.short;throw new Error(`Cannot add option '${option.flags}'${this._name&&` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
|
|
18
|
+
- already used by option '${matchingOption.flags}'`)}this._initOptionGroup(option),this.options.push(option)}_registerCommand(command){let knownBy=cmd=>[cmd.name()].concat(cmd.aliases()),alreadyUsed=knownBy(command).find(name=>this._findCommand(name));if(alreadyUsed){let existingCmd=knownBy(this._findCommand(alreadyUsed)).join("|"),newCmd=knownBy(command).join("|");throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`)}this._initCommandGroup(command),this.commands.push(command)}addOption(option){this._registerOption(option);let oname=option.name(),name=option.attributeName();if(option.negate){let positiveLongFlag=option.long.replace(/^--no-/,"--");this._findOption(positiveLongFlag)||this.setOptionValueWithSource(name,option.defaultValue===void 0?!0:option.defaultValue,"default")}else option.defaultValue!==void 0&&this.setOptionValueWithSource(name,option.defaultValue,"default");let handleOptionValue=(val,invalidValueMessage,valueSource)=>{val==null&&option.presetArg!==void 0&&(val=option.presetArg);let oldValue=this.getOptionValue(name);val!==null&&option.parseArg?val=this._callParseArg(option,val,oldValue,invalidValueMessage):val!==null&&option.variadic&&(val=option._collectValue(val,oldValue)),val==null&&(option.negate?val=!1:option.isBoolean()||option.optional?val=!0:val=""),this.setOptionValueWithSource(name,val,valueSource)};return this.on("option:"+oname,val=>{let invalidValueMessage=`error: option '${option.flags}' argument '${val}' is invalid.`;handleOptionValue(val,invalidValueMessage,"cli")}),option.envVar&&this.on("optionEnv:"+oname,val=>{let invalidValueMessage=`error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;handleOptionValue(val,invalidValueMessage,"env")}),this}_optionEx(config,flags,description,fn,defaultValue){if(typeof flags=="object"&&flags instanceof Option2)throw new Error("To add an Option object use addOption() instead of option() or requiredOption()");let option=this.createOption(flags,description);if(option.makeOptionMandatory(!!config.mandatory),typeof fn=="function")option.default(defaultValue).argParser(fn);else if(fn instanceof RegExp){let regex=fn;fn=(val,def)=>{let m=regex.exec(val);return m?m[0]:def},option.default(defaultValue).argParser(fn)}else option.default(fn);return this.addOption(option)}option(flags,description,parseArg,defaultValue){return this._optionEx({},flags,description,parseArg,defaultValue)}requiredOption(flags,description,parseArg,defaultValue){return this._optionEx({mandatory:!0},flags,description,parseArg,defaultValue)}combineFlagAndOptionalValue(combine=!0){return this._combineFlagAndOptionalValue=!!combine,this}allowUnknownOption(allowUnknown=!0){return this._allowUnknownOption=!!allowUnknown,this}allowExcessArguments(allowExcess=!0){return this._allowExcessArguments=!!allowExcess,this}enablePositionalOptions(positional=!0){return this._enablePositionalOptions=!!positional,this}passThroughOptions(passThrough=!0){return this._passThroughOptions=!!passThrough,this._checkForBrokenPassThrough(),this}_checkForBrokenPassThrough(){if(this.parent&&this._passThroughOptions&&!this.parent._enablePositionalOptions)throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`)}storeOptionsAsProperties(storeAsProperties=!0){if(this.options.length)throw new Error("call .storeOptionsAsProperties() before adding options");if(Object.keys(this._optionValues).length)throw new Error("call .storeOptionsAsProperties() before setting option values");return this._storeOptionsAsProperties=!!storeAsProperties,this}getOptionValue(key){return this._storeOptionsAsProperties?this[key]:this._optionValues[key]}setOptionValue(key,value){return this.setOptionValueWithSource(key,value,void 0)}setOptionValueWithSource(key,value,source){return this._storeOptionsAsProperties?this[key]=value:this._optionValues[key]=value,this._optionValueSources[key]=source,this}getOptionValueSource(key){return this._optionValueSources[key]}getOptionValueSourceWithGlobals(key){let source;return this._getCommandAndAncestors().forEach(cmd=>{cmd.getOptionValueSource(key)!==void 0&&(source=cmd.getOptionValueSource(key))}),source}_prepareUserArgs(argv,parseOptions){if(argv!==void 0&&!Array.isArray(argv))throw new Error("first parameter to parse must be array or undefined");if(parseOptions=parseOptions||{},argv===void 0&&parseOptions.from===void 0){process2.versions?.electron&&(parseOptions.from="electron");let execArgv=process2.execArgv??[];(execArgv.includes("-e")||execArgv.includes("--eval")||execArgv.includes("-p")||execArgv.includes("--print"))&&(parseOptions.from="eval")}argv===void 0&&(argv=process2.argv),this.rawArgs=argv.slice();let userArgs;switch(parseOptions.from){case void 0:case"node":this._scriptPath=argv[1],userArgs=argv.slice(2);break;case"electron":process2.defaultApp?(this._scriptPath=argv[1],userArgs=argv.slice(2)):userArgs=argv.slice(1);break;case"user":userArgs=argv.slice(0);break;case"eval":userArgs=argv.slice(1);break;default:throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`)}return!this._name&&this._scriptPath&&this.nameFromFilename(this._scriptPath),this._name=this._name||"program",userArgs}parse(argv,parseOptions){this._prepareForParse();let userArgs=this._prepareUserArgs(argv,parseOptions);return this._parseCommand([],userArgs),this}async parseAsync(argv,parseOptions){this._prepareForParse();let userArgs=this._prepareUserArgs(argv,parseOptions);return await this._parseCommand([],userArgs),this}_prepareForParse(){this._savedState===null?this.saveStateBeforeParse():this.restoreStateBeforeParse()}saveStateBeforeParse(){this._savedState={_name:this._name,_optionValues:{...this._optionValues},_optionValueSources:{...this._optionValueSources}}}restoreStateBeforeParse(){if(this._storeOptionsAsProperties)throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
|
|
19
|
+
- either make a new Command for each call to parse, or stop storing options as properties`);this._name=this._savedState._name,this._scriptPath=null,this.rawArgs=[],this._optionValues={...this._savedState._optionValues},this._optionValueSources={...this._savedState._optionValueSources},this.args=[],this.processedArgs=[]}_checkForMissingExecutable(executableFile,executableDir,subcommandName){if(fs7.existsSync(executableFile))return;let executableDirMessage=executableDir?`searched for local subcommand relative to directory '${executableDir}'`:"no directory for search for local subcommand, use .executableDir() to supply a custom directory",executableMissing=`'${executableFile}' does not exist
|
|
20
20
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
21
21
|
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
22
|
-
- ${executableDirMessage}`;throw new Error(executableMissing)}_executeSubCommand(subcommand,args){args=args.slice();let sourceExt=[".js",".ts",".tsx",".mjs",".cjs"];function findFile(baseDir,baseName){let localBin=path.resolve(baseDir,baseName);if(fs.existsSync(localBin))return localBin;if(sourceExt.includes(path.extname(baseName)))return;let foundExt=sourceExt.find(ext=>fs.existsSync(`${localBin}${ext}`));if(foundExt)return`${localBin}${foundExt}`}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let executableFile=subcommand._executableFile||`${this._name}-${subcommand._name}`,executableDir=this._executableDir||"";if(this._scriptPath){let resolvedScriptPath;try{resolvedScriptPath=fs.realpathSync(this._scriptPath)}catch{resolvedScriptPath=this._scriptPath}executableDir=path.resolve(path.dirname(resolvedScriptPath),executableDir)}if(executableDir){let localFile=findFile(executableDir,executableFile);if(!localFile&&!subcommand._executableFile&&this._scriptPath){let legacyName=path.basename(this._scriptPath,path.extname(this._scriptPath));legacyName!==this._name&&(localFile=findFile(executableDir,`${legacyName}-${subcommand._name}`))}executableFile=localFile||executableFile}let launchWithNode=sourceExt.includes(path.extname(executableFile)),proc;process2.platform!=="win32"?launchWithNode?(args.unshift(executableFile),args=incrementNodeInspectorPort(process2.execArgv).concat(args),proc=childProcess.spawn(process2.argv[0],args,{stdio:"inherit"})):proc=childProcess.spawn(executableFile,args,{stdio:"inherit"}):(this._checkForMissingExecutable(executableFile,executableDir,subcommand._name),args.unshift(executableFile),args=incrementNodeInspectorPort(process2.execArgv).concat(args),proc=childProcess.spawn(process2.execPath,args,{stdio:"inherit"})),proc.killed||["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach(signal=>{process2.on(signal,()=>{proc.killed===!1&&proc.exitCode===null&&proc.kill(signal)})});let exitCallback=this._exitCallback;proc.on("close",code=>{code=code??1,exitCallback?exitCallback(new CommanderError(code,"commander.executeSubCommandAsync","(close)")):process2.exit(code)}),proc.on("error",err=>{if(err.code==="ENOENT")this._checkForMissingExecutable(executableFile,executableDir,subcommand._name);else if(err.code==="EACCES")throw new Error(`'${executableFile}' not executable`);if(!exitCallback)process2.exit(1);else{let wrappedError=new CommanderError(1,"commander.executeSubCommandAsync","(error)");wrappedError.nestedError=err,exitCallback(wrappedError)}}),this.runningCommand=proc}_dispatchSubcommand(commandName,operands,unknown){let subCommand=this._findCommand(commandName);subCommand||this.help({error:!0}),subCommand._prepareForParse();let promiseChain;return promiseChain=this._chainOrCallSubCommandHook(promiseChain,subCommand,"preSubcommand"),promiseChain=this._chainOrCall(promiseChain,()=>{if(subCommand._executableHandler)this._executeSubCommand(subCommand,operands.concat(unknown));else return subCommand._parseCommand(operands,unknown)}),promiseChain}_dispatchHelpCommand(subcommandName){subcommandName||this.help();let subCommand=this._findCommand(subcommandName);return subCommand&&!subCommand._executableHandler&&subCommand.help(),this._dispatchSubcommand(subcommandName,[],[this._getHelpOption()?.long??this._getHelpOption()?.short??"--help"])}_checkNumberOfArguments(){this.registeredArguments.forEach((arg,i)=>{arg.required&&this.args[i]==null&&this.missingArgument(arg.name())}),!(this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)&&this.args.length>this.registeredArguments.length&&this._excessArguments(this.args)}_processArguments(){let myParseArg=(argument,value,previous)=>{let parsedValue=value;if(value!==null&&argument.parseArg){let invalidValueMessage=`error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;parsedValue=this._callParseArg(argument,value,previous,invalidValueMessage)}return parsedValue};this._checkNumberOfArguments();let processedArgs=[];this.registeredArguments.forEach((declaredArg,index)=>{let value=declaredArg.defaultValue;declaredArg.variadic?index<this.args.length?(value=this.args.slice(index),declaredArg.parseArg&&(value=value.reduce((processed,v)=>myParseArg(declaredArg,v,processed),declaredArg.defaultValue))):value===void 0&&(value=[]):index<this.args.length&&(value=this.args[index],declaredArg.parseArg&&(value=myParseArg(declaredArg,value,declaredArg.defaultValue))),processedArgs[index]=value}),this.processedArgs=processedArgs}_chainOrCall(promise,fn){return promise?.then&&typeof promise.then=="function"?promise.then(()=>fn()):fn()}_chainOrCallHooks(promise,event){let result=promise,hooks=[];return this._getCommandAndAncestors().reverse().filter(cmd=>cmd._lifeCycleHooks[event]!==void 0).forEach(hookedCommand=>{hookedCommand._lifeCycleHooks[event].forEach(callback=>{hooks.push({hookedCommand,callback})})}),event==="postAction"&&hooks.reverse(),hooks.forEach(hookDetail=>{result=this._chainOrCall(result,()=>hookDetail.callback(hookDetail.hookedCommand,this))}),result}_chainOrCallSubCommandHook(promise,subCommand,event){let result=promise;return this._lifeCycleHooks[event]!==void 0&&this._lifeCycleHooks[event].forEach(hook=>{result=this._chainOrCall(result,()=>hook(this,subCommand))}),result}_parseCommand(operands,unknown){let parsed=this.parseOptions(unknown);if(this._parseOptionsEnv(),this._parseOptionsImplied(),operands=operands.concat(parsed.operands),unknown=parsed.unknown,this.args=operands.concat(unknown),operands&&this._findCommand(operands[0]))return this._dispatchSubcommand(operands[0],operands.slice(1),unknown);if(this._getHelpCommand()&&operands[0]===this._getHelpCommand().name())return this._dispatchHelpCommand(operands[1]);if(this._defaultCommandName)return this._outputHelpIfRequested(unknown),this._dispatchSubcommand(this._defaultCommandName,operands,unknown);this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName&&this.help({error:!0}),this._outputHelpIfRequested(parsed.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let checkForUnknownOptions=()=>{parsed.unknown.length>0&&this.unknownOption(parsed.unknown[0])},commandEvent=`command:${this.name()}`;if(this._actionHandler){checkForUnknownOptions(),this._processArguments();let promiseChain;return promiseChain=this._chainOrCallHooks(promiseChain,"preAction"),promiseChain=this._chainOrCall(promiseChain,()=>this._actionHandler(this.processedArgs)),this.parent&&(promiseChain=this._chainOrCall(promiseChain,()=>{this.parent.emit(commandEvent,operands,unknown)})),promiseChain=this._chainOrCallHooks(promiseChain,"postAction"),promiseChain}if(this.parent?.listenerCount(commandEvent))checkForUnknownOptions(),this._processArguments(),this.parent.emit(commandEvent,operands,unknown);else if(operands.length){if(this._findCommand("*"))return this._dispatchSubcommand("*",operands,unknown);this.listenerCount("command:*")?this.emit("command:*",operands,unknown):this.commands.length?this.unknownCommand():(checkForUnknownOptions(),this._processArguments())}else this.commands.length?(checkForUnknownOptions(),this.help({error:!0})):(checkForUnknownOptions(),this._processArguments())}_findCommand(name){if(name)return this.commands.find(cmd=>cmd._name===name||cmd._aliases.includes(name))}_findOption(arg){return this.options.find(option=>option.is(arg))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(cmd=>{cmd.options.forEach(anOption=>{anOption.mandatory&&cmd.getOptionValue(anOption.attributeName())===void 0&&cmd.missingMandatoryOptionValue(anOption)})})}_checkForConflictingLocalOptions(){let definedNonDefaultOptions=this.options.filter(option=>{let optionKey=option.attributeName();return this.getOptionValue(optionKey)===void 0?!1:this.getOptionValueSource(optionKey)!=="default"});definedNonDefaultOptions.filter(option=>option.conflictsWith.length>0).forEach(option=>{let conflictingAndDefined=definedNonDefaultOptions.find(defined=>option.conflictsWith.includes(defined.attributeName()));conflictingAndDefined&&this._conflictingOption(option,conflictingAndDefined)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(cmd=>{cmd._checkForConflictingLocalOptions()})}parseOptions(args){let operands=[],unknown=[],dest=operands;function maybeOption(arg){return arg.length>1&&arg[0]==="-"}let negativeNumberArg=arg=>/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)?!this._getCommandAndAncestors().some(cmd=>cmd.options.map(opt=>opt.short).some(short=>/^-\d$/.test(short))):!1,activeVariadicOption=null,activeGroup=null,i=0;for(;i<args.length||activeGroup;){let arg=activeGroup??args[i++];if(activeGroup=null,arg==="--"){dest===unknown&&dest.push(arg),dest.push(...args.slice(i));break}if(activeVariadicOption&&(!maybeOption(arg)||negativeNumberArg(arg))){this.emit(`option:${activeVariadicOption.name()}`,arg);continue}if(activeVariadicOption=null,maybeOption(arg)){let option=this._findOption(arg);if(option){if(option.required){let value=args[i++];value===void 0&&this.optionMissingArgument(option),this.emit(`option:${option.name()}`,value)}else if(option.optional){let value=null;i<args.length&&(!maybeOption(args[i])||negativeNumberArg(args[i]))&&(value=args[i++]),this.emit(`option:${option.name()}`,value)}else this.emit(`option:${option.name()}`);activeVariadicOption=option.variadic?option:null;continue}}if(arg.length>2&&arg[0]==="-"&&arg[1]!=="-"){let option=this._findOption(`-${arg[1]}`);if(option){option.required||option.optional&&this._combineFlagAndOptionalValue?this.emit(`option:${option.name()}`,arg.slice(2)):(this.emit(`option:${option.name()}`),activeGroup=`-${arg.slice(2)}`);continue}}if(/^--[^=]+=/.test(arg)){let index=arg.indexOf("="),option=this._findOption(arg.slice(0,index));if(option&&(option.required||option.optional)){this.emit(`option:${option.name()}`,arg.slice(index+1));continue}}if(dest===operands&&maybeOption(arg)&&!(this.commands.length===0&&negativeNumberArg(arg))&&(dest=unknown),(this._enablePositionalOptions||this._passThroughOptions)&&operands.length===0&&unknown.length===0){if(this._findCommand(arg)){operands.push(arg),unknown.push(...args.slice(i));break}else if(this._getHelpCommand()&&arg===this._getHelpCommand().name()){operands.push(arg,...args.slice(i));break}else if(this._defaultCommandName){unknown.push(arg,...args.slice(i));break}}if(this._passThroughOptions){dest.push(arg,...args.slice(i));break}dest.push(arg)}return{operands,unknown}}opts(){if(this._storeOptionsAsProperties){let result={},len=this.options.length;for(let i=0;i<len;i++){let key=this.options[i].attributeName();result[key]=key===this._versionOptionName?this._version:this[key]}return result}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce((combinedOptions,cmd)=>Object.assign(combinedOptions,cmd.opts()),{})}error(message,errorOptions){this._outputConfiguration.outputError(`${message}
|
|
22
|
+
- ${executableDirMessage}`;throw new Error(executableMissing)}_executeSubCommand(subcommand,args){args=args.slice();let launchWithNode=!1,sourceExt=[".js",".ts",".tsx",".mjs",".cjs"];function findFile(baseDir,baseName){let localBin=path7.resolve(baseDir,baseName);if(fs7.existsSync(localBin))return localBin;if(sourceExt.includes(path7.extname(baseName)))return;let foundExt=sourceExt.find(ext=>fs7.existsSync(`${localBin}${ext}`));if(foundExt)return`${localBin}${foundExt}`}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let executableFile=subcommand._executableFile||`${this._name}-${subcommand._name}`,executableDir=this._executableDir||"";if(this._scriptPath){let resolvedScriptPath;try{resolvedScriptPath=fs7.realpathSync(this._scriptPath)}catch{resolvedScriptPath=this._scriptPath}executableDir=path7.resolve(path7.dirname(resolvedScriptPath),executableDir)}if(executableDir){let localFile=findFile(executableDir,executableFile);if(!localFile&&!subcommand._executableFile&&this._scriptPath){let legacyName=path7.basename(this._scriptPath,path7.extname(this._scriptPath));legacyName!==this._name&&(localFile=findFile(executableDir,`${legacyName}-${subcommand._name}`))}executableFile=localFile||executableFile}launchWithNode=sourceExt.includes(path7.extname(executableFile));let proc;process2.platform!=="win32"?launchWithNode?(args.unshift(executableFile),args=incrementNodeInspectorPort(process2.execArgv).concat(args),proc=childProcess.spawn(process2.argv[0],args,{stdio:"inherit"})):proc=childProcess.spawn(executableFile,args,{stdio:"inherit"}):(this._checkForMissingExecutable(executableFile,executableDir,subcommand._name),args.unshift(executableFile),args=incrementNodeInspectorPort(process2.execArgv).concat(args),proc=childProcess.spawn(process2.execPath,args,{stdio:"inherit"})),proc.killed||["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach(signal=>{process2.on(signal,()=>{proc.killed===!1&&proc.exitCode===null&&proc.kill(signal)})});let exitCallback=this._exitCallback;proc.on("close",code=>{code=code??1,exitCallback?exitCallback(new CommanderError2(code,"commander.executeSubCommandAsync","(close)")):process2.exit(code)}),proc.on("error",err=>{if(err.code==="ENOENT")this._checkForMissingExecutable(executableFile,executableDir,subcommand._name);else if(err.code==="EACCES")throw new Error(`'${executableFile}' not executable`);if(!exitCallback)process2.exit(1);else{let wrappedError=new CommanderError2(1,"commander.executeSubCommandAsync","(error)");wrappedError.nestedError=err,exitCallback(wrappedError)}}),this.runningCommand=proc}_dispatchSubcommand(commandName,operands,unknown){let subCommand=this._findCommand(commandName);subCommand||this.help({error:!0}),subCommand._prepareForParse();let promiseChain;return promiseChain=this._chainOrCallSubCommandHook(promiseChain,subCommand,"preSubcommand"),promiseChain=this._chainOrCall(promiseChain,()=>{if(subCommand._executableHandler)this._executeSubCommand(subCommand,operands.concat(unknown));else return subCommand._parseCommand(operands,unknown)}),promiseChain}_dispatchHelpCommand(subcommandName){subcommandName||this.help();let subCommand=this._findCommand(subcommandName);return subCommand&&!subCommand._executableHandler&&subCommand.help(),this._dispatchSubcommand(subcommandName,[],[this._getHelpOption()?.long??this._getHelpOption()?.short??"--help"])}_checkNumberOfArguments(){this.registeredArguments.forEach((arg,i)=>{arg.required&&this.args[i]==null&&this.missingArgument(arg.name())}),!(this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)&&this.args.length>this.registeredArguments.length&&this._excessArguments(this.args)}_processArguments(){let myParseArg=(argument,value,previous)=>{let parsedValue=value;if(value!==null&&argument.parseArg){let invalidValueMessage=`error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;parsedValue=this._callParseArg(argument,value,previous,invalidValueMessage)}return parsedValue};this._checkNumberOfArguments();let processedArgs=[];this.registeredArguments.forEach((declaredArg,index)=>{let value=declaredArg.defaultValue;declaredArg.variadic?index<this.args.length?(value=this.args.slice(index),declaredArg.parseArg&&(value=value.reduce((processed,v)=>myParseArg(declaredArg,v,processed),declaredArg.defaultValue))):value===void 0&&(value=[]):index<this.args.length&&(value=this.args[index],declaredArg.parseArg&&(value=myParseArg(declaredArg,value,declaredArg.defaultValue))),processedArgs[index]=value}),this.processedArgs=processedArgs}_chainOrCall(promise,fn){return promise?.then&&typeof promise.then=="function"?promise.then(()=>fn()):fn()}_chainOrCallHooks(promise,event){let result=promise,hooks=[];return this._getCommandAndAncestors().reverse().filter(cmd=>cmd._lifeCycleHooks[event]!==void 0).forEach(hookedCommand=>{hookedCommand._lifeCycleHooks[event].forEach(callback=>{hooks.push({hookedCommand,callback})})}),event==="postAction"&&hooks.reverse(),hooks.forEach(hookDetail=>{result=this._chainOrCall(result,()=>hookDetail.callback(hookDetail.hookedCommand,this))}),result}_chainOrCallSubCommandHook(promise,subCommand,event){let result=promise;return this._lifeCycleHooks[event]!==void 0&&this._lifeCycleHooks[event].forEach(hook=>{result=this._chainOrCall(result,()=>hook(this,subCommand))}),result}_parseCommand(operands,unknown){let parsed=this.parseOptions(unknown);if(this._parseOptionsEnv(),this._parseOptionsImplied(),operands=operands.concat(parsed.operands),unknown=parsed.unknown,this.args=operands.concat(unknown),operands&&this._findCommand(operands[0]))return this._dispatchSubcommand(operands[0],operands.slice(1),unknown);if(this._getHelpCommand()&&operands[0]===this._getHelpCommand().name())return this._dispatchHelpCommand(operands[1]);if(this._defaultCommandName)return this._outputHelpIfRequested(unknown),this._dispatchSubcommand(this._defaultCommandName,operands,unknown);this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName&&this.help({error:!0}),this._outputHelpIfRequested(parsed.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let checkForUnknownOptions=()=>{parsed.unknown.length>0&&this.unknownOption(parsed.unknown[0])},commandEvent=`command:${this.name()}`;if(this._actionHandler){checkForUnknownOptions(),this._processArguments();let promiseChain;return promiseChain=this._chainOrCallHooks(promiseChain,"preAction"),promiseChain=this._chainOrCall(promiseChain,()=>this._actionHandler(this.processedArgs)),this.parent&&(promiseChain=this._chainOrCall(promiseChain,()=>{this.parent.emit(commandEvent,operands,unknown)})),promiseChain=this._chainOrCallHooks(promiseChain,"postAction"),promiseChain}if(this.parent?.listenerCount(commandEvent))checkForUnknownOptions(),this._processArguments(),this.parent.emit(commandEvent,operands,unknown);else if(operands.length){if(this._findCommand("*"))return this._dispatchSubcommand("*",operands,unknown);this.listenerCount("command:*")?this.emit("command:*",operands,unknown):this.commands.length?this.unknownCommand():(checkForUnknownOptions(),this._processArguments())}else this.commands.length?(checkForUnknownOptions(),this.help({error:!0})):(checkForUnknownOptions(),this._processArguments())}_findCommand(name){if(name)return this.commands.find(cmd=>cmd._name===name||cmd._aliases.includes(name))}_findOption(arg){return this.options.find(option=>option.is(arg))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(cmd=>{cmd.options.forEach(anOption=>{anOption.mandatory&&cmd.getOptionValue(anOption.attributeName())===void 0&&cmd.missingMandatoryOptionValue(anOption)})})}_checkForConflictingLocalOptions(){let definedNonDefaultOptions=this.options.filter(option=>{let optionKey=option.attributeName();return this.getOptionValue(optionKey)===void 0?!1:this.getOptionValueSource(optionKey)!=="default"});definedNonDefaultOptions.filter(option=>option.conflictsWith.length>0).forEach(option=>{let conflictingAndDefined=definedNonDefaultOptions.find(defined=>option.conflictsWith.includes(defined.attributeName()));conflictingAndDefined&&this._conflictingOption(option,conflictingAndDefined)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(cmd=>{cmd._checkForConflictingLocalOptions()})}parseOptions(args){let operands=[],unknown=[],dest=operands;function maybeOption(arg){return arg.length>1&&arg[0]==="-"}let negativeNumberArg=arg=>/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)?!this._getCommandAndAncestors().some(cmd=>cmd.options.map(opt=>opt.short).some(short=>/^-\d$/.test(short))):!1,activeVariadicOption=null,activeGroup=null,i=0;for(;i<args.length||activeGroup;){let arg=activeGroup??args[i++];if(activeGroup=null,arg==="--"){dest===unknown&&dest.push(arg),dest.push(...args.slice(i));break}if(activeVariadicOption&&(!maybeOption(arg)||negativeNumberArg(arg))){this.emit(`option:${activeVariadicOption.name()}`,arg);continue}if(activeVariadicOption=null,maybeOption(arg)){let option=this._findOption(arg);if(option){if(option.required){let value=args[i++];value===void 0&&this.optionMissingArgument(option),this.emit(`option:${option.name()}`,value)}else if(option.optional){let value=null;i<args.length&&(!maybeOption(args[i])||negativeNumberArg(args[i]))&&(value=args[i++]),this.emit(`option:${option.name()}`,value)}else this.emit(`option:${option.name()}`);activeVariadicOption=option.variadic?option:null;continue}}if(arg.length>2&&arg[0]==="-"&&arg[1]!=="-"){let option=this._findOption(`-${arg[1]}`);if(option){option.required||option.optional&&this._combineFlagAndOptionalValue?this.emit(`option:${option.name()}`,arg.slice(2)):(this.emit(`option:${option.name()}`),activeGroup=`-${arg.slice(2)}`);continue}}if(/^--[^=]+=/.test(arg)){let index=arg.indexOf("="),option=this._findOption(arg.slice(0,index));if(option&&(option.required||option.optional)){this.emit(`option:${option.name()}`,arg.slice(index+1));continue}}if(dest===operands&&maybeOption(arg)&&!(this.commands.length===0&&negativeNumberArg(arg))&&(dest=unknown),(this._enablePositionalOptions||this._passThroughOptions)&&operands.length===0&&unknown.length===0){if(this._findCommand(arg)){operands.push(arg),unknown.push(...args.slice(i));break}else if(this._getHelpCommand()&&arg===this._getHelpCommand().name()){operands.push(arg,...args.slice(i));break}else if(this._defaultCommandName){unknown.push(arg,...args.slice(i));break}}if(this._passThroughOptions){dest.push(arg,...args.slice(i));break}dest.push(arg)}return{operands,unknown}}opts(){if(this._storeOptionsAsProperties){let result={},len=this.options.length;for(let i=0;i<len;i++){let key=this.options[i].attributeName();result[key]=key===this._versionOptionName?this._version:this[key]}return result}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce((combinedOptions,cmd)=>Object.assign(combinedOptions,cmd.opts()),{})}error(message,errorOptions){this._outputConfiguration.outputError(`${message}
|
|
23
23
|
`,this._outputConfiguration.writeErr),typeof this._showHelpAfterError=="string"?this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
24
24
|
`):this._showHelpAfterError&&(this._outputConfiguration.writeErr(`
|
|
25
|
-
`),this.outputHelp({error:!0}));let config=errorOptions||{},exitCode=config.exitCode||1,code=config.code||"commander.error";this._exit(exitCode,code,message)}_parseOptionsEnv(){this.options.forEach(option=>{if(option.envVar&&option.envVar in process2.env){let optionKey=option.attributeName();(this.getOptionValue(optionKey)===void 0||["default","config","env"].includes(this.getOptionValueSource(optionKey)))&&(option.required||option.optional?this.emit(`optionEnv:${option.name()}`,process2.env[option.envVar]):this.emit(`optionEnv:${option.name()}`))}})}_parseOptionsImplied(){let dualHelper=new DualOptions(this.options),hasCustomOptionValue=optionKey=>this.getOptionValue(optionKey)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(optionKey));this.options.filter(option=>option.implied!==void 0&&hasCustomOptionValue(option.attributeName())&&dualHelper.valueFromOption(this.getOptionValue(option.attributeName()),option)).forEach(option=>{Object.keys(option.implied).filter(impliedKey=>!hasCustomOptionValue(impliedKey)).forEach(impliedKey=>{this.setOptionValueWithSource(impliedKey,option.implied[impliedKey],"implied")})})}missingArgument(name){let message=`error: missing required argument '${name}'`;this.error(message,{code:"commander.missingArgument"})}optionMissingArgument(option){let message=`error: option '${option.flags}' argument missing`;this.error(message,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(option){let message=`error: required option '${option.flags}' not specified`;this.error(message,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(option,conflictingOption){let findBestOptionFromValue=option2=>{let optionKey=option2.attributeName(),optionValue=this.getOptionValue(optionKey),negativeOption=this.options.find(target=>target.negate&&optionKey===target.attributeName()),positiveOption=this.options.find(target=>!target.negate&&optionKey===target.attributeName());return negativeOption&&(negativeOption.presetArg===void 0&&optionValue===!1||negativeOption.presetArg!==void 0&&optionValue===negativeOption.presetArg)?negativeOption:positiveOption||option2},getErrorMessage=option2=>{let bestOption=findBestOptionFromValue(option2),optionKey=bestOption.attributeName();return this.getOptionValueSource(optionKey)==="env"?`environment variable '${bestOption.envVar}'`:`option '${bestOption.flags}'`},message=`error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;this.error(message,{code:"commander.conflictingOption"})}unknownOption(flag){if(this._allowUnknownOption)return;let suggestion="";if(flag.startsWith("--")&&this._showSuggestionAfterError){let candidateFlags=[],command=this;do{let moreFlags=command.createHelp().visibleOptions(command).filter(option=>option.long).map(option=>option.long);candidateFlags=candidateFlags.concat(moreFlags),command=command.parent}while(command&&!command._enablePositionalOptions);suggestion=suggestSimilar(flag,candidateFlags)}let message=`error: unknown option '${flag}'${suggestion}`;this.error(message,{code:"commander.unknownOption"})}_excessArguments(receivedArgs){if(this._allowExcessArguments)return;let expected=this.registeredArguments.length,s=expected===1?"":"s",
|
|
26
|
-
`),this._exit(0,"commander.version",str)}),this}description(str,argsDescription){return str===void 0&&argsDescription===void 0?this._description:(this._description=str,argsDescription&&(this._argsDescription=argsDescription),this)}summary(str){return str===void 0?this._summary:(this._summary=str,this)}alias(alias){if(alias===void 0)return this._aliases[0];let command=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(command=this.commands[this.commands.length-1]),alias===command._name)throw new Error("Command alias can't be the same as its name");let matchingCommand=this.parent?._findCommand(alias);if(matchingCommand){let existingCmd=[matchingCommand.name()].concat(matchingCommand.aliases()).join("|");throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`)}return command._aliases.push(alias),this}aliases(aliases){return aliases===void 0?this._aliases:(aliases.forEach(alias=>this.alias(alias)),this)}usage(str){if(str===void 0){if(this._usage)return this._usage;let args=this.registeredArguments.map(arg=>humanReadableArgName(arg));return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?args:[]).join(" ")}return this._usage=str,this}name(str){return str===void 0?this._name:(this._name=str,this)}helpGroup(heading){return heading===void 0?this._helpGroupHeading??"":(this._helpGroupHeading=heading,this)}commandsGroup(heading){return heading===void 0?this._defaultCommandGroup??"":(this._defaultCommandGroup=heading,this)}optionsGroup(heading){return heading===void 0?this._defaultOptionGroup??"":(this._defaultOptionGroup=heading,this)}_initOptionGroup(option){this._defaultOptionGroup&&!option.helpGroupHeading&&option.helpGroup(this._defaultOptionGroup)}_initCommandGroup(cmd){this._defaultCommandGroup&&!cmd.helpGroup()&&cmd.helpGroup(this._defaultCommandGroup)}nameFromFilename(filename){return this._name=
|
|
25
|
+
`),this.outputHelp({error:!0}));let config=errorOptions||{},exitCode=config.exitCode||1,code=config.code||"commander.error";this._exit(exitCode,code,message)}_parseOptionsEnv(){this.options.forEach(option=>{if(option.envVar&&option.envVar in process2.env){let optionKey=option.attributeName();(this.getOptionValue(optionKey)===void 0||["default","config","env"].includes(this.getOptionValueSource(optionKey)))&&(option.required||option.optional?this.emit(`optionEnv:${option.name()}`,process2.env[option.envVar]):this.emit(`optionEnv:${option.name()}`))}})}_parseOptionsImplied(){let dualHelper=new DualOptions(this.options),hasCustomOptionValue=optionKey=>this.getOptionValue(optionKey)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(optionKey));this.options.filter(option=>option.implied!==void 0&&hasCustomOptionValue(option.attributeName())&&dualHelper.valueFromOption(this.getOptionValue(option.attributeName()),option)).forEach(option=>{Object.keys(option.implied).filter(impliedKey=>!hasCustomOptionValue(impliedKey)).forEach(impliedKey=>{this.setOptionValueWithSource(impliedKey,option.implied[impliedKey],"implied")})})}missingArgument(name){let message=`error: missing required argument '${name}'`;this.error(message,{code:"commander.missingArgument"})}optionMissingArgument(option){let message=`error: option '${option.flags}' argument missing`;this.error(message,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(option){let message=`error: required option '${option.flags}' not specified`;this.error(message,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(option,conflictingOption){let findBestOptionFromValue=option2=>{let optionKey=option2.attributeName(),optionValue=this.getOptionValue(optionKey),negativeOption=this.options.find(target=>target.negate&&optionKey===target.attributeName()),positiveOption=this.options.find(target=>!target.negate&&optionKey===target.attributeName());return negativeOption&&(negativeOption.presetArg===void 0&&optionValue===!1||negativeOption.presetArg!==void 0&&optionValue===negativeOption.presetArg)?negativeOption:positiveOption||option2},getErrorMessage=option2=>{let bestOption=findBestOptionFromValue(option2),optionKey=bestOption.attributeName();return this.getOptionValueSource(optionKey)==="env"?`environment variable '${bestOption.envVar}'`:`option '${bestOption.flags}'`},message=`error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;this.error(message,{code:"commander.conflictingOption"})}unknownOption(flag){if(this._allowUnknownOption)return;let suggestion="";if(flag.startsWith("--")&&this._showSuggestionAfterError){let candidateFlags=[],command=this;do{let moreFlags=command.createHelp().visibleOptions(command).filter(option=>option.long).map(option=>option.long);candidateFlags=candidateFlags.concat(moreFlags),command=command.parent}while(command&&!command._enablePositionalOptions);suggestion=suggestSimilar(flag,candidateFlags)}let message=`error: unknown option '${flag}'${suggestion}`;this.error(message,{code:"commander.unknownOption"})}_excessArguments(receivedArgs){if(this._allowExcessArguments)return;let expected=this.registeredArguments.length,s=expected===1?"":"s",message=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;this.error(message,{code:"commander.excessArguments"})}unknownCommand(){let unknownName=this.args[0],suggestion="";if(this._showSuggestionAfterError){let candidateNames=[];this.createHelp().visibleCommands(this).forEach(command=>{candidateNames.push(command.name()),command.alias()&&candidateNames.push(command.alias())}),suggestion=suggestSimilar(unknownName,candidateNames)}let message=`error: unknown command '${unknownName}'${suggestion}`;this.error(message,{code:"commander.unknownCommand"})}version(str,flags,description){if(str===void 0)return this._version;this._version=str,flags=flags||"-V, --version",description=description||"output the version number";let versionOption=this.createOption(flags,description);return this._versionOptionName=versionOption.attributeName(),this._registerOption(versionOption),this.on("option:"+versionOption.name(),()=>{this._outputConfiguration.writeOut(`${str}
|
|
26
|
+
`),this._exit(0,"commander.version",str)}),this}description(str,argsDescription){return str===void 0&&argsDescription===void 0?this._description:(this._description=str,argsDescription&&(this._argsDescription=argsDescription),this)}summary(str){return str===void 0?this._summary:(this._summary=str,this)}alias(alias){if(alias===void 0)return this._aliases[0];let command=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(command=this.commands[this.commands.length-1]),alias===command._name)throw new Error("Command alias can't be the same as its name");let matchingCommand=this.parent?._findCommand(alias);if(matchingCommand){let existingCmd=[matchingCommand.name()].concat(matchingCommand.aliases()).join("|");throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`)}return command._aliases.push(alias),this}aliases(aliases){return aliases===void 0?this._aliases:(aliases.forEach(alias=>this.alias(alias)),this)}usage(str){if(str===void 0){if(this._usage)return this._usage;let args=this.registeredArguments.map(arg=>humanReadableArgName(arg));return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?args:[]).join(" ")}return this._usage=str,this}name(str){return str===void 0?this._name:(this._name=str,this)}helpGroup(heading){return heading===void 0?this._helpGroupHeading??"":(this._helpGroupHeading=heading,this)}commandsGroup(heading){return heading===void 0?this._defaultCommandGroup??"":(this._defaultCommandGroup=heading,this)}optionsGroup(heading){return heading===void 0?this._defaultOptionGroup??"":(this._defaultOptionGroup=heading,this)}_initOptionGroup(option){this._defaultOptionGroup&&!option.helpGroupHeading&&option.helpGroup(this._defaultOptionGroup)}_initCommandGroup(cmd){this._defaultCommandGroup&&!cmd.helpGroup()&&cmd.helpGroup(this._defaultCommandGroup)}nameFromFilename(filename){return this._name=path7.basename(filename,path7.extname(filename)),this}executableDir(path8){return path8===void 0?this._executableDir:(this._executableDir=path8,this)}helpInformation(contextOptions){let helper=this.createHelp(),context=this._getOutputContext(contextOptions);helper.prepareContext({error:context.error,helpWidth:context.helpWidth,outputHasColors:context.hasColors});let text2=helper.formatHelp(this,helper);return context.hasColors?text2:this._outputConfiguration.stripColor(text2)}_getOutputContext(contextOptions){contextOptions=contextOptions||{};let error=!!contextOptions.error,baseWrite,hasColors,helpWidth;return error?(baseWrite=str=>this._outputConfiguration.writeErr(str),hasColors=this._outputConfiguration.getErrHasColors(),helpWidth=this._outputConfiguration.getErrHelpWidth()):(baseWrite=str=>this._outputConfiguration.writeOut(str),hasColors=this._outputConfiguration.getOutHasColors(),helpWidth=this._outputConfiguration.getOutHelpWidth()),{error,write:str=>(hasColors||(str=this._outputConfiguration.stripColor(str)),baseWrite(str)),hasColors,helpWidth}}outputHelp(contextOptions){let deprecatedCallback;typeof contextOptions=="function"&&(deprecatedCallback=contextOptions,contextOptions=void 0);let outputContext=this._getOutputContext(contextOptions),eventContext={error:outputContext.error,write:outputContext.write,command:this};this._getCommandAndAncestors().reverse().forEach(command=>command.emit("beforeAllHelp",eventContext)),this.emit("beforeHelp",eventContext);let helpInformation=this.helpInformation({error:outputContext.error});if(deprecatedCallback&&(helpInformation=deprecatedCallback(helpInformation),typeof helpInformation!="string"&&!Buffer.isBuffer(helpInformation)))throw new Error("outputHelp callback must return a string or a Buffer");outputContext.write(helpInformation),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit("afterHelp",eventContext),this._getCommandAndAncestors().forEach(command=>command.emit("afterAllHelp",eventContext))}helpOption(flags,description){return typeof flags=="boolean"?(flags?(this._helpOption===null&&(this._helpOption=void 0),this._defaultOptionGroup&&this._initOptionGroup(this._getHelpOption())):this._helpOption=null,this):(this._helpOption=this.createOption(flags??"-h, --help",description??"display help for command"),(flags||description)&&this._initOptionGroup(this._helpOption),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(option){return this._helpOption=option,this._initOptionGroup(option),this}help(contextOptions){this.outputHelp(contextOptions);let exitCode=Number(process2.exitCode??0);exitCode===0&&contextOptions&&typeof contextOptions!="function"&&contextOptions.error&&(exitCode=1),this._exit(exitCode,"commander.help","(outputHelp)")}addHelpText(position,text2){let allowedValues=["beforeAll","before","after","afterAll"];if(!allowedValues.includes(position))throw new Error(`Unexpected value for position to addHelpText.
|
|
27
27
|
Expecting one of '${allowedValues.join("', '")}'`);let helpEvent=`${position}Help`;return this.on(helpEvent,context=>{let helpStr;typeof text2=="function"?helpStr=text2({error:context.error,command:context.command}):helpStr=text2,helpStr&&context.write(`${helpStr}
|
|
28
|
-
`)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();helpOption&&args.find(arg=>helpOption.is(arg))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}}}});var program,init_commander=__esm({"../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/index.js"(){init_argument();init_command();init_error();init_help();init_option();program=new Command}});var APP_PROFILE_NAME_LIST,DEVICE_PRESET_TYPE,PAGE_DIAGNOSTICS_PARAM,PAGE_OBSERVE_PARAM,PAGE_ACTION_RESULT,COMMANDS,COMMAND_MAP,init_commands=__esm({"../client/src/commands.ts"(){"use strict";init_browser_action_protocol();APP_PROFILE_NAME_LIST=APP_PROFILE_NAMES.join("/"),DEVICE_PRESET_TYPE=BROWSER_DEVICE_PRESET_NAMES.map(name=>JSON.stringify(name)).join(" | "),PAGE_DIAGNOSTICS_PARAM={name:"diagnostics",type:"object | boolean",description:"默认关闭;传 true 返回动作期间新增的 error logs/业务 requests,或传对象自定义通道与过滤",details:["logs: boolean | { level, limit, filter };true 默认采集 error 日志","requests: boolean | { count, filter, source, includeBody, includeHeaders, maxBodySize, fields, keysOnly }","events: boolean | { source, event_type, filter, limit, includeRaw };埋点需显式开启","各通道过滤字段同 get_logs / get_requests / get_events;observe=false 时仍返回诊断增量,但不等待 DOM/导航稳定"]},PAGE_OBSERVE_PARAM={name:"observe",type:"object | false",description:"默认开启 DOM/导航观察;传 false 关闭,不影响显式请求的 diagnostics",details:["quietMs: number,DOM 变化后的稳定窗口,默认 100ms","firstChangeTimeoutMs: number,无 DOM 变化时的观察窗口,默认 500ms","timeoutMs: number,DOM 观察阶段最大时间,默认 3000ms","navigationGraceMs: number,低信息量点击/按键的导航宽限,默认 1000ms;相关网络活动可延长宽限","navigationTimeoutMs: number,导航就绪最大等待时间,默认 15000ms","networkIdleMs: number,文档完成且相关请求归零后的静默时间,默认 500ms","contentReadyAfterMs: number,结构稳定兜底保护期,默认 min(5000, navigationTimeoutMs / 2),并限制在导航超时前"]},PAGE_ACTION_RESULT=["默认返回 { action, observation };action.success 只表示动作成功,业务效果需结合 observation 和目标状态判断。","observe=false 且未开启 diagnostics 时返回裸动作结果(如 { clicked: true }),没有 action/observation;开启 diagnostics 时返回 { action, diagnostics }。","包装结果中的 action.stage=precondition 表示未派发,省略 observation/diagnostics;dispatch-uncertain 表示可能已派发,先查看 action.attempt 与可用观察或最小快照核验,避免重复提交。CLI 单次调用失败以退出码 1 结束;脚本需检查 action.success。","observation.effects 返回通知、控件和焦点增量,可直接复用 node.ref/selector;changed=true 且 effects 为空不表示失败。","effects.texts 按需返回普通可见文本的 selector/text,不代表可点击控件或业务成功;超限或覆盖不完整时仍提示补快照。","fullSnapshotRecommended/snapshotReasons 提示是否补充快照;openedTabs 返回可继续操作的 tabId 和 ready。navigation 模式的 ready 表示新页面就绪。","显式开启的诊断通道在 diagnostics 中返回动作期间增量,与 observe 独立。"],COMMANDS=[{name:"browser_control",description:"把控制会话交给用户;用户在 Mearl 浏览器管理页交还后重新观察页面",params:[{name:"operation",type:'"handoff" | "resume"',required:!0,description:"交给用户操作;resume 仅在用户明确交还后使用"},{name:"tabId",type:"number",description:"可选的目标页面"},{name:"reason",type:"string",description:"用户需要处理的事项"}],notes:["必须携带 --session;接管停止后续派发,已经发出的操作可能仍然生效。"]},{name:"page_download",description:"先监听再点击,等待下载完成并创建浏览器文件产物",outputFlag:!0,params:[{name:"tabId",type:"number",required:!0,description:"下载来源页面"},{name:"trigger",type:"object",required:!0,description:"page_click 参数,不含 tabId"},{name:"url",type:"string",description:"预期下载 URL;扩展无法通过 referrer 归属时需显式指定"},{name:"timeout",type:"number",description:"下载等待毫秒,默认 30000,范围 1000–300000"}],notes:["--output 把文件分块保存到调用方机器;未指定时返回 artifactId,可供 page_upload 复用。","共享 CDP 浏览器保持原下载目录;Chrome 未返回文件路径时明确报错。超时不能直接重复点击。"]},{name:"tab_checkpoint",description:"为目标标签页建立日志、请求和埋点增量边界",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_open 获取"}],examples:[`tab_checkpoint --payload '{"tabId":12345}'`]},{name:"get_requests",description:"获取最近的网络请求(mtop 或普通 xhr/fetch)",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"count",type:"number",description:"返回条数,默认 10"},{name:"source",type:'"mtop" | "requests" | "all"',description:"数据来源,不填时默认 mtop;all 返回全部业务请求"},{name:"filter",type:"string",description:"按 URL 或 API 名称过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的请求"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的请求"},{name:"includeBody",type:"boolean",description:"是否包含请求/响应体;指定 fields 时默认 false,否则默认 true"},{name:"includeHeaders",type:"boolean",description:"是否包含请求/响应头,默认 false"},{name:"maxBodySize",type:"number",description:"单个请求/响应体最大字符数,默认 50000"},{name:"fields",type:"string[]",description:"从响应体提取指定字段路径,最多 100 个"},{name:"keysOnly",type:"boolean",description:"只返回数据结构,不返回叶子值"}],notes:["流式请求开始后即进入缓冲区;页面及 App 桥代发的 MTop SSE 都归入 mtop。无法归属当前页面 target 的 Service Worker 请求不在采集范围内。"],result:["nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。","省略正文时不返回 postData / responseBody 字段;指定 fields 后需要同时读取全文时显式传 includeBody:true。","isPending 标记未完成请求;SSE 的 responseBody 保存按序到达的 event/data/timestamp/duration 分片。敏感请求头返回脱敏值。"],examples:[`get_requests --payload '{"tabId":12345,"count":5}'`,`get_requests --payload '{"tabId":12345,"source":"mtop","filter":"cart"}'`]},{name:"get_logs",description:"获取浏览器控制台日志",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"limit",type:"number",description:"返回最新 N 条,默认 100"},{name:"level",type:"string",description:"按日志级别过滤:log/info/warn/error/all"},{name:"filter",type:"string",description:"按内容过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的日志"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的日志"}],result:["nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。"],examples:[`get_logs --payload '{"tabId":12345,"limit":10,"level":"error"}'`]},{name:"get_events",description:"获取 RUM/aplus/ARMS 埋点事件",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"source",type:'"rum" | "aplus" | "arms" | "all"',description:"数据来源,默认 all"},{name:"event_type",type:"string",description:"按事件类型过滤,支持正则,如 CLK/PV"},{name:"filter",type:"string",description:"按 name 或 url 过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的事件"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 之后的事件"},{name:"limit",type:"number",description:"返回条数,默认 20"},{name:"includeRaw",type:"boolean",description:"返回完整 URL、_raw 和 _context;默认 false"}],notes:["tab_open 新页从首屏采集;既有页面首次查询才启用采集,需要刷新或重新触发埋点。同批事件不会被 limit 拆开。"],result:["nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。","captureStatus 为 armed/active/inactive;空结果附 hint 时按提示刷新或触发。默认去除 tracking URL query 与 _raw/_context,includeRaw=true 时保留。"],examples:[`get_events --payload '{"tabId":12345,"source":"aplus","event_type":"CLK","limit":10}'`,`get_events --payload '{"tabId":12345,"filter":"order","includeRaw":true,"limit":1}'`,`get_events --payload '{"tabId":12345,"source":"all","limit":20}'`]},{name:"set_mock",description:"设置 API mock 数据",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",required:!0,description:"API 名称或正则表达式"},{name:"mockData",type:"object",description:"完整 mock 响应数据(与 fields 二选一)"},{name:"fields",type:"array",description:"按字段路径修改真实响应(与 mockData 二选一)"},{name:"enabled",type:"boolean",description:"是否启用,默认 true。false 时恢复真实数据"},{name:"duration",type:"number",description:"完整响应时长(毫秒):mock 的总耗时,绕过真实服务器精确控制"},{name:"conditions",type:"object",description:"请求 query/body 字段子集匹配;$index 从 0 开始指定调用顺序"}],notes:["启用时至少提供 mockData 或非空 fields;非空 fields 优先。fields 每项 { path: string, value: any },path 支持点号和数组索引。","相同 apiName 的多条无条件 Mock 会覆盖;conditions 子集匹配 query/body(含 data 内层),不同条件可共存;$index 从 0 起控制调用顺序,不参与字段匹配。","大字段可用顶层 @<绝对路径> 文件引用或 --payload-file;文件展开后仍受 Native Messaging 单条消息大小限制。"],examples:[`set_mock --payload '{"tabId":12345,"apiName":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,"set_mock --payload-file ./mock-data.json"]},{name:"get_mocks",description:"查看当前生效的 mock 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",description:"按 API 名称或正则表达式过滤"}],examples:[`get_mocks --payload '{"tabId":12345}'`]},{name:"set_rule",description:"添加浏览器请求规则;enabled=false 且传 ruleId 时彻底删除规则",params:[{name:"ruleId",type:"number",description:"删除时必填,从 get_rules 获取"},{name:"enabled",type:"boolean",description:"省略时添加;false 时按 ruleId 删除"},{name:"actionType",type:'"redirect" | "block" | "allow" | "upgradeScheme" | "modifyHeaders"',description:"添加时必填,规则动作"},{name:"filter",type:"string",description:"添加时必填,URL 过滤表达式"},{name:"redirectUrl",type:"string",description:"redirect 动作的目标 URL"},{name:"requestHeaders",type:"array",description:"modifyHeaders 动作的请求头修改列表",details:['每项 { header: string, operation: "set" | "append" | "remove", value?: string };set/append 需 value']},{name:"responseHeaders",type:"array",description:"modifyHeaders 动作的响应头修改列表",details:['每项 { header: string, operation: "set" | "append" | "remove", value?: string };set/append 需 value']},{name:"initiatorDomains",type:"string",description:"发起方域名过滤"},{name:"resourceTypes",type:"string[]",description:"资源类型过滤"},{name:"priority",type:"number",description:"规则优先级"},{name:"description",type:"string",description:"规则说明"}],notes:["扩展模式规则持久化;CDP 仅支持会话级 modifyHeaders 请求头 set,不支持响应头、initiatorDomains 或其他动作。Provider 是否支持以其能力声明为准。","扩展模式会检查规则请求 URL 和显式来源域名的访问权限;缺失时仍保存规则,返回 warnings 和 missingOrigins,不自动弹窗。可在请求规则页面授权,或按提示调用 request_domain_permission。复杂 URL 表达式无法完整推断域名时会提示手动检查。"],examples:[`set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`,`set_rule --payload '{"ruleId":42,"enabled":false}'`]},{name:"get_rules",description:"查看当前模式的请求规则;扩展模式包含 Options 面板配置的规则",examples:["get_rules"]},{name:"send_request",description:"发送 HTTP 请求,自动携带浏览器 Cookie,支持 multipart 和原始二进制上传",params:[{name:"url",type:"string",required:!0,description:"完整目标 URL"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"headers",type:"object",description:"自定义请求头"},{name:"params",type:"object",description:"URL 查询参数"},{name:"body",type:"any",description:"请求体(传对象时自动 JSON 序列化)"},{name:"bodyFile",type:"object",description:"原始二进制请求体:filePath 或 base64 二选一,可选 contentType(默认 application/octet-stream);与 body/formData/files 互斥"},{name:"formData",type:"object",description:"multipart 文本字段(值支持 string/number/boolean)"},{name:"files",type:"SendRequestFile[]",description:"multipart 文件,最多 20 个、总计不超过 40 MiB;Base64 文件总计不超过 7 MiB。每项传 fieldName 和绝对 filePath,或传 base64 + filename",details:["fieldName: string(必填);filePath: string 与 base64: string 二选一","filename: string,base64 时必填,filePath 时默认文件 basename","contentType: string(可选),默认按文件名推断 MIME,否则 application/octet-stream"]},{name:"withCookies",type:"boolean",description:"是否附加浏览器 Cookie,默认 true"},{name:"responseType",type:'"json" | "text" | "auto"',description:"响应解析方式,默认 auto"},{name:"timeout",type:"number",description:"超时毫秒数,默认 30000"}],notes:["仅用于非 BUC 请求;BUC 接口使用 mearl buc,不手工传 Token、DPoP 或 Ticket。","body 不能与 formData/files 组合;bodyFile 以原始字节发送,不包 multipart boundary,不能用于 GET/HEAD。","bodyFile.filePath 属于 native-host,最大 40 MiB;base64 解码后最大 7 MiB。multipart 不手工设置 Content-Type,由 Mearl 生成 boundary。","filePath 属于 native-host 所在机器;无法引用远端路径时用 base64。BUC 上传的路径属于插件执行宿主。"],result:["返回 status、statusText、headers、body、bodyType、attachedCookieCount;bodyType 为 json/text/base64,二进制 body 需解码后保存。"],examples:[`send_request --payload '{"url":"https://api.example.com/data","method":"GET"}'`,`send_request --payload '{"url":"https://api.example.com/upload","method":"POST","formData":{"folder":"assets"},"files":[{"fieldName":"file","filePath":"/absolute/path/image.png"}]}'`,`send_request --payload '{"url":"https://api.example.com/upload","method":"POST","bodyFile":{"filePath":"/absolute/path/image.png","contentType":"image/png"}}'`]},{name:"send_mtop_request",description:"使用目标浏览器 Cookie 发起 mtop 请求,自动处理签名和 token",params:[{name:"api",type:"string",required:!0,description:"mtop API 名称"},{name:"data",type:"object",description:"请求数据"},{name:"version",type:"string",description:"API 版本,默认 1.0"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"appKey",type:"string",description:"签名使用的 appKey,默认 12574478"},{name:"env",type:'"prod" | "pre"',description:"请求环境,默认 prod"},{name:"timeout",type:"number",description:"超时毫秒数,默认 10000"}],notes:["需要目标浏览器有对应登录态;Mearl 自动处理签名,不依赖页面脚本。api 以 mopen. 开头时使用 mopen 协议。","env=prod 使用 h5api.m.taobao.com,pre 使用 h5api.wapa.taobao.com。"],result:["返回 success、response、requestData;业务成功需检查 response.ret。"],examples:[`send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`]},{name:"browser_list",description:"列出所有浏览器及其连接状态、类型和 Provider 托管实例信息",summary:"列出本地及远端浏览器与连接状态",examples:["browser_list"]},{name:"browser_release",description:"释放当前浏览器的调试控制和会话级临时效果(含设备/时区模拟);不用于普通任务收尾,Provider 实例的行为以 mearl <providerId> 为准",params:[{name:"closeCreatedTabs",type:"boolean",description:"带 --session 时关闭会话创建的过程页,默认 false"},{name:"keepTabIds",type:"number[]",description:"保留的结果页面;复用的用户页面始终保留"},{name:"preserveEnvironment",type:"boolean",description:"带 --session 时默认 true,保留 Mock 与模拟现场;false 清理这些页面的环境"},{name:"keepArtifactIds",type:"string[]",description:"保留在浏览器宿主的文件产物;其余会话临时文件删除"}],notes:["带 --session 时可用于任务收尾,只释放该会话;未带会话时保留原浏览器级释放行为,活动会话存在时拒绝全局释放。"],summary:"释放浏览器调试控制和会话级临时效果",examples:["browser_release","browser_release --browser chrome-a"]},{name:"browser_launch",description:"启动本地 Chrome,或通过已注册 Provider 创建浏览器实例",params:[{name:"name",type:"string",description:"本地实例名称;使用 local Provider 时必填"},{name:"provider",type:"string",description:"运行环境,默认 local;可传 mearl --help 中展示的已注册 Provider ID"},{name:"providerOptions",type:"Record<string, JSON value>",description:"所选 Provider 声明的结构化启动参数;不能与顶层启动字段混用"},{name:"headless",type:"boolean",description:"本地 Provider 是否无头运行,默认 true"},{name:"userAgentMode",type:'"default" | "desktop"',description:"本地 UA 模式:default 使用默认 UA;desktop 使用匹配本机版本的 UA"},{name:"persistent",type:"boolean",description:"本地实例关闭后是否保留 Profile,默认 false"},{name:"url",type:"string",description:"登录完成后打开的初始页面"},{name:"executablePath",type:"string",description:"自定义 Chrome 可执行文件路径"},{name:"copyCookieDomains",type:'string[] | "mearl-services" | { presets?: ["mearl-services"]; domains?: string[] }',description:"从控制浏览器复制 Cookie:可传域名数组、Mearl 登录态预设,或组合预设与额外域名"}],examples:[`browser_launch --payload '{"provider":"brow","providerOptions":{}}'`,`browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,`browser_launch --payload '{"name":"with-cookies","copyCookieDomains":["example.com","sub.example.org"]}'`]},{name:"browser_close",description:"关闭指定托管浏览器,并按 Provider 策略保留或清理持久化数据",params:[{name:"browser",type:"string",required:!0,description:"托管浏览器的 browserId 或名称"},{name:"deleteProfile",type:"boolean",description:"强制删除持久化数据,默认 false"}],examples:[`browser_close --payload '{"browser":"managed:account-a"}'`,`browser_close --payload '{"browser":"account-b","deleteProfile":true}'`]},{name:"tab_open",description:"打开或按 URL 规则复用 Tab,并等待新页面加载完成",aliases:["tab_new","new_tab","tab_create","create_tab"],params:[{name:"url",type:"string",required:!0,description:"要打开的 URL"},{name:"active",type:"boolean",description:"是否激活目标 Tab,默认 false;扩展免打扰默认开启,使用后台焦点模拟,关闭后才切换前台;响应返回 activation"},{name:"openerTabId",type:"number",description:"来源 Tab ID;用于把目标 Tab 关联到来源侧边栏对话"},{name:"closeExisting",type:"boolean",description:"打开前先关闭 Agent 受控的已有标签页,默认 false"},{name:"group",type:"string",description:"把新 Tab 加入指定标题的标签页分组(同名分组存在则加入,否则新建)。仅扩展模式支持"},{name:"reuse",type:'"never" | "prefer" | "require"',description:"never 始终新开;prefer 优先复用;require 只允许复用。默认 never"},{name:"match",type:"object",description:"复用匹配规则:urlPattern(支持 *)、ignoreSearch、ignoreHash、onMultiple(error/first)"},{name:"restoreFocusOnClose",type:"boolean",description:"关闭本次新开的 active Tab 后恢复原活动标签页,默认 false"},{name:"emulation",type:"object",description:"开 tab 即进入移动端模拟态(首屏即移动态、无需 reload)。字段同 set_device_emulation 去掉 enabled/reload;与 appProfile、deviceShell=true、orientation=landscape、splitScreen=true 组合可首屏进入左右分屏"},{name:"appProfile",type:"string",description:'开 tab 即注入 App 客户端环境与 JSBridge;档案名同 set_app_profile,如 "fliggy"。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true'},{name:"os",type:'"ios" | "android"',description:"与 appProfile 配合;容器系统,默认 ios"},{name:"bridgeConfig",type:"object",description:"与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}"}],notes:["emulation / appProfile 只应用到新建 Tab;复用 Tab 要切换状态时用对应设置 action。","closeExisting 不能与复用或 openerTabId 组合;多匹配默认报错,match.onMultiple=first 可显式选择第一个。"],result:["返回 tabId、url、title、opened/reused;reused=true 的既有页面应保留。","active=true 时 activation 包含 tabActive、windowFocused、windowState、visibilityState;emulation 返回实际生效配置。","capture.cursor 是导航前诊断边界,可分别用于 get_logs/get_requests/get_events 的 after。"],examples:[`tab_open --payload '{"url":"https://example.com"}'`,`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-17-pro"}}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy"}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`tab_open --payload '{"url":"https://example.com","appProfile":"fliggy","os":"android"}'`,`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`]},{name:"tab_close",description:"关闭指定标签页",aliases:["tab_remove","remove_tab","tab_delete","delete_tab"],params:[{name:"tabId",type:"number",required:!0,description:"要关闭的标签页 ID"}],examples:[`tab_close --payload '{"tabId":123}'`]},{name:"tab_list",description:"列出目标浏览器所有窗口中的标签页",aliases:["tabs","list_tabs","show_tabs"],examples:["tab_list"]},{name:"tab_group",description:"把同一窗口中的标签页加入分组,或通过 ungroup 取消分组并保留标签页;仅扩展模式支持",params:[{name:"tabIds",type:"number[]",required:!0,description:"标签页 ID,分组最多 100 个,取消分组最多 1000 个"},{name:"title",type:"string",required:!1,description:"分组标题;取消分组时省略"},{name:"ungroup",type:"boolean",required:!1,description:"为 true 时取消分组并保留标签页"}],examples:[`tab_group --payload '{"tabIds":[123,124],"title":"项目文档"}'`,`tab_group --payload '{"tabIds":[123,124],"ungroup":true}'`]},{name:"page_click",description:"点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位",params:[{name:"selector",type:"string",description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类"},{name:"text",type:"string",description:"按可见文本(accessibility name)定位。需要时配合 role/exact 消歧;多匹配会报错并列出候选"},{name:"point",type:"{ x: number; y: number }",description:'按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: "active-frame"'},{name:"frameId",type:"string",description:"浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame"},{name:"coordinateSpace",type:'"outer-viewport" | "active-frame"',description:"仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入"},{name:"role",type:"string",description:"配合 text 使用,按 AX role 过滤(如 button、link、heading)"},{name:"exact",type:"boolean",description:"配合 text 使用,默认 true 精确匹配;false 时按子串匹配"},{name:"scope",type:"string",description:"配合 text 使用,把文本匹配限制在指定 CSS 元素或 @eN ref 子树内,适合消除重复文案歧义"},{name:"clickMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,notes:["selector / text / point 必须且只能提供一个。隐藏页 auto 使用 DOM;只有明确依赖真实用户手势时才激活页面。","原生 select 可按 option 文本点击;checkbox/radio 返回 controlState.checkedBefore/checkedAfter。"],examples:[`page_click --payload '{"tabId":12345,"text":"提交"}'`,`page_click --payload '{"tabId":12345,"text":"退款明细","role":"button"}'`,`page_click --payload '{"tabId":12345,"text":"确定","scope":"@e12"}'`,`page_click --payload '{"tabId":12345,"selector":"@e3"}'`,`page_click --payload '{"tabId":12345,"selector":".submit-btn"}'`,`page_click --payload '{"tabId":12345,"selector":".gesture-btn","clickMode":"touch"}'`,`page_click --payload '{"tabId":12345,"point":{"x":336,"y":117}}'`,`page_click --payload '{"tabId":12345,"point":{"x":196,"y":240},"coordinateSpace":"active-frame"}'`]},{name:"page_drag",description:"拖动页面元素或视口坐标,适用于轮播图、滑块和拖放",params:[{name:"from",type:"string | { x: number; y: number }",required:!0,description:"起点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"to",type:"string | { x: number; y: number }",required:!0,description:"终点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"dragMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},{name:"durationMs",type:"number",description:"拖动持续时间,0–5000ms,默认 400ms;内部自动分段移动"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,notes:["起点会自动滚入视口,终点必须同时位于当前视口;否则先滚动页面。隐藏页 auto 使用 DOM,不切换活动页。"],examples:[`page_drag --payload '{"tabId":12345,"from":{"x":350,"y":80},"to":{"x":80,"y":80}}'`,`page_drag --payload '{"tabId":12345,"from":"@e3","to":"#drop-zone","dragMode":"mouse"}'`]},{name:"page_type",description:"向输入框填写文本,兼容 React 受控组件",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},{name:"text",type:"string",required:!0,description:"要填写的文本"},{name:"clearFirst",type:"boolean",description:"是否先清空原有内容,默认 true"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,examples:[`page_type --payload '{"tabId":12345,"selector":"@e6","text":"搜索关键词"}'`]},{name:"page_hover",description:"将鼠标悬停在页面元素上",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,examples:[`page_hover --payload '{"tabId":12345,"selector":".nav-menu"}'`]},{name:"page_scroll",description:"滚动页面或指定容器;页面根不可滚动时自动发现活动滚动区",params:[{name:"direction",type:'"up" | "down" | "top" | "bottom"',required:!0,description:"滚动方向"},{name:"distance",type:"number",description:"滚动距离(px),默认 600"},{name:"selector",type:"string",description:"目标滚动容器的原生 CSS 选择器,或 page_snapshot 返回的 @eN ref;不传时滚动页面"},{name:"containerPolicy",type:'"self" | "nearest"',description:"默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:[...PAGE_ACTION_RESULT,"action.data 返回 moved、atTop/atBottom、scrollYBefore/After、maxScrollY、resolvedContainer 和 ancestorDistance;自动发现的内部容器提供可复用 containerSelector。"],examples:[`page_scroll --payload '{"tabId":12345,"direction":"down"}'`,`page_scroll --payload '{"tabId":12345,"direction":"bottom"}'`,`page_scroll --payload '{"tabId":12345,"selector":".virtual-list","direction":"down","distance":800}'`,`page_scroll --payload '{"tabId":12345,"selector":"@e8","containerPolicy":"nearest","direction":"bottom"}'`]},{name:"page_runtime",description:"页面运行时传输适配器;插件使用 PluginPageClient 或 app.page",params:[{name:"operation",type:"string",required:!0,description:"resolve/attach/get/send/detach/activation"}]},{name:"page_eval",description:"在页面上下文中执行任意 JavaScript 表达式",params:[{name:"expression",type:"string",required:!0,description:"要执行的 JS 表达式;传 args 时须求值为函数"},{name:"args",type:"unknown[]",description:"传给页面函数的 JSON 参数;SDK/CLI 自动处理大参数分块,保持指定执行环境"},{name:"executionWorld",type:"string",description:"main(默认)读取网页 JS;isolated 使用命名隔离环境,扩展连接无需 debugger"},{name:"worldId",type:"string",description:"isolated 必填,小写字母开头,允许数字和连字符,最长 64 字符"},{name:"awaitPromise",type:"boolean",description:"表达式返回 Promise 时等待完成,默认 true"},{name:"frameId",type:"string",description:"page_frames 返回的目标 frame ID,扩展/CDP 均支持;省略时容器/设备外壳使用当前业务 frame,普通页面使用主 frame"},{...PAGE_OBSERVE_PARAM,type:"object",description:"仅在表达式会修改页面且需要观察结果时显式传入;不传保持轻量裸执行"},PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["优先使用结构化 action;仅在其无法表达需求时执行最小范围脚本。"],result:["默认返回 { result };observe 对象启用观察并返回 { action, observation };仅开启 diagnostics 时返回 { action, diagnostics }。diagnostics=false 不启用包装。失败阶段语义同 page_click。"],examples:[`page_eval --payload '{"tabId":12345,"expression":"document.title"}'`]},{name:"page_inspect",description:"查询 DOM 元素的控件状态、数量、边框盒、计算样式、遮挡、溢出和最近滚动容器",params:[{name:"selector",type:"string",description:"原生 CSS、page_snapshot 返回的 @eN ref,或 DevTools Elements 当前选区 $0;做全页溢出诊断时可省略"},{name:"filter",type:'"all" | "overflowing" | "horizontal-overflow" | "vertical-overflow" | "scrollable"',description:"结果过滤;省略 selector 时必须指定非 all 的过滤条件"},{name:"styles",type:"string[]",description:"要返回的计算样式属性,默认 display/position/box-sizing/overflow-x/overflow-y"},{name:"maxResults",type:"number",description:"最多返回的明细数,默认 20,最大 100;未触发 scanTruncated 时 count 为完整命中数"},{name:"includeOuterHTML",type:"boolean",description:"是否返回 outerHTML(最多 3000 字符);$0 默认 true,其他目标默认 false"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:["matches[] 包含 boundingBox、computedStyle、hitTest、scroll 溢出量及可用的 scrollContainer。receivesPointerEvents=false 时读取 occludedBy。","state 返回原生/ARIA 状态及来源;缺失字段表示未知。","$0 还返回 resolvedSelector、属性、XPath 和可用框架信息。"],examples:[`page_inspect --payload '{"tabId":12345,"selector":".form-field","styles":["display","width"]}'`,`page_inspect --payload '{"tabId":12345,"selector":"@e8"}'`,`page_inspect --payload '{"tabId":12345,"selector":"$0"}'`,`page_inspect --payload '{"tabId":12345,"filter":"horizontal-overflow"}'`,`page_inspect --payload '{"tabId":12345,"filter":"scrollable"}'`]},{name:"page_press",description:"在页面中按下键盘按键或组合键",params:[{name:"key",type:"string",required:!0,description:"按键名称:Enter/Tab/Escape/Backspace 等"},{name:"modifiers",type:"string[]",description:"修饰键数组:ctrl/alt/shift/meta/cmd"},{name:"pressMode",type:'"auto" | "dom" | "keyboard"',description:"派发模式;auto 默认在隐藏页降级为 DOM 键盘事件"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["隐藏页 DOM 模式支持 Tab 焦点移动、原生控件 Enter/Space 激活和输入框 Enter 提交;编辑、选择、方向键和页面滚动等原生行为需可见页与 pressMode=keyboard。"],result:[...PAGE_ACTION_RESULT,"action.data.dispatchMode / fallbackReason / defaultAction 说明实际输入路径。"],examples:[`page_press --payload '{"tabId":12345,"key":"Enter"}'`]},{name:"page_wait",description:"等待指定时间、元素状态、可见文本或页面条件成立",params:[{name:"time",type:"number",description:"等待毫秒数(与 selector/text/condition 四选一)"},{name:"selector",type:"string",description:"目标 CSS 选择器(与 time/text/condition 四选一)"},{name:"state",type:'"attached" | "detached" | "visible" | "hidden"',description:"selector 的目标状态,默认 attached"},{name:"text",type:"string",description:"等待页面出现的可见文本"},{name:"exact",type:"boolean",description:"text 是否精确匹配,默认 false"},{name:"condition",type:"string",description:"在页面主上下文轮询的 JS 表达式,返回 truthy 时结束"},{name:"timeout",type:"number",description:"等待超时毫秒数,默认 10000"},{name:"interval",type:"number",description:"轮询间隔毫秒数,默认 200"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["time / selector / text / condition 必须且只能提供一个;time 范围 0–60000ms。页面交互已有内置观察,仅在需要独立等待条件时使用。"],examples:[`page_wait --payload '{"tabId":12345,"time":1000}'`,`page_wait --payload '{"tabId":12345,"selector":".dialog","state":"visible"}'`,`page_wait --payload '{"tabId":12345,"selector":".loading","state":"hidden"}'`,`page_wait --payload '{"tabId":12345,"text":"提交成功"}'`,`page_wait --payload '{"tabId":12345,"condition":"window.appReady === true","timeout":30000}'`]},{name:"page_navigate",description:"在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进",params:[{name:"url",type:"string",description:"要导航到的 URL;与 refresh/history 互斥"},{name:"refresh",type:"boolean",description:"为 true 时直接重新加载当前页面;与 url/history 互斥"},{name:"history",type:'"back" | "forward"',description:"沿当前标签页浏览历史后退或前进;与 url/refresh 互斥"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["url / refresh=true / history 必须且只能提供一个。"],examples:[`page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,`page_navigate --payload '{"tabId":12345,"refresh":true}'`,`page_navigate --payload '{"tabId":12345,"history":"back"}'`]},{name:"page_upload",description:'向 <input type="file"> 元素上传一个或多个文件',params:[{name:"files",type:"object[]",description:"调用方绝对路径 {filePath} 或浏览器产物 {artifactId};与 filePaths 二选一"},{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀),必须指向 input[type=file]"},{name:"filePaths",type:"string[]",description:"浏览器宿主上的绝对路径数组;与 files 二选一"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,notes:["直接写入 input[type=file],不依赖 file chooser;隐藏的文件节点也可上传。外部 Provider 的文件中转能力查询 mearl <providerId>。"],examples:[`page_upload --payload '{"tabId":12345,"selector":"#file-input","filePaths":["/Users/me/photo.jpg"]}'`]},{name:"page_snapshot",description:"获取带 @ref 的页面结构快照,默认使用无障碍树,也可显式读取渲染 DOM",params:[{name:"depth",type:"number",description:"树深度,默认 15,复杂页面可调大"},{name:"mode",type:'"full" | "interactive" | "viewport" | "dom"',description:"默认 full;interactive/viewport 裁剪 AX 树;AX 信息缺失时可显式使用 dom 读取渲染 DOM"},{name:"rootSelector",type:"string",description:"只获取指定 CSS 元素的局部子树,可与 mode 组合;与 rootRef 互斥"},{name:"rootRef",type:"string",description:"以已有 @eN ref 为根获取局部子树;与 rootSelector 互斥"},{name:"ancestorDepth",type:"number",description:"rootRef 向上扩展的 DOM 祖先层数,默认 0,最大 20"},{name:"query",type:"{ text?: string; role?: string; exact?: boolean }",description:"服务端按 name / role 过滤当前模式的树,只保留命中节点及祖先路径"},{name:"maxNodes",type:"number",description:"最多输出节点数,0 表示不限制"},{name:"maxChars",type:"number",description:"快照文本最大字符数,默认 60000,超出保留首尾;传 0 不限制"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["query.text / query.role 至少提供一个;query.exact 默认 true。每次快照刷新有效 ref 集合。","interactive 无 AX 控件时回退到 viewport,不会自动改用 dom;Canvas 内容需截图。"],result:["返回 snapshot、elementCount、outputNodeCount、mode;截断时 truncated=true。","snapshot 中的 @eN 可直接用于操作;内部节点映射仅保存在运行时。无名称、无 ref 且无状态的分组折叠到子节点。","query 返回 matches 与完整 matchCount,matches 最多 100 项,裁剪时 matchesTruncated=true。容器/iframe 的视口裁剪返回 outerViewport、contentViewport 和滚动位置。"],examples:[`page_snapshot --payload '{"tabId":12345}'`,`page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,`page_snapshot --payload '{"tabId":1,"mode":"dom"}'`,`page_snapshot --payload '{"tabId":1,"rootSelector":"[role=dialog]"}'`,`page_snapshot --payload '{"tabId":1,"rootRef":"@e8","ancestorDepth":1}'`,`page_snapshot --payload '{"tabId":1,"query":{"text":"保存","role":"button"}}'`]},{name:"page_screenshot",description:"获取当前视口或指定元素截图",outputFlag:!0,params:[{name:"selector",type:"string",description:"CSS 选择器,提供后只截取该元素区域"},{name:"format",type:'"png" | "jpeg"',description:"图片格式,默认 png"},{name:"quality",type:"number",description:"JPEG 压缩质量(0-100),默认 80"},{name:"captureMode",type:'"cdp" | "visible"',description:"默认 cdp;visible 使用活动标签页截图,普通网页无需 debugger;设备模拟复用模拟会话并截取业务视口,不支持 selector"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["使用 --output <path> 保存图片;省略时 stdout 返回含 base64 data 的 JSON,避免直接将其加载为文本。"],result:["meta 包含 format、width、height、size、url、title;宽高为实际截图的物理像素。"],examples:[`page_screenshot --payload '{"tabId":12345}' --output ./screenshot.png`,`page_screenshot --payload '{"tabId":12345,"selector":".product-card"}' --output ./card.png`]},{name:"set_device_emulation",description:"把目标 tab 切换为移动端模拟(视口/DPR/UA/触摸/视觉比例),等价 DevTools 设备工具栏,作用域 per-tab;需保持调试控制才持续生效",summary:"设置或清除目标标签页的设备模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"preset",type:DEVICE_PRESET_TYPE,description:"内置设备预设,提供 width/height/DPR/UA 默认值;旧机型 ID 继续兼容"},{name:"width",type:"number",description:"视口宽度(覆盖 preset)"},{name:"height",type:"number",description:"视口高度(覆盖 preset)"},{name:"deviceScaleFactor",type:"number",description:"DPR(覆盖 preset)"},{name:"scale",type:"number",description:"画面视觉比例,不改变视口尺寸或 DPR;必须为有限正数,默认 1"},{name:"mobile",type:"boolean",description:"是否走移动渲染模式,默认从 preset 推断"},{name:"userAgent",type:"string",description:"自定义 UA(覆盖 preset)"},{name:"orientation",type:'"portrait" | "landscape"',description:"横竖屏,默认 portrait"},{name:"touch",type:"boolean",description:"是否启用触摸事件,默认从 preset 推断;无 preset 时跟随 mobile"},{name:"deviceShell",type:"boolean",description:"是否使用 iframe WebView 并渲染顶部状态栏与底部操作区,默认 false"},{name:"splitScreen",type:"boolean",description:"是否将首页与业务页分置左右 WebView;仅在已启用 App 档案、deviceShell=true、横屏时生效,默认 false"},{name:"reload",type:"boolean",description:"启用后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["无 preset 时 width/height 必须成对提供且 userAgent 必填;mobile 默认 true,touch 跟随 mobile。","deviceShell 开启/移除时必须重载;splitScreen 仅在已启用 App 档案、deviceShell=true、横屏时生效。"],result:["返回实际 viewport(width/height/deviceScaleFactor/scale)、UA、mobile、touch、orientation、deviceShell、splitScreen 和 reloaded;应以响应确认生效状态。"],examples:[`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"iphone-17-pro"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"pixel-11","orientation":"landscape"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":false}'`]},{name:"set_app_profile",description:"设置 App 客户端环境与 JSBridge;可同时设置 MTop 页面接口环境,传 emulation 时联动设备模拟",summary:"设置或清除目标标签页的 App 容器模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"profile",type:"string",description:`容器档案名(enabled=true 时必填);内置 ${APP_PROFILE_NAME_LIST}`},{name:"os",type:'"ios" | "android"',description:"容器系统,默认 ios"},{name:"refreshDefinition",type:"boolean",description:"立即采用最新档案定义,保留用户显式设置"},{name:"lockDefinition",type:"boolean",description:"固定当前定义;默认在下次刷新或文档导航时自动更新"},{name:"appVersion",type:"string",description:"覆盖档案默认 App 版本号"},{name:"deviceModel",type:"string",description:"Android 机型名(拼入 UA 与 __DEVICE_MODEL__)"},{name:"bridgeConfig",type:"object",description:"声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本"},{name:"mtopEnv",type:'"default" | "prod" | "pre"',description:"可选 MTop 页面接口环境;default 关闭环境改写,省略时保持当前设置。仅作用于目标 tab"},{name:"emulation",type:"object",description:"可选设备联动参数,字段同 set_device_emulation 去掉 enabled/reload;字段覆盖档案推荐设备,deviceShell 默认 true,横屏时可传 splitScreen=true。省略时不设置或清除设备"},{name:"reload",type:"boolean",description:"应用/清除后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["只有用户明确要求 App/客户端/容器/JSBridge 模拟时启用。移动视口或普通 H5 调试使用 set_device_emulation。","emulation={} 使用档案推荐设备;enabled=false 时省略 emulation 只清除 App 注入,传 {} 同时清除设备模拟。","bridgeConfig.methods 按方法声明 behavior / response / noop 三选一,可传 silent;只支持受控行为、固定 JSON 回包或成功空实现,不执行配置脚本。"],result:["返回 enabled、profile、label、userAgent、os、mtopEnv、reloaded;联动设备时额外返回实际 emulation。"],examples:[`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","mtopEnv":"pre"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"mtopEnv":"prod"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"alipay","emulation":{"preset":"pixel-11","deviceShell":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"emulation":{}}'`]},{name:"set_timezone",description:"覆盖目标 tab 的时区,传空字符串恢复浏览器默认时区",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"timezone",type:"string",required:!0,description:"IANA 时区标识(如 Asia/Shanghai);空字符串表示清除覆盖"}],examples:[`set_timezone --payload '{"tabId":12345,"timezone":"America/New_York"}'`,`set_timezone --payload '{"tabId":12345,"timezone":""}'`]},{name:"get_cookie",description:"从目标浏览器读取一个指定非分区 Cookie;拒绝返回 HttpOnly Cookie",params:[{name:"tabId",type:"number",description:"可选;指定标签页的 Cookie 存储区,省略时使用浏览器默认存储区"},{name:"name",type:"string",required:!0,description:"要读取的 Cookie 名称;不支持列举全部 Cookie"},{name:"url",type:"string",description:"Cookie 查询 URL;未传 tabId 时必填,省略时使用指定标签页 URL"},{name:"domain",type:"string",description:"可选精确域过滤,只允许 Cookie 查询 URL 的 host 或其父域"},{name:"path",type:"string",description:"可选精确 path 过滤"}],notes:["只读取指定非分区 Cookie,不列举全部、不回退分区 Cookie,拒绝 HttpOnly;禁止读取认证 Token。指定 url 不导航,指定 tabId 仅选择存储区时不启动采集。"],result:["找到时 found=true 并返回 value/domain/path;不存在时 found=false。"],examples:[`get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,`get_cookie --payload '{"url":"https://www.taobao.com/","name":"tracknick"}'`,`get_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","domain":"taobao.com"}'`,`get_cookie --payload '{"tabId":12345,"name":"tracknick","url":"https://www.taobao.com/","domain":"taobao.com","path":"/"}'`]},{name:"set_cookie",description:"在目标浏览器设置一个指定非分区 session Cookie,可选刷新指定页面",params:[{name:"tabId",type:"number",description:"可选;指定标签页的 Cookie 存储区,reload=true 时必填"},{name:"url",type:"string",description:"Cookie 目标 URL;未传 tabId 时必填,省略时使用指定标签页 URL"},{name:"name",type:"string",required:!0,description:"Cookie 名称"},{name:"value",type:"string",required:!0,description:"Cookie 值,可传空字符串;空字符串不会删除 Cookie"},{name:"domain",type:"string",description:"Cookie 域,默认目标 URL 的 host;只允许目标 host 或其父域"},{name:"path",type:"string",description:"Cookie path,默认 /"},{name:"reload",type:"boolean",description:"设置后是否刷新指定 tabId,默认 false;true 时必须传 tabId"}],notes:["仅写非分区 session Cookie,不支持删除。reload=true 时校验目标域与刷新页域的授权。"],result:["返回 url/name/domain/path/reloaded,指定标签页时包含 tabId;不回显 Cookie 值。"],examples:[`set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,`set_cookie --payload '{"url":"https://www.taobao.com/","name":"feature_flag","value":"enabled"}'`,`set_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","value":"3.6.63","domain":"taobao.com","reload":true}'`]},{name:"page_frames",description:"获取页面主 frame 与所有 iframe 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:["frames[] 包含 frameId、url、name 和 isMainFrame;frameId 可用于 page_eval 等支持 frame 定位的 action。"],examples:[`page_frames --payload '{"tabId":12345}'`]},{name:"request_domain_permission",description:"申请访问指定域名的权限(必要时弹窗让用户授权)",params:[{name:"domain",type:"string",required:!0,description:"需要授权的域名,如 example.com"}],notes:["domain 使用纯主机名,不传 URL。在非 BUC send_request 报域权限缺失,或 set_rule 提示缺少域名权限时申请;BUC 不使用浏览器域权限。","弹窗等待用户选择,90 秒超时或关闭按拒绝处理;granted=true 后才重试原请求。"],result:["返回 granted、domain,授权成功时包含 origin。"],examples:[`request_domain_permission --payload '{"domain":"example.com"}'`]},{name:"run_actions",description:"批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察",summary:"批量顺序执行多个 action,遇错即停",params:[{name:"actions",type:"Array<{action: string, data?: object}>",required:!0,description:"要依次执行的 action 列表"},{name:"tabId",type:"number",required:!0,description:"所有步骤共享的 tabId,步骤自身指定的优先"}],notes:["最多 50 步,不允许嵌套 run_actions;需要根据每步效果决策时逐步调用普通 action。"],result:["返回 results、completedSteps、totalSteps;失败时包含 error/failedStep,后续步骤未执行。"],examples:[`run_actions --payload '{"tabId":12345,"actions":[{"action":"page_hover","data":{"selector":"#menu"}},{"action":"page_click","data":{"selector":"#menu-item"}}]}'`]}],COMMAND_MAP=new Map(COMMANDS.map(command=>[command.name,command]))}});function findOfficialPlugin(name){return Object.hasOwn(OFFICIAL_PLUGINS,name)?OFFICIAL_PLUGINS[name]:void 0}var OFFICIAL_PLUGINS,init_officialPluginCatalog=__esm({"../client/src/plugins/officialPluginCatalog.ts"(){"use strict";OFFICIAL_PLUGINS={buc:{description:"使用 BUC 身份请求内部服务",installArgs:["trip/mearl","--skill","buc-request","--yes"],skill:"buc-request"},authx:{description:"使用 AuthX 身份请求内部服务",installArgs:["trip/mearl","--skill","authx-request","--yes"],skill:"authx-request"},tdbank:{description:"查询、借用和切换 TDBank 测试账号",installArgs:["trip/mearl","--skill","tdbank-account","--yes"],setup:"alibaba",skill:"tdbank-account"}}}});import{createRequire}from"node:module";import{fileURLToPath as fileURLToPath2}from"node:url";var require2,CLIENT_VERSION,PLUGIN_TASK_HOST_PATH,PLUGIN_WORKER_PATH,SCRIPT_WORKER_PATH,PLUGIN_MODEL_SESSION_WORKER_PATH,init_runtimePaths=__esm({"../client/src/runtimePaths.ts"(){"use strict";require2=createRequire(import.meta.url),CLIENT_VERSION=require2("../package.json").version,PLUGIN_TASK_HOST_PATH=fileURLToPath2(new URL("./plugin-task-host.js",import.meta.url)),PLUGIN_WORKER_PATH=fileURLToPath2(new URL("./plugin-worker.js",import.meta.url)),SCRIPT_WORKER_PATH=fileURLToPath2(new URL("./scriptWorker.js",import.meta.url)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath2(new URL("./pluginModelSessionWorker.js",import.meta.url))}});function parseToolboxIcon(value){if(typeof value!="string")return;let icon=value.trim();if(!icon||icon.length>32*1024)return;if(/^[a-z][a-z0-9-]{0,39}$/.test(icon))return{kind:"name",name:icon};if(/^(?:<\?xml\s[^>]*\?>\s*)?<svg\b[^>]*(?:\/>|>[\s\S]*<\/svg\s*>)$/i.test(icon)){let svg=/<svg\b[^>]*\sxmlns\s*=/i.test(icon)?icon:icon.replace(/<svg\b/i,'<svg xmlns="http://www.w3.org/2000/svg"');try{return{kind:"image",src:`data:image/svg+xml,${encodeURIComponent(svg)}`,.../\bcurrentColor\b/i.test(svg)?{monochrome:!0}:{}}}catch{return}}let dataHeader=/^data:image\/(?:svg\+xml|png|jpeg|gif|webp|avif)(?:;charset=utf-8|;utf8)?(?:;base64)?,/i.exec(icon);if(dataHeader&&icon.length>dataHeader[0].length)return{kind:"image",src:icon};try{let url=new URL(icon);if(["http:","https:"].includes(url.protocol)&&!url.username&&!url.password)return{kind:"image",src:url.href}}catch{}}var init_toolbox_icon=__esm({"../client/src/generated/toolbox-icon.ts"(){"use strict"}});import{createHash as createHash3}from"node:crypto";import{readFileSync as readFileSync2,realpathSync as realpathSync2}from"node:fs";import{basename as basename2,dirname as dirname2,extname,isAbsolute as isAbsolute2,join as join2,relative as relative2,resolve as resolve2,sep}from"node:path";var PLUGIN_PAGE_CHUNK_BYTES,MAX_PAGE_SOURCE_BYTES,MAX_PAGE_BUNDLE_BYTES,PAGE_BRIDGE_SCRIPT,PAGE_SECURITY_META,PAGE_THEME_STYLE,PLUGIN_PAGE_RUNTIME_HASH,init_pluginPageBundle=__esm({"../client/src/plugins/pluginPageBundle.ts"(){"use strict";init_pluginSource();PLUGIN_PAGE_CHUNK_BYTES=384*1024,MAX_PAGE_SOURCE_BYTES=16*1024*1024,MAX_PAGE_BUNDLE_BYTES=24*1024*1024,PAGE_BRIDGE_SCRIPT=String.raw`(() => {
|
|
28
|
+
`)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();helpOption&&args.find(arg=>helpOption.is(arg))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}};function incrementNodeInspectorPort(args){return args.map(arg=>{if(!arg.startsWith("--inspect"))return arg;let debugOption,debugHost="127.0.0.1",debugPort="9229",match;return(match=arg.match(/^(--inspect(-brk)?)$/))!==null?debugOption=match[1]:(match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(debugOption=match[1],/^\d+$/.test(match[3])?debugPort=match[3]:debugHost=match[3]):(match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(debugOption=match[1],debugHost=match[3],debugPort=match[4]),debugOption&&debugPort!=="0"?`${debugOption}=${debugHost}:${parseInt(debugPort)+1}`:arg})}function useColor(){if(process2.env.NO_COLOR||process2.env.FORCE_COLOR==="0"||process2.env.FORCE_COLOR==="false")return!1;if(process2.env.FORCE_COLOR||process2.env.CLICOLOR_FORCE!==void 0)return!0}exports.Command=Command2;exports.useColor=useColor}});var require_commander=__commonJS({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/index.js"(exports){var{Argument:Argument2}=require_argument(),{Command:Command2}=require_command(),{CommanderError:CommanderError2,InvalidArgumentError:InvalidArgumentError2}=require_error(),{Help:Help2}=require_help(),{Option:Option2}=require_option();exports.program=new Command2;exports.createCommand=name=>new Command2(name);exports.createOption=(flags,description)=>new Option2(flags,description);exports.createArgument=(name,description)=>new Argument2(name,description);exports.Command=Command2;exports.Option=Option2;exports.Argument=Argument2;exports.Help=Help2;exports.CommanderError=CommanderError2;exports.InvalidArgumentError=InvalidArgumentError2;exports.InvalidOptionArgumentError=InvalidArgumentError2}});var import_index,program,createCommand,createArgument,createOption,CommanderError,InvalidArgumentError,InvalidOptionArgumentError,Command,Argument,Option,Help,init_esm=__esm({"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs"(){import_index=__toESM(require_commander(),1),{program,createCommand,createArgument,createOption,CommanderError,InvalidArgumentError,InvalidOptionArgumentError,Command,Argument,Option,Help}=import_index.default}});var APP_PROFILE_NAME_LIST,DEVICE_PRESET_TYPE,PAGE_DIAGNOSTICS_PARAM,PAGE_OBSERVE_PARAM,PAGE_ACTION_RESULT,COMMANDS,COMMAND_MAP,init_commands=__esm({"../client/src/commands.ts"(){"use strict";init_browser_action_protocol();APP_PROFILE_NAME_LIST=APP_PROFILE_NAMES.join("/"),DEVICE_PRESET_TYPE=BROWSER_DEVICE_PRESET_NAMES.map(name=>JSON.stringify(name)).join(" | "),PAGE_DIAGNOSTICS_PARAM={name:"diagnostics",type:"object | boolean",description:"默认关闭;传 true 返回动作期间新增的 error logs/业务 requests,或传对象自定义通道与过滤",details:["logs: boolean | { level, limit, filter };true 默认采集 error 日志","requests: boolean | { count, filter, source, includeBody, includeHeaders, maxBodySize, fields, keysOnly }","events: boolean | { source, event_type, filter, limit, includeRaw };埋点需显式开启","各通道过滤字段同 get_logs / get_requests / get_events;observe=false 时仍返回诊断增量,但不等待 DOM/导航稳定"]},PAGE_OBSERVE_PARAM={name:"observe",type:"object | false",description:"默认开启 DOM/导航观察;传 false 关闭,不影响显式请求的 diagnostics",details:["quietMs: number,DOM 变化后的稳定窗口,默认 100ms","firstChangeTimeoutMs: number,无 DOM 变化时的观察窗口,默认 500ms","timeoutMs: number,DOM 观察阶段最大时间,默认 3000ms","navigationGraceMs: number,低信息量点击/按键的导航宽限,默认 1000ms;相关网络活动可延长宽限","navigationTimeoutMs: number,导航就绪最大等待时间,默认 15000ms","networkIdleMs: number,文档完成且相关请求归零后的静默时间,默认 500ms","contentReadyAfterMs: number,结构稳定兜底保护期,默认 min(5000, navigationTimeoutMs / 2),并限制在导航超时前"]},PAGE_ACTION_RESULT=["默认返回 { action, observation };action.success 只表示动作成功,业务效果需结合 observation 和目标状态判断。","observe=false 且未开启 diagnostics 时返回裸动作结果(如 { clicked: true }),没有 action/observation;开启 diagnostics 时返回 { action, diagnostics }。","包装结果中的 action.stage=precondition 表示未派发,省略 observation/diagnostics;dispatch-uncertain 表示可能已派发,先查看 action.attempt 与可用观察或最小快照核验,避免重复提交。CLI 单次调用失败以退出码 1 结束;脚本需检查 action.success。","observation.effects 返回通知、控件和焦点增量,可直接复用 node.ref/selector;changed=true 且 effects 为空不表示失败。","effects.texts 按需返回普通可见文本的 selector/text,不代表可点击控件或业务成功;超限或覆盖不完整时仍提示补快照。","fullSnapshotRecommended/snapshotReasons 提示是否补充快照;openedTabs 返回可继续操作的 tabId 和 ready。navigation 模式的 ready 表示新页面就绪。","显式开启的诊断通道在 diagnostics 中返回动作期间增量,与 observe 独立。"],COMMANDS=[{name:"browser_control",description:"把控制会话交给用户;用户在 Mearl 浏览器管理页交还后重新观察页面",params:[{name:"operation",type:'"handoff" | "resume"',required:!0,description:"交给用户操作;resume 仅在用户明确交还后使用"},{name:"tabId",type:"number",description:"可选的目标页面"},{name:"reason",type:"string",description:"用户需要处理的事项"}],notes:["必须携带 --session;接管停止后续派发,已经发出的操作可能仍然生效。"]},{name:"page_download",description:"先监听再点击,等待下载完成并创建浏览器文件产物",outputFlag:!0,params:[{name:"tabId",type:"number",required:!0,description:"下载来源页面"},{name:"trigger",type:"object",required:!0,description:"page_click 参数,不含 tabId"},{name:"url",type:"string",description:"预期下载 URL;扩展无法通过 referrer 归属时需显式指定"},{name:"timeout",type:"number",description:"下载等待毫秒,默认 30000,范围 1000–300000"}],notes:["--output 把文件分块保存到调用方机器;未指定时返回 artifactId,可供 page_upload 复用。","共享 CDP 浏览器保持原下载目录;Chrome 未返回文件路径时明确报错。超时不能直接重复点击。"]},{name:"tab_checkpoint",description:"为目标标签页建立日志、请求和埋点增量边界",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_open 获取"}],examples:[`tab_checkpoint --payload '{"tabId":12345}'`]},{name:"get_requests",description:"获取最近的网络请求(mtop 或普通 xhr/fetch)",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"count",type:"number",description:"返回条数,默认 10"},{name:"source",type:'"mtop" | "requests" | "all"',description:"数据来源,不填时默认 mtop;all 返回全部业务请求"},{name:"filter",type:"string",description:"按 URL 或 API 名称过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的请求"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的请求"},{name:"includeBody",type:"boolean",description:"是否包含请求/响应体;指定 fields 时默认 false,否则默认 true"},{name:"includeHeaders",type:"boolean",description:"是否包含请求/响应头,默认 false"},{name:"maxBodySize",type:"number",description:"单个请求/响应体最大字符数,默认 50000"},{name:"fields",type:"string[]",description:"从响应体提取指定字段路径,最多 100 个"},{name:"keysOnly",type:"boolean",description:"只返回数据结构,不返回叶子值"}],notes:["流式请求开始后即进入缓冲区;页面及 App 桥代发的 MTop SSE 都归入 mtop。无法归属当前页面 target 的 Service Worker 请求不在采集范围内。"],result:["nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。","省略正文时不返回 postData / responseBody 字段;指定 fields 后需要同时读取全文时显式传 includeBody:true。","isPending 标记未完成请求;SSE 的 responseBody 保存按序到达的 event/data/timestamp/duration 分片。敏感请求头返回脱敏值。"],examples:[`get_requests --payload '{"tabId":12345,"count":5}'`,`get_requests --payload '{"tabId":12345,"source":"mtop","filter":"cart"}'`]},{name:"get_logs",description:"获取浏览器控制台日志",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"limit",type:"number",description:"返回最新 N 条,默认 100"},{name:"level",type:"string",description:"按日志级别过滤:log/info/warn/error/all"},{name:"filter",type:"string",description:"按内容过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的日志"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的日志"}],result:["nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。"],examples:[`get_logs --payload '{"tabId":12345,"limit":10,"level":"error"}'`]},{name:"get_events",description:"获取 RUM/aplus/ARMS 埋点事件",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"source",type:'"rum" | "aplus" | "arms" | "all"',description:"数据来源,默认 all"},{name:"event_type",type:"string",description:"按事件类型过滤,支持正则,如 CLK/PV"},{name:"filter",type:"string",description:"按 name 或 url 过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的事件"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 之后的事件"},{name:"limit",type:"number",description:"返回条数,默认 20"},{name:"includeRaw",type:"boolean",description:"返回完整 URL、_raw 和 _context;默认 false"}],notes:["tab_open 新页从首屏采集;既有页面首次查询才启用采集,需要刷新或重新触发埋点。同批事件不会被 limit 拆开。"],result:["nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。","captureStatus 为 armed/active/inactive;空结果附 hint 时按提示刷新或触发。默认去除 tracking URL query 与 _raw/_context,includeRaw=true 时保留。"],examples:[`get_events --payload '{"tabId":12345,"source":"aplus","event_type":"CLK","limit":10}'`,`get_events --payload '{"tabId":12345,"filter":"order","includeRaw":true,"limit":1}'`,`get_events --payload '{"tabId":12345,"source":"all","limit":20}'`]},{name:"set_mock",description:"设置 API mock 数据",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",required:!0,description:"API 名称或正则表达式"},{name:"mockData",type:"object",description:"完整 mock 响应数据(与 fields 二选一)"},{name:"fields",type:"array",description:"按字段路径修改真实响应(与 mockData 二选一)"},{name:"enabled",type:"boolean",description:"是否启用,默认 true。false 时恢复真实数据"},{name:"duration",type:"number",description:"完整响应时长(毫秒):mock 的总耗时,绕过真实服务器精确控制"},{name:"conditions",type:"object",description:"请求 query/body 字段子集匹配;$index 从 0 开始指定调用顺序"}],notes:["启用时至少提供 mockData 或非空 fields;非空 fields 优先。fields 每项 { path: string, value: any },path 支持点号和数组索引。","相同 apiName 的多条无条件 Mock 会覆盖;conditions 子集匹配 query/body(含 data 内层),不同条件可共存;$index 从 0 起控制调用顺序,不参与字段匹配。","大字段可用顶层 @<绝对路径> 文件引用或 --payload-file;文件展开后仍受 Native Messaging 单条消息大小限制。"],examples:[`set_mock --payload '{"tabId":12345,"apiName":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,"set_mock --payload-file ./mock-data.json"]},{name:"get_mocks",description:"查看当前生效的 mock 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",description:"按 API 名称或正则表达式过滤"}],examples:[`get_mocks --payload '{"tabId":12345}'`]},{name:"set_rule",description:"添加浏览器请求规则;enabled=false 且传 ruleId 时彻底删除规则",params:[{name:"ruleId",type:"number",description:"删除时必填,从 get_rules 获取"},{name:"enabled",type:"boolean",description:"省略时添加;false 时按 ruleId 删除"},{name:"actionType",type:'"redirect" | "block" | "allow" | "upgradeScheme" | "modifyHeaders"',description:"添加时必填,规则动作"},{name:"filter",type:"string",description:"添加时必填,URL 过滤表达式"},{name:"redirectUrl",type:"string",description:"redirect 动作的目标 URL"},{name:"requestHeaders",type:"array",description:"modifyHeaders 动作的请求头修改列表",details:['每项 { header: string, operation: "set" | "append" | "remove", value?: string };set/append 需 value']},{name:"responseHeaders",type:"array",description:"modifyHeaders 动作的响应头修改列表",details:['每项 { header: string, operation: "set" | "append" | "remove", value?: string };set/append 需 value']},{name:"initiatorDomains",type:"string",description:"发起方域名过滤"},{name:"resourceTypes",type:"string[]",description:"资源类型过滤"},{name:"priority",type:"number",description:"规则优先级"},{name:"description",type:"string",description:"规则说明"}],notes:["扩展模式规则持久化;CDP 仅支持会话级 modifyHeaders 请求头 set,不支持响应头、initiatorDomains 或其他动作。Provider 是否支持以其能力声明为准。","扩展模式会检查规则请求 URL 和显式来源域名的访问权限;缺失时仍保存规则,返回 warnings 和 missingOrigins,不自动弹窗。可在请求规则页面授权,或按提示调用 request_domain_permission。复杂 URL 表达式无法完整推断域名时会提示手动检查。"],examples:[`set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`,`set_rule --payload '{"ruleId":42,"enabled":false}'`]},{name:"get_rules",description:"查看当前模式的请求规则;扩展模式包含 Options 面板配置的规则",examples:["get_rules"]},{name:"send_request",description:"发送 HTTP 请求,自动携带浏览器 Cookie,支持 multipart 和原始二进制上传",params:[{name:"url",type:"string",required:!0,description:"完整目标 URL"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"headers",type:"object",description:"自定义请求头"},{name:"params",type:"object",description:"URL 查询参数"},{name:"body",type:"any",description:"请求体(传对象时自动 JSON 序列化)"},{name:"bodyFile",type:"object",description:"原始二进制请求体:filePath 或 base64 二选一,可选 contentType(默认 application/octet-stream);与 body/formData/files 互斥"},{name:"formData",type:"object",description:"multipart 文本字段(值支持 string/number/boolean)"},{name:"files",type:"SendRequestFile[]",description:"multipart 文件,最多 20 个、总计不超过 40 MiB;Base64 文件总计不超过 7 MiB。每项传 fieldName 和绝对 filePath,或传 base64 + filename",details:["fieldName: string(必填);filePath: string 与 base64: string 二选一","filename: string,base64 时必填,filePath 时默认文件 basename","contentType: string(可选),默认按文件名推断 MIME,否则 application/octet-stream"]},{name:"withCookies",type:"boolean",description:"是否附加浏览器 Cookie,默认 true"},{name:"responseType",type:'"json" | "text" | "auto"',description:"响应解析方式,默认 auto"},{name:"timeout",type:"number",description:"超时毫秒数,默认 30000"}],notes:["仅用于非 BUC 请求;BUC 接口使用 mearl buc,不手工传 Token、DPoP 或 Ticket。","body 不能与 formData/files 组合;bodyFile 以原始字节发送,不包 multipart boundary,不能用于 GET/HEAD。","bodyFile.filePath 属于 native-host,最大 40 MiB;base64 解码后最大 7 MiB。multipart 不手工设置 Content-Type,由 Mearl 生成 boundary。","filePath 属于 native-host 所在机器;无法引用远端路径时用 base64。BUC 上传的路径属于插件执行宿主。"],result:["返回 status、statusText、headers、body、bodyType、attachedCookieCount;bodyType 为 json/text/base64,二进制 body 需解码后保存。"],examples:[`send_request --payload '{"url":"https://api.example.com/data","method":"GET"}'`,`send_request --payload '{"url":"https://api.example.com/upload","method":"POST","formData":{"folder":"assets"},"files":[{"fieldName":"file","filePath":"/absolute/path/image.png"}]}'`,`send_request --payload '{"url":"https://api.example.com/upload","method":"POST","bodyFile":{"filePath":"/absolute/path/image.png","contentType":"image/png"}}'`]},{name:"send_mtop_request",description:"使用目标浏览器 Cookie 发起 mtop 请求,自动处理签名和 token",params:[{name:"api",type:"string",required:!0,description:"mtop API 名称"},{name:"data",type:"object",description:"请求数据"},{name:"version",type:"string",description:"API 版本,默认 1.0"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"appKey",type:"string",description:"签名使用的 appKey,默认 12574478"},{name:"env",type:'"prod" | "pre"',description:"请求环境,默认 prod"},{name:"timeout",type:"number",description:"超时毫秒数,默认 10000"}],notes:["需要目标浏览器有对应登录态;Mearl 自动处理签名,不依赖页面脚本。api 以 mopen. 开头时使用 mopen 协议。","env=prod 使用 h5api.m.taobao.com,pre 使用 h5api.wapa.taobao.com。"],result:["返回 success、response、requestData;业务成功需检查 response.ret。"],examples:[`send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`]},{name:"browser_list",description:"列出所有浏览器及其连接状态、类型和 Provider 托管实例信息",summary:"列出本地及远端浏览器与连接状态",examples:["browser_list"]},{name:"browser_release",description:"释放当前浏览器的调试控制和会话级临时效果(含设备/时区模拟);不用于普通任务收尾,Provider 实例的行为以 mearl <providerId> 为准",params:[{name:"closeCreatedTabs",type:"boolean",description:"带 --session 时关闭会话创建的过程页,默认 false"},{name:"keepTabIds",type:"number[]",description:"保留的结果页面;复用的用户页面始终保留"},{name:"preserveEnvironment",type:"boolean",description:"带 --session 时默认 true,保留 Mock 与模拟现场;false 清理这些页面的环境"},{name:"keepArtifactIds",type:"string[]",description:"保留在浏览器宿主的文件产物;其余会话临时文件删除"}],notes:["带 --session 时可用于任务收尾,只释放该会话;未带会话时保留原浏览器级释放行为,活动会话存在时拒绝全局释放。"],summary:"释放浏览器调试控制和会话级临时效果",examples:["browser_release","browser_release --browser chrome-a"]},{name:"browser_launch",description:"启动本地 Chrome,或通过已注册 Provider 创建浏览器实例",params:[{name:"name",type:"string",description:"本地实例名称;使用 local Provider 时必填"},{name:"provider",type:"string",description:"运行环境,默认 local;可传 mearl --help 中展示的已注册 Provider ID"},{name:"providerOptions",type:"Record<string, JSON value>",description:"所选 Provider 声明的结构化启动参数;不能与顶层启动字段混用"},{name:"headless",type:"boolean",description:"本地 Provider 是否无头运行,默认 true"},{name:"userAgentMode",type:'"default" | "desktop"',description:"本地 UA 模式:default 使用默认 UA;desktop 使用匹配本机版本的 UA"},{name:"persistent",type:"boolean",description:"本地实例关闭后是否保留 Profile,默认 false"},{name:"url",type:"string",description:"登录完成后打开的初始页面"},{name:"executablePath",type:"string",description:"自定义 Chrome 可执行文件路径"},{name:"copyCookieDomains",type:'string[] | "mearl-services" | { presets?: ["mearl-services"]; domains?: string[] }',description:"从控制浏览器复制 Cookie:可传域名数组、Mearl 登录态预设,或组合预设与额外域名"}],examples:[`browser_launch --payload '{"provider":"brow","providerOptions":{}}'`,`browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,`browser_launch --payload '{"name":"with-cookies","copyCookieDomains":["example.com","sub.example.org"]}'`]},{name:"browser_close",description:"关闭指定托管浏览器,并按 Provider 策略保留或清理持久化数据",params:[{name:"browser",type:"string",required:!0,description:"托管浏览器的 browserId 或名称"},{name:"deleteProfile",type:"boolean",description:"强制删除持久化数据,默认 false"}],examples:[`browser_close --payload '{"browser":"managed:account-a"}'`,`browser_close --payload '{"browser":"account-b","deleteProfile":true}'`]},{name:"tab_open",description:"打开或按 URL 规则复用 Tab,并等待新页面加载完成",aliases:["tab_new","new_tab","tab_create","create_tab"],params:[{name:"url",type:"string",required:!0,description:"要打开的 URL"},{name:"active",type:"boolean",description:"是否激活目标 Tab,默认 false;扩展免打扰默认开启,使用后台焦点模拟,关闭后才切换前台;响应返回 activation"},{name:"openerTabId",type:"number",description:"来源 Tab ID;用于把目标 Tab 关联到来源侧边栏对话"},{name:"closeExisting",type:"boolean",description:"打开前先关闭 Agent 受控的已有标签页,默认 false"},{name:"group",type:"string",description:"把新 Tab 加入指定标题的标签页分组(同名分组存在则加入,否则新建)。仅扩展模式支持"},{name:"reuse",type:'"never" | "prefer" | "require"',description:"never 始终新开;prefer 优先复用;require 只允许复用。默认 never"},{name:"match",type:"object",description:"复用匹配规则:urlPattern(支持 *)、ignoreSearch、ignoreHash、onMultiple(error/first)"},{name:"restoreFocusOnClose",type:"boolean",description:"关闭本次新开的 active Tab 后恢复原活动标签页,默认 false"},{name:"emulation",type:"object",description:"开 tab 即进入移动端模拟态(首屏即移动态、无需 reload)。字段同 set_device_emulation 去掉 enabled/reload;与 appProfile、deviceShell=true、orientation=landscape、splitScreen=true 组合可首屏进入左右分屏"},{name:"appProfile",type:"string",description:'开 tab 即注入 App 客户端环境与 JSBridge;档案名同 set_app_profile,如 "fliggy"。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true'},{name:"os",type:'"ios" | "android"',description:"与 appProfile 配合;容器系统,默认 ios"},{name:"bridgeConfig",type:"object",description:"与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}"}],notes:["emulation / appProfile 只应用到新建 Tab;复用 Tab 要切换状态时用对应设置 action。","closeExisting 不能与复用或 openerTabId 组合;多匹配默认报错,match.onMultiple=first 可显式选择第一个。"],result:["返回 tabId、url、title、opened/reused;reused=true 的既有页面应保留。","active=true 时 activation 包含 tabActive、windowFocused、windowState、visibilityState;emulation 返回实际生效配置。","capture.cursor 是导航前诊断边界,可分别用于 get_logs/get_requests/get_events 的 after。"],examples:[`tab_open --payload '{"url":"https://example.com"}'`,`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-17-pro"}}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy"}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`tab_open --payload '{"url":"https://example.com","appProfile":"fliggy","os":"android"}'`,`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`]},{name:"tab_close",description:"关闭指定标签页",aliases:["tab_remove","remove_tab","tab_delete","delete_tab"],params:[{name:"tabId",type:"number",required:!0,description:"要关闭的标签页 ID"}],examples:[`tab_close --payload '{"tabId":123}'`]},{name:"tab_list",description:"列出目标浏览器所有窗口中的标签页",aliases:["tabs","list_tabs","show_tabs"],examples:["tab_list"]},{name:"tab_group",description:"把同一窗口中的标签页加入分组,或通过 ungroup 取消分组并保留标签页;仅扩展模式支持",params:[{name:"tabIds",type:"number[]",required:!0,description:"标签页 ID,分组最多 100 个,取消分组最多 1000 个"},{name:"title",type:"string",required:!1,description:"分组标题;取消分组时省略"},{name:"ungroup",type:"boolean",required:!1,description:"为 true 时取消分组并保留标签页"}],examples:[`tab_group --payload '{"tabIds":[123,124],"title":"项目文档"}'`,`tab_group --payload '{"tabIds":[123,124],"ungroup":true}'`]},{name:"page_click",description:"点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位",params:[{name:"selector",type:"string",description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类"},{name:"text",type:"string",description:"按可见文本(accessibility name)定位。需要时配合 role/exact 消歧;多匹配会报错并列出候选"},{name:"point",type:"{ x: number; y: number }",description:'按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: "active-frame"'},{name:"frameId",type:"string",description:"浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame"},{name:"coordinateSpace",type:'"outer-viewport" | "active-frame"',description:"仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入"},{name:"role",type:"string",description:"配合 text 使用,按 AX role 过滤(如 button、link、heading)"},{name:"exact",type:"boolean",description:"配合 text 使用,默认 true 精确匹配;false 时按子串匹配"},{name:"scope",type:"string",description:"配合 text 使用,把文本匹配限制在指定 CSS 元素或 @eN ref 子树内,适合消除重复文案歧义"},{name:"clickMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,notes:["selector / text / point 必须且只能提供一个。隐藏页 auto 使用 DOM;只有明确依赖真实用户手势时才激活页面。","原生 select 可按 option 文本点击;checkbox/radio 返回 controlState.checkedBefore/checkedAfter。"],examples:[`page_click --payload '{"tabId":12345,"text":"提交"}'`,`page_click --payload '{"tabId":12345,"text":"退款明细","role":"button"}'`,`page_click --payload '{"tabId":12345,"text":"确定","scope":"@e12"}'`,`page_click --payload '{"tabId":12345,"selector":"@e3"}'`,`page_click --payload '{"tabId":12345,"selector":".submit-btn"}'`,`page_click --payload '{"tabId":12345,"selector":".gesture-btn","clickMode":"touch"}'`,`page_click --payload '{"tabId":12345,"point":{"x":336,"y":117}}'`,`page_click --payload '{"tabId":12345,"point":{"x":196,"y":240},"coordinateSpace":"active-frame"}'`]},{name:"page_drag",description:"拖动页面元素或视口坐标,适用于轮播图、滑块和拖放",params:[{name:"from",type:"string | { x: number; y: number }",required:!0,description:"起点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"to",type:"string | { x: number; y: number }",required:!0,description:"终点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"dragMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},{name:"durationMs",type:"number",description:"拖动持续时间,0–5000ms,默认 400ms;内部自动分段移动"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,notes:["起点会自动滚入视口,终点必须同时位于当前视口;否则先滚动页面。隐藏页 auto 使用 DOM,不切换活动页。"],examples:[`page_drag --payload '{"tabId":12345,"from":{"x":350,"y":80},"to":{"x":80,"y":80}}'`,`page_drag --payload '{"tabId":12345,"from":"@e3","to":"#drop-zone","dragMode":"mouse"}'`]},{name:"page_type",description:"向输入框填写文本,兼容 React 受控组件",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},{name:"text",type:"string",required:!0,description:"要填写的文本"},{name:"clearFirst",type:"boolean",description:"是否先清空原有内容,默认 true"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,examples:[`page_type --payload '{"tabId":12345,"selector":"@e6","text":"搜索关键词"}'`]},{name:"page_hover",description:"将鼠标悬停在页面元素上",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,examples:[`page_hover --payload '{"tabId":12345,"selector":".nav-menu"}'`]},{name:"page_scroll",description:"滚动页面或指定容器;页面根不可滚动时自动发现活动滚动区",params:[{name:"direction",type:'"up" | "down" | "top" | "bottom"',required:!0,description:"滚动方向"},{name:"distance",type:"number",description:"滚动距离(px),默认 600"},{name:"selector",type:"string",description:"目标滚动容器的原生 CSS 选择器,或 page_snapshot 返回的 @eN ref;不传时滚动页面"},{name:"containerPolicy",type:'"self" | "nearest"',description:"默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:[...PAGE_ACTION_RESULT,"action.data 返回 moved、atTop/atBottom、scrollYBefore/After、maxScrollY、resolvedContainer 和 ancestorDistance;自动发现的内部容器提供可复用 containerSelector。"],examples:[`page_scroll --payload '{"tabId":12345,"direction":"down"}'`,`page_scroll --payload '{"tabId":12345,"direction":"bottom"}'`,`page_scroll --payload '{"tabId":12345,"selector":".virtual-list","direction":"down","distance":800}'`,`page_scroll --payload '{"tabId":12345,"selector":"@e8","containerPolicy":"nearest","direction":"bottom"}'`]},{name:"page_runtime",description:"页面运行时传输适配器;插件使用 PluginPageClient 或 app.page",params:[{name:"operation",type:"string",required:!0,description:"resolve/attach/get/send/detach/activation"}]},{name:"page_eval",description:"在页面上下文中执行任意 JavaScript 表达式",params:[{name:"expression",type:"string",required:!0,description:"要执行的 JS 表达式;传 args 时须求值为函数"},{name:"args",type:"unknown[]",description:"传给页面函数的 JSON 参数;SDK/CLI 自动处理大参数分块,保持指定执行环境"},{name:"executionWorld",type:"string",description:"main(默认)读取网页 JS;isolated 使用命名隔离环境,扩展连接无需 debugger"},{name:"worldId",type:"string",description:"isolated 必填,小写字母开头,允许数字和连字符,最长 64 字符"},{name:"awaitPromise",type:"boolean",description:"表达式返回 Promise 时等待完成,默认 true"},{name:"frameId",type:"string",description:"page_frames 返回的目标 frame ID,扩展/CDP 均支持;省略时容器/设备外壳使用当前业务 frame,普通页面使用主 frame"},{...PAGE_OBSERVE_PARAM,type:"object",description:"仅在表达式会修改页面且需要观察结果时显式传入;不传保持轻量裸执行"},PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["优先使用结构化 action;仅在其无法表达需求时执行最小范围脚本。"],result:["默认返回 { result };observe 对象启用观察并返回 { action, observation };仅开启 diagnostics 时返回 { action, diagnostics }。diagnostics=false 不启用包装。失败阶段语义同 page_click。"],examples:[`page_eval --payload '{"tabId":12345,"expression":"document.title"}'`]},{name:"page_inspect",description:"查询 DOM 元素的控件状态、数量、边框盒、计算样式、遮挡、溢出和最近滚动容器",params:[{name:"selector",type:"string",description:"原生 CSS、page_snapshot 返回的 @eN ref,或 DevTools Elements 当前选区 $0;做全页溢出诊断时可省略"},{name:"filter",type:'"all" | "overflowing" | "horizontal-overflow" | "vertical-overflow" | "scrollable"',description:"结果过滤;省略 selector 时必须指定非 all 的过滤条件"},{name:"styles",type:"string[]",description:"要返回的计算样式属性,默认 display/position/box-sizing/overflow-x/overflow-y"},{name:"maxResults",type:"number",description:"最多返回的明细数,默认 20,最大 100;未触发 scanTruncated 时 count 为完整命中数"},{name:"includeOuterHTML",type:"boolean",description:"是否返回 outerHTML(最多 3000 字符);$0 默认 true,其他目标默认 false"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:["matches[] 包含 boundingBox、computedStyle、hitTest、scroll 溢出量及可用的 scrollContainer。receivesPointerEvents=false 时读取 occludedBy。","state 返回原生/ARIA 状态及来源;缺失字段表示未知。","$0 还返回 resolvedSelector、属性、XPath 和可用框架信息。"],examples:[`page_inspect --payload '{"tabId":12345,"selector":".form-field","styles":["display","width"]}'`,`page_inspect --payload '{"tabId":12345,"selector":"@e8"}'`,`page_inspect --payload '{"tabId":12345,"selector":"$0"}'`,`page_inspect --payload '{"tabId":12345,"filter":"horizontal-overflow"}'`,`page_inspect --payload '{"tabId":12345,"filter":"scrollable"}'`]},{name:"page_press",description:"在页面中按下键盘按键或组合键",params:[{name:"key",type:"string",required:!0,description:"按键名称:Enter/Tab/Escape/Backspace 等"},{name:"modifiers",type:"string[]",description:"修饰键数组:ctrl/alt/shift/meta/cmd"},{name:"pressMode",type:'"auto" | "dom" | "keyboard"',description:"派发模式;auto 默认在隐藏页降级为 DOM 键盘事件"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["隐藏页 DOM 模式支持 Tab 焦点移动、原生控件 Enter/Space 激活和输入框 Enter 提交;编辑、选择、方向键和页面滚动等原生行为需可见页与 pressMode=keyboard。"],result:[...PAGE_ACTION_RESULT,"action.data.dispatchMode / fallbackReason / defaultAction 说明实际输入路径。"],examples:[`page_press --payload '{"tabId":12345,"key":"Enter"}'`]},{name:"page_wait",description:"等待指定时间、元素状态、可见文本或页面条件成立",params:[{name:"time",type:"number",description:"等待毫秒数(与 selector/text/condition 四选一)"},{name:"selector",type:"string",description:"目标 CSS 选择器(与 time/text/condition 四选一)"},{name:"state",type:'"attached" | "detached" | "visible" | "hidden"',description:"selector 的目标状态,默认 attached"},{name:"text",type:"string",description:"等待页面出现的可见文本"},{name:"exact",type:"boolean",description:"text 是否精确匹配,默认 false"},{name:"condition",type:"string",description:"在页面主上下文轮询的 JS 表达式,返回 truthy 时结束"},{name:"timeout",type:"number",description:"等待超时毫秒数,默认 10000"},{name:"interval",type:"number",description:"轮询间隔毫秒数,默认 200"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["time / selector / text / condition 必须且只能提供一个;time 范围 0–60000ms。页面交互已有内置观察,仅在需要独立等待条件时使用。"],examples:[`page_wait --payload '{"tabId":12345,"time":1000}'`,`page_wait --payload '{"tabId":12345,"selector":".dialog","state":"visible"}'`,`page_wait --payload '{"tabId":12345,"selector":".loading","state":"hidden"}'`,`page_wait --payload '{"tabId":12345,"text":"提交成功"}'`,`page_wait --payload '{"tabId":12345,"condition":"window.appReady === true","timeout":30000}'`]},{name:"page_navigate",description:"在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进",params:[{name:"url",type:"string",description:"要导航到的 URL;与 refresh/history 互斥"},{name:"refresh",type:"boolean",description:"为 true 时直接重新加载当前页面;与 url/history 互斥"},{name:"history",type:'"back" | "forward"',description:"沿当前标签页浏览历史后退或前进;与 url/refresh 互斥"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["url / refresh=true / history 必须且只能提供一个。"],examples:[`page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,`page_navigate --payload '{"tabId":12345,"refresh":true}'`,`page_navigate --payload '{"tabId":12345,"history":"back"}'`]},{name:"page_upload",description:'向 <input type="file"> 元素上传一个或多个文件',params:[{name:"files",type:"object[]",description:"调用方绝对路径 {filePath} 或浏览器产物 {artifactId};与 filePaths 二选一"},{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀),必须指向 input[type=file]"},{name:"filePaths",type:"string[]",description:"浏览器宿主上的绝对路径数组;与 files 二选一"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:PAGE_ACTION_RESULT,notes:["直接写入 input[type=file],不依赖 file chooser;隐藏的文件节点也可上传。外部 Provider 的文件中转能力查询 mearl <providerId>。"],examples:[`page_upload --payload '{"tabId":12345,"selector":"#file-input","filePaths":["/Users/me/photo.jpg"]}'`]},{name:"page_snapshot",description:"获取带 @ref 的页面结构快照,默认使用无障碍树,也可显式读取渲染 DOM",params:[{name:"depth",type:"number",description:"树深度,默认 15,复杂页面可调大"},{name:"mode",type:'"full" | "interactive" | "viewport" | "dom"',description:"默认 full;interactive/viewport 裁剪 AX 树;AX 信息缺失时可显式使用 dom 读取渲染 DOM"},{name:"rootSelector",type:"string",description:"只获取指定 CSS 元素的局部子树,可与 mode 组合;与 rootRef 互斥"},{name:"rootRef",type:"string",description:"以已有 @eN ref 为根获取局部子树;与 rootSelector 互斥"},{name:"ancestorDepth",type:"number",description:"rootRef 向上扩展的 DOM 祖先层数,默认 0,最大 20"},{name:"query",type:"{ text?: string; role?: string; exact?: boolean }",description:"服务端按 name / role 过滤当前模式的树,只保留命中节点及祖先路径"},{name:"maxNodes",type:"number",description:"最多输出节点数,0 表示不限制"},{name:"maxChars",type:"number",description:"快照文本最大字符数,默认 60000,超出保留首尾;传 0 不限制"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["query.text / query.role 至少提供一个;query.exact 默认 true。每次快照刷新有效 ref 集合。","interactive 无 AX 控件时回退到 viewport,不会自动改用 dom;Canvas 内容需截图。"],result:["返回 snapshot、elementCount、outputNodeCount、mode;截断时 truncated=true。","snapshot 中的 @eN 可直接用于操作;内部节点映射仅保存在运行时。无名称、无 ref 且无状态的分组折叠到子节点。","query 返回 matches 与完整 matchCount,matches 最多 100 项,裁剪时 matchesTruncated=true。容器/iframe 的视口裁剪返回 outerViewport、contentViewport 和滚动位置。"],examples:[`page_snapshot --payload '{"tabId":12345}'`,`page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,`page_snapshot --payload '{"tabId":1,"mode":"dom"}'`,`page_snapshot --payload '{"tabId":1,"rootSelector":"[role=dialog]"}'`,`page_snapshot --payload '{"tabId":1,"rootRef":"@e8","ancestorDepth":1}'`,`page_snapshot --payload '{"tabId":1,"query":{"text":"保存","role":"button"}}'`]},{name:"page_screenshot",description:"获取当前视口或指定元素截图",outputFlag:!0,params:[{name:"selector",type:"string",description:"CSS 选择器,提供后只截取该元素区域"},{name:"format",type:'"png" | "jpeg"',description:"图片格式,默认 png"},{name:"quality",type:"number",description:"JPEG 压缩质量(0-100),默认 80"},{name:"captureMode",type:'"cdp" | "visible"',description:"默认 cdp;visible 使用活动标签页截图,普通网页无需 debugger;设备模拟复用模拟会话并截取业务视口,不支持 selector"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["使用 --output <path> 保存图片;省略时 stdout 返回含 base64 data 的 JSON,避免直接将其加载为文本。"],result:["meta 包含 format、width、height、size、url、title;宽高为实际截图的物理像素。"],examples:[`page_screenshot --payload '{"tabId":12345}' --output ./screenshot.png`,`page_screenshot --payload '{"tabId":12345,"selector":".product-card"}' --output ./card.png`]},{name:"set_device_emulation",description:"把目标 tab 切换为移动端模拟(视口/DPR/UA/触摸/视觉比例),等价 DevTools 设备工具栏,作用域 per-tab;需保持调试控制才持续生效",summary:"设置或清除目标标签页的设备模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"preset",type:DEVICE_PRESET_TYPE,description:"内置设备预设,提供 width/height/DPR/UA 默认值;旧机型 ID 继续兼容"},{name:"width",type:"number",description:"视口宽度(覆盖 preset)"},{name:"height",type:"number",description:"视口高度(覆盖 preset)"},{name:"deviceScaleFactor",type:"number",description:"DPR(覆盖 preset)"},{name:"scale",type:"number",description:"画面视觉比例,不改变视口尺寸或 DPR;必须为有限正数,默认 1"},{name:"mobile",type:"boolean",description:"是否走移动渲染模式,默认从 preset 推断"},{name:"userAgent",type:"string",description:"自定义 UA(覆盖 preset)"},{name:"orientation",type:'"portrait" | "landscape"',description:"横竖屏,默认 portrait"},{name:"touch",type:"boolean",description:"是否启用触摸事件,默认从 preset 推断;无 preset 时跟随 mobile"},{name:"deviceShell",type:"boolean",description:"是否使用 iframe WebView 并渲染顶部状态栏与底部操作区,默认 false"},{name:"splitScreen",type:"boolean",description:"是否将首页与业务页分置左右 WebView;仅在已启用 App 档案、deviceShell=true、横屏时生效,默认 false"},{name:"reload",type:"boolean",description:"启用后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["无 preset 时 width/height 必须成对提供且 userAgent 必填;mobile 默认 true,touch 跟随 mobile。","deviceShell 开启/移除时必须重载;splitScreen 仅在已启用 App 档案、deviceShell=true、横屏时生效。"],result:["返回实际 viewport(width/height/deviceScaleFactor/scale)、UA、mobile、touch、orientation、deviceShell、splitScreen 和 reloaded;应以响应确认生效状态。"],examples:[`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"iphone-17-pro"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"pixel-11","orientation":"landscape"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":false}'`]},{name:"set_app_profile",description:"设置 App 客户端环境与 JSBridge;可同时设置 MTop 页面接口环境,传 emulation 时联动设备模拟",summary:"设置或清除目标标签页的 App 容器模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"profile",type:"string",description:`容器档案名(enabled=true 时必填);内置 ${APP_PROFILE_NAME_LIST}`},{name:"os",type:'"ios" | "android"',description:"容器系统,默认 ios"},{name:"refreshDefinition",type:"boolean",description:"立即采用最新档案定义,保留用户显式设置"},{name:"lockDefinition",type:"boolean",description:"固定当前定义;默认在下次刷新或文档导航时自动更新"},{name:"appVersion",type:"string",description:"覆盖档案默认 App 版本号"},{name:"deviceModel",type:"string",description:"Android 机型名(拼入 UA 与 __DEVICE_MODEL__)"},{name:"bridgeConfig",type:"object",description:"声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本"},{name:"mtopEnv",type:'"default" | "prod" | "pre"',description:"可选 MTop 页面接口环境;default 关闭环境改写,省略时保持当前设置。仅作用于目标 tab"},{name:"emulation",type:"object",description:"可选设备联动参数,字段同 set_device_emulation 去掉 enabled/reload;字段覆盖档案推荐设备,deviceShell 默认 true,横屏时可传 splitScreen=true。省略时不设置或清除设备"},{name:"reload",type:"boolean",description:"应用/清除后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],notes:["只有用户明确要求 App/客户端/容器/JSBridge 模拟时启用。移动视口或普通 H5 调试使用 set_device_emulation。","emulation={} 使用档案推荐设备;enabled=false 时省略 emulation 只清除 App 注入,传 {} 同时清除设备模拟。","bridgeConfig.methods 按方法声明 behavior / response / noop 三选一,可传 silent;只支持受控行为、固定 JSON 回包或成功空实现,不执行配置脚本。"],result:["返回 enabled、profile、label、userAgent、os、mtopEnv、reloaded;联动设备时额外返回实际 emulation。"],examples:[`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","mtopEnv":"pre"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"mtopEnv":"prod"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"alipay","emulation":{"preset":"pixel-11","deviceShell":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"emulation":{}}'`]},{name:"set_timezone",description:"覆盖目标 tab 的时区,传空字符串恢复浏览器默认时区",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"timezone",type:"string",required:!0,description:"IANA 时区标识(如 Asia/Shanghai);空字符串表示清除覆盖"}],examples:[`set_timezone --payload '{"tabId":12345,"timezone":"America/New_York"}'`,`set_timezone --payload '{"tabId":12345,"timezone":""}'`]},{name:"get_cookie",description:"从目标浏览器读取一个指定非分区 Cookie;拒绝返回 HttpOnly Cookie",params:[{name:"tabId",type:"number",description:"可选;指定标签页的 Cookie 存储区,省略时使用浏览器默认存储区"},{name:"name",type:"string",required:!0,description:"要读取的 Cookie 名称;不支持列举全部 Cookie"},{name:"url",type:"string",description:"Cookie 查询 URL;未传 tabId 时必填,省略时使用指定标签页 URL"},{name:"domain",type:"string",description:"可选精确域过滤,只允许 Cookie 查询 URL 的 host 或其父域"},{name:"path",type:"string",description:"可选精确 path 过滤"}],notes:["只读取指定非分区 Cookie,不列举全部、不回退分区 Cookie,拒绝 HttpOnly;禁止读取认证 Token。指定 url 不导航,指定 tabId 仅选择存储区时不启动采集。"],result:["找到时 found=true 并返回 value/domain/path;不存在时 found=false。"],examples:[`get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,`get_cookie --payload '{"url":"https://www.taobao.com/","name":"tracknick"}'`,`get_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","domain":"taobao.com"}'`,`get_cookie --payload '{"tabId":12345,"name":"tracknick","url":"https://www.taobao.com/","domain":"taobao.com","path":"/"}'`]},{name:"set_cookie",description:"在目标浏览器设置一个指定非分区 session Cookie,可选刷新指定页面",params:[{name:"tabId",type:"number",description:"可选;指定标签页的 Cookie 存储区,reload=true 时必填"},{name:"url",type:"string",description:"Cookie 目标 URL;未传 tabId 时必填,省略时使用指定标签页 URL"},{name:"name",type:"string",required:!0,description:"Cookie 名称"},{name:"value",type:"string",required:!0,description:"Cookie 值,可传空字符串;空字符串不会删除 Cookie"},{name:"domain",type:"string",description:"Cookie 域,默认目标 URL 的 host;只允许目标 host 或其父域"},{name:"path",type:"string",description:"Cookie path,默认 /"},{name:"reload",type:"boolean",description:"设置后是否刷新指定 tabId,默认 false;true 时必须传 tabId"}],notes:["仅写非分区 session Cookie,不支持删除。reload=true 时校验目标域与刷新页域的授权。"],result:["返回 url/name/domain/path/reloaded,指定标签页时包含 tabId;不回显 Cookie 值。"],examples:[`set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,`set_cookie --payload '{"url":"https://www.taobao.com/","name":"feature_flag","value":"enabled"}'`,`set_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","value":"3.6.63","domain":"taobao.com","reload":true}'`]},{name:"page_frames",description:"获取页面主 frame 与所有 iframe 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],result:["frames[] 包含 frameId、url、name 和 isMainFrame;frameId 可用于 page_eval 等支持 frame 定位的 action。"],examples:[`page_frames --payload '{"tabId":12345}'`]},{name:"request_domain_permission",description:"申请访问指定域名的权限(必要时弹窗让用户授权)",params:[{name:"domain",type:"string",required:!0,description:"需要授权的域名,如 example.com"}],notes:["domain 使用纯主机名,不传 URL。在非 BUC send_request 报域权限缺失,或 set_rule 提示缺少域名权限时申请;BUC 不使用浏览器域权限。","弹窗等待用户选择,90 秒超时或关闭按拒绝处理;granted=true 后才重试原请求。"],result:["返回 granted、domain,授权成功时包含 origin。"],examples:[`request_domain_permission --payload '{"domain":"example.com"}'`]},{name:"run_actions",description:"批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察",summary:"批量顺序执行多个 action,遇错即停",params:[{name:"actions",type:"Array<{action: string, data?: object}>",required:!0,description:"要依次执行的 action 列表"},{name:"tabId",type:"number",required:!0,description:"所有步骤共享的 tabId,步骤自身指定的优先"}],notes:["最多 50 步,不允许嵌套 run_actions;需要根据每步效果决策时逐步调用普通 action。"],result:["返回 results、completedSteps、totalSteps;失败时包含 error/failedStep,后续步骤未执行。"],examples:[`run_actions --payload '{"tabId":12345,"actions":[{"action":"page_hover","data":{"selector":"#menu"}},{"action":"page_click","data":{"selector":"#menu-item"}}]}'`]}],COMMAND_MAP=new Map(COMMANDS.map(command=>[command.name,command]))}});function findOfficialPlugin(name){return Object.hasOwn(OFFICIAL_PLUGINS,name)?OFFICIAL_PLUGINS[name]:void 0}var OFFICIAL_PLUGINS,init_officialPluginCatalog=__esm({"../client/src/plugins/officialPluginCatalog.ts"(){"use strict";OFFICIAL_PLUGINS={buc:{description:"使用 BUC 身份请求内部服务",installArgs:["trip/mearl","--skill","buc-request","--yes"],skill:"buc-request"},authx:{description:"使用 AuthX 身份请求内部服务",installArgs:["trip/mearl","--skill","authx-request","--yes"],skill:"authx-request"},tdbank:{description:"查询、借用和切换 TDBank 测试账号",installArgs:["trip/mearl","--skill","tdbank-account","--yes"],setup:"alibaba",skill:"tdbank-account"}}}});import{createRequire}from"node:module";import{fileURLToPath as fileURLToPath2}from"node:url";var require2,CLIENT_VERSION,PLUGIN_TASK_HOST_PATH,PLUGIN_WORKER_PATH,SCRIPT_WORKER_PATH,PLUGIN_MODEL_SESSION_WORKER_PATH,init_runtimePaths=__esm({"../client/src/runtimePaths.ts"(){"use strict";require2=createRequire(import.meta.url),CLIENT_VERSION=require2("../package.json").version,PLUGIN_TASK_HOST_PATH=fileURLToPath2(new URL("./plugin-task-host.js",import.meta.url)),PLUGIN_WORKER_PATH=fileURLToPath2(new URL("./plugin-worker.js",import.meta.url)),SCRIPT_WORKER_PATH=fileURLToPath2(new URL("./scriptWorker.js",import.meta.url)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath2(new URL("./pluginModelSessionWorker.js",import.meta.url))}});import{readFileSync as readFileSync2,readdirSync}from"node:fs";import{spawnSync}from"node:child_process";var init_process=__esm({"../daemon-core/dist/process.js"(){"use strict"}});import{join as join2}from"node:path";import{homedir}from"node:os";var DAEMON_HOME,init_paths=__esm({"../daemon-core/dist/paths.js"(){"use strict";DAEMON_HOME=join2(homedir(),".mearl")}});import{closeSync,existsSync as existsSync2,linkSync,openSync,statSync as statSync2,mkdirSync,readFileSync as readFileSync3,writeFileSync,renameSync as renameSync2,rmSync,readdirSync as readdirSync2}from"node:fs";import{dirname as dirname2,join as join3}from"node:path";var lockWaitBuffer,init_registry=__esm({"../daemon-core/dist/registry.js"(){"use strict";init_process();lockWaitBuffer=new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))}});import{existsSync as existsSync3,statSync as statSync3,renameSync as renameSync3,readFileSync as readFileSync4,readdirSync as readdirSync3,rmSync as rmSync2}from"node:fs";import{join as join4}from"node:path";var DEFAULT_MAX_LOG_BYTES,init_log=__esm({"../daemon-core/dist/log.js"(){"use strict";DEFAULT_MAX_LOG_BYTES=5*1024*1024}});import{spawn}from"node:child_process";import{closeSync as closeSync2,openSync as openSync2}from"node:fs";import{dirname as dirname3}from"node:path";var init_daemon=__esm({"../daemon-core/dist/daemon.js"(){"use strict";init_process();init_registry();init_log()}});import fs from"node:fs";import path from"node:path";import{spawn as spawn2}from"node:child_process";function versionManagerExecutableCandidates(home,names,options={}){let env=options.env??process.env,platform=options.platform??process.platform,readdirSync6=options.readdirSync??fs.readdirSync,fnmDefaultRoot=env.XDG_DATA_HOME?path.join(env.XDG_DATA_HOME,"fnm"):platform==="darwin"?path.join(home,"Library","Application Support","fnm"):platform==="win32"&&env.APPDATA?path.join(env.APPDATA,"fnm"):path.join(home,".local","share","fnm");return[path.join(env.NVM_DIR||path.join(home,".nvm"),"versions","node"),path.join(env.FNM_DIR||fnmDefaultRoot,"node-versions"),path.join(home,".fnm","node-versions")].filter((root,index,all)=>all.indexOf(root)===index).flatMap(root=>{try{return readdirSync6(root,{withFileTypes:!0}).filter(entry=>entry.isDirectory()).sort((left,right)=>right.name.localeCompare(left.name,void 0,{numeric:!0})).flatMap(entry=>names.flatMap(name=>[path.join(root,entry.name,"bin",name),path.join(root,entry.name,"installation","bin",name)]))}catch{return[]}})}function resolveSpawnCommand(executable,args,platform=process.platform,commandInterpreter=process.env.ComSpec){return platform==="win32"&&/\.(?:cmd|bat)$/i.test(executable)?{command:commandInterpreter||"cmd.exe",args:["/d","/s","/c",executable,...args]}:{command:executable,args}}function prependNodePath(env=process.env,nodeExecutable=process.execPath){return prependPathDirectory(path.dirname(nodeExecutable),env)}function npmExecEnvironment(env=process.env){return Object.fromEntries(Object.entries(env).filter(([key])=>key.toLowerCase()!=="npm_config_package"))}function prependPathDirectory(directory,env=process.env){let pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",entries=(env[pathKey]||"").split(path.delimiter).filter(Boolean);return entries.includes(directory)?env:{...env,[pathKey]:[directory,...entries].join(path.delimiter)}}var init_command=__esm({"../daemon-core/dist/command.js"(){"use strict"}});var init_dist=__esm({"../daemon-core/dist/index.js"(){"use strict";init_process();init_paths();init_registry();init_log();init_daemon();init_command()}});function parseToolboxIcon(value){if(typeof value!="string")return;let icon=value.trim();if(!icon||icon.length>32*1024)return;if(/^[a-z][a-z0-9-]{0,39}$/.test(icon))return{kind:"name",name:icon};if(/^(?:<\?xml\s[^>]*\?>\s*)?<svg\b[^>]*(?:\/>|>[\s\S]*<\/svg\s*>)$/i.test(icon)){let svg=/<svg\b[^>]*\sxmlns\s*=/i.test(icon)?icon:icon.replace(/<svg\b/i,'<svg xmlns="http://www.w3.org/2000/svg"');try{return{kind:"image",src:`data:image/svg+xml,${encodeURIComponent(svg)}`,.../\bcurrentColor\b/i.test(svg)?{monochrome:!0}:{}}}catch{return}}let dataHeader=/^data:image\/(?:svg\+xml|png|jpeg|gif|webp|avif)(?:;charset=utf-8|;utf8)?(?:;base64)?,/i.exec(icon);if(dataHeader&&icon.length>dataHeader[0].length)return{kind:"image",src:icon};try{let url=new URL(icon);if(["http:","https:"].includes(url.protocol)&&!url.username&&!url.password)return{kind:"image",src:url.href}}catch{}}var init_toolbox_icon=__esm({"../client/src/generated/toolbox-icon.ts"(){"use strict"}});import{createHash as createHash3}from"node:crypto";import{readFileSync as readFileSync5,realpathSync as realpathSync2}from"node:fs";import{basename as basename2,dirname as dirname4,extname,isAbsolute as isAbsolute2,join as join5,relative as relative2,resolve as resolve2,sep}from"node:path";var PLUGIN_PAGE_CHUNK_BYTES,MAX_PAGE_SOURCE_BYTES,MAX_PAGE_BUNDLE_BYTES,PAGE_BRIDGE_SCRIPT,PAGE_SECURITY_META,PAGE_THEME_STYLE,PLUGIN_PAGE_RUNTIME_HASH,init_pluginPageBundle=__esm({"../client/src/plugins/pluginPageBundle.ts"(){"use strict";init_pluginSource();PLUGIN_PAGE_CHUNK_BYTES=384*1024,MAX_PAGE_SOURCE_BYTES=16*1024*1024,MAX_PAGE_BUNDLE_BYTES=24*1024*1024,PAGE_BRIDGE_SCRIPT=String.raw`(() => {
|
|
29
29
|
let context = null;
|
|
30
30
|
let port = null;
|
|
31
31
|
let requestSequence = 0;
|
|
@@ -630,8 +630,8 @@ body {
|
|
|
630
630
|
color: var(--mearl-text-primary);
|
|
631
631
|
}
|
|
632
632
|
button, input, select, textarea { font: inherit; }
|
|
633
|
-
</style>`,PLUGIN_PAGE_RUNTIME_HASH=createHash3("sha256").update(PAGE_BRIDGE_SCRIPT).update(PAGE_SECURITY_META).update(PAGE_THEME_STYLE).digest("hex")}});import{closeSync,mkdirSync,openSync,readFileSync as
|
|
634
|
-
`),
|
|
633
|
+
</style>`,PLUGIN_PAGE_RUNTIME_HASH=createHash3("sha256").update(PAGE_BRIDGE_SCRIPT).update(PAGE_SECURITY_META).update(PAGE_THEME_STYLE).digest("hex")}});import{closeSync as closeSync3,mkdirSync as mkdirSync2,openSync as openSync3,readFileSync as readFileSync6,readSync,readdirSync as readdirSync4,renameSync as renameSync4,rmSync as rmSync3,statSync as statSync4,writeFileSync as writeFileSync2}from"node:fs";import{homedir as homedir2}from"node:os";import{isAbsolute as isAbsolute3,join as join6,resolve as resolve3}from"node:path";function pluginDirectory(){return resolve3(process.env.MEARL_PLUGIN_DIR||join6(homedir2(),".mearl","plugins"))}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 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||isAbsolute3(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 agent;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");agent={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}:{},...agent?{agent}:{},page,...candidate.order!==void 0?{order:candidate.order}:{}}}function findPluginRegistration(name){if(!/^[a-z][a-z0-9-]*$/.test(name))return;let file=join6(pluginDirectory(),`${name}.json`),content;try{content=readFileSync6(file,"utf8")}catch(error){if(error.code==="ENOENT")return;throw new PluginError("PLUGIN_REGISTRY_INVALID",`无法读取插件记录: ${file}`)}try{let record2=JSON.parse(content);if(typeof record2?.entry!="string"||!isAbsolute3(record2.entry))throw new Error("invalid entry");if(record2.hasPublicCommands!==void 0&&typeof record2.hasPublicCommands!="boolean")throw new Error("invalid public commands");let description=typeof record2.description=="string"&&record2.description.trim()?record2.description.trim():void 0,managedBy=typeof record2.managedBy=="string"&&record2.managedBy.trim()?record2.managedBy.trim():void 0,toolbox=normalizePluginToolboxContribution(record2.toolbox),pageBundle=toolbox?normalizePageBundle(record2.pageBundle):void 0,appProfiles=validateAppProfileContribution(record2.appProfiles),source=record2.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(([path7,version])=>!isAbsolute3(path7)||typeof version!="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(([path7,version])=>!isAbsolute3(path7)||typeof version!="string"))))throw new Error("invalid source");return{entry:record2.entry,...record2.hasPublicCommands!==void 0?{hasPublicCommands:record2.hasPublicCommands}:{},...description?{description}:{},...managedBy?{managedBy}:{},...toolbox?{toolbox}:{},...pageBundle?{pageBundle}:{},...appProfiles?{appProfiles}:{},...source?{source}:{}}}catch(cause){let reason=cause instanceof SyntaxError?"JSON 格式错误":cause instanceof Error?cause.message:"未知校验错误";throw new PluginError("PLUGIN_REGISTRY_INVALID",`无效的插件记录: ${file} (${reason})`,{cause})}}var PluginError,init_pluginRegistry=__esm({"../client/src/plugins/pluginRegistry.ts"(){"use strict";init_app_profile_definition();init_toolbox_icon();init_commands();init_pluginPageBundle();init_pluginSource();PluginError=class extends Error{constructor(code,message,options){super(`${code}: ${message}`,options);this.code=code}}}});import{closeSync as closeSync4,mkdirSync as mkdirSync3,openSync as openSync4,rmSync as rmSync4,statSync as statSync5,writeFileSync as writeFileSync3}from"node:fs";import{join as join7}from"node:path";import{spawn as spawn3}from"node:child_process";function delay(milliseconds){return new Promise(resolve6=>setTimeout(resolve6,milliseconds))}function installLockPath(name){return join7(pluginDirectory(),`.official-${name}.install.lock`)}async function acquireInstallLock(name){let directory=pluginDirectory();mkdirSync3(directory,{recursive:!0,mode:448});let lockPath=installLockPath(name),deadline=Date.now()+INSTALL_TIMEOUT_MS;for(;;){let descriptor;try{return descriptor=openSync4(lockPath,"wx",384),writeFileSync3(descriptor,`${process.pid}
|
|
634
|
+
`),closeSync4(descriptor),()=>rmSync4(lockPath,{force:!0})}catch(error){if(descriptor!==void 0&&closeSync4(descriptor),error.code!=="EEXIST")throw error}if(findPluginRegistration(name))return()=>{};try{if(Date.now()-statSync5(lockPath).mtimeMs>INSTALL_LOCK_STALE_MS){rmSync4(lockPath,{force:!0});continue}}catch(error){if(error.code==="ENOENT")continue;throw error}if(Date.now()>=deadline)throw new Error(`等待安装官方插件 ${name} 超时`);await delay(250)}}function appendOutput(current,chunk){return current.length>=MAX_INSTALL_OUTPUT?current:(current+chunk.toString("utf8")).slice(0,MAX_INSTALL_OUTPUT)}function installWithSetup(name){return new Promise((resolve6,reject)=>{let command=process.platform==="win32"?"npx.cmd":"npx",child=spawn3(command,["-y",`@mearl/setup@${CLIENT_VERSION}`,"plugin","ensure",name],{env:npmExecEnvironment(),stdio:["ignore","pipe","pipe"],windowsHide:!0}),stdout="",stderr="",settled=!1,finish=error=>{settled||(settled=!0,clearTimeout(timer),error?reject(error):resolve6())},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",error=>finish(error)),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;if(progress?.(`正在安装官方插件 ${name}...`),await installWithSetup(name),!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/src/plugins/officialPluginInstaller.ts"(){"use strict";init_runtimePaths();init_dist();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(error){let value=error,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(error),...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/src/plugins/runtime/pluginExecutorProtocol.ts"(){"use strict"}});import{spawn as spawn4}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(error){let serialized=serializePluginExecutionError(error);if(error instanceof PluginError){let prefix=`${error.code}: `;return{...serialized,code:error.code,message:error.message.startsWith(prefix)?error.message.slice(prefix.length):error.message}}return serialized}async function runPythonWorker(entry,initial,app,signal,expectedDescriptor){return new Promise((resolve6,reject)=>{let executable=pythonExecutable(),child=spawn4(executable,["-u","-c",PYTHON_BOOTSTRAP,entry],{stdio:["pipe","pipe","pipe"],windowsHide:!0}),lines=createInterface({input:child.stdout}),descriptor,outcome,protocolError,stderr="",failProtocol=error=>{protocolError||(protocolError=error instanceof Error?error:new Error(String(error)),cancel())},write=message=>{try{child.stdin.write(`${JSON.stringify(message)}
|
|
635
635
|
`)}catch(error){failProtocol(error)}};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",error=>{error.code==="ENOENT"?reject(new Error(`未找到 ${executable},Python 插件需要 Python 3.9 或更高版本(可通过 MEARL_PYTHON 指定解释器)`)):reject(error)}),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(error){failProtocol(new Error(`Python 插件输出了无效协议消息: ${line.slice(0,200)}`,error instanceof Error?{cause:error}: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(error){failProtocol(error)}return}if(message.type==="progress"){if(!app||typeof message.message!="string"){failProtocol(new Error("Python 插件发送了无效的 progress 消息"));return}try{app.progress(message.message)}catch(error){failProtocol(error)}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(error=>{write({type:"response",id:message.id,error:errorResponse(error)})});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}resolve6({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,input,app,context,recovery=!1,expectedDescriptor,runtimeOnly=!1){let{result}=await runPythonWorker(entry,{mode:"run",command,input,options:app.options,identity:context.identity,recovery,runtime:runtimeOnly},app,context.signal,expectedDescriptor);return result}var STDERR_LIMIT,PYTHON_BOOTSTRAP,init_pythonPlugin=__esm({"../client/src/plugins/runtime/pythonPlugin.ts"(){"use strict";init_pluginRecoveryDefinition();init_pluginRegistry();init_pluginExecutorProtocol();STDERR_LIMIT=64*1024,PYTHON_BOOTSTRAP=String.raw`
|
|
636
636
|
import asyncio
|
|
637
637
|
import importlib.util
|
|
@@ -962,10 +962,10 @@ except BaseException as error:
|
|
|
962
962
|
"message": "返回值无法 JSON 序列化: " + _error_message(serialization_error),
|
|
963
963
|
})
|
|
964
964
|
sys.exit(1)
|
|
965
|
-
`}});import{randomUUID}from"node:crypto";import{linkSync,mkdirSync as mkdirSync3,readFileSync as readFileSync4,rmSync as rmSync3,writeFileSync as writeFileSync3}from"node:fs";import{join as join5}from"node:path";function localPluginExecutionHost(){let directory=pluginDirectory(),hostId=hostIds.get(directory);if(!hostId){mkdirSync3(directory,{recursive:!0,mode:448});let file=join5(directory,".execution-host-id"),proposed=randomUUID(),temporary=`${file}.${proposed}.tmp`;try{writeFileSync3(temporary,proposed,{flag:"wx",mode:384}),linkSync(temporary,file)}catch(error){if(error.code!=="EEXIST")throw error}finally{rmSync3(temporary,{force:!0})}if(hostId=readFileSync4(file,"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:randomUUID(),host:parent?.host??localPluginExecutionHost(),plugin,source,...parent?{parentInvocationId:parent.invocationId}:{}})}var epoch,hostIds,UUID,init_pluginExecution=__esm({"../client/src/plugins/runtime/pluginExecution.ts"(){"use strict";init_pluginRegistry();epoch=randomUUID(),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{readFileSync as readFileSync5,readdirSync as readdirSync2}from"node:fs";import{spawnSync}from"node:child_process";var init_process=__esm({"../daemon-core/dist/process.js"(){"use strict"}});import{join as join6}from"node:path";import{homedir as homedir2}from"node:os";var DAEMON_HOME,init_paths=__esm({"../daemon-core/dist/paths.js"(){"use strict";DAEMON_HOME=join6(homedir2(),".mearl")}});import{closeSync as closeSync3,existsSync as existsSync2,linkSync as linkSync2,openSync as openSync3,statSync as statSync4,mkdirSync as mkdirSync4,readFileSync as readFileSync6,writeFileSync as writeFileSync4,renameSync as renameSync3,rmSync as rmSync4,readdirSync as readdirSync3}from"node:fs";import{dirname as dirname3,join as join7}from"node:path";var lockWaitBuffer,init_registry=__esm({"../daemon-core/dist/registry.js"(){"use strict";init_process();lockWaitBuffer=new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))}});import{existsSync as existsSync3,statSync as statSync5,renameSync as renameSync4,readFileSync as readFileSync7,readdirSync as readdirSync4,rmSync as rmSync5}from"node:fs";import{join as join8}from"node:path";var DEFAULT_MAX_LOG_BYTES,init_log=__esm({"../daemon-core/dist/log.js"(){"use strict";DEFAULT_MAX_LOG_BYTES=5*1024*1024}});import{spawn as spawn3}from"node:child_process";import{closeSync as closeSync4,openSync as openSync4}from"node:fs";import{dirname as dirname4}from"node:path";var init_daemon=__esm({"../daemon-core/dist/daemon.js"(){"use strict";init_process();init_registry();init_log()}});import fs2 from"node:fs";import path2 from"node:path";import{spawn as spawn4}from"node:child_process";function versionManagerExecutableCandidates(home,names,options={}){let env=options.env??process.env,platform=options.platform??process.platform,readdirSync6=options.readdirSync??fs2.readdirSync,fnmDefaultRoot=env.XDG_DATA_HOME?path2.join(env.XDG_DATA_HOME,"fnm"):platform==="darwin"?path2.join(home,"Library","Application Support","fnm"):platform==="win32"&&env.APPDATA?path2.join(env.APPDATA,"fnm"):path2.join(home,".local","share","fnm");return[path2.join(env.NVM_DIR||path2.join(home,".nvm"),"versions","node"),path2.join(env.FNM_DIR||fnmDefaultRoot,"node-versions"),path2.join(home,".fnm","node-versions")].filter((root,index,all)=>all.indexOf(root)===index).flatMap(root=>{try{return readdirSync6(root,{withFileTypes:!0}).filter(entry=>entry.isDirectory()).sort((left,right)=>right.name.localeCompare(left.name,void 0,{numeric:!0})).flatMap(entry=>names.flatMap(name=>[path2.join(root,entry.name,"bin",name),path2.join(root,entry.name,"installation","bin",name)]))}catch{return[]}})}function resolveSpawnCommand(executable,args,platform=process.platform,commandInterpreter=process.env.ComSpec){return platform==="win32"&&/\.(?:cmd|bat)$/i.test(executable)?{command:commandInterpreter||"cmd.exe",args:["/d","/s","/c",executable,...args]}:{command:executable,args}}function prependNodePath(env=process.env,nodeExecutable=process.execPath){return prependPathDirectory(path2.dirname(nodeExecutable),env)}function prependPathDirectory(directory,env=process.env){let pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",entries=(env[pathKey]||"").split(path2.delimiter).filter(Boolean);return entries.includes(directory)?env:{...env,[pathKey]:[directory,...entries].join(path2.delimiter)}}var init_command2=__esm({"../daemon-core/dist/command.js"(){"use strict"}});var init_dist=__esm({"../daemon-core/dist/index.js"(){"use strict";init_process();init_paths();init_registry();init_log();init_daemon();init_command2()}});import{execFile}from"node:child_process";var init_pluginProcessTree=__esm({"../client/src/plugins/runtime/pluginProcessTree.ts"(){"use strict";init_dist()}});import{fork as fork2}from"node:child_process";var init_pluginExecutor=__esm({"../client/src/plugins/runtime/pluginExecutor.ts"(){"use strict";init_runtimePaths();init_pluginRegistry();init_pluginSource();init_pluginExecution();init_pluginExecutorProtocol();init_pluginProcessTree();init_dist()}});import{tmpdir}from"node:os";import{join as join9}from"node:path";var init_pluginHostPaths=__esm({"../client/src/plugins/runtime/pluginHostPaths.ts"(){"use strict";init_pluginRegistry()}});var init_plugin_tasks=__esm({"../client/src/generated/plugin-tasks.ts"(){"use strict"}});var MAX_MESSAGE_BYTES,init_pluginTaskWire=__esm({"../client/src/plugins/pluginTaskWire.ts"(){"use strict";MAX_MESSAGE_BYTES=96*1024*1024}});import{spawn as spawn5}from"node:child_process";import{closeSync as closeSync5,mkdirSync as mkdirSync5,openSync as openSync5}from"node:fs";import{createConnection}from"node:net";var init_pluginHostConnection=__esm({"../client/src/plugins/clients/pluginHostConnection.ts"(){"use strict";init_runtimePaths();init_dist();init_pluginHostPaths();init_plugin_tasks();init_pluginTaskWire();init_pluginExecutorProtocol()}});import{open,mkdir,rename,rm,stat}from"node:fs/promises";import path3 from"node:path";var CHUNK_BYTES,init_artifacts=__esm({"../client/src/artifacts.ts"(){"use strict";CHUNK_BYTES=256*1024}});var init_dist2=__esm({"../cloud/cloud-types/dist/index.js"(){"use strict"}});var OBSERVED_PAGE_ACTIONS,init_actionTimeouts=__esm({"../client/src/actionTimeouts.ts"(){"use strict";init_browser_action_protocol();OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS)}});var init_protocol=__esm({"../provider/dist/protocol.js"(){"use strict"}});var init_types=__esm({"../provider/dist/types.js"(){"use strict";init_protocol()}});var PROVIDER_ACTIONS,providerActionSet,init_provider_actions=__esm({"../provider/dist/generated/provider-actions.js"(){"use strict";PROVIDER_ACTIONS=["tab_checkpoint","capture_checkpoint","get_requests","get_logs","get_events","set_mock","get_mocks","set_rule","get_rules","send_request","send_mtop_request","browser_release","page_screenshot","tab_open","tab_close","tab_list","tab_group","page_click","page_drag","page_type","page_scroll","page_hover","page_eval","page_runtime","page_inspect","page_snapshot","page_press","page_wait","page_navigate","page_upload","page_frames","set_device_emulation","set_app_profile","set_timezone","get_cookie","set_cookie","request_domain_permission","run_actions","page_download"],providerActionSet=new Set(PROVIDER_ACTIONS)}});var init_provider_runtime=__esm({"../provider/dist/provider-runtime.js"(){"use strict";init_types();init_provider_actions()}});import{existsSync as existsSync4,readFileSync as readFileSync8,renameSync as renameSync5,rmSync as rmSync6,statSync as statSync6,writeFileSync as writeFileSync5}from"node:fs";import{isAbsolute as isAbsolute4,join as join10,relative as relative3,resolve as resolve4,sep as sep2}from"node:path";var init_registry2=__esm({"../provider/dist/registry.js"(){"use strict";init_dist();init_types();init_provider_runtime();init_protocol()}});import{spawn as spawn6}from"node:child_process";import{tmpdir as tmpdir2}from"node:os";import{join as join11}from"node:path";var init_control_host=__esm({"../provider/dist/control-host.js"(){"use strict";init_protocol();init_dist()}});var init_host=__esm({"../provider/dist/host.js"(){"use strict";init_registry2();init_control_host()}});import net from"node:net";import{chmodSync,rmSync as rmSync7}from"node:fs";import{dirname as dirname5}from"node:path";var MAX_REQUEST_BYTES,init_server=__esm({"../provider/dist/server.js"(){"use strict";init_dist();init_provider_actions();init_provider_runtime();init_registry2();init_types();init_protocol();MAX_REQUEST_BYTES=16*1024*1024}});var init_dist3=__esm({"../provider/dist/index.js"(){"use strict";init_types();init_protocol();init_provider_actions();init_registry2();init_provider_runtime();init_server()}});import{spawn as spawn7}from"node:child_process";import{closeSync as closeSync6,existsSync as existsSync5,mkdirSync as mkdirSync6,openSync as openSync6}from"node:fs";import{join as join12}from"node:path";var init_launcher=__esm({"../provider/dist/launcher.js"(){"use strict";init_dist();init_registry2();init_protocol()}});var init_runtime=__esm({"../provider/dist/runtime.js"(){"use strict";init_launcher();init_registry2();init_provider_runtime()}});import fs3 from"node:fs";var init_fileRefs=__esm({"../client/src/fileRefs.ts"(){"use strict"}});import fs4 from"node:fs";import os from"node:os";import path4 from"node:path";var BROWSERS_DIR,init_browserRegistry=__esm({"../client/src/browserRegistry.ts"(){"use strict";BROWSERS_DIR=path4.join(os.homedir(),".mearl","browsers")}});import net2 from"node:net";import fs5 from"node:fs";import os2 from"node:os";import path5 from"node:path";var MAX_SOCKET_BUFFER_SIZE,SOCKET_PATH,SESSION_OPTION,init_socket=__esm({"../client/src/socket.ts"(){"use strict";init_runtimePaths();init_host();init_dist3();init_runtime();init_fileRefs();init_browserRegistry();init_actionTimeouts();init_browser_action_protocol();MAX_SOCKET_BUFFER_SIZE=64*1024*1024,SOCKET_PATH=process.platform==="win32"?"\\\\.\\pipe\\mearl-agent":path5.join(os2.tmpdir(),"mearl-agent.sock"),SESSION_OPTION=Symbol("control-session")}});import{existsSync as existsSync6,readFileSync as readFileSync9}from"node:fs";import{homedir as homedir3}from"node:os";import{join as join13}from"node:path";var MEARL_CONFIG_DIR,init_unifiedConfig=__esm({"../client/src/unifiedConfig.ts"(){"use strict";MEARL_CONFIG_DIR=join13(homedir3(),".mearl")}});import WebSocket from"ws";var init_unified=__esm({"../client/src/unified.ts"(){"use strict";init_pageEvalArguments();init_artifacts();init_dist2();init_actionTimeouts();init_browser_action_protocol();init_socket();init_unifiedConfig()}});var init_pluginTasks=__esm({"../client/src/plugins/clients/pluginTasks.ts"(){"use strict";init_pluginHostConnection();init_dist();init_pluginHostPaths();init_unified();init_plugin_tasks();init_pluginExecutorProtocol()}});import{closeSync as closeSync7,fsyncSync,mkdirSync as mkdirSync7,openSync as openSync7,renameSync as renameSync6,rmSync as rmSync8,writeFileSync as writeFileSync6}from"node:fs";import{dirname as dirname6}from"node:path";var init_pluginHostFiles=__esm({"../client/src/plugins/runtime/pluginHostFiles.ts"(){"use strict"}});import{closeSync as closeSync8,openSync as openSync8,opendirSync,readFileSync as readFileSync10,readSync as readSync2,readdirSync as readdirSync5,rmSync as rmSync9,statSync as statSync7}from"node:fs";import{join as join14}from"node:path";var PLUGIN_TASK_RESULT_CHUNK_BYTES,MAX_EVENT_BYTES,MAX_RESULT_BYTES,RETENTION_MS,init_pluginTaskStore=__esm({"../client/src/plugins/runtime/pluginTaskStore.ts"(){"use strict";init_plugin_tasks();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}});import{rmSync as rmSync10}from"node:fs";var init_pluginRuntimeCleanup=__esm({"../client/src/plugins/runtime/pluginRuntimeCleanup.ts"(){"use strict";init_dist();init_pluginHostPaths();init_pluginRegistry();init_pluginTasks();init_pluginTaskStore()}});var init_pluginPages=__esm({"../client/src/plugins/clients/pluginPages.ts"(){"use strict";init_unified()}});var init_pluginState=__esm({"../client/src/plugins/clients/pluginState.ts"(){"use strict";init_pluginHostConnection()}});var init_pluginModels=__esm({"../client/src/plugins/clients/pluginModels.ts"(){"use strict";init_pluginTasks()}});import{readFileSync as readFileSync11}from"node:fs";import{dirname as dirname7,extname as extname2,resolve as resolve5}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{let manifest=skillManifestPath(resolve5(dirname7(entry),".."));return manifest?readFileSync11(manifest,"utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]?.split(/\r?\n/).find(line=>/^version:\s*/.test(line))?.match(/^version:\s*["']?([^"'#\s]+)["']?\s*$/)?.[1]:void 0}catch{return}}function isObject2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isPluginInvocation(value){return isObject2(value)&&typeof value.command=="string"&&isObject2(value.input)}function normalizePluginProgress(progress){if(typeof progress=="string"){if(!progress)throw new Error("app.progress 需要非空消息");return progress}if(!isObject2(progress)||typeof progress.message!="string"||!progress.message)throw new Error("app.progress 需要非空消息");if(progress.data!==void 0&&!isObject2(progress.data))throw new Error("app.progress data 必须是对象");let data;if(progress.data)try{let serialized=JSON.stringify(progress.data),parsed=serialized===void 0?void 0:JSON.parse(serialized);if(!isObject2(parsed))throw new Error("invalid object");data=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data?{data}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx @mearl/setup plugin uninstall ${name}`].join(`
|
|
965
|
+
`}});import{randomUUID}from"node:crypto";import{linkSync as linkSync2,mkdirSync as mkdirSync4,readFileSync as readFileSync7,rmSync as rmSync5,writeFileSync as writeFileSync4}from"node:fs";import{join as join8}from"node:path";function localPluginExecutionHost(){let directory=pluginDirectory(),hostId=hostIds.get(directory);if(!hostId){mkdirSync4(directory,{recursive:!0,mode:448});let file=join8(directory,".execution-host-id"),proposed=randomUUID(),temporary=`${file}.${proposed}.tmp`;try{writeFileSync4(temporary,proposed,{flag:"wx",mode:384}),linkSync2(temporary,file)}catch(error){if(error.code!=="EEXIST")throw error}finally{rmSync5(temporary,{force:!0})}if(hostId=readFileSync7(file,"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:randomUUID(),host:parent?.host??localPluginExecutionHost(),plugin,source,...parent?{parentInvocationId:parent.invocationId}:{}})}var epoch,hostIds,UUID,init_pluginExecution=__esm({"../client/src/plugins/runtime/pluginExecution.ts"(){"use strict";init_pluginRegistry();epoch=randomUUID(),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";var init_pluginProcessTree=__esm({"../client/src/plugins/runtime/pluginProcessTree.ts"(){"use strict";init_dist()}});import{fork as fork2}from"node:child_process";var init_pluginExecutor=__esm({"../client/src/plugins/runtime/pluginExecutor.ts"(){"use strict";init_runtimePaths();init_pluginRegistry();init_pluginSource();init_pluginExecution();init_pluginExecutorProtocol();init_pluginProcessTree();init_dist()}});import{tmpdir}from"node:os";import{join as join9}from"node:path";var init_pluginHostPaths=__esm({"../client/src/plugins/runtime/pluginHostPaths.ts"(){"use strict";init_pluginRegistry()}});var init_plugin_tasks=__esm({"../client/src/generated/plugin-tasks.ts"(){"use strict"}});var MAX_MESSAGE_BYTES,init_pluginTaskWire=__esm({"../client/src/plugins/pluginTaskWire.ts"(){"use strict";MAX_MESSAGE_BYTES=96*1024*1024}});import{spawn as spawn5}from"node:child_process";import{closeSync as closeSync5,mkdirSync as mkdirSync5,openSync as openSync5}from"node:fs";import{createConnection}from"node:net";var init_pluginHostConnection=__esm({"../client/src/plugins/clients/pluginHostConnection.ts"(){"use strict";init_runtimePaths();init_dist();init_pluginHostPaths();init_plugin_tasks();init_pluginTaskWire();init_pluginExecutorProtocol()}});import{open,mkdir,rename,rm,stat}from"node:fs/promises";import path2 from"node:path";var CHUNK_BYTES,init_artifacts=__esm({"../client/src/artifacts.ts"(){"use strict";CHUNK_BYTES=256*1024}});var init_dist2=__esm({"../cloud/cloud-types/dist/index.js"(){"use strict"}});var OBSERVED_PAGE_ACTIONS,init_actionTimeouts=__esm({"../client/src/actionTimeouts.ts"(){"use strict";init_browser_action_protocol();OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS)}});var init_protocol=__esm({"../provider/dist/protocol.js"(){"use strict"}});var init_types=__esm({"../provider/dist/types.js"(){"use strict";init_protocol()}});var PROVIDER_ACTIONS,providerActionSet,init_provider_actions=__esm({"../provider/dist/generated/provider-actions.js"(){"use strict";PROVIDER_ACTIONS=["tab_checkpoint","capture_checkpoint","get_requests","get_logs","get_events","set_mock","get_mocks","set_rule","get_rules","send_request","send_mtop_request","browser_release","page_screenshot","tab_open","tab_close","tab_list","tab_group","page_click","page_drag","page_type","page_scroll","page_hover","page_eval","page_runtime","page_inspect","page_snapshot","page_press","page_wait","page_navigate","page_upload","page_frames","set_device_emulation","set_app_profile","set_timezone","get_cookie","set_cookie","request_domain_permission","run_actions","page_download"],providerActionSet=new Set(PROVIDER_ACTIONS)}});var init_provider_runtime=__esm({"../provider/dist/provider-runtime.js"(){"use strict";init_types();init_provider_actions()}});import{existsSync as existsSync4,readFileSync as readFileSync8,renameSync as renameSync5,rmSync as rmSync6,statSync as statSync6,writeFileSync as writeFileSync5}from"node:fs";import{isAbsolute as isAbsolute4,join as join10,relative as relative3,resolve as resolve4,sep as sep2}from"node:path";var init_registry2=__esm({"../provider/dist/registry.js"(){"use strict";init_dist();init_types();init_provider_runtime();init_protocol()}});import{spawn as spawn6}from"node:child_process";import{tmpdir as tmpdir2}from"node:os";import{join as join11}from"node:path";var init_control_host=__esm({"../provider/dist/control-host.js"(){"use strict";init_protocol();init_dist()}});var init_host=__esm({"../provider/dist/host.js"(){"use strict";init_registry2();init_control_host()}});import net from"node:net";import{chmodSync,rmSync as rmSync7}from"node:fs";import{dirname as dirname5}from"node:path";var MAX_REQUEST_BYTES,init_server=__esm({"../provider/dist/server.js"(){"use strict";init_dist();init_provider_actions();init_provider_runtime();init_registry2();init_types();init_protocol();MAX_REQUEST_BYTES=16*1024*1024}});var init_dist3=__esm({"../provider/dist/index.js"(){"use strict";init_types();init_protocol();init_provider_actions();init_registry2();init_provider_runtime();init_server()}});import{spawn as spawn7}from"node:child_process";import{closeSync as closeSync6,existsSync as existsSync5,mkdirSync as mkdirSync6,openSync as openSync6}from"node:fs";import{join as join12}from"node:path";var init_launcher=__esm({"../provider/dist/launcher.js"(){"use strict";init_dist();init_registry2();init_protocol()}});var init_runtime=__esm({"../provider/dist/runtime.js"(){"use strict";init_launcher();init_registry2();init_provider_runtime()}});import fs2 from"node:fs";var init_fileRefs=__esm({"../client/src/fileRefs.ts"(){"use strict"}});import fs3 from"node:fs";import os from"node:os";import path3 from"node:path";var BROWSERS_DIR,init_browserRegistry=__esm({"../client/src/browserRegistry.ts"(){"use strict";BROWSERS_DIR=path3.join(os.homedir(),".mearl","browsers")}});import net2 from"node:net";import fs4 from"node:fs";import os2 from"node:os";import path4 from"node:path";var MAX_SOCKET_BUFFER_SIZE,SOCKET_PATH,SESSION_OPTION,init_socket=__esm({"../client/src/socket.ts"(){"use strict";init_runtimePaths();init_host();init_dist3();init_runtime();init_fileRefs();init_browserRegistry();init_actionTimeouts();init_browser_action_protocol();MAX_SOCKET_BUFFER_SIZE=64*1024*1024,SOCKET_PATH=process.platform==="win32"?"\\\\.\\pipe\\mearl-agent":path4.join(os2.tmpdir(),"mearl-agent.sock"),SESSION_OPTION=Symbol("control-session")}});import{existsSync as existsSync6,readFileSync as readFileSync9}from"node:fs";import{homedir as homedir3}from"node:os";import{join as join13}from"node:path";var MEARL_CONFIG_DIR,init_unifiedConfig=__esm({"../client/src/unifiedConfig.ts"(){"use strict";MEARL_CONFIG_DIR=join13(homedir3(),".mearl")}});import WebSocket from"ws";var init_unified=__esm({"../client/src/unified.ts"(){"use strict";init_pageEvalArguments();init_artifacts();init_dist2();init_actionTimeouts();init_browser_action_protocol();init_socket();init_unifiedConfig()}});var init_pluginTasks=__esm({"../client/src/plugins/clients/pluginTasks.ts"(){"use strict";init_pluginHostConnection();init_dist();init_pluginHostPaths();init_unified();init_plugin_tasks();init_pluginExecutorProtocol()}});import{closeSync as closeSync7,fsyncSync,mkdirSync as mkdirSync7,openSync as openSync7,renameSync as renameSync6,rmSync as rmSync8,writeFileSync as writeFileSync6}from"node:fs";import{dirname as dirname6}from"node:path";var init_pluginHostFiles=__esm({"../client/src/plugins/runtime/pluginHostFiles.ts"(){"use strict"}});import{closeSync as closeSync8,openSync as openSync8,opendirSync,readFileSync as readFileSync10,readSync as readSync2,readdirSync as readdirSync5,rmSync as rmSync9,statSync as statSync7}from"node:fs";import{join as join14}from"node:path";var PLUGIN_TASK_RESULT_CHUNK_BYTES,MAX_EVENT_BYTES,MAX_RESULT_BYTES,RETENTION_MS,init_pluginTaskStore=__esm({"../client/src/plugins/runtime/pluginTaskStore.ts"(){"use strict";init_plugin_tasks();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}});import{rmSync as rmSync10}from"node:fs";var init_pluginRuntimeCleanup=__esm({"../client/src/plugins/runtime/pluginRuntimeCleanup.ts"(){"use strict";init_dist();init_pluginHostPaths();init_pluginRegistry();init_pluginTasks();init_pluginTaskStore()}});var init_pluginPages=__esm({"../client/src/plugins/clients/pluginPages.ts"(){"use strict";init_unified()}});var init_pluginState=__esm({"../client/src/plugins/clients/pluginState.ts"(){"use strict";init_pluginHostConnection()}});var init_pluginModels=__esm({"../client/src/plugins/clients/pluginModels.ts"(){"use strict";init_pluginTasks()}});import{readFileSync as readFileSync11}from"node:fs";import{dirname as dirname7,extname as extname2,resolve as resolve5}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{let manifest=skillManifestPath(resolve5(dirname7(entry),".."));return manifest?readFileSync11(manifest,"utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]?.split(/\r?\n/).find(line=>/^version:\s*/.test(line))?.match(/^version:\s*["']?([^"'#\s]+)["']?\s*$/)?.[1]:void 0}catch{return}}function isObject2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isPluginInvocation(value){return isObject2(value)&&typeof value.command=="string"&&isObject2(value.input)}function normalizePluginProgress(progress){if(typeof progress=="string"){if(!progress)throw new Error("app.progress 需要非空消息");return progress}if(!isObject2(progress)||typeof progress.message!="string"||!progress.message)throw new Error("app.progress 需要非空消息");if(progress.data!==void 0&&!isObject2(progress.data))throw new Error("app.progress data 必须是对象");let data;if(progress.data)try{let serialized=JSON.stringify(progress.data),parsed=serialized===void 0?void 0:JSON.parse(serialized);if(!isObject2(parsed))throw new Error("invalid object");data=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data?{data}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx @mearl/setup plugin uninstall ${name}`].join(`
|
|
966
966
|
`)}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,(input,commandContext)=>handler(input,commandContext))},checkpoint(data,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,expectedSequence,expectedDeclaration:checkpointDeclaration})},state(collection,operation,input={}){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",{...input,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,input={}){if(!executing)throw new Error("app.page is only available during command execution");return context.signal?.throwIfAborted(),context.invoke("plugin_page",{...input,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,(input,commandContext)=>runPythonPluginCommand(entry,commandName,input,app,commandContext,"migration",descriptor));continue}if(command.recoveryOnly){app.recoveryCommand(commandName,(input,commandContext)=>runPythonPluginCommand(entry,commandName,input,app,commandContext,!0,descriptor));continue}(command.runtimeOnly?app.runtimeCommand:command.toolboxOnly?app.toolboxCommand:app.command)(command.signature,(input,commandContext)=>runPythonPluginCommand(entry,commandName,input,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(error){throw new PluginError("PLUGIN_LOAD_FAILED",`${entry}: ${error instanceof Error?error.message:String(error)}`)}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),run2=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 input={...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(input,argument.name())?input[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 identity=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,signal,...identity.recovery?{recovery:structuredClone(identity.recovery)}:{},checkpoint:(data,expectedSequence)=>(assertActive(),app.checkpoint(data,expectedSequence)),...identity.page?{page:Object.freeze({send:(message,options={})=>(assertActive(),app.page("send",{instanceId:identity.page.instanceId,message,...options.timeoutSec!==void 0?{timeoutSec:options.timeoutSec}:{}})),get:()=>(assertActive(),app.page("get",{instanceId:identity.page.instanceId}))})}:{},invoke:(action,payload2,options)=>(assertActive(),app.invoke(action,payload2,options)),state:(collection,operation,input2)=>(assertActive(),app.state(collection,operation,{...identity.page?{instanceId:identity.page.instanceId}:{},...input2})),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?.(identity);try{return await handler(input,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(`
|
|
967
967
|
`)},help(namespace,name2){let selected=name2?[find(name2)]:publicCommands();if(!selected.length){let location=toolbox?`请在 Mearl ${toolbox.displayMode==="popup"?"Popup":"工具箱"} 中打开「${toolbox.title}」使用。`:"此插件未提供公开 CLI 命令。";return`${namespace} 未提供 CLI 命令。
|
|
968
968
|
${location}`}let examples=selected.flatMap(({examples:examples2})=>examples2);return["用法:",...selected.map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`),...examples.length?["","示例:",...examples.map(example=>` ${namespace} ${example}`)]:[]].join(`
|
|
969
|
-
`)},run(positionals,payload,namedInput={}){return run2(positionals,payload,namedInput)},runRuntime(invocation){return run2([],invocation,{},"runtime")},runRecovery(invocation){return run2([],invocation,{},"recovery")},runMigration(invocation){return run2([],invocation,{},"migration")},runToolbox(invocation){return run2([],invocation,{},!0)}}}async function loadRegisteredPluginWithState(name,context,options={},state={stack:[]}){if(state.stack.includes(name))throw new PluginError("PLUGIN_INVOCATION_CYCLE",`插件调用形成循环: ${[...state.stack,name].join(" -> ")}`);let registration=context.resolveRegistration?context.resolveRegistration(name):findPluginRegistration(name);if(!registration&&findOfficialPlugin(name)&&(await(context.ensurePlugin??ensureOfficialPluginRegistered)(name,options.onProgress?message=>options.onProgress?.(message):void 0),registration=findPluginRegistration(name)),!registration)throw new PluginError("PLUGIN_NOT_REGISTERED",`插件未注册: ${name}`);let{onProgress,signal,source,...invokeOptions}=options,childState={stack:[...state.stack,name]},activeInvocation;return loadPlugin(registration.entry,{options:invokeOptions,source:source??context.source,parentInvocation:context.parentInvocation,invocation:context.invocation,signal,runModel:context.runModel,onInvocation:identity=>{activeInvocation=identity},progress:onProgress??(()=>{}),async invoke(action,payload,overrides,progress){let nestedOptions={...invokeOptions,...overrides};if(COMMAND_MAP.has(action)||action==="connector_list"){let result2=await context.invoke(action,payload,nestedOptions);if(result2?.action?.success===!1)throw new Error(result2.action.error||`${action} failed`);return result2}let pluginInvocation=isPluginInvocation(payload);if(findPluginRegistration(action)||findOfficialPlugin(action)||pluginInvocation){if(!pluginInvocation)throw new PluginError("PLUGIN_INVALID_INPUT",`调用插件 ${action} 需要 {"command":"...","input":{...}}`);return activeInvocation?.taskId?(!findPluginRegistration(action)&&findOfficialPlugin(action)&&await(context.ensurePlugin??ensureOfficialPluginRegistered)(action),context.invoke("plugin_invoke_child",{plugin:action,invocation:payload},nestedOptions)):invokeRegisteredPluginWithState(action,payload,{...context,invocation:void 0,parentInvocation:activeInvocation},{...nestedOptions,...onProgress?{onProgress}:{},...signal?{signal}:{},...source?{source}:{}},childState)}let result=await(progress?context.invoke(action,payload,nestedOptions,progress):context.invoke(action,payload,nestedOptions));if(result?.action?.success===!1)throw new Error(result.action.error||`${action} failed`);return result}},name)}async function invokeRegisteredPluginWithState(name,invocation,context,options={},state={stack:[]}){return(await loadRegisteredPluginWithState(name,context,options,state)).run([],invocation)}function invokeRegisteredPlugin(name,invocation,context,options={}){return invokeRegisteredPluginWithState(name,invocation,context,options)}async function invokeRegisteredToolboxPlugin(name,invocation,context,options={}){return(await loadRegisteredPluginWithState(name,context,options)).runToolbox(invocation)}async function invokeRegisteredRuntimePlugin(name,invocation,context,options={}){return(await loadRegisteredPluginWithState(name,context,options)).runRuntime(invocation)}async function invokeRegisteredRecoveryPlugin(name,invocation,context,options={}){return(await loadRegisteredPluginWithState(name,context,options)).runRecovery(invocation)}var init_plugin=__esm({"../client/src/plugins/sdk/plugin.ts"(){"use strict";init_pluginStateDefinition();init_pluginRecoveryDefinition();init_pluginPageDefinition();init_pluginAppProfiles();init_pageEvalArguments();init_skillManifest();init_commander();init_commands();init_officialPluginCatalog();init_officialPluginInstaller();init_pluginRegistry();init_pluginSource();init_pythonPlugin();init_pluginExecution();init_pluginExecutor();init_pluginTasks();init_pluginRuntimeCleanup();init_pluginPages();init_pluginRegistry();init_officialPluginCatalog();init_pluginState();init_pluginModels()}});var init_process_env=__esm({"../agent-runtime/dist/process-env.js"(){"use strict";init_dist()}});import fs6 from"node:fs";import{spawn as spawn8}from"node:child_process";import path6 from"node:path";function agentExecutableCandidatePaths({executableNames,configuredPath,env=process.env,extraUserCandidates=[],home,platform=process.platform,processExecPath=process.execPath,readdirSync:readdirSync6}){let pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",pathCandidates=(env[pathKey]||"").split(path6.delimiter).filter(Boolean).flatMap(directory=>executableNames.map(name=>path6.join(directory,name))),commonUserDirectories=[path6.join(home,".local","bin"),path6.join(home,".npm-global","bin"),path6.join(home,".volta","bin"),path6.join(home,".local","share","pnpm"),path6.join(home,"Library","pnpm"),path6.join(home,".bun","bin"),...platform==="win32"&&env.APPDATA?[path6.join(env.APPDATA,"npm")]:[]],systemDirectories=platform==="win32"?[]:["/opt/homebrew/bin","/usr/local/bin","/usr/bin"];return[configuredPath,...executableNames.map(name=>path6.join(path6.dirname(processExecPath),name)),...commonUserDirectories.flatMap(directory=>executableNames.map(name=>path6.join(directory,name))),...extraUserCandidates,...versionManagerExecutableCandidates(home,executableNames,{env,platform,readdirSync:readdirSync6}),...systemDirectories.flatMap(directory=>executableNames.map(name=>path6.join(directory,name))),...pathCandidates].filter(candidate=>typeof candidate=="string")}function executableFileCandidates(candidates){let seen=new Set,executableCandidates=[];for(let candidate of candidates)!candidate||seen.has(candidate)||(seen.add(candidate),isExecutableFile(candidate)&&executableCandidates.push(candidate));return executableCandidates}function probeAgentExecutable(executable,options){return new Promise(resolve6=>{let settled=!1,stderr="",launch=resolveSpawnCommand(executable,options.args),child=spawn8(launch.command,launch.args,{stdio:["ignore","ignore","pipe"],windowsHide:!0,env:prependNodePath()}),finish=error=>{settled||(settled=!0,clearTimeout(timer),resolve6(error))},timer=setTimeout(()=>{child.kill("SIGTERM"),finish(options.timeoutError)},options.timeoutMs);child.stderr?.on("data",chunk=>{stderr.length<4e3&&(stderr+=chunk.toString("utf8"))}),child.once("error",error=>finish(options.startError(error))),child.once("exit",code=>{if(code===0){finish(null);return}finish(stderr.trim()||options.exitError(code))})})}function isExecutableFile(candidate){try{return fs6.accessSync(candidate,process.platform==="win32"?fs6.constants.F_OK:fs6.constants.X_OK),fs6.statSync(candidate).isFile()}catch{return!1}}var AgentExecutableResolver,init_executable_resolver=__esm({"../agent-runtime/dist/executable-resolver.js"(){"use strict";init_process_env();AgentExecutableResolver=class{options;resolvedExecutable=null;resolutionPromise=null;generation=0;constructor(options){this.options=options}async resolve(){if(this.resolvedExecutable){if(isExecutableFile(this.resolvedExecutable))return{executable:this.resolvedExecutable,error:null};this.resolvedExecutable=null}if(this.resolutionPromise)return this.resolutionPromise;let generation=this.generation,resolution=this.probeCandidates(generation);this.resolutionPromise=resolution;try{return await resolution}finally{this.resolutionPromise===resolution&&(this.resolutionPromise=null)}}reset(){this.generation+=1,this.resolvedExecutable=null,this.resolutionPromise=null}async probeCandidates(generation){let candidates=this.options.candidates();if(candidates.length===0)return{executable:null,error:this.options.notFoundError};let failures=[],recordFailure=(executable,error)=>{failures.push({executable,error}),this.options.onFailure?.(executable,error)},select=(executable,version)=>(this.generation===generation&&(this.resolvedExecutable=executable,this.options.onSelection?.(executable,version)),{executable,error:null}),preferredCandidates=this.options.preferred?candidates.filter(executable=>this.options.preferred?.(executable)):[],automaticCandidates=candidates.filter(executable=>!preferredCandidates.includes(executable));for(let executable of preferredCandidates){let error=await this.options.probe(executable);if(error===null)return select(executable,null);recordFailure(executable,error)}let getVersion=this.options.getVersion;if(getVersion){let inspected=await Promise.all(automaticCandidates.map(async(executable,index)=>{let[error,version]=await Promise.all([this.options.probe(executable),getVersion(executable).catch(()=>null)]);return{executable,error,index,version}})),usable=inspected.filter(candidate=>candidate.error===null);for(let candidate of inspected)candidate.error!==null&&recordFailure(candidate.executable,candidate.error);usable.sort((left,right)=>{if(left.version&&right.version&&this.options.compareVersions){let comparison=this.options.compareVersions(left.version,right.version);if(comparison!==0)return-comparison}else{if(left.version)return-1;if(right.version)return 1}return left.index-right.index});let selected=usable[0];if(selected)return select(selected.executable,selected.version)}else for(let executable of automaticCandidates){let error=await this.options.probe(executable);if(error===null)return select(executable,null);recordFailure(executable,error)}let detail=failures.map(({executable,error})=>{let compactError=error.replace(/\s+/g," ").trim().slice(0,300);return`${executable}: ${compactError}`}).join("; ");return{executable:null,error:`${this.options.unusableError} ${detail}`}}}}});import fs7 from"node:fs";import os3 from"node:os";import path7 from"node:path";import readline from"node:readline";import{spawn as spawn9}from"node:child_process";function configOverride(value){return Array.isArray(value)?value.map(configOverride):value&&typeof value=="object"?Object.fromEntries(Object.entries(value).filter(([,field])=>field!=null).map(([key,field])=>[key,configOverride(field)])):value}function normalizeCodexVersion(value){return typeof value!="string"||value.length>MAX_VERSION_OUTPUT_CHARS?null:CODEX_VERSION_PATTERN.exec(value.trim())?.[1]??null}function parsedCodexVersion(value){let normalized=normalizeCodexVersion(value);if(!normalized)return null;let withoutBuild=normalized.split("+",1)[0],prereleaseSeparator=withoutBuild.indexOf("-"),coreValue=prereleaseSeparator===-1?withoutBuild:withoutBuild.slice(0,prereleaseSeparator),prereleaseValue=prereleaseSeparator===-1?void 0:withoutBuild.slice(prereleaseSeparator+1),core=coreValue?.split(".").map(Number);return core?.length!==3||core.some(component=>!Number.isSafeInteger(component)||component<0)?null:{core,prerelease:prereleaseValue?prereleaseValue.split("."):[]}}function compareCodexVersions(leftValue,rightValue){let left=parsedCodexVersion(leftValue),right=parsedCodexVersion(rightValue);if(!left||!right)return leftValue.localeCompare(rightValue,void 0,{numeric:!0});for(let index=0;index<left.core.length;index+=1){let difference=left.core[index]-right.core[index];if(difference!==0)return difference}if(left.prerelease.length===0||right.prerelease.length===0)return left.prerelease.length===right.prerelease.length?0:left.prerelease.length===0?1:-1;let identifierCount=Math.max(left.prerelease.length,right.prerelease.length);for(let index=0;index<identifierCount;index+=1){let leftIdentifier=left.prerelease[index],rightIdentifier=right.prerelease[index];if(leftIdentifier===void 0||rightIdentifier===void 0)return leftIdentifier===rightIdentifier?0:leftIdentifier===void 0?-1:1;if(leftIdentifier===rightIdentifier)continue;let leftNumeric=/^\d+$/.test(leftIdentifier),rightNumeric=/^\d+$/.test(rightIdentifier);return leftNumeric&&rightNumeric?Number(leftIdentifier)-Number(rightIdentifier):leftNumeric!==rightNumeric?leftNumeric?-1:1:leftIdentifier.localeCompare(rightIdentifier)}return 0}function codexAppExecutableCandidatePaths(options={}){let env=options.env??process.env,home=(options.homedir??os3.homedir)(),platform=options.platform??process.platform;return platform==="darwin"?["/Applications",path7.join(home,"Applications")].flatMap(root=>["ChatGPT.app","Codex.app"].flatMap(app=>{let resources=path7.join(root,app,"Contents","Resources");return[path7.join(resources,"codex-cli","CodexCLI.app","Contents","MacOS","codex"),path7.join(resources,"codex")]})):platform==="win32"?[path7.join(env.LOCALAPPDATA||path7.join(home,"AppData","Local"),"Programs"),env.ProgramFiles,env["ProgramFiles(x86)"]].filter(root=>typeof root=="string"&&root.length>0).flatMap(root=>["ChatGPT","Codex"].map(app=>path7.join(root,app,"resources","codex.exe"))):[]}function isIdeBundledCodexPath(candidate,home){let resolvedCandidates=[path7.resolve(candidate)];try{resolvedCandidates.push(fs7.realpathSync(candidate))}catch{}return[".vscode",".vscode-insiders",".cursor",".windsurf"].some(directory=>{let extensionsRoot=`${path7.join(home,directory,"extensions")}${path7.sep}`;return resolvedCandidates.some(resolved=>resolved.startsWith(extensionsRoot))})}function codexExecutableCandidatePaths(options={}){let env=options.env??process.env,home=(options.homedir??os3.homedir)(),platform=options.platform??process.platform;return agentExecutableCandidatePaths({executableNames:[platform==="win32"?"codex.cmd":"codex"],configuredPath:env.MEARL_CODEX_PATH,env,home,platform,processExecPath:options.processExecPath,readdirSync:options.readdirSync,extraUserCandidates:codexAppExecutableCandidatePaths({env,homedir:()=>home,platform})}).filter(candidate=>candidate===env.MEARL_CODEX_PATH||!isIdeBundledCodexPath(candidate,home))}function codexPackageVersion(executable){let packageFiles=[];try{let resolved=fs7.realpathSync(executable);if(resolved.split(path7.sep).includes("node_modules")){let directory=path7.dirname(resolved);for(let depth=0;depth<6;depth+=1){packageFiles.push(path7.join(directory,"package.json"));let parent=path7.dirname(directory);if(parent===directory)break;directory=parent}}}catch{}/\.(?:cmd|bat)$/i.test(executable)&&packageFiles.push(path7.join(path7.dirname(executable),"node_modules","@openai","codex","package.json"));for(let packageFile of packageFiles)try{let manifest=JSON.parse(fs7.readFileSync(packageFile,"utf8"));if(manifest.name==="@openai/codex"){let version=normalizeCodexVersion(manifest.version);if(version)return version}}catch{}return null}function codexExecutableVersion(executable){let packageVersion=codexPackageVersion(executable);return packageVersion?Promise.resolve(packageVersion):new Promise(resolve6=>{let settled=!1,output="",launch=resolveSpawnCommand(executable,["--version"]),child=spawn9(launch.command,launch.args,{stdio:["ignore","pipe","pipe"],windowsHide:!0,env:prependNodePath()}),finish=version=>{settled||(settled=!0,clearTimeout(timer),resolve6(version))},capture=chunk=>{let remaining=MAX_VERSION_OUTPUT_CHARS-output.length;remaining>0&&(output+=chunk.toString("utf8").slice(0,remaining))};child.stdout.on("data",capture),child.stderr.on("data",capture),child.once("error",()=>finish(null)),child.once("exit",code=>finish(code===0?normalizeCodexVersion(output):null));let timer=setTimeout(()=>{child.kill("SIGTERM"),finish(null)},PROBE_TIMEOUT_MS)})}function codexModelInfo(value){if(typeof value!="string")return;let id=value.trim().slice(0,MAX_MODEL_CHARS);return id?{id}:void 0}function fullAccessWithApprovals(){return{sandbox:"danger-full-access",approvalPolicy:"untrusted"}}function timestampMs(value){if(typeof value=="number"&&Number.isFinite(value))return value<1e12?value*1e3:value;if(typeof value=="string"){let parsed=Date.parse(value);return Number.isNaN(parsed)?void 0:parsed}}function codexSkillScope(value){return value==="user"?"global":value==="repo"?"project":value==="system"||value==="admin"?value:"unknown"}function userMessageText(item){return Array.isArray(item?.content)?item.content.flatMap(part=>part?.type==="text"&&typeof part.text=="string"?[part.text]:[]).join(`
|
|
970
|
-
`):""}function userMessageImageCount(item){return Array.isArray(item?.content)?item.content.filter(part=>part?.type==="image"||part?.type==="localImage").length:0}function threadHistoryEvents(thread){if(!Array.isArray(thread?.turns))return[];let events=[];for(let turn of thread.turns.slice(-100)){if(!turn||typeof turn.id!="string"||!Array.isArray(turn.items))continue;let timestamp=timestampMs(turn.completedAt??turn.startedAt);for(let item of turn.items)if(!(!item||typeof item.id!="string"||typeof item.type!="string")){if(item.type==="userMessage"){let text2=userMessageText(item),imageCount=userMessageImageCount(item);(text2||imageCount>0)&&events.push({kind:"lifecycle",method:"chat/userMessage",params:{text:text2,...imageCount>0?{imageCount}:{}},...timestamp!==void 0?{timestamp}:{}});continue}events.push({kind:"notification",method:"item/completed",params:{turnId:turn.id,item},...timestamp!==void 0?{timestamp}:{}})}}return events}function codexThreadUrl(providerSessionId){if(!/^[a-zA-Z0-9_-]+$/.test(providerSessionId))throw new Error("Codex returned an invalid thread id");return`codex://threads/${providerSessionId}`}function codexWorkspaceUrl(directory){return`codex://threads/new?path=${encodeURIComponent(directory)}`}function externalOpenCommand(url,platform=process.platform){return platform==="darwin"?{command:"open",args:[url]}:platform==="win32"?{command:"cmd.exe",args:["/d","/s","/c","start","",url]}:{command:"xdg-open",args:[url]}}function openExternalUrl(url){let{command,args}=externalOpenCommand(url);return new Promise((resolve6,reject)=>{let child=spawn9(command,args,{stdio:"ignore",windowsHide:!0});child.once("error",error=>{reject(new Error(`Unable to open Codex App: ${error.message}`))}),child.once("close",code=>{code===0?resolve6():reject(new Error("Unable to open Codex App. Make sure it is installed."))})})}var REQUEST_TIMEOUT_MS,PROBE_TIMEOUT_MS,MAX_MODEL_CHARS,MAX_VERSION_OUTPUT_CHARS,CODEX_NOT_FOUND_ERROR,CODEX_VERSION_PATTERN,CodexAgentProvider,init_codex_provider=__esm({"../agent-runtime/dist/codex-provider.js"(){"use strict";init_executable_resolver();init_process_env();REQUEST_TIMEOUT_MS=3e4,PROBE_TIMEOUT_MS=5e3,MAX_MODEL_CHARS=256,MAX_VERSION_OUTPUT_CHARS=1024,CODEX_NOT_FOUND_ERROR="Codex was not found. Install @openai/codex, install the Codex App, or set MEARL_CODEX_PATH.",CODEX_VERSION_PATTERN=/^(?:codex-cli\s+)?v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)$/;CodexAgentProvider=class{log;clientVersion;mearlSocketPath;id="codex";process=null;initialized=!1;lifecycle=0;modelRuntime;startPromise=null;nextRequestId=1;pendingRequests=new Map;listeners=new Set;knownThreadIds=new Set;sessionModels=new Map;executableResolver;constructor(log,clientVersion,mearlSocketPath){this.log=log,this.clientVersion=clientVersion,this.mearlSocketPath=mearlSocketPath,this.executableResolver=new AgentExecutableResolver({candidates:()=>this.resolveExecutableCandidates(),probe:executable=>this.probeExecutable(executable),getVersion:executable=>this.readExecutableVersion(executable),compareVersions:compareCodexVersions,preferred:executable=>executable===process.env.MEARL_CODEX_PATH,notFoundError:CODEX_NOT_FOUND_ERROR,unusableError:"Codex candidates were found, but none supports app-server.",onFailure:(executable,error)=>{this.log("[Codex] Skipping unusable runtime:",executable,error)},onSelection:(executable,version)=>{this.modelRuntime={executable,...version?{version}:{},selection:executable===process.env.MEARL_CODEX_PATH?"explicit":"automatic",started:!1},this.modelDiagnostic({runtime:this.modelRuntime}),this.log("[Codex] Selected runtime:",executable,version?`(version ${version})`:executable===process.env.MEARL_CODEX_PATH?"(explicitly configured)":"(version unavailable)")}})}async getDescriptor(){let{error}=await this.resolveExecutable();return{id:this.id,name:"Codex",available:error===null,capabilities:{streaming:!0,resume:!0,listSessions:!0,refreshHistory:!0,imageInput:!0,interrupt:!0,requests:!0},...error?{error}:{},setup:{installCommand:"npm install -g @openai/codex",loginCommand:"codex login",docsUrl:"https://developers.openai.com/codex/cli"}}}async prepare(){await this.ensureStarted()}async listModels(){await this.ensureStarted();let models=new Map,cursor,cursors=new Set;for(let page=0;page<4;page++){let result=await this.request("model/list",{limit:100,...cursor?{cursor}:{}});if(!Array.isArray(result?.data))throw new Error("Invalid Codex model list");for(let value of result.data){let id=value?.model??value?.id;if(value?.hidden||typeof id!="string"||!id||id.length>256||models.has(id))continue;let efforts=["none","minimal","low","medium","high","xhigh","max"],reasoningEfforts=Array.isArray(value.supportedReasoningEfforts)?efforts.filter(effort=>value.supportedReasoningEfforts.some(option=>option?.reasoningEffort===effort)):void 0;if(models.set(id,{id,displayName:typeof value.displayName=="string"?value.displayName.slice(0,256):id,...typeof value.description=="string"?{description:value.description.slice(0,2e3)}:{},isDefault:value.isDefault===!0,...reasoningEfforts?{reasoningEfforts}:{},...efforts.includes(value.defaultReasoningEffort)?{defaultReasoningEffort:value.defaultReasoningEffort}:{}}),models.size>=200)break}if(!result.nextCursor||models.size>=200)break;if(typeof result.nextCursor!="string"||cursors.has(result.nextCursor))throw new Error("Invalid Codex model cursor");cursor=result.nextCursor,cursors.add(result.nextCursor)}return[...models.values()]}onEvent(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}async listSessions(options){await this.ensureStarted();let result=await this.request("thread/list",{cursor:options.cursor??null,limit:options.limit,sortKey:"updated_at",sortDirection:"desc",archived:!1,...options.cwd?{cwd:options.cwd}:{}});return{sessions:Array.isArray(result?.data)?result.data.flatMap(thread=>{if(!thread||typeof thread.id!="string")return[];let title=typeof thread.name=="string"&&thread.name.trim()?thread.name.trim():typeof thread.preview=="string"&&thread.preview.trim()?thread.preview.trim():void 0,cwd=typeof thread.cwd=="string"?thread.cwd:void 0,updatedAt=timestampMs(thread.recencyAt??thread.updatedAt),ephemeral=typeof thread.ephemeral=="boolean"?thread.ephemeral:void 0;return[{providerSessionId:thread.id,...title?{title}:{},...cwd?{cwd}:{},...updatedAt!==void 0?{updatedAt}:{},...ephemeral!==void 0?{ephemeral}:{}}]}):[],...typeof result?.nextCursor=="string"?{nextCursor:result.nextCursor}:{}}}async listSkills(cwd){await this.ensureStarted();let result=await this.request("skills/list",{cwds:[cwd||os3.homedir()],forceReload:!0});return Array.isArray(result?.data)?result.data.flatMap(entry=>Array.isArray(entry?.skills)?entry.skills.flatMap(skill=>!skill||typeof skill.name!="string"||typeof skill.path!="string"?[]:[{name:skill.name,path:skill.path,scope:codexSkillScope(skill.scope)}]):[]):[]}async startSession(options){await this.ensureStarted();let cwd=options.cwd||process.env.MEARL_AGENT_CWD||os3.homedir(),config=options.modelExecution?await this.modelExecutionConfig():void 0,result=await this.request("thread/start",{...config?{config}:{},cwd,...options.modelId?{model:options.modelId}:{},...options.readOnly?{sandbox:"read-only",approvalPolicy:"never"}:fullAccessWithApprovals(),...options.ephemeral!==void 0?{ephemeral:options.ephemeral}:{},...options.developerInstructions?{developerInstructions:options.developerInstructions}:{}}),threadId=result?.thread?.id;if(typeof threadId!="string"||!threadId)throw new Error("Codex did not return a thread id");options.modelExecution&&this.modelDiagnostic({threadRestrictionsAccepted:!0}),this.knownThreadIds.add(threadId);let model=codexModelInfo(result?.model);return model&&this.sessionModels.set(threadId,model),threadId}async modelExecutionConfig(){let config=(await this.request("config/read",{includeLayers:!1}))?.config;if(!config||typeof config!="object")throw new Error("Codex cannot report its effective execution configuration");let home=process.env.CODEX_HOME||path7.join(os3.homedir(),".codex"),store=config.cli_auth_credentials_store;this.modelDiagnostic({configuration:{source:process.env.CODEX_HOME?"environment":"default",home,filePresent:fs7.existsSync(path7.join(home,"config.toml")),...typeof config.model_provider=="string"?{baseProvider:config.model_provider}:{},...typeof store=="string"?{credentialStore:["file","keyring","auto","ephemeral"].includes(store)?store:"unknown"}:{}}});let mcp=config.mcp_servers??{},apps=config.apps??{};if(typeof mcp!="object"||Array.isArray(mcp)||typeof apps!="object"||Array.isArray(apps))throw new Error("Invalid Codex model tool configuration");return configOverride({mcp_servers:Object.fromEntries(Object.keys(mcp).map(name=>[name,{...mcp[name],enabled:!1}])),apps:Object.fromEntries(["_default",...Object.keys(apps)].map(name=>[name,{...apps[name]??{},enabled:!1}])),web_search:"disabled",features:{apps:!1,plugins:!1,hooks:!1,codex_hooks:!1,plugin_hooks:!1,multi_agent:!1,multi_agent_v2:!1,collab:!1,computer_use:!1,browser_use:!1,image_generation:!1,imagegenext:!1,memory_tool:!1,memories:!1,skill_search:!1}})}async resumeSession(providerSessionId,options){await this.ensureStarted();let result=await this.request("thread/resume",{threadId:providerSessionId,...options.cwd?{cwd:options.cwd}:{},...fullAccessWithApprovals(),...options.developerInstructions?{developerInstructions:options.developerInstructions}:{}}),threadId=result?.thread?.id;if(typeof threadId!="string"||!threadId)throw new Error("Codex did not return a resumed thread id");this.knownThreadIds.add(threadId);let model=codexModelInfo(result?.model);return model&&this.sessionModels.set(threadId,model),{providerSessionId:threadId,history:threadHistoryEvents(result.thread),historyComplete:!0}}getSessionModel(providerSessionId){let model=this.sessionModels.get(providerSessionId);return model?{...model}:void 0}async sendMessage(providerSessionId,message,images=[],options={}){await this.ensureStarted();let turnId=(await this.request("turn/start",{threadId:providerSessionId,input:[...message?[{type:"text",text:message,text_elements:[]}]:[],...images.map(image=>({type:"image",url:`data:${image.mimeType};base64,${image.data}`}))],summary:options.reasoningSummary??"detailed",...options.outputSchema?{outputSchema:options.outputSchema}:{},...options.modelExecution?{approvalPolicy:"never",sandboxPolicy:{type:"readOnly",networkAccess:!1}}:{},...options.reasoningEffort?{effort:options.reasoningEffort}:{}}))?.turn?.id;if(typeof turnId!="string"||!turnId)throw new Error("Codex did not return a turn id");return options.modelExecution&&this.modelDiagnostic({turnRestrictionsAccepted:!0}),{turnId}}async interrupt(providerSessionId,turnId){await this.ensureStarted(),await this.request("turn/interrupt",{threadId:providerSessionId,turnId})}async closeSession(providerSessionId){this.knownThreadIds.delete(providerSessionId),this.sessionModels.delete(providerSessionId),this.initialized&&this.request("thread/unsubscribe",{threadId:providerSessionId}).catch(error=>{this.log("[Codex] Unable to unsubscribe thread:",String(error))})}openSession(providerSessionId){return openExternalUrl(codexThreadUrl(providerSessionId))}openWorkspace(cwd){return openExternalUrl(codexWorkspaceUrl(cwd))}respondToRequest(requestId,result){this.write({id:requestId,result})}dispose(){this.lifecycle++,this.rejectPending(new Error("Codex provider disposed"));let child=this.process;this.process=null,this.initialized=!1,this.startPromise=null,this.sessionModels.clear(),this.executableResolver.reset(),child&&!child.killed&&child.kill("SIGTERM")}async ensureStarted(){if(this.process&&!this.process.killed&&this.initialized)return;if(this.startPromise)return this.startPromise;this.process&&!this.process.killed&&(this.process.kill("SIGTERM"),this.process=null);let pending2=this.start();this.startPromise=pending2;try{await pending2}catch(error){throw this.startPromise===pending2&&(this.startPromise=null),error}}async start(){let lifecycle=this.lifecycle,resolution=await this.resolveExecutable();if(lifecycle!==this.lifecycle)throw new Error("Codex provider disposed during startup");if(resolution.executable===null)throw new Error(resolution.error);let{executable}=resolution,launch=resolveSpawnCommand(executable,["app-server","--listen","stdio://"]),childEnv=prependNodePath();this.mearlSocketPath&&(childEnv.MEARL_SOCKET_PATH=this.mearlSocketPath);let child=spawn9(launch.command,launch.args,{stdio:["pipe","pipe","pipe"],windowsHide:!0,env:childEnv});this.process=child,readline.createInterface({input:child.stdout}).on("line",line=>this.handleLine(line)),child.stderr.on("data",chunk=>{let message=chunk.toString("utf8").trim();message&&this.log("[Codex]",message)}),child.once("error",error=>this.handleExit(child,error)),child.once("exit",(code,signal)=>{this.handleExit(child,new Error(`Codex app-server exited (code=${String(code)}, signal=${String(signal)})`))});try{await this.request("initialize",{clientInfo:{name:"mearl",title:"Mearl",version:this.clientVersion},capabilities:{experimentalApi:!0}}),this.write({method:"initialized",params:{}}),this.initialized=!0,this.modelRuntime&&(this.modelRuntime={...this.modelRuntime,started:!0},this.modelDiagnostic({runtime:this.modelRuntime}))}catch(error){let startupError=error instanceof Error?error:new Error(String(error));throw this.handleExit(child,startupError),child.killed||child.kill("SIGTERM"),startupError}}handleLine(line){let message;try{message=JSON.parse(line)}catch{this.log("[Codex] Invalid JSONL message:",line);return}if(message.method){let isRequest=message.id!==void 0,providerSessionId=this.extractThreadId(message.params);if(!isRequest&&providerSessionId&&message.method==="thread/settings/updated"){let model=codexModelInfo(message.params?.threadSettings?.model);model&&(this.sessionModels.set(providerSessionId,model),this.emit({providerSessionId,kind:"notification",method:"session/model/updated",params:{model}}))}else if(!isRequest&&providerSessionId&&message.method==="model/rerouted"){let model=codexModelInfo(message.params?.toModel);model&&this.emit({providerSessionId,kind:"notification",method:"session/activeModel/updated",params:{model}})}this.emit({providerSessionId,kind:isRequest?"request":message.method==="error"?"error":"notification",method:message.method,params:message.params??{},...isRequest?{requestId:message.id}:{}});return}if(typeof message.id!="number")return;let pending2=this.pendingRequests.get(message.id);pending2&&(clearTimeout(pending2.timer),this.pendingRequests.delete(message.id),message.error?pending2.reject(new Error(message.error.message||`Codex error ${message.error.code??""}`)):pending2.resolve(message.result))}request(method,params){let id=this.nextRequestId++;return new Promise((resolve6,reject)=>{let timer=setTimeout(()=>{this.pendingRequests.delete(id),reject(new Error(`Codex request timed out: ${method}`))},REQUEST_TIMEOUT_MS);this.pendingRequests.set(id,{resolve:resolve6,reject,timer});try{this.write({id,method,params})}catch(error){clearTimeout(timer),this.pendingRequests.delete(id),reject(error instanceof Error?error:new Error(String(error)))}})}write(message){let child=this.process;if(!child||child.killed||!child.stdin.writable)throw new Error("Codex app-server is not running");child.stdin.write(`${JSON.stringify(message)}
|
|
969
|
+
`)},run(positionals,payload,namedInput={}){return run2(positionals,payload,namedInput)},runRuntime(invocation){return run2([],invocation,{},"runtime")},runRecovery(invocation){return run2([],invocation,{},"recovery")},runMigration(invocation){return run2([],invocation,{},"migration")},runToolbox(invocation){return run2([],invocation,{},!0)}}}async function loadRegisteredPluginWithState(name,context,options={},state={stack:[]}){if(state.stack.includes(name))throw new PluginError("PLUGIN_INVOCATION_CYCLE",`插件调用形成循环: ${[...state.stack,name].join(" -> ")}`);let registration=context.resolveRegistration?context.resolveRegistration(name):findPluginRegistration(name);if(!registration&&findOfficialPlugin(name)&&(await(context.ensurePlugin??ensureOfficialPluginRegistered)(name,options.onProgress?message=>options.onProgress?.(message):void 0),registration=findPluginRegistration(name)),!registration)throw new PluginError("PLUGIN_NOT_REGISTERED",`插件未注册: ${name}`);let{onProgress,signal,source,...invokeOptions}=options,childState={stack:[...state.stack,name]},activeInvocation;return loadPlugin(registration.entry,{options:invokeOptions,source:source??context.source,parentInvocation:context.parentInvocation,invocation:context.invocation,signal,runModel:context.runModel,onInvocation:identity=>{activeInvocation=identity},progress:onProgress??(()=>{}),async invoke(action,payload,overrides,progress){let nestedOptions={...invokeOptions,...overrides};if(COMMAND_MAP.has(action)||action==="connector_list"){let result2=await context.invoke(action,payload,nestedOptions);if(result2?.action?.success===!1)throw new Error(result2.action.error||`${action} failed`);return result2}let pluginInvocation=isPluginInvocation(payload);if(findPluginRegistration(action)||findOfficialPlugin(action)||pluginInvocation){if(!pluginInvocation)throw new PluginError("PLUGIN_INVALID_INPUT",`调用插件 ${action} 需要 {"command":"...","input":{...}}`);return activeInvocation?.taskId?(!findPluginRegistration(action)&&findOfficialPlugin(action)&&await(context.ensurePlugin??ensureOfficialPluginRegistered)(action),context.invoke("plugin_invoke_child",{plugin:action,invocation:payload},nestedOptions)):invokeRegisteredPluginWithState(action,payload,{...context,invocation:void 0,parentInvocation:activeInvocation},{...nestedOptions,...onProgress?{onProgress}:{},...signal?{signal}:{},...source?{source}:{}},childState)}let result=await(progress?context.invoke(action,payload,nestedOptions,progress):context.invoke(action,payload,nestedOptions));if(result?.action?.success===!1)throw new Error(result.action.error||`${action} failed`);return result}},name)}async function invokeRegisteredPluginWithState(name,invocation,context,options={},state={stack:[]}){return(await loadRegisteredPluginWithState(name,context,options,state)).run([],invocation)}function invokeRegisteredPlugin(name,invocation,context,options={}){return invokeRegisteredPluginWithState(name,invocation,context,options)}async function invokeRegisteredToolboxPlugin(name,invocation,context,options={}){return(await loadRegisteredPluginWithState(name,context,options)).runToolbox(invocation)}async function invokeRegisteredRuntimePlugin(name,invocation,context,options={}){return(await loadRegisteredPluginWithState(name,context,options)).runRuntime(invocation)}async function invokeRegisteredRecoveryPlugin(name,invocation,context,options={}){return(await loadRegisteredPluginWithState(name,context,options)).runRecovery(invocation)}var init_plugin=__esm({"../client/src/plugins/sdk/plugin.ts"(){"use strict";init_pluginStateDefinition();init_pluginRecoveryDefinition();init_pluginPageDefinition();init_pluginAppProfiles();init_pageEvalArguments();init_skillManifest();init_esm();init_commands();init_officialPluginCatalog();init_officialPluginInstaller();init_pluginRegistry();init_pluginSource();init_pythonPlugin();init_pluginExecution();init_pluginExecutor();init_pluginTasks();init_pluginRuntimeCleanup();init_pluginPages();init_pluginRegistry();init_officialPluginCatalog();init_pluginState();init_pluginModels()}});var init_process_env=__esm({"../agent-runtime/dist/process-env.js"(){"use strict";init_dist()}});import fs5 from"node:fs";import{spawn as spawn8}from"node:child_process";import path5 from"node:path";function agentExecutableCandidatePaths({executableNames,configuredPath,env=process.env,extraUserCandidates=[],home,platform=process.platform,processExecPath=process.execPath,readdirSync:readdirSync6}){let pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",pathCandidates=(env[pathKey]||"").split(path5.delimiter).filter(Boolean).flatMap(directory=>executableNames.map(name=>path5.join(directory,name))),commonUserDirectories=[path5.join(home,".local","bin"),path5.join(home,".npm-global","bin"),path5.join(home,".volta","bin"),path5.join(home,".local","share","pnpm"),path5.join(home,"Library","pnpm"),path5.join(home,".bun","bin"),...platform==="win32"&&env.APPDATA?[path5.join(env.APPDATA,"npm")]:[]],systemDirectories=platform==="win32"?[]:["/opt/homebrew/bin","/usr/local/bin","/usr/bin"];return[configuredPath,...executableNames.map(name=>path5.join(path5.dirname(processExecPath),name)),...commonUserDirectories.flatMap(directory=>executableNames.map(name=>path5.join(directory,name))),...extraUserCandidates,...versionManagerExecutableCandidates(home,executableNames,{env,platform,readdirSync:readdirSync6}),...systemDirectories.flatMap(directory=>executableNames.map(name=>path5.join(directory,name))),...pathCandidates].filter(candidate=>typeof candidate=="string")}function executableFileCandidates(candidates){let seen=new Set,executableCandidates=[];for(let candidate of candidates)!candidate||seen.has(candidate)||(seen.add(candidate),isExecutableFile(candidate)&&executableCandidates.push(candidate));return executableCandidates}function probeAgentExecutable(executable,options){return new Promise(resolve6=>{let settled=!1,stderr="",launch=resolveSpawnCommand(executable,options.args),child=spawn8(launch.command,launch.args,{stdio:["ignore","ignore","pipe"],windowsHide:!0,env:prependNodePath()}),finish=error=>{settled||(settled=!0,clearTimeout(timer),resolve6(error))},timer=setTimeout(()=>{child.kill("SIGTERM"),finish(options.timeoutError)},options.timeoutMs);child.stderr?.on("data",chunk=>{stderr.length<4e3&&(stderr+=chunk.toString("utf8"))}),child.once("error",error=>finish(options.startError(error))),child.once("exit",code=>{if(code===0){finish(null);return}finish(stderr.trim()||options.exitError(code))})})}function isExecutableFile(candidate){try{return fs5.accessSync(candidate,process.platform==="win32"?fs5.constants.F_OK:fs5.constants.X_OK),fs5.statSync(candidate).isFile()}catch{return!1}}var AgentExecutableResolver,init_executable_resolver=__esm({"../agent-runtime/dist/executable-resolver.js"(){"use strict";init_process_env();AgentExecutableResolver=class{options;resolvedExecutable=null;resolutionPromise=null;generation=0;constructor(options){this.options=options}async resolve(){if(this.resolvedExecutable){if(isExecutableFile(this.resolvedExecutable))return{executable:this.resolvedExecutable,error:null};this.resolvedExecutable=null}if(this.resolutionPromise)return this.resolutionPromise;let generation=this.generation,resolution=this.probeCandidates(generation);this.resolutionPromise=resolution;try{return await resolution}finally{this.resolutionPromise===resolution&&(this.resolutionPromise=null)}}reset(){this.generation+=1,this.resolvedExecutable=null,this.resolutionPromise=null}async probeCandidates(generation){let candidates=this.options.candidates();if(candidates.length===0)return{executable:null,error:this.options.notFoundError};let failures=[],recordFailure=(executable,error)=>{failures.push({executable,error}),this.options.onFailure?.(executable,error)},select=(executable,version)=>(this.generation===generation&&(this.resolvedExecutable=executable,this.options.onSelection?.(executable,version)),{executable,error:null}),preferredCandidates=this.options.preferred?candidates.filter(executable=>this.options.preferred?.(executable)):[],automaticCandidates=candidates.filter(executable=>!preferredCandidates.includes(executable));for(let executable of preferredCandidates){let error=await this.options.probe(executable);if(error===null)return select(executable,null);recordFailure(executable,error)}let getVersion=this.options.getVersion;if(getVersion){let inspected=await Promise.all(automaticCandidates.map(async(executable,index)=>{let[error,version]=await Promise.all([this.options.probe(executable),getVersion(executable).catch(()=>null)]);return{executable,error,index,version}})),usable=inspected.filter(candidate=>candidate.error===null);for(let candidate of inspected)candidate.error!==null&&recordFailure(candidate.executable,candidate.error);usable.sort((left,right)=>{if(left.version&&right.version&&this.options.compareVersions){let comparison=this.options.compareVersions(left.version,right.version);if(comparison!==0)return-comparison}else{if(left.version)return-1;if(right.version)return 1}return left.index-right.index});let selected=usable[0];if(selected)return select(selected.executable,selected.version)}else for(let executable of automaticCandidates){let error=await this.options.probe(executable);if(error===null)return select(executable,null);recordFailure(executable,error)}let detail=failures.map(({executable,error})=>{let compactError=error.replace(/\s+/g," ").trim().slice(0,300);return`${executable}: ${compactError}`}).join("; ");return{executable:null,error:`${this.options.unusableError} ${detail}`}}}}});import fs6 from"node:fs";import os3 from"node:os";import path6 from"node:path";import readline from"node:readline";import{spawn as spawn9}from"node:child_process";function configOverride(value){return Array.isArray(value)?value.map(configOverride):value&&typeof value=="object"?Object.fromEntries(Object.entries(value).filter(([,field])=>field!=null).map(([key,field])=>[key,configOverride(field)])):value}function normalizeCodexVersion(value){return typeof value!="string"||value.length>MAX_VERSION_OUTPUT_CHARS?null:CODEX_VERSION_PATTERN.exec(value.trim())?.[1]??null}function parsedCodexVersion(value){let normalized=normalizeCodexVersion(value);if(!normalized)return null;let withoutBuild=normalized.split("+",1)[0],prereleaseSeparator=withoutBuild.indexOf("-"),coreValue=prereleaseSeparator===-1?withoutBuild:withoutBuild.slice(0,prereleaseSeparator),prereleaseValue=prereleaseSeparator===-1?void 0:withoutBuild.slice(prereleaseSeparator+1),core=coreValue?.split(".").map(Number);return core?.length!==3||core.some(component=>!Number.isSafeInteger(component)||component<0)?null:{core,prerelease:prereleaseValue?prereleaseValue.split("."):[]}}function compareCodexVersions(leftValue,rightValue){let left=parsedCodexVersion(leftValue),right=parsedCodexVersion(rightValue);if(!left||!right)return leftValue.localeCompare(rightValue,void 0,{numeric:!0});for(let index=0;index<left.core.length;index+=1){let difference=left.core[index]-right.core[index];if(difference!==0)return difference}if(left.prerelease.length===0||right.prerelease.length===0)return left.prerelease.length===right.prerelease.length?0:left.prerelease.length===0?1:-1;let identifierCount=Math.max(left.prerelease.length,right.prerelease.length);for(let index=0;index<identifierCount;index+=1){let leftIdentifier=left.prerelease[index],rightIdentifier=right.prerelease[index];if(leftIdentifier===void 0||rightIdentifier===void 0)return leftIdentifier===rightIdentifier?0:leftIdentifier===void 0?-1:1;if(leftIdentifier===rightIdentifier)continue;let leftNumeric=/^\d+$/.test(leftIdentifier),rightNumeric=/^\d+$/.test(rightIdentifier);return leftNumeric&&rightNumeric?Number(leftIdentifier)-Number(rightIdentifier):leftNumeric!==rightNumeric?leftNumeric?-1:1:leftIdentifier.localeCompare(rightIdentifier)}return 0}function codexAppExecutableCandidatePaths(options={}){let env=options.env??process.env,home=(options.homedir??os3.homedir)(),platform=options.platform??process.platform;return platform==="darwin"?["/Applications",path6.join(home,"Applications")].flatMap(root=>["ChatGPT.app","Codex.app"].flatMap(app=>{let resources=path6.join(root,app,"Contents","Resources");return[path6.join(resources,"codex-cli","CodexCLI.app","Contents","MacOS","codex"),path6.join(resources,"codex")]})):platform==="win32"?[path6.join(env.LOCALAPPDATA||path6.join(home,"AppData","Local"),"Programs"),env.ProgramFiles,env["ProgramFiles(x86)"]].filter(root=>typeof root=="string"&&root.length>0).flatMap(root=>["ChatGPT","Codex"].map(app=>path6.join(root,app,"resources","codex.exe"))):[]}function isIdeBundledCodexPath(candidate,home){let resolvedCandidates=[path6.resolve(candidate)];try{resolvedCandidates.push(fs6.realpathSync(candidate))}catch{}return[".vscode",".vscode-insiders",".cursor",".windsurf"].some(directory=>{let extensionsRoot=`${path6.join(home,directory,"extensions")}${path6.sep}`;return resolvedCandidates.some(resolved=>resolved.startsWith(extensionsRoot))})}function codexExecutableCandidatePaths(options={}){let env=options.env??process.env,home=(options.homedir??os3.homedir)(),platform=options.platform??process.platform;return agentExecutableCandidatePaths({executableNames:[platform==="win32"?"codex.cmd":"codex"],configuredPath:env.MEARL_CODEX_PATH,env,home,platform,processExecPath:options.processExecPath,readdirSync:options.readdirSync,extraUserCandidates:codexAppExecutableCandidatePaths({env,homedir:()=>home,platform})}).filter(candidate=>candidate===env.MEARL_CODEX_PATH||!isIdeBundledCodexPath(candidate,home))}function codexPackageVersion(executable){let packageFiles=[];try{let resolved=fs6.realpathSync(executable);if(resolved.split(path6.sep).includes("node_modules")){let directory=path6.dirname(resolved);for(let depth=0;depth<6;depth+=1){packageFiles.push(path6.join(directory,"package.json"));let parent=path6.dirname(directory);if(parent===directory)break;directory=parent}}}catch{}/\.(?:cmd|bat)$/i.test(executable)&&packageFiles.push(path6.join(path6.dirname(executable),"node_modules","@openai","codex","package.json"));for(let packageFile of packageFiles)try{let manifest=JSON.parse(fs6.readFileSync(packageFile,"utf8"));if(manifest.name==="@openai/codex"){let version=normalizeCodexVersion(manifest.version);if(version)return version}}catch{}return null}function codexExecutableVersion(executable){let packageVersion=codexPackageVersion(executable);return packageVersion?Promise.resolve(packageVersion):new Promise(resolve6=>{let settled=!1,output="",launch=resolveSpawnCommand(executable,["--version"]),child=spawn9(launch.command,launch.args,{stdio:["ignore","pipe","pipe"],windowsHide:!0,env:prependNodePath()}),finish=version=>{settled||(settled=!0,clearTimeout(timer),resolve6(version))},capture=chunk=>{let remaining=MAX_VERSION_OUTPUT_CHARS-output.length;remaining>0&&(output+=chunk.toString("utf8").slice(0,remaining))};child.stdout.on("data",capture),child.stderr.on("data",capture),child.once("error",()=>finish(null)),child.once("exit",code=>finish(code===0?normalizeCodexVersion(output):null));let timer=setTimeout(()=>{child.kill("SIGTERM"),finish(null)},PROBE_TIMEOUT_MS)})}function codexModelInfo(value){if(typeof value!="string")return;let id=value.trim().slice(0,MAX_MODEL_CHARS);return id?{id}:void 0}function fullAccessWithApprovals(){return{sandbox:"danger-full-access",approvalPolicy:"untrusted"}}function timestampMs(value){if(typeof value=="number"&&Number.isFinite(value))return value<1e12?value*1e3:value;if(typeof value=="string"){let parsed=Date.parse(value);return Number.isNaN(parsed)?void 0:parsed}}function codexSkillScope(value){return value==="user"?"global":value==="repo"?"project":value==="system"||value==="admin"?value:"unknown"}function userMessageText(item){return Array.isArray(item?.content)?item.content.flatMap(part=>part?.type==="text"&&typeof part.text=="string"?[part.text]:[]).join(`
|
|
970
|
+
`):""}function userMessageImageCount(item){return Array.isArray(item?.content)?item.content.filter(part=>part?.type==="image"||part?.type==="localImage").length:0}function threadHistoryEvents(thread){if(!Array.isArray(thread?.turns))return[];let events=[];for(let turn of thread.turns.slice(-100)){if(!turn||typeof turn.id!="string"||!Array.isArray(turn.items))continue;let timestamp=timestampMs(turn.completedAt??turn.startedAt);for(let item of turn.items)if(!(!item||typeof item.id!="string"||typeof item.type!="string")){if(item.type==="userMessage"){let text2=userMessageText(item),imageCount=userMessageImageCount(item);(text2||imageCount>0)&&events.push({kind:"lifecycle",method:"chat/userMessage",params:{text:text2,...imageCount>0?{imageCount}:{}},...timestamp!==void 0?{timestamp}:{}});continue}events.push({kind:"notification",method:"item/completed",params:{turnId:turn.id,item},...timestamp!==void 0?{timestamp}:{}})}}return events}function codexThreadUrl(providerSessionId){if(!/^[a-zA-Z0-9_-]+$/.test(providerSessionId))throw new Error("Codex returned an invalid thread id");return`codex://threads/${providerSessionId}`}function codexWorkspaceUrl(directory){return`codex://threads/new?path=${encodeURIComponent(directory)}`}function externalOpenCommand(url,platform=process.platform){return platform==="darwin"?{command:"open",args:[url]}:platform==="win32"?{command:"cmd.exe",args:["/d","/s","/c","start","",url]}:{command:"xdg-open",args:[url]}}function openExternalUrl(url){let{command,args}=externalOpenCommand(url);return new Promise((resolve6,reject)=>{let child=spawn9(command,args,{stdio:"ignore",windowsHide:!0});child.once("error",error=>{reject(new Error(`Unable to open Codex App: ${error.message}`))}),child.once("close",code=>{code===0?resolve6():reject(new Error("Unable to open Codex App. Make sure it is installed."))})})}var REQUEST_TIMEOUT_MS,PROBE_TIMEOUT_MS,MAX_MODEL_CHARS,MAX_VERSION_OUTPUT_CHARS,CODEX_NOT_FOUND_ERROR,CODEX_VERSION_PATTERN,CodexAgentProvider,init_codex_provider=__esm({"../agent-runtime/dist/codex-provider.js"(){"use strict";init_executable_resolver();init_process_env();REQUEST_TIMEOUT_MS=3e4,PROBE_TIMEOUT_MS=5e3,MAX_MODEL_CHARS=256,MAX_VERSION_OUTPUT_CHARS=1024,CODEX_NOT_FOUND_ERROR="Codex was not found. Install @openai/codex, install the Codex App, or set MEARL_CODEX_PATH.",CODEX_VERSION_PATTERN=/^(?:codex-cli\s+)?v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)$/;CodexAgentProvider=class{log;clientVersion;mearlSocketPath;id="codex";process=null;initialized=!1;lifecycle=0;modelRuntime;startPromise=null;nextRequestId=1;pendingRequests=new Map;listeners=new Set;knownThreadIds=new Set;sessionModels=new Map;executableResolver;constructor(log,clientVersion,mearlSocketPath){this.log=log,this.clientVersion=clientVersion,this.mearlSocketPath=mearlSocketPath,this.executableResolver=new AgentExecutableResolver({candidates:()=>this.resolveExecutableCandidates(),probe:executable=>this.probeExecutable(executable),getVersion:executable=>this.readExecutableVersion(executable),compareVersions:compareCodexVersions,preferred:executable=>executable===process.env.MEARL_CODEX_PATH,notFoundError:CODEX_NOT_FOUND_ERROR,unusableError:"Codex candidates were found, but none supports app-server.",onFailure:(executable,error)=>{this.log("[Codex] Skipping unusable runtime:",executable,error)},onSelection:(executable,version)=>{this.modelRuntime={executable,...version?{version}:{},selection:executable===process.env.MEARL_CODEX_PATH?"explicit":"automatic",started:!1},this.modelDiagnostic({runtime:this.modelRuntime}),this.log("[Codex] Selected runtime:",executable,version?`(version ${version})`:executable===process.env.MEARL_CODEX_PATH?"(explicitly configured)":"(version unavailable)")}})}async getDescriptor(){let{error}=await this.resolveExecutable();return{id:this.id,name:"Codex",available:error===null,capabilities:{streaming:!0,resume:!0,listSessions:!0,refreshHistory:!0,imageInput:!0,interrupt:!0,requests:!0},...error?{error}:{},setup:{installCommand:"npm install -g @openai/codex",loginCommand:"codex login",docsUrl:"https://developers.openai.com/codex/cli"}}}async prepare(){await this.ensureStarted()}async listModels(){await this.ensureStarted();let models=new Map,cursor,cursors=new Set;for(let page=0;page<4;page++){let result=await this.request("model/list",{limit:100,...cursor?{cursor}:{}});if(!Array.isArray(result?.data))throw new Error("Invalid Codex model list");for(let value of result.data){let id=value?.model??value?.id;if(value?.hidden||typeof id!="string"||!id||id.length>256||models.has(id))continue;let efforts=["none","minimal","low","medium","high","xhigh","max"],reasoningEfforts=Array.isArray(value.supportedReasoningEfforts)?efforts.filter(effort=>value.supportedReasoningEfforts.some(option=>option?.reasoningEffort===effort)):void 0;if(models.set(id,{id,displayName:typeof value.displayName=="string"?value.displayName.slice(0,256):id,...typeof value.description=="string"?{description:value.description.slice(0,2e3)}:{},isDefault:value.isDefault===!0,...reasoningEfforts?{reasoningEfforts}:{},...efforts.includes(value.defaultReasoningEffort)?{defaultReasoningEffort:value.defaultReasoningEffort}:{}}),models.size>=200)break}if(!result.nextCursor||models.size>=200)break;if(typeof result.nextCursor!="string"||cursors.has(result.nextCursor))throw new Error("Invalid Codex model cursor");cursor=result.nextCursor,cursors.add(result.nextCursor)}return[...models.values()]}onEvent(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}async listSessions(options){await this.ensureStarted();let result=await this.request("thread/list",{cursor:options.cursor??null,limit:options.limit,sortKey:"updated_at",sortDirection:"desc",archived:!1,...options.cwd?{cwd:options.cwd}:{}});return{sessions:Array.isArray(result?.data)?result.data.flatMap(thread=>{if(!thread||typeof thread.id!="string")return[];let title=typeof thread.name=="string"&&thread.name.trim()?thread.name.trim():typeof thread.preview=="string"&&thread.preview.trim()?thread.preview.trim():void 0,cwd=typeof thread.cwd=="string"?thread.cwd:void 0,updatedAt=timestampMs(thread.recencyAt??thread.updatedAt),ephemeral=typeof thread.ephemeral=="boolean"?thread.ephemeral:void 0;return[{providerSessionId:thread.id,...title?{title}:{},...cwd?{cwd}:{},...updatedAt!==void 0?{updatedAt}:{},...ephemeral!==void 0?{ephemeral}:{}}]}):[],...typeof result?.nextCursor=="string"?{nextCursor:result.nextCursor}:{}}}async listSkills(cwd){await this.ensureStarted();let result=await this.request("skills/list",{cwds:[cwd||os3.homedir()],forceReload:!0});return Array.isArray(result?.data)?result.data.flatMap(entry=>Array.isArray(entry?.skills)?entry.skills.flatMap(skill=>!skill||typeof skill.name!="string"||typeof skill.path!="string"?[]:[{name:skill.name,path:skill.path,scope:codexSkillScope(skill.scope)}]):[]):[]}async startSession(options){await this.ensureStarted();let cwd=options.cwd||process.env.MEARL_AGENT_CWD||os3.homedir(),config=options.modelExecution?await this.modelExecutionConfig():void 0,result=await this.request("thread/start",{...config?{config}:{},cwd,...options.modelId?{model:options.modelId}:{},...options.readOnly?{sandbox:"read-only",approvalPolicy:"never"}:fullAccessWithApprovals(),...options.ephemeral!==void 0?{ephemeral:options.ephemeral}:{},...options.developerInstructions?{developerInstructions:options.developerInstructions}:{}}),threadId=result?.thread?.id;if(typeof threadId!="string"||!threadId)throw new Error("Codex did not return a thread id");options.modelExecution&&this.modelDiagnostic({threadRestrictionsAccepted:!0}),this.knownThreadIds.add(threadId);let model=codexModelInfo(result?.model);return model&&this.sessionModels.set(threadId,model),threadId}async modelExecutionConfig(){let config=(await this.request("config/read",{includeLayers:!1}))?.config;if(!config||typeof config!="object")throw new Error("Codex cannot report its effective execution configuration");let home=process.env.CODEX_HOME||path6.join(os3.homedir(),".codex"),store=config.cli_auth_credentials_store;this.modelDiagnostic({configuration:{source:process.env.CODEX_HOME?"environment":"default",home,filePresent:fs6.existsSync(path6.join(home,"config.toml")),...typeof config.model_provider=="string"?{baseProvider:config.model_provider}:{},...typeof store=="string"?{credentialStore:["file","keyring","auto","ephemeral"].includes(store)?store:"unknown"}:{}}});let mcp=config.mcp_servers??{},apps=config.apps??{};if(typeof mcp!="object"||Array.isArray(mcp)||typeof apps!="object"||Array.isArray(apps))throw new Error("Invalid Codex model tool configuration");return configOverride({mcp_servers:Object.fromEntries(Object.keys(mcp).map(name=>[name,{...mcp[name],enabled:!1}])),apps:Object.fromEntries(["_default",...Object.keys(apps)].map(name=>[name,{...apps[name]??{},enabled:!1}])),web_search:"disabled",features:{apps:!1,plugins:!1,hooks:!1,codex_hooks:!1,plugin_hooks:!1,multi_agent:!1,multi_agent_v2:!1,collab:!1,computer_use:!1,browser_use:!1,image_generation:!1,imagegenext:!1,memory_tool:!1,memories:!1,skill_search:!1}})}async resumeSession(providerSessionId,options){await this.ensureStarted();let result=await this.request("thread/resume",{threadId:providerSessionId,...options.cwd?{cwd:options.cwd}:{},...fullAccessWithApprovals(),...options.developerInstructions?{developerInstructions:options.developerInstructions}:{}}),threadId=result?.thread?.id;if(typeof threadId!="string"||!threadId)throw new Error("Codex did not return a resumed thread id");this.knownThreadIds.add(threadId);let model=codexModelInfo(result?.model);return model&&this.sessionModels.set(threadId,model),{providerSessionId:threadId,history:threadHistoryEvents(result.thread),historyComplete:!0}}getSessionModel(providerSessionId){let model=this.sessionModels.get(providerSessionId);return model?{...model}:void 0}async sendMessage(providerSessionId,message,images=[],options={}){await this.ensureStarted();let turnId=(await this.request("turn/start",{threadId:providerSessionId,input:[...message?[{type:"text",text:message,text_elements:[]}]:[],...images.map(image=>({type:"image",url:`data:${image.mimeType};base64,${image.data}`}))],summary:options.reasoningSummary??"detailed",...options.outputSchema?{outputSchema:options.outputSchema}:{},...options.modelExecution?{approvalPolicy:"never",sandboxPolicy:{type:"readOnly",networkAccess:!1}}:{},...options.reasoningEffort?{effort:options.reasoningEffort}:{}}))?.turn?.id;if(typeof turnId!="string"||!turnId)throw new Error("Codex did not return a turn id");return options.modelExecution&&this.modelDiagnostic({turnRestrictionsAccepted:!0}),{turnId}}async interrupt(providerSessionId,turnId){await this.ensureStarted(),await this.request("turn/interrupt",{threadId:providerSessionId,turnId})}async closeSession(providerSessionId){this.knownThreadIds.delete(providerSessionId),this.sessionModels.delete(providerSessionId),this.initialized&&this.request("thread/unsubscribe",{threadId:providerSessionId}).catch(error=>{this.log("[Codex] Unable to unsubscribe thread:",String(error))})}openSession(providerSessionId){return openExternalUrl(codexThreadUrl(providerSessionId))}openWorkspace(cwd){return openExternalUrl(codexWorkspaceUrl(cwd))}respondToRequest(requestId,result){this.write({id:requestId,result})}dispose(){this.lifecycle++,this.rejectPending(new Error("Codex provider disposed"));let child=this.process;this.process=null,this.initialized=!1,this.startPromise=null,this.sessionModels.clear(),this.executableResolver.reset(),child&&!child.killed&&child.kill("SIGTERM")}async ensureStarted(){if(this.process&&!this.process.killed&&this.initialized)return;if(this.startPromise)return this.startPromise;this.process&&!this.process.killed&&(this.process.kill("SIGTERM"),this.process=null);let pending2=this.start();this.startPromise=pending2;try{await pending2}catch(error){throw this.startPromise===pending2&&(this.startPromise=null),error}}async start(){let lifecycle=this.lifecycle,resolution=await this.resolveExecutable();if(lifecycle!==this.lifecycle)throw new Error("Codex provider disposed during startup");if(resolution.executable===null)throw new Error(resolution.error);let{executable}=resolution,launch=resolveSpawnCommand(executable,["app-server","--listen","stdio://"]),childEnv=prependNodePath();this.mearlSocketPath&&(childEnv.MEARL_SOCKET_PATH=this.mearlSocketPath);let child=spawn9(launch.command,launch.args,{stdio:["pipe","pipe","pipe"],windowsHide:!0,env:childEnv});this.process=child,readline.createInterface({input:child.stdout}).on("line",line=>this.handleLine(line)),child.stderr.on("data",chunk=>{let message=chunk.toString("utf8").trim();message&&this.log("[Codex]",message)}),child.once("error",error=>this.handleExit(child,error)),child.once("exit",(code,signal)=>{this.handleExit(child,new Error(`Codex app-server exited (code=${String(code)}, signal=${String(signal)})`))});try{await this.request("initialize",{clientInfo:{name:"mearl",title:"Mearl",version:this.clientVersion},capabilities:{experimentalApi:!0}}),this.write({method:"initialized",params:{}}),this.initialized=!0,this.modelRuntime&&(this.modelRuntime={...this.modelRuntime,started:!0},this.modelDiagnostic({runtime:this.modelRuntime}))}catch(error){let startupError=error instanceof Error?error:new Error(String(error));throw this.handleExit(child,startupError),child.killed||child.kill("SIGTERM"),startupError}}handleLine(line){let message;try{message=JSON.parse(line)}catch{this.log("[Codex] Invalid JSONL message:",line);return}if(message.method){let isRequest=message.id!==void 0,providerSessionId=this.extractThreadId(message.params);if(!isRequest&&providerSessionId&&message.method==="thread/settings/updated"){let model=codexModelInfo(message.params?.threadSettings?.model);model&&(this.sessionModels.set(providerSessionId,model),this.emit({providerSessionId,kind:"notification",method:"session/model/updated",params:{model}}))}else if(!isRequest&&providerSessionId&&message.method==="model/rerouted"){let model=codexModelInfo(message.params?.toModel);model&&this.emit({providerSessionId,kind:"notification",method:"session/activeModel/updated",params:{model}})}this.emit({providerSessionId,kind:isRequest?"request":message.method==="error"?"error":"notification",method:message.method,params:message.params??{},...isRequest?{requestId:message.id}:{}});return}if(typeof message.id!="number")return;let pending2=this.pendingRequests.get(message.id);pending2&&(clearTimeout(pending2.timer),this.pendingRequests.delete(message.id),message.error?pending2.reject(new Error(message.error.message||`Codex error ${message.error.code??""}`)):pending2.resolve(message.result))}request(method,params){let id=this.nextRequestId++;return new Promise((resolve6,reject)=>{let timer=setTimeout(()=>{this.pendingRequests.delete(id),reject(new Error(`Codex request timed out: ${method}`))},REQUEST_TIMEOUT_MS);this.pendingRequests.set(id,{resolve:resolve6,reject,timer});try{this.write({id,method,params})}catch(error){clearTimeout(timer),this.pendingRequests.delete(id),reject(error instanceof Error?error:new Error(String(error)))}})}write(message){let child=this.process;if(!child||child.killed||!child.stdin.writable)throw new Error("Codex app-server is not running");child.stdin.write(`${JSON.stringify(message)}
|
|
971
971
|
`)}handleExit(child,error){if(this.process===child){this.process=null,this.initialized=!1,this.startPromise=null,this.executableResolver.reset(),this.rejectPending(error);for(let providerSessionId of this.knownThreadIds)this.emit({providerSessionId,kind:"error",method:"provider/exited",params:{message:error.message}})}}rejectPending(error){for(let[id,pending2]of this.pendingRequests)clearTimeout(pending2.timer),pending2.reject(error),this.pendingRequests.delete(id)}modelDiagnostic(metadata){this.emit({kind:"notification",method:"provider/model/diagnostic",params:metadata})}emit(event){for(let listener of this.listeners)listener(event)}extractThreadId(params){return[params?.threadId,params?.conversationId,params?.thread?.id,params?.turn?.threadId].find(value=>typeof value=="string")}probeExecutable(executable){return probeAgentExecutable(executable,{args:["app-server","--help"],timeoutMs:PROBE_TIMEOUT_MS,timeoutError:"Timed out while checking Codex app-server availability.",startError:error=>`Failed to start Codex: ${error.message}`,exitError:code=>`Codex app-server check exited with code ${String(code)}`})}readExecutableVersion(executable){return codexExecutableVersion(executable)}resolveExecutable(){return this.executableResolver.resolve()}resolveExecutableCandidates(){return executableFileCandidates(codexExecutableCandidatePaths())}}}});var CODEX_MODEL_CAPABILITY,init_capabilities=__esm({"../agent-runtime/dist/capabilities.js"(){"use strict";CODEX_MODEL_CAPABILITY={provider:"codex",modes:["agent"],permissions:["read-only"],structuredOutput:!0,streaming:!0,cancellation:!0}}});import{readFileSync as readFileSync12}from"node:fs";async function runCodexModel(request,context,provider=new CodexAgentProvider(()=>{},JSON.parse(readFileSync12(new URL("../package.json",import.meta.url),"utf8")).version)){if(request.provider!=="codex"||request.mode!=="agent"||request.permissions!=="read-only")throw Object.assign(new Error("Codex supports explicit read-only agent execution; strict tool-free generation is unavailable"),{code:"PLUGIN_MODEL_CAPABILITY_UNSUPPORTED"});context.signal.throwIfAborted();let session,turn,text2,bytes=0,index=0,retries=0,buffered="",streamItem,streamPhase,phases=new Map,flushTimer,flush=()=>{clearTimeout(flushTimer),flushTimer=void 0;try{for(let offset=0;offset<buffered.length;offset+=4e3)streamItem||streamPhase?context.onDelta(buffered.slice(offset,offset+4e3),++index,{...streamItem?{itemId:streamItem}:{},...streamPhase?{phase:streamPhase}:{}}):context.onDelta(buffered.slice(offset,offset+4e3),++index)}catch(error){fail(error)}buffered=""},finish,fail,completed2=new Promise((resolve6,reject)=>{finish=resolve6,fail=reject});completed2.catch(()=>{});let listener=event=>{let params=event.params;event.method==="provider/model/diagnostic"&&context.onDiagnostic?.(params),event.method==="account/updated"&&context.onDiagnostic?.({authentication:["apikey","chatgpt","chatgptAuthTokens"].includes(params?.authMode)?params.authMode:"unknown"}),event.method==="session/model/updated"&&typeof params?.model?.id=="string"&&context.onDiagnostic?.({selectedModel:params.model.id}),event.method==="session/activeModel/updated"&&typeof params?.model?.id=="string"&&context.onDiagnostic?.({activeModel:params.model.id});let relevant=event.providerSessionId===void 0||event.providerSessionId===session;if(event.kind==="request"&&relevant){try{provider.respondToRequest(event.requestId,{error:"Interactive requests are disabled for background model tasks"})}catch{}fail(Object.assign(new Error("Model requested interactive input"),{code:"PLUGIN_MODEL_INTERACTION_REQUIRED"})),provider.dispose();return}if((event.kind==="error"||event.method==="provider/exited")&&relevant){if(event.method!=="provider/exited"&¶ms?.willRetry===!0){context.onDiagnostic?.({retryCount:++retries});return}fail(Object.assign(new Error(String(params?.error?.message??params?.message??"Model provider failed")),{code:"PLUGIN_MODEL_PROVIDER_ERROR"})),provider.dispose();return}if(!(!session||event.providerSessionId!==session))if(event.method==="item/started"&¶ms?.item?.type==="agentMessage")flush(),streamItem=params.item.id,streamPhase=params.item.phase,streamItem&&streamPhase&&phases.set(streamItem,streamPhase);else if(event.method==="item/agentMessage/delta"&&typeof params?.delta=="string"){let itemId=params.itemId??streamItem,phase=params.phase??(itemId?phases.get(itemId):streamPhase);if((itemId!==streamItem||phase!==streamPhase)&&flush(),streamItem=itemId,streamPhase=phase,bytes+=Buffer.byteLength(params.delta),bytes>32*1024*1024){fail(new Error("Model output exceeds 32 MiB"));return}buffered+=params.delta,buffered.length>=16e3?flush():flushTimer??=setTimeout(flush,50)}else if(event.method==="item/completed"&¶ms?.item?.type==="agentMessage"&&typeof params.item.text=="string"){if(flush(),Buffer.byteLength(params.item.text)>32*1024*1024){fail(new Error("Model output exceeds 32 MiB"));return}(!params.item.phase||params.item.phase==="final_answer")&&(text2=params.item.text)}else event.method==="turn/completed"&&(params?.turn?.status!=="completed"?fail(Object.assign(new Error(`Model turn ended with ${String(params?.turn?.status)}${params?.turn?.error?.message?`: ${params.turn.error.message}`:""}`),{code:"PLUGIN_MODEL_TURN_FAILED"})):text2===void 0?fail(new Error("Model returned no final text")):(flush(),finish(text2)))},unsubscribe=provider.onEvent(listener),abort=()=>{fail(Object.assign(new Error("Model execution cancelled"),{code:"PLUGIN_EXECUTION_CANCELLED"})),session&&turn&&provider.interrupt(session,turn).catch(()=>{}),provider.dispose()};context.signal.addEventListener("abort",abort,{once:!0});try{session=context.conversation?.threadId??await provider.startSession({cwd:context.cwd,ephemeral:!0,readOnly:!0,modelExecution:!0,...request.model?{modelId:request.model}:{},...request.instructions?{developerInstructions:request.instructions}:{}}),context.conversation&&(context.conversation.threadId=session),context.onDiagnostic?.({...provider.getSessionModel(session)?.id?{selectedModel:provider.getSessionModel(session).id}:{}}),context.signal.throwIfAborted();let[,result]=await Promise.all([provider.sendMessage(session,request.prompt,[],{reasoningSummary:"none",reasoningEffort:request.reasoningEffort,outputSchema:request.outputSchema,modelExecution:!0}).then(value=>{turn=value.turnId}),completed2]);return context.signal.throwIfAborted(),{text:result,provider:request.provider,mode:request.mode,...provider.getSessionModel(session)?.id?{model:provider.getSessionModel(session).id}:{}}}catch(error){throw context.conversation&&(delete context.conversation.threadId,provider.dispose()),error}finally{clearTimeout(flushTimer),context.signal.removeEventListener("abort",abort),unsubscribe(),context.conversation||provider.dispose()}}var init_model=__esm({"../agent-runtime/dist/model.js"(){"use strict";init_codex_provider();init_capabilities()}});import{readFileSync as readFileSync13}from"node:fs";async function listCodexModels(signal,provider=new CodexAgentProvider(()=>{},JSON.parse(readFileSync13(new URL("../package.json",import.meta.url),"utf8")).version)){signal.throwIfAborted();let abort,cancelled=new Promise((_resolve,reject)=>{abort=()=>{provider.dispose(),reject(signal.reason??new Error("Model discovery cancelled"))},signal.addEventListener("abort",abort,{once:!0})});try{return await Promise.race([provider.listModels(),cancelled])}finally{signal.removeEventListener("abort",abort),provider.dispose()}}var init_model_catalog=__esm({"../agent-runtime/dist/model-catalog.js"(){"use strict";init_codex_provider()}});var codex_exports={};__export(codex_exports,{CODEX_MODEL_CAPABILITY:()=>CODEX_MODEL_CAPABILITY,CodexAgentProvider:()=>CodexAgentProvider,codexAppExecutableCandidatePaths:()=>codexAppExecutableCandidatePaths,codexExecutableCandidatePaths:()=>codexExecutableCandidatePaths,codexThreadUrl:()=>codexThreadUrl,codexWorkspaceUrl:()=>codexWorkspaceUrl,compareCodexVersions:()=>compareCodexVersions,externalOpenCommand:()=>externalOpenCommand,listCodexModels:()=>listCodexModels,normalizeCodexVersion:()=>normalizeCodexVersion,runCodexModel:()=>runCodexModel});var init_codex=__esm({"../agent-runtime/dist/codex.js"(){"use strict";init_codex_provider();init_model();init_model_catalog()}});var pluginCommandWorker_exports={};__export(pluginCommandWorker_exports,{handlePluginWorkerMessage:()=>handlePluginWorkerMessage});function send(event){return new Promise((resolve6,reject)=>{if(!process.connected||!process.send){reject(new Error("Plugin executor disconnected"));return}process.send(event,error=>error?reject(error):resolve6())})}async function run(message){try{if((message.registration??findPluginRegistration(message.plugin))?.entry!==message.entry||pluginFileVersion(message.entry)!==message.entryVersion)throw Object.assign(new Error("Plugin source changed before execution"),{code:"PLUGIN_SOURCE_CHANGED"});let invokePlugin=message.recovery?invokeRegisteredRecoveryPlugin:message.access==="runtime"?invokeRegisteredRuntimePlugin:message.access==="toolbox"?invokeRegisteredToolboxPlugin:invokeRegisteredPlugin,declaration=message.describe||message.help?await loadPlugin(message.entry,{options:{},progress:()=>{},invoke:async()=>{throw new Error("Host actions are unavailable during runtime declaration")}},message.plugin):void 0,migration=message.migration?await loadPlugin(message.entry,{options:{},signal:controller.signal,progress:()=>{},invoke:async()=>{throw Object.assign(new Error("Checkpoint migration cannot invoke host actions or plugins"),{code:"PLUGIN_CHECKPOINT_MIGRATION_HOST_CALL"})}},message.plugin):void 0;if(migration){let definitions=migration.taskRecovery?.commands,definition=definitions&&Object.hasOwn(definitions,message.invocation.command)?definitions[message.invocation.command]:void 0;if(!definition||!message.expectedRecovery||pluginRecoverySignature(definition)!==message.expectedRecovery)throw Object.assign(new Error("Migration declaration differs from the admitted target format"),{code:"PLUGIN_RECOVERY_DECLARATION_CHANGED"})}let value=migration?await migration.runMigration(message.invocation):declaration?message.help?declaration.help(message.help.namespace,message.help.command):{pageRuntime:declaration.pageRuntime,stateStorage:declaration.stateStorage,taskRecovery:declaration.taskRecovery}:message.model?await(await Promise.resolve().then(()=>(init_codex(),codex_exports))).runCodexModel(message.model,{signal:controller.signal,cwd:process.cwd(),onDiagnostic:metadata=>{send({type:"diagnostic",metadata}).catch(()=>process.exit(1))},onDelta:(delta,index,metadata)=>{send({type:"progress",progress:{message:"model.delta",data:{delta,index,...metadata,partial:!0}}}).catch(()=>process.exit(1))}}):await invokePlugin(message.plugin,message.invocation,{invocation:Object.freeze({...message.identity,host:Object.freeze(message.identity.host)}),...message.registration?{resolveRegistration:name=>name===message.plugin?message.registration:findPluginRegistration(name)}:{},invoke:(action,payload={},options={},onProgress)=>{controller.signal.throwIfAborted();let id=++sequence;return new Promise((resolve6,reject)=>{pending.set(id,{resolve:resolve6,reject,onProgress}),send({type:"invoke",id,action,payload,options,...onProgress?{stream:!0}:{}}).catch(error=>{pending.delete(id),reject(error)})})}},{...message.options,signal:controller.signal,source:message.identity.source,onProgress:progress=>{send({type:"progress",progress}).catch(()=>process.exit(1))}}),json2=JSON.stringify({value});if(Buffer.byteLength(json2)>(message.migration?64*1024:67108864))throw Object.assign(new Error("Plugin result exceeds the execution result limit"),{code:"PLUGIN_RESULT_TOO_LARGE"});await send({type:"result",json:json2}),completed=!0}catch(error){await send({type:"error",error:serializePluginExecutionError(error)}).catch(()=>{}),completed=!0}}function handlePluginWorkerMessage(message){if(message.type==="start"){if(started)return;started=!0,run(message)}else if(message.type==="cancel"){if(completed)return;let error=pluginExecutionError(message.error);controller.abort(error);for(let request of pending.values())request.reject(error);pending.clear()}else if(message.type==="invoke-progress"){let request=pending.get(message.id);try{request?.onProgress?.(message.progress)}catch(error){pending.delete(message.id),request?.reject(error instanceof Error?error:new Error(String(error)))}}else if(message.type==="response"){let request=pending.get(message.id);pending.delete(message.id),message.error?request?.reject(pluginExecutionError(message.error)):request?.resolve(message.result)}}var controller,pending,sequence,started,completed,init_pluginCommandWorker=__esm({"../client/src/plugins/runtime/pluginCommandWorker.ts"(){"use strict";init_pluginRecoveryDefinition();init_plugin();init_pluginSource();init_pluginExecutorProtocol();controller=new AbortController,pending=new Map,sequence=0,started=!1,completed=!1}});import{execFileSync,fork}from"node:child_process";import{fileURLToPath}from"node:url";function supervisePluginExecutor(workerUrl){let child=fork(fileURLToPath(workerUrl),["--command"],{stdio:["ignore","pipe","pipe","ipc"],serialization:"advanced",execArgv:[]}),ending=!1,forwarded=Promise.resolve();child.stderr?.on("data",chunk=>process.stderr.write(chunk)),child.stdout?.on("data",chunk=>process.stdout.write(chunk));let terminate=()=>{if(process.platform==="win32")try{execFileSync("taskkill",["/PID",String(process.pid),"/T","/F"],{stdio:"ignore",windowsHide:!0})}catch{child.kill("SIGKILL")}else try{process.kill(-process.pid,"SIGKILL")}catch{child.kill("SIGKILL")}process.exit(1)};process.on("disconnect",terminate),process.on("message",message=>{!child.connected||ending||child.send(message,error=>{error&&!ending&&terminate()})}),child.on("message",message=>{forwarded=forwarded.then(()=>new Promise((resolve6,reject)=>{if(!process.send||!process.connected){reject(new Error("Plugin owner disconnected"));return}process.send(message,error=>error?reject(error):resolve6())})),forwarded.catch(terminate)}),child.once("error",error=>{process.stderr.write(error.message),terminate()}),child.once("exit",code=>{ending=!0,child.stderr?.destroy(),forwarded.then(()=>process.exit(code??1),terminate)})}if(process.argv[2]==="--command"){let command;process.on("message",message=>{(command??=Promise.resolve().then(()=>(init_pluginCommandWorker(),pluginCommandWorker_exports))).then(worker=>worker.handlePluginWorkerMessage(message)).catch(error=>{process.stderr.write(String(error)),process.exit(1)})}),process.on("disconnect",()=>process.exit(1))}else supervisePluginExecutor(import.meta.url);
|