@orcha-ai/runtime-bridge 0.1.59 → 0.1.60

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
@@ -94,7 +94,7 @@ Version 0.1.44 routes replies, native `message` tool sends, and background notif
94
94
 
95
95
  ```bash
96
96
  npm run release:check &&
97
- npm publish ./dist/orcha-ai-runtime-bridge-0.1.59.tgz --access public --registry=https://registry.npmjs.org
97
+ npm publish ./dist/orcha-ai-runtime-bridge-0.1.60.tgz --access public --registry=https://registry.npmjs.org
98
98
  ```
99
99
 
100
100
  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.
@@ -192,13 +192,13 @@ Acceptance on 2026-10-08: Bridge checks/tests/build and the PostgreSQL approval
192
192
 
193
193
  ### Codex file delivery (0.1.51)
194
194
 
195
- Codex conversation and delegated turns expose `orcha.send_file({path, message?})` through that turn's local MCP proxy. The tool reads the selected file on the device, uploads it to `POST /api/mcp/orcha/files`, and returns the saved attachment's string `fileId` and `messageId`. Core binds the destination and sender to the signed active run; the model cannot choose another conversation. This uses the same attachment-message persistence as OpenClaw. It does not complete the run or replace the final reply. Because the attachment message and the final reply appear separately, `message` is only a short caption describing the file; the tool schema tells the model not to repeat the final reply's summary there and to omit it when the reply already explains the file.
195
+ Codex conversation and delegated turns expose `orcha.send_file({path, message?})` through that turn's local MCP proxy. The tool reads the selected file on the device, uploads it to `POST /api/mcp/orcha/files`, and returns the saved attachment's string `fileId` and `messageId`. Core binds the destination and sender to the signed active run; the model cannot choose another conversation. All files sent by the same run share its final reply's stable message identity. The first successful upload creates that reply, later uploads append attachments, and finalization replaces the temporary `message` text while retaining every attachment. Delegated members use their own AgentRun identity, so their files remain on their own replies. Sending a file does not complete the run.
196
196
 
197
- Paths must resolve inside the selected workspace, configured artifact roots, or the exact current Codex thread's `generated_images` directory. Other deliverables must first be copied into the workspace. Empty files, non-regular files and files over 32 MiB are rejected locally; Core also enforces its existing `agent_runtime_artifact_max_bytes` limit (20 MiB by default). Same-run retries of the same file and caption reuse the receipt, including after credential refresh; a finished run or expired delegated lease cannot send. Uploaded file retention, group-member access, realtime notification and transaction rollback reuse the existing attachment lifecycle. Local paths and MCP credentials are not included in attachment messages.
197
+ Paths must resolve inside the selected workspace, configured artifact roots, or the exact current Codex thread's `generated_images` directory. Other deliverables must first be copied into the workspace. Empty files, non-regular files and files over 32 MiB are rejected locally; Core also enforces its existing `agent_runtime_artifact_max_bytes` limit (20 MiB by default). `ChatRun.run_plan.fileDeliveries` records each signed source/delivery identity, payload hash, file ID and message ID under the existing parent-run lock. Same-run retries reuse the receipt, including after credential refresh; reusing an identity with different bytes, filename or caption fails. A finished run or expired delegated lease cannot send. Uploaded file retention, group-member access, realtime notification and transaction rollback reuse the existing attachment lifecycle. Local paths and MCP credentials are not included in attachment messages.
198
198
 
199
199
  For these tool-enabled turns, legacy image-generation events no longer publish images automatically: viewing an image, embedding a local Markdown path or inspecting an intermediate result does not deliver it. Other CLI/workflow paths retain their existing artifact collector. Use `send_file` for each intended deliverable, and treat only a successful saved receipt as delivery confirmation.
200
200
 
201
- Rollout requires the updated Core endpoint, then an updated and reloaded device Bridge. There is no database migration, protocol-version change or new project environment variable. This source change has not been published to npm or deployed; historical empty attachment messages are not backfilled.
201
+ Merged replies require the updated Core endpoint; existing Bridge requests keep the same format and receive the same receipt fields. Reload an updated Bridge to receive the revised tool description. There is no database migration, protocol-version change or new project environment variable. Missing `fileDeliveries` on old run records means no recorded deliveries; historical messages are not merged or backfilled. This source change has not been published to npm or deployed.
202
202
 
203
203
  Acceptance on 2026-10-02: Bridge checks/tests/build and the PostgreSQL/Redis file/channel/MCP tests pass. The opt-in installed-Codex test now checks discovery plus an actual file upload to an isolated local fixture. With local `codex-cli 0.153.4`, discovery and `send_file` both stop before invocation with `MCP tool call requires approval, but approval policy is never`. End-to-end model delivery remains unverified, so local service restart was skipped under the repository's failed-validation rule. No host approval policy was changed. Resolve the device's approved MCP policy or implement a supported approval interaction before production acceptance; do not treat this as successful delivery. Codex supports server/tool approval settings in its [official configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference). Resolved for device Codex in 0.1.53: app-server routes Orcha task-tool approvals to Bridge, which accepts them for the Core-authorized task.
