@mearl/native-host 3.0.0-beta.1 → 3.0.0-beta.3

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.
@@ -646,7 +646,7 @@ body {
646
646
  }
647
647
  button, input, select, textarea { font: inherit; }
648
648
  </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 readFileSync4,readSync,readdirSync,renameSync as renameSync2,rmSync,statSync as statSync3,writeFileSync}from"node:fs";import{homedir}from"node:os";import{isAbsolute as isAbsolute3,join as join3,resolve as resolve3}from"node:path";function pluginDirectory(){return resolve3(process.env.MEARL_PLUGIN_DIR||join3(homedir(),".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 assertPluginName(name){if(!/^[a-z][a-z0-9-]*$/.test(name)||RESERVED_NAMES.has(name)||COMMAND_MAP.has(name))throw new PluginError("PLUGIN_INVALID_NAME",`不可用的插件名称: ${name}`)}function normalizePluginToolboxContribution(value){if(value===void 0)return;if(!value||typeof value!="object"||Array.isArray(value))throw new Error("toolbox 必须是对象");let candidate=value;if(candidate.displayMode!==void 0&&!["popup","tab","both"].includes(candidate.displayMode))throw new Error("toolbox.displayMode 必须是 popup、tab 或 both");let title=typeof candidate.title=="string"?candidate.title.trim():"",description=typeof candidate.description=="string"?candidate.description.trim():void 0,icon=typeof candidate.icon=="string"?candidate.icon.trim():void 0;if(candidate.version!==1)throw new Error("toolbox.version 必须为 1");if(!title||title.length>80)throw new Error("toolbox.title 必须是 1-80 个字符");if(description&&description.length>240)throw new Error("toolbox.description 不能超过 240 个字符");if(icon&&!parseToolboxIcon(icon))throw new Error("toolbox.icon 必须是图标名称、SVG、图片 Data URL 或 HTTP(S) 图片地址,最多 32768 个字符");let locales;if(candidate.locales!==void 0){if(!candidate.locales||typeof candidate.locales!="object"||Array.isArray(candidate.locales))throw new Error("toolbox.locales 必须是对象");let entries=Object.entries(candidate.locales);if(entries.length===0||entries.length>20)throw new Error("toolbox.locales 必须包含 1-20 个语言");locales=Object.fromEntries(entries.map(([locale,localized])=>{if(!/^[a-z]{2,3}(?:[_-][A-Za-z0-9]{2,8})*$/.test(locale))throw new Error(`toolbox.locales 包含无效语言: ${locale}`);if(!localized||typeof localized!="object"||Array.isArray(localized))throw new Error(`toolbox.locales.${locale} 必须是对象`);let localizedTitle=typeof localized.title=="string"?localized.title.trim():void 0,localizedDescription=typeof localized.description=="string"?localized.description.trim():void 0;if(localizedTitle!==void 0&&(!localizedTitle||localizedTitle.length>80))throw new Error(`toolbox.locales.${locale}.title 必须是 1-80 个字符`);if(localizedDescription!==void 0&&localizedDescription.length>240)throw new Error(`toolbox.locales.${locale}.description 不能超过 240 个字符`);if(!localizedTitle&&!localizedDescription)throw new Error(`toolbox.locales.${locale} 至少声明 title 或 description`);return[locale,{...localizedTitle?{title:localizedTitle}:{},...localizedDescription?{description:localizedDescription}:{}}]}))}if(!candidate.page||typeof candidate.page!="object"||Array.isArray(candidate.page))throw new Error("toolbox.page 必须是对象");let pageCandidate=candidate.page;if(pageCandidate.type!=="sandbox")throw new Error("toolbox.page.type 必须为 sandbox");if(pageCandidate.runtime!==void 0&&pageCandidate.runtime!=="preact")throw new Error("toolbox.page.runtime 仅支持 preact");let pageEntry=typeof pageCandidate.entry=="string"?pageCandidate.entry.trim():"";if(!pageEntry||pageEntry.length>240||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=join3(pluginDirectory(),`${name}.json`),content;try{content=readFileSync4(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(([path8,version2])=>!isAbsolute3(path8)||typeof version2!="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(([path8,version2])=>!isAbsolute3(path8)||typeof version2!="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{throw new PluginError("PLUGIN_REGISTRY_INVALID",`无效的插件记录: ${file}`)}}var RESERVED_NAMES,PluginError,init_pluginRegistry=__esm({"../client/src/plugins/pluginRegistry.ts"(){"use strict";init_dist();init_dist();init_commands();init_pluginPageBundle();init_pluginSource();RESERVED_NAMES=new Set(["check","help","connector_list","capture_checkpoint","plugin","plugins"]),PluginError=class extends Error{constructor(code,message){super(`${code}: ${message}`);this.code=code}code}}});import{constants,closeSync as closeSync2,fstatSync,lstatSync as lstatSync2,mkdirSync as mkdirSync2,openSync as openSync2,readSync as readSync2,readFileSync as readFileSync5,renameSync as renameSync3,rmSync as rmSync2,writeFileSync as writeFileSync2}from"node:fs";import{createHash as createHash4,randomUUID}from"node:crypto";import{isAbsolute as isAbsolute4,join as join4}from"node:path";function validateOfficialPluginCatalog(value){if(!value||typeof value!="object"||Array.isArray(value))throw new Error("Invalid managed plugin catalog");let input=value;if(input.schemaVersion!==1||typeof input.revision!="string"||!/^[a-f0-9]{64}$/.test(input.revision)||!input.plugins||typeof input.plugins!="object"||Array.isArray(input.plugins)||Object.keys(input).some(key=>!["schemaVersion","revision","plugins","selection"].includes(key))||Object.keys(input.plugins).length>200)throw new Error("Invalid managed plugin catalog");let selection=input.selection;if(selection!==void 0&&(!selection||typeof selection!="object"||Array.isArray(selection)||Object.keys(selection).some(key=>!["path","sha256"].includes(key))||typeof selection.path!="string"||!isAbsolute4(selection.path)||selection.path.length>4096||/[\0\r\n]/.test(selection.path)||typeof selection.sha256!="string"||!/^[a-f0-9]{64}$/.test(selection.sha256)))throw new Error("Invalid plugin catalog selection");let plugins={};for(let[name,value2]of Object.entries(input.plugins)){if(assertPluginName(name),!value2||typeof value2!="object"||Array.isArray(value2))throw new Error("Invalid managed plugin declaration");let item=value2;if(Object.keys(item).some(key=>!["description","installArgs","setup","skill"].includes(key))||typeof item.description!="string"||item.description.length>1e3||typeof item.skill!="string"||!/^[a-z][a-z0-9-]*$/.test(item.skill)||!Array.isArray(item.installArgs)||item.installArgs.length===0||item.installArgs.length>32||item.installArgs.some(arg=>typeof arg!="string"||arg.length>2048||/[\0\r\n]/.test(arg))||item.setup!==void 0&&(typeof item.setup!="string"||!/^[a-z][a-z0-9-]*$/.test(item.setup)))throw new Error("Invalid managed plugin declaration");plugins[name]={description:item.description,skill:item.skill,installArgs:[...item.installArgs],...item.setup!==void 0&&{setup:item.setup}}}let catalog={schemaVersion:1,revision:input.revision,plugins,...selection?{selection:{path:selection.path,sha256:selection.sha256}}:{}};if(Buffer.byteLength(JSON.stringify(catalog))>MAX_CATALOG_BYTES)throw new Error("Managed plugin catalog exceeds 256 KiB");return catalog}function selectionMatches(selection){try{let before=lstatSync2(selection.path);if(!before.isFile()||before.isSymbolicLink()||before.size>1024*1024)return!1;let fd=openSync2(selection.path,constants.O_RDONLY|(constants.O_NOFOLLOW??0));try{let stat2=fstatSync(fd);if(!stat2.isFile()||stat2.size>1024*1024)return!1;let bytes=Buffer.alloc(stat2.size+1),size=0;for(;size<bytes.length;){let count=readSync2(fd,bytes,size,bytes.length-size,null);if(!count)break;size+=count}return size===stat2.size&&createHash4("sha256").update(bytes.subarray(0,size)).digest("hex")===selection.sha256}finally{closeSync2(fd)}}catch(error){if(error.code==="ENOENT")return!1;throw error}}function readOfficialPluginCatalog(){let source;try{source=readFileSync5(catalogPath(),"utf8")}catch(error){if(error.code==="ENOENT")return;throw error}if(Buffer.byteLength(source)>MAX_CATALOG_BYTES)throw new Error("Managed plugin catalog exceeds 256 KiB");let catalog=validateOfficialPluginCatalog(JSON.parse(source));return catalog.selection&&!selectionMatches(catalog.selection)?void 0:catalog}function refreshOfficialPlugins(){let plugins={};try{plugins=readOfficialPluginCatalog()?.plugins??{}}catch{}for(let name of Object.keys(OFFICIAL_PLUGINS))delete OFFICIAL_PLUGINS[name];return Object.assign(OFFICIAL_PLUGINS,plugins),OFFICIAL_PLUGINS}function findOfficialPlugin(name){let plugins=refreshOfficialPlugins();return Object.hasOwn(plugins,name)?plugins[name]:void 0}var OFFICIAL_PLUGINS,MAX_CATALOG_BYTES,catalogPath,init_officialPluginCatalog=__esm({"../client/src/plugins/officialPluginCatalog.ts"(){"use strict";init_pluginRegistry();OFFICIAL_PLUGINS={},MAX_CATALOG_BYTES=256*1024,catalogPath=()=>join4(pluginDirectory(),".official-catalog.json");refreshOfficialPlugins()}});import{createRequire}from"node:module";import{fileURLToPath as fileURLToPath2}from"node:url";var require2,CLIENT_VERSION,PLUGIN_TASK_HOST_PATH,PLUGIN_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)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath2(new URL("./pluginModelSessionWorker.js",import.meta.url))}});import{closeSync as closeSync3,mkdirSync as mkdirSync3,openSync as openSync3,rmSync as rmSync3,statSync as statSync4,writeFileSync as writeFileSync3}from"node:fs";import{join as join5}from"node:path";import{spawn}from"node:child_process";function delay(milliseconds){return new Promise(resolve6=>setTimeout(resolve6,milliseconds))}function installLockPath(name){return join5(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=openSync3(lockPath,"wx",384),writeFileSync3(descriptor,`${process.pid}
649
- `),closeSync3(descriptor),()=>rmSync3(lockPath,{force:!0})}catch(error){if(descriptor!==void 0&&closeSync3(descriptor),error.code!=="EEXIST")throw error}if(findPluginRegistration(name))return()=>{};try{if(Date.now()-statSync4(lockPath).mtimeMs>INSTALL_LOCK_STALE_MS){rmSync3(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(current2,chunk){return current2.length>=MAX_INSTALL_OUTPUT?current2:(current2+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=spawn(command,["-y",`@mearl/setup@${CLIENT_VERSION}`,"plugin","ensure",name],{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;let accepted=JSON.stringify(readOfficialPluginCatalog());if(!findOfficialPlugin(name))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(progress?.(`正在安装官方插件 ${name}...`),await installWithSetup(name),JSON.stringify(readOfficialPluginCatalog())!==accepted)throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(!findPluginRegistration(name))throw new Error(`官方插件 ${name} 安装完成后仍未注册`);progress?.(`官方插件 ${name} 已安装。`)}finally{releaseLock()}}var INSTALL_TIMEOUT_MS,INSTALL_LOCK_STALE_MS,MAX_INSTALL_OUTPUT,activeInstallations,ensureOfficialPluginRegistered,init_officialPluginInstaller=__esm({"../client/src/plugins/officialPluginInstaller.ts"(){"use strict";init_runtimePaths();init_officialPluginCatalog();init_pluginRegistry();INSTALL_TIMEOUT_MS=18e4,INSTALL_LOCK_STALE_MS=5*6e4,MAX_INSTALL_OUTPUT=1024*1024,activeInstallations=new Map;ensureOfficialPluginRegistered=(name,progress)=>{let active=activeInstallations.get(name);if(active)return active;let installation=installOfficialPlugin(name,progress).finally(()=>{activeInstallations.delete(name)});return activeInstallations.set(name,installation),installation}}});function serializePluginExecutionError(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 spawn2}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=spawn2(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)}
649
+ `),closeSync3(descriptor),()=>rmSync3(lockPath,{force:!0})}catch(error){if(descriptor!==void 0&&closeSync3(descriptor),error.code!=="EEXIST")throw error}if(findPluginRegistration(name))return()=>{};try{if(Date.now()-statSync4(lockPath).mtimeMs>INSTALL_LOCK_STALE_MS){rmSync3(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(current2,chunk){return current2.length>=MAX_INSTALL_OUTPUT?current2:(current2+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=spawn(command,["-y","--@mearl:registry=https://registry.npmjs.org",`@mearl/setup@${CLIENT_VERSION}`,"plugin","ensure",name],{stdio:["ignore","pipe","pipe"],windowsHide:!0}),stdout="",stderr="",settled=!1,finish=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;let accepted=JSON.stringify(readOfficialPluginCatalog());if(!findOfficialPlugin(name))throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(progress?.(`正在安装官方插件 ${name}...`),await installWithSetup(name),JSON.stringify(readOfficialPluginCatalog())!==accepted)throw new Error("PLUGIN_CATALOG_SELECTION_CHANGED");if(!findPluginRegistration(name))throw new Error(`官方插件 ${name} 安装完成后仍未注册`);progress?.(`官方插件 ${name} 已安装。`)}finally{releaseLock()}}var INSTALL_TIMEOUT_MS,INSTALL_LOCK_STALE_MS,MAX_INSTALL_OUTPUT,activeInstallations,ensureOfficialPluginRegistered,init_officialPluginInstaller=__esm({"../client/src/plugins/officialPluginInstaller.ts"(){"use strict";init_runtimePaths();init_officialPluginCatalog();init_pluginRegistry();INSTALL_TIMEOUT_MS=18e4,INSTALL_LOCK_STALE_MS=5*6e4,MAX_INSTALL_OUTPUT=1024*1024,activeInstallations=new Map;ensureOfficialPluginRegistered=(name,progress)=>{let active=activeInstallations.get(name);if(active)return active;let installation=installOfficialPlugin(name,progress).finally(()=>{activeInstallations.delete(name)});return activeInstallations.set(name,installation),installation}}});function serializePluginExecutionError(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 spawn2}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=spawn2(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)}
650
650
  `)}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`
651
651
  import asyncio
652
652
  import importlib.util
@@ -977,7 +977,7 @@ except BaseException as error:
977
977
  "message": "返回值无法 JSON 序列化: " + _error_message(serialization_error),
978
978
  })
979
979
  sys.exit(1)
980
- `}});import{randomUUID as randomUUID2}from"node:crypto";import{linkSync,mkdirSync as mkdirSync4,readFileSync as readFileSync6,rmSync as rmSync4,writeFileSync as writeFileSync4}from"node:fs";import{join as join6}from"node:path";function localPluginExecutionHost(){let directory=pluginDirectory(),hostId=hostIds.get(directory);if(!hostId){mkdirSync4(directory,{recursive:!0,mode:448});let file=join6(directory,".execution-host-id"),proposed=randomUUID2(),temporary=`${file}.${proposed}.tmp`;try{writeFileSync4(temporary,proposed,{flag:"wx",mode:384}),linkSync(temporary,file)}catch(error){if(error.code!=="EEXIST")throw error}finally{rmSync4(temporary,{force:!0})}if(hostId=readFileSync6(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:randomUUID2(),host:parent?.host??localPluginExecutionHost(),plugin,source,...parent?{parentInvocationId:parent.invocationId}:{}})}var epoch,hostIds,UUID,init_pluginExecution2=__esm({"../client/src/plugins/runtime/pluginExecution.ts"(){"use strict";init_pluginRegistry();epoch=randomUUID2(),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 readFileSync7,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 join7}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=join7(homedir2(),".mearl")}});import{closeSync as closeSync4,existsSync as existsSync2,linkSync as linkSync2,openSync as openSync4,statSync as statSync5,mkdirSync as mkdirSync5,readFileSync as readFileSync8,writeFileSync as writeFileSync5,renameSync as renameSync4,rmSync as rmSync5,readdirSync as readdirSync3}from"node:fs";import{dirname as dirname3,join as join8}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 statSync6,renameSync as renameSync5,readFileSync as readFileSync9,readdirSync as readdirSync4,rmSync as rmSync6}from"node:fs";import{join as join9}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 closeSync5,openSync as openSync5}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";import{AsyncLocalStorage}from"node:async_hooks";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 ownedCommands,init_command2=__esm({"../daemon-core/dist/command.js"(){"use strict";init_process();ownedCommands=new AsyncLocalStorage}});var init_dist2=__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_dist2()}});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_pluginExecution2();init_pluginExecutorProtocol();init_pluginProcessTree();init_dist2()}});import{tmpdir}from"node:os";import{join as join10}from"node:path";var init_pluginHostPaths=__esm({"../client/src/plugins/runtime/pluginHostPaths.ts"(){"use strict";init_pluginRegistry()}});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 closeSync6,mkdirSync as mkdirSync6,openSync as openSync6}from"node:fs";import{createConnection}from"node:net";var init_pluginHostConnection=__esm({"../client/src/plugins/clients/pluginHostConnection.ts"(){"use strict";init_runtimePaths();init_dist2();init_pluginHostPaths();init_dist();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_dist3=__esm({"../cloud/cloud-types/dist/index.js"(){"use strict"}});var OBSERVED_PAGE_ACTIONS,init_actionTimeouts=__esm({"../client/src/actionTimeouts.ts"(){"use strict";init_dist();OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS)}});var init_protocol=__esm({"../provider/dist/protocol.js"(){"use strict"}});var init_types2=__esm({"../provider/dist/types.js"(){"use strict";init_protocol()}});var PROVIDER_ACTIONS,init_actions=__esm({"../provider/dist/actions.js"(){"use strict";init_browserActionProtocol();PROVIDER_ACTIONS=Object.keys(BROWSER_CAPABILITY_ACTIONS)}});var init_provider_runtime=__esm({"../provider/dist/provider-runtime.js"(){"use strict";init_types2();init_actions()}});import{existsSync as existsSync4,readFileSync as readFileSync10,renameSync as renameSync6,rmSync as rmSync7,statSync as statSync7,writeFileSync as writeFileSync6}from"node:fs";import{isAbsolute as isAbsolute5,join as join11,relative as relative3,resolve as resolve4,sep as sep2}from"node:path";var init_registry2=__esm({"../provider/dist/registry.js"(){"use strict";init_dist2();init_types2();init_provider_runtime();init_protocol()}});import{spawn as spawn6}from"node:child_process";import{tmpdir as tmpdir2}from"node:os";import{join as join12}from"node:path";var init_control_host=__esm({"../provider/dist/control-host.js"(){"use strict";init_protocol();init_dist2()}});var init_host=__esm({"../provider/dist/host.js"(){"use strict";init_registry2();init_control_host()}});import net from"node:net";import{chmodSync,rmSync as rmSync8}from"node:fs";import{dirname as dirname5}from"node:path";var MAX_REQUEST_BYTES,init_server=__esm({"../provider/dist/server.js"(){"use strict";init_dist2();init_actions();init_provider_runtime();init_registry2();init_types2();init_protocol();MAX_REQUEST_BYTES=16*1024*1024}});var init_dist4=__esm({"../provider/dist/index.js"(){"use strict";init_types2();init_protocol();init_actions();init_registry2();init_provider_runtime();init_server()}});import{spawn as spawn7}from"node:child_process";import{closeSync as closeSync7,existsSync as existsSync5,mkdirSync as mkdirSync7,openSync as openSync7}from"node:fs";import{join as join13}from"node:path";var init_launcher=__esm({"../provider/dist/launcher.js"(){"use strict";init_dist2();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,init_socket=__esm({"../client/src/socket.ts"(){"use strict";init_runtimePaths();init_host();init_dist4();init_runtime();init_fileRefs();init_browserRegistry();init_actionTimeouts();init_dist();MAX_SOCKET_BUFFER_SIZE=64*1024*1024,SOCKET_PATH=process.platform==="win32"?"\\\\.\\pipe\\mearl-agent":path5.join(os2.tmpdir(),"mearl-agent.sock")}});import{existsSync as existsSync6,readFileSync as readFileSync11}from"node:fs";import{homedir as homedir3}from"node:os";import{join as join14}from"node:path";var MEARL_CONFIG_DIR,init_unifiedConfig=__esm({"../client/src/unifiedConfig.ts"(){"use strict";MEARL_CONFIG_DIR=join14(homedir3(),".mearl")}});import WebSocket from"ws";var init_unified=__esm({"../client/src/unified.ts"(){"use strict";init_pageEvalArguments();init_artifacts();init_dist3();init_actionTimeouts();init_dist();init_socket();init_unifiedConfig()}});var init_pluginTasks2=__esm({"../client/src/plugins/clients/pluginTasks.ts"(){"use strict";init_pluginHostConnection();init_dist2();init_pluginHostPaths();init_unified();init_dist();init_pluginExecutorProtocol()}});import{closeSync as closeSync8,fsyncSync,mkdirSync as mkdirSync8,openSync as openSync8,renameSync as renameSync7,rmSync as rmSync9,writeFileSync as writeFileSync7}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 closeSync9,openSync as openSync9,opendirSync,readFileSync as readFileSync12,readSync as readSync3,readdirSync as readdirSync5,rmSync as rmSync10,statSync as statSync8}from"node:fs";import{join as join15}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_dist();init_pluginHostFiles();init_pluginHostPaths();init_dist2();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 rmSync11}from"node:fs";var init_pluginRuntimeCleanup=__esm({"../client/src/plugins/runtime/pluginRuntimeCleanup.ts"(){"use strict";init_dist2();init_pluginHostPaths();init_pluginRegistry();init_pluginTasks2();init_pluginTaskStore()}});var init_pluginPages2=__esm({"../client/src/plugins/clients/pluginPages.ts"(){"use strict";init_unified()}});var init_pluginState2=__esm({"../client/src/plugins/clients/pluginState.ts"(){"use strict";init_pluginHostConnection()}});var init_pluginModels2=__esm({"../client/src/plugins/clients/pluginModels.ts"(){"use strict";init_pluginTasks2()}});import{dirname as dirname7,extname as extname2,resolve as resolve5}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{return readInstalledSkillMetadata(resolve5(dirname7(entry),".."))?.version}catch{return}}function isObject2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isPluginInvocation(value){return isObject2(value)&&typeof value.command=="string"&&isObject2(value.input)}function normalizePluginProgress(progress){if(typeof progress=="string"){if(!progress)throw new Error("app.progress 需要非空消息");return progress}if(!isObject2(progress)||typeof progress.message!="string"||!progress.message)throw new Error("app.progress 需要非空消息");if(progress.data!==void 0&&!isObject2(progress.data))throw new Error("app.progress data 必须是对象");let data2;if(progress.data)try{let serialized=JSON.stringify(progress.data),parsed=serialized===void 0?void 0:JSON.parse(serialized);if(!isObject2(parsed))throw new Error("invalid object");data2=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data2?{data:data2}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx @mearl/setup plugin uninstall ${name}`].join(`
980
+ `}});import{randomUUID as randomUUID2}from"node:crypto";import{linkSync,mkdirSync as mkdirSync4,readFileSync as readFileSync6,rmSync as rmSync4,writeFileSync as writeFileSync4}from"node:fs";import{join as join6}from"node:path";function localPluginExecutionHost(){let directory=pluginDirectory(),hostId=hostIds.get(directory);if(!hostId){mkdirSync4(directory,{recursive:!0,mode:448});let file=join6(directory,".execution-host-id"),proposed=randomUUID2(),temporary=`${file}.${proposed}.tmp`;try{writeFileSync4(temporary,proposed,{flag:"wx",mode:384}),linkSync(temporary,file)}catch(error){if(error.code!=="EEXIST")throw error}finally{rmSync4(temporary,{force:!0})}if(hostId=readFileSync6(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:randomUUID2(),host:parent?.host??localPluginExecutionHost(),plugin,source,...parent?{parentInvocationId:parent.invocationId}:{}})}var epoch,hostIds,UUID,init_pluginExecution2=__esm({"../client/src/plugins/runtime/pluginExecution.ts"(){"use strict";init_pluginRegistry();epoch=randomUUID2(),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 readFileSync7,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 join7}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=join7(homedir2(),".mearl")}});import{closeSync as closeSync4,existsSync as existsSync2,linkSync as linkSync2,openSync as openSync4,statSync as statSync5,mkdirSync as mkdirSync5,readFileSync as readFileSync8,writeFileSync as writeFileSync5,renameSync as renameSync4,rmSync as rmSync5,readdirSync as readdirSync3}from"node:fs";import{dirname as dirname3,join as join8}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 statSync6,renameSync as renameSync5,readFileSync as readFileSync9,readdirSync as readdirSync4,rmSync as rmSync6}from"node:fs";import{join as join9}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 closeSync5,openSync as openSync5}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";import{AsyncLocalStorage}from"node:async_hooks";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 ownedCommands,init_command2=__esm({"../daemon-core/dist/command.js"(){"use strict";init_process();ownedCommands=new AsyncLocalStorage}});var init_dist2=__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_dist2()}});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_pluginExecution2();init_pluginExecutorProtocol();init_pluginProcessTree();init_dist2()}});import{tmpdir}from"node:os";import{join as join10}from"node:path";var init_pluginHostPaths=__esm({"../client/src/plugins/runtime/pluginHostPaths.ts"(){"use strict";init_pluginRegistry()}});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 closeSync6,mkdirSync as mkdirSync6,openSync as openSync6}from"node:fs";import{createConnection}from"node:net";var init_pluginHostConnection=__esm({"../client/src/plugins/clients/pluginHostConnection.ts"(){"use strict";init_runtimePaths();init_dist2();init_pluginHostPaths();init_dist();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_dist3=__esm({"../cloud/cloud-types/dist/index.js"(){"use strict"}});var OBSERVED_PAGE_ACTIONS,init_actionTimeouts=__esm({"../client/src/actionTimeouts.ts"(){"use strict";init_dist();OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS)}});var init_protocol=__esm({"../provider/dist/protocol.js"(){"use strict"}});var init_types2=__esm({"../provider/dist/types.js"(){"use strict";init_protocol()}});var PROVIDER_ACTIONS,init_actions=__esm({"../provider/dist/actions.js"(){"use strict";init_browserActionProtocol();PROVIDER_ACTIONS=Object.keys(BROWSER_CAPABILITY_ACTIONS)}});var init_provider_runtime=__esm({"../provider/dist/provider-runtime.js"(){"use strict";init_types2();init_actions()}});import{existsSync as existsSync4,readFileSync as readFileSync10,renameSync as renameSync6,rmSync as rmSync7,statSync as statSync7,writeFileSync as writeFileSync6}from"node:fs";import{isAbsolute as isAbsolute5,join as join11,relative as relative3,resolve as resolve4,sep as sep2}from"node:path";var init_registry2=__esm({"../provider/dist/registry.js"(){"use strict";init_dist2();init_types2();init_provider_runtime();init_protocol()}});import{spawn as spawn6}from"node:child_process";import{tmpdir as tmpdir2}from"node:os";import{join as join12}from"node:path";var init_control_host=__esm({"../provider/dist/control-host.js"(){"use strict";init_protocol();init_dist2()}});var init_host=__esm({"../provider/dist/host.js"(){"use strict";init_registry2();init_control_host()}});import net from"node:net";import{chmodSync,rmSync as rmSync8}from"node:fs";import{dirname as dirname5}from"node:path";var MAX_REQUEST_BYTES,init_server=__esm({"../provider/dist/server.js"(){"use strict";init_dist2();init_actions();init_provider_runtime();init_registry2();init_types2();init_protocol();MAX_REQUEST_BYTES=16*1024*1024}});var init_dist4=__esm({"../provider/dist/index.js"(){"use strict";init_types2();init_protocol();init_actions();init_registry2();init_provider_runtime();init_server()}});import{spawn as spawn7}from"node:child_process";import{closeSync as closeSync7,existsSync as existsSync5,mkdirSync as mkdirSync7,openSync as openSync7}from"node:fs";import{join as join13}from"node:path";var init_launcher=__esm({"../provider/dist/launcher.js"(){"use strict";init_dist2();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,init_socket=__esm({"../client/src/socket.ts"(){"use strict";init_runtimePaths();init_host();init_dist4();init_runtime();init_fileRefs();init_browserRegistry();init_actionTimeouts();init_dist();MAX_SOCKET_BUFFER_SIZE=64*1024*1024,SOCKET_PATH=process.platform==="win32"?"\\\\.\\pipe\\mearl-agent":path5.join(os2.tmpdir(),"mearl-agent.sock")}});import{existsSync as existsSync6,readFileSync as readFileSync11}from"node:fs";import{homedir as homedir3}from"node:os";import{join as join14}from"node:path";var MEARL_CONFIG_DIR,init_unifiedConfig=__esm({"../client/src/unifiedConfig.ts"(){"use strict";MEARL_CONFIG_DIR=join14(homedir3(),".mearl")}});import WebSocket from"ws";var init_unified=__esm({"../client/src/unified.ts"(){"use strict";init_pageEvalArguments();init_artifacts();init_dist3();init_actionTimeouts();init_dist();init_socket();init_unifiedConfig()}});var init_pluginTasks2=__esm({"../client/src/plugins/clients/pluginTasks.ts"(){"use strict";init_pluginHostConnection();init_dist2();init_pluginHostPaths();init_unified();init_dist();init_pluginExecutorProtocol()}});import{closeSync as closeSync8,fsyncSync,mkdirSync as mkdirSync8,openSync as openSync8,renameSync as renameSync7,rmSync as rmSync9,writeFileSync as writeFileSync7}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 closeSync9,openSync as openSync9,opendirSync,readFileSync as readFileSync12,readSync as readSync3,readdirSync as readdirSync5,rmSync as rmSync10,statSync as statSync8}from"node:fs";import{join as join15}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_dist();init_pluginHostFiles();init_pluginHostPaths();init_dist2();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 rmSync11}from"node:fs";var init_pluginRuntimeCleanup=__esm({"../client/src/plugins/runtime/pluginRuntimeCleanup.ts"(){"use strict";init_dist2();init_pluginHostPaths();init_pluginRegistry();init_pluginTasks2();init_pluginTaskStore()}});var init_pluginPages2=__esm({"../client/src/plugins/clients/pluginPages.ts"(){"use strict";init_unified()}});var init_pluginState2=__esm({"../client/src/plugins/clients/pluginState.ts"(){"use strict";init_pluginHostConnection()}});var init_pluginModels2=__esm({"../client/src/plugins/clients/pluginModels.ts"(){"use strict";init_pluginTasks2()}});import{dirname as dirname7,extname as extname2,resolve as resolve5}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{return readInstalledSkillMetadata(resolve5(dirname7(entry),".."))?.version}catch{return}}function isObject2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isPluginInvocation(value){return isObject2(value)&&typeof value.command=="string"&&isObject2(value.input)}function normalizePluginProgress(progress){if(typeof progress=="string"){if(!progress)throw new Error("app.progress 需要非空消息");return progress}if(!isObject2(progress)||typeof progress.message!="string"||!progress.message)throw new Error("app.progress 需要非空消息");if(progress.data!==void 0&&!isObject2(progress.data))throw new Error("app.progress data 必须是对象");let data2;if(progress.data)try{let serialized=JSON.stringify(progress.data),parsed=serialized===void 0?void 0:JSON.parse(serialized);if(!isObject2(parsed))throw new Error("invalid object");data2=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data2?{data:data2}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx --@mearl:registry=https://registry.npmjs.org @mearl/setup plugin uninstall ${name}`].join(`
981
981
  `)}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(data2,expectedSequence){if(!executing||!context.invocation?.taskId)throw new PluginError("PLUGIN_TASK_REQUIRED","Checkpoints require a managed task");return context.signal?.throwIfAborted(),context.invoke("plugin_task_checkpoint",{plugin:pluginName??name,data:data2,expectedSequence,expectedDeclaration:checkpointDeclaration})},state(collection,operation,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:(data2,expectedSequence)=>(assertActive(),app.checkpoint(data2,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(`
