@orcha-ai/runtime-bridge 0.1.45 → 0.1.46

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.45.tgz --access public --registry=https://registry.npmjs.org
83
+ npm publish ./dist/orcha-ai-runtime-bridge-0.1.46.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.
@@ -93,17 +93,21 @@ Tests cover discovery errors, paths, public-field filtering, immutable commands,
93
93
 
94
94
  To check reply classification against the real SDK without installing or starting a Gateway, extract the official `openclaw@2026.7.1` npm tarball and run `npm run test:openclaw-sdk -- /absolute/path/to/extracted/package`. This check imports the actual SDK functions, covering final text/media, reasoning, commentary, status/progress notices and TTS supplements; it does not replace a live host/model acceptance test.
95
95
 
96
+ ## Tool error warnings (0.1.46)
97
+
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
+
96
100
  ## Long chats and independent topics (0.1.45)
97
101
 
98
102
  Bridge and the bundled OpenClaw plugin are versioned together. Version 0.1.45 accepts an explicit `taskContextId: null` for long chats and independent topic conversations. Missing or invalid task identifiers still fail validation. Native session keys include the conversation ID, so separate conversations remain isolated even when both have no embedded task ID. External proactive messages and background results use the existing long chat unless bound to an existing run.
99
103
 
100
- Only an explicit new-topic action creates an independent conversation. The corresponding Core/frontend update requires the memory and checkpoint migration described in [长聊与独立话题](../docs/新文档/02-AI对话/36-默认长聊与独立话题列表交互建议.md). Publishing this package does not deploy Core or migrate its database. Upgrade the device package and run Bridge `reload` to install the bundled plugin; update remote Gateway plugins on their own host. No wire protocol version or environment variable is added.
104
+ Only the UI new-topic action creates an independent conversation. `/new` resets the context inside the current conversation. The corresponding Core/frontend update requires the memory and checkpoint migration described in [长聊与独立话题](../docs/新文档/02-AI对话/36-默认长聊与独立话题列表交互建议.md). Publishing this package does not deploy Core or migrate its database. Upgrade the device package and run Bridge `reload` to install the bundled plugin; update remote Gateway plugins on their own host. No wire protocol version or environment variable is added.
101
105
 
102
106
  ## Native conversation context
103
107
 
104
108
  OpenClaw native Channel and device Codex conversations send only the current message and attachments. Orcha conversation IDs and optional historical task IDs define conversation boundaries; native runtimes own history and compaction. OpenClaw session keys include the Core endpoint, binding revision, chat/task/member and history/policy scope. Codex saves the actual `thread.started.thread_id` under `~/.orcha/codex-sessions/` and uses `codex exec resume <thread-id>` for later turns. The identity also includes the endpoint, Agent, target, workspace and Codex home. It never uses `--last`. Each turn still has a separate run ID, tool credential and retry fence. Device Codex closes its temporary MCP proxy after each turn and opens a fresh one for the next.
105
109
 
106
- Send exactly `/new` to an Agent to create an independent topic conversation, using the same creation service as the UI. It creates no model run and is not forwarded to OpenClaw or Codex. In a group, select the Agent explicitly; send the command without attachments, plugins or skills. The receipt returns the new `sessionId`, `taskContextId:null` and `runId:null`; clients must select that conversation for subsequent messages. An already running conversation continues independently. Other raw commands, such as `/status`, reach OpenClaw and remain subject to its own command permissions.
110
+ Send exactly `/new` to an Agent to reset context while staying in the current conversation. It creates no model run and is not forwarded to OpenClaw or Codex. Core records a centered “已开始新对话” system notice; existing messages remain visible, while subsequent model context starts after this boundary. The receipt retains the same `sessionId` and task scope with `runId:null`. In a group, select an Agent explicitly; send the command without a quoted message, attachments, plugins or skills. Complete or stop unfinished work in that context before resetting. The existing history boundary in native session keys makes the next OpenClaw/Codex turn start a fresh native conversation. Other raw commands, such as `/status`, reach OpenClaw and remain subject to its own command permissions.
107
111
 
108
112
  Old Orcha history and per-run native sessions are not migrated or injected. Upgrade Core, Bridge and the bundled plugin together. A normal Bridge restart preserves completed Codex conversations. If a process crashes during a Codex turn, its durable lock remains and the affected conversation requires `/new`: automatically replaying a detached process could repeat side effects. Missing/mismatched native IDs and repeated run IDs fail explicitly. Keep the local Codex home and Orcha session mapping together; clearing either does not authorize silently starting over in the same conversation.