204
204
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{spawn as hu}from"node:child_process";import{closeSync as gu,existsSync as Kr,mkdirSync as _u,openSync as yu,readFileSync as jr,rmSync as wu,statSync as Hs,writeFileSync as Gs}from"node:fs";import{dirname as Ks,resolve as Ct}from"node:path";import{fileURLToPath as Tu}from"node:url";import{createHash as es}from"node:crypto";import{mkdir as ia,readFile as oa,writeFile as aa,rename as ca}from"node:fs/promises";import{join as ts}from"node:path";import{homedir as ua,hostname as la}from"node:os";import{execFile as ti}from"node:child_process";import{access as ei,realpath as ri}from"node:fs/promises";import{constants as ni}from"node:fs";import{delimiter as si,join as Xr,isAbsolute as Yr}from"node:path";import{homedir as Wr}from"node:os";async function xe(e,t=process.env){let r=process.platform==="win32"?[".exe",".cmd",".bat",""]:[""];for(let n of(t.PATH||"").split(si).filter(Yr))for(let s of r){let i=Xr(n,`${e}${s}`);try{return await ei(i,ni.X_OK),i}catch{}}return null}function ii(e,t){return new Promise(r=>ti(e,t,{timeout:8e3,maxBuffer:1024*1024,windowsHide:!0},(n,s)=>r({code:n?n.code:0,stdout:String(s||"")})))}async function Ae(e){let t=e==="~"?Wr():e.startsWith("~/")?Xr(Wr(),e.slice(2)):e;if(!Yr(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 ri(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 Qr({find:e=xe,run:t=ii,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"]),c=a.code===0&&a.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0]||"",l={id:s,name:o,framework:s,version:c,workspace:r,managed:!1};if(a.code!==0)return[{...l,status:"error",message:"\u7A0B\u5E8F\u65E0\u6CD5\u542F\u52A8\uFF0C\u8BF7\u5728\u672C\u673A\u68C0\u67E5\u5B89\u88C5"}];if(s==="openclaw"){let f=await t(i,["agents","list","--json"]),h;try{h=JSON.parse(f.stdout)}catch{}if(f.code!==0||!Array.isArray(h))return[{...l,status:"error",message:"\u65E0\u6CD5\u8BFB\u53D6 OpenClaw \u667A\u80FD\u4F53\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u914D\u7F6E"}];let _=await t(i,["health","--json"]);return h.filter(w=>typeof w.id=="string"&&typeof w.workspace=="string").slice(0,32).map(w=>({...l,id:`openclaw:${w.id}`,name:w.name||w.identityName||w.id,workspace:w.workspace,managed:!0,localAgentId:w.id,command:i,status:_.code===0?"ready":"needs_setup",message:_.code===0?"":"\u8BF7\u5148\u5728\u672C\u673A\u542F\u52A8\u5E76\u914D\u7F6E OpenClaw Gateway"}))}let p=await t(i,s==="codex"?["login","status"]:["auth","status"]),m=p.code===0?"ready":p.code===1?"needs_login":"error";return[{...l,command:i,status:m,message:m==="needs_login"?`\u8BF7\u5728\u672C\u673A\u8FD0\u884C ${s} ${s==="codex"?"login":"auth login"}`:m==="error"?"\u767B\u5F55\u72B6\u6001\u68C0\u6D4B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 CLI \u7248\u672C":""}]}))).flat()}import{spawn as ra}from"node:child_process";import{createInterface as na}from"node:readline";import{randomUUID as sa}from"node:crypto";import{createInterface as di}from"node:readline";var B="0.1.59";function Mt(){return new Date().toISOString()}function $(e,t=2){return String(e).padStart(t,"0")}function Zr(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${$(Math.floor(r/60))}:${$(r%60)}`}function oi(e){let t=-e.getTimezoneOffset();return[`${e.getFullYear()}-${$(e.getMonth()+1)}-${$(e.getDate())}`,`T${$(e.getHours())}:${$(e.getMinutes())}:${$(e.getSeconds())}.${$(e.getMilliseconds(),3)}`,Zr(t)].join("")}function ai(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 ci(e,t){let r=ai(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}-${$(r.month)}-${$(r.day)}`,`T${$(r.hour)}:${$(r.minute)}:${$(r.second)}.${$(e.getMilliseconds(),3)}`,Zr(s)].join("")}function ui(e=new Date){let t=u(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return ci(e,t)}catch{return oi(e)}}function d(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function u(e){return String(e??"").trim()}function R(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)?r:t}function k(e){return Array.isArray(e)?e.map(String):[]}function K(e,t,r=process.cwd()){let n=d(e)?e:{};return u(n.cwd)||u(n.workspace)||u(t)||u(r)||process.cwd()}var qt="[redacted]",li=/(authorization|api[_-]?key|credential|password|secret|token)/i;function rt(e){return li.test(u(e))}function ct(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(qt))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${qt}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${qt}`)}function at(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]=at(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=>at(i,t));return t.delete(e),s}let r={},n=rt(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=rt(s)||n&&s.toLowerCase()==="value"?qt:at(i,t);return t.delete(e),r}function tn(e,t=4e3){let r=JSON.stringify(at(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function g(e,t,r,n={}){let s={ts:ui(),level:e,module:t,msg:r,...d(n)?at(n):{}};console.error(JSON.stringify(s))}function Gt(e,{onNotification:t=()=>{},onRequest:r=()=>{throw new Error("Unsupported request")}}={}){let n=1,s=new Map,i=o=>e.stdin.write(`${JSON.stringify(o)}
2
+ import{spawn as hu}from"node:child_process";import{closeSync as gu,existsSync as Kr,mkdirSync as _u,openSync as yu,readFileSync as jr,rmSync as wu,statSync as Hs,writeFileSync as Gs}from"node:fs";import{dirname as Ks,resolve as Ct}from"node:path";import{fileURLToPath as Tu}from"node:url";import{createHash as es}from"node:crypto";import{mkdir as ia,readFile as oa,writeFile as aa,rename as ca}from"node:fs/promises";import{join as ts}from"node:path";import{homedir as ua,hostname as la}from"node:os";import{execFile as ti}from"node:child_process";import{access as ei,realpath as ri}from"node:fs/promises";import{constants as ni}from"node:fs";import{delimiter as si,join as Xr,isAbsolute as Yr}from"node:path";import{homedir as Wr}from"node:os";async function xe(e,t=process.env){let r=process.platform==="win32"?[".exe",".cmd",".bat",""]:[""];for(let n of(t.PATH||"").split(si).filter(Yr))for(let s of r){let i=Xr(n,`${e}${s}`);try{return await ei(i,ni.X_OK),i}catch{}}return null}function ii(e,t){return new Promise(r=>ti(e,t,{timeout:8e3,maxBuffer:1024*1024,windowsHide:!0},(n,s)=>r({code:n?n.code:0,stdout:String(s||"")})))}async function Ae(e){let t=e==="~"?Wr():e.startsWith("~/")?Xr(Wr(),e.slice(2)):e;if(!Yr(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 ri(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 Qr({find:e=xe,run:t=ii,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"]),c=a.code===0&&a.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0]||"",l={id:s,name:o,framework:s,version:c,workspace:r,managed:!1};if(a.code!==0)return[{...l,status:"error",message:"\u7A0B\u5E8F\u65E0\u6CD5\u542F\u52A8\uFF0C\u8BF7\u5728\u672C\u673A\u68C0\u67E5\u5B89\u88C5"}];if(s==="openclaw"){let f=await t(i,["agents","list","--json"]),h;try{h=JSON.parse(f.stdout)}catch{}if(f.code!==0||!Array.isArray(h))return[{...l,status:"error",message:"\u65E0\u6CD5\u8BFB\u53D6 OpenClaw \u667A\u80FD\u4F53\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u914D\u7F6E"}];let _=await t(i,["health","--json"]);return h.filter(w=>typeof w.id=="string"&&typeof w.workspace=="string").slice(0,32).map(w=>({...l,id:`openclaw:${w.id}`,name:w.name||w.identityName||w.id,workspace:w.workspace,managed:!0,localAgentId:w.id,command:i,status:_.code===0?"ready":"needs_setup",message:_.code===0?"":"\u8BF7\u5148\u5728\u672C\u673A\u542F\u52A8\u5E76\u914D\u7F6E OpenClaw Gateway"}))}let p=await t(i,s==="codex"?["login","status"]:["auth","status"]),m=p.code===0?"ready":p.code===1?"needs_login":"error";return[{...l,command:i,status:m,message:m==="needs_login"?`\u8BF7\u5728\u672C\u673A\u8FD0\u884C ${s} ${s==="codex"?"login":"auth login"}`:m==="error"?"\u767B\u5F55\u72B6\u6001\u68C0\u6D4B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 CLI \u7248\u672C":""}]}))).flat()}import{spawn as ra}from"node:child_process";import{createInterface as na}from"node:readline";import{randomUUID as sa}from"node:crypto";import{createInterface as di}from"node:readline";var B="0.1.60";function Mt(){return new Date().toISOString()}function $(e,t=2){return String(e).padStart(t,"0")}function Zr(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${$(Math.floor(r/60))}:${$(r%60)}`}function oi(e){let t=-e.getTimezoneOffset();return[`${e.getFullYear()}-${$(e.getMonth()+1)}-${$(e.getDate())}`,`T${$(e.getHours())}:${$(e.getMinutes())}:${$(e.getSeconds())}.${$(e.getMilliseconds(),3)}`,Zr(t)].join("")}function ai(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 ci(e,t){let r=ai(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}-${$(r.month)}-${$(r.day)}`,`T${$(r.hour)}:${$(r.minute)}:${$(r.second)}.${$(e.getMilliseconds(),3)}`,Zr(s)].join("")}function ui(e=new Date){let t=u(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return ci(e,t)}catch{return oi(e)}}function d(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function u(e){return String(e??"").trim()}function R(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)?r:t}function k(e){return Array.isArray(e)?e.map(String):[]}function K(e,t,r=process.cwd()){let n=d(e)?e:{};return u(n.cwd)||u(n.workspace)||u(t)||u(r)||process.cwd()}var qt="[redacted]",li=/(authorization|api[_-]?key|credential|password|secret|token)/i;function rt(e){return li.test(u(e))}function ct(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(qt))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${qt}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${qt}`)}function at(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]=at(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=>at(i,t));return t.delete(e),s}let r={},n=rt(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=rt(s)||n&&s.toLowerCase()==="value"?qt:at(i,t);return t.delete(e),r}function tn(e,t=4e3){let r=JSON.stringify(at(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function g(e,t,r,n={}){let s={ts:ui(),level:e,module:t,msg:r,...d(n)?at(n):{}};console.error(JSON.stringify(s))}function Gt(e,{onNotification:t=()=>{},onRequest:r=()=>{throw new Error("Unsupported request")}}={}){let n=1,s=new Map,i=o=>e.stdin.write(`${JSON.stringify(o)}
3
3
  `);return di({input:e.stdout}).on("line",o=>{if(!o.trim())return;let a;try{a=JSON.parse(o)}catch{g("warn","runtime.codex","ignored non-JSON app-server output");return}if(typeof a.method=="string"&&a.id!==void 0){Promise.resolve().then(()=>r(a.method,d(a.params)?a.params:{})).then(l=>i({id:a.id,result:l}),l=>i({id:a.id,error:{code:-32603,message:String(l?.message||l)}}));return}if(typeof a.method=="string"){t(a.method,d(a.params)?a.params:{});return}let c=s.get(a.id);c&&(s.delete(a.id),a.error?c.reject(Object.assign(new Error(u(a.error.message)||"Codex app-server request failed"),{code:"RUNTIME_CODEX_APP_SERVER_ERROR"})):c.resolve(a.result))}),e.once("exit",()=>{for(let o of s.values())o.reject(new Error("Codex app-server closed"));s.clear()}),{request:(o,a)=>new Promise((c,l)=>{let p=n++;s.set(p,{resolve:c,reject:l}),i({id:p,method:o,params:a})}),notify:o=>i({method:o})}}import{spawn as $n}from"node:child_process";import{randomUUID as wt}from"node:crypto";import{existsSync as Hn,mkdirSync as co,readdirSync as Fn,readFileSync as Bn,realpathSync as kt,rmSync as uo,rmdirSync as lo,statSync as po,unlinkSync as fo}from"node:fs";import{homedir as mo,tmpdir as jn}from"node:os";import{basename as Fe,dirname as ho,join as q,resolve as Pn}from"node:path";import{randomUUID as sn}from"node:crypto";import{existsSync as pi,readFileSync as fi,realpathSync as en,statSync as mi}from"node:fs";import{basename as on,extname as an,isAbsolute as Ut,join as hi,relative as cn,resolve as rn}from"node:path";var gi=25*1024*1024;function un(e,t=""){let r=u(t);if(r)return r;let n=an(u(e)).toLowerCase();return n===".jpg"||n===".jpeg"?"image/jpeg":n===".webp"?"image/webp":n===".gif"?"image/gif":"image/png"}function ln(e,t){let r=typeof e=="string"?e.trim():"";return!r||r==="<omitted>"?"":r.startsWith("data:")?r:`data:${t};base64,${r.replace(/\s+/g,"")}`}function Kt(e){if(Array.isArray(e))return e.map(u).filter(Boolean);let t=u(e);return t?[t]:[]}function _i(e,t){let r=cn(t,e);return r===""||!!r&&!r.startsWith("..")&&!Ut(r)}function yi(e,t){let r=u(e);if(!r||!pi(r))return"";try{let n=en(r);for(let s of t)try{let i=en(s);if(_i(n,i))return n}catch{}}catch{return""}return""}function wi(e,t){let r=u(e);if(!r||!Ut(r))return r;for(let n of Array.isArray(t)?t:[]){if(!d(n))continue;let s=u(n.runtimeRoot),i=u(n.hostRoot);if(!s||!i||!Ut(s)||!Ut(i))continue;let o=cn(rn(s),rn(r));if(o===""||!o.startsWith("..")&&!Ut(o))return o?hi(i,o):i}return r}function be(e,t,r={}){let n=u(e);return!n||n.startsWith("data:")||/^https?:\/\//i.test(n)?n:Ti(n,t,r)}function Ti(e,t,r={}){let n=[...Kt(r.trustedFileRoots),...Kt(r.trustedFileRoot),...Kt(r.artifactRoots),...Kt(r.artifactRoot)],s=yi(wi(e,r.pathMappings),n);if(!s)return"";try{let i=mi(s);return!i.isFile()||i.size<=0||i.size>gi?"":`data:${t};base64,${fi(s).toString("base64")}`}catch{return""}}function v(...e){for(let t of e){let r=u(t);if(r)return r}return""}function Ei(e,t,r,n){let s=r.toLowerCase();if(s==="image"||s==="picture")return!0;let i=v(n,e.previewUrl,e.fileUrl,e.imageUrl,e.dataUrl,e.url,e.uri,t.previewUrl,t.fileUrl,t.imageUrl,t.dataUrl,t.url,t.uri),o=an(i.split("?",1)[0].split("#",1)[0]).toLowerCase();return[".png",".jpg",".jpeg",".webp",".gif"].includes(o)}function Me(e,t={}){let{source:r="runtime_image_generation_event"}=t;if(!d(e))return null;let n=d(e.payload)?e.payload:{},s=u(e.type),i=u(n.type);if(!(s==="event_msg"&&i==="image_generation_end"||s==="response_item"&&i==="image_generation_call"))return null;let o=v(n.call_id,n.id),a=v(n.saved_path,n.savedPath),c=v(n.revised_prompt,n.revisedPrompt),l=un(a,n.mimeType||n.mime_type),p=ln(n.result,l)||be(a,l,t);if(!p)return null;let m=p.startsWith("data:")?p:"",f=a?on(a):`${o||sn()}.png`;return{artifactType:"image",type:"image",fieldKey:"image",title:f||"Generated image",summary:c||"Generated image",content:{prompt:c||void 0,dataUrl:m||void 0,imageUrl:p,previewUrl:p,fileUrl:p,mimeType:l},dataUrl:m||void 0,previewUrl:p,fileUrl:p,metadata:{source:r,eventType:i,callId:o||void 0,savedPath:a||void 0,filename:f,mimeType:l,revisedPrompt:c||void 0}}}function Oi(e){let t=d(e)?e:{},r=[];for(let n of["_artifacts","artifacts"]){let s=t[n];Array.isArray(s)&&r.push(...s)}for(let n of["_artifact","artifact"]){let s=t[n];d(s)&&r.push(s)}return r}function Si(e,t={}){let{source:r="runtime_artifact"}=t,n=d(e)?e:{};if(!Object.keys(n).length)return null;let s=d(n.content)?{...n.content}:{},i=d(n.metadata)?{...n.metadata}:{},o=v(n.saved_path,n.savedPath,s.saved_path,s.savedPath,i.savedPath),a=v(n.mimeType,n.mime_type,s.mimeType,s.mime_type,i.mimeType),c=v(n.artifactType,n.artifact_type,n.type,n.kind,s.type,o?"image":"file"),l=Ei(n,s,c,o),p=l?un(o,a):a;if(l){let I=v(n.dataUrl,s.dataUrl),E=I.startsWith("data:")?I:"",C=v(n.imageUrl,n.previewUrl,n.fileUrl,n.downloadUrl,n.url,n.uri,s.imageUrl,s.previewUrl,s.fileUrl,s.downloadUrl,s.url,s.uri),y=ln(n.result??s.result,p)||E||be(o,p,t)||be(C,p,t);y&&(y.startsWith("data:")&&(s.dataUrl||=y),s.imageUrl||=y,s.previewUrl||=y,s.fileUrl||=y,p&&(s.mimeType||=p))}for(let[I,E]of[["prompt","prompt"],["previewUrl","previewUrl"],["fileUrl","fileUrl"],["downloadUrl","downloadUrl"],["imageUrl","imageUrl"],["dataUrl","dataUrl"],["url","url"],["uri","uri"],["mimeType","mimeType"],["mime_type","mimeType"]]){let C=n[I];C!=null&&C!==""&&!(E in s)&&(s[E]=C)}let m=v(n.fileUrl,n.downloadUrl,n.imageUrl,n.dataUrl,n.url,n.uri,s.fileUrl,s.downloadUrl,s.imageUrl,s.dataUrl,s.url,s.uri),f=v(n.previewUrl,n.imageUrl,n.dataUrl,n.url,n.fileUrl,n.uri,s.previewUrl,s.imageUrl,s.dataUrl,s.url,s.fileUrl,s.uri),h=v(n.dataUrl,s.dataUrl,m.startsWith("data:")?m:"",f.startsWith("data:")?f:""),_=v(n.filename,i.filename,o?on(o):""),w=v(n.fieldKey,n.field_key,s.fieldKey,i.fieldKey,l?"image":"artifact");return{...n,artifactType:c,type:n.type||c,fieldKey:w,title:v(n.title,_,"Runtime artifact"),summary:v(n.summary,s.prompt,n.title,_,"Runtime artifact"),content:s,dataUrl:h||void 0,fileUrl:m||void 0,previewUrl:f||void 0,metadata:{...i,source:v(i.source,r),savedPath:o||i.savedPath,filename:_||i.filename,mimeType:p||i.mimeType}}}function zt(e,t){if(!t||!e)return;let r=d(t.metadata)?t.metadata:{},n=v(r.savedPath,r.callId,t.previewUrl,t.fileUrl)||sn(),s=e.get(n);if(!s){e.set(n,t);return}s.content={...d(s.content)?s.content:{},...d(t.content)?t.content:{}},s.metadata={...d(s.metadata)?s.metadata:{},...r},s.previewUrl=t.previewUrl||s.previewUrl,s.fileUrl=t.fileUrl||s.fileUrl,s.summary=t.summary||s.summary,s.title=t.title||s.title}function Ne(e,t,r={}){for(let n of Oi(e))zt(t,Si(n,r))}function Ue(e){if(!d(e)||!d(e.payload))return d(e)?e:{value:e};let t=u(e.payload.type);if(t!=="image_generation_end"&&t!=="image_generation_call")return e;let r={...e.payload};return typeof r.result=="string"&&r.result&&(r.result="<omitted>",r.resultLength=e.payload.result.length),{...e,payload:r}}function nn(e,t,r){if(!d(e))return e;let n=d(e.event)?e.event:null;return n?(zt(t,Me(n,r)),{...e,event:Ue(n)}):e}function dn(e,t,r={}){if(!d(e))return e;Ne(e,t,r);let n=nn(e,t,r),s=d(n.update)?nn(n.update,t,r):null;return s&&s!==n.update&&(n={...n,update:s}),n}function pn(e,t,r={}){let n=d(e)?{...e}:{};Ne(n,t,r),Ne(d(n.output)?n.output:{},t,r);let s=[...t?.values?.()||[]];return s.length&&(n._artifacts=s),delete n.artifacts,n}function yt(e){return Array.isArray(e)?e.map(t=>d(t)?t.type==="text"?u(t.text):t.type==="file"?u(t.uri):t.type==="image"?u(t.uri):"":"").filter(Boolean).join(`
4
- `):""}import{createHash as Gi,randomUUID as Ki}from"node:crypto";import{mkdirSync as In,readFileSync as zi,renameSync as Vi,rmSync as Ji,writeFileSync as Cn}from"node:fs";import{homedir as Le}from"node:os";import{join as lt}from"node:path";import{createServer as Ii}from"node:http";import{randomBytes as Ci}from"node:crypto";var Vt={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs","knowledge_search"]};var xi=Object.freeze([...Vt.controlTools,...Vt.residentTools]),Ai=new Set(xi),bi=8*1024*1024;function Jt(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 mn(e){let t=0,r=[];for await(let n of e){if(t+=n.length,t>bi)throw new Error("MCP payload exceeds the size limit");r.push(Buffer.from(n))}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function hn(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 mn(n.body);if(!s||s.jsonrpc!=="2.0"||s.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return s}async function fn(e,t){let r=await hn(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])=>rt(a)).flatMap(([,a])=>[a,String(a).replace(/^Bearer\s+/i,"")]),i=typeof r.error.message=="string"?ct(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 Ni(n)}function Ni(e){if(!Array.isArray(e)||e.some(t=>!t||!Ai.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&Vt.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 Mi(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 gn(e,t=[]){let r=Jt(e),n=new AbortController,s=await fn(r,n.signal);if(t.some(a=>s.some(c=>c.name===a.name)))throw new Error("Local and remote MCP tools conflict");let i=Ci(32).toString("hex"),o=Ii(async(a,c)=>{if(a.url!=="/mcp"||a.headers.authorization!==`Bearer ${i}`){c.writeHead(403).end();return}if(a.method!=="POST"){c.writeHead(405).end();return}try{let l=await mn(a);if(!l||l.jsonrpc!=="2.0"||typeof l.method!="string")throw new Error("Invalid MCP request");let p=l.method==="tools/call"&&t.find(f=>f.name===l.params?.name);if(l.method==="tools/call"&&!p&&!s.some(f=>f.name===l.params?.name))throw new Error("Tool is not authorized in this task binding");let m;if(p)try{m={jsonrpc:"2.0",id:l.id,result:await p.call(l.params.arguments,{upstream:r,signal:n.signal})}}catch(f){m={jsonrpc:"2.0",id:l.id,result:{isError:!0,content:[{type:"text",text:ct(String(f.message),[r.headers.authorization,i])}]}}}else m=await hn(r,l,n.signal),l.method==="tools/list"&&m?.result?.tools&&m.result.tools.push(...t.map(({call:f,...h})=>h));c.writeHead(m===null?202:200,{"content-type":"application/json"}),c.end(m===null?"":JSON.stringify(m))}catch{c.writeHead(502,{"content-type":"application/json"}).end(JSON.stringify({error:"The task-scoped Orcha MCP connection failed"}))}});return await new Promise((a,c)=>{o.once("error",c),o.listen(0,"127.0.0.1",a)}),{url:`http://127.0.0.1:${o.address().port}/mcp`,token:i,async refresh(a){let c=Jt(a,r.url);if(!Mi(s,await fn(c,n.signal)))throw new Error("The frozen MCP tool catalog changed; start a new task");r=c},async close(){n.abort(),o.closeAllConnections(),await new Promise(a=>o.close(a))}}}import{createHash as _n}from"node:crypto";import{constants as Pe}from"node:fs";import{open as Ui,realpath as yn}from"node:fs/promises";import{basename as Pi,isAbsolute as Li,relative as ki,resolve as vi}from"node:path";var Di=32*1024*1024,$i={name:"send_file",description:"Send one explicitly selected local file to the current OrchaAI conversation. Use this to deliver images, PDFs, documents, spreadsheets or other files to the user; viewing an image or writing a local Markdown link does not send it. path must be in the current workspace, a configured artifact root, or (Codex only) the current thread's generated_images directory. Copy other intended deliverables into the workspace first. Success means the attachment message is saved; do not send it again or embed the local path. Internal previews and intermediate files need not be sent.",inputSchema:{type:"object",additionalProperties:!1,required:["path"],properties:{path:{type:"string",minLength:1,description:"Absolute file path, or a path relative to the current workspace."},message:{type:"string",maxLength:1e4,description:"Optional short caption for the attachment message, such as what the file is. The attachment is saved as its own message and your final reply is still posted separately, so do not repeat the final reply's summary, findings or conclusions here; omit it when the final reply already explains the file."}}}};function wn(e){return{...$i,async call(t,{upstream:r,signal:n}){if(!t||typeof t.path!="string"||!t.path.trim()||Object.keys(t).some(y=>!["path","message"].includes(y))||t.message!==void 0&&(typeof t.message!="string"||t.message.length>1e4))throw new Error("send_file requires a file path and an optional caption of at most 10000 characters");let{cwd:s,roots:i}=e();if(!s)throw new Error("The current file delivery workspace is unavailable");let o=await yn(vi(s,t.path)),a=!1;for(let y of i)try{let O=ki(await yn(y),o);(!O||O!==".."&&!O.startsWith("../")&&!O.startsWith("..\\")&&!Li(O))&&(a=!0)}catch{}if(!a)throw new Error("File is outside the current workspace and authorized artifact roots");let c=await Ui(o,Pe.O_RDONLY|Pe.O_NOFOLLOW|Pe.O_NONBLOCK),l;try{let y=await c.stat();if(!y.isFile()||y.size<=0||y.size>Di)throw new Error("Select a non-empty regular file of at most 32 MiB");l=Buffer.alloc(y.size);let O=0;for(;O<l.length;){let{bytesRead:A}=await c.read(l,O,l.length-O,O);if(!A)throw new Error("File changed while preparing delivery; retry after it is saved");O+=A}let M=await c.stat();if(M.size!==y.size||M.mtimeMs!==y.mtimeMs)throw new Error("File changed while preparing delivery; retry after it is saved")}finally{await c.close()}let p=t.message||"",m=Pi(o),f=_n("sha256").update(l).digest("hex"),h=_n("sha256").update(JSON.stringify([o,f,p])).digest("hex"),_=new FormData;_.set("deliveryId",h),_.set("message",p),_.set("file",new Blob([l]),m);let w=new URL(r.url);w.pathname=`${w.pathname.replace(/\/$/,"")}/files`;let I=await fetch(w,{method:"POST",headers:{authorization:r.headers.authorization},body:_,redirect:"error",signal:AbortSignal.any([n,AbortSignal.timeout(12e4)])});if(!I.ok)throw new Error(`File delivery failed (HTTP ${I.status}); no successful receipt was received`);let E=await I.json();if(!E.success)throw new Error(`File delivery failed: ${String(E.message||E.code||"request rejected").slice(0,512)}`);let C=E.data;if(!C?.accepted||typeof C.messageId!="string"||!C.messageId||typeof C.fileId!="string"||!C.fileId)throw new Error("File delivery did not return a saved message and file receipt");return{content:[{type:"text",text:JSON.stringify(C)}],structuredContent:C,isError:!1}}}}var Hi=new Set(["Bash","PowerShell"]),Fi=new Set(["Edit","Write","MultiEdit","NotebookEdit"]),Bi="SandboxNetworkAccess",Tn=2e3,En=50;function ut(e,t=0){return typeof e=="string"?e.length>Tn?`${e.slice(0,Tn)}\u2026`:e:t>=4&&(Array.isArray(e)||d(e))?"\u2026":Array.isArray(e)?e.slice(0,En).map(r=>ut(r,t+1)):d(e)?Object.fromEntries(Object.entries(e).slice(0,En).map(([r,n])=>[r,ut(n,t+1)])):e}function ji(e){let t=e.tool_name,r=e.input,n=Hi.has(t)?"command":Fi.has(t)?"file_change":t===Bi?"permission":"other",s=r.file_path||r.notebook_path;return{runtime:"claude",kind:n,toolName:t,title:typeof e.description=="string"?e.description:"",...n==="command"&&typeof r.command=="string"?{command:r.command}:{},...n==="file_change"&&typeof s=="string"?{paths:[s]}:{},input:ut(r)}}async function On(e,t,r){if(e?.subtype!=="can_use_tool"||typeof e.tool_name!="string"||!d(e.input))return{subtype:"error",error:`OrchaAI does not handle Claude control request ${e?.subtype}`};let n=await t(ji(e),{signal:r}),s=n?.response?.reason||n?.reason||n?.outcome||"not approved";return{subtype:"success",response:n?.outcome==="approved"?{behavior:"allow",updatedInput:e.input}:{behavior:"deny",message:`OrchaAI did not approve this action (${s}). Do not retry the same action unless the user asks.`}}}var qi=new Set(["threadId","turnId","itemId","approvalId","startedAtMs","environmentId","command","cwd","reason"]);function Sn(e,t,r){let n=Object.fromEntries(Object.entries(t).filter(([i,o])=>!qi.has(i)&&o!=null)),s={runtime:"codex",title:typeof t.reason=="string"?t.reason:"",input:ut(n)};if(e==="item/commandExecution/requestApproval")return{...s,kind:"command",toolName:"shell",...typeof t.command=="string"?{command:t.command}:{},...typeof t.cwd=="string"?{cwd:t.cwd}:{}};if(e==="item/fileChange/requestApproval"){let i=Array.isArray(r?.changes)?r.changes.map(o=>o?.path).filter(o=>typeof o=="string"):[];return{...s,kind:"file_change",toolName:"apply_patch",...i.length?{paths:i}:{}}}return{...s,kind:"permission",...typeof t.cwd=="string"?{cwd:t.cwd}:{}}}function Rn(e,t,r){return e==="item/permissions/requestApproval"?{permissions:Object.fromEntries(Object.entries(d(t.permissions)?t.permissions:{}).filter(([,s])=>r&&s!=null)),scope:"turn"}:{decision:r?"accept":"decline"}}var xn=e=>Gi("sha256").update(JSON.stringify(e)).digest("hex"),Q=(e,t)=>Object.assign(new Error(t),{code:e}),An=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,ke="ORCHA_TASK_MCP_TOKEN",Wi=new Set(["--no-session-persistence","--resume","-r","--continue","-c","--session-id","--fork-session"]);function Xi(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(t=>t?.type==="text").map(t=>t.text).join(`
4
+ `):""}import{createHash as Gi,randomUUID as Ki}from"node:crypto";import{mkdirSync as In,readFileSync as zi,renameSync as Vi,rmSync as Ji,writeFileSync as Cn}from"node:fs";import{homedir as Le}from"node:os";import{join as lt}from"node:path";import{createServer as Ii}from"node:http";import{randomBytes as Ci}from"node:crypto";var Vt={controlTools:["find_capabilities_and_skills","describe_capability","inspect_result","execute_capability"],residentTools:["search_orcha_docs","knowledge_search"]};var xi=Object.freeze([...Vt.controlTools,...Vt.residentTools]),Ai=new Set(xi),bi=8*1024*1024;function Jt(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 mn(e){let t=0,r=[];for await(let n of e){if(t+=n.length,t>bi)throw new Error("MCP payload exceeds the size limit");r.push(Buffer.from(n))}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function hn(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 mn(n.body);if(!s||s.jsonrpc!=="2.0"||s.id!==t.id)throw new Error("Orcha MCP response identity mismatch");return s}async function fn(e,t){let r=await hn(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])=>rt(a)).flatMap(([,a])=>[a,String(a).replace(/^Bearer\s+/i,"")]),i=typeof r.error.message=="string"?ct(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 Ni(n)}function Ni(e){if(!Array.isArray(e)||e.some(t=>!t||!Ai.has(t.name)||t.inputSchema?.type!=="object"||typeof t.description!="string")||new Set(e.map(t=>t.name)).size!==e.length||e.length&&Vt.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 Mi(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 gn(e,t=[]){let r=Jt(e),n=new AbortController,s=await fn(r,n.signal);if(t.some(a=>s.some(c=>c.name===a.name)))throw new Error("Local and remote MCP tools conflict");let i=Ci(32).toString("hex"),o=Ii(async(a,c)=>{if(a.url!=="/mcp"||a.headers.authorization!==`Bearer ${i}`){c.writeHead(403).end();return}if(a.method!=="POST"){c.writeHead(405).end();return}try{let l=await mn(a);if(!l||l.jsonrpc!=="2.0"||typeof l.method!="string")throw new Error("Invalid MCP request");let p=l.method==="tools/call"&&t.find(f=>f.name===l.params?.name);if(l.method==="tools/call"&&!p&&!s.some(f=>f.name===l.params?.name))throw new Error("Tool is not authorized in this task binding");let m;if(p)try{m={jsonrpc:"2.0",id:l.id,result:await p.call(l.params.arguments,{upstream:r,signal:n.signal})}}catch(f){m={jsonrpc:"2.0",id:l.id,result:{isError:!0,content:[{type:"text",text:ct(String(f.message),[r.headers.authorization,i])}]}}}else m=await hn(r,l,n.signal),l.method==="tools/list"&&m?.result?.tools&&m.result.tools.push(...t.map(({call:f,...h})=>h));c.writeHead(m===null?202:200,{"content-type":"application/json"}),c.end(m===null?"":JSON.stringify(m))}catch{c.writeHead(502,{"content-type":"application/json"}).end(JSON.stringify({error:"The task-scoped Orcha MCP connection failed"}))}});return await new Promise((a,c)=>{o.once("error",c),o.listen(0,"127.0.0.1",a)}),{url:`http://127.0.0.1:${o.address().port}/mcp`,token:i,async refresh(a){let c=Jt(a,r.url);if(!Mi(s,await fn(c,n.signal)))throw new Error("The frozen MCP tool catalog changed; start a new task");r=c},async close(){n.abort(),o.closeAllConnections(),await new Promise(a=>o.close(a))}}}import{createHash as _n}from"node:crypto";import{constants as Pe}from"node:fs";import{open as Ui,realpath as yn}from"node:fs/promises";import{basename as Pi,isAbsolute as Li,relative as ki,resolve as vi}from"node:path";var Di=32*1024*1024,$i={name:"send_file",description:"Send one explicitly selected local file to the current OrchaAI conversation. Use this to deliver images, PDFs, documents, spreadsheets or other files to the user; viewing an image or writing a local Markdown link does not send it. path must be in the current workspace, a configured artifact root, or (Codex only) the current thread's generated_images directory. Copy other intended deliverables into the workspace first. Success means the attachment message is saved; do not send it again or embed the local path. Internal previews and intermediate files need not be sent.",inputSchema:{type:"object",additionalProperties:!1,required:["path"],properties:{path:{type:"string",minLength:1,description:"Absolute file path, or a path relative to the current workspace."},message:{type:"string",maxLength:1e4,description:"Optional short description shown while the file is being delivered. Files sent in this turn share one message with your final reply, which replaces this temporary text and keeps the attachments. Explain the deliverables in your final reply; omit this description when unnecessary."}}}};function wn(e){return{...$i,async call(t,{upstream:r,signal:n}){if(!t||typeof t.path!="string"||!t.path.trim()||Object.keys(t).some(y=>!["path","message"].includes(y))||t.message!==void 0&&(typeof t.message!="string"||t.message.length>1e4))throw new Error("send_file requires a file path and an optional caption of at most 10000 characters");let{cwd:s,roots:i}=e();if(!s)throw new Error("The current file delivery workspace is unavailable");let o=await yn(vi(s,t.path)),a=!1;for(let y of i)try{let O=ki(await yn(y),o);(!O||O!==".."&&!O.startsWith("../")&&!O.startsWith("..\\")&&!Li(O))&&(a=!0)}catch{}if(!a)throw new Error("File is outside the current workspace and authorized artifact roots");let c=await Ui(o,Pe.O_RDONLY|Pe.O_NOFOLLOW|Pe.O_NONBLOCK),l;try{let y=await c.stat();if(!y.isFile()||y.size<=0||y.size>Di)throw new Error("Select a non-empty regular file of at most 32 MiB");l=Buffer.alloc(y.size);let O=0;for(;O<l.length;){let{bytesRead:A}=await c.read(l,O,l.length-O,O);if(!A)throw new Error("File changed while preparing delivery; retry after it is saved");O+=A}let M=await c.stat();if(M.size!==y.size||M.mtimeMs!==y.mtimeMs)throw new Error("File changed while preparing delivery; retry after it is saved")}finally{await c.close()}let p=t.message||"",m=Pi(o),f=_n("sha256").update(l).digest("hex"),h=_n("sha256").update(JSON.stringify([o,f,p])).digest("hex"),_=new FormData;_.set("deliveryId",h),_.set("message",p),_.set("file",new Blob([l]),m);let w=new URL(r.url);w.pathname=`${w.pathname.replace(/\/$/,"")}/files`;let I=await fetch(w,{method:"POST",headers:{authorization:r.headers.authorization},body:_,redirect:"error",signal:AbortSignal.any([n,AbortSignal.timeout(12e4)])});if(!I.ok)throw new Error(`File delivery failed (HTTP ${I.status}); no successful receipt was received`);let E=await I.json();if(!E.success)throw new Error(`File delivery failed: ${String(E.message||E.code||"request rejected").slice(0,512)}`);let C=E.data;if(!C?.accepted||typeof C.messageId!="string"||!C.messageId||typeof C.fileId!="string"||!C.fileId)throw new Error("File delivery did not return a saved message and file receipt");return{content:[{type:"text",text:JSON.stringify(C)}],structuredContent:C,isError:!1}}}}var Hi=new Set(["Bash","PowerShell"]),Fi=new Set(["Edit","Write","MultiEdit","NotebookEdit"]),Bi="SandboxNetworkAccess",Tn=2e3,En=50;function ut(e,t=0){return typeof e=="string"?e.length>Tn?`${e.slice(0,Tn)}\u2026`:e:t>=4&&(Array.isArray(e)||d(e))?"\u2026":Array.isArray(e)?e.slice(0,En).map(r=>ut(r,t+1)):d(e)?Object.fromEntries(Object.entries(e).slice(0,En).map(([r,n])=>[r,ut(n,t+1)])):e}function ji(e){let t=e.tool_name,r=e.input,n=Hi.has(t)?"command":Fi.has(t)?"file_change":t===Bi?"permission":"other",s=r.file_path||r.notebook_path;return{runtime:"claude",kind:n,toolName:t,title:typeof e.description=="string"?e.description:"",...n==="command"&&typeof r.command=="string"?{command:r.command}:{},...n==="file_change"&&typeof s=="string"?{paths:[s]}:{},input:ut(r)}}async function On(e,t,r){if(e?.subtype!=="can_use_tool"||typeof e.tool_name!="string"||!d(e.input))return{subtype:"error",error:`OrchaAI does not handle Claude control request ${e?.subtype}`};let n=await t(ji(e),{signal:r}),s=n?.response?.reason||n?.reason||n?.outcome||"not approved";return{subtype:"success",response:n?.outcome==="approved"?{behavior:"allow",updatedInput:e.input}:{behavior:"deny",message:`OrchaAI did not approve this action (${s}). Do not retry the same action unless the user asks.`}}}var qi=new Set(["threadId","turnId","itemId","approvalId","startedAtMs","environmentId","command","cwd","reason"]);function Sn(e,t,r){let n=Object.fromEntries(Object.entries(t).filter(([i,o])=>!qi.has(i)&&o!=null)),s={runtime:"codex",title:typeof t.reason=="string"?t.reason:"",input:ut(n)};if(e==="item/commandExecution/requestApproval")return{...s,kind:"command",toolName:"shell",...typeof t.command=="string"?{command:t.command}:{},...typeof t.cwd=="string"?{cwd:t.cwd}:{}};if(e==="item/fileChange/requestApproval"){let i=Array.isArray(r?.changes)?r.changes.map(o=>o?.path).filter(o=>typeof o=="string"):[];return{...s,kind:"file_change",toolName:"apply_patch",...i.length?{paths:i}:{}}}return{...s,kind:"permission",...typeof t.cwd=="string"?{cwd:t.cwd}:{}}}function Rn(e,t,r){return e==="item/permissions/requestApproval"?{permissions:Object.fromEntries(Object.entries(d(t.permissions)?t.permissions:{}).filter(([,s])=>r&&s!=null)),scope:"turn"}:{decision:r?"accept":"decline"}}var xn=e=>Gi("sha256").update(JSON.stringify(e)).digest("hex"),Q=(e,t)=>Object.assign(new Error(t),{code:e}),An=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,ke="ORCHA_TASK_MCP_TOKEN",Wi=new Set(["--no-session-persistence","--resume","-r","--continue","-c","--session-id","--fork-session"]);function Xi(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(t=>t?.type==="text").map(t=>t.text).join(`
5
5
  `):""}var Pt=(e,t)=>({sessionUpdate:e,content:{type:"text",text:t}});function Yi(e,t,{emitThoughts:r,streamText:n}){let s=e?.type;if(s==="result"&&e.is_error!==!0){let c=typeof e.result=="string"?e.result:"",l=t.streamed;return t.text=t.streamed="",c?l?l.trim()===c.trim()?[]:[Pt("agent_message_snapshot",c)]:[Pt("agent_message_chunk",c)]:[]}if(!["assistant","user","stream_event"].includes(s))return null;let i=[];if(e.parent_tool_use_id)return i;let o=()=>{let c=t.streamed||t.text;t.streamed&&i.push(Pt("agent_message_snapshot","")),c&&r&&i.push(Pt("agent_thought_chunk",c)),t.text=t.streamed=""},a=c=>{t.streamed=(t.streamed||"")+c,i.push(Pt("agent_message_chunk",c))};if(s==="stream_event"){if(!n)return i;t.streaming=!0;let c=e.event,l=c?.content_block?.type;return c?.type==="content_block_start"&&l==="tool_use"?o():c?.type==="content_block_start"&&l==="text"&&t.streamed?a(`
6
6
 
7
7
  `):c?.type==="content_block_delta"&&c.delta?.type==="text_delta"&&c.delta.text&&a(c.delta.text),i}for(let c of Array.isArray(e.message?.content)?e.message.content:[])s==="user"?c?.type==="tool_result"&&c.tool_use_id&&i.push({sessionUpdate:"tool_call_update",toolCallId:c.tool_use_id,status:c.is_error?"failed":"completed",rawOutput:Xi(c.content)}):c?.type==="text"&&c.text?t.streaming||(t.text=t.text?`${t.text}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orcha-ai/openclaw-tools",
3
- "version": "0.1.59",
3
+ "version": "0.1.60",
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.59",
3
+ "version": "0.1.60",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Local Orcha runtime bridge for ACP-compatible agent runtimes.",