@mearl/native-host 3.0.0-beta.0 → 3.0.0-beta.10
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/README.md +119 -168
- package/README.zh-CN.md +319 -0
- package/dist/THIRD_PARTY_NOTICES.txt +22 -655
- package/dist/agent/chat-visualization.d.ts +3 -0
- package/dist/agent/managed-programs.d.ts +24 -0
- package/dist/agent/manager.d.ts +15 -2
- package/dist/agent/skill-manager.d.ts +8 -1
- package/dist/app-authorization.d.ts +8 -0
- package/dist/app-profile-catalog.d.ts +3 -1
- package/dist/browser-enhancement-gateway.d.ts +24 -0
- package/dist/browser-identity.d.ts +11 -0
- package/dist/browser-registry.d.ts +1 -0
- package/dist/browser-socket-request.d.ts +4 -0
- package/dist/capability-contracts.d.ts +15 -52
- package/dist/capability-hooks.d.ts +42 -0
- package/dist/cdp-backend/buffers.d.ts +11 -11
- package/dist/cdp-backend/capability-handlers.d.ts +1 -0
- package/dist/cdp-backend/cdp-session.d.ts +2 -0
- package/dist/cdp-backend/cdp-utils.d.ts +3 -8
- package/dist/cdp-backend/handlers.d.ts +2 -1
- package/dist/cdp-backend/http-handlers.d.ts +12 -9
- package/dist/cdp-backend/network-control.d.ts +5 -0
- package/dist/cdp-backend/page-dialogs.d.ts +14 -0
- package/dist/cdp-backend/request-cookies.d.ts +8 -0
- package/dist/cdp-backend/response-cookies.d.ts +8 -0
- package/dist/cdp-backend/send-request.d.ts +3 -2
- package/dist/control-session-manager.d.ts +1 -1
- package/dist/index.js +182 -217
- package/dist/install.js +1 -1
- package/dist/native-capability-services.d.ts +5 -2
- package/dist/node-capabilities.d.ts +1 -0
- package/dist/node-capabilities.js +2 -2
- package/dist/page-runtime-store.d.ts +2 -27
- package/dist/plugin-task-host.js +30 -45
- package/dist/plugin-worker.js +23 -38
- package/dist/pluginModelSessionWorker.js +1 -1
- package/dist/preset-auto-update.d.ts +18 -0
- package/dist/preset-components.d.ts +3 -1
- package/dist/provider-app-resources.d.ts +32 -0
- package/dist/provider-control.d.ts +1 -1
- package/dist/provider-enhancements.d.ts +21 -0
- package/package.json +17 -10
- package/dist/alipay-auth-code.d.ts +0 -13
- package/dist/cdp-backend/mtop-environment.d.ts +0 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { createRequire as __mearlCreateRequire } from 'node:module'; const require = __mearlCreateRequire(import.meta.url);
|
|
2
2
|
var __defProp=Object.defineProperty;var __getOwnPropNames=Object.getOwnPropertyNames;var __esm=(fn,res,err)=>function(){if(err)throw err[0];try{return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res}catch(e){throw err=[e],e}};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})};import{readFileSync,readdirSync}from"node:fs";import{spawnSync}from"node:child_process";var init_process=__esm({"../daemon-core/dist/process.js"(){"use strict"}});import{join}from"node:path";import{homedir}from"node:os";var DAEMON_HOME,init_paths=__esm({"../daemon-core/dist/paths.js"(){"use strict";DAEMON_HOME=join(homedir(),".mearl")}});import{closeSync,existsSync,linkSync,openSync,statSync,mkdirSync,readFileSync as readFileSync2,writeFileSync,renameSync,rmSync,readdirSync as readdirSync2}from"node:fs";import{dirname,join as join2}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 existsSync2,statSync as statSync2,renameSync as renameSync2,readFileSync as readFileSync3,readdirSync as readdirSync3,rmSync as rmSync2}from"node:fs";import{join as join3}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 dirname2}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";import{AsyncLocalStorage}from"node:async_hooks";function versionManagerExecutableCandidates(home,names,options={}){let env=options.env??process.env,platform=options.platform??process.platform,readdirSync4=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 readdirSync4(root,{withFileTypes:!0}).filter(entry=>entry.isDirectory()).sort((left,right)=>right.name.localeCompare(left.name,void 0,{numeric:!0})).flatMap(entry=>names.flatMap(name=>[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 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 ownedCommands,init_command=__esm({"../daemon-core/dist/command.js"(){"use strict";init_process();ownedCommands=new AsyncLocalStorage}});var init_dist=__esm({"../daemon-core/dist/index.js"(){"use strict";init_process();init_paths();init_registry();init_log();init_daemon();init_command()}});var init_process_env=__esm({"../agent-runtime/dist/process-env.js"(){"use strict";init_dist()}});import fs2 from"node:fs";import{spawn as spawn3}from"node:child_process";import path2 from"node:path";function agentExecutableCandidatePaths({executableNames,configuredPath,env=process.env,extraUserCandidates=[],home,platform=process.platform,processExecPath=process.execPath,readdirSync:readdirSync4}){let pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",pathCandidates=(env[pathKey]||"").split(path2.delimiter).filter(Boolean).flatMap(directory=>executableNames.map(name=>path2.join(directory,name))),commonUserDirectories=[path2.join(home,".local","bin"),path2.join(home,".npm-global","bin"),path2.join(home,".volta","bin"),path2.join(home,".local","share","pnpm"),path2.join(home,"Library","pnpm"),path2.join(home,".bun","bin"),...platform==="win32"&&env.APPDATA?[path2.join(env.APPDATA,"npm")]:[]],systemDirectories=platform==="win32"?[]:["/opt/homebrew/bin","/usr/local/bin","/usr/bin"];return[configuredPath,...executableNames.map(name=>path2.join(path2.dirname(processExecPath),name)),...commonUserDirectories.flatMap(directory=>executableNames.map(name=>path2.join(directory,name))),...extraUserCandidates,...versionManagerExecutableCandidates(home,executableNames,{env,platform,readdirSync:readdirSync4}),...systemDirectories.flatMap(directory=>executableNames.map(name=>path2.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(resolve=>{let settled=!1,stderr="",launch=resolveSpawnCommand(executable,options.args),child=spawn3(launch.command,launch.args,{stdio:["ignore","ignore","pipe"],windowsHide:!0,env:prependNodePath()}),finish=error=>{settled||(settled=!0,clearTimeout(timer),resolve(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 fs2.accessSync(candidate,process.platform==="win32"?fs2.constants.F_OK:fs2.constants.X_OK),fs2.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 fs3 from"node:fs";import os from"node:os";import path3 from"node:path";import readline from"node:readline";import{spawn as spawn4}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??os.homedir)(),platform=options.platform??process.platform;return platform==="darwin"?["/Applications",path3.join(home,"Applications")].flatMap(root=>["ChatGPT.app","Codex.app"].flatMap(app=>{let resources=path3.join(root,app,"Contents","Resources");return[path3.join(resources,"codex-cli","CodexCLI.app","Contents","MacOS","codex"),path3.join(resources,"codex")]})):platform==="win32"?[path3.join(env.LOCALAPPDATA||path3.join(home,"AppData","Local"),"Programs"),env.ProgramFiles,env["ProgramFiles(x86)"]].filter(root=>typeof root=="string"&&root.length>0).flatMap(root=>["ChatGPT","Codex"].map(app=>path3.join(root,app,"resources","codex.exe"))):[]}function isIdeBundledCodexPath(candidate,home){let resolvedCandidates=[path3.resolve(candidate)];try{resolvedCandidates.push(fs3.realpathSync(candidate))}catch{}return[".vscode",".vscode-insiders",".cursor",".windsurf"].some(directory=>{let extensionsRoot=`${path3.join(home,directory,"extensions")}${path3.sep}`;return resolvedCandidates.some(resolved=>resolved.startsWith(extensionsRoot))})}function codexExecutableCandidatePaths(options={}){let env=options.env??process.env,home=(options.homedir??os.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=fs3.realpathSync(executable);if(resolved.split(path3.sep).includes("node_modules")){let directory=path3.dirname(resolved);for(let depth=0;depth<6;depth+=1){packageFiles.push(path3.join(directory,"package.json"));let parent=path3.dirname(directory);if(parent===directory)break;directory=parent}}}catch{}/\.(?:cmd|bat)$/i.test(executable)&&packageFiles.push(path3.join(path3.dirname(executable),"node_modules","@openai","codex","package.json"));for(let packageFile of packageFiles)try{let manifest=JSON.parse(fs3.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(resolve=>{let settled=!1,output="",launch=resolveSpawnCommand(executable,["--version"]),child=spawn4(launch.command,launch.args,{stdio:["ignore","pipe","pipe"],windowsHide:!0,env:prependNodePath()}),finish=version=>{settled||(settled=!0,clearTimeout(timer),resolve(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(`
|
|
3
3
|
`):""}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 text=userMessageText(item),imageCount=userMessageImageCount(item);(text||imageCount>0)&&events.push({kind:"lifecycle",method:"chat/userMessage",params:{text,...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((resolve,reject)=>{let child=spawn4(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?resolve():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||os.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||os.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||path3.join(os.homedir(),".codex"),store=config.cli_auth_credentials_store;this.modelDiagnostic({configuration:{source:process.env.CODEX_HOME?"environment":"default",home,filePresent:fs3.existsSync(path3.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 pending=this.start();this.startPromise=pending;try{await pending}catch(error){throw this.startPromise===pending&&(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=spawn4(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 pending=this.pendingRequests.get(message.id);pending&&(clearTimeout(pending.timer),this.pendingRequests.delete(message.id),message.error?pending.reject(new Error(message.error.message||`Codex error ${message.error.code??""}`)):pending.resolve(message.result))}request(method,params){let id=this.nextRequestId++;return new Promise((resolve,reject)=>{let timer=setTimeout(()=>{this.pendingRequests.delete(id),reject(new Error(`Codex request timed out: ${method}`))},REQUEST_TIMEOUT_MS);this.pendingRequests.set(id,{resolve,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)}
|
|
4
|
-
`)}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,pending]of this.pendingRequests)clearTimeout(pending.timer),pending.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 readFileSync4}from"node:fs";async function runCodexModel(request,context,provider=new CodexAgentProvider(()=>{},JSON.parse(readFileSync4(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,text,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,completed=new Promise((resolve,reject)=>{finish=resolve,fail=reject});completed.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")&&(text=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"})):text===void 0?fail(new Error("Model returned no final text")):(flush(),finish(text)))},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}),completed]);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 readFileSync5}from"node:fs";async function listCodexModels(signal,provider=new CodexAgentProvider(()=>{},JSON.parse(readFileSync5(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()}});import{createRequire}from"node:module";import{fileURLToPath}from"node:url";var require2=createRequire(import.meta.url),CLIENT_VERSION=require2("../package.json").version,PLUGIN_TASK_HOST_PATH=fileURLToPath(new URL("./plugin-task-host.js",import.meta.url)),PLUGIN_WORKER_PATH=fileURLToPath(new URL("./plugin-worker.js",import.meta.url)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath(new URL("./pluginModelSessionWorker.js",import.meta.url));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]))}}import{execFileSync,fork}from"node:child_process";import{fileURLToPath as fileURLToPath2}from"node:url";function supervisePluginExecutor(workerUrl){let child=fork(fileURLToPath2(workerUrl),["--command"],{stdio:["ignore","ignore","pipe","ipc"],serialization:"advanced",execArgv:[]}),ending=!1,forwarded=Promise.resolve();child.stderr?.on("data",chunk=>process.stderr.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((resolve,reject)=>{if(!process.send||!process.connected){reject(new Error("Plugin owner disconnected"));return}process.send(message,error=>error?reject(error):resolve())})),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")supervisePluginExecutor(import.meta.url);else{let ready=Promise.resolve().then(()=>(init_codex(),codex_exports)).then(runtime=>({runtime,provider:new runtime.CodexAgentProvider(()=>{},CLIENT_VERSION)})),conversation={},busy=!1,turns=0,diagnostic={},send=value=>{process.connected&&process.send?.(value)};process.on("disconnect",()=>process.exit(1)),process.on("message",message=>{if(busy){process.exit(1);return}busy=!0,ready.then(async({runtime,provider})=>{send({type:"diagnostic",metadata:diagnostic}),turns>=32&&(conversation.threadId&&await provider.closeSession(conversation.threadId),delete conversation.threadId,turns=0);let result=await runtime.runCodexModel(message.request,{cwd:process.cwd(),conversation,signal:new AbortController().signal,onDiagnostic:metadata=>{for(let[key,value]of Object.entries(metadata))["retryCount","activeModel"].includes(key)||Object.assign(diagnostic,{[key]:value});send({type:"diagnostic",metadata})},onDelta:(delta,index,metadata)=>send({type:"delta",delta,index,metadata})},provider);return turns++,result}).then(result=>{busy=!1,send({type:"result",result})},error=>{busy=!1,send({type:"error",error:serializePluginExecutionError(error)})})})}
|
|
4
|
+
`)}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,pending]of this.pendingRequests)clearTimeout(pending.timer),pending.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 readFileSync4}from"node:fs";async function runCodexModel(request,context,provider=new CodexAgentProvider(()=>{},JSON.parse(readFileSync4(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,text,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,completed=new Promise((resolve,reject)=>{finish=resolve,fail=reject});completed.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")&&(text=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"})):text===void 0?fail(new Error("Model returned no final text")):(flush(),finish(text)))},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}),completed]);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 readFileSync5}from"node:fs";async function listCodexModels(signal,provider=new CodexAgentProvider(()=>{},JSON.parse(readFileSync5(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()}});import{createRequire}from"node:module";import{fileURLToPath}from"node:url";var require2=createRequire(import.meta.url),CLIENT_VERSION=require2("../package.json").version,PLUGIN_TASK_HOST_PATH=fileURLToPath(new URL("./plugin-task-host.js",import.meta.url)),PLUGIN_WORKER_PATH=fileURLToPath(new URL("./plugin-worker.js",import.meta.url)),SCRIPT_WORKER_PATH=fileURLToPath(new URL("./scriptWorker.js",import.meta.url)),PLUGIN_MODEL_SESSION_WORKER_PATH=fileURLToPath(new URL("./pluginModelSessionWorker.js",import.meta.url));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]))}}import{execFileSync,fork}from"node:child_process";import{fileURLToPath as fileURLToPath2}from"node:url";function supervisePluginExecutor(workerUrl){let child=fork(fileURLToPath2(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((resolve,reject)=>{if(!process.send||!process.connected){reject(new Error("Plugin owner disconnected"));return}process.send(message,error=>error?reject(error):resolve())})),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")supervisePluginExecutor(import.meta.url);else{let ready=Promise.resolve().then(()=>(init_codex(),codex_exports)).then(runtime=>({runtime,provider:new runtime.CodexAgentProvider(()=>{},CLIENT_VERSION)})),conversation={},busy=!1,turns=0,diagnostic={},send=value=>{process.connected&&process.send?.(value)};process.on("disconnect",()=>process.exit(1)),process.on("message",message=>{if(busy){process.exit(1);return}busy=!0,ready.then(async({runtime,provider})=>{send({type:"diagnostic",metadata:diagnostic}),turns>=32&&(conversation.threadId&&await provider.closeSession(conversation.threadId),delete conversation.threadId,turns=0);let result=await runtime.runCodexModel(message.request,{cwd:process.cwd(),conversation,signal:new AbortController().signal,onDiagnostic:metadata=>{for(let[key,value]of Object.entries(metadata))["retryCount","activeModel"].includes(key)||Object.assign(diagnostic,{[key]:value});send({type:"diagnostic",metadata})},onDelta:(delta,index,metadata)=>send({type:"delta",delta,index,metadata})},provider);return turns++,result}).then(result=>{busy=!1,send({type:"result",result})},error=>{busy=!1,send({type:"error",error:serializePluginExecutionError(error)})})})}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createNodePresetLoader, type PresetInstallerOptions } from '@mearl/setup/preset';
|
|
2
|
+
import { loadInstallationConfig } from '@mearl/preset/installation';
|
|
3
|
+
interface Dependencies {
|
|
4
|
+
directory: string;
|
|
5
|
+
invoke: NonNullable<PresetInstallerOptions['invoke']>;
|
|
6
|
+
extensionConnected: () => boolean;
|
|
7
|
+
browserSelection?: () => Promise<{
|
|
8
|
+
presetId?: string;
|
|
9
|
+
presetSource?: string;
|
|
10
|
+
}>;
|
|
11
|
+
configuration?: () => ReturnType<typeof loadInstallationConfig>;
|
|
12
|
+
now?: () => number;
|
|
13
|
+
load?: ReturnType<typeof createNodePresetLoader>;
|
|
14
|
+
log?: (...values: unknown[]) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Detached/CDP hosts update only an existing trusted selection; an attached extension owns its updates. */
|
|
17
|
+
export declare function createNativePresetAutoUpdater(dependencies: Dependencies): () => Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -31,5 +31,7 @@ export declare class PresetComponentInstaller {
|
|
|
31
31
|
private providerStatus;
|
|
32
32
|
private skillStatus;
|
|
33
33
|
status(revision: string): Promise<PresetComponentHostStatus>;
|
|
34
|
-
install(revision: string
|
|
34
|
+
install(revision: string, options?: {
|
|
35
|
+
replaceSkills?: readonly string[];
|
|
36
|
+
}): Promise<PresetComponentHostStatus>;
|
|
35
37
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ProviderAppResourceRequest, type ProviderAppResourceResponse, type ProviderEnhancementTarget } from '@mearl/browser-core';
|
|
2
|
+
import { NodePageRuntimeStore } from '@mearl/daemon-core/page-runtimes';
|
|
3
|
+
import type { PageRuntimeBinding } from '@mearl/preset/bundles';
|
|
4
|
+
import { type BrowserRecord } from './browser-registry.js';
|
|
5
|
+
/** Capture functions and definitions from one accepted installation; do not refresh Skill source. */
|
|
6
|
+
export declare function acceptedAppResources(): Promise<{
|
|
7
|
+
catalog: {
|
|
8
|
+
profiles: import("@mearl/browser-core").AppProfileCatalogEntry[];
|
|
9
|
+
errors: Array<{
|
|
10
|
+
plugin: string;
|
|
11
|
+
error: string;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
runtime: ((binding: PageRuntimeBinding) => string | undefined) | undefined;
|
|
15
|
+
defaultRuntime: (() => PageRuntimeBinding) | undefined;
|
|
16
|
+
revision: string | null;
|
|
17
|
+
installationRevision: string | null;
|
|
18
|
+
}>;
|
|
19
|
+
type Snapshot = Awaited<ReturnType<typeof acceptedAppResources>>;
|
|
20
|
+
interface Dependencies {
|
|
21
|
+
browsers(): BrowserRecord[];
|
|
22
|
+
verify(provider: BrowserRecord, tabId: number, deadline?: number): Promise<ProviderEnhancementTarget>;
|
|
23
|
+
snapshot(): Promise<Snapshot>;
|
|
24
|
+
store?: Pick<NodePageRuntimeStore, 'resolve'>;
|
|
25
|
+
}
|
|
26
|
+
/** Read-only resource preparation for a live external owner, separate from all page effects. */
|
|
27
|
+
export declare class ProviderAppResourceService {
|
|
28
|
+
private readonly dependencies;
|
|
29
|
+
constructor(dependencies: Dependencies);
|
|
30
|
+
invoke(owner: string, request: ProviderAppResourceRequest, deadline?: number): Promise<ProviderAppResourceResponse>;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -6,7 +6,7 @@ interface Dependencies {
|
|
|
6
6
|
request: (browser: BrowserRecord, action: string, data: any, origin: string, host?: ProviderHostContextData, deadline?: number) => Promise<any>;
|
|
7
7
|
notify: () => void;
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
9
|
+
/** Mearl sessions are the default; externally controlled Providers keep their own lifecycle. */
|
|
10
10
|
export declare class ProviderControlService {
|
|
11
11
|
private readonly dependencies;
|
|
12
12
|
private readonly deadlines;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type BrowserEnhancementRequest, type BrowserEnhancementResponse, type ProviderEnhancementRequest, type ProviderEnhancementResponse } from '@mearl/browser-core';
|
|
2
|
+
import type { BrowserRecord } from './browser-registry.js';
|
|
3
|
+
interface Dependencies {
|
|
4
|
+
browsers(): BrowserRecord[];
|
|
5
|
+
request(browser: BrowserRecord, action: string, data: any, deadline?: number): Promise<any>;
|
|
6
|
+
enhance(browser: BrowserRecord, provider: BrowserRecord, request: BrowserEnhancementRequest, deadline?: number, providerTabId?: number): Promise<BrowserEnhancementResponse>;
|
|
7
|
+
}
|
|
8
|
+
/** One bounded gateway for accepted Provider instances; no page action or code forwarding. */
|
|
9
|
+
export declare class ProviderEnhancementService {
|
|
10
|
+
private readonly dependencies;
|
|
11
|
+
private readonly bindings;
|
|
12
|
+
private readonly busy;
|
|
13
|
+
private pendingBindings;
|
|
14
|
+
constructor(dependencies: Dependencies);
|
|
15
|
+
private provider;
|
|
16
|
+
private verifyPage;
|
|
17
|
+
invoke(owner: string, request: ProviderEnhancementRequest, deadline?: number): Promise<ProviderEnhancementResponse>;
|
|
18
|
+
private mutate;
|
|
19
|
+
private negotiate;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/native-host",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.10",
|
|
4
4
|
"description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=20.18.0"
|
|
8
8
|
},
|
|
9
9
|
"main": "dist/install.js",
|
|
10
10
|
"types": "dist/install.d.ts",
|
|
@@ -48,20 +48,27 @@
|
|
|
48
48
|
"ws": "^8.18.3",
|
|
49
49
|
"@types/node": "^24.9.1",
|
|
50
50
|
"@types/ws": "^8.18.1",
|
|
51
|
-
"
|
|
52
|
-
"@mearl/
|
|
53
|
-
"@mearl/browser-core": "3.0.0-beta.
|
|
54
|
-
"@mearl/
|
|
55
|
-
"@mearl/
|
|
56
|
-
"@mearl/provider": "3.0.0-beta.
|
|
57
|
-
"@mearl/
|
|
58
|
-
"@mearl/
|
|
51
|
+
"tough-cookie": "^6.0.0",
|
|
52
|
+
"@mearl/app-profiles": "3.0.0-beta.10",
|
|
53
|
+
"@mearl/browser-core": "3.0.0-beta.10",
|
|
54
|
+
"@mearl/client": "3.0.0-beta.10",
|
|
55
|
+
"@mearl/daemon-core": "3.0.0-beta.10",
|
|
56
|
+
"@mearl/provider": "3.0.0-beta.10",
|
|
57
|
+
"@mearl/setup": "3.0.0-beta.10",
|
|
58
|
+
"@mearl/agent-runtime": "3.0.0-beta.10",
|
|
59
|
+
"@mearl/preset": "3.0.0-beta.10",
|
|
60
|
+
"@mearl/plugin-tracking": "3.0.0-beta.10"
|
|
59
61
|
},
|
|
60
62
|
"devDependencies": {
|
|
61
63
|
"@types/semver": "^7.7.1",
|
|
62
64
|
"esbuild": "^0.28.2",
|
|
63
65
|
"typescript": "^5.8.3"
|
|
64
66
|
},
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "git+https://github.com/mearlhq/mearl.git",
|
|
70
|
+
"directory": "packages/native-host"
|
|
71
|
+
},
|
|
65
72
|
"scripts": {
|
|
66
73
|
"build": "rm -rf dist/ && node build.mjs",
|
|
67
74
|
"typecheck": "tsc --noEmit",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type AlipayAuthCodeProgress = 'installing' | 'connected' | 'authorizing';
|
|
2
|
-
export interface AlipayAuthCodeParams {
|
|
3
|
-
appId: string;
|
|
4
|
-
scopeNicks: string[];
|
|
5
|
-
showErrorTip?: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare function validateAlipayAuthCodeParams(value: unknown): AlipayAuthCodeParams;
|
|
8
|
-
export declare function startAlipayAuthCode(value: unknown, onProgress?: (phase: AlipayAuthCodeProgress) => void): Promise<{
|
|
9
|
-
browserId: string;
|
|
10
|
-
qrSvg: string;
|
|
11
|
-
}>;
|
|
12
|
-
export declare function waitAlipayAuthCode(browserId: string, value: unknown, onProgress?: (phase: AlipayAuthCodeProgress) => void): Promise<Record<string, unknown>>;
|
|
13
|
-
export declare function closeAlipayAuthCode(browserId: string): Promise<void>;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/** Per-tab MTop gateway environment switching for direct CDP browsers. */
|
|
2
|
-
import type { MtopEnvironment, MtopEnvironmentTarget } from '@mearl/browser-core';
|
|
3
|
-
import type { PageSession } from './cdp-session.js';
|
|
4
|
-
export declare function setCdpMtopEnvironment(session: PageSession, target: MtopEnvironment): Promise<void>;
|
|
5
|
-
export declare function getCdpMtopEnvironment(session: PageSession): MtopEnvironmentTarget | undefined;
|
|
6
|
-
/** browser_release 使用:清除指定 tab 的 MTop 环境选择。 */
|
|
7
|
-
export declare function clearCdpMtopEnvironmentState(sessions?: Iterable<PageSession>): void;
|