@orcha-ai/runtime-bridge 0.1.49 → 0.1.50

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 CHANGED
@@ -80,7 +80,7 @@ Version 0.1.44 routes replies, native `message` tool sends, and background notif
80
80
 
81
81
  ```bash
82
82
  npm run pack:local
83
- npm publish ./dist/orcha-ai-runtime-bridge-0.1.49.tgz --access public --registry=https://registry.npmjs.org
83
+ npm publish ./dist/orcha-ai-runtime-bridge-0.1.50.tgz --access public --registry=https://registry.npmjs.org
84
84
  ```
85
85
 
86
86
  After updating the npm package on a device, run `orcha-runtime-bridge reload --url ...` to switch the existing background process to the installed version. `reload` and `restart` also install/update the bundled plugin for OpenClaw targets saved on that device, using the target's executable and environment. Bridge stops before `openclaw plugins install <bundled-path> --force` and `openclaw gateway restart`; it starts again only after Gateway health succeeds and any configured MCP binding endpoint passes native Channel protocol preflight. Targets sharing an executable and environment update together. Installation/restart/health failures stop the command with an error and leave Bridge stopped; fix the reported problem and rerun `reload`. Package/executable preflight failures leave the existing Bridge running. The earlier manually downloaded foreground process must be stopped before connecting with npm to avoid duplicate connections.
@@ -97,6 +97,8 @@ To check reply classification against the real SDK without installing or startin
97
97
 
98
98
  The OpenClaw channel sets the host's `suppressToolErrorWarnings` reply option to prevent synthesized tool-error warnings from becoming extra chat messages. Tool failures remain in the execution progress, and terminal error replies, delivery failures, timeouts, and empty-result checks keep their existing handling. Update the bundled plugin on the OpenClaw host and restart its Gateway for this change to take effect; publishing npm or deploying Core alone does not update an installed Gateway plugin.
99
99
 
100
+ Version 0.1.50 honors a terminal `NO_REPLY` after a confirmed message-tool delivery to the same conversation. It observes the active native session's visible assistant terminal through the host's synchronous `before_message_write` hook and official silent-reply classifier, preventing accumulated pre-tool text from becoming an extra final message. Normal follow-up replies, terminal errors, failed sends and other conversation targets retain their existing behavior. It does not read hidden reasoning or change protocol, persisted data or environment configuration. Update the installed plugin and restart Gateway after upgrading the package.
101
+
100
102
  Native reply previews use the host's `onPartialReply` callback. Growing snapshots emit `agent_message_chunk`; revised or cleared snapshots emit `agent_message_snapshot` with the complete preview in `content.text`, projected by Core as the existing `message_replace` event. Assistant message boundaries separate preview paragraphs. Block streaming is disabled so previews cannot consume final IM delivery. The final Bridge result remains a delivery receipt; only the IM sender persists the actual reply and attachments. This event addition requires the updated Core, Bridge and bundled plugin together; protocol version numbers are unchanged, with no database migration or new environment variable. Existing installed plugins need an explicit update and Gateway restart.
101
103
 