982
982
  `)},help(namespace,name2){let selected=name2?[find(name2)]:publicCommands();if(!selected.length){let location2=toolbox?`请在 Mearl ${toolbox.displayMode==="popup"?"Popup":"工具箱"} 中打开「${toolbox.title}」使用。`:"此插件未提供公开 CLI 命令。";return`${namespace} 未提供 CLI 命令。
983
983
  ${location2}`}let examples=selected.flatMap(({examples:examples2})=>examples2);return["用法:",...selected.map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`),...examples.length?["","示例:",...examples.map(example=>` ${namespace} ${example}`)]:[]].join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/native-host",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.3",
4
4
  "description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server",
5
5
  "type": "module",
6
6
  "engines": {
@@ -48,14 +48,14 @@
48
48
  "ws": "^8.18.3",
49
49
  "@types/node": "^24.9.1",
50
50
  "@types/ws": "^8.18.1",
51
- "@mearl/app-profiles": "3.0.0-beta.1",
52
- "@mearl/browser-core": "3.0.0-beta.1",
53
- "@mearl/daemon-core": "3.0.0-beta.1",
54
- "@mearl/client": "3.0.0-beta.1",
55
- "@mearl/provider": "3.0.0-beta.1",
56
- "@mearl/setup": "3.0.0-beta.1",
57
- "@mearl/agent-runtime": "3.0.0-beta.1",
58
- "@mearl/preset": "3.0.0-beta.1"
51
+ "@mearl/browser-core": "3.0.0-beta.3",
52
+ "@mearl/daemon-core": "3.0.0-beta.3",
53
+ "@mearl/setup": "3.0.0-beta.3",
54
+ "@mearl/provider": "3.0.0-beta.3",
55
+ "@mearl/client": "3.0.0-beta.3",
56
+ "@mearl/agent-runtime": "3.0.0-beta.3",
57
+ "@mearl/preset": "3.0.0-beta.3",
58
+ "@mearl/app-profiles": "3.0.0-beta.3"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@types/semver": "^7.7.1",