@orcha-ai/runtime-bridge 0.1.37 → 0.1.38
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 +19 -7
- package/bin/orcha-runtime-bridge.js +2 -2
- package/openclaw-plugin/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,6 +63,25 @@ npm tarball under `dist/`. The release package includes the minified `bin/`
|
|
|
63
63
|
runtime, the bundled `openclaw-plugin/`, `README.md`, and `.env.example`; it does not publish `src/`, build
|
|
64
64
|
scripts, test scripts, or the local `.env` file.
|
|
65
65
|
|
|
66
|
+
### 0.1.38 Release
|
|
67
|
+
|
|
68
|
+
Updates the Runtime Node registration handshake to `orcha-runtime-node.v2`.
|
|
69
|
+
Deploy this release with the Orcha backend that accepts v2; that backend rejects
|
|
70
|
+
older Bridge clients using v1. The standalone execution protocol remains
|
|
71
|
+
`orcha.runtime-execution/v1`.
|
|
72
|
+
|
|
73
|
+
The npm Bridge package is released separately from the managed Runtime container
|
|
74
|
+
images. After publishing, upgrade each external Runtime Node's installed package
|
|
75
|
+
and reload its Bridge process using the existing env file as described in
|
|
76
|
+
[Background Process](#background-process).
|
|
77
|
+
|
|
78
|
+
After `npm run check`, `npm test`, and `npm run pack:local` succeed, publish the
|
|
79
|
+
prepared tarball from this directory:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm publish ./dist/orcha-ai-runtime-bridge-0.1.38.tgz --access public --registry=https://registry.npmjs.org
|
|
83
|
+
```
|
|
84
|
+
|
|
66
85
|
### 0.1.37 Release
|
|
67
86
|
|
|
68
87
|
Packages task-scoped Orcha MCP access for delegated Codex and OpenClaw group
|
|
@@ -72,13 +91,6 @@ install and configure it as described in [Delegated group member tools](#delegat
|
|
|
72
91
|
Local adapter fixtures cover these integrations; a real OpenClaw Gateway has
|
|
73
92
|
not yet been verified.
|
|
74
93
|
|
|
75
|
-
After `npm run check`, `npm test`, and `npm run pack:local` succeed, publish the
|
|
76
|
-
prepared tarball from this directory:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
npm publish ./dist/orcha-ai-runtime-bridge-0.1.37.tgz --access public --registry=https://registry.npmjs.org
|
|
80
|
-
```
|
|
81
|
-
|
|
82
94
|
### 0.1.36 Release
|
|
83
95
|
|
|
84
96
|
Packages the goal-verification changes committed on August 25–26, 2026.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as ea}from"node:child_process";import{closeSync as ra,existsSync as Ln,mkdirSync as na,openSync as sa,readFileSync as Ye,rmSync as ia,statSync as bn,writeFileSync as Dn}from"node:fs";import{dirname as oa,resolve as tr}from"node:path";import{fileURLToPath as aa}from"node:url";import{createHash as Zi,randomUUID as Kt}from"node:crypto";var Q="0.1.
|
|
2
|
+
import{spawn as ea}from"node:child_process";import{closeSync as ra,existsSync as Ln,mkdirSync as na,openSync as sa,readFileSync as Ye,rmSync as ia,statSync as bn,writeFileSync as Dn}from"node:fs";import{dirname as oa,resolve as tr}from"node:path";import{fileURLToPath as aa}from"node:url";import{createHash as Zi,randomUUID as Kt}from"node:crypto";var Q="0.1.38";function dt(){return new Date().toISOString()}function U(e,t=2){return String(e).padStart(t,"0")}function or(e){let t=e>=0?"+":"-",r=Math.abs(e);return`${t}${U(Math.floor(r/60))}:${U(r%60)}`}function jn(e){let t=-e.getTimezoneOffset();return[`${e.getFullYear()}-${U(e.getMonth()+1)}-${U(e.getDate())}`,`T${U(e.getHours())}:${U(e.getMinutes())}:${U(e.getSeconds())}.${U(e.getMilliseconds(),3)}`,or(t)].join("")}function Kn(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 Gn(e,t){let r=Kn(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}-${U(r.month)}-${U(r.day)}`,`T${U(r.hour)}:${U(r.minute)}:${U(r.second)}.${U(e.getMilliseconds(),3)}`,or(s)].join("")}function zn(e=new Date){let t=a(process.env.ORCHA_RUNTIME_LOG_TIMEZONE||process.env.TZ||"Asia/Shanghai");try{return Gn(e,t)}catch{return jn(e)}}function u(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function a(e){return String(e??"").trim()}function _(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)?r:t}function b(e){return Array.isArray(e)?e.map(String):[]}function tt(e,t,r=process.cwd()){let n=u(e)?e:{};return a(n.cwd)||a(n.workspace)||a(t)||a(r)||process.cwd()}var St="[redacted]",Vn=/(authorization|api[_-]?key|credential|password|secret|token)/i;function Et(e){return Vn.test(a(e))}function ar(e,t=[]){let r=String(e??"");for(let n of t){let s=String(n??"");s.length>=4&&(r=r.split(s).join(St))}return r.replace(/((?:authorization|api[_-]?key|credential|password|secret|token)\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,`$1${St}`).replace(/([?&](?:api[_-]?key|credential|password|secret|token)=)[^&\s]+/gi,`$1${St}`)}function V(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]=V(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=>V(i,t));return t.delete(e),s}let r={},n=Et(e.name||e.key);for(let[s,i]of Object.entries(e))r[s]=Et(s)||n&&s.toLowerCase()==="value"?St:V(i,t);return t.delete(e),r}function cr(e,t=4e3){let r=JSON.stringify(V(e))??String(e);return!Number.isFinite(t)||r.length<=t?r:`${r.slice(0,t)}...`}function h(e,t,r,n={}){let s={ts:zn(),level:e,module:t,msg:r,...u(n)?V(n):{}};console.error(JSON.stringify(s))}function Ot(e){return Array.isArray(e)?e.map(t=>u(t)?t.type==="text"?a(t.text):t.type==="file"?a(t.uri):t.type==="image"?a(t.uri):"":"").filter(Boolean).join(`
|
|
3
3
|
`):""}var It=class{constructor(t){this.agent=t,this.sessionCounter=0}async sessionNew(){return this.sessionCounter+=1,{sessionId:`echo-${this.agent.agentId}-${this.sessionCounter}`}}async sessionPrompt(t,r){let n=Ot(t.prompt);return r({sessionId:t.sessionId,update:{sessionUpdate:"agent_message_chunk",content:{type:"text",text:n?`Echo runtime received: ${n}`:"Echo runtime received an empty prompt."}}}),{stopReason:"end_turn"}}async sessionCancel(){return{ok:!0}}};import{spawn as Wn}from"node:child_process";var ft="2.0",te=3e4,Jn=4e3;function xt(e,t){let r=Object.entries(u(t)?t:{}).filter(([n])=>Et(n)).map(([,n])=>n);return ar(e,r)}function Xn(e){return{code:Number.isInteger(e?.code)?e.code:-32e3,message:a(e?.message)||String(e),data:u(e?.data)?e.data:void 0}}function Yn(e){if(!u(e))return new Error(String(e||"runtime error"));let t=a(e.message)||"runtime error",r="data"in e?cr(e.data,4e3):"",n=new Error(r?`${t}; data=${r}`:t);return n.rpcCode=e.code,n.data=e.data,n}function Zn(e){return u(e)&&"id"in e&&!("method"in e)}function Qn(e){return u(e)&&typeof e.method=="string"&&"id"in e}function ts(e){return u(e)&&typeof e.method=="string"&&!("id"in e)}var Ct=class{constructor({command:t,args:r=[],cwd:n,env:s,label:i,framing:o="line",detached:c=!0}){this.command=t,this.args=Array.isArray(r)?r.map(String):[],this.cwd=n||process.cwd(),this.env=u(s)?{...s}:{...process.env},this.label=i||t,this.framing=o==="content-length"?"content-length":"line",this.detached=c!==!1,this.child=null,this.exited=!1,this.exitCode=null,this.exitSignal=null,this.stopPromise=null,this.stderrTail="",this.spawnError=null,this.lineBuffer="",this.headerBuffer=Buffer.alloc(0),this.seq=0,this.pending=new Map,this.notificationHandlers=new Map,this.requestHandlers=new Map,this.exitHandlers=new Set}async start({initialize:t=!0,initializeParams:r={},initializeTimeoutMs:n=te}={}){if(!(this.child&&!this.exited)&&(this.exited=!1,this.exitCode=null,this.exitSignal=null,this.stderrTail="",this.spawnError=null,this.child=Wn(this.command,this.args,{cwd:this.cwd,env:this.env,stdio:["pipe","pipe","pipe"],detached:this.detached}),this.child.stdout.on("data",s=>this.onStdout(s)),this.child.stderr.setEncoding("utf8"),this.child.stderr.on("data",s=>{this.stderrTail=`${this.stderrTail}${s}`.slice(-Jn);let i=xt(s.trimEnd(),this.env);i&&h("debug","runtime.stderr","runtime stderr",{target:this.label,text:i})}),this.child.on("exit",(s,i)=>this.handleExit(s,i)),this.child.on("error",s=>{this.spawnError=s,this.rejectAll(s)}),t)){let s=Math.max(1,_(n,te));try{await this.call("initialize",{protocolVersion:1,clientCapabilities:{},...r},s)}catch(i){let o=this.startupFailureDetail(),c=xt(i?.message||i,this.env);h("warn","runtime.initialize","runtime initialize failed",{target:this.label,timeoutMs:s,cause:c,...o}),await this.stop("initialize failed",{termTimeoutMs:1e3,killTimeoutMs:1e3});let l=o.stderr?`; stderr: ${o.stderr}`:`; command=${o.command}; cwd=${o.cwd}`;throw Object.assign(new Error(`runtime initialize failed: ${c}${l}`,{cause:i}),{code:"RUNTIME_INITIALIZE_FAILED",detail:o})}}}startupFailureDetail(){return{command:this.command,cwd:this.cwd,exited:this.exited,exitCode:this.exitCode,exitSignal:this.exitSignal,...this.spawnError?{spawnError:xt(this.spawnError.message,this.env)}:{},...this.stderrTail.trim()?{stderr:xt(this.stderrTail.trim(),this.env)}:{}}}onStdout(t){if(this.framing==="content-length"){this.onContentLengthData(Buffer.isBuffer(t)?t:Buffer.from(t));return}this.onLineData(t.toString("utf8"))}onLineData(t){this.lineBuffer+=t;let r=this.lineBuffer.split(/\r?\n/);this.lineBuffer=r.pop()||"";for(let n of r){let s=n.trim();s&&this.dispatchRaw(s)}}onContentLengthData(t){for(this.headerBuffer=Buffer.concat([this.headerBuffer,t]);this.headerBuffer.length>0;){let r=this.headerBuffer.indexOf(`\r
|
|
4
4
|
\r
|
|
5
5
|
`);if(r<0)return;let s=this.headerBuffer.subarray(0,r).toString("utf8").match(/content-length:\s*(\d+)/i);if(!s){h("warn","runtime.protocol","missing Content-Length header",{target:this.label}),this.headerBuffer=Buffer.alloc(0);return}let i=Number.parseInt(s[1],10),o=r+4,c=o+i;if(this.headerBuffer.length<c)return;let l=this.headerBuffer.subarray(o,c).toString("utf8");this.headerBuffer=this.headerBuffer.subarray(c),this.dispatchRaw(l)}}dispatchRaw(t){let r;try{r=JSON.parse(t)}catch(n){h("warn","runtime.protocol","invalid JSON frame",{target:this.label,error:String(n)});return}this.dispatch(r)}dispatch(t){if(Zn(t)){this.resolveResponse(t);return}if(Qn(t)){this.handleRequest(t);return}ts(t)&&this.handleNotification(t)}resolveResponse(t){let r=String(t.id),n=this.pending.get(r);n&&(clearTimeout(n.timer),this.pending.delete(r),t.error?(h("warn","runtime.protocol","runtime rpc error",{target:this.label,method:n.method,requestId:r,error:t.error}),n.reject(Yn(t.error))):n.resolve(t.result))}async handleRequest(t){let r=this.requestHandlers.get(t.method);if(!r){this.writeFrame({jsonrpc:ft,id:t.id,error:{code:-32601,message:`method not found: ${t.method}`}});return}try{let n=await r(u(t.params)?t.params:{},t);this.writeFrame({jsonrpc:ft,id:t.id,result:n??{}})}catch(n){this.writeFrame({jsonrpc:ft,id:t.id,error:Xn(n)})}}handleNotification(t){let r=this.notificationHandlers.get(t.method);if(r)for(let n of r)n(u(t.params)?t.params:{},t)}call(t,r={},n=te){if(!this.child||!this.child.stdin||this.exited)return Promise.reject(new Error("runtime process is not running"));let s=`${t}_${++this.seq}`,i={jsonrpc:ft,id:s,method:t,params:r};return new Promise((o,c)=>{let l=setTimeout(()=>{this.pending.delete(s),c(new Error(`${t} timed out after ${n}ms`))},n);this.pending.set(s,{resolve:o,reject:c,timer:l,method:t}),this.writeFrame(i,d=>{d&&(clearTimeout(l),this.pending.delete(s),c(d))})})}notify(t,r={}){this.writeFrame({jsonrpc:ft,method:t,params:r})}writeFrame(t,r){if(!this.child?.stdin||this.exited){r?.(new Error("runtime process is not running"));return}let n=JSON.stringify(t),s=this.framing==="content-length"?`Content-Length: ${Buffer.byteLength(n,"utf8")}\r
|
|
@@ -15,7 +15,7 @@ ${s}`:s;Gr(t,r,n,d,s)&&(o=1,c=1)}return s&&i&&(t.finalTextSeen=!0),qr(t,Br(e,t.a
|
|
|
15
15
|
`:"";t+=`${s}${n}`}}return t.trim()}function bo(e){let t=String(e||"").trim();if(!t)return"";let r=t.match(/(?:^|\n)#{1,3}\s+\S/);return!r||r.index===0?t:t.slice(r.index+(t[r.index]===`
|
|
16
16
|
`?1:0)).trim()}function ln(e){let t=String(e||"").trim();if(!t)return null;try{let r=JSON.parse(t);if(u(r)&&(gn(r)||L(r._artifacts)||L(r.artifacts)||L(r._decision)||L(r._meta)))return r}catch{}return null}function Rt(e){try{return Se(e)}catch{return null}}function jt(...e){let t=null;for(let r of e)try{if(Se(r))return}catch(n){t||=n}if(t)throw t}function $e(e){let t=String(e||"").trim();if(!t)return null;let r=Rt(t);if(r)return r;let n=[...t.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi)];for(let s=n.length-1;s>=0;s-=1){let i=ln(n[s][1]);if(i)return i}if(!t.endsWith("}"))return null;for(let s=t.lastIndexOf("{");s>=0;s=t.lastIndexOf("{",s-1)){let i=ln(t.slice(s));if(i)return i}return null}function Ao(e){let t=Rt(Ge(e));if(t)return t;let r=Gt(e);for(let n=r.length-1;n>=0;n-=1){let s=Rt(r[n]);if(s)return s}return Rt(st(r))}function gn(e){if(!u(e))return!1;if(L(e.output))return!0;for(let t of["content","text","message","summary"])if(a(e[t]))return!0;return!!(pn(e.status)||a(e.error)||a(e.errorMessage))}function B(e){let t=u(e)?{...e}:{};return(!Array.isArray(t._artifacts)||t._artifacts.length===0)&&Array.isArray(t.artifacts)&&t.artifacts.length>0&&(t._artifacts=t.artifacts),delete t.artifacts,t}function No(e){return u(e)?typeof(u(e._decision)?e._decision:u(e.decision)?e.decision:e).passed=="boolean":!1}function _n(e){return u(e)?u(e._decision)&&typeof e._decision.passed=="boolean"?!0:No(e.output):!1}function Fe(e,t,r){let n=u(e)?{...e}:{};if(!L(n.output)){for(let s of["summary","message","content","text"])if(a(n[s])){n.output=a(n[s]);break}}return!L(n.output)&&a(r)&&(n.output=a(r)),{...n,_meta:{...u(n._meta)?n._meta:{},runtimeOutputSource:t,requiredRuntimeResult:!0,finalMessagePreview:a(r).slice(0,1e3)}}}var Mo=["dataUrl","dataURL","contentDataUrl","contentDataURL","contentBase64","base64","data"];function dn(e){if(!u(e))return"";let t=u(e.content)?e.content:{},r=u(e.metadata)?e.metadata:{};return a(e.fieldKey||e.field_key||t.fieldKey||r.fieldKey)}function Uo(e,t){let r=u(e.content)?e.content:{},n=u(t.content)?t.content:{},s={...e,...t,content:{...r,...n},metadata:{...u(e.metadata)?e.metadata:{},...u(t.metadata)?t.metadata:{}}};for(let i of Mo)L(e[i])&&(s[i]=e[i]),L(r[i])&&(s.content[i]=r[i]);return s}function Tn(e,t){let r=Array.isArray(e)?e.filter(u):[],n=Array.isArray(t)?t.filter(u):[];if(!r.length)return n;if(!n.length)return r;let s=[...r],i=new Map;for(let c=0;c<r.length;c+=1){let l=dn(r[c]),d=i.get(l)||[];d.push(c),i.set(l,d)}let o=new Map;for(let c of n){let l=dn(c),d=o.get(l)||0;o.set(l,d+1);let f=i.get(l)?.[d];f===void 0?s.push(c):s[f]=Uo(s[f],c)}return s}function j(e,t,r){let n={...e,...t,_meta:{...u(e._meta)?e._meta:{},...u(t._meta)?t._meta:{},runtimeOutputSource:r}};return(Array.isArray(e._artifacts)||Array.isArray(t._artifacts))&&(n._artifacts=Tn(e._artifacts,t._artifacts)),n}function yn(e,t,r={}){let n=a(r.promptKind),s=r.requiresRuntimeResult===!0,i=s||n==="dispatch",o=B(e),c=typeof o.output=="string"?Rt(o.output):null;if(c)return j(o,B(c),"result_block");let l=Co(t),d=l?$e(l):null,f=i?Ao(t):null;if(gn(o))return pn(o.status)||a(o.error)||a(o.errorMessage)?o:n==="dispatch"&&d?j(o,B(d),"final_event"):n==="dispatch"&&f?j(o,B(f),"updates"):!s||_n(o)?o:d?j(o,B(d),"final_event"):f?j(o,B(f),"updates"):(jt(o.output,l,st(Gt(t))),Fe(o,"result",o.output));if(d)return j(o,B(d),"final_event");if(f)return j(o,B(f),"updates");if(l)return s?(jt(l,st(Gt(t))),Fe(o,"final_event",l)):{...o,output:l,_meta:{...u(o._meta)?o._meta:{},runtimeOutputSource:"final_event"}};let p=Ge(t),m=$e(p);if(m)return j(o,B(m),"updates");let g=bo(p);if(!g)return s&&jt(st(Gt(t))),o;let y=$e(g);return y?j(o,B(y),"updates"):s?(jt(p,g),Fe(o,"updates",g)):{...o,output:g,_meta:{...u(o._meta)?o._meta:{},runtimeOutputSource:"updates"}}}function ze(e){return u(e)?a(e.stopReason||e.stop_reason).toLowerCase():""}function Rn(e){return oo.has(ze(e))}function Po(e,t,r){if(r.promptKind!=="dispatch"||r.requiresRuntimeResult!==!0||!Rn(e))return!1;try{return!_n(yn(e,t,r))}catch{return!0}}function ko(){return["Your previous final response reached the output limit before the Runtime Result protocol was complete.","Re-emit the complete final Runtime Result from scratch using the conclusion you already reached.","Do not repeat analysis, process notes, tool calls, or task work.",`Keep the OUTPUT report within ${fn} Unicode characters.`,`Output ${_e}, ${Te}, ${ye}, and ${Re} on their own lines.`,"The CONTROL block must be valid JSON containing _decision and must be fully closed.","Return only the two protocol blocks."].join(`
|
|
17
17
|
`)}function Lo(e,t){let r=u(t)?{...t}:{},n=Tn(e?._artifacts,t?._artifacts);return n.length>0&&(r._artifacts=n),r}function Do(e,t){return{...e,_meta:{...u(e?._meta)?e._meta:{},runtimeProtocolRetry:{attempted:!0,recovered:!0,reason:ze(t)||"max_tokens"}}}}function vo(e,t){let r=typeof e?.output=="string"?e.output:Ge(t),n=new k("runtime_output_truncated","Runtime Result \u8FBE\u5230\u6700\u5927\u8F93\u51FA\u957F\u5EA6\uFF0C\u7D27\u51D1\u91CD\u8BD5\u540E\u4ECD\u672A\u5B8C\u6574\u8FD4\u56DE",r);return n.detail={...n.detail,stopReason:ze(e)||"max_tokens",retryAttempted:!0},n}var zt=class{constructor(t){this.config=t,this.targets=t.targets||{},this.agents=new Map,this.sessions=new Map,this.startingSessions=new Set,this.targetReservations=new Map,this.runtimeSessionIndex=new Map,this.pendingPermissions=new Map,this.operations=new Map,this.startedAt=dt(),this.sandboxCapabilities={dispatchable:t.sandboxRequired!==!0,enforced:!1,backend:t.sandboxRequired?"unavailable":"direct",daemonStatus:t.sandboxRequired?"pending":"not_required",policySchemaVersions:[1],runtimePolicyUpdates:t.sandboxRequired===!0,workspaceSync:!1,egressProxy:!1},this.cleanupTimer=null,this.onCapacityChanged=null,this.startSessionCleanup()}async start(){try{this.sandboxCapabilities=await on(this.config)}catch(t){this.sandboxCapabilities={...this.sandboxCapabilities,dispatchable:!1,enforced:!1,backend:"unavailable",daemonStatus:"unavailable",reason:a(t?.code||t?.message||t)||"sandbox_probe_failed"},h("error","runtime-bridge","runtime node sandbox probe failed; node will not accept work",{reason:this.sandboxCapabilities.reason})}return this.sandboxCapabilities}assertDispatchable(){if(this.config.sandboxRequired&&!(this.sandboxCapabilities.dispatchable===!0&&this.sandboxCapabilities.enforced===!0))throw Object.assign(new Error("runtime node strong sandbox is unavailable"),{code:"RUNTIME_NODE_SANDBOX_UNAVAILABLE"})}operationIdentity(t,r,n){let s=u(t.goalContract)?xe(t.goalContract):a(t.goalContractHash),i=Zi("sha256").update(q({prompt:Array.isArray(t.prompt)?t.prompt:[],mcpServers:fo(t.mcpServers),metadata:u(t.metadata)?t.metadata:{}})).digest("hex");return{agentId:r,runId:a(t.runId),sessionId:n,targetCode:a(t.targetCode||t.framework),workspace:a(t.workspace),goalContractHash:s,requestHash:i}}assertOperationIdentity(t,r,n,s){let i=this.operationIdentity(r,n,s),o=Object.keys(t.identity).find(c=>t.identity[c]!==i[c]);if(o)throw Object.assign(new Error(`runtime operation correlation conflict: ${t.correlationId}`),{code:"RUNTIME_OPERATION_CORRELATION_CONFLICT",field:o})}createOperation(t,r,n,s){let i={correlationId:t,agentId:n,sessionId:s,identity:this.operationIdentity(r,n,s),sandboxPolicy:u(r.sandboxPolicy)?structuredClone(r.sandboxPolicy):null,status:"running",updates:[],listeners:new Set,waiters:[],response:null,error:null,mcpServers:r.mcpServers,createdAtMs:Date.now(),completedAtMs:null};return this.operations.set(t,i),i}async attachOperation(t,r={}){let n=()=>{if(r.onUpdate)for(let s of t.updates)r.onUpdate(s)};if(t.status==="completed")return n(),t.response;if(t.status==="failed")throw n(),t.error;r.onUpdate&&t.listeners.add(r.onUpdate);try{return n(),await new Promise((s,i)=>t.waiters.push({resolve:s,reject:i}))}finally{r.onUpdate&&t.listeners.delete(r.onUpdate)}}completeOperation(t,r){if(t.status==="running"){t.status="completed",t.response=r,t.mcpServers=null,t.completedAtMs=Date.now();for(let n of t.waiters.splice(0))n.resolve(r);t.listeners.clear()}}promptResponse(t,r,n,s,i,o=s){let c=u(t.metadata)?t.metadata:{},l=u(c._runtimeBridge)?c._runtimeBridge:{},d=yn(i,o,l),f=en(t.goalContract,s,t.goalContractHash);return{sessionId:n,runtimeSessionId:r.runtimeSessionId,result:d,updates:s,...f?{verification:f}:{}}}failOperation(t,r){if(t.status!=="running")return;let n=r instanceof Error?r:Object.assign(new Error(String(r||"runtime operation failed")),{code:"RUNTIME_NODE_ERROR"});t.status="failed",t.error=n,t.mcpServers=null,t.completedAtMs=Date.now();for(let s of t.waiters.splice(0))s.reject(n);t.listeners.clear()}cleanupOperations(t=Date.now()){let r=G(this.config.operationTtlMs,no);for(let[n,s]of this.operations)s.status!=="running"&&t-(s.completedAtMs||s.createdAtMs)>r&&this.operations.delete(n)}targetFor(t){let r=a(t)||this.config.defaultTargetCode,n=this.targets[r];if(!r||!u(n)){let s=new Error(`runtime target is not configured: ${r||"<empty>"}`);throw s.code="RUNTIME_TARGET_NOT_FOUND",s}return{code:r,target:n}}targetIdleTtlMs(t){let n=K(t)==="openclaw"?G(this.config.openClawSessionIdleTtlMs,so):G(this.config.sessionIdleTtlMs,to);return G(t?.sessionIdleTtlMs??t?.idleTtlMs,n)}targetMaxSessions(t){let n=K(t)==="openclaw"?G(this.config.openClawMaxSessions,io):G(this.config.maxSessionsPerTarget,ro);return G(t?.maxSessions,n)}targetReservationCount(t){return Number(this.targetReservations.get(t)||0)}notifyCapacityChanged(){try{this.onCapacityChanged?.()}catch(t){h("warn","runtime-bridge","capacity heartbeat callback failed",{error:String(t)})}}targetCapacitySnapshot(t=!0){return Object.entries(this.targets).map(([r,n])=>{let s=[...this.sessions.values()].filter(f=>f.targetCode===r),i=s.filter(f=>f.busy).length,o=s.length-i,c=this.targetReservationCount(r),l=this.targetMaxSessions(n),d=t?Math.max(0,l-i-c):0;return{targetCode:r,targetName:a(n?.name||n?.targetName||r),targetType:a(n?.type||"echo"),status:t?d>0?"available":"busy":"unavailable",maxSessions:l,busySessions:i,idleSessions:o,reservedSessions:c,availableSessions:d}})}targetReleaseAfterPrompt(t,r={}){let n=K(t),s=u(r?._runtimeBridge)?r._runtimeBridge:{},i=Be(s);return i!==void 0?yt(i,!1):yt(t?.releaseAfterPrompt??t?.disposeAfterPrompt,n==="openclaw")}promptReleaseAfterPrompt(t,r={}){if(this.config.sandboxRequired)return!0;let n=u(r?._runtimeBridge)?r._runtimeBridge:{},s=Be(n);return s!==void 0?yt(s,t.releaseAfterPrompt):t.releaseAfterPrompt}startSessionCleanup(){let t=G(this.config.sessionCleanupIntervalMs,eo);t<=0||(this.cleanupTimer=setInterval(()=>{this.cleanupExpiredSessions().catch(r=>{h("warn","runtime-bridge","runtime session cleanup failed",{error:String(r)})})},t),this.cleanupTimer.unref?.())}sessionCountForTarget(t){let r=0;for(let n of this.sessions.values())n.targetCode===t&&(r+=1);return r}idleTargetSessions(t){return[...this.sessions.entries()].filter(([,r])=>r.targetCode===t&&!r.busy).sort((r,n)=>(r[1].lastUsedAtMs||0)-(n[1].lastUsedAtMs||0))}async closeSession(t,r="session_closed"){let n=this.sessions.get(t);if(!n)return!1;try{await n.runtime?.stop?.(r)}catch(s){h("warn","runtime-bridge","runtime session stop failed",{sessionId:n.sessionId,runtimeSessionId:n.runtimeSessionId,targetCode:n.targetCode,runtimeKind:n.runtimeKind,error:String(s)})}return this.sessions.delete(t),this.runtimeSessionIndex.delete(`${n.agentId}:${n.runtimeSessionId}`),this.notifyCapacityChanged(),h("info","runtime-bridge","runtime session closed",{sessionId:n.sessionId,runtimeSessionId:n.runtimeSessionId,targetCode:n.targetCode,runtimeKind:n.runtimeKind,reason:r}),!0}async closeAllSessions(t="bridge_shutdown"){for(let r of[...this.sessions.keys()])await this.closeSession(r,t)}async stop(t="bridge_stop"){this.cleanupTimer&&clearInterval(this.cleanupTimer),this.cleanupTimer=null,await this.closeAllSessions(t)}async cleanupExpiredSessions(t=Date.now()){for(let[r,n]of[...this.sessions.entries()])n.busy||t-(n.lastUsedAtMs||n.createdAtMs||t)>n.idleTtlMs&&await this.closeSession(r,"idle_timeout")}async reserveTargetSlot(t,r){let n=this.targetMaxSessions(r);for(;this.sessionCountForTarget(t)+this.targetReservationCount(t)>=n;){let s=this.idleTargetSessions(t);if(!s.length){let i=new Error(`runtime target session limit reached: ${t}`);throw i.code="RUNTIME_TARGET_SESSION_LIMIT",i}await this.closeSession(s[0][0],"target_session_limit")}this.targetReservations.set(t,this.targetReservationCount(t)+1),this.notifyCapacityChanged()}releaseTargetSlot(t){let r=Math.max(0,this.targetReservationCount(t)-1);r>0?this.targetReservations.set(t,r):this.targetReservations.delete(t),this.notifyCapacityChanged()}async createAgent(t){let r=a(t.agentId);if(!r)throw Object.assign(new Error("agentId is required"),{status:400,code:"BAD_REQUEST"});let{code:n,target:s}=this.targetFor(t.targetCode||t.framework),i=this.agents.get(r);if(i&&i.targetCode!==n)throw Object.assign(new Error(`runtime agent target conflict: ${r}`),{code:"RUNTIME_AGENT_TARGET_CONFLICT"});let o=this.config.sandboxRequired?await Ue(this.config,s,t.workspace):a(t.workspace),c={agentId:r,targetCode:n,framework:a(t.framework||n),workspace:o,metadata:u(t.metadata)?t.metadata:{},createdAt:dt(),runtimeKind:K(s)};return this.agents.set(r,c),{agent:c}}runtimeFor(t,r,n={}){let{target:s}=this.targetFor(t.targetCode),i=K(s),o={onPermissionRequest:l=>n.source==="conversation_delegation"?{outcome:"denied",reason:"External group member permission continuation is not supported"}:this.requestPermission(l)},c={sessionPromptTimeoutMs:this.config.sessionPromptTimeoutMs,initializeTimeoutMs:this.config.initializeTimeoutMs,sandboxRequired:this.config.sandboxRequired,runId:n.runId,sandboxPolicy:n.sandboxPolicy,...this.config.sandboxRequired?{prepareLaunch:l=>an({config:this.config,target:s,...l,runId:n.runId,agentId:t.agentId,sessionId:r,sandboxPolicy:n.sandboxPolicy})}:{}};return i==="stdio-acp"||i==="acp"?new et(t,s,o,c):i==="openclaw"?new Ut(t,s,r,o,c):i==="cli"?new vt(t,s,c):new It(t)}async prompt(t,r={}){if(this.assertDispatchable(),this.config.sandboxRequired){let c=a(t.runId);if(!c)throw Object.assign(new Error("runId is required"),{code:"BAD_REQUEST"});t={...t,runId:c,sandboxPolicy:W(t.sandboxPolicy)}}let n=a(t.agentId),s=a(t.sessionId)||Kt(),i=a(t.correlationId);if(!n)throw Object.assign(new Error("agentId is required"),{status:400,code:"BAD_REQUEST"});if(this.cleanupOperations(),i){let c=this.operations.get(i);if(c){if(this.assertOperationIdentity(c,t,n,s),c.status==="running"&&t.metadata?.source==="conversation_delegation"){c.mcpServers=t.mcpServers;let l=this.sessions.get(`${n}:${s}`);if(l){if(!l.runtime.refreshMcpServers)throw Object.assign(new Error("This runtime cannot refresh task MCP credentials"),{code:"unsupported_dynamic_mcp"});await l.runtime.refreshMcpServers(t.mcpServers)}}return this.attachOperation(c,r)}if(t.attachOnly===!0)throw Object.assign(new Error(`runtime operation is no longer available: ${i}`),{code:"RUNTIME_OPERATION_NOT_FOUND"})}else if(t.attachOnly===!0)throw Object.assign(new Error("correlationId is required for attachOnly"),{code:"BAD_REQUEST"});let o=i?this.createOperation(i,t,n,s):null;if(o){let c=this.attachOperation(o,r);return(async()=>{try{await this._promptOwned(t,{},o,n,s)}catch(l){let d=o.status==="completed";this.failOperation(o,l),d&&h("warn","runtime-bridge","runtime cleanup failed after operation completion",{correlationId:o.correlationId,error:String(l)})}})(),await c}return await this._promptOwned(t,r,o,n,s)}async _promptOwned(t,r,n,s,i){let o=a(t.runId),c=this.config.sandboxRequired?W(n?.sandboxPolicy||t.sandboxPolicy):null,l=this.agents.get(s),d=this.targetFor(t.targetCode||t.framework||l?.targetCode);if(l&&l.targetCode!==d.code)throw Object.assign(new Error(`runtime agent target conflict: ${s}`),{code:"RUNTIME_AGENT_TARGET_CONFLICT"});if(K(d.target)==="cli"&&po(t.goalContract))throw Object.assign(new Error("CLI runtimes do not support per-run dynamic MCP required by plugin_operation"),{code:"unsupported_dynamic_mcp"});let f=l||(await this.createAgent({agentId:s,targetCode:d.code,framework:t.framework,workspace:t.workspace,metadata:t.metadata})).agent;if(!this.config.sandboxRequired){let T=a(t.workspace);T&&T!==f.workspace&&(f.workspace=T)}let p=`${s}:${i}`;await this.cleanupExpiredSessions();let m=this.sessions.get(p),g=null;if(m&&m.targetCode!==d.code)throw Object.assign(new Error(`runtime session target conflict: ${i}`),{code:"RUNTIME_SESSION_TARGET_CONFLICT"});if(m&&this.config.sandboxRequired&&m.runId!==o)throw Object.assign(new Error(`runtime session cannot be shared across runs: ${i}`),{code:"RUNTIME_SESSION_RUN_CONFLICT"});if(!m){if(this.startingSessions.has(p))throw Object.assign(new Error(`runtime session is already starting: ${i}`),{code:"RUNTIME_SESSION_BUSY"});this.startingSessions.add(p);let{code:T,target:R}=d,w;try{await this.reserveTargetSlot(T,R),g=T;let O=this.runtimeFor(f,i,{runId:o,sandboxPolicy:c,source:t.metadata?.source});w=O;let P=n?.mcpServers||t.mcpServers||[],v=await O.sessionNew({cwd:tt(R,f.workspace),mcpServers:P,metadata:u(t.metadata)?t.metadata:{}});if(n&&n.status!=="running")throw Object.assign(new Error("Runtime operation was cancelled before prompt dispatch"),{code:"RUNTIME_OPERATION_CANCELLED"});let N=Date.now();m={agentId:s,sessionId:i,runtime:O,targetCode:T,runtimeKind:K(R),runId:o,sandboxPolicy:c?structuredClone(c):null,runtimeSessionId:a(u(v)?v.sessionId:"")||i,idleTtlMs:this.targetIdleTtlMs(R),releaseAfterPrompt:this.config.sandboxRequired?!0:this.targetReleaseAfterPrompt(R,t.metadata),createdAtMs:N,lastUsedAtMs:N,busy:!1,createdAt:dt()},this.sessions.set(p,m),this.runtimeSessionIndex.set(`${s}:${m.runtimeSessionId}`,m),n?.mcpServers!==P&&n?.mcpServers&&O.refreshMcpServers&&await O.refreshMcpServers(n.mcpServers)}catch(O){throw this.sessions.get(p)?.runtime===w?await this.closeSession(p,"session_start_failed"):await w?.stop("session_start_failed"),g&&(this.releaseTargetSlot(g),g=null),O}finally{this.startingSessions.delete(p)}}if(m.busy){let T=new Error(`runtime session is already running: ${i}`);throw T.code="RUNTIME_SESSION_BUSY",T}m.busy=!0,g&&this.releaseTargetSlot(g),this.notifyCapacityChanged(),m.operationCorrelationId=n?.correlationId||null,m.lastUsedAtMs=Date.now();let y=n?.updates||[],x=T=>{let R=mo(T,i,m);if(y.push(R),n)for(let w of n.listeners)try{w?.(R)}catch(O){h("warn","runtime-bridge","runtime operation update listener failed",{correlationId:n.correlationId,error:String(O)})}else r.onUpdate?.(R)},A=T=>{if(!(!n||n.status!=="running"||!u(T))){if(T.status==="failed"){let R=T.error;if(R instanceof Error){this.failOperation(n,R);return}let w=u(R)?R:{},O=Object.assign(new Error(a(w.message||T.message)||"runtime terminal failure"),{code:a(w.code||T.code)||"RUNTIME_TERMINAL_FAILED"});this.failOperation(n,O);return}this.completeOperation(n,this.promptResponse(t,m,i,y,u(T.result)?T.result:{stopReason:"end_turn"}))}};try{let T=tn(t.goalContract),R=Array.isArray(t.prompt)?[...t.prompt]:[];T&&R.unshift({type:"text",text:T,metadata:{source:"orcha_goal_contract"}});let w=u(t.metadata)?t.metadata:{},O=u(w._runtimeBridge)?w._runtimeBridge:{},P=await m.runtime.sessionPrompt({sessionId:m.runtimeSessionId,prompt:R,metadata:w},x,A),v=y,N=null;if(mn({type:m.runtimeKind})&&Po(P,y,O)){N=P;let Y=y.length,at=await m.runtime.sessionPrompt({sessionId:m.runtimeSessionId,prompt:[{type:"text",text:ko()}],metadata:w,_meta:{thinking:"off"}},x,A);P=Lo(N,at),v=y.slice(Y)}let E;try{E=this.promptResponse(t,m,i,y,P,v)}catch(Y){throw N&&Rn(P)?vo(P,v):Y}return N&&(E.result=Do(E.result,N)),n&&this.completeOperation(n,E),E}finally{m.busy=!1,this.notifyCapacityChanged(),m.operationCorrelationId===n?.correlationId&&(m.operationCorrelationId=null),m.lastUsedAtMs=Date.now(),this.promptReleaseAfterPrompt(m,u(t.metadata)?t.metadata:{})&&await this.closeSession(p,"release_after_prompt"),n&&(n.mcpServers=null)}}async updatePolicy(t){if(this.assertDispatchable(),!this.config.sandboxRequired)throw Object.assign(new Error("runtime sandbox policy updates require an enforced sandbox"),{code:"RUNTIME_NODE_SANDBOX_UNAVAILABLE"});let r=a(t.agentId),n=a(t.runId),s=a(t.sessionId),i=a(t.correlationId);if(!r||!n||!s||!i)throw Object.assign(new Error("agentId, runId, sessionId and correlationId are required"),{code:"BAD_REQUEST"});let o=W(t.sandboxPolicy),c=this.operations.get(i);if(c&&(c.agentId!==r||c.sessionId!==s||c.identity.runId!==n))throw Object.assign(new Error(`runtime operation policy identity conflict: ${i}`),{code:"RUNTIME_OPERATION_CORRELATION_CONFLICT"});let l=`${r}:${s}`,d=this.sessions.get(l);if(d&&d.runId!==n)throw Object.assign(new Error(`runtime session policy identity conflict: ${s}`),{code:"RUNTIME_SESSION_RUN_CONFLICT"});let f=d?.sandboxPolicy||c?.sandboxPolicy;if(!f)throw Object.assign(new Error(`runtime operation is no longer available: ${i}`),{code:"RUNTIME_OPERATION_NOT_FOUND"});let p=Number(f.policyRevision),m=Number(o.policyRevision);if(m<p)throw Object.assign(new Error("runtime sandbox policy revision is stale"),{code:"RUNTIME_POLICY_REVISION_CONFLICT",currentPolicyRevision:p});if(m===p){if(q(f)!==q(o))throw Object.assign(new Error("runtime sandbox policy revision payload conflicts"),{code:"RUNTIME_POLICY_REVISION_CONFLICT",currentPolicyRevision:p});return{updated:!1,idempotent:!0,policyRevision:p,accessMode:f.accessMode}}let g=sn(f,o);c&&(c.sandboxPolicy=structuredClone(o)),d&&(d.sandboxPolicy=structuredClone(o));let y=!1;return g&&d?.busy===!0&&(await d.runtime.sessionCancel({sessionId:d.runtimeSessionId}),y=await this.closeSession(l,"sandbox_policy_downgrade")),{updated:!0,policyRevision:m,accessMode:o.accessMode,activeCommandCancelled:y,deferredToNextLaunch:!g&&d?.busy===!0}}async cancel(t){let r=a(t.agentId),n=a(t.sessionId),s=a(t.correlationId);if(s){let c=this.operations.get(s);if(!c||c.status!=="running")return{cancelled:!1,correlationId:s,reason:"operation_not_running"};if(c.agentId!==r||c.sessionId!==n)throw Object.assign(new Error(`runtime operation cancellation identity conflict: ${s}`),{code:"RUNTIME_OPERATION_CORRELATION_CONFLICT"});let l=this.sessions.get(`${r}:${n}`);return!l||l.busy!==!0||l.operationCorrelationId!==s?(this.failOperation(c,Object.assign(new Error("Runtime operation cancelled before dispatch"),{code:"RUNTIME_OPERATION_CANCELLED"})),{cancelled:!0,correlationId:s,reason:"cancelled_before_dispatch"}):(await l.runtime.sessionCancel({sessionId:l.runtimeSessionId}),await this.closeSession(`${r}:${n}`,"cancelled"),{cancelled:!0,correlationId:s})}let i=`${r}:${n}`,o=this.sessions.get(i);return o?(await o.runtime.sessionCancel({sessionId:o.runtimeSessionId}),await this.closeSession(i,"cancelled"),{cancelled:!0}):{cancelled:!1}}async dispatch(t,r={}){let n=a(t.agentId),s=a(t.taskId),i=a(t.executionId);if(!n||!s)throw Object.assign(new Error("agentId and taskId are required"),{status:400,code:"BAD_REQUEST"});let o=a(t.sessionId)||`dispatch-${i||s}`,c=a(t.instructions),l=Eo(t),d=hn(t),{target:f}=this.targetFor(t.targetCode||t.framework),p=[{type:"text",text:["Task dispatch received.",`taskId: ${s}`,i?`executionId: ${i}`:"",c?`instructions: ${c}`:"",l?"orchaContext:":"",l,l?"Use orchaContext as the source of truth for upstream outputs, review reports, artifacts, and workflow metadata.":"","Follow the execution protocol in instructions exactly.","When embedding a generated artifact in final Markdown, use the Orcha artifact placeholder as the link target: orcha-artifact://<fieldKey>/<index>.","Example: use  for the first generated image artifact.","Do not use local filesystem paths, file:// URLs, or data: URLs in final Markdown; Orcha replaces artifact placeholders after ingestion.",d?`For decision results, put the raw report between ${_e} and ${Te}.`:"",d?`Then put a JSON object containing _decision between ${ye} and ${Re}.`:"",d?"Do not JSON-escape the report. Keep output out of the CONTROL JSON, and put every protocol marker on its own line.":"",d?`Keep the report within ${fn} Unicode characters so the CONTROL block fits before the output limit.`:"","Return only the final answer required by that protocol.","Do not include process notes, logs, or explanations."].filter(Boolean).join(`
|
|
18
|
-
`)}];return this.prompt({...t,agentId:n,sessionId:o,prompt:p,metadata:So(t,f)},r)}async requestPermission({agent:t,runtimeSessionId:r,request:n,emitUpdate:s}){let i=Kt(),c=this.runtimeSessionIndex.get(`${t.agentId}:${r}`)?.sessionId||r||Kt(),l={permissionId:i,agentId:t.agentId,sessionId:c,runtimeSessionId:r,request:u(n)?n:{},status:"pending",createdAt:dt()};return s?.({sessionId:r,update:{sessionUpdate:"permission_request",permission:l}}),await new Promise(d=>{let f=_(n?.timeoutMs,this.config.permissionRequestTimeoutMs),p=setTimeout(()=>{this.pendingPermissions.delete(i),d({permissionId:i,outcome:"denied",response:{reason:"permission request timed out"}})},f);this.pendingPermissions.set(i,{timer:p,resolve:d,permission:l})})}async respondPermission(t){let r=a(t.permissionId),n=this.pendingPermissions.get(r),s=a(t.outcome||"approved")||"approved";return n?(clearTimeout(n.timer),this.pendingPermissions.delete(r),n.resolve({permissionId:r,outcome:s,response:u(t.response)?t.response:{},userId:a(t.userId),metadata:u(t.metadata)?t.metadata:{}}),{accepted:!0,permissionId:r,outcome:s}):{accepted:!1,permissionId:r,outcome:s}}health(){return{status:this.config.sandboxRequired&&!this.sandboxCapabilities.dispatchable?"unavailable":"ok",bridgeVersion:Q,startedAt:this.startedAt,agents:[...this.agents.values()].map(t=>({agentId:t.agentId,targetCode:t.targetCode,framework:t.framework,runtimeKind:t.runtimeKind})),sessions:this.sessions.size,pendingPermissions:this.pendingPermissions.size,targets:Object.keys(this.targets),sandboxCapabilities:this.sandboxCapabilities}}};import Ho from"node:http";import $o from"node:https";import{randomBytes as wn}from"node:crypto";var it=1,J=3,Fo=1e4,Vt=class{constructor(t,r={}){this.url=t,this.readyState=0,this.socket=null,this.request=null,this.buffer=Buffer.alloc(0),this.listeners=new Map,this.connectTimeoutMs=Bo(r.connectTimeoutMs,Fo),this.connectTimer=null,this.connect()}addEventListener(t,r){let n=this.listeners.get(t)||new Set;n.add(r),this.listeners.set(t,n)}emit(t,r={}){let n=this.listeners.get(t);if(n)for(let s of n)s(r)}connect(){let t=new URL(this.url),r=t.protocol==="wss:"?$o:Ho,n=wn(16).toString("base64"),s=r.request({protocol:t.protocol==="wss:"?"https:":"http:",hostname:t.hostname,port:t.port||(t.protocol==="wss:"?443:80),path:`${t.pathname}${t.search}`,method:"GET",headers:{Connection:"Upgrade",Upgrade:"websocket","Sec-WebSocket-Key":n,"Sec-WebSocket-Version":"13"}});this.request=s,this.startConnectTimer(s),s.on("upgrade",(i,o,c)=>{if(this.clearConnectTimer(),this.readyState===J){o.destroy();return}this.socket=o,this.readyState=it,o.on("data",l=>this.onData(l)),o.on("close",()=>this.onClose()),o.on("error",l=>{this.readyState!==J&&this.emit("error",{error:l,message:l.message,type:"error"}),this.onClose()}),c?.length&&this.onData(c),this.emit("open")}),s.on("response",i=>{this.clearConnectTimer(),this.emit("error",{message:`websocket upgrade failed: HTTP ${i.statusCode}`,type:"error"}),i.resume(),this.onClose()}),s.on("error",i=>{this.clearConnectTimer(),this.readyState!==J&&this.emit("error",{error:i,message:i.message,type:"error"}),this.onClose()}),s.end()}startConnectTimer(t){this.connectTimeoutMs<=0||(this.connectTimer=setTimeout(()=>{if(this.readyState===it||this.readyState===J)return;let r=`websocket connect timeout after ${this.connectTimeoutMs}ms`;this.emit("error",{message:r,type:"timeout"}),this.onClose(),t.destroy(new Error(r))},this.connectTimeoutMs),this.connectTimer.unref?.())}clearConnectTimer(){this.connectTimer&&(clearTimeout(this.connectTimer),this.connectTimer=null)}send(t){!this.socket||this.readyState!==it||this.socket.write(Ve(1,Buffer.from(String(t),"utf8")))}close(){if(this.readyState!==J){if(this.clearConnectTimer(),!this.socket){this.request?.destroy(),this.onClose();return}try{this.readyState===it&&this.socket.write(Ve(8,Buffer.alloc(0))),this.socket.end()}catch{this.socket.destroy()}this.onClose()}}onClose(){this.readyState!==J&&(this.clearConnectTimer(),this.readyState=J,this.request=null,this.emit("close"))}onData(t){for(this.buffer=Buffer.concat([this.buffer,t]);this.buffer.length>=2;){let r=this.buffer[0],n=this.buffer[1],s=r&15,i=(n&128)!==0,o=n&127,c=2;if(o===126){if(this.buffer.length<c+2)return;o=this.buffer.readUInt16BE(c),c+=2}else if(o===127){if(this.buffer.length<c+8)return;let f=this.buffer.readUInt32BE(c),p=this.buffer.readUInt32BE(c+4);o=f*2**32+p,c+=8}let l=c;if(i&&(c+=4),this.buffer.length<c+o)return;let d=this.buffer.subarray(c,c+o);if(i){let f=this.buffer.subarray(l,l+4);d=Buffer.from(d.map((p,m)=>p^f[m%4]))}this.buffer=this.buffer.subarray(c+o),s===1?this.emit("message",{data:d.toString("utf8")}):s===8?this.close():s===9&&this.socket?.write(Ve(10,d))}}};function Bo(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)&&r>=0?r:t}function Ve(e,t){let r=t.length,n=2;r>=126&&r<=65535?n+=2:r>65535&&(n+=8);let s=wn(4),i=Buffer.alloc(n+4+r);i[0]=128|e;let o=2;r<126?i[1]=128|r:r<=65535?(i[1]=254,i.writeUInt16BE(r,o),o+=2):(i[1]=255,i.writeUInt32BE(Math.floor(r/2**32),o),i.writeUInt32BE(r>>>0,o+4),o+=8),s.copy(i,o),o+=4;for(let c=0;c<r;c+=1)i[o+c]=t[c]^s[c%4];return i}function qo(e){let t=new URL(e);if(t.protocol==="http:")t.protocol="ws:";else if(t.protocol==="https:")t.protocol="wss:";else if(t.protocol!=="ws:"&&t.protocol!=="wss:")throw new Error(`unsupported ORCHA_RUNTIME_ORCHA_URL protocol: ${t.protocol}`);return t.pathname=`${t.pathname.replace(/\/+$/,"")}/api/agent-runtime-bridge/ws`,t.search="",t.toString()}function jo(e,t=!0){return Object.entries(e||{}).map(([r,n])=>({targetCode:r,targetName:a(n?.name||n?.targetName||r),targetType:a(n?.type||"echo"),status:t?"available":"unavailable"}))}var We=Object.freeze(["health","agents/create","agents/dispatch","sessions/prompt","sessions/policy","sessions/cancel","permissions/respond"]),Wt=class{constructor(t,r){this.config=t,this.bridge=r,this.ws=null,this.stopped=!1,this.connected=!1,this.reconnectTimer=null,this.heartbeatTimer=null,this.capacityHeartbeatTimer=null,this.bridge.onCapacityChanged=()=>this.scheduleCapacityHeartbeat()}sandboxCapabilities(){return this.bridge.sandboxCapabilities||{dispatchable:this.config.sandboxRequired!==!0,enforced:!1,backend:"development_direct",daemonStatus:"development_only",policySchemaVersions:[1],runtimePolicyUpdates:!0,workspaceSync:!1,egressProxy:!1}}runtimeTargets(){let t=this.sandboxCapabilities().dispatchable===!0;return typeof this.bridge.targetCapacitySnapshot=="function"?this.bridge.targetCapacitySnapshot(t):jo(this.config.targets,t)}start(){this.connect()}stop(){this.stopped=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null,this.capacityHeartbeatTimer&&clearTimeout(this.capacityHeartbeatTimer),this.capacityHeartbeatTimer=null,this.bridge.onCapacityChanged=null,this.ws?.close()}connect(){if(this.stopped)return;let t=qo(this.config.orchaUrl),r=new Vt(t,{connectTimeoutMs:this.config.connectTimeoutMs});this.ws=r,r.addEventListener("open",()=>{if(this.ws!==r||this.stopped){r.close();return}this.authenticate(r)}),r.addEventListener("message",n=>this.handleMessage(n.data,r)),r.addEventListener("close",()=>this.scheduleReconnect("close",r)),r.addEventListener("error",n=>{h("warn","orcha-client","runtime node websocket error",{error:String(n?.message||n?.type||n)})})}authenticate(t=this.ws){this.send({type:"runtime_node.authenticate",token:this.config.nodeToken,nodeId:this.config.nodeId,nodeName:this.config.nodeName,version:Q,protocolVersion:"orcha-runtime-node.v1",defaultTargetCode:this.config.defaultTargetCode,supportedMethods:We,sandboxCapabilities:this.sandboxCapabilities(),targets:this.runtimeTargets()},t)}scheduleReconnect(t,r=this.ws){r&&this.ws!==r||(this.connected=!1,this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null,this.capacityHeartbeatTimer&&clearTimeout(this.capacityHeartbeatTimer),this.capacityHeartbeatTimer=null,r&&this.ws===r&&(this.ws=null),!this.stopped&&(this.reconnectTimer||(h("info","orcha-client","runtime node disconnected; reconnect scheduled",{reason:t,reconnectMs:this.config.reconnectMs}),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},this.config.reconnectMs))))}async handleMessage(t,r=this.ws){if(r&&this.ws!==r)return;let n;try{n=JSON.parse(String(t))}catch(s){h("warn","orcha-client","invalid Orcha websocket frame",{error:String(s)});return}if(u(n)){if(n.type==="runtime_node.authenticated"){if(r&&this.ws!==r)return;this.connected=!0,this.startHeartbeat(r),h("info","orcha-client","runtime node authenticated",{nodeId:this.config.nodeId,connectionId:n.connectionId});return}if(n.type==="orcha.runtime.request"){await this.handleRequest(n);return}n.type==="runtime_node.ping"&&this.send({type:"runtime_node.pong",ts:new Date().toISOString(),supportedMethods:We,sandboxCapabilities:this.sandboxCapabilities(),targets:this.runtimeTargets()})}}startHeartbeat(t){this.heartbeatTimer&&clearInterval(this.heartbeatTimer);let r=Math.max(1e3,Number(this.config.heartbeatIntervalMs||15e3)),n=()=>this.sendCapacityHeartbeat(t);n(),this.heartbeatTimer=setInterval(n,r),this.heartbeatTimer.unref?.()}scheduleCapacityHeartbeat(){if(!this.connected||this.capacityHeartbeatTimer)return;let t=Math.max(25,Math.min(1e3,Number(this.config.capacityHeartbeatDebounceMs||100)));this.capacityHeartbeatTimer=setTimeout(()=>{this.capacityHeartbeatTimer=null,this.sendCapacityHeartbeat()},t),this.capacityHeartbeatTimer.unref?.()}sendCapacityHeartbeat(t=this.ws){return this.connected?this.send({type:"runtime_node.heartbeat",ts:new Date().toISOString(),supportedMethods:We,sandboxCapabilities:this.sandboxCapabilities(),targets:this.runtimeTargets()},t):!1}async handleRequest(t){let r=a(t.id),n=a(t.method),s=u(t.params)?t.params:{};try{let i=await this.invoke(n,s,r);this.send({type:"orcha.runtime.response",id:r,ok:!0,result:i})}catch(i){this.send({type:"orcha.runtime.response",id:r,ok:!1,error:{code:i.code||"RUNTIME_NODE_ERROR",message:i.message||String(i),...i.detail===void 0?{}:{detail:i.detail}}})}}async invoke(t,r,n){if(t==="health")return this.bridge.health();if(t==="agents/create")return this.bridge.createAgent(r);if(t==="agents/dispatch")return this.bridge.dispatch(r,{onUpdate:s=>this.sendUpdate(n,s)});if(t==="sessions/prompt")return this.bridge.prompt(r,{onUpdate:s=>this.sendUpdate(n,s)});if(t==="sessions/policy")return this.bridge.updatePolicy(r);if(t==="sessions/cancel")return this.bridge.cancel(r);if(t==="permissions/respond")return this.bridge.respondPermission(r);throw Object.assign(new Error(`unsupported Orcha runtime method: ${t}`),{code:"METHOD_NOT_FOUND"})}sendUpdate(t,r){this.send({type:"orcha.runtime.event",requestId:t,eventType:"runtime.update",payload:r})}send(t,r=this.ws){return!r||r!==this.ws||r.readyState!==it?!1:(r.send(JSON.stringify(t)),!0)}};import{existsSync as Sn,readFileSync as Ko}from"node:fs";import{dirname as Go,resolve as Jt}from"node:path";import{fileURLToPath as zo}from"node:url";var Vo=/^[A-Za-z_][A-Za-z0-9_]*$/;function En(e=process.env,t=process.cwd()){let r=a(e.ORCHA_RUNTIME_ENV_FILE),n=r?Jt(t,r):Jt(t,".env");if(!Sn(n))return r&&h("warn","config","runtime env file not found",{path:n}),{loaded:!1,path:n,keys:[]};let s=[],i=Ko(n,"utf8");for(let o of i.split(/\r?\n/)){let c=Xo(o);if(!c)continue;let[l,d]=c;Object.prototype.hasOwnProperty.call(e,l)||(e[l]=d,s.push(l))}return h("info","config","runtime env file loaded",{path:n,keyCount:s.length}),{loaded:!0,path:n,keys:s}}function On(e=process.env){let t=a(e.ORCHA_RUNTIME_MODE||(e.ORCHA_RUNTIME_ORCHA_URL?"node":"server")),r=a(e.ORCHA_RUNTIME_BRIDGE_HOST||"127.0.0.1"),n=!1,s=Go(zo(import.meta.url)),i=Jt(s,"sandbox","broker.js"),o=Jt(s,"orcha-runtime-sandbox-broker.js"),c=Sn(i)?i:o,l=a(e.ORCHA_RUNTIME_SANDBOX_BROKER_COMMAND);return{mode:t,host:r,port:_(e.ORCHA_RUNTIME_BRIDGE_PORT,5588),token:e.ORCHA_RUNTIME_BRIDGE_TOKEN||"",orchaUrl:a(e.ORCHA_RUNTIME_ORCHA_URL),nodeToken:e.ORCHA_RUNTIME_NODE_TOKEN||e.ORCHA_RUNTIME_BRIDGE_TOKEN||"",nodeId:a(e.ORCHA_RUNTIME_NODE_ID||e.HOSTNAME||"local-runtime-node"),nodeName:a(e.ORCHA_RUNTIME_NODE_NAME||e.ORCHA_RUNTIME_NODE_ID||e.HOSTNAME||"Local Runtime Node"),reconnectMs:_(e.ORCHA_RUNTIME_RECONNECT_MS,3e3),connectTimeoutMs:_(e.ORCHA_RUNTIME_CONNECT_TIMEOUT_MS||e.ORCHA_RUNTIME_WS_CONNECT_TIMEOUT_MS,1e4),defaultTargetCode:e.ORCHA_RUNTIME_DEFAULT_TARGET||"echo",requestLimitBytes:_(e.ORCHA_RUNTIME_REQUEST_LIMIT_BYTES,1048576),initializeTimeoutMs:_(e.ORCHA_RUNTIME_INITIALIZE_TIMEOUT_MS,3e4),sessionPromptTimeoutMs:_(e.ORCHA_RUNTIME_SESSION_PROMPT_TIMEOUT_MS,36e5),permissionRequestTimeoutMs:_(e.ORCHA_RUNTIME_PERMISSION_TIMEOUT_MS,3e5),sessionIdleTtlMs:_(e.ORCHA_RUNTIME_SESSION_IDLE_TTL_MS,6e5),sessionCleanupIntervalMs:_(e.ORCHA_RUNTIME_SESSION_CLEANUP_INTERVAL_MS,6e4),maxSessionsPerTarget:_(e.ORCHA_RUNTIME_MAX_SESSIONS_PER_TARGET,8),openClawSessionIdleTtlMs:_(e.ORCHA_RUNTIME_OPENCLAW_SESSION_IDLE_TTL_MS,6e4),openClawMaxSessions:_(e.ORCHA_RUNTIME_OPENCLAW_MAX_SESSIONS,1),heartbeatIntervalMs:_(e.ORCHA_RUNTIME_HEARTBEAT_INTERVAL_MS,15e3),sandboxRequired:n,sandboxBrokerCommand:l||process.execPath,sandboxBrokerArguments:Je(e.ORCHA_RUNTIME_SANDBOX_BROKER_ARGUMENTS,"ORCHA_RUNTIME_SANDBOX_BROKER_ARGUMENTS",l?[]:[c]),sandboxProbeTimeoutMs:_(e.ORCHA_RUNTIME_SANDBOX_PROBE_TIMEOUT_MS,1e4),sandboxTempRoot:a(e.ORCHA_RUNTIME_SANDBOX_TEMP_ROOT),trustedWorkspaceRoots:Je(e.ORCHA_RUNTIME_TRUSTED_WORKSPACE_ROOTS,"ORCHA_RUNTIME_TRUSTED_WORKSPACE_ROOTS"),trustedToolchainRoots:Je(e.ORCHA_RUNTIME_TRUSTED_TOOLCHAIN_ROOTS,"ORCHA_RUNTIME_TRUSTED_TOOLCHAIN_ROOTS"),egressProxyRequired:Jo(e.ORCHA_RUNTIME_EGRESS_PROXY_REQUIRED,t==="node"),egressProxySocket:a(e.ORCHA_RUNTIME_EGRESS_PROXY_SOCKET),egressProxyToken:a(e.ORCHA_RUNTIME_EGRESS_PROXY_TOKEN),egressGrantMaxTtlMs:_(e.ORCHA_RUNTIME_EGRESS_GRANT_MAX_TTL_MS,9e5),targets:Wo(e.ORCHA_RUNTIME_TARGETS_JSON||"")}}function Wo(e){if(!a(e))return{};try{let t=JSON.parse(e);if(u(t))return t}catch(t){h("warn","config","invalid ORCHA_RUNTIME_TARGETS_JSON",{error:String(t)})}return{}}function Jo(e,t){let r=a(e).toLowerCase();if(!r)return t;if(["true","1","yes","on"].includes(r))return!0;if(["false","0","no","off"].includes(r))return!1;throw new Error(`invalid boolean configuration value: ${r}`)}function Je(e,t,r=[]){let n=a(e);if(!n)return[...r];let s;try{s=JSON.parse(n)}catch{throw new Error(`${t} must be a JSON string array`)}if(!Array.isArray(s)||s.some(i=>typeof i!="string"))throw new Error(`${t} must be a JSON string array`);return s.map(i=>i.trim()).filter(Boolean)}function Xo(e){let t=e.trim();if(!t||t.startsWith("#"))return null;let r=t.startsWith("export ")?t.slice(7).trimStart():t,n=r.indexOf("=");if(n<=0)return null;let s=r.slice(0,n).trim();if(!Vo.test(s))return null;let i=Yo(r.slice(n+1).trim());return[s,i]}function Yo(e){if(!e)return"";let t=e[0];if((t==='"'||t==="'")&&e.endsWith(t)){let r=e.slice(1,-1);return t==='"'?Zo(r):r}return Qo(e).trim()}function Zo(e){return e.replaceAll("\\n",`
|
|
18
|
+
`)}];return this.prompt({...t,agentId:n,sessionId:o,prompt:p,metadata:So(t,f)},r)}async requestPermission({agent:t,runtimeSessionId:r,request:n,emitUpdate:s}){let i=Kt(),c=this.runtimeSessionIndex.get(`${t.agentId}:${r}`)?.sessionId||r||Kt(),l={permissionId:i,agentId:t.agentId,sessionId:c,runtimeSessionId:r,request:u(n)?n:{},status:"pending",createdAt:dt()};return s?.({sessionId:r,update:{sessionUpdate:"permission_request",permission:l}}),await new Promise(d=>{let f=_(n?.timeoutMs,this.config.permissionRequestTimeoutMs),p=setTimeout(()=>{this.pendingPermissions.delete(i),d({permissionId:i,outcome:"denied",response:{reason:"permission request timed out"}})},f);this.pendingPermissions.set(i,{timer:p,resolve:d,permission:l})})}async respondPermission(t){let r=a(t.permissionId),n=this.pendingPermissions.get(r),s=a(t.outcome||"approved")||"approved";return n?(clearTimeout(n.timer),this.pendingPermissions.delete(r),n.resolve({permissionId:r,outcome:s,response:u(t.response)?t.response:{},userId:a(t.userId),metadata:u(t.metadata)?t.metadata:{}}),{accepted:!0,permissionId:r,outcome:s}):{accepted:!1,permissionId:r,outcome:s}}health(){return{status:this.config.sandboxRequired&&!this.sandboxCapabilities.dispatchable?"unavailable":"ok",bridgeVersion:Q,startedAt:this.startedAt,agents:[...this.agents.values()].map(t=>({agentId:t.agentId,targetCode:t.targetCode,framework:t.framework,runtimeKind:t.runtimeKind})),sessions:this.sessions.size,pendingPermissions:this.pendingPermissions.size,targets:Object.keys(this.targets),sandboxCapabilities:this.sandboxCapabilities}}};import Ho from"node:http";import $o from"node:https";import{randomBytes as wn}from"node:crypto";var it=1,J=3,Fo=1e4,Vt=class{constructor(t,r={}){this.url=t,this.readyState=0,this.socket=null,this.request=null,this.buffer=Buffer.alloc(0),this.listeners=new Map,this.connectTimeoutMs=Bo(r.connectTimeoutMs,Fo),this.connectTimer=null,this.connect()}addEventListener(t,r){let n=this.listeners.get(t)||new Set;n.add(r),this.listeners.set(t,n)}emit(t,r={}){let n=this.listeners.get(t);if(n)for(let s of n)s(r)}connect(){let t=new URL(this.url),r=t.protocol==="wss:"?$o:Ho,n=wn(16).toString("base64"),s=r.request({protocol:t.protocol==="wss:"?"https:":"http:",hostname:t.hostname,port:t.port||(t.protocol==="wss:"?443:80),path:`${t.pathname}${t.search}`,method:"GET",headers:{Connection:"Upgrade",Upgrade:"websocket","Sec-WebSocket-Key":n,"Sec-WebSocket-Version":"13"}});this.request=s,this.startConnectTimer(s),s.on("upgrade",(i,o,c)=>{if(this.clearConnectTimer(),this.readyState===J){o.destroy();return}this.socket=o,this.readyState=it,o.on("data",l=>this.onData(l)),o.on("close",()=>this.onClose()),o.on("error",l=>{this.readyState!==J&&this.emit("error",{error:l,message:l.message,type:"error"}),this.onClose()}),c?.length&&this.onData(c),this.emit("open")}),s.on("response",i=>{this.clearConnectTimer(),this.emit("error",{message:`websocket upgrade failed: HTTP ${i.statusCode}`,type:"error"}),i.resume(),this.onClose()}),s.on("error",i=>{this.clearConnectTimer(),this.readyState!==J&&this.emit("error",{error:i,message:i.message,type:"error"}),this.onClose()}),s.end()}startConnectTimer(t){this.connectTimeoutMs<=0||(this.connectTimer=setTimeout(()=>{if(this.readyState===it||this.readyState===J)return;let r=`websocket connect timeout after ${this.connectTimeoutMs}ms`;this.emit("error",{message:r,type:"timeout"}),this.onClose(),t.destroy(new Error(r))},this.connectTimeoutMs),this.connectTimer.unref?.())}clearConnectTimer(){this.connectTimer&&(clearTimeout(this.connectTimer),this.connectTimer=null)}send(t){!this.socket||this.readyState!==it||this.socket.write(Ve(1,Buffer.from(String(t),"utf8")))}close(){if(this.readyState!==J){if(this.clearConnectTimer(),!this.socket){this.request?.destroy(),this.onClose();return}try{this.readyState===it&&this.socket.write(Ve(8,Buffer.alloc(0))),this.socket.end()}catch{this.socket.destroy()}this.onClose()}}onClose(){this.readyState!==J&&(this.clearConnectTimer(),this.readyState=J,this.request=null,this.emit("close"))}onData(t){for(this.buffer=Buffer.concat([this.buffer,t]);this.buffer.length>=2;){let r=this.buffer[0],n=this.buffer[1],s=r&15,i=(n&128)!==0,o=n&127,c=2;if(o===126){if(this.buffer.length<c+2)return;o=this.buffer.readUInt16BE(c),c+=2}else if(o===127){if(this.buffer.length<c+8)return;let f=this.buffer.readUInt32BE(c),p=this.buffer.readUInt32BE(c+4);o=f*2**32+p,c+=8}let l=c;if(i&&(c+=4),this.buffer.length<c+o)return;let d=this.buffer.subarray(c,c+o);if(i){let f=this.buffer.subarray(l,l+4);d=Buffer.from(d.map((p,m)=>p^f[m%4]))}this.buffer=this.buffer.subarray(c+o),s===1?this.emit("message",{data:d.toString("utf8")}):s===8?this.close():s===9&&this.socket?.write(Ve(10,d))}}};function Bo(e,t){let r=Number.parseInt(String(e??""),10);return Number.isFinite(r)&&r>=0?r:t}function Ve(e,t){let r=t.length,n=2;r>=126&&r<=65535?n+=2:r>65535&&(n+=8);let s=wn(4),i=Buffer.alloc(n+4+r);i[0]=128|e;let o=2;r<126?i[1]=128|r:r<=65535?(i[1]=254,i.writeUInt16BE(r,o),o+=2):(i[1]=255,i.writeUInt32BE(Math.floor(r/2**32),o),i.writeUInt32BE(r>>>0,o+4),o+=8),s.copy(i,o),o+=4;for(let c=0;c<r;c+=1)i[o+c]=t[c]^s[c%4];return i}function qo(e){let t=new URL(e);if(t.protocol==="http:")t.protocol="ws:";else if(t.protocol==="https:")t.protocol="wss:";else if(t.protocol!=="ws:"&&t.protocol!=="wss:")throw new Error(`unsupported ORCHA_RUNTIME_ORCHA_URL protocol: ${t.protocol}`);return t.pathname=`${t.pathname.replace(/\/+$/,"")}/api/agent-runtime-bridge/ws`,t.search="",t.toString()}function jo(e,t=!0){return Object.entries(e||{}).map(([r,n])=>({targetCode:r,targetName:a(n?.name||n?.targetName||r),targetType:a(n?.type||"echo"),status:t?"available":"unavailable"}))}var We=Object.freeze(["health","agents/create","agents/dispatch","sessions/prompt","sessions/policy","sessions/cancel","permissions/respond"]),Wt=class{constructor(t,r){this.config=t,this.bridge=r,this.ws=null,this.stopped=!1,this.connected=!1,this.reconnectTimer=null,this.heartbeatTimer=null,this.capacityHeartbeatTimer=null,this.bridge.onCapacityChanged=()=>this.scheduleCapacityHeartbeat()}sandboxCapabilities(){return this.bridge.sandboxCapabilities||{dispatchable:this.config.sandboxRequired!==!0,enforced:!1,backend:"development_direct",daemonStatus:"development_only",policySchemaVersions:[1],runtimePolicyUpdates:!0,workspaceSync:!1,egressProxy:!1}}runtimeTargets(){let t=this.sandboxCapabilities().dispatchable===!0;return typeof this.bridge.targetCapacitySnapshot=="function"?this.bridge.targetCapacitySnapshot(t):jo(this.config.targets,t)}start(){this.connect()}stop(){this.stopped=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null,this.capacityHeartbeatTimer&&clearTimeout(this.capacityHeartbeatTimer),this.capacityHeartbeatTimer=null,this.bridge.onCapacityChanged=null,this.ws?.close()}connect(){if(this.stopped)return;let t=qo(this.config.orchaUrl),r=new Vt(t,{connectTimeoutMs:this.config.connectTimeoutMs});this.ws=r,r.addEventListener("open",()=>{if(this.ws!==r||this.stopped){r.close();return}this.authenticate(r)}),r.addEventListener("message",n=>this.handleMessage(n.data,r)),r.addEventListener("close",()=>this.scheduleReconnect("close",r)),r.addEventListener("error",n=>{h("warn","orcha-client","runtime node websocket error",{error:String(n?.message||n?.type||n)})})}authenticate(t=this.ws){this.send({type:"runtime_node.authenticate",token:this.config.nodeToken,nodeId:this.config.nodeId,nodeName:this.config.nodeName,version:Q,protocolVersion:"orcha-runtime-node.v2",defaultTargetCode:this.config.defaultTargetCode,supportedMethods:We,sandboxCapabilities:this.sandboxCapabilities(),targets:this.runtimeTargets()},t)}scheduleReconnect(t,r=this.ws){r&&this.ws!==r||(this.connected=!1,this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null,this.capacityHeartbeatTimer&&clearTimeout(this.capacityHeartbeatTimer),this.capacityHeartbeatTimer=null,r&&this.ws===r&&(this.ws=null),!this.stopped&&(this.reconnectTimer||(h("info","orcha-client","runtime node disconnected; reconnect scheduled",{reason:t,reconnectMs:this.config.reconnectMs}),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},this.config.reconnectMs))))}async handleMessage(t,r=this.ws){if(r&&this.ws!==r)return;let n;try{n=JSON.parse(String(t))}catch(s){h("warn","orcha-client","invalid Orcha websocket frame",{error:String(s)});return}if(u(n)){if(n.type==="runtime_node.authenticated"){if(r&&this.ws!==r)return;this.connected=!0,this.startHeartbeat(r),h("info","orcha-client","runtime node authenticated",{nodeId:this.config.nodeId,connectionId:n.connectionId});return}if(n.type==="orcha.runtime.request"){await this.handleRequest(n);return}n.type==="runtime_node.ping"&&this.send({type:"runtime_node.pong",ts:new Date().toISOString(),supportedMethods:We,sandboxCapabilities:this.sandboxCapabilities(),targets:this.runtimeTargets()})}}startHeartbeat(t){this.heartbeatTimer&&clearInterval(this.heartbeatTimer);let r=Math.max(1e3,Number(this.config.heartbeatIntervalMs||15e3)),n=()=>this.sendCapacityHeartbeat(t);n(),this.heartbeatTimer=setInterval(n,r),this.heartbeatTimer.unref?.()}scheduleCapacityHeartbeat(){if(!this.connected||this.capacityHeartbeatTimer)return;let t=Math.max(25,Math.min(1e3,Number(this.config.capacityHeartbeatDebounceMs||100)));this.capacityHeartbeatTimer=setTimeout(()=>{this.capacityHeartbeatTimer=null,this.sendCapacityHeartbeat()},t),this.capacityHeartbeatTimer.unref?.()}sendCapacityHeartbeat(t=this.ws){return this.connected?this.send({type:"runtime_node.heartbeat",ts:new Date().toISOString(),supportedMethods:We,sandboxCapabilities:this.sandboxCapabilities(),targets:this.runtimeTargets()},t):!1}async handleRequest(t){let r=a(t.id),n=a(t.method),s=u(t.params)?t.params:{};try{let i=await this.invoke(n,s,r);this.send({type:"orcha.runtime.response",id:r,ok:!0,result:i})}catch(i){this.send({type:"orcha.runtime.response",id:r,ok:!1,error:{code:i.code||"RUNTIME_NODE_ERROR",message:i.message||String(i),...i.detail===void 0?{}:{detail:i.detail}}})}}async invoke(t,r,n){if(t==="health")return this.bridge.health();if(t==="agents/create")return this.bridge.createAgent(r);if(t==="agents/dispatch")return this.bridge.dispatch(r,{onUpdate:s=>this.sendUpdate(n,s)});if(t==="sessions/prompt")return this.bridge.prompt(r,{onUpdate:s=>this.sendUpdate(n,s)});if(t==="sessions/policy")return this.bridge.updatePolicy(r);if(t==="sessions/cancel")return this.bridge.cancel(r);if(t==="permissions/respond")return this.bridge.respondPermission(r);throw Object.assign(new Error(`unsupported Orcha runtime method: ${t}`),{code:"METHOD_NOT_FOUND"})}sendUpdate(t,r){this.send({type:"orcha.runtime.event",requestId:t,eventType:"runtime.update",payload:r})}send(t,r=this.ws){return!r||r!==this.ws||r.readyState!==it?!1:(r.send(JSON.stringify(t)),!0)}};import{existsSync as Sn,readFileSync as Ko}from"node:fs";import{dirname as Go,resolve as Jt}from"node:path";import{fileURLToPath as zo}from"node:url";var Vo=/^[A-Za-z_][A-Za-z0-9_]*$/;function En(e=process.env,t=process.cwd()){let r=a(e.ORCHA_RUNTIME_ENV_FILE),n=r?Jt(t,r):Jt(t,".env");if(!Sn(n))return r&&h("warn","config","runtime env file not found",{path:n}),{loaded:!1,path:n,keys:[]};let s=[],i=Ko(n,"utf8");for(let o of i.split(/\r?\n/)){let c=Xo(o);if(!c)continue;let[l,d]=c;Object.prototype.hasOwnProperty.call(e,l)||(e[l]=d,s.push(l))}return h("info","config","runtime env file loaded",{path:n,keyCount:s.length}),{loaded:!0,path:n,keys:s}}function On(e=process.env){let t=a(e.ORCHA_RUNTIME_MODE||(e.ORCHA_RUNTIME_ORCHA_URL?"node":"server")),r=a(e.ORCHA_RUNTIME_BRIDGE_HOST||"127.0.0.1"),n=!1,s=Go(zo(import.meta.url)),i=Jt(s,"sandbox","broker.js"),o=Jt(s,"orcha-runtime-sandbox-broker.js"),c=Sn(i)?i:o,l=a(e.ORCHA_RUNTIME_SANDBOX_BROKER_COMMAND);return{mode:t,host:r,port:_(e.ORCHA_RUNTIME_BRIDGE_PORT,5588),token:e.ORCHA_RUNTIME_BRIDGE_TOKEN||"",orchaUrl:a(e.ORCHA_RUNTIME_ORCHA_URL),nodeToken:e.ORCHA_RUNTIME_NODE_TOKEN||e.ORCHA_RUNTIME_BRIDGE_TOKEN||"",nodeId:a(e.ORCHA_RUNTIME_NODE_ID||e.HOSTNAME||"local-runtime-node"),nodeName:a(e.ORCHA_RUNTIME_NODE_NAME||e.ORCHA_RUNTIME_NODE_ID||e.HOSTNAME||"Local Runtime Node"),reconnectMs:_(e.ORCHA_RUNTIME_RECONNECT_MS,3e3),connectTimeoutMs:_(e.ORCHA_RUNTIME_CONNECT_TIMEOUT_MS||e.ORCHA_RUNTIME_WS_CONNECT_TIMEOUT_MS,1e4),defaultTargetCode:e.ORCHA_RUNTIME_DEFAULT_TARGET||"echo",requestLimitBytes:_(e.ORCHA_RUNTIME_REQUEST_LIMIT_BYTES,1048576),initializeTimeoutMs:_(e.ORCHA_RUNTIME_INITIALIZE_TIMEOUT_MS,3e4),sessionPromptTimeoutMs:_(e.ORCHA_RUNTIME_SESSION_PROMPT_TIMEOUT_MS,36e5),permissionRequestTimeoutMs:_(e.ORCHA_RUNTIME_PERMISSION_TIMEOUT_MS,3e5),sessionIdleTtlMs:_(e.ORCHA_RUNTIME_SESSION_IDLE_TTL_MS,6e5),sessionCleanupIntervalMs:_(e.ORCHA_RUNTIME_SESSION_CLEANUP_INTERVAL_MS,6e4),maxSessionsPerTarget:_(e.ORCHA_RUNTIME_MAX_SESSIONS_PER_TARGET,8),openClawSessionIdleTtlMs:_(e.ORCHA_RUNTIME_OPENCLAW_SESSION_IDLE_TTL_MS,6e4),openClawMaxSessions:_(e.ORCHA_RUNTIME_OPENCLAW_MAX_SESSIONS,1),heartbeatIntervalMs:_(e.ORCHA_RUNTIME_HEARTBEAT_INTERVAL_MS,15e3),sandboxRequired:n,sandboxBrokerCommand:l||process.execPath,sandboxBrokerArguments:Je(e.ORCHA_RUNTIME_SANDBOX_BROKER_ARGUMENTS,"ORCHA_RUNTIME_SANDBOX_BROKER_ARGUMENTS",l?[]:[c]),sandboxProbeTimeoutMs:_(e.ORCHA_RUNTIME_SANDBOX_PROBE_TIMEOUT_MS,1e4),sandboxTempRoot:a(e.ORCHA_RUNTIME_SANDBOX_TEMP_ROOT),trustedWorkspaceRoots:Je(e.ORCHA_RUNTIME_TRUSTED_WORKSPACE_ROOTS,"ORCHA_RUNTIME_TRUSTED_WORKSPACE_ROOTS"),trustedToolchainRoots:Je(e.ORCHA_RUNTIME_TRUSTED_TOOLCHAIN_ROOTS,"ORCHA_RUNTIME_TRUSTED_TOOLCHAIN_ROOTS"),egressProxyRequired:Jo(e.ORCHA_RUNTIME_EGRESS_PROXY_REQUIRED,t==="node"),egressProxySocket:a(e.ORCHA_RUNTIME_EGRESS_PROXY_SOCKET),egressProxyToken:a(e.ORCHA_RUNTIME_EGRESS_PROXY_TOKEN),egressGrantMaxTtlMs:_(e.ORCHA_RUNTIME_EGRESS_GRANT_MAX_TTL_MS,9e5),targets:Wo(e.ORCHA_RUNTIME_TARGETS_JSON||"")}}function Wo(e){if(!a(e))return{};try{let t=JSON.parse(e);if(u(t))return t}catch(t){h("warn","config","invalid ORCHA_RUNTIME_TARGETS_JSON",{error:String(t)})}return{}}function Jo(e,t){let r=a(e).toLowerCase();if(!r)return t;if(["true","1","yes","on"].includes(r))return!0;if(["false","0","no","off"].includes(r))return!1;throw new Error(`invalid boolean configuration value: ${r}`)}function Je(e,t,r=[]){let n=a(e);if(!n)return[...r];let s;try{s=JSON.parse(n)}catch{throw new Error(`${t} must be a JSON string array`)}if(!Array.isArray(s)||s.some(i=>typeof i!="string"))throw new Error(`${t} must be a JSON string array`);return s.map(i=>i.trim()).filter(Boolean)}function Xo(e){let t=e.trim();if(!t||t.startsWith("#"))return null;let r=t.startsWith("export ")?t.slice(7).trimStart():t,n=r.indexOf("=");if(n<=0)return null;let s=r.slice(0,n).trim();if(!Vo.test(s))return null;let i=Yo(r.slice(n+1).trim());return[s,i]}function Yo(e){if(!e)return"";let t=e[0];if((t==='"'||t==="'")&&e.endsWith(t)){let r=e.slice(1,-1);return t==='"'?Zo(r):r}return Qo(e).trim()}function Zo(e){return e.replaceAll("\\n",`
|
|
19
19
|
`).replaceAll("\\r","\r").replaceAll("\\t"," ").replaceAll('\\"','"').replaceAll("\\\\","\\")}function Qo(e){let t=!1,r=!1;for(let n=0;n<e.length;n+=1){let s=e[n],i=e[n-1];if(s==="'"&&!r)t=!t;else if(s==='"'&&!t&&i!=="\\")r=!r;else if(s==="#"&&!t&&!r&&/\s/.test(i||""))return e.slice(0,n)}return e}import{createServer as ta}from"node:http";function Xt(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"content-type":"application/json; charset=utf-8","content-length":Buffer.byteLength(n)}),e.end(n)}function X(e={}){return{ok:!0,...e}}function Xe(e,t,r){return{ok:!1,error:{code:e,message:t,...r===void 0?{}:{detail:r}}}}async function In(e,t){let r=[],n=0;for await(let i of e){if(n+=i.length,n>t)throw Object.assign(new Error("request body too large"),{status:413,code:"REQUEST_TOO_LARGE"});r.push(i)}if(r.length===0)return{};let s=Buffer.concat(r).toString("utf8");if(!s.trim())return{};try{let i=JSON.parse(s);if(!u(i))throw Object.assign(new Error("JSON body must be an object"),{status:400,code:"BAD_JSON"});return i}catch(i){throw i.status?i:Object.assign(new Error(`invalid JSON body: ${i.message}`),{status:400,code:"BAD_JSON"})}}function xn(e,t){if(!t)return;if((e.headers.authorization||"")!==`Bearer ${t}`)throw Object.assign(new Error("runtime bridge token is invalid"),{status:401,code:"UNAUTHORIZED"})}function Cn(e,t){let r={"GET /health":async()=>X(t.health()),"POST /agents/create":async n=>X(await t.createAgent(n)),"POST /agents/dispatch":async n=>X(await t.dispatch(n)),"POST /sessions/prompt":async n=>X(await t.prompt(n)),"POST /sessions/cancel":async n=>X(await t.cancel(n)),"POST /permissions/respond":async n=>X(await t.respondPermission(n))};return ta(async(n,s)=>{let i=new URL(n.url||"/",`http://${n.headers.host||`${e.host}:${e.port}`}`),o=`${n.method||"GET"} ${i.pathname}`,c=r[o];if(!c){Xt(s,404,Xe("NOT_FOUND",`No route for ${o}`));return}try{xn(n,e.token);let l=n.method==="GET"?{}:await In(n,e.requestLimitBytes);Xt(s,200,await c(l))}catch(l){let d=l.status||500,f=l.code||"BRIDGE_INTERNAL";Xt(s,d,Xe(f,l.message||String(l),l.detail))}})}var ca=aa(import.meta.url),ua=".orcha-runtime-bridge.pid",la=".orcha-runtime-bridge.log",da=3,fa=36e5,{command:pa,options:vn}=_a(process.argv.slice(2));Ta(vn);En();var ma=On();await ha(pa,ma,vn);async function ha(e,t,r){switch(e){case"run":case"foreground":await An(t);return;case"start":if(r.foreground){await An(t);return}Mn();return;case"reload":case"restart":await Un({quiet:!0}),Mn();return;case"stop":await Un();return;case"status":ga();return;case"help":case"--help":case"-h":Sa();return;default:throw new Error(`Unknown command: ${e}`)}}async function An(e){ya();let t=new zt(e);if(await t.start(),e.mode==="server"){let n=Cn(e,t);Nn({bridge:t,server:n}),n.listen(e.port,e.host,()=>{h("info","runtime-bridge","Orcha runtime bridge HTTP server started",{host:e.host,port:e.port,targets:Object.keys(t.targets)})});return}if(!e.orchaUrl)throw new Error("ORCHA_RUNTIME_ORCHA_URL is required in runtime node mode");let r=new Wt(e,t);Nn({bridge:t,client:r}),r.start(),h("info","runtime-bridge","Orcha runtime node started",{nodeId:e.nodeId,nodeName:e.nodeName,orchaUrl:e.orchaUrl,targets:Object.keys(t.targets)})}function Nn({bridge:e,client:t,server:r}){let n=!1,s=i=>{if(n)return;n=!0;let o=Number(e?.sessions?.size||0)>0;h("info","runtime-bridge","runtime bridge shutting down",{signal:i});try{t?.stop?.()}catch(c){h("warn","runtime-bridge","runtime client stop failed",{error:String(c)})}Promise.resolve(e?.stop?.(`process_${String(i||"shutdown").toLowerCase()}`)).catch(c=>{h("warn","runtime-bridge","runtime bridge stop failed",{error:String(c)})}).finally(()=>{try{r?.close?.()}catch(c){h("warn","runtime-bridge","runtime server close failed",{error:String(c)})}}),setTimeout(()=>process.exit(0),o?8500:200)};process.once("SIGTERM",()=>s("SIGTERM")),process.once("SIGINT",()=>s("SIGINT"))}function Mn(){let e=er(),t=Hn(),r=rr(e);if(r&&ot(r)){console.log(JSON.stringify({status:"already_running",pid:r,pidFile:e,logFile:t}));return}r&&Qe(e),kn(e),kn(t),Ze(t);let n=sa(t,"a"),s={...process.env,ORCHA_RUNTIME_PID_FILE:e,ORCHA_RUNTIME_LOG_FILE:t},i=ea(process.execPath,[ca,"run"],{cwd:process.cwd(),detached:!0,env:s,stdio:["ignore",n,n]});i.unref(),ra(n),Dn(e,`${i.pid}
|
|
20
20
|
`),console.log(JSON.stringify({status:"started",pid:i.pid,pidFile:e,logFile:t}))}async function Un({quiet:e=!1}={}){let t=er(),r=rr(t);if(!r){e||console.log(JSON.stringify({status:"not_running",pidFile:t}));return}if(!ot(r)){Qe(t),e||console.log(JSON.stringify({status:"not_running",pid:r,pidFile:t}));return}process.kill(r,"SIGTERM"),!await Pn(r,1e4)&&ot(r)&&(process.kill(r,"SIGKILL"),await Pn(r,3e3)),Qe(t),e||console.log(JSON.stringify({status:"stopped",pid:r,pidFile:t}))}function ga(){let e=er(),t=Hn(),r=rr(e),n=!!(r&&ot(r));console.log(JSON.stringify({status:n?"running":"not_running",running:n,pid:n?r:null,pidFile:e,logFile:t}))}function _a(e){let t=[],r={};for(let s=0;s<e.length;s+=1){let i=e[s];i==="--daemon"?r.daemon=!0:i==="--foreground"?r.foreground=!0:i==="--env-file"?r.envFile=e[++s]:i==="--pid-file"?r.pidFile=e[++s]:i==="--log-file"?r.logFile=e[++s]:t.push(i)}return{command:t[0]||"run",options:r}}function Ta(e){e.envFile&&(process.env.ORCHA_RUNTIME_ENV_FILE=e.envFile),e.pidFile&&(process.env.ORCHA_RUNTIME_PID_FILE=e.pidFile),e.logFile&&(process.env.ORCHA_RUNTIME_LOG_FILE=e.logFile)}function er(){return tr(process.cwd(),process.env.ORCHA_RUNTIME_PID_FILE||ua)}function Hn(){return tr(process.cwd(),process.env.ORCHA_RUNTIME_LOG_FILE||la)}function ya(){let e=process.env.ORCHA_RUNTIME_LOG_FILE;if(!e)return;let t=$n();if(t<=0)return;let r=tr(process.cwd(),e);Ze(r,t);let n=wa();n<=0||setInterval(()=>Ze(r,t),n).unref()}function Ze(e,t=$n()){if(t<=0||!Ln(e))return;let r=0,n="";try{if(r=bn(e).size,r<=0)return;n=Ye(e,"utf8")}catch(d){h("warn","runtime-bridge","runtime log cleanup skipped",{logFile:e,error:String(d)});return}let s=Date.now()-t*24*60*60*1e3,i=n.split(/\r?\n/),o=[],c=0;for(let d of i)d&&(Ra(d,s)?o.push(d):c+=1);if(c===0)return;let l="";try{bn(e).size>r&&(l=Ye(e,"utf8").slice(n.length));let f=[...o,...l.split(/\r?\n/).filter(Boolean)].join(`
|
|
21
21
|
`);Dn(e,f?`${f}
|