102
104
  Version 0.1.48 includes these native reply previews. Deploy Core with commit `3c165340` or later before upgrading connected devices, then reload Bridge to update its bundled Gateway plugin.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{spawn as fc}from"node:child_process";import{closeSync as pc,existsSync as Rr,mkdirSync as hc,openSync as mc,readFileSync as yr,rmSync as gc,statSync as ls,writeFileSync as ms}from"node:fs";import{dirname as gs,resolve as mt}from"node:path";import{fileURLToPath as _c}from"node:url";import{createHash as Pr}from"node:crypto";import{mkdir as Ms,readFile as Us,writeFile as Ps,rename as Ls}from"node:fs/promises";import{join as Mr}from"node:path";import{homedir as ks,hostname as vs}from"node:os";import{execFile as Is}from"node:child_process";import{access as Cs,realpath as xs}from"node:fs/promises";import{constants as As}from"node:fs";import{delimiter as Ns,join as Ar,isAbsolute as Nr}from"node:path";import{homedir as xr}from"node:os";async function he(e,t=process.env){let r=process.platform==="win32"?[".exe",".cmd",".bat",""]:[""];for(let n of(t.PATH||"").split(Ns).filter(Nr))for(let s of r){let i=Ar(n,`${e}${s}`);try{return await Cs(i,As.X_OK),i}catch{}}return null}function bs(e,t){return new Promise(r=>Is(e,t,{timeout:8e3,maxBuffer:1024*1024,windowsHide:!0},(n,s)=>r({code:n?n.code:0,stdout:String(s||"")})))}async function me(e){let t=e==="~"?xr():e.startsWith("~/")?Ar(xr(),e.slice(2)):e;if(!Nr(t))throw new Error("\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u8BBE\u5907\u4E0A\u7684\u7EDD\u5BF9\u8DEF\u5F84\u6216 ~/ \u5F00\u5934\u7684\u8DEF\u5F84");let r=await xs(t),{stat:n}=await import("node:fs/promises");if(!(await n(r)).isDirectory())throw new Error("\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6\u5939");return r}async function br({find:e=he,run:t=bs,cwd:r=process.cwd()}={}){return(await Promise.all(["codex","claude","openclaw"].map(async s=>{let i=await e(s);if(!i)return[];let o={codex:"Codex",claude:"Claude Code",openclaw:"OpenClaw"}[s],a=await t(i,["--version"]),u=a.code===0&&a.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0]||"",d={id:s,name:o,framework:s,version:u,workspace:r,managed:!1};if(a.code!==0)return[{...d,status:"error",message:"\u7A0B\u5E8F\u65E0\u6CD5\u542F\u52A8\uFF0C\u8BF7\u5728\u672C\u673A\u68C0\u67E5\u5B89\u88C5"}];if(s==="openclaw"){let h=await t(i,["agents","list","--json"]),m;try{m=JSON.parse(h.stdout)}catch{}if(h.code!==0||!Array.isArray(m))return[{...d,status:"error",message:"\u65E0\u6CD5\u8BFB\u53D6 OpenClaw \u667A\u80FD\u4F53\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u914D\u7F6E"}];let T=await t(i,["health","--json"]);return m.filter(S=>typeof S.id=="string"&&typeof S.workspace=="string").slice(0,32).map(S=>({...d,id:`openclaw:${S.id}`,name:S.name||S.identityName||S.id,workspace:S.workspace,managed:!0,localAgentId:S.id,command:i,status:T.code===0?"ready":"needs_setup",message:T.code===0?"":"\u8BF7\u5148\u5728\u672C\u673A\u542F\u52A8\u5E76\u914D\u7F6E OpenClaw Gateway"}))}let f=await t(i,s==="codex"?["login","status"]:["auth","status"]),p=f.code===0?"ready":f.code===1?"needs_login":"error";return[{...d,command:i,status:p,message:p==="needs_login"?`\u8BF7\u5728\u672C\u673A\u8FD0\u884C ${s} ${s==="codex"?"login":"auth login"}`:p==="error"?"\u767B\u5F55\u72B6\u6001\u68C0\u6D4B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 CLI \u7248\u672C":""}]}))).flat()}async function Ur(e,t){let r=`${e}.${process.pid}.tmp`;await Ps(r,JSON.stringify(t),{mode:384}),await Ls(r,e)}function _e(e){let t=new URL(e);if(t.username||t.password||t.search||t.hash||t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw new Error("\u8FDE\u63A5\u5730\u5740\u5FC5\u987B\u4F7F\u7528 HTTPS\uFF1B\u4EC5\u672C\u673A\u5F00\u53D1\u5141\u8BB8 HTTP");let r=Mr(ks(),".orcha","devices"),n=Mr(r,Pr("sha256").update(t.toString()).digest("hex").slice(0,20));return{address:t,root:r,profile:`${n}.json`,pidFile:`${n}.pid`,logFile:`${n}.log`}}async function Mt(e,{url:t,pairCode:r}){let{address:n,root:s,profile:i}=_e(t||e.orchaUrl);await Ms(s,{recursive:!0,mode:448});let o;if(r){let a=await fetch(new URL("api/agent-devices/pairings/exchange",`${n.toString().replace(/\/+$/,"")}/`),{method:"POST",redirect:"error",headers:{"content-type":"application/json"},signal:AbortSignal.timeout(15e3),body:JSON.stringify({code:r,name:vs()})}),u=await a.json();if(!a.ok||!u.success)throw new Error(u.message||u.detail||"\u8BBE\u5907\u8FDE\u63A5\u5931\u8D25");o={...u.data,targets:{}},await Ur(i,o)}else try{o=JSON.parse(await Us(i,"utf8"))}catch{throw new Error("\u6CA1\u6709\u5DF2\u8FDE\u63A5\u8BBE\u5907\uFF0C\u8BF7\u4ECE\u667A\u80FD\u4F53\u9875\u9762\u751F\u6210\u8FDE\u63A5\u7801")}e.orchaUrl=n.toString().replace(/\/+$/,""),e.mode="node",e.nodeId=o.nodeCode,e.nodeName=o.nodeName,e.nodeToken=o.token,e.targets=o.targets,e.defaultTargetCode="",e.deviceConnection=new ge(e,o,async()=>Ur(i,o))}var ge=class{constructor(t,r,n,s=br){this.config=t,this.profile=r,this.persist=n,this.discover=s}async candidates(){return{candidates:(await this.discover()).map(({command:r,localAgentId:n,...s})=>s)}}async configure(t,r){if(!Array.isArray(t.selections)||!t.selections.length||t.selections.length>32)throw new Error("\u6DFB\u52A0\u9879\u65E0\u6548");let n=new Map((await this.discover()).map(u=>[u.id,u])),s={...r.targets},i=[],o=new Set;for(let u of t.selections){let d=n.get(u.candidateId);if(!d||d.status!=="ready"||o.has(d.id))throw new Error("\u53D1\u73B0\u7ED3\u679C\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u68C0\u6D4B");o.add(d.id);let f=String(u.name||"").trim();if(!f||f.length>128)throw new Error("\u667A\u80FD\u4F53\u540D\u79F0\u65E0\u6548");let p=await me(String(u.workspace||""));if(d.managed&&p!==await me(d.workspace))throw new Error("\u5DF2\u6709\u667A\u80FD\u4F53\u5FC5\u987B\u6CBF\u7528\u672C\u673A\u5DE5\u4F5C\u76EE\u5F55");let h=`${this.config.nodeId}:${Pr("sha256").update(d.id).digest("hex").slice(0,20)}`;if([...r.sessions.values()].some(m=>m.targetCode===h))throw new Error("\u6B64\u667A\u80FD\u4F53\u4ECD\u6709\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u7ED3\u675F\u4F1A\u8BDD\u518D\u4FEE\u6539\u63A5\u5165");s[h]={name:f,workspace:p,command:d.command,type:d.managed?"openclaw":"cli",...d.managed?{openclawAgentId:d.localAgentId}:d.framework==="codex"?{terminalProtocol:"codex",args:["exec","--skip-git-repo-check","--json"],promptMode:"stdin",outputMode:"json-lines",captureLastMessage:!0}:{terminalProtocol:"claude",args:["-p","--output-format","json","--no-session-persistence"],promptMode:"args",outputMode:"json-lines"}},i.push({candidateId:d.id,name:f,workspace:p,targetCode:h,framework:d.framework})}let a=this.profile.targets;this.profile.targets=s;try{await this.persist()}catch(u){throw this.profile.targets=a,u}return r.targets=s,this.config.targets=s,r.notifyCapacityChanged(),{agents:i}}};import{execFile as Xs}from"node:child_process";import{constants as Ys}from"node:fs";import{access as jr,readFile as qr,realpath as Qs}from"node:fs/promises";import{join as Te}from"node:path";import{promisify as Zs}from"node:util";var J="0.1.49";function yt(){return new Date().toISOString()}function P(e,t=2){return String(e).padStart(t,"0")}function Lr(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${P(Math.floor(r/60))}:${P(r%60)}`}function Ds(e){let t=-e.getTimezoneOffset();return[`${e.getFullYear()}-${P(e.getMonth()+1)}-${P(e.getDate())}`,`T${P(e.getHours())}:${P(e.getMinutes())}:${P(e.getSeconds())}.${P(e.getMilliseconds(),3)}`,Lr(t)].join("")}function Hs(e,t){let r=new Intl.DateTimeFormat("en-US",{timeZone:t,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}),n={};for(let s of r.formatToParts(e))s.type!=="literal"&&(n[s.type]=Number(s.value));return n}function Fs(e,t){let r=Hs(e,t),n=Date.UTC(r.year,r.month-1,r.day,r.hour,r.minute,r.second,e.getMilliseconds()),s=Math.round((n-e.getTime())/6e4);return[`${r.year}-${P(r.month)}-${P(r.day)}`,`T${P(r.hour)}:${P(r.minute)}:${P(r.second)}.${P(e.getMilliseconds(),3)}`,Lr(s)].join("")}function $s(e=new Date){let t=c(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return Fs(e,t)}catch{return Ds(e)}}function l(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function c(e){return String(e??"").trim()}function y(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)?r:t}function A(e){return Array.isArray(e)?e.map(String):[]}function et(e,t,r=process.cwd()){let n=l(e)?e:{};return c(n.cwd)||c(n.workspace)||c(t)||c(r)||process.cwd()}var Ut="[redacted]",Bs=/(authorization|api[_-]?key|credential|password|secret|token)/i;function V(e){return Bs.test(c(e))}function ut(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(Ut))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${Ut}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${Ut}`)}function tt(e,t=new WeakSet){if(e==null)return e;if(typeof e=="bigint")return e.toString();if(typeof e!="object")return e;if(e instanceof Date)return e.toISOString();if(e instanceof Error){if(t.has(e))return"[circular]";t.add(e);let s={name:e.name,message:e.message};e.stack&&(s.stack=e.stack);for(let i of Object.keys(e))s[i]=tt(e[i],t);return t.delete(e),s}if(t.has(e))return"[circular]";if(t.add(e),Array.isArray(e)){let s=e.map(i=>tt(i,t));return t.delete(e),s}let r={},n=V(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=V(s)||n&&s.toLowerCase()==="value"?Ut:tt(i,t);return t.delete(e),r}function kr(e,t=4e3){let r=JSON.stringify(tt(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function g(e,t,r,n={}){let s={ts:$s(),level:e,module:t,msg:r,...l(n)?tt(n):{}};console.error(JSON.stringify(s))}var rt="application/x-orcha-channel-events-v2+ndjson";function M(e,t){return Object.assign(new Error(t||(["run_timeout","RUNTIME_NODE_TIMEOUT"].includes(e)?"OpenClaw \u539F\u751F IM \u6267\u884C\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002":e==="OPENCLAW_CHANNEL_PROTOCOL_MISMATCH"?"OpenClaw \u63D2\u4EF6\u4E0E Bridge \u7684\u539F\u751F IM \u534F\u8BAE\u4E0D\u517C\u5BB9\uFF0C\u8BF7\u914D\u5957\u5347\u7EA7\u3002":`OpenClaw \u539F\u751F IM \u6267\u884C\u5931\u8D25\uFF08${e}\uFF09`)),{code:e})}function vr(e,t){let r=e.cause?.code||e.code;return t?.reason?.name==="TimeoutError"||e.name==="TimeoutError"||["UND_ERR_HEADERS_TIMEOUT","UND_ERR_BODY_TIMEOUT","UND_ERR_CONNECT_TIMEOUT","ETIMEDOUT"].includes(r)?Object.assign(M("RUNTIME_NODE_TIMEOUT","OpenClaw \u8FDE\u63A5\u6216\u7B49\u5F85\u54CD\u5E94\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002"),{detail:{causeCode:r||"REQUEST_TIMEOUT"}}):e}async function Dr(e,t){if(e.headers.get("content-type")!==rt)throw await e.body?.cancel(),M("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH");let r=Buffer.alloc(0);for await(let n of e.body){r=Buffer.concat([r,n]);let s;for(;(s=r.indexOf(10))>=0;){if(s>2097152)throw M("OPENCLAW_CHANNEL_FRAME_TOO_LARGE");let i=r.subarray(0,s).toString("utf8");r=r.subarray(s+1);let o;try{o=JSON.parse(i)}catch{throw M("OPENCLAW_CHANNEL_INVALID_FRAME")}if(o.type!=="heartbeat")if(o.type==="update"&&o.payload?.update&&o.payload?._meta?.channelUpdateId)await t(o.payload);else{if(o.type==="result"&&o.result?.stopReason)return o.result;throw o.type==="error"&&typeof o.code=="string"?M(o.code):M("OPENCLAW_CHANNEL_INVALID_FRAME")}}if(r.length>2097152)throw M("OPENCLAW_CHANNEL_FRAME_TOO_LARGE")}throw M("OPENCLAW_CHANNEL_STREAM_INTERRUPTED","OpenClaw \u8FC7\u7A0B\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u672A\u6536\u5230\u4EFB\u52A1\u7EC8\u6001\uFF0C\u8BF7\u68C0\u67E5\u8282\u70B9\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002")}import{createServer as qs}from"node:http";import{randomBytes as Gs}from"node:crypto";var Pt={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs","knowledge_search"]};var Ks=Object.freeze([...Pt.controlTools,...Pt.residentTools]),zs=new Set(Ks),Vs=8*1024*1024;function Lt(e,t){if(!Array.isArray(e)||e.length!==1)throw new Error("one task-scoped Orcha MCP server is required");let r=e[0],n=new URL(r.url);if(r.name!=="orcha"||r.type!=="http"||!["http:","https:"].includes(n.protocol)||n.username||n.password||n.hash||t&&n.href!==new URL(t).href)throw new Error("Orcha MCP server does not match the trusted binding");let s=Object.fromEntries((r.headers||[]).map(({name:i,value:o})=>[i.toLowerCase(),o]));if(!String(s.authorization||"").startsWith("Bearer "))throw new Error("Orcha MCP task credentials are missing");return{url:n.href,headers:{...s,"content-type":"application/json",accept:"application/json"}}}async function Fr(e){let t=0,r=[];for await(let n of e){if(t+=n.length,t>Vs)throw new Error("MCP payload exceeds the size limit");r.push(Buffer.from(n))}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function $r(e,t,r){let n=await fetch(e.url,{method:"POST",headers:e.headers,body:JSON.stringify(t),redirect:"error",signal:AbortSignal.any([AbortSignal.timeout(36e5),...r?[r]:[]])});if(!n.ok)throw new Error(`Orcha MCP request failed (${n.status})`);if(n.status===202||n.status===204)return null;let s=await Fr(n.body);if(!s||s.jsonrpc!=="2.0"||s.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return s}async function Hr(e,t){let r=await $r(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},t),n=r?.result?.tools;if(r?.error){let s=Object.entries(e.headers).filter(([a])=>V(a)).flatMap(([,a])=>[a,String(a).replace(/^Bearer\s+/i,"")]),i=typeof r.error.message=="string"?ut(r.error.message,s).slice(0,512):"",o=Number.isInteger(r.error.code)?` (${r.error.code})`:"";throw new Error(`Orcha MCP tool discovery failed${o}${i?`: ${i}`:""}`)}return Js(n)}function Js(e){if(!Array.isArray(e)||e.some(t=>!t||!zs.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&Pt.controlTools.some(t=>!e.some(r=>r.name===t)))throw new Error("Orcha MCP returned an unsupported or invalid authorized tool catalog");return e}function Ws(e,t){let r=s=>Array.isArray(s)?s.map(r):s&&typeof s=="object"?Object.fromEntries(Object.keys(s).sort().map(i=>[i,r(s[i])])):s,n=s=>s.map(({name:i,inputSchema:o})=>({name:i,inputSchema:o})).sort((i,o)=>i.name.localeCompare(o.name));return JSON.stringify(r(n(e)))===JSON.stringify(r(n(t)))}async function Br(e){let t=Lt(e),r=new AbortController,n=await Hr(t,r.signal),s=Gs(32).toString("hex"),i=qs(async(o,a)=>{if(o.url!=="/mcp"||o.headers.authorization!==`Bearer ${s}`){a.writeHead(403).end();return}if(o.method!=="POST"){a.writeHead(405).end();return}try{let u=await Fr(o);if(!u||u.jsonrpc!=="2.0"||typeof u.method!="string")throw new Error("Invalid MCP request");if(u.method==="tools/call"&&!n.some(f=>f.name===u.params?.name))throw new Error("Tool is not authorized in this task binding");let d=await $r(t,u,r.signal);a.writeHead(d===null?202:200,{"content-type":"application/json"}),a.end(d===null?"":JSON.stringify(d))}catch{a.writeHead(502,{"content-type":"application/json"}).end(JSON.stringify({error:"The task-scoped Orcha MCP connection failed"}))}});return await new Promise((o,a)=>{i.once("error",a),i.listen(0,"127.0.0.1",o)}),{url:`http://127.0.0.1:${i.address().port}/mcp`,token:s,async refresh(o){let a=Lt(o,t.url);if(!Ws(n,await Hr(a,r.signal)))throw new Error("The frozen MCP tool catalog changed; start a new task");t=a},async close(){r.abort(),i.closeAllConnections(),await new Promise(o=>i.close(o))}}}var W=class{constructor(t,r){this.target=t,this.identity=r,this.bound=!1}async request(t,r,n=!1,s="mcp-bindings",i=3e4,o=null){let a=c(this.target.mcpBridgeUrl),u=c(this.target.mcpBridgeTokenEnv),d=this.target.env?.[u]||process.env[u];if(!a||!u||!d)throw Object.assign(new Error("OpenClaw requires the Orcha tool plugin, mcpBridgeUrl and mcpBridgeTokenEnv"),{code:"OPENCLAW_MCP_NOT_CONFIGURED"});let f=new URL(a);if(!["http:","https:"].includes(f.protocol)||f.username||f.password||f.pathname!=="/plugins/orcha-runtime/mcp-bindings"||f.search||f.hash)throw new Error("OpenClaw MCP binding URL must be the trusted Gateway plugin route");if(!["mcp-bindings","deliveries","background"].includes(s))throw new Error("Unsupported Orcha plugin route");f.pathname=`/plugins/orcha-runtime/${s}`;let p=AbortSignal.timeout(i);try{let h=await fetch(f,{method:t,redirect:"error",signal:p,headers:{authorization:`Bearer ${d}`,"content-type":"application/json",...o?{accept:rt}:{},...n?{"if-match":this.identity.runId}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});if(t==="GET"&&s==="deliveries"&&[404,405].includes(h.status))throw await h.body?.cancel(),M("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH");if(h.ok&&o)return await Dr(h,o);let m=await h.json();if(!h.ok)throw M(m.error||"OPENCLAW_MCP_BINDING_FAILED");return m}catch(h){throw vr(h,p)}}async bind(t,r=!1){Lt(t),await this.request("PUT",{...this.identity,mcpServer:t[0]},r),this.bound=!0}async close(){this.bound&&(await this.request("DELETE",{runId:this.identity.runId,sessionKey:this.identity.sessionKey}),this.bound=!1)}};var ti=Zs(Xs),ei=12e4;async function Gr(e,t){let r=new Map,n=[];for(let s of Object.values(e)){if(s.type!=="openclaw")continue;if(s.mcpBridgeUrl&&(n.push(s),!["localhost","127.0.0.1","[::1]"].includes(new URL(s.mcpBridgeUrl).hostname))){process.stderr.write(`\u8FDC\u7A0B OpenClaw Gateway \u7684\u914D\u5957\u63D2\u4EF6\u9700\u5728\u6240\u5728\u4E3B\u673A\u66F4\u65B0\uFF1Breload \u5C06\u68C0\u67E5\u5176\u534F\u8BAE\u3002
2
+ import{spawn as fc}from"node:child_process";import{closeSync as pc,existsSync as Rr,mkdirSync as hc,openSync as mc,readFileSync as yr,rmSync as gc,statSync as ls,writeFileSync as ms}from"node:fs";import{dirname as gs,resolve as mt}from"node:path";import{fileURLToPath as _c}from"node:url";import{createHash as Pr}from"node:crypto";import{mkdir as Ms,readFile as Us,writeFile as Ps,rename as Ls}from"node:fs/promises";import{join as Mr}from"node:path";import{homedir as ks,hostname as vs}from"node:os";import{execFile as Is}from"node:child_process";import{access as Cs,realpath as xs}from"node:fs/promises";import{constants as As}from"node:fs";import{delimiter as Ns,join as Ar,isAbsolute as Nr}from"node:path";import{homedir as xr}from"node:os";async function he(e,t=process.env){let r=process.platform==="win32"?[".exe",".cmd",".bat",""]:[""];for(let n of(t.PATH||"").split(Ns).filter(Nr))for(let s of r){let i=Ar(n,`${e}${s}`);try{return await Cs(i,As.X_OK),i}catch{}}return null}function bs(e,t){return new Promise(r=>Is(e,t,{timeout:8e3,maxBuffer:1024*1024,windowsHide:!0},(n,s)=>r({code:n?n.code:0,stdout:String(s||"")})))}async function me(e){let t=e==="~"?xr():e.startsWith("~/")?Ar(xr(),e.slice(2)):e;if(!Nr(t))throw new Error("\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u8BBE\u5907\u4E0A\u7684\u7EDD\u5BF9\u8DEF\u5F84\u6216 ~/ \u5F00\u5934\u7684\u8DEF\u5F84");let r=await xs(t),{stat:n}=await import("node:fs/promises");if(!(await n(r)).isDirectory())throw new Error("\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6\u5939");return r}async function br({find:e=he,run:t=bs,cwd:r=process.cwd()}={}){return(await Promise.all(["codex","claude","openclaw"].map(async s=>{let i=await e(s);if(!i)return[];let o={codex:"Codex",claude:"Claude Code",openclaw:"OpenClaw"}[s],a=await t(i,["--version"]),u=a.code===0&&a.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0]||"",d={id:s,name:o,framework:s,version:u,workspace:r,managed:!1};if(a.code!==0)return[{...d,status:"error",message:"\u7A0B\u5E8F\u65E0\u6CD5\u542F\u52A8\uFF0C\u8BF7\u5728\u672C\u673A\u68C0\u67E5\u5B89\u88C5"}];if(s==="openclaw"){let h=await t(i,["agents","list","--json"]),m;try{m=JSON.parse(h.stdout)}catch{}if(h.code!==0||!Array.isArray(m))return[{...d,status:"error",message:"\u65E0\u6CD5\u8BFB\u53D6 OpenClaw \u667A\u80FD\u4F53\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u914D\u7F6E"}];let T=await t(i,["health","--json"]);return m.filter(S=>typeof S.id=="string"&&typeof S.workspace=="string").slice(0,32).map(S=>({...d,id:`openclaw:${S.id}`,name:S.name||S.identityName||S.id,workspace:S.workspace,managed:!0,localAgentId:S.id,command:i,status:T.code===0?"ready":"needs_setup",message:T.code===0?"":"\u8BF7\u5148\u5728\u672C\u673A\u542F\u52A8\u5E76\u914D\u7F6E OpenClaw Gateway"}))}let f=await t(i,s==="codex"?["login","status"]:["auth","status"]),p=f.code===0?"ready":f.code===1?"needs_login":"error";return[{...d,command:i,status:p,message:p==="needs_login"?`\u8BF7\u5728\u672C\u673A\u8FD0\u884C ${s} ${s==="codex"?"login":"auth login"}`:p==="error"?"\u767B\u5F55\u72B6\u6001\u68C0\u6D4B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 CLI \u7248\u672C":""}]}))).flat()}async function Ur(e,t){let r=`${e}.${process.pid}.tmp`;await Ps(r,JSON.stringify(t),{mode:384}),await Ls(r,e)}function _e(e){let t=new URL(e);if(t.username||t.password||t.search||t.hash||t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw new Error("\u8FDE\u63A5\u5730\u5740\u5FC5\u987B\u4F7F\u7528 HTTPS\uFF1B\u4EC5\u672C\u673A\u5F00\u53D1\u5141\u8BB8 HTTP");let r=Mr(ks(),".orcha","devices"),n=Mr(r,Pr("sha256").update(t.toString()).digest("hex").slice(0,20));return{address:t,root:r,profile:`${n}.json`,pidFile:`${n}.pid`,logFile:`${n}.log`}}async function Mt(e,{url:t,pairCode:r}){let{address:n,root:s,profile:i}=_e(t||e.orchaUrl);await Ms(s,{recursive:!0,mode:448});let o;if(r){let a=await fetch(new URL("api/agent-devices/pairings/exchange",`${n.toString().replace(/\/+$/,"")}/`),{method:"POST",redirect:"error",headers:{"content-type":"application/json"},signal:AbortSignal.timeout(15e3),body:JSON.stringify({code:r,name:vs()})}),u=await a.json();if(!a.ok||!u.success)throw new Error(u.message||u.detail||"\u8BBE\u5907\u8FDE\u63A5\u5931\u8D25");o={...u.data,targets:{}},await Ur(i,o)}else try{o=JSON.parse(await Us(i,"utf8"))}catch{throw new Error("\u6CA1\u6709\u5DF2\u8FDE\u63A5\u8BBE\u5907\uFF0C\u8BF7\u4ECE\u667A\u80FD\u4F53\u9875\u9762\u751F\u6210\u8FDE\u63A5\u7801")}e.orchaUrl=n.toString().replace(/\/+$/,""),e.mode="node",e.nodeId=o.nodeCode,e.nodeName=o.nodeName,e.nodeToken=o.token,e.targets=o.targets,e.defaultTargetCode="",e.deviceConnection=new ge(e,o,async()=>Ur(i,o))}var ge=class{constructor(t,r,n,s=br){this.config=t,this.profile=r,this.persist=n,this.discover=s}async candidates(){return{candidates:(await this.discover()).map(({command:r,localAgentId:n,...s})=>s)}}async configure(t,r){if(!Array.isArray(t.selections)||!t.selections.length||t.selections.length>32)throw new Error("\u6DFB\u52A0\u9879\u65E0\u6548");let n=new Map((await this.discover()).map(u=>[u.id,u])),s={...r.targets},i=[],o=new Set;for(let u of t.selections){let d=n.get(u.candidateId);if(!d||d.status!=="ready"||o.has(d.id))throw new Error("\u53D1\u73B0\u7ED3\u679C\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u68C0\u6D4B");o.add(d.id);let f=String(u.name||"").trim();if(!f||f.length>128)throw new Error("\u667A\u80FD\u4F53\u540D\u79F0\u65E0\u6548");let p=await me(String(u.workspace||""));if(d.managed&&p!==await me(d.workspace))throw new Error("\u5DF2\u6709\u667A\u80FD\u4F53\u5FC5\u987B\u6CBF\u7528\u672C\u673A\u5DE5\u4F5C\u76EE\u5F55");let h=`${this.config.nodeId}:${Pr("sha256").update(d.id).digest("hex").slice(0,20)}`;if([...r.sessions.values()].some(m=>m.targetCode===h))throw new Error("\u6B64\u667A\u80FD\u4F53\u4ECD\u6709\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u7ED3\u675F\u4F1A\u8BDD\u518D\u4FEE\u6539\u63A5\u5165");s[h]={name:f,workspace:p,command:d.command,type:d.managed?"openclaw":"cli",...d.managed?{openclawAgentId:d.localAgentId}:d.framework==="codex"?{terminalProtocol:"codex",args:["exec","--skip-git-repo-check","--json"],promptMode:"stdin",outputMode:"json-lines",captureLastMessage:!0}:{terminalProtocol:"claude",args:["-p","--output-format","json","--no-session-persistence"],promptMode:"args",outputMode:"json-lines"}},i.push({candidateId:d.id,name:f,workspace:p,targetCode:h,framework:d.framework})}let a=this.profile.targets;this.profile.targets=s;try{await this.persist()}catch(u){throw this.profile.targets=a,u}return r.targets=s,this.config.targets=s,r.notifyCapacityChanged(),{agents:i}}};import{execFile as Xs}from"node:child_process";import{constants as Ys}from"node:fs";import{access as jr,readFile as qr,realpath as Qs}from"node:fs/promises";import{join as Te}from"node:path";import{promisify as Zs}from"node:util";var J="0.1.50";function yt(){return new Date().toISOString()}function P(e,t=2){return String(e).padStart(t,"0")}function Lr(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${P(Math.floor(r/60))}:${P(r%60)}`}function Ds(e){let t=-e.getTimezoneOffset();return[`${e.getFullYear()}-${P(e.getMonth()+1)}-${P(e.getDate())}`,`T${P(e.getHours())}:${P(e.getMinutes())}:${P(e.getSeconds())}.${P(e.getMilliseconds(),3)}`,Lr(t)].join("")}function Hs(e,t){let r=new Intl.DateTimeFormat("en-US",{timeZone:t,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}),n={};for(let s of r.formatToParts(e))s.type!=="literal"&&(n[s.type]=Number(s.value));return n}function Fs(e,t){let r=Hs(e,t),n=Date.UTC(r.year,r.month-1,r.day,r.hour,r.minute,r.second,e.getMilliseconds()),s=Math.round((n-e.getTime())/6e4);return[`${r.year}-${P(r.month)}-${P(r.day)}`,`T${P(r.hour)}:${P(r.minute)}:${P(r.second)}.${P(e.getMilliseconds(),3)}`,Lr(s)].join("")}function $s(e=new Date){let t=c(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return Fs(e,t)}catch{return Ds(e)}}function l(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function c(e){return String(e??"").trim()}function y(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)?r:t}function A(e){return Array.isArray(e)?e.map(String):[]}function et(e,t,r=process.cwd()){let n=l(e)?e:{};return c(n.cwd)||c(n.workspace)||c(t)||c(r)||process.cwd()}var Ut="[redacted]",Bs=/(authorization|api[_-]?key|credential|password|secret|token)/i;function V(e){return Bs.test(c(e))}function ut(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(Ut))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${Ut}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${Ut}`)}function tt(e,t=new WeakSet){if(e==null)return e;if(typeof e=="bigint")return e.toString();if(typeof e!="object")return e;if(e instanceof Date)return e.toISOString();if(e instanceof Error){if(t.has(e))return"[circular]";t.add(e);let s={name:e.name,message:e.message};e.stack&&(s.stack=e.stack);for(let i of Object.keys(e))s[i]=tt(e[i],t);return t.delete(e),s}if(t.has(e))return"[circular]";if(t.add(e),Array.isArray(e)){let s=e.map(i=>tt(i,t));return t.delete(e),s}let r={},n=V(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=V(s)||n&&s.toLowerCase()==="value"?Ut:tt(i,t);return t.delete(e),r}function kr(e,t=4e3){let r=JSON.stringify(tt(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function g(e,t,r,n={}){let s={ts:$s(),level:e,module:t,msg:r,...l(n)?tt(n):{}};console.error(JSON.stringify(s))}var rt="application/x-orcha-channel-events-v2+ndjson";function M(e,t){return Object.assign(new Error(t||(["run_timeout","RUNTIME_NODE_TIMEOUT"].includes(e)?"OpenClaw \u539F\u751F IM \u6267\u884C\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002":e==="OPENCLAW_CHANNEL_PROTOCOL_MISMATCH"?"OpenClaw \u63D2\u4EF6\u4E0E Bridge \u7684\u539F\u751F IM \u534F\u8BAE\u4E0D\u517C\u5BB9\uFF0C\u8BF7\u914D\u5957\u5347\u7EA7\u3002":`OpenClaw \u539F\u751F IM \u6267\u884C\u5931\u8D25\uFF08${e}\uFF09`)),{code:e})}function vr(e,t){let r=e.cause?.code||e.code;return t?.reason?.name==="TimeoutError"||e.name==="TimeoutError"||["UND_ERR_HEADERS_TIMEOUT","UND_ERR_BODY_TIMEOUT","UND_ERR_CONNECT_TIMEOUT","ETIMEDOUT"].includes(r)?Object.assign(M("RUNTIME_NODE_TIMEOUT","OpenClaw \u8FDE\u63A5\u6216\u7B49\u5F85\u54CD\u5E94\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002"),{detail:{causeCode:r||"REQUEST_TIMEOUT"}}):e}async function Dr(e,t){if(e.headers.get("content-type")!==rt)throw await e.body?.cancel(),M("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH");let r=Buffer.alloc(0);for await(let n of e.body){r=Buffer.concat([r,n]);let s;for(;(s=r.indexOf(10))>=0;){if(s>2097152)throw M("OPENCLAW_CHANNEL_FRAME_TOO_LARGE");let i=r.subarray(0,s).toString("utf8");r=r.subarray(s+1);let o;try{o=JSON.parse(i)}catch{throw M("OPENCLAW_CHANNEL_INVALID_FRAME")}if(o.type!=="heartbeat")if(o.type==="update"&&o.payload?.update&&o.payload?._meta?.channelUpdateId)await t(o.payload);else{if(o.type==="result"&&o.result?.stopReason)return o.result;throw o.type==="error"&&typeof o.code=="string"?M(o.code):M("OPENCLAW_CHANNEL_INVALID_FRAME")}}if(r.length>2097152)throw M("OPENCLAW_CHANNEL_FRAME_TOO_LARGE")}throw M("OPENCLAW_CHANNEL_STREAM_INTERRUPTED","OpenClaw \u8FC7\u7A0B\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u672A\u6536\u5230\u4EFB\u52A1\u7EC8\u6001\uFF0C\u8BF7\u68C0\u67E5\u8282\u70B9\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002")}import{createServer as qs}from"node:http";import{randomBytes as Gs}from"node:crypto";var Pt={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs","knowledge_search"]};var Ks=Object.freeze([...Pt.controlTools,...Pt.residentTools]),zs=new Set(Ks),Vs=8*1024*1024;function Lt(e,t){if(!Array.isArray(e)||e.length!==1)throw new Error("one task-scoped Orcha MCP server is required");let r=e[0],n=new URL(r.url);if(r.name!=="orcha"||r.type!=="http"||!["http:","https:"].includes(n.protocol)||n.username||n.password||n.hash||t&&n.href!==new URL(t).href)throw new Error("Orcha MCP server does not match the trusted binding");let s=Object.fromEntries((r.headers||[]).map(({name:i,value:o})=>[i.toLowerCase(),o]));if(!String(s.authorization||"").startsWith("Bearer "))throw new Error("Orcha MCP task credentials are missing");return{url:n.href,headers:{...s,"content-type":"application/json",accept:"application/json"}}}async function Fr(e){let t=0,r=[];for await(let n of e){if(t+=n.length,t>Vs)throw new Error("MCP payload exceeds the size limit");r.push(Buffer.from(n))}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function $r(e,t,r){let n=await fetch(e.url,{method:"POST",headers:e.headers,body:JSON.stringify(t),redirect:"error",signal:AbortSignal.any([AbortSignal.timeout(36e5),...r?[r]:[]])});if(!n.ok)throw new Error(`Orcha MCP request failed (${n.status})`);if(n.status===202||n.status===204)return null;let s=await Fr(n.body);if(!s||s.jsonrpc!=="2.0"||s.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return s}async function Hr(e,t){let r=await $r(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},t),n=r?.result?.tools;if(r?.error){let s=Object.entries(e.headers).filter(([a])=>V(a)).flatMap(([,a])=>[a,String(a).replace(/^Bearer\s+/i,"")]),i=typeof r.error.message=="string"?ut(r.error.message,s).slice(0,512):"",o=Number.isInteger(r.error.code)?` (${r.error.code})`:"";throw new Error(`Orcha MCP tool discovery failed${o}${i?`: ${i}`:""}`)}return Js(n)}function Js(e){if(!Array.isArray(e)||e.some(t=>!t||!zs.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&Pt.controlTools.some(t=>!e.some(r=>r.name===t)))throw new Error("Orcha MCP returned an unsupported or invalid authorized tool catalog");return e}function Ws(e,t){let r=s=>Array.isArray(s)?s.map(r):s&&typeof s=="object"?Object.fromEntries(Object.keys(s).sort().map(i=>[i,r(s[i])])):s,n=s=>s.map(({name:i,inputSchema:o})=>({name:i,inputSchema:o})).sort((i,o)=>i.name.localeCompare(o.name));return JSON.stringify(r(n(e)))===JSON.stringify(r(n(t)))}async function Br(e){let t=Lt(e),r=new AbortController,n=await Hr(t,r.signal),s=Gs(32).toString("hex"),i=qs(async(o,a)=>{if(o.url!=="/mcp"||o.headers.authorization!==`Bearer ${s}`){a.writeHead(403).end();return}if(o.method!=="POST"){a.writeHead(405).end();return}try{let u=await Fr(o);if(!u||u.jsonrpc!=="2.0"||typeof u.method!="string")throw new Error("Invalid MCP request");if(u.method==="tools/call"&&!n.some(f=>f.name===u.params?.name))throw new Error("Tool is not authorized in this task binding");let d=await $r(t,u,r.signal);a.writeHead(d===null?202:200,{"content-type":"application/json"}),a.end(d===null?"":JSON.stringify(d))}catch{a.writeHead(502,{"content-type":"application/json"}).end(JSON.stringify({error:"The task-scoped Orcha MCP connection failed"}))}});return await new Promise((o,a)=>{i.once("error",a),i.listen(0,"127.0.0.1",o)}),{url:`http://127.0.0.1:${i.address().port}/mcp`,token:s,async refresh(o){let a=Lt(o,t.url);if(!Ws(n,await Hr(a,r.signal)))throw new Error("The frozen MCP tool catalog changed; start a new task");t=a},async close(){r.abort(),i.closeAllConnections(),await new Promise(o=>i.close(o))}}}var W=class{constructor(t,r){this.target=t,this.identity=r,this.bound=!1}async request(t,r,n=!1,s="mcp-bindings",i=3e4,o=null){let a=c(this.target.mcpBridgeUrl),u=c(this.target.mcpBridgeTokenEnv),d=this.target.env?.[u]||process.env[u];if(!a||!u||!d)throw Object.assign(new Error("OpenClaw requires the Orcha tool plugin, mcpBridgeUrl and mcpBridgeTokenEnv"),{code:"OPENCLAW_MCP_NOT_CONFIGURED"});let f=new URL(a);if(!["http:","https:"].includes(f.protocol)||f.username||f.password||f.pathname!=="/plugins/orcha-runtime/mcp-bindings"||f.search||f.hash)throw new Error("OpenClaw MCP binding URL must be the trusted Gateway plugin route");if(!["mcp-bindings","deliveries","background"].includes(s))throw new Error("Unsupported Orcha plugin route");f.pathname=`/plugins/orcha-runtime/${s}`;let p=AbortSignal.timeout(i);try{let h=await fetch(f,{method:t,redirect:"error",signal:p,headers:{authorization:`Bearer ${d}`,"content-type":"application/json",...o?{accept:rt}:{},...n?{"if-match":this.identity.runId}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});if(t==="GET"&&s==="deliveries"&&[404,405].includes(h.status))throw await h.body?.cancel(),M("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH");if(h.ok&&o)return await Dr(h,o);let m=await h.json();if(!h.ok)throw M(m.error||"OPENCLAW_MCP_BINDING_FAILED");return m}catch(h){throw vr(h,p)}}async bind(t,r=!1){Lt(t),await this.request("PUT",{...this.identity,mcpServer:t[0]},r),this.bound=!0}async close(){this.bound&&(await this.request("DELETE",{runId:this.identity.runId,sessionKey:this.identity.sessionKey}),this.bound=!1)}};var ti=Zs(Xs),ei=12e4;async function Gr(e,t){let r=new Map,n=[];for(let s of Object.values(e)){if(s.type!=="openclaw")continue;if(s.mcpBridgeUrl&&(n.push(s),!["localhost","127.0.0.1","[::1]"].includes(new URL(s.mcpBridgeUrl).hostname))){process.stderr.write(`\u8FDC\u7A0B OpenClaw Gateway \u7684\u914D\u5957\u63D2\u4EF6\u9700\u5728\u6240\u5728\u4E3B\u673A\u66F4\u65B0\uFF1Breload \u5C06\u68C0\u67E5\u5176\u534F\u8BAE\u3002
3
3
  `);continue}let i={...process.env,...s.env},o=c(s.command)||"openclaw",a=o.includes("/")?o:await he(o,i);if(!a)throw new Error("\u627E\u4E0D\u5230\u5DF2\u63A5\u5165\u7684 OpenClaw\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u5B89\u88C5\u540E\u91CD\u8BD5 reload");let u=await Qs(a);await jr(u,Ys.X_OK);let d=JSON.stringify([u,Object.entries(i).sort(([f],[p])=>f.localeCompare(p))]);r.has(d)||r.set(d,{command:u,env:i})}if(r.size)try{let s=JSON.parse(await qr(Te(t,"openclaw.plugin.json"),"utf8")),i=JSON.parse(await qr(Te(t,"package.json"),"utf8"));if(await jr(Te(t,"index.js")),s.id!=="orcha-runtime"||i.version!==J)throw new Error("\u63D2\u4EF6\u6807\u8BC6\u6216\u7248\u672C\u4E0D\u5339\u914D")}catch(s){throw new Error("\u914D\u5957 OpenClaw \u63D2\u4EF6\u7F3A\u5931\u3001\u635F\u574F\u6216\u7248\u672C\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5 Bridge\uFF1B\u6E90\u7801\u8FD0\u884C\u8BF7\u5148 npm run build",{cause:s})}return async()=>{for(let s of r.values()){process.stderr.write(`\u6B63\u5728\u5B89\u88C5\u914D\u5957 OpenClaw \u63D2\u4EF6\u5E76\u91CD\u542F Gateway\u2026
4
4
  `),await ye(s,["plugins","install",t,"--force"]),await ye(s,["gateway","restart"]);let i=await ye(s,["health","--json"]);if(JSON.parse(i).ok!==!0)throw new Error("OpenClaw Gateway \u5065\u5EB7\u68C0\u67E5\u5931\u8D25\uFF0CBridge \u672A\u542F\u52A8\uFF0C\u8BF7\u4FEE\u590D\u540E\u91CD\u8BD5 reload");process.stderr.write(`OpenClaw \u914D\u5957\u63D2\u4EF6\u5DF2\u66F4\u65B0\uFF0CGateway \u5065\u5EB7\u68C0\u67E5\u901A\u8FC7\u3002
5
5
  `)}for(let s of n)if((await new W(s,{}).request("GET",void 0,!1,"deliveries")).streamType!==rt)throw M("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH")}}async function ye(e,t){try{let{stdout:r}=await ti(e.command,t,{env:e.env,timeout:ei,killSignal:"SIGKILL",maxBuffer:1048576,windowsHide:!0});return r}catch(r){let n=Object.entries(e.env).filter(([i])=>V(i)).map(([,i])=>i),s=ut(r.stderr||r.message,n).trim();throw new Error(`OpenClaw ${t.slice(0,2).join(" ")} \u5931\u8D25\uFF0CBridge \u672A\u542F\u52A8\uFF0C\u8BF7\u4FEE\u590D\u540E\u91CD\u8BD5 reload\uFF1A${s}`)}}import{createHash as ya,randomUUID as re}from"node:crypto";function kt(e){return Array.isArray(e)?e.map(t=>l(t)?t.type==="text"?c(t.text):t.type==="file"?c(t.uri):t.type==="image"?c(t.uri):"":"").filter(Boolean).join(`
@@ -1,7 +1,8 @@
1
- import{getPluginRuntimeGatewayRequestScope as Je}from"openclaw/plugin-sdk/plugin-runtime";import{loadOutboundMediaFromUrl as We}from"openclaw/plugin-sdk/outbound-media";function Se(e){return String(e??"").trim()}var G="[redacted]",Ne=/(authorization|api[_-]?key|credential|password|secret|token)/i;function ie(e){return Ne.test(Se(e))}function ce(e,n=[]){let o=String(e??"");for(let f of n){let c=String(f??"");c.length>=4&&(o=o.split(c).join(G))}return o.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${G}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${G}`)}var W={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs","knowledge_search"]};var Q=Object.freeze([...W.controlTools,...W.residentTools]),Ce=new Set(Q),Re=8*1024*1024;function de(e,n){if(!Array.isArray(e)||e.length!==1)throw new Error("one task-scoped Orcha MCP server is required");let o=e[0],f=new URL(o.url);if(o.name!=="orcha"||o.type!=="http"||!["http:","https:"].includes(f.protocol)||f.username||f.password||f.hash||n&&f.href!==new URL(n).href)throw new Error("Orcha MCP server does not match the trusted binding");let c=Object.fromEntries((o.headers||[]).map(({name:l,value:m})=>[l.toLowerCase(),m]));if(!String(c.authorization||"").startsWith("Bearer "))throw new Error("Orcha MCP task credentials are missing");return{url:f.href,headers:{...c,"content-type":"application/json",accept:"application/json"}}}async function v(e){let n=0,o=[];for await(let f of e){if(n+=f.length,n>Re)throw new Error("MCP payload exceeds the size limit");o.push(Buffer.from(f))}return JSON.parse(Buffer.concat(o).toString("utf8"))}async function Z(e,n,o){let f=await fetch(e.url,{method:"POST",headers:e.headers,body:JSON.stringify(n),redirect:"error",signal:AbortSignal.any([AbortSignal.timeout(36e5),...o?[o]:[]])});if(!f.ok)throw new Error(`Orcha MCP request failed (${f.status})`);if(f.status===202||f.status===204)return null;let c=await v(f.body);if(!c||c.jsonrpc!=="2.0"||c.id!==n.id)throw new Error("Orcha MCP response identity mismatch");return c}async function le(e,n){let o=await Z(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},n),f=o?.result?.tools;if(o?.error){let c=Object.entries(e.headers).filter(([i])=>ie(i)).flatMap(([,i])=>[i,String(i).replace(/^Bearer\s+/i,"")]),l=typeof o.error.message=="string"?ce(o.error.message,c).slice(0,512):"",m=Number.isInteger(o.error.code)?` (${o.error.code})`:"";throw new Error(`Orcha MCP tool discovery failed${m}${l?`: ${l}`:""}`)}return Me(f)}function Me(e){if(!Array.isArray(e)||e.some(n=>!n||!Ce.has(n.name)||n.inputSchema?.type!=="object"||typeof n.description!="string")||new Set(e.map(n=>n.name)).size!==e.length||e.length&&W.controlTools.some(n=>!e.some(o=>o.name===n)))throw new Error("Orcha MCP returned an unsupported or invalid authorized tool catalog");return e}function ue(e,n){let o=c=>Array.isArray(c)?c.map(o):c&&typeof c=="object"?Object.fromEntries(Object.keys(c).sort().map(l=>[l,o(c[l])])):c,f=c=>c.map(({name:l,inputSchema:m})=>({name:l,inputSchema:m})).sort((l,m)=>l.name.localeCompare(m.name));return JSON.stringify(o(f(e)))===JSON.stringify(o(f(n)))}var q=e=>Object.assign(new Error(e),{status:409});function pe(e){let n=new Map,o=e.pluginConfig?.allowedOrchaMcpUrl;if(!o)throw new Error("Orcha plugin requires allowedOrchaMcpUrl");function f(m,i=n.get(m)){!i||n.get(m)!==i||(i.lifetime.abort(),clearTimeout(i.timer),n.delete(m))}function c(m){let i=n.get(m);return i&&i.deadline<=Date.now()?(f(m,i),null):i}async function l(m,{refresh:i=!1}={}){let{runId:u,sessionKey:O,agentCode:L,expiresAt:x,mcpServer:t}=m,h=Date.parse(x);if(typeof u!="string"||!u||typeof O!="string"||!O||typeof L!="string"||!L||!O.startsWith(`agent:${L}:`)||!Number.isFinite(h)||h<=Date.now()||h>Date.now()+24*36e5)throw new Error("invalid_binding_scope");let I=c(O);if(i&&!I||I&&(I.runId!==u||I.agentCode!==L||I.deadline!==h))throw q("original_binding_unavailable_or_changed");let r=de([t],o),d=I?.lifetime||new AbortController,a=await le(r,d.signal);if(c(O)!==I)throw q("binding_changed");if(I){if(!ue(I.tools,a))throw q("frozen_tool_catalog_changed");I.upstream=r}else{let s={runId:u,agentCode:L,deadline:h,upstream:r,tools:a,lifetime:d};s.timer=setTimeout(()=>f(O,s),h-Date.now()),s.timer.unref?.(),n.set(O,s)}}return e.registerTool(m=>{let i=c(m.sessionKey);return!i||m.agentId!==i.agentCode?null:i.tools.map(u=>({name:`orcha_${u.name}`,label:`Orcha ${u.name}`,description:u.description,parameters:u.inputSchema,async execute(O,L,x){if(c(m.sessionKey)!==i||m.agentId!==i.agentCode||!O||!i.tools.some(h=>h.name===u.name))throw new Error("Orcha task binding expired or changed");let t=await Z(i.upstream,{jsonrpc:"2.0",id:O,method:"tools/call",params:{name:u.name,arguments:L}},AbortSignal.any([i.lifetime.signal,...x?[x]:[]]));if(t?.error||!t?.result)throw new Error("Orcha rejected this task-scoped tool call");return{content:t.result.content,details:t.result.structuredContent,isError:t.result.isError===!0}}}))},{names:Q.map(m=>`orcha_${m}`)}),{bind:l,active:c,release:f,allowedUrl:o}}import{createHash as xe}from"node:crypto";import{mkdirSync as ke,readFileSync as Ue,renameSync as $e,writeFileSync as He}from"node:fs";import{join as ge}from"node:path";import{createHash as Pe}from"node:crypto";var fe=e=>Pe("sha256").update(JSON.stringify(e)).digest("hex"),B=e=>Object.assign(new Error(e),{code:e}),X=e=>{let n=String(e||"").replace(/^orcha:/,"");return/^[1-9]\d{0,18}$/.test(n)?n:void 0},me={normalizeTarget:X,targetResolver:{looksLikeId:e=>!!X(e),hint:"Orcha session ID"}};function he({core:e,load:n,save:o,loadMedia:f,activeRun:c}){let l=new Map,m=(t,h)=>fe([t,h]),i=t=>({channel:"orcha",messageId:t.messageId,chatId:t.sessionId,receipt:{primaryPlatformMessageId:t.messageId,platformMessageIds:[t.messageId],parts:[{platformMessageId:t.messageId,kind:"unknown",index:0}],sentAt:Date.now()}});async function u(t,h,I={}){return await I.onPlatformSendDispatch?.(),I.signal?.throwIfAborted(),i(await e(t,"/messages",h.payload,{cfg:I.cfg,signal:I.signal}))}async function O(t){t.signal?.throwIfAborted();let h=X(t.to);if(!h)throw B("invalid_conversation");if(!t.deliveryQueueId)throw B("OPENCLAW_DURABLE_DELIVERY_ID_REQUIRED");let I=t.run&&t.run.delivery.bindingId===t.accountId&&t.run.delivery.sessionId===h?t.run:null,r=t.replyToId||I?.delivery.messageId||null,d=t.payload||{text:t.text||"",mediaUrl:t.mediaUrl},a=d.mediaUrls||(d.mediaUrl?[d.mediaUrl]:[]),s=m(t.accountId,t.deliveryQueueId),p=fe([h,d.text||"",a,r,I?.runId||null]),_=n(s,"sends");if(_&&_.requestHash!==p)throw B("channel_send_conflict");let E=l.get(s);if(E){if(E.requestHash!==p)throw B("channel_send_conflict");return E.promise}let T=(async()=>{let y=_;if(!y){let w=[];for(let P of a){let b=await f(P,{maxBytes:33554432,mediaAccess:t.mediaAccess,mediaReadFile:t.mediaReadFile,mediaLocalRoots:t.mediaLocalRoots}),N=new FormData;N.set("sessionId",h),N.set("file",new Blob([b.buffer],{type:b.contentType||"application/octet-stream"}),b.fileName||"attachment"),w.push((await e(t.accountId,"/files",N,{cfg:t.cfg,signal:t.signal})).inputPart)}y={requestHash:p,payload:{sourceMessageId:`openclaw:${s}`,sessionId:h,content:d.text||"",inputParts:w,...r?{replyToMessageId:r}:{},...I?{agentRunId:I.runId}:{}}},o(s,y,"sends")}let S=await u(t.accountId,y,t);return I&&!I.messageIds.includes(S.messageId)&&I.messageIds.push(S.messageId),S})().finally(()=>l.delete(s));return l.set(s,{requestHash:p,promise:T}),T}return{send:O,message:{send:{text:O,media:O,payload:O},durableFinal:{capabilities:{text:!0,media:!0,payload:!0,replyTo:!0,reconcileUnknownSend:!0},reconcileUnknownSendKinds:{text:!0,media:!0,payload:!0},async reconcileUnknownSend(t){let h=n(m(t.accountId,t.queueId),"sends");if(!h)return{status:"not_sent"};if(h.payload.sessionId!==String(t.to).replace(/^orcha:/,""))throw B("channel_send_conflict");let I=await u(t.accountId,h,t);return{status:"sent",receipt:I.receipt,messageId:I.messageId}}}},actions:{describeMessageTool:()=>({actions:["send"],mediaSourceParams:{send:["media"]}}),supportsAction:({action:t})=>t==="send",isToolDeliveryAction:({args:t})=>t.action==="send",extractToolSend:({args:t})=>typeof(t.to||t.target)=="string"?{to:t.to||t.target,accountId:t.accountId}:null,async handleAction(t){if(t.action!=="send")throw B("unsupported_channel_action");let h=t.params;if(t.dryRun)return{content:[{type:"text",text:"Orcha send dry run"}],details:{dryRun:!0}};let I=c(t.sessionKey),r=await O({cfg:t.cfg,accountId:t.accountId,to:h.to||h.target,text:h.message,mediaUrl:h.media,replyToId:h.replyTo,deliveryQueueId:h.idempotencyKey,mediaAccess:t.mediaAccess,mediaLocalRoots:t.mediaLocalRoots,mediaReadFile:t.mediaReadFile,run:I,signal:I?.controller.signal});return{content:[{type:"text",text:JSON.stringify(r)}],details:r}}}}}var z="application/x-orcha-channel-events-v2+ndjson";function K(e,n){return Object.assign(new Error(n||(["run_timeout","RUNTIME_NODE_TIMEOUT"].includes(e)?"OpenClaw \u539F\u751F IM \u6267\u884C\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002":e==="OPENCLAW_CHANNEL_PROTOCOL_MISMATCH"?"OpenClaw \u63D2\u4EF6\u4E0E Bridge \u7684\u539F\u751F IM \u534F\u8BAE\u4E0D\u517C\u5BB9\uFF0C\u8BF7\u914D\u5957\u5347\u7EA7\u3002":`OpenClaw \u539F\u751F IM \u6267\u884C\u5931\u8D25\uFF08${e}\uFF09`)),{code:e})}function ee(e,n){let o=e.cause?.code||e.code;return n?.reason?.name==="TimeoutError"||e.name==="TimeoutError"||["UND_ERR_HEADERS_TIMEOUT","UND_ERR_BODY_TIMEOUT","UND_ERR_CONNECT_TIMEOUT","ETIMEDOUT"].includes(o)?Object.assign(K("RUNTIME_NODE_TIMEOUT","OpenClaw \u8FDE\u63A5\u6216\u7B49\u5F85\u54CD\u5E94\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002"),{detail:{causeCode:o||"REQUEST_TIMEOUT"}}):e}var we=e=>xe("sha256").update(JSON.stringify(e)).digest("hex"),R=(e,n=409)=>Object.assign(new Error(e),{status:n,code:e}),Y=e=>typeof e=="string"&&/^[1-9]\d{0,18}$/.test(e),De=e=>new Promise(n=>setTimeout(n,e));function ye(e,n,o){return`agent:${e}:orcha:task:${we([o,n.bindingId,n.bindingRevision,n.sessionId,n.taskContextId,n.memberId,n.historyFromSeq,n.runtimePolicyRevision])}`}function Ie(e,n,o,f,c){let l=new Map,m=()=>e.config;function i(r,d=m()){let a=d?.channels?.orcha?.accounts?.[r];if(!Y(r)||!a||a.enabled===!1||!a.serviceToken||!a.agentId)throw R("orcha_channel_account_unavailable",403);return{...a,accountId:r}}async function u(r,d,a,{cfg:s,signal:p,method:_="POST"}={}){let E=i(r,s),T=new URL(`/api/agent-channels${d}`,n.allowedUrl),y=a instanceof FormData,S=AbortSignal.any([AbortSignal.timeout(3e4),...p?[p]:[]]);try{let w=await fetch(T,{method:_,redirect:"error",signal:S,headers:{authorization:`Bearer ${E.serviceToken}`,...y?{}:{"content-type":"application/json"}},...a!==void 0?{body:y?a:JSON.stringify(a)}:{}}),P=await v(w.body);if(!w.ok||P.success!==!0)throw R(`orcha_channel_request_${w.status}`,w.status);return P.data}catch(w){throw ee(w,S)}}function O(r,d="runs"){if(!/^[a-zA-Z0-9_-]{1,128}$/.test(r))throw R("invalid_record_identity",422);let a=ge(e.runtime.state.resolveStateDir(),"plugins","orcha-runtime",d);return ke(a,{recursive:!0,mode:448}),ge(a,`${r}.json`)}function L(r,d){try{return JSON.parse(Ue(O(r,d),"utf8"))}catch(a){if(a.code==="ENOENT")return null;throw a}}function x(r,d,a){let s=O(r,a),p=`${s}.pending`;He(p,JSON.stringify(d),{mode:384}),$e(p,s)}async function t(r,d=!1,a){let s=i(r.delivery?.bindingId),{runId:p,delivery:_}=r;if(!Y(p)||!Y(_.sessionId)||_.taskContextId!==null&&!Y(_.taskContextId)||_.mode!=="channel"||r.agentCode!==s.agentId)throw R("invalid_channel_delivery",422);if(!Array.isArray(r.prompt)||r.prompt.some(C=>!["text","image","file"].includes(C.type)||(C.type==="text"?typeof C.text!="string":typeof C.uri!="string")))throw R("invalid_channel_prompt",422);let E=we({agentCode:r.agentCode,delivery:_,prompt:r.prompt}),T=L(p);if(T&&T.requestHash!==E)throw R("channel_delivery_conflict");if(T?.status==="completed")return T.result;if(T?.status==="failed")throw R(T.error);let y=l.get(p),S=T?.expiresAt||r.expiresAt,w=ye(s.agentId,_,n.allowedUrl),P=()=>{let C=n.active(w);C?.runId===p&&n.release(w,C)},b=T?.hostRunId||`orcha-${p}`;if(T&&!y||r.attachOnly&&!y&&!T)throw R("RUNTIME_OPERATION_NOT_FOUND");if(y){try{await n.bind({runId:p,sessionKey:w,agentCode:s.agentId,expiresAt:S,mcpServer:r.mcpServer},{refresh:!0})}catch(C){if(l.get(p)!==y)return await y.promise;throw C}if(d)return{refreshed:!0};y.listeners.add(a);try{for(let C of y.updates)a?.(C);return await y.promise}finally{y.listeners.delete(a)}}if(d)throw R("RUNTIME_OPERATION_NOT_FOUND");let N=new AbortController,M={runId:p,delivery:_,messageIds:[],controller:N,promise:null,listeners:new Set(a?[a]:[]),updates:[],bytes:0},$=C=>{let k={type:"update",payload:{sessionId:w,update:C,_meta:{channelUpdateId:`${b}:${M.updates.length+1}`}}},H=Buffer.byteLength(JSON.stringify(k));if(H>2097152||M.bytes+H>16777216){N.abort(K("OPENCLAW_CHANNEL_PROGRESS_LIMIT"));return}M.bytes+=H,M.updates.push(k);for(let V of M.listeners)V?.(k)};return l.set(p,M),M.promise=(async()=>{await n.bind({runId:p,sessionKey:w,agentCode:s.agentId,expiresAt:S,mcpServer:r.mcpServer}),x(p,{requestHash:E,status:"running",sessionKey:w,hostRunId:b,expiresAt:S});let C=0,k,H,V=setTimeout(()=>N.abort(R("run_timeout")),Date.parse(S)-Date.now());try{let F=e.runtime.channel.reply;if(typeof F?.dispatchReplyWithBufferedBlockDispatcher!="function"||typeof e.runtime.events?.onAgentEvent!="function")throw R("OPENCLAW_CHANNEL_RUNTIME_UNAVAILABLE");H=e.runtime.events.onAgentEvent(g=>{let A=g.data;g.runId!==b||g.stream!=="tool"||!A?.toolCallId||A.hideFromChannelProgress||!["start","update","result"].includes(A.phase)||$({sessionUpdate:A.phase==="start"?"tool_call":"tool_call_update",toolCallId:A.toolCallId,title:A.name,status:A.phase==="result"?A.isError?"failed":"completed":"in_progress",...A.args?{rawInput:A.args}:{},...A.result!==void 0?{rawOutput:A.result}:{}})});let U="",ne="",j="",Te=g=>{if(typeof g.text!="string")return;let A=[ne,g.text].filter(Boolean).join(`
1
+ import{getPluginRuntimeGatewayRequestScope as Ke}from"openclaw/plugin-sdk/plugin-runtime";import{loadOutboundMediaFromUrl as Ye}from"openclaw/plugin-sdk/outbound-media";function Ce(e){return String(e??"").trim()}var Q="[redacted]",Re=/(authorization|api[_-]?key|credential|password|secret|token)/i;function ce(e){return Re.test(Ce(e))}function de(e,t=[]){let i=String(e??"");for(let g of t){let d=String(g??"");d.length>=4&&(i=i.split(d).join(Q))}return i.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${Q}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${Q}`)}var z={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs","knowledge_search"]};var Z=Object.freeze([...z.controlTools,...z.residentTools]),xe=new Set(Z),Pe=8*1024*1024;function le(e,t){if(!Array.isArray(e)||e.length!==1)throw new Error("one task-scoped Orcha MCP server is required");let i=e[0],g=new URL(i.url);if(i.name!=="orcha"||i.type!=="http"||!["http:","https:"].includes(g.protocol)||g.username||g.password||g.hash||t&&g.href!==new URL(t).href)throw new Error("Orcha MCP server does not match the trusted binding");let d=Object.fromEntries((i.headers||[]).map(({name:O,value:s})=>[O.toLowerCase(),s]));if(!String(d.authorization||"").startsWith("Bearer "))throw new Error("Orcha MCP task credentials are missing");return{url:g.href,headers:{...d,"content-type":"application/json",accept:"application/json"}}}async function B(e){let t=0,i=[];for await(let g of e){if(t+=g.length,t>Pe)throw new Error("MCP payload exceeds the size limit");i.push(Buffer.from(g))}return JSON.parse(Buffer.concat(i).toString("utf8"))}async function q(e,t,i){let g=await fetch(e.url,{method:"POST",headers:e.headers,body:JSON.stringify(t),redirect:"error",signal:AbortSignal.any([AbortSignal.timeout(36e5),...i?[i]:[]])});if(!g.ok)throw new Error(`Orcha MCP request failed (${g.status})`);if(g.status===202||g.status===204)return null;let d=await B(g.body);if(!d||d.jsonrpc!=="2.0"||d.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return d}async function ue(e,t){let i=await q(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},t),g=i?.result?.tools;if(i?.error){let d=Object.entries(e.headers).filter(([u])=>ce(u)).flatMap(([,u])=>[u,String(u).replace(/^Bearer\s+/i,"")]),O=typeof i.error.message=="string"?de(i.error.message,d).slice(0,512):"",s=Number.isInteger(i.error.code)?` (${i.error.code})`:"";throw new Error(`Orcha MCP tool discovery failed${s}${O?`: ${O}`:""}`)}return Le(g)}function Le(e){if(!Array.isArray(e)||e.some(t=>!t||!xe.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&z.controlTools.some(t=>!e.some(i=>i.name===t)))throw new Error("Orcha MCP returned an unsupported or invalid authorized tool catalog");return e}function pe(e,t){let i=d=>Array.isArray(d)?d.map(i):d&&typeof d=="object"?Object.fromEntries(Object.keys(d).sort().map(O=>[O,i(d[O])])):d,g=d=>d.map(({name:O,inputSchema:s})=>({name:O,inputSchema:s})).sort((O,s)=>O.name.localeCompare(s.name));return JSON.stringify(i(g(e)))===JSON.stringify(i(g(t)))}var X=e=>Object.assign(new Error(e),{status:409});function fe(e){let t=new Map,i=e.pluginConfig?.allowedOrchaMcpUrl;if(!i)throw new Error("Orcha plugin requires allowedOrchaMcpUrl");function g(s,u=t.get(s)){!u||t.get(s)!==u||(u.lifetime.abort(),clearTimeout(u.timer),t.delete(s))}function d(s){let u=t.get(s);return u&&u.deadline<=Date.now()?(g(s,u),null):u}async function O(s,{refresh:u=!1}={}){let{runId:_,sessionKey:c,agentCode:M,expiresAt:k,mcpServer:n}=s,m=Date.parse(k);if(typeof _!="string"||!_||typeof c!="string"||!c||typeof M!="string"||!M||!c.startsWith(`agent:${M}:`)||!Number.isFinite(m)||m<=Date.now()||m>Date.now()+24*36e5)throw new Error("invalid_binding_scope");let h=d(c);if(u&&!h||h&&(h.runId!==_||h.agentCode!==M||h.deadline!==m))throw X("original_binding_unavailable_or_changed");let L=le([n],i),r=h?.lifetime||new AbortController,l=await ue(L,r.signal);if(d(c)!==h)throw X("binding_changed");if(h){if(!pe(h.tools,l))throw X("frozen_tool_catalog_changed");h.upstream=L}else{let o={runId:_,agentCode:M,deadline:m,upstream:L,tools:l,lifetime:r};o.timer=setTimeout(()=>g(c,o),m-Date.now()),o.timer.unref?.(),t.set(c,o)}}return e.registerTool(s=>{let u=d(s.sessionKey);return!u||s.agentId!==u.agentCode?null:u.tools.map(_=>({name:`orcha_${_.name}`,label:`Orcha ${_.name}`,description:_.description,parameters:_.inputSchema,async execute(c,M,k){if(d(s.sessionKey)!==u||s.agentId!==u.agentCode||!c||!u.tools.some(m=>m.name===_.name))throw new Error("Orcha task binding expired or changed");let n=await q(u.upstream,{jsonrpc:"2.0",id:c,method:"tools/call",params:{name:_.name,arguments:M}},AbortSignal.any([u.lifetime.signal,...k?[k]:[]]));if(n?.error||!n?.result)throw new Error("Orcha rejected this task-scoped tool call");return{content:n.result.content,details:n.result.structuredContent,isError:n.result.isError===!0}}}))},{names:Z.map(s=>`orcha_${s}`)}),{bind:O,active:d,release:g,allowedUrl:i}}import{createHash as $e}from"node:crypto";import{mkdirSync as He,readFileSync as De,renameSync as ve,writeFileSync as Be}from"node:fs";import{join as ye}from"node:path";import{createHash as ke}from"node:crypto";var me=e=>ke("sha256").update(JSON.stringify(e)).digest("hex"),j=e=>Object.assign(new Error(e),{code:e}),ee=e=>{let t=String(e||"").replace(/^orcha:/,"");return/^[1-9]\d{0,18}$/.test(t)?t:void 0},he={normalizeTarget:ee,targetResolver:{looksLikeId:e=>!!ee(e),hint:"Orcha session ID"}};function ge({core:e,load:t,save:i,loadMedia:g,activeRun:d}){let O=new Map,s=(n,m)=>me([n,m]),u=n=>({channel:"orcha",messageId:n.messageId,chatId:n.sessionId,receipt:{primaryPlatformMessageId:n.messageId,platformMessageIds:[n.messageId],parts:[{platformMessageId:n.messageId,kind:"unknown",index:0}],sentAt:Date.now()}});async function _(n,m,h={}){return await h.onPlatformSendDispatch?.(),h.signal?.throwIfAborted(),u(await e(n,"/messages",m.payload,{cfg:h.cfg,signal:h.signal}))}async function c(n){n.signal?.throwIfAborted();let m=ee(n.to);if(!m)throw j("invalid_conversation");if(!n.deliveryQueueId)throw j("OPENCLAW_DURABLE_DELIVERY_ID_REQUIRED");let h=n.run&&n.run.delivery.bindingId===n.accountId&&n.run.delivery.sessionId===m?n.run:null,L=n.replyToId||h?.delivery.messageId||null,r=n.payload||{text:n.text||"",mediaUrl:n.mediaUrl},l=r.mediaUrls||(r.mediaUrl?[r.mediaUrl]:[]),o=s(n.accountId,n.deliveryQueueId),a=me([m,r.text||"",l,L,h?.runId||null]),p=t(o,"sends");if(p&&p.requestHash!==a)throw j("channel_send_conflict");let y=O.get(o);if(y){if(y.requestHash!==a)throw j("channel_send_conflict");return y.promise}let E=(async()=>{let T=p;if(!T){let S=[];for(let I of l){let P=await g(I,{maxBytes:33554432,mediaAccess:n.mediaAccess,mediaReadFile:n.mediaReadFile,mediaLocalRoots:n.mediaLocalRoots}),N=new FormData;N.set("sessionId",m),N.set("file",new Blob([P.buffer],{type:P.contentType||"application/octet-stream"}),P.fileName||"attachment"),S.push((await e(n.accountId,"/files",N,{cfg:n.cfg,signal:n.signal})).inputPart)}T={requestHash:a,payload:{sourceMessageId:`openclaw:${o}`,sessionId:m,content:r.text||"",inputParts:S,...L?{replyToMessageId:L}:{},...h?{agentRunId:h.runId}:{}}},i(o,T,"sends")}let w=await _(n.accountId,T,n);return h&&!h.messageIds.includes(w.messageId)&&h.messageIds.push(w.messageId),w})().finally(()=>O.delete(o));return O.set(o,{requestHash:a,promise:E}),E}return{send:c,message:{send:{text:c,media:c,payload:c},durableFinal:{capabilities:{text:!0,media:!0,payload:!0,replyTo:!0,reconcileUnknownSend:!0},reconcileUnknownSendKinds:{text:!0,media:!0,payload:!0},async reconcileUnknownSend(n){let m=t(s(n.accountId,n.queueId),"sends");if(!m)return{status:"not_sent"};if(m.payload.sessionId!==String(n.to).replace(/^orcha:/,""))throw j("channel_send_conflict");let h=await _(n.accountId,m,n);return{status:"sent",receipt:h.receipt,messageId:h.messageId}}}},actions:{describeMessageTool:()=>({actions:["send"],mediaSourceParams:{send:["media"]}}),supportsAction:({action:n})=>n==="send",isToolDeliveryAction:({args:n})=>n.action==="send",extractToolSend:({args:n})=>typeof(n.to||n.target)=="string"?{to:n.to||n.target,accountId:n.accountId}:null,async handleAction(n){if(n.action!=="send")throw j("unsupported_channel_action");let m=n.params;if(n.dryRun)return{content:[{type:"text",text:"Orcha send dry run"}],details:{dryRun:!0}};let h=d(n.sessionKey),L=await c({cfg:n.cfg,accountId:n.accountId,to:m.to||m.target,text:m.message,mediaUrl:m.media,replyToId:m.replyTo,deliveryQueueId:m.idempotencyKey,mediaAccess:n.mediaAccess,mediaLocalRoots:n.mediaLocalRoots,mediaReadFile:n.mediaReadFile,run:h,signal:h?.controller.signal});return{content:[{type:"text",text:JSON.stringify(L)}],details:L}}}}}var K="application/x-orcha-channel-events-v2+ndjson";function Y(e,t){return Object.assign(new Error(t||(["run_timeout","RUNTIME_NODE_TIMEOUT"].includes(e)?"OpenClaw \u539F\u751F IM \u6267\u884C\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002":e==="OPENCLAW_CHANNEL_PROTOCOL_MISMATCH"?"OpenClaw \u63D2\u4EF6\u4E0E Bridge \u7684\u539F\u751F IM \u534F\u8BAE\u4E0D\u517C\u5BB9\uFF0C\u8BF7\u914D\u5957\u5347\u7EA7\u3002":`OpenClaw \u539F\u751F IM \u6267\u884C\u5931\u8D25\uFF08${e}\uFF09`)),{code:e})}function te(e,t){let i=e.cause?.code||e.code;return t?.reason?.name==="TimeoutError"||e.name==="TimeoutError"||["UND_ERR_HEADERS_TIMEOUT","UND_ERR_BODY_TIMEOUT","UND_ERR_CONNECT_TIMEOUT","ETIMEDOUT"].includes(i)?Object.assign(Y("RUNTIME_NODE_TIMEOUT","OpenClaw \u8FDE\u63A5\u6216\u7B49\u5F85\u54CD\u5E94\u8D85\u65F6\uFF0C\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u8BD5\u3002"),{detail:{causeCode:i||"REQUEST_TIMEOUT"}}):e}var Ie=e=>$e("sha256").update(JSON.stringify(e)).digest("hex"),R=(e,t=409)=>Object.assign(new Error(e),{status:t,code:e}),V=e=>typeof e=="string"&&/^[1-9]\d{0,18}$/.test(e),je=e=>new Promise(t=>setTimeout(t,e));function we(e,t,i){return`agent:${e}:orcha:task:${Ie([i,t.bindingId,t.bindingRevision,t.sessionId,t.taskContextId,t.memberId,t.historyFromSeq,t.runtimePolicyRevision])}`}function _e(e,t,i,g,d,O){let s=new Map;e.on("before_message_write",({message:r},l)=>{if(r?.role!=="assistant")return;let o=t.active(l.sessionKey),a=s.get(o?.runId);a&&l.agentId===o.agentCode&&(a.silentFinal=O(r))});let u=()=>e.config;function _(r,l=u()){let o=l?.channels?.orcha?.accounts?.[r];if(!V(r)||!o||o.enabled===!1||!o.serviceToken||!o.agentId)throw R("orcha_channel_account_unavailable",403);return{...o,accountId:r}}async function c(r,l,o,{cfg:a,signal:p,method:y="POST"}={}){let E=_(r,a),T=new URL(`/api/agent-channels${l}`,t.allowedUrl),w=o instanceof FormData,S=AbortSignal.any([AbortSignal.timeout(3e4),...p?[p]:[]]);try{let I=await fetch(T,{method:y,redirect:"error",signal:S,headers:{authorization:`Bearer ${E.serviceToken}`,...w?{}:{"content-type":"application/json"}},...o!==void 0?{body:w?o:JSON.stringify(o)}:{}}),P=await B(I.body);if(!I.ok||P.success!==!0)throw R(`orcha_channel_request_${I.status}`,I.status);return P.data}catch(I){throw te(I,S)}}function M(r,l="runs"){if(!/^[a-zA-Z0-9_-]{1,128}$/.test(r))throw R("invalid_record_identity",422);let o=ye(e.runtime.state.resolveStateDir(),"plugins","orcha-runtime",l);return He(o,{recursive:!0,mode:448}),ye(o,`${r}.json`)}function k(r,l){try{return JSON.parse(De(M(r,l),"utf8"))}catch(o){if(o.code==="ENOENT")return null;throw o}}function n(r,l,o){let a=M(r,o),p=`${a}.pending`;Be(p,JSON.stringify(l),{mode:384}),ve(p,a)}async function m(r,l=!1,o){let a=_(r.delivery?.bindingId),{runId:p,delivery:y}=r;if(!V(p)||!V(y.sessionId)||y.taskContextId!==null&&!V(y.taskContextId)||y.mode!=="channel"||r.agentCode!==a.agentId)throw R("invalid_channel_delivery",422);if(!Array.isArray(r.prompt)||r.prompt.some(C=>!["text","image","file"].includes(C.type)||(C.type==="text"?typeof C.text!="string":typeof C.uri!="string")))throw R("invalid_channel_prompt",422);let E=Ie({agentCode:r.agentCode,delivery:y,prompt:r.prompt}),T=k(p);if(T&&T.requestHash!==E)throw R("channel_delivery_conflict");if(T?.status==="completed")return T.result;if(T?.status==="failed")throw R(T.error);let w=s.get(p),S=T?.expiresAt||r.expiresAt,I=we(a.agentId,y,t.allowedUrl),P=()=>{let C=t.active(I);C?.runId===p&&t.release(I,C)},N=T?.hostRunId||`orcha-${p}`;if(T&&!w||r.attachOnly&&!w&&!T)throw R("RUNTIME_OPERATION_NOT_FOUND");if(w){try{await t.bind({runId:p,sessionKey:I,agentCode:a.agentId,expiresAt:S,mcpServer:r.mcpServer},{refresh:!0})}catch(C){if(s.get(p)!==w)return await w.promise;throw C}if(l)return{refreshed:!0};w.listeners.add(o);try{for(let C of w.updates)o?.(C);return await w.promise}finally{w.listeners.delete(o)}}if(l)throw R("RUNTIME_OPERATION_NOT_FOUND");let b=new AbortController,x={runId:p,delivery:y,messageIds:[],controller:b,promise:null,listeners:new Set(o?[o]:[]),updates:[],bytes:0},H=C=>{let U={type:"update",payload:{sessionId:I,update:C,_meta:{channelUpdateId:`${N}:${x.updates.length+1}`}}},D=Buffer.byteLength(JSON.stringify(U));if(D>2097152||x.bytes+D>16777216){b.abort(Y("OPENCLAW_CHANNEL_PROGRESS_LIMIT"));return}x.bytes+=D,x.updates.push(U);for(let G of x.listeners)G?.(U)};return s.set(p,x),x.promise=(async()=>{await t.bind({runId:p,sessionKey:I,agentCode:a.agentId,expiresAt:S,mcpServer:r.mcpServer}),n(p,{requestHash:E,status:"running",sessionKey:I,hostRunId:N,expiresAt:S});let C=0,U,D,G=setTimeout(()=>b.abort(R("run_timeout")),Date.parse(S)-Date.now());try{let J=e.runtime.channel.reply;if(typeof J?.dispatchReplyWithBufferedBlockDispatcher!="function"||typeof e.runtime.events?.onAgentEvent!="function")throw R("OPENCLAW_CHANNEL_RUNTIME_UNAVAILABLE");D=e.runtime.events.onAgentEvent(f=>{let A=f.data;f.runId!==N||f.stream!=="tool"||!A?.toolCallId||A.hideFromChannelProgress||!["start","update","result"].includes(A.phase)||H({sessionUpdate:A.phase==="start"?"tool_call":"tool_call_update",toolCallId:A.toolCallId,title:A.name,status:A.phase==="result"?A.isError?"failed":"completed":"in_progress",...A.args?{rawInput:A.args}:{},...A.result!==void 0?{rawOutput:A.result}:{}})});let $="",re="",F="",Se=f=>{if(typeof f.text!="string")return;let A=[re,f.text].filter(Boolean).join(`
2
2
 
3
- `);if(A===j)return;let D=A.startsWith(j);$({sessionUpdate:D?"agent_message_chunk":"agent_message_snapshot",content:{type:"text",text:D?A.slice(j.length):A}}),j=A},re=g=>{if(g.requiresReasoningProgressOptIn||typeof g.text!="string")return;let A=g.text.startsWith(U)?g.text.slice(U.length):g.text;U=g.text,A&&$({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:A}})},J=r.prompt.filter(g=>g.type==="text").map(g=>g.text).join(`
3
+ `);if(A===F)return;let v=A.startsWith(F);H({sessionUpdate:v?"agent_message_chunk":"agent_message_snapshot",content:{type:"text",text:v?A.slice(F.length):A}}),F=A},oe=f=>{if(f.requiresReasoningProgressOptIn||typeof f.text!="string")return;let A=f.text.startsWith($)?f.text.slice($.length):f.text;$=f.text,A&&H({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:A}})},W=r.prompt.filter(f=>f.type==="text").map(f=>f.text).join(`
4
4
 
5
- `),oe=r.prompt.filter(g=>g.type!=="text"),Oe={Body:J,BodyForAgent:J,BodyForCommands:J,RawBody:J,From:`orcha:${_.memberId}`,To:`orcha:${_.sessionId}`,SessionKey:w,AccountId:_.bindingId,Provider:"orcha",Surface:"orcha",ChatType:"direct",OriginatingChannel:"orcha",OriginatingTo:_.sessionId,MessageSid:_.messageId||p,MediaUrls:oe.map(g=>g.uri),MediaTypes:oe.map(g=>g.mimeType||"application/octet-stream"),CommandAuthorized:!1,WasMentioned:!0};if(await F.dispatchReplyWithBufferedBlockDispatcher({ctx:Oe,cfg:m(),replyOptions:{runId:b,abortSignal:N.signal,suppressTyping:!0,suppressDefaultToolProgressMessages:!0,suppressToolErrorWarnings:!0,disableBlockStreaming:!0,reasoningPayloadsEnabled:!0,commentaryPayloadsEnabled:!0,onAssistantMessageStart:()=>{U="",ne=j},onPartialReply:Te,onReasoningStream:re},dispatcherOptions:{deliver:async(g,A)=>{if(N.signal.throwIfAborted(),g.isReasoning&&re(g),g.isCommentary&&g.text&&$({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:g.text}}),A.kind==="final"&&f(g)){let D=m(),se=D?.agents?.list?.find(Ae=>Ae.id===s.agentId)?.workspace||D?.agents?.defaults?.workspace;await h.send({cfg:D,accountId:_.bindingId,to:_.sessionId,payload:g,run:M,deliveryQueueId:`${b}:final:${++C}`,signal:N.signal,mediaLocalRoots:se?[se]:void 0})}},onError:g=>{k??=g}}}),k)throw k;if(N.signal.throwIfAborted(),!M.messageIds.length)throw R("runtime_node_empty_result");let ae={stopReason:"end_turn",messageIds:M.messageIds,sessionId:w};return x(p,{requestHash:E,status:"completed",sessionKey:w,hostRunId:b,expiresAt:S,result:ae}),ae}catch(F){let U=N.signal.aborted?N.signal.reason:ee(F,N.signal);throw x(p,{requestHash:E,status:"failed",sessionKey:w,hostRunId:b,expiresAt:S,error:U.code||"channel_host_failed"}),U}finally{H?.(),clearTimeout(V),P(),l.delete(p)}})().catch(C=>{throw P(),l.delete(p),C}),M.promise}let h=he({core:u,load:L,save:x,loadMedia:c,activeRun:r=>l.get(n.active(r)?.runId)});e.registerChannel({plugin:{id:"orcha",meta:{id:"orcha",label:"Orcha",selectionLabel:"Orcha",docsPath:"/channels/orcha",blurb:"Enterprise people and Agent conversations"},capabilities:{chatTypes:["direct","group"],media:!0},config:{listAccountIds:r=>Object.keys(r?.channels?.orcha?.accounts||{}),inspectAccount:(r,d)=>{let a=r?.channels?.orcha?.accounts?.[d];return{enabled:!!(a&&a.enabled!==!1),configured:!!(a?.serviceToken&&a?.agentId),tokenStatus:a?.serviceToken?"available":"missing"}},resolveAccount:(r,d)=>i(d,r),isEnabled:r=>r.enabled!==!1,isConfigured:r=>!!(r.serviceToken&&r.agentId)},outbound:{deliveryMode:"direct",textChunkLimit:1e5},message:h.message,actions:h.actions,messaging:me}});async function I(r){let{accountId:d,grantId:a,externalInvocationId:s}=r;i(d);let p=await u(d,"/runs",{grantId:a,externalInvocationId:s,input:r.input||{}}),_=p.agentRunId;if(["completed","failed","cancelled","expired"].includes(p.status))return p;let E;do E=await u(d,`/runs/${_}/claim`,{}),E.attemptId||await De(Math.max(1,E.retryAfterSeconds||2)*1e3);while(!E.attemptId);let T=ye(i(d).agentId,E.delivery,n.allowedUrl),y,S=!1,w=setInterval(async()=>{if(!S){S=!0;try{let N=await u(d,`/runs/${_}/heartbeat`,{attemptId:E.attemptId});n.active(T)&&await n.bind({runId:_,sessionKey:T,agentCode:i(d).agentId,expiresAt:E.expiresAt,mcpServer:N.mcpServer},{refresh:!0})}catch(N){y=N,l.get(_)?.controller.abort(N),n.release(T)}finally{S=!1}}},Math.max(1,E.heartbeatIntervalSeconds)*1e3),P,b;try{let N;try{N=await t({runId:_,agentCode:i(d).agentId,delivery:E.delivery,prompt:[{type:"text",text:JSON.stringify({task:E.prompt,eventInput:E.input})}],mcpServer:E.mcpServer,expiresAt:E.expiresAt,attachOnly:E.recovery})}catch($){b=$}if(y)throw y;P=b?{attemptId:E.attemptId,errorMessage:K(b.code||"channel_host_failed").message,status:"failed"}:{attemptId:E.attemptId,messageIds:N.messageIds,status:"completed"};let M=await u(d,`/runs/${_}/complete`,P);if(b)throw b;return M}finally{clearInterval(w),n.release(T)}}for(let[r,d]of[["deliveries",t],["background",I]])e.registerHttpRoute({path:`/plugins/orcha-runtime/${r}`,auth:"gateway",match:"exact",async handler(a,s){let p,_=Promise.resolve(),E=0,T=y=>{if(s.destroyed||s.writableEnded)return;let S=JSON.stringify(y)+`
6
- `,w=Buffer.byteLength(S);if(w>2097152||E+s.writableLength+w>2097152){s.destroy();return}return E+=w,_=_.then(async()=>{s.destroyed||s.writableEnded||(await o(),s.write(S))}).catch(P=>{!s.destroyed&&!s.writableEnded&&s.end(JSON.stringify({type:"error",code:P.code||"OPENCLAW_CHANNEL_AUTH_FAILED"})+`
7
- `)}).finally(()=>{E-=w}),_};try{if(r==="deliveries"&&a.method==="GET"){await o(),s.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({streamType:z}));return}if(!["POST","PATCH","DELETE"].includes(a.method))throw R("method_not_allowed",405);let y=await v(a);if(await o(),r==="deliveries"&&a.method==="POST"){if(a.headers.accept!==z)throw R("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH",409);s.writeHead(200,{"content-type":z,"cache-control":"no-store","x-accel-buffering":"no"}),T({type:"heartbeat"}),p=setInterval(()=>T({type:"heartbeat"}),15e3),s.once("close",()=>clearInterval(p));let w=await t(y,!1,T);await o(),await T({type:"result",result:w}),s.end();return}if(a.method==="DELETE"){let w=l.get(y.runId);w?.controller.abort(R("RUNTIME_OPERATION_CANCELLED")),s.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({cancelled:!!w}));return}if(a.method==="PATCH"&&r!=="deliveries")throw R("method_not_allowed",405);let S=await d(y,a.method==="PATCH");await o(),s.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify(S))}catch(y){s.headersSent?(await T({type:"error",code:y.code||"channel_host_failed"}),s.end()):s.writableEnded||s.writeHead(y.status||500,{"content-type":"application/json"}).end(JSON.stringify({error:y.code||y.message}))}finally{clearInterval(p)}}})}function _e(e,n,o){return{id:"orcha-runtime",name:"Orcha Channel and authorized tools",register(f){let c=pe(f);f.registerHttpRoute({path:"/plugins/orcha-runtime/mcp-bindings",auth:"gateway",match:"exact",async handler(l,m){let i=(u,O)=>{m.writeHead(u,{"content-type":"application/json"}),m.end(JSON.stringify(O))};try{if(l.method==="GET"){i(200,{ready:!0});return}if(!["PUT","DELETE"].includes(l.method)){i(405,{error:"method_not_allowed"});return}let u=await v(l);if(await e(),typeof u.runId!="string"||!u.runId||typeof u.sessionKey!="string"||!u.sessionKey){i(422,{error:"invalid_binding_identity"});return}let O=c.active(u.sessionKey);if(l.headers["if-match"]&&l.headers["if-match"]!==u.runId){i(409,{error:"binding_run_conflict"});return}if(O&&O.runId!==u.runId){i(409,{error:"session_already_bound"});return}l.method==="DELETE"?c.release(u.sessionKey):await c.bind(u,{refresh:!!l.headers["if-match"]}),i(200,{[l.method==="DELETE"?"released":"bound"]:!0})}catch(u){m.writableEnded||i(u.status||422,{error:u.message})}}}),Ie(f,c,e,n,o)}}}import{isFastModeAutoProgressPayload as ve,isReasoningReplyPayload as Be,isReplyPayloadNonTerminalToolErrorWarning as je,isReplyPayloadTtsSupplement as Fe}from"openclaw/plugin-sdk/reply-payload";function Ee(e){return!Be(e)&&!e.isCommentary&&!e.isCompactionNotice&&!e.isFallbackNotice&&!e.isStatusNotice&&!ve(e)&&!je(e)&&!Fe(e)}var It=_e(async()=>{await Je()?.revalidate?.()},Ee,We);export{It as default};
5
+ `),ie=r.prompt.filter(f=>f.type!=="text"),be={Body:W,BodyForAgent:W,BodyForCommands:W,RawBody:W,From:`orcha:${y.memberId}`,To:`orcha:${y.sessionId}`,SessionKey:I,AccountId:y.bindingId,Provider:"orcha",Surface:"orcha",ChatType:"direct",OriginatingChannel:"orcha",OriginatingTo:y.sessionId,MessageSid:y.messageId||p,MediaUrls:ie.map(f=>f.uri),MediaTypes:ie.map(f=>f.mimeType||"application/octet-stream"),CommandAuthorized:!1,WasMentioned:!0};if(await J.dispatchReplyWithBufferedBlockDispatcher({ctx:be,cfg:u(),replyOptions:{runId:N,abortSignal:b.signal,suppressTyping:!0,suppressDefaultToolProgressMessages:!0,suppressToolErrorWarnings:!0,disableBlockStreaming:!0,reasoningPayloadsEnabled:!0,commentaryPayloadsEnabled:!0,onAssistantMessageStart:()=>{$="",re=F},onPartialReply:Se,onReasoningStream:oe},dispatcherOptions:{deliver:async(f,A)=>{if(b.signal.throwIfAborted(),f.isReasoning&&oe(f),f.isCommentary&&f.text&&H({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:f.text}}),A.kind==="final"&&g(f)){if(x.silentFinal&&x.messageIds.length&&!f.isError)return;let v=u(),ae=v?.agents?.list?.find(Ne=>Ne.id===a.agentId)?.workspace||v?.agents?.defaults?.workspace;await h.send({cfg:v,accountId:y.bindingId,to:y.sessionId,payload:f,run:x,deliveryQueueId:`${N}:final:${++C}`,signal:b.signal,mediaLocalRoots:ae?[ae]:void 0})}},onError:f=>{U??=f}}}),U)throw U;if(b.signal.throwIfAborted(),!x.messageIds.length)throw R("runtime_node_empty_result");let se={stopReason:"end_turn",messageIds:x.messageIds,sessionId:I};return n(p,{requestHash:E,status:"completed",sessionKey:I,hostRunId:N,expiresAt:S,result:se}),se}catch(J){let $=b.signal.aborted?b.signal.reason:te(J,b.signal);throw n(p,{requestHash:E,status:"failed",sessionKey:I,hostRunId:N,expiresAt:S,error:$.code||"channel_host_failed"}),$}finally{D?.(),clearTimeout(G),P(),s.delete(p)}})().catch(C=>{throw P(),s.delete(p),C}),x.promise}let h=ge({core:c,load:k,save:n,loadMedia:d,activeRun:r=>s.get(t.active(r)?.runId)});e.registerChannel({plugin:{id:"orcha",meta:{id:"orcha",label:"Orcha",selectionLabel:"Orcha",docsPath:"/channels/orcha",blurb:"Enterprise people and Agent conversations"},capabilities:{chatTypes:["direct","group"],media:!0},config:{listAccountIds:r=>Object.keys(r?.channels?.orcha?.accounts||{}),inspectAccount:(r,l)=>{let o=r?.channels?.orcha?.accounts?.[l];return{enabled:!!(o&&o.enabled!==!1),configured:!!(o?.serviceToken&&o?.agentId),tokenStatus:o?.serviceToken?"available":"missing"}},resolveAccount:(r,l)=>_(l,r),isEnabled:r=>r.enabled!==!1,isConfigured:r=>!!(r.serviceToken&&r.agentId)},outbound:{deliveryMode:"direct",textChunkLimit:1e5},message:h.message,actions:h.actions,messaging:he}});async function L(r){let{accountId:l,grantId:o,externalInvocationId:a}=r;_(l);let p=await c(l,"/runs",{grantId:o,externalInvocationId:a,input:r.input||{}}),y=p.agentRunId;if(["completed","failed","cancelled","expired"].includes(p.status))return p;let E;do E=await c(l,`/runs/${y}/claim`,{}),E.attemptId||await je(Math.max(1,E.retryAfterSeconds||2)*1e3);while(!E.attemptId);let T=we(_(l).agentId,E.delivery,t.allowedUrl),w,S=!1,I=setInterval(async()=>{if(!S){S=!0;try{let b=await c(l,`/runs/${y}/heartbeat`,{attemptId:E.attemptId});t.active(T)&&await t.bind({runId:y,sessionKey:T,agentCode:_(l).agentId,expiresAt:E.expiresAt,mcpServer:b.mcpServer},{refresh:!0})}catch(b){w=b,s.get(y)?.controller.abort(b),t.release(T)}finally{S=!1}}},Math.max(1,E.heartbeatIntervalSeconds)*1e3),P,N;try{let b;try{b=await m({runId:y,agentCode:_(l).agentId,delivery:E.delivery,prompt:[{type:"text",text:JSON.stringify({task:E.prompt,eventInput:E.input})}],mcpServer:E.mcpServer,expiresAt:E.expiresAt,attachOnly:E.recovery})}catch(H){N=H}if(w)throw w;P=N?{attemptId:E.attemptId,errorMessage:Y(N.code||"channel_host_failed").message,status:"failed"}:{attemptId:E.attemptId,messageIds:b.messageIds,status:"completed"};let x=await c(l,`/runs/${y}/complete`,P);if(N)throw N;return x}finally{clearInterval(I),t.release(T)}}for(let[r,l]of[["deliveries",m],["background",L]])e.registerHttpRoute({path:`/plugins/orcha-runtime/${r}`,auth:"gateway",match:"exact",async handler(o,a){let p,y=Promise.resolve(),E=0,T=w=>{if(a.destroyed||a.writableEnded)return;let S=JSON.stringify(w)+`
6
+ `,I=Buffer.byteLength(S);if(I>2097152||E+a.writableLength+I>2097152){a.destroy();return}return E+=I,y=y.then(async()=>{a.destroyed||a.writableEnded||(await i(),a.write(S))}).catch(P=>{!a.destroyed&&!a.writableEnded&&a.end(JSON.stringify({type:"error",code:P.code||"OPENCLAW_CHANNEL_AUTH_FAILED"})+`
7
+ `)}).finally(()=>{E-=I}),y};try{if(r==="deliveries"&&o.method==="GET"){await i(),a.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({streamType:K}));return}if(!["POST","PATCH","DELETE"].includes(o.method))throw R("method_not_allowed",405);let w=await B(o);if(await i(),r==="deliveries"&&o.method==="POST"){if(o.headers.accept!==K)throw R("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH",409);a.writeHead(200,{"content-type":K,"cache-control":"no-store","x-accel-buffering":"no"}),T({type:"heartbeat"}),p=setInterval(()=>T({type:"heartbeat"}),15e3),a.once("close",()=>clearInterval(p));let I=await m(w,!1,T);await i(),await T({type:"result",result:I}),a.end();return}if(o.method==="DELETE"){let I=s.get(w.runId);I?.controller.abort(R("RUNTIME_OPERATION_CANCELLED")),a.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({cancelled:!!I}));return}if(o.method==="PATCH"&&r!=="deliveries")throw R("method_not_allowed",405);let S=await l(w,o.method==="PATCH");await i(),a.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify(S))}catch(w){a.headersSent?(await T({type:"error",code:w.code||"channel_host_failed"}),a.end()):a.writableEnded||a.writeHead(w.status||500,{"content-type":"application/json"}).end(JSON.stringify({error:w.code||w.message}))}finally{clearInterval(p)}}})}function Ee(e,t,i,g){return{id:"orcha-runtime",name:"Orcha Channel and authorized tools",register(d){let O=fe(d);d.registerHttpRoute({path:"/plugins/orcha-runtime/mcp-bindings",auth:"gateway",match:"exact",async handler(s,u){let _=(c,M)=>{u.writeHead(c,{"content-type":"application/json"}),u.end(JSON.stringify(M))};try{if(s.method==="GET"){_(200,{ready:!0});return}if(!["PUT","DELETE"].includes(s.method)){_(405,{error:"method_not_allowed"});return}let c=await B(s);if(await e(),typeof c.runId!="string"||!c.runId||typeof c.sessionKey!="string"||!c.sessionKey){_(422,{error:"invalid_binding_identity"});return}let M=O.active(c.sessionKey);if(s.headers["if-match"]&&s.headers["if-match"]!==c.runId){_(409,{error:"binding_run_conflict"});return}if(M&&M.runId!==c.runId){_(409,{error:"session_already_bound"});return}s.method==="DELETE"?O.release(c.sessionKey):await O.bind(c,{refresh:!!s.headers["if-match"]}),_(200,{[s.method==="DELETE"?"released":"bound"]:!0})}catch(c){u.writableEnded||_(c.status||422,{error:c.message})}}}),_e(d,O,e,t,i,g)}}}import{isFastModeAutoProgressPayload as Fe,isReasoningReplyPayload as Je,isReplyPayloadNonTerminalToolErrorWarning as We,isReplyPayloadTtsSupplement as ze}from"openclaw/plugin-sdk/reply-payload";import{isSilentReplyText as Te}from"openclaw/plugin-sdk/reply-chunking";function Oe(e){return e?.role!=="assistant"||e.stopReason!=="stop"?!1:typeof e.content=="string"?Te(e.content):!Array.isArray(e.content)||e.content.some(t=>!["text","thinking"].includes(t.type))?!1:Te(e.content.filter(t=>t.type==="text").map(t=>t.text).join(`
8
+ `))}function Ae(e){return!Je(e)&&!e.isCommentary&&!e.isCompactionNotice&&!e.isFallbackNotice&&!e.isStatusNotice&&!Fe(e)&&!We(e)&&!ze(e)}var Ot=Ee(async()=>{await Ke()?.revalidate?.()},Ae,Ye,Oe);export{Ot as default};
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orcha-ai/openclaw-tools",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "openclaw": { "extensions": ["./index.js"] }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orcha-ai/runtime-bridge",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Local Orcha runtime bridge for ACP-compatible agent runtimes.",