109
113
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{spawn as dc}from"node:child_process";import{closeSync as fc,existsSync as Er,mkdirSync as pc,openSync as hc,readFileSync as yr,rmSync as mc,statSync as us,writeFileSync as hs}from"node:fs";import{dirname as ms,resolve as pt}from"node:path";import{fileURLToPath as gc}from"node:url";import{createHash as Ur}from"node:crypto";import{mkdir as bs,readFile as Ms,writeFile as Us,rename as Ps}from"node:fs/promises";import{join as br}from"node:path";import{homedir as Ls,hostname as ks}from"node:os";import{execFile as Os}from"node:child_process";import{access as Is,realpath as Cs}from"node:fs/promises";import{constants as xs}from"node:fs";import{delimiter as As,join as xr,isAbsolute as Ar}from"node:path";import{homedir as Cr}from"node:os";async function pe(e,t=process.env){let r=process.platform==="win32"?[".exe",".cmd",".bat",""]:[""];for(let n of(t.PATH||"").split(As).filter(Ar))for(let s of r){let i=xr(n,`${e}${s}`);try{return await Is(i,xs.X_OK),i}catch{}}return null}function Ns(e,t){return new Promise(r=>Os(e,t,{timeout:8e3,maxBuffer:1024*1024,windowsHide:!0},(n,s)=>r({code:n?n.code:0,stdout:String(s||"")})))}async function he(e){let t=e==="~"?Cr():e.startsWith("~/")?xr(Cr(),e.slice(2)):e;if(!Ar(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 Cs(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 Nr({find:e=pe,run:t=Ns,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 y=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:y.code===0?"ready":"needs_setup",message:y.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 Mr(e,t){let r=`${e}.${process.pid}.tmp`;await Us(r,JSON.stringify(t),{mode:384}),await Ps(r,e)}function ge(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=br(Ls(),".orcha","devices"),n=br(r,Ur("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 Nt(e,{url:t,pairCode:r}){let{address:n,root:s,profile:i}=ge(t||e.orchaUrl);await bs(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:ks()})}),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 Mr(i,o)}else try{o=JSON.parse(await Ms(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 me(e,o,async()=>Mr(i,o))}var me=class{constructor(t,r,n,s=Nr){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 he(String(u.workspace||""));if(d.managed&&p!==await he(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}:${Ur("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 Ws}from"node:child_process";import{constants as Xs}from"node:fs";import{access as Br,readFile as jr,realpath as Ys}from"node:fs/promises";import{join as _e}from"node:path";import{promisify as Qs}from"node:util";var J="0.1.45";function _t(){return new Date().toISOString()}function P(e,t=2){return String(e).padStart(t,"0")}function Pr(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${P(Math.floor(r/60))}:${P(r%60)}`}function vs(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)}`,Pr(t)].join("")}function Ds(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 Hs(e,t){let r=Ds(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)}`,Pr(s)].join("")}function Fs(e=new Date){let t=c(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return Hs(e,t)}catch{return vs(e)}}function l(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function c(e){return String(e??"").trim()}function T(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 Z(e,t,r=process.cwd()){let n=l(e)?e:{};return c(n.cwd)||c(n.workspace)||c(t)||c(r)||process.cwd()}var bt="[redacted]",$s=/(authorization|api[_-]?key|credential|password|secret|token)/i;function at(e){return $s.test(c(e))}function Mt(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(bt))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${bt}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${bt}`)}function Q(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]=Q(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=>Q(i,t));return t.delete(e),s}let r={},n=at(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=at(s)||n&&s.toLowerCase()==="value"?bt:Q(i,t);return t.delete(e),r}function Lr(e,t=4e3){let r=JSON.stringify(Q(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function g(e,t,r,n={}){let s={ts:Fs(),level:e,module:t,msg:r,...l(n)?Q(n):{}};console.error(JSON.stringify(s))}var tt="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 kr(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 vr(e,t){if(e.headers.get("content-type")!==tt)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 js}from"node:http";import{randomBytes as qs}from"node:crypto";var Ut={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs"]};var Gs=Object.freeze([...Ut.controlTools,...Ut.residentTools]),Ks=new Set(Gs),zs=8*1024*1024;function Pt(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 Hr(e){let t=0,r=[];for await(let n of e){if(t+=n.length,t>zs)throw new Error("MCP payload exceeds the size limit");r.push(Buffer.from(n))}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function Fr(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 Hr(n.body);if(!s||s.jsonrpc!=="2.0"||s.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return s}async function Dr(e,t){let r=await Fr(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},t),n=r?.result?.tools;if(r?.error)throw new Error("Orcha MCP tool discovery failed");return Js(n)}function Js(e){if(!Array.isArray(e)||e.some(t=>!t||!Ks.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&Ut.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 Vs(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 $r(e){let t=Pt(e),r=new AbortController,n=await Dr(t,r.signal),s=qs(32).toString("hex"),i=js(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 Hr(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 Fr(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=Pt(o,t.url);if(!Vs(n,await Dr(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 V=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:tt}:{},...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 vr(h,o);let m=await h.json();if(!h.ok)throw M(m.error||"OPENCLAW_MCP_BINDING_FAILED");return m}catch(h){throw kr(h,p)}}async bind(t,r=!1){Pt(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 Zs=Qs(Ws),ti=12e4;async function qr(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 dc}from"node:child_process";import{closeSync as fc,existsSync as Er,mkdirSync as pc,openSync as hc,readFileSync as yr,rmSync as mc,statSync as us,writeFileSync as hs}from"node:fs";import{dirname as ms,resolve as pt}from"node:path";import{fileURLToPath as gc}from"node:url";import{createHash as Ur}from"node:crypto";import{mkdir as bs,readFile as Ms,writeFile as Us,rename as Ps}from"node:fs/promises";import{join as br}from"node:path";import{homedir as Ls,hostname as ks}from"node:os";import{execFile as Os}from"node:child_process";import{access as Is,realpath as Cs}from"node:fs/promises";import{constants as xs}from"node:fs";import{delimiter as As,join as xr,isAbsolute as Ar}from"node:path";import{homedir as Cr}from"node:os";async function pe(e,t=process.env){let r=process.platform==="win32"?[".exe",".cmd",".bat",""]:[""];for(let n of(t.PATH||"").split(As).filter(Ar))for(let s of r){let i=xr(n,`${e}${s}`);try{return await Is(i,xs.X_OK),i}catch{}}return null}function Ns(e,t){return new Promise(r=>Os(e,t,{timeout:8e3,maxBuffer:1024*1024,windowsHide:!0},(n,s)=>r({code:n?n.code:0,stdout:String(s||"")})))}async function he(e){let t=e==="~"?Cr():e.startsWith("~/")?xr(Cr(),e.slice(2)):e;if(!Ar(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 Cs(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 Nr({find:e=pe,run:t=Ns,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 y=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:y.code===0?"ready":"needs_setup",message:y.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 Mr(e,t){let r=`${e}.${process.pid}.tmp`;await Us(r,JSON.stringify(t),{mode:384}),await Ps(r,e)}function ge(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=br(Ls(),".orcha","devices"),n=br(r,Ur("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 Nt(e,{url:t,pairCode:r}){let{address:n,root:s,profile:i}=ge(t||e.orchaUrl);await bs(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:ks()})}),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 Mr(i,o)}else try{o=JSON.parse(await Ms(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 me(e,o,async()=>Mr(i,o))}var me=class{constructor(t,r,n,s=Nr){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 he(String(u.workspace||""));if(d.managed&&p!==await he(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}:${Ur("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 Ws}from"node:child_process";import{constants as Xs}from"node:fs";import{access as Br,readFile as jr,realpath as Ys}from"node:fs/promises";import{join as _e}from"node:path";import{promisify as Qs}from"node:util";var J="0.1.46";function _t(){return new Date().toISOString()}function P(e,t=2){return String(e).padStart(t,"0")}function Pr(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${P(Math.floor(r/60))}:${P(r%60)}`}function vs(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)}`,Pr(t)].join("")}function Ds(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 Hs(e,t){let r=Ds(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)}`,Pr(s)].join("")}function Fs(e=new Date){let t=c(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return Hs(e,t)}catch{return vs(e)}}function l(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function c(e){return String(e??"").trim()}function T(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 Z(e,t,r=process.cwd()){let n=l(e)?e:{};return c(n.cwd)||c(n.workspace)||c(t)||c(r)||process.cwd()}var bt="[redacted]",$s=/(authorization|api[_-]?key|credential|password|secret|token)/i;function at(e){return $s.test(c(e))}function Mt(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(bt))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${bt}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${bt}`)}function Q(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]=Q(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=>Q(i,t));return t.delete(e),s}let r={},n=at(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=at(s)||n&&s.toLowerCase()==="value"?bt:Q(i,t);return t.delete(e),r}function Lr(e,t=4e3){let r=JSON.stringify(Q(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function g(e,t,r,n={}){let s={ts:Fs(),level:e,module:t,msg:r,...l(n)?Q(n):{}};console.error(JSON.stringify(s))}var tt="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 kr(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 vr(e,t){if(e.headers.get("content-type")!==tt)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 js}from"node:http";import{randomBytes as qs}from"node:crypto";var Ut={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs"]};var Gs=Object.freeze([...Ut.controlTools,...Ut.residentTools]),Ks=new Set(Gs),zs=8*1024*1024;function Pt(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 Hr(e){let t=0,r=[];for await(let n of e){if(t+=n.length,t>zs)throw new Error("MCP payload exceeds the size limit");r.push(Buffer.from(n))}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function Fr(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 Hr(n.body);if(!s||s.jsonrpc!=="2.0"||s.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return s}async function Dr(e,t){let r=await Fr(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},t),n=r?.result?.tools;if(r?.error)throw new Error("Orcha MCP tool discovery failed");return Js(n)}function Js(e){if(!Array.isArray(e)||e.some(t=>!t||!Ks.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&Ut.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 Vs(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 $r(e){let t=Pt(e),r=new AbortController,n=await Dr(t,r.signal),s=qs(32).toString("hex"),i=js(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 Hr(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 Fr(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=Pt(o,t.url);if(!Vs(n,await Dr(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 V=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:tt}:{},...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 vr(h,o);let m=await h.json();if(!h.ok)throw M(m.error||"OPENCLAW_MCP_BINDING_FAILED");return m}catch(h){throw kr(h,p)}}async bind(t,r=!1){Pt(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 Zs=Qs(Ws),ti=12e4;async function qr(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 pe(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 Ys(a);await Br(u,Xs.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 jr(_e(t,"openclaw.plugin.json"),"utf8")),i=JSON.parse(await jr(_e(t,"package.json"),"utf8"));if(await Br(_e(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 V(s,{}).request("GET",void 0,!1,"deliveries")).streamType!==tt)throw M("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH")}}async function ye(e,t){try{let{stdout:r}=await Zs(e.command,t,{env:e.env,timeout:ti,killSignal:"SIGKILL",maxBuffer:1048576,windowsHide:!0});return r}catch(r){let n=Object.entries(e.env).filter(([i])=>at(i)).map(([,i])=>i),s=Mt(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 ca,randomUUID as te}from"node:crypto";function Lt(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,5 +1,5 @@
1
1
  import{getPluginRuntimeGatewayRequestScope as xe}from"openclaw/plugin-sdk/plugin-runtime";import{loadOutboundMediaFromUrl as He}from"openclaw/plugin-sdk/outbound-media";var $={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs"]};var G=Object.freeze([...$.controlTools,...$.residentTools]),_e=new Set(G),Ee=8*1024*1024;function oe(e,n){if(!Array.isArray(e)||e.length!==1)throw new Error("one task-scoped Orcha MCP server is required");let s=e[0],p=new URL(s.url);if(s.name!=="orcha"||s.type!=="http"||!["http:","https:"].includes(p.protocol)||p.username||p.password||p.hash||n&&p.href!==new URL(n).href)throw new Error("Orcha MCP server does not match the trusted binding");let m=Object.fromEntries((s.headers||[]).map(({name:h,value:f})=>[h.toLowerCase(),f]));if(!String(m.authorization||"").startsWith("Bearer "))throw new Error("Orcha MCP task credentials are missing");return{url:p.href,headers:{...m,"content-type":"application/json",accept:"application/json"}}}async function B(e){let n=0,s=[];for await(let p of e){if(n+=p.length,n>Ee)throw new Error("MCP payload exceeds the size limit");s.push(Buffer.from(p))}return JSON.parse(Buffer.concat(s).toString("utf8"))}async function Q(e,n,s){let p=await fetch(e.url,{method:"POST",headers:e.headers,body:JSON.stringify(n),redirect:"error",signal:AbortSignal.any([AbortSignal.timeout(36e5),...s?[s]:[]])});if(!p.ok)throw new Error(`Orcha MCP request failed (${p.status})`);if(p.status===202||p.status===204)return null;let m=await B(p.body);if(!m||m.jsonrpc!=="2.0"||m.id!==n.id)throw new Error("Orcha MCP response identity mismatch");return m}async function ae(e,n){let s=await Q(e,{jsonrpc:"2.0",id:"orcha-bind-tools",method:"tools/list"},n),p=s?.result?.tools;if(s?.error)throw new Error("Orcha MCP tool discovery failed");return Oe(p)}function Oe(e){if(!Array.isArray(e)||e.some(n=>!n||!_e.has(n.name)||n.inputSchema?.type!=="object"||typeof n.description!="string")||new Set(e.map(n=>n.name)).size!==e.length||e.length&&$.controlTools.some(n=>!e.some(s=>s.name===n)))throw new Error("Orcha MCP returned an unsupported or invalid authorized tool catalog");return e}function se(e,n){let s=m=>Array.isArray(m)?m.map(s):m&&typeof m=="object"?Object.fromEntries(Object.keys(m).sort().map(h=>[h,s(m[h])])):m,p=m=>m.map(({name:h,inputSchema:f})=>({name:h,inputSchema:f})).sort((h,f)=>h.name.localeCompare(f.name));return JSON.stringify(s(p(e)))===JSON.stringify(s(p(n)))}var V=e=>Object.assign(new Error(e),{status:409});function ie(e){let n=new Map,s=e.pluginConfig?.allowedOrchaMcpUrl;if(!s)throw new Error("Orcha plugin requires allowedOrchaMcpUrl");function p(f,i=n.get(f)){!i||n.get(f)!==i||(i.lifetime.abort(),clearTimeout(i.timer),n.delete(f))}function m(f){let i=n.get(f);return i&&i.deadline<=Date.now()?(p(f,i),null):i}async function h(f,{refresh:i=!1}={}){let{runId:d,sessionKey:T,agentCode:L,expiresAt:P,mcpServer:t}=f,u=Date.parse(P);if(typeof d!="string"||!d||typeof T!="string"||!T||typeof L!="string"||!L||!T.startsWith(`agent:${L}:`)||!Number.isFinite(u)||u<=Date.now()||u>Date.now()+24*36e5)throw new Error("invalid_binding_scope");let w=m(T);if(i&&!w||w&&(w.runId!==d||w.agentCode!==L||w.deadline!==u))throw V("original_binding_unavailable_or_changed");let r=oe([t],s),c=w?.lifetime||new AbortController,o=await ae(r,c.signal);if(m(T)!==w)throw V("binding_changed");if(w){if(!se(w.tools,o))throw V("frozen_tool_catalog_changed");w.upstream=r}else{let a={runId:d,agentCode:L,deadline:u,upstream:r,tools:o,lifetime:c};a.timer=setTimeout(()=>p(T,a),u-Date.now()),a.timer.unref?.(),n.set(T,a)}}return e.registerTool(f=>{let i=m(f.sessionKey);return!i||f.agentId!==i.agentCode?null:i.tools.map(d=>({name:`orcha_${d.name}`,label:`Orcha ${d.name}`,description:d.description,parameters:d.inputSchema,async execute(T,L,P){if(m(f.sessionKey)!==i||f.agentId!==i.agentCode||!T||!i.tools.some(u=>u.name===d.name))throw new Error("Orcha task binding expired or changed");let t=await Q(i.upstream,{jsonrpc:"2.0",id:T,method:"tools/call",params:{name:d.name,arguments:L}},AbortSignal.any([i.lifetime.signal,...P?[P]:[]]));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:G.map(f=>`orcha_${f}`)}),{bind:h,active:m,release:p,allowedUrl:s}}import{createHash as Ne}from"node:crypto";import{mkdirSync as Ce,readFileSync as be,renameSync as Se,writeFileSync as Re}from"node:fs";import{join as ue}from"node:path";import{createHash as Te}from"node:crypto";var ce=e=>Te("sha256").update(JSON.stringify(e)).digest("hex"),D=e=>Object.assign(new Error(e),{code:e}),q=e=>{let n=String(e||"").replace(/^orcha:/,"");return/^[1-9]\d{0,18}$/.test(n)?n:void 0},de={normalizeTarget:q,targetResolver:{looksLikeId:e=>!!q(e),hint:"Orcha session ID"}};function le({core:e,load:n,save:s,loadMedia:p,activeRun:m}){let h=new Map,f=(t,u)=>ce([t,u]),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 d(t,u,w={}){return await w.onPlatformSendDispatch?.(),w.signal?.throwIfAborted(),i(await e(t,"/messages",u.payload,{cfg:w.cfg,signal:w.signal}))}async function T(t){t.signal?.throwIfAborted();let u=q(t.to);if(!u)throw D("invalid_conversation");if(!t.deliveryQueueId)throw D("OPENCLAW_DURABLE_DELIVERY_ID_REQUIRED");let w=t.run&&t.run.delivery.bindingId===t.accountId&&t.run.delivery.sessionId===u?t.run:null,r=t.replyToId||w?.delivery.messageId||null,c=t.payload||{text:t.text||"",mediaUrl:t.mediaUrl},o=c.mediaUrls||(c.mediaUrl?[c.mediaUrl]:[]),a=f(t.accountId,t.deliveryQueueId),l=ce([u,c.text||"",o,r,w?.runId||null]),I=n(a,"sends");if(I&&I.requestHash!==l)throw D("channel_send_conflict");let _=h.get(a);if(_){if(_.requestHash!==l)throw D("channel_send_conflict");return _.promise}let O=(async()=>{let g=I;if(!g){let y=[];for(let v of o){let C=await p(v,{maxBytes:33554432,mediaAccess:t.mediaAccess,mediaReadFile:t.mediaReadFile,mediaLocalRoots:t.mediaLocalRoots}),N=new FormData;N.set("sessionId",u),N.set("file",new Blob([C.buffer],{type:C.contentType||"application/octet-stream"}),C.fileName||"attachment"),y.push((await e(t.accountId,"/files",N,{cfg:t.cfg,signal:t.signal})).inputPart)}g={requestHash:l,payload:{sourceMessageId:`openclaw:${a}`,sessionId:u,content:c.text||"",inputParts:y,...r?{replyToMessageId:r}:{},...w?{agentRunId:w.runId}:{}}},s(a,g,"sends")}let A=await d(t.accountId,g,t);return w&&!w.messageIds.includes(A.messageId)&&w.messageIds.push(A.messageId),A})().finally(()=>h.delete(a));return h.set(a,{requestHash:l,promise:O}),O}return{send:T,message:{send:{text:T,media:T,payload:T},durableFinal:{capabilities:{text:!0,media:!0,payload:!0,replyTo:!0,reconcileUnknownSend:!0},reconcileUnknownSendKinds:{text:!0,media:!0,payload:!0},async reconcileUnknownSend(t){let u=n(f(t.accountId,t.queueId),"sends");if(!u)return{status:"not_sent"};if(u.payload.sessionId!==String(t.to).replace(/^orcha:/,""))throw D("channel_send_conflict");let w=await d(t.accountId,u,t);return{status:"sent",receipt:w.receipt,messageId:w.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 D("unsupported_channel_action");let u=t.params;if(t.dryRun)return{content:[{type:"text",text:"Orcha send dry run"}],details:{dryRun:!0}};let w=m(t.sessionKey),r=await T({cfg:t.cfg,accountId:t.accountId,to:u.to||u.target,text:u.message,mediaUrl:u.media,replyToId:u.replyTo,deliveryQueueId:u.idempotencyKey,mediaAccess:t.mediaAccess,mediaLocalRoots:t.mediaLocalRoots,mediaReadFile:t.mediaReadFile,run:w,signal:w?.controller.signal});return{content:[{type:"text",text:JSON.stringify(r)}],details:r}}}}}var J="application/x-orcha-channel-events-v2+ndjson";function W(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 X(e,n){let s=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(s)?Object.assign(W("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:s||"REQUEST_TIMEOUT"}}):e}var me=e=>Ne("sha256").update(JSON.stringify(e)).digest("hex"),R=(e,n=409)=>Object.assign(new Error(e),{status:n,code:e}),z=e=>typeof e=="string"&&/^[1-9]\d{0,18}$/.test(e),Me=e=>new Promise(n=>setTimeout(n,e));function pe(e,n,s){return`agent:${e}:orcha:task:${me([s,n.bindingId,n.bindingRevision,n.sessionId,n.taskContextId,n.memberId,n.historyFromSeq,n.runtimePolicyRevision])}`}function he(e,n,s,p,m){let h=new Map,f=()=>e.config;function i(r,c=f()){let o=c?.channels?.orcha?.accounts?.[r];if(!z(r)||!o||o.enabled===!1||!o.serviceToken||!o.agentId)throw R("orcha_channel_account_unavailable",403);return{...o,accountId:r}}async function d(r,c,o,{cfg:a,signal:l,method:I="POST"}={}){let _=i(r,a),O=new URL(`/api/agent-channels${c}`,n.allowedUrl),g=o instanceof FormData,A=AbortSignal.any([AbortSignal.timeout(3e4),...l?[l]:[]]);try{let y=await fetch(O,{method:I,redirect:"error",signal:A,headers:{authorization:`Bearer ${_.serviceToken}`,...g?{}:{"content-type":"application/json"}},...o!==void 0?{body:g?o:JSON.stringify(o)}:{}}),v=await B(y.body);if(!y.ok||v.success!==!0)throw R(`orcha_channel_request_${y.status}`,y.status);return v.data}catch(y){throw X(y,A)}}function T(r,c="runs"){if(!/^[a-zA-Z0-9_-]{1,128}$/.test(r))throw R("invalid_record_identity",422);let o=ue(e.runtime.state.resolveStateDir(),"plugins","orcha-runtime",c);return Ce(o,{recursive:!0,mode:448}),ue(o,`${r}.json`)}function L(r,c){try{return JSON.parse(be(T(r,c),"utf8"))}catch(o){if(o.code==="ENOENT")return null;throw o}}function P(r,c,o){let a=T(r,o),l=`${a}.pending`;Re(l,JSON.stringify(c),{mode:384}),Se(l,a)}async function t(r,c=!1,o){let a=i(r.delivery?.bindingId),{runId:l,delivery:I}=r;if(!z(l)||!z(I.sessionId)||I.taskContextId!==null&&!z(I.taskContextId)||I.mode!=="channel"||r.agentCode!==a.agentId)throw R("invalid_channel_delivery",422);if(!Array.isArray(r.prompt)||r.prompt.some(b=>!["text","image","file"].includes(b.type)||(b.type==="text"?typeof b.text!="string":typeof b.uri!="string")))throw R("invalid_channel_prompt",422);let _=me({agentCode:r.agentCode,delivery:I,prompt:r.prompt}),O=L(l);if(O&&O.requestHash!==_)throw R("channel_delivery_conflict");if(O?.status==="completed")return O.result;if(O?.status==="failed")throw R(O.error);let g=h.get(l),A=O?.expiresAt||r.expiresAt,y=pe(a.agentId,I,n.allowedUrl),v=()=>{let b=n.active(y);b?.runId===l&&n.release(y,b)},C=O?.hostRunId||`orcha-${l}`;if(O&&!g||r.attachOnly&&!g&&!O)throw R("RUNTIME_OPERATION_NOT_FOUND");if(g){try{await n.bind({runId:l,sessionKey:y,agentCode:a.agentId,expiresAt:A,mcpServer:r.mcpServer},{refresh:!0})}catch(b){if(h.get(l)!==g)return await g.promise;throw b}if(c)return{refreshed:!0};g.listeners.add(o);try{for(let b of g.updates)o?.(b);return await g.promise}finally{g.listeners.delete(o)}}if(c)throw R("RUNTIME_OPERATION_NOT_FOUND");let N=new AbortController,M={runId:l,delivery:I,messageIds:[],controller:N,promise:null,listeners:new Set(o?[o]:[]),updates:[],bytes:0},k=b=>{let U={type:"update",payload:{sessionId:y,update:b,_meta:{channelUpdateId:`${C}:${M.updates.length+1}`}}},H=Buffer.byteLength(JSON.stringify(U));if(H>2097152||M.bytes+H>16777216){N.abort(W("OPENCLAW_CHANNEL_PROGRESS_LIMIT"));return}M.bytes+=H,M.updates.push(U);for(let K of M.listeners)K?.(U)};return h.set(l,M),M.promise=(async()=>{await n.bind({runId:l,sessionKey:y,agentCode:a.agentId,expiresAt:A,mcpServer:r.mcpServer}),P(l,{requestHash:_,status:"running",sessionKey:y,hostRunId:C,expiresAt:A});let b=0,U,H,K=setTimeout(()=>N.abort(R("run_timeout")),Date.parse(A)-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");H=e.runtime.events.onAgentEvent(E=>{let S=E.data;E.runId!==C||E.stream!=="tool"||!S?.toolCallId||S.hideFromChannelProgress||!["start","update","result"].includes(S.phase)||k({sessionUpdate:S.phase==="start"?"tool_call":"tool_call_update",toolCallId:S.toolCallId,title:S.name,status:S.phase==="result"?S.isError?"failed":"completed":"in_progress",...S.args?{rawInput:S.args}:{},...S.result!==void 0?{rawOutput:S.result}:{}})});let x="",ee=E=>{if(E.requiresReasoningProgressOptIn||typeof E.text!="string")return;let S=E.text.startsWith(x)?E.text.slice(x.length):E.text;x=E.text,S&&k({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:S}})},F=r.prompt.filter(E=>E.type==="text").map(E=>E.text).join(`
2
2
 
3
- `),te=r.prompt.filter(E=>E.type!=="text"),ye={Body:F,BodyForAgent:F,BodyForCommands:F,RawBody:F,From:`orcha:${I.memberId}`,To:`orcha:${I.sessionId}`,SessionKey:y,AccountId:I.bindingId,Provider:"orcha",Surface:"orcha",ChatType:"direct",OriginatingChannel:"orcha",OriginatingTo:I.sessionId,MessageSid:I.messageId||l,MediaUrls:te.map(E=>E.uri),MediaTypes:te.map(E=>E.mimeType||"application/octet-stream"),CommandAuthorized:!1,WasMentioned:!0};if(await j.dispatchReplyWithBufferedBlockDispatcher({ctx:ye,cfg:f(),replyOptions:{runId:C,abortSignal:N.signal,suppressTyping:!0,suppressDefaultToolProgressMessages:!0,reasoningPayloadsEnabled:!0,commentaryPayloadsEnabled:!0,onAssistantMessageStart:()=>{x=""},onReasoningStream:ee},dispatcherOptions:{deliver:async(E,S)=>{if(N.signal.throwIfAborted(),E.isReasoning&&ee(E),E.isCommentary&&E.text&&k({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:E.text}}),S.kind==="final"&&p(E)){let Y=f(),re=Y?.agents?.list?.find(we=>we.id===a.agentId)?.workspace||Y?.agents?.defaults?.workspace;await u.send({cfg:Y,accountId:I.bindingId,to:I.sessionId,payload:E,run:M,deliveryQueueId:`${C}:final:${++b}`,signal:N.signal,mediaLocalRoots:re?[re]:void 0})}},onError:E=>{U??=E}}}),U)throw U;if(N.signal.throwIfAborted(),!M.messageIds.length)throw R("runtime_node_empty_result");let ne={stopReason:"end_turn",messageIds:M.messageIds,sessionId:y};return P(l,{requestHash:_,status:"completed",sessionKey:y,hostRunId:C,expiresAt:A,result:ne}),ne}catch(j){let x=N.signal.aborted?N.signal.reason:X(j,N.signal);throw P(l,{requestHash:_,status:"failed",sessionKey:y,hostRunId:C,expiresAt:A,error:x.code||"channel_host_failed"}),x}finally{H?.(),clearTimeout(K),v(),h.delete(l)}})().catch(b=>{throw v(),h.delete(l),b}),M.promise}let u=le({core:d,load:L,save:P,loadMedia:m,activeRun:r=>h.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,c)=>{let o=r?.channels?.orcha?.accounts?.[c];return{enabled:!!(o&&o.enabled!==!1),configured:!!(o?.serviceToken&&o?.agentId),tokenStatus:o?.serviceToken?"available":"missing"}},resolveAccount:(r,c)=>i(c,r),isEnabled:r=>r.enabled!==!1,isConfigured:r=>!!(r.serviceToken&&r.agentId)},outbound:{deliveryMode:"direct",textChunkLimit:1e5},message:u.message,actions:u.actions,messaging:de}});async function w(r){let{accountId:c,grantId:o,externalInvocationId:a}=r;i(c);let l=await d(c,"/runs",{grantId:o,externalInvocationId:a,input:r.input||{}}),I=l.agentRunId;if(["completed","failed","cancelled","expired"].includes(l.status))return l;let _;do _=await d(c,`/runs/${I}/claim`,{}),_.attemptId||await Me(Math.max(1,_.retryAfterSeconds||2)*1e3);while(!_.attemptId);let O=pe(i(c).agentId,_.delivery,n.allowedUrl),g,A=!1,y=setInterval(async()=>{if(!A){A=!0;try{let N=await d(c,`/runs/${I}/heartbeat`,{attemptId:_.attemptId});n.active(O)&&await n.bind({runId:I,sessionKey:O,agentCode:i(c).agentId,expiresAt:_.expiresAt,mcpServer:N.mcpServer},{refresh:!0})}catch(N){g=N,h.get(I)?.controller.abort(N),n.release(O)}finally{A=!1}}},Math.max(1,_.heartbeatIntervalSeconds)*1e3),v,C;try{let N;try{N=await t({runId:I,agentCode:i(c).agentId,delivery:_.delivery,prompt:[{type:"text",text:JSON.stringify({task:_.prompt,eventInput:_.input})}],mcpServer:_.mcpServer,expiresAt:_.expiresAt,attachOnly:_.recovery})}catch(k){C=k}if(g)throw g;v=C?{attemptId:_.attemptId,errorMessage:W(C.code||"channel_host_failed").message,status:"failed"}:{attemptId:_.attemptId,messageIds:N.messageIds,status:"completed"};let M=await d(c,`/runs/${I}/complete`,v);if(C)throw C;return M}finally{clearInterval(y),n.release(O)}}for(let[r,c]of[["deliveries",t],["background",w]])e.registerHttpRoute({path:`/plugins/orcha-runtime/${r}`,auth:"gateway",match:"exact",async handler(o,a){let l,I=Promise.resolve(),_=0,O=g=>{if(a.destroyed||a.writableEnded)return;let A=JSON.stringify(g)+`
3
+ `),te=r.prompt.filter(E=>E.type!=="text"),ye={Body:F,BodyForAgent:F,BodyForCommands:F,RawBody:F,From:`orcha:${I.memberId}`,To:`orcha:${I.sessionId}`,SessionKey:y,AccountId:I.bindingId,Provider:"orcha",Surface:"orcha",ChatType:"direct",OriginatingChannel:"orcha",OriginatingTo:I.sessionId,MessageSid:I.messageId||l,MediaUrls:te.map(E=>E.uri),MediaTypes:te.map(E=>E.mimeType||"application/octet-stream"),CommandAuthorized:!1,WasMentioned:!0};if(await j.dispatchReplyWithBufferedBlockDispatcher({ctx:ye,cfg:f(),replyOptions:{runId:C,abortSignal:N.signal,suppressTyping:!0,suppressDefaultToolProgressMessages:!0,suppressToolErrorWarnings:!0,reasoningPayloadsEnabled:!0,commentaryPayloadsEnabled:!0,onAssistantMessageStart:()=>{x=""},onReasoningStream:ee},dispatcherOptions:{deliver:async(E,S)=>{if(N.signal.throwIfAborted(),E.isReasoning&&ee(E),E.isCommentary&&E.text&&k({sessionUpdate:"agent_thought_chunk",content:{type:"text",text:E.text}}),S.kind==="final"&&p(E)){let Y=f(),re=Y?.agents?.list?.find(we=>we.id===a.agentId)?.workspace||Y?.agents?.defaults?.workspace;await u.send({cfg:Y,accountId:I.bindingId,to:I.sessionId,payload:E,run:M,deliveryQueueId:`${C}:final:${++b}`,signal:N.signal,mediaLocalRoots:re?[re]:void 0})}},onError:E=>{U??=E}}}),U)throw U;if(N.signal.throwIfAborted(),!M.messageIds.length)throw R("runtime_node_empty_result");let ne={stopReason:"end_turn",messageIds:M.messageIds,sessionId:y};return P(l,{requestHash:_,status:"completed",sessionKey:y,hostRunId:C,expiresAt:A,result:ne}),ne}catch(j){let x=N.signal.aborted?N.signal.reason:X(j,N.signal);throw P(l,{requestHash:_,status:"failed",sessionKey:y,hostRunId:C,expiresAt:A,error:x.code||"channel_host_failed"}),x}finally{H?.(),clearTimeout(K),v(),h.delete(l)}})().catch(b=>{throw v(),h.delete(l),b}),M.promise}let u=le({core:d,load:L,save:P,loadMedia:m,activeRun:r=>h.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,c)=>{let o=r?.channels?.orcha?.accounts?.[c];return{enabled:!!(o&&o.enabled!==!1),configured:!!(o?.serviceToken&&o?.agentId),tokenStatus:o?.serviceToken?"available":"missing"}},resolveAccount:(r,c)=>i(c,r),isEnabled:r=>r.enabled!==!1,isConfigured:r=>!!(r.serviceToken&&r.agentId)},outbound:{deliveryMode:"direct",textChunkLimit:1e5},message:u.message,actions:u.actions,messaging:de}});async function w(r){let{accountId:c,grantId:o,externalInvocationId:a}=r;i(c);let l=await d(c,"/runs",{grantId:o,externalInvocationId:a,input:r.input||{}}),I=l.agentRunId;if(["completed","failed","cancelled","expired"].includes(l.status))return l;let _;do _=await d(c,`/runs/${I}/claim`,{}),_.attemptId||await Me(Math.max(1,_.retryAfterSeconds||2)*1e3);while(!_.attemptId);let O=pe(i(c).agentId,_.delivery,n.allowedUrl),g,A=!1,y=setInterval(async()=>{if(!A){A=!0;try{let N=await d(c,`/runs/${I}/heartbeat`,{attemptId:_.attemptId});n.active(O)&&await n.bind({runId:I,sessionKey:O,agentCode:i(c).agentId,expiresAt:_.expiresAt,mcpServer:N.mcpServer},{refresh:!0})}catch(N){g=N,h.get(I)?.controller.abort(N),n.release(O)}finally{A=!1}}},Math.max(1,_.heartbeatIntervalSeconds)*1e3),v,C;try{let N;try{N=await t({runId:I,agentCode:i(c).agentId,delivery:_.delivery,prompt:[{type:"text",text:JSON.stringify({task:_.prompt,eventInput:_.input})}],mcpServer:_.mcpServer,expiresAt:_.expiresAt,attachOnly:_.recovery})}catch(k){C=k}if(g)throw g;v=C?{attemptId:_.attemptId,errorMessage:W(C.code||"channel_host_failed").message,status:"failed"}:{attemptId:_.attemptId,messageIds:N.messageIds,status:"completed"};let M=await d(c,`/runs/${I}/complete`,v);if(C)throw C;return M}finally{clearInterval(y),n.release(O)}}for(let[r,c]of[["deliveries",t],["background",w]])e.registerHttpRoute({path:`/plugins/orcha-runtime/${r}`,auth:"gateway",match:"exact",async handler(o,a){let l,I=Promise.resolve(),_=0,O=g=>{if(a.destroyed||a.writableEnded)return;let A=JSON.stringify(g)+`
4
4
  `,y=Buffer.byteLength(A);if(y>2097152||_+a.writableLength+y>2097152){a.destroy();return}return _+=y,I=I.then(async()=>{a.destroyed||a.writableEnded||(await s(),a.write(A))}).catch(v=>{!a.destroyed&&!a.writableEnded&&a.end(JSON.stringify({type:"error",code:v.code||"OPENCLAW_CHANNEL_AUTH_FAILED"})+`
5
5
  `)}).finally(()=>{_-=y}),I};try{if(r==="deliveries"&&o.method==="GET"){await s(),a.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({streamType:J}));return}if(!["POST","PATCH","DELETE"].includes(o.method))throw R("method_not_allowed",405);let g=await B(o);if(await s(),r==="deliveries"&&o.method==="POST"){if(o.headers.accept!==J)throw R("OPENCLAW_CHANNEL_PROTOCOL_MISMATCH",409);a.writeHead(200,{"content-type":J,"cache-control":"no-store","x-accel-buffering":"no"}),O({type:"heartbeat"}),l=setInterval(()=>O({type:"heartbeat"}),15e3),a.once("close",()=>clearInterval(l));let y=await t(g,!1,O);await s(),await O({type:"result",result:y}),a.end();return}if(o.method==="DELETE"){let y=h.get(g.runId);y?.controller.abort(R("RUNTIME_OPERATION_CANCELLED")),a.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({cancelled:!!y}));return}if(o.method==="PATCH"&&r!=="deliveries")throw R("method_not_allowed",405);let A=await c(g,o.method==="PATCH");await s(),a.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify(A))}catch(g){a.headersSent?(await O({type:"error",code:g.code||"channel_host_failed"}),a.end()):a.writableEnded||a.writeHead(g.status||500,{"content-type":"application/json"}).end(JSON.stringify({error:g.code||g.message}))}finally{clearInterval(l)}}})}function fe(e,n,s){return{id:"orcha-runtime",name:"Orcha Channel and authorized tools",register(p){let m=ie(p);p.registerHttpRoute({path:"/plugins/orcha-runtime/mcp-bindings",auth:"gateway",match:"exact",async handler(h,f){let i=(d,T)=>{f.writeHead(d,{"content-type":"application/json"}),f.end(JSON.stringify(T))};try{if(h.method==="GET"){i(200,{ready:!0});return}if(!["PUT","DELETE"].includes(h.method)){i(405,{error:"method_not_allowed"});return}let d=await B(h);if(await e(),typeof d.runId!="string"||!d.runId||typeof d.sessionKey!="string"||!d.sessionKey){i(422,{error:"invalid_binding_identity"});return}let T=m.active(d.sessionKey);if(h.headers["if-match"]&&h.headers["if-match"]!==d.runId){i(409,{error:"binding_run_conflict"});return}if(T&&T.runId!==d.runId){i(409,{error:"session_already_bound"});return}h.method==="DELETE"?m.release(d.sessionKey):await m.bind(d,{refresh:!!h.headers["if-match"]}),i(200,{[h.method==="DELETE"?"released":"bound"]:!0})}catch(d){f.writableEnded||i(d.status||422,{error:d.message})}}}),he(p,m,e,n,s)}}}import{isFastModeAutoProgressPayload as ve,isReasoningReplyPayload as Le,isReplyPayloadNonTerminalToolErrorWarning as Pe,isReplyPayloadTtsSupplement as Ue}from"openclaw/plugin-sdk/reply-payload";function ge(e){return!Le(e)&&!e.isCommentary&&!e.isCompactionNotice&&!e.isFallbackNotice&&!e.isStatusNotice&&!ve(e)&&!Pe(e)&&!Ue(e)}var dt=fe(async()=>{await xe()?.revalidate?.()},ge,He);export{dt as default};
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orcha-ai/openclaw-tools",
3
- "version": "0.1.45",
3
+ "version": "0.1.46",
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.45",
3
+ "version": "0.1.46",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Local Orcha runtime bridge for ACP-compatible agent runtimes.",