@orcha-ai/runtime-bridge 0.1.0

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/.env.example ADDED
@@ -0,0 +1,17 @@
1
+ # Orcha Runtime Node deployment config.
2
+ # Copy this file to .env and fill the values for the computer running the runtime.
3
+
4
+ ORCHA_RUNTIME_MODE=node
5
+ ORCHA_RUNTIME_ORCHA_URL=https://orcha.example.com
6
+ ORCHA_RUNTIME_NODE_TOKEN=replace-with-agent-runtime-node-service-token
7
+ ORCHA_RUNTIME_NODE_ID=workstation-a
8
+ ORCHA_RUNTIME_NODE_NAME=Workstation A
9
+ ORCHA_RUNTIME_DEFAULT_TARGET=codex
10
+ ORCHA_RUNTIME_RECONNECT_MS=3000
11
+ ORCHA_RUNTIME_SESSION_PROMPT_TIMEOUT_MS=3600000
12
+ ORCHA_RUNTIME_PERMISSION_TIMEOUT_MS=300000
13
+ ORCHA_RUNTIME_PID_FILE=.orcha-runtime-bridge.pid
14
+ ORCHA_RUNTIME_LOG_FILE=.orcha-runtime-bridge.log
15
+
16
+ # Target examples. Keep this JSON on one line.
17
+ ORCHA_RUNTIME_TARGETS_JSON='{"codex":{"type":"cli","command":"codex","args":["exec","--json"],"promptMode":"stdin","outputMode":"json-lines","captureLastMessage":true},"openclaw":{"type":"openclaw","command":"openclaw"},"claude":{"type":"cli","command":"claude","args":["-p","--output-format","json","--no-session-persistence"],"promptMode":"args","outputMode":"json-lines"}}'
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # Orcha Runtime Bridge
2
+
3
+ Runtime Node package that keeps Codex, OpenClaw, Claude Code, and other
4
+ agent runtimes outside the Python API process.
5
+
6
+ The bridge owns Orcha's first-party ACP adapter. It does not depend on a
7
+ third-party ACP package: JSON-RPC framing, request ids, notifications,
8
+ runtime permission requests, and process lifecycle are implemented under
9
+ `src/acp/`.
10
+
11
+ In production the Runtime Node actively connects to Orcha over WebSocket. The
12
+ computer running Codex/OpenClaw/Claude does not need to expose an inbound port.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install -g @orcha-ai/runtime-bridge
18
+ ```
19
+
20
+ Run it with:
21
+
22
+ ```bash
23
+ orcha-runtime-bridge
24
+ ```
25
+
26
+ You can also run without a global install:
27
+
28
+ ```bash
29
+ npx @orcha-ai/runtime-bridge
30
+ ```
31
+
32
+ ## Build And Pack
33
+
34
+ The bridge is plain Node.js ESM. The build step bundles and minifies the runtime
35
+ CLI into `bin/orcha-runtime-bridge.js`, then prepares a clean release directory.
36
+
37
+ ```bash
38
+ npm run build
39
+ npm run pack:local
40
+ ```
41
+
42
+ `npm run build` writes `dist/package`. `npm run pack:local` creates the local
43
+ npm tarball under `dist/`. The release package includes the minified `bin/`
44
+ runtime, `README.md`, and `.env.example`; it does not publish `src/`, build
45
+ scripts, test scripts, or the local `.env` file.
46
+
47
+ ## Configure
48
+
49
+ ```bash
50
+ cp .env.example .env
51
+ # Edit .env and fill ORCHA_RUNTIME_ORCHA_URL / ORCHA_RUNTIME_NODE_TOKEN / targets.
52
+ orcha-runtime-bridge
53
+ ```
54
+
55
+ ## Background Process
56
+
57
+ The CLI has a small built-in process manager. It does not require pm2,
58
+ forever, or any third-party package.
59
+
60
+ ```bash
61
+ # Start in the background.
62
+ orcha-runtime-bridge start --env-file /etc/orcha/runtime-node.env
63
+
64
+ # Check status.
65
+ orcha-runtime-bridge status --env-file /etc/orcha/runtime-node.env
66
+
67
+ # Reload after editing the env file or upgrading the package.
68
+ orcha-runtime-bridge reload --env-file /etc/orcha/runtime-node.env
69
+
70
+ # Stop.
71
+ orcha-runtime-bridge stop --env-file /etc/orcha/runtime-node.env
72
+ ```
73
+
74
+ `start` writes the process id to `ORCHA_RUNTIME_PID_FILE` and redirects stdout
75
+ and stderr to `ORCHA_RUNTIME_LOG_FILE`. Both paths can be set in the env file or
76
+ overridden on the command line:
77
+
78
+ ```bash
79
+ orcha-runtime-bridge start \
80
+ --env-file /etc/orcha/runtime-node.env \
81
+ --pid-file /var/run/orcha-runtime-bridge.pid \
82
+ --log-file /var/log/orcha-runtime-bridge.log
83
+ ```
84
+
85
+ Running `orcha-runtime-bridge` with no command still runs in the foreground,
86
+ which is the right mode for systemd, Docker, launchd, and supervised services.
87
+
88
+ The bridge loads environment variables from `ORCHA_RUNTIME_ENV_FILE` when it is
89
+ set. Otherwise it reads `.env` from the current working directory. Real process
90
+ environment variables always win over values from the file.
91
+
92
+ The node connects to:
93
+
94
+ - `WS /api/agent-runtime-bridge/ws`
95
+
96
+ and receives Orcha RPC frames for:
97
+
98
+ - `agents/create`
99
+ - `agents/dispatch`
100
+ - `sessions/prompt`
101
+ - `sessions/cancel`
102
+ - `permissions/respond`
103
+
104
+ Runtime targets are configured with `ORCHA_RUNTIME_TARGETS_JSON`.
105
+
106
+ ```json
107
+ {
108
+ "codex": {
109
+ "type": "cli",
110
+ "command": "codex",
111
+ "args": ["exec", "--json"],
112
+ "promptMode": "stdin",
113
+ "outputMode": "json-lines"
114
+ },
115
+ "openclaw": {
116
+ "type": "openclaw",
117
+ "command": "openclaw"
118
+ },
119
+ "custom-acp": {
120
+ "type": "stdio-acp",
121
+ "command": "node",
122
+ "args": ["/path/to/runtime.js"],
123
+ "framing": "line"
124
+ }
125
+ }
126
+ ```
127
+
128
+ If a target is missing, the bridge uses the built-in `echo` adapter so the
129
+ protocol can be verified without starting a real agent runtime.
130
+
131
+ Target types:
132
+
133
+ - `stdio-acp`: spawn a runtime process and speak Orcha ACP over stdio JSON-RPC.
134
+ - `openclaw`: built-in `openclaw acp --session ...` command adapter.
135
+ - `cli`: run an independent CLI per prompt and wrap stdout as session updates.
136
+ - `echo`: local test adapter.
137
+
138
+ Supported stdio framing:
139
+
140
+ - `line`: one JSON-RPC frame per line.
141
+ - `content-length`: `Content-Length: N` headers, compatible with LSP-style stdio transports.
142
+
143
+ Local HTTP server mode is only for development smoke tests:
144
+
145
+ ```bash
146
+ ORCHA_RUNTIME_MODE=server npm start
147
+ ```
148
+
149
+ For systemd or Docker deployments, point `ORCHA_RUNTIME_ENV_FILE` at the file
150
+ managed by the host:
151
+
152
+ ```bash
153
+ ORCHA_RUNTIME_ENV_FILE=/etc/orcha/runtime-node.env npm start
154
+ ```
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import{spawn as re}from"node:child_process";import{closeSync as ie,existsSync as oe,mkdirSync as ae,openSync as ce,readFileSync as de,rmSync as ue,writeFileSync as le}from"node:fs";import{dirname as he,resolve as gt}from"node:path";import{fileURLToPath as pe}from"node:url";import{randomUUID as $}from"node:crypto";var M="0.1.0";function R(){return new Date().toISOString()}function d(s){return s!==null&&typeof s=="object"&&!Array.isArray(s)}function o(s){return String(s??"").trim()}function g(s,t){let e=Number.parseInt(String(s??""),10);return Number.isFinite(e)?e:t}function k(s){return Array.isArray(s)?s.map(String):[]}function h(s,t,e,n={}){let r={ts:R(),level:s,module:t,msg:e,...d(n)?n:{}};console.error(JSON.stringify(r))}function P(s){return Array.isArray(s)?s.map(t=>d(t)?t.type==="text"?o(t.text):t.type==="file"?o(t.uri):t.type==="image"?o(t.uri):"":"").filter(Boolean).join(`
3
+ `):""}var C=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,e){let n=P(t.prompt);return e({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 yt}from"node:child_process";var N="2.0",Tt=3e4;function St(s){return{code:Number.isInteger(s?.code)?s.code:-32e3,message:o(s?.message)||String(s),data:d(s?.data)?s.data:void 0}}function Rt(s){return d(s)&&"id"in s&&!("method"in s)}function Ot(s){return d(s)&&typeof s.method=="string"&&"id"in s}function xt(s){return d(s)&&typeof s.method=="string"&&!("id"in s)}var L=class{constructor({command:t,args:e=[],cwd:n,env:r,label:i,framing:a="line"}){this.command=t,this.args=Array.isArray(e)?e.map(String):[],this.cwd=n||process.cwd(),this.env={...process.env,...d(r)?r:{}},this.label=i||t,this.framing=a==="content-length"?"content-length":"line",this.child=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:e={}}={}){this.child&&!this.child.killed||(this.child=yt(this.command,this.args,{cwd:this.cwd,env:this.env,stdio:["pipe","pipe","pipe"]}),this.child.stdout.on("data",n=>this.onStdout(n)),this.child.stderr.setEncoding("utf8"),this.child.stderr.on("data",n=>{let r=n.trimEnd();r&&h("debug","runtime.stderr","runtime stderr",{target:this.label,text:r})}),this.child.on("exit",(n,r)=>this.handleExit(n,r)),this.child.on("error",n=>this.rejectAll(n)),t&&await this.call("initialize",{protocolVersion:1,clientCapabilities:{},...e}).catch(n=>{throw Object.assign(new Error(`runtime initialize failed: ${n.message}`),{code:"RUNTIME_INITIALIZE_FAILED"})}))}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 e=this.lineBuffer.split(/\r?\n/);this.lineBuffer=e.pop()||"";for(let n of e){let r=n.trim();r&&this.dispatchRaw(r)}}onContentLengthData(t){for(this.headerBuffer=Buffer.concat([this.headerBuffer,t]);this.headerBuffer.length>0;){let e=this.headerBuffer.indexOf(`\r
4
+ \r
5
+ `);if(e<0)return;let r=this.headerBuffer.subarray(0,e).toString("utf8").match(/content-length:\s*(\d+)/i);if(!r){h("warn","runtime.protocol","missing Content-Length header",{target:this.label}),this.headerBuffer=Buffer.alloc(0);return}let i=Number.parseInt(r[1],10),a=e+4,c=a+i;if(this.headerBuffer.length<c)return;let u=this.headerBuffer.subarray(a,c).toString("utf8");this.headerBuffer=this.headerBuffer.subarray(c),this.dispatchRaw(u)}}dispatchRaw(t){let e;try{e=JSON.parse(t)}catch(n){h("warn","runtime.protocol","invalid JSON frame",{target:this.label,error:String(n)});return}this.dispatch(e)}dispatch(t){if(Rt(t)){this.resolveResponse(t);return}if(Ot(t)){this.handleRequest(t);return}xt(t)&&this.handleNotification(t)}resolveResponse(t){let e=String(t.id),n=this.pending.get(e);n&&(clearTimeout(n.timer),this.pending.delete(e),t.error?n.reject(new Error(d(t.error)?String(t.error.message||"runtime error"):String(t.error))):n.resolve(t.result))}async handleRequest(t){let e=this.requestHandlers.get(t.method);if(!e){this.writeFrame({jsonrpc:N,id:t.id,error:{code:-32601,message:`method not found: ${t.method}`}});return}try{let n=await e(d(t.params)?t.params:{},t);this.writeFrame({jsonrpc:N,id:t.id,result:n??{}})}catch(n){this.writeFrame({jsonrpc:N,id:t.id,error:St(n)})}}handleNotification(t){let e=this.notificationHandlers.get(t.method);if(e)for(let n of e)n(d(t.params)?t.params:{},t)}call(t,e={},n=Tt){if(!this.child||!this.child.stdin||this.child.killed)return Promise.reject(new Error("runtime process is not running"));let r=`${t}_${++this.seq}`,i={jsonrpc:N,id:r,method:t,params:e};return new Promise((a,c)=>{let u=setTimeout(()=>{this.pending.delete(r),c(new Error(`${t} timed out after ${n}ms`))},n);this.pending.set(r,{resolve:a,reject:c,timer:u}),this.writeFrame(i,l=>{l&&(clearTimeout(u),this.pending.delete(r),c(l))})})}notify(t,e={}){this.writeFrame({jsonrpc:N,method:t,params:e})}writeFrame(t,e){if(!this.child?.stdin||this.child.killed){e?.(new Error("runtime process is not running"));return}let n=JSON.stringify(t),r=this.framing==="content-length"?`Content-Length: ${Buffer.byteLength(n,"utf8")}\r
6
+ \r
7
+ ${n}`:`${n}
8
+ `;this.child.stdin.write(r,e)}onNotification(t,e){let n=this.notificationHandlers.get(t)||new Set;return n.add(e),this.notificationHandlers.set(t,n),()=>{n.delete(e),n.size===0&&this.notificationHandlers.delete(t)}}onRequest(t,e){return this.requestHandlers.set(t,e),()=>this.requestHandlers.delete(t)}onExit(t){return this.exitHandlers.add(t),()=>this.exitHandlers.delete(t)}rejectAll(t){for(let e of this.pending.values())clearTimeout(e.timer),e.reject(t);this.pending.clear()}handleExit(t,e){this.rejectAll(new Error(`runtime exited before response (${t}/${e})`));for(let n of this.exitHandlers)n(t,e)}stop(t="stop"){!this.child||this.child.killed||(h("info","runtime","stopping runtime",{target:this.label,reason:t}),this.child.kill("SIGTERM"),setTimeout(()=>{this.child&&!this.child.killed&&this.child.kill("SIGKILL")},5e3).unref())}};var O=class{constructor(t,e,n={},r={}){this.agent=t,this.target=e,this.callbacks=n,this.options=r,this.proc=null,this.permissionHandlers=new Map}async ensureStarted(){if(this.proc)return;let t=o(this.target.command);if(!t)throw new Error(`runtime target ${this.agent.targetCode} is missing command`);this.proc=new L({command:t,args:k(this.target.args),cwd:o(this.target.cwd)||this.agent.workspace||process.cwd(),env:d(this.target.env)?this.target.env:{},label:`${this.agent.agentId}:${this.agent.targetCode}`,framing:o(this.target.framing||"line")}),this.proc.onRequest("session/request_permission",e=>this.handlePermissionRequest(e)),this.proc.onRequest("session/requestPermission",e=>this.handlePermissionRequest(e)),await this.proc.start({initialize:this.target.initialize!==!1,initializeParams:{clientInfo:{name:"orcha-runtime-bridge",version:"0.1.0"},...d(this.target.initializeParams)?this.target.initializeParams:{}}})}async sessionNew(t={}){return await this.ensureStarted(),this.proc.call("session/new",t)}async sessionPrompt(t,e){await this.ensureStarted();let n=o(t.sessionId),r=this.proc.onNotification("session/update",a=>{let c=o(a.sessionId);(!c||c===n)&&e(a)}),i=async a=>this.callbacks.onPermissionRequest?.({agent:this.agent,runtimeSessionId:n,request:a,emitUpdate:e})||{outcome:"denied",reason:"permission handler is not configured"};n&&this.permissionHandlers.set(n,i),this.permissionHandlers.set("*",i);try{return await this.proc.call("session/prompt",t,this.options.sessionPromptTimeoutMs)}finally{r(),n&&this.permissionHandlers.delete(n),this.permissionHandlers.delete("*")}}async sessionCancel(t){return await this.ensureStarted(),this.proc.call("session/cancel",t,5e3).catch(()=>({ok:!0}))}async handlePermissionRequest(t){let e=o(t.sessionId),n=this.permissionHandlers.get(e)||this.permissionHandlers.get("*");return n?n(t):{outcome:"denied",reason:"no active Orcha permission handler"}}stop(t){this.proc?.stop(t)}};var v=class extends O{constructor(t,e,n,r={},i={}){let a=o(n).replace(/[^A-Za-z0-9._-]+/g,"-")||"default",c=o(e.command)||"openclaw",u=Array.isArray(e.args)?e.args.map(String):[],l=u.length>0?u:["acp","--session",`agent:${t.agentId}:${a}`];super(t,{...e,command:c,args:l},r,i)}};import{spawn as Nt}from"node:child_process";import{randomUUID as F}from"node:crypto";import{existsSync as Ut,readFileSync as bt,unlinkSync as At}from"node:fs";import{tmpdir as Mt}from"node:os";import{basename as nt,extname as kt,join as Pt}from"node:path";var Ct=36e5,Lt=5e3;function H(s,t){try{s.kill(t)}catch{}}function w(s){if(typeof s=="string")return s;if(Array.isArray(s))return s.map(t=>w(t)).join("");if(!d(s))return"";for(let t of["text","delta","output_text","content","message","output"]){let e=w(s[t]);if(e)return e}return""}function vt(s){if(!d(s))return"";let t=d(s.payload)?s.payload:{};if(o(s.type)==="event_msg"){if(o(t.type)==="agent_message")return o(t.message);if(o(t.type)==="task_complete")return o(t.last_agent_message)}if(o(s.type)==="response_item"&&o(t.type)==="message"&&o(t.role)==="assistant")return w(t.content)||w(t.message);let e=w(s.delta)||w(s.text)||w(s.content);if(e)return e;let n=d(s.item)?s.item:{};return o(n.role)==="assistant"||o(n.type)==="message"?w(n.content)||w(n.text)||w(n.message):""}function Ht(s){let t=kt(o(s)).toLowerCase();return t===".jpg"||t===".jpeg"?"image/jpeg":t===".webp"?"image/webp":t===".gif"?"image/gif":"image/png"}function Ft(s,t){let e=typeof s=="string"?s.trim():"";return e?e.startsWith("data:")?e:`data:${t};base64,${e.replace(/\s+/g,"")}`:""}function Dt(s){if(!d(s))return null;let t=d(s.payload)?s.payload:{},e=o(s.type),n=o(t.type);if(!(e==="event_msg"&&n==="image_generation_end"||e==="response_item"&&n==="image_generation_call"))return null;let r=o(t.call_id||t.id),i=o(t.saved_path||t.savedPath),a=o(t.revised_prompt||t.revisedPrompt),c=Ht(i),l=Ft(t.result,c)||i;if(!l)return null;let f=i?nt(i):`${r||F()}.png`;return{artifactType:"image",type:"image",title:f||"Generated image",summary:a||"Generated image",content:{prompt:a||void 0,imageUrl:l,previewUrl:l,fileUrl:l,mimeType:c},previewUrl:l,fileUrl:l,metadata:{source:"codex_cli_image_generation",eventType:n,callId:r||void 0,savedPath:i||void 0,filename:f,mimeType:c,revisedPrompt:a||void 0}}}function $t(s,t){if(!t)return;let e=d(t.metadata)?t.metadata:{},n=o(e.callId||e.savedPath||t.previewUrl||t.fileUrl);if(!n)return;let r=s.artifacts.get(n);if(!r){s.artifacts.set(n,t);return}r.content={...d(r.content)?r.content:{},...d(t.content)?t.content:{}},r.metadata={...d(r.metadata)?r.metadata:{},...e},r.previewUrl=t.previewUrl||r.previewUrl,r.fileUrl=t.fileUrl||r.fileUrl,r.summary=t.summary||r.summary,r.title=t.title||r.title}function Bt(s){if(!d(s)||!d(s.payload))return d(s)?s:{value:s};let t=o(s.payload.type);if(t!=="image_generation_end"&&t!=="image_generation_call")return s;let e={...s.payload};return typeof e.result=="string"&&e.result&&(e.result="<omitted>",e.resultLength=s.payload.result.length),{...s,payload:e}}function jt(s,t,e){return e.captureLastMessage===!1||t.includes("--output-last-message")||t.includes("-o")?!1:e.captureLastMessage===!0?!0:nt(s)==="codex"}function qt(s){if(!s||!Ut(s))return"";try{return bt(s,"utf8").trim()}catch{return""}finally{try{At(s)}catch{}}}var D=class{constructor(t,e,n={}){this.agent=t,this.target=e,this.options=n,this.active=new Map}async sessionNew(){return{sessionId:`cli-${this.agent.agentId}-${F()}`}}async sessionPrompt(t,e){let n=o(this.target.command);if(!n)throw new Error(`runtime target ${this.agent.targetCode} is missing command`);let r=o(t.sessionId)||F(),i=P(t.prompt),a=o(this.target.promptMode||"stdin"),c=this.buildArgs(a,i),u=jt(n,c,this.target)?Pt(Mt(),`orcha-runtime-last-message-${F()}.txt`):"";u&&c.push("--output-last-message",u);let l=g(this.target.timeoutMs||this.target.sessionPromptTimeoutMs,g(this.options.sessionPromptTimeoutMs,Ct)),f={...process.env,...d(this.target.env)?this.target.env:{},...a==="env"?{ORCHA_RUNTIME_PROMPT:i}:{},ORCHA_AGENT_ID:this.agent.agentId,ORCHA_SESSION_ID:r},p=Nt(n,c,{cwd:o(this.target.cwd)||this.agent.workspace||process.cwd(),env:f,stdio:["pipe","pipe","pipe"]});this.active.set(r,p),h("info","runtime.cli","runtime prompt started",{target:this.agent.targetCode,sessionId:r,pid:p.pid,timeoutMs:l});let I="",_=o(this.target.outputMode||"text"),T={artifacts:new Map,emittedTexts:new Set,value:""};return p.stdout.setEncoding("utf8"),p.stdout.on("data",S=>this.handleStdout(S,_,T,r,e)),p.stderr.setEncoding("utf8"),p.stderr.on("data",S=>{I+=S,this.target.emitStderr===!0&&e({sessionId:r,update:{sessionUpdate:"runtime_stderr_chunk",content:{type:"text",text:S}}})}),a==="stdin"?p.stdin.end(i):p.stdin.end(),await new Promise((S,_t)=>{let U=!1,Y=!1,E=null,X=setTimeout(()=>{Y=!0,h("warn","runtime.cli","runtime prompt timed out; terminating child",{target:this.agent.targetCode,sessionId:r,pid:p.pid,timeoutMs:l}),H(p,"SIGTERM"),E=setTimeout(()=>{h("warn","runtime.cli","runtime prompt force killing child",{target:this.agent.targetCode,sessionId:r,pid:p.pid}),H(p,"SIGKILL")},Lt),E.unref?.(),et(Object.assign(new Error(`runtime CLI timed out after ${l}ms`),{code:"RUNTIME_CLI_TIMEOUT"}))},l);X.unref?.();let tt=()=>{clearTimeout(X),E&&!Y&&clearTimeout(E),this.active.delete(r)},Et=m=>{U||(U=!0,tt(),S(m))},et=m=>{U||(U=!0,tt(),_t(m))};p.on("error",m=>{h("warn","runtime.cli","runtime child error",{target:this.agent.targetCode,sessionId:r,pid:p.pid,error:String(m?.message||m)}),et(m)}),p.on("exit",(m,st)=>{E&&(clearTimeout(E),E=null),_==="json-lines"&&T.value.trim()&&this.handleStdout(`
9
+ `,_,T,r,e);let b=qt(u);b&&!T.emittedTexts.has(b)&&(T.emittedTexts.add(b),e({sessionId:r,update:{sessionUpdate:"agent_message_chunk",content:{type:"text",text:b}}}));let A=I.trim();A&&h("debug","runtime.cli","runtime stderr",{target:this.agent.targetCode,sessionId:r,stderr:A}),h("info","runtime.cli","runtime prompt finished",{target:this.agent.targetCode,sessionId:r,pid:p.pid,exitCode:m,signal:st}),Et({stopReason:m===0?"end_turn":"error",exitCode:m,signal:st,artifacts:[...T.artifacts.values()],...A?{stderr:A}:{}})})})}buildArgs(t,e){let n=k(this.target.args);return t==="args"?[...n,e]:n}handleStdout(t,e,n,r,i){if(e!=="json-lines"){i({sessionId:r,update:{sessionUpdate:"agent_message_chunk",content:{type:"text",text:t}}});return}n.value+=t;let a=n.value.split(/\r?\n/);n.value=a.pop()||"";for(let c of a){let u=c.trim();if(u)try{let l=JSON.parse(u);$t(n,Dt(l)),i({sessionId:r,update:{sessionUpdate:"runtime_event",event:Bt(l)}});let f=vt(l);f&&!n.emittedTexts.has(f)&&(n.emittedTexts.add(f),i({sessionId:r,update:{sessionUpdate:"agent_message_chunk",content:{type:"text",text:f}}}))}catch{i({sessionId:r,update:{sessionUpdate:"agent_message_chunk",content:{type:"text",text:`${c}
10
+ `}}})}}}async sessionCancel(t){let e=o(t.sessionId),n=this.active.get(e);return n?(h("info","runtime.cli","cancelling runtime child",{target:this.agent.targetCode,sessionId:e,pid:n.pid}),H(n,"SIGTERM"),this.active.delete(e),{ok:!0,cancelled:!0}):{ok:!0,cancelled:!1}}stop(t="stop"){for(let[e,n]of this.active.entries())h("info","runtime.cli","stopping runtime child",{target:this.agent.targetCode,sessionId:e,pid:n.pid,reason:t}),H(n,"SIGTERM");this.active.clear()}};function Gt(s,t,e){let n=d(s?._meta)?s._meta:{};return{...d(s)?s:{},sessionId:t,update:d(s?.update)?s.update:{},_meta:{...n,orchaAgentId:e.agentId,runtimeSessionId:e.runtimeSessionId,bridgeUpdateId:$()}}}var B=class{constructor(t){this.config=t,this.targets=t.targets||{},this.agents=new Map,this.sessions=new Map,this.runtimeSessionIndex=new Map,this.pendingPermissions=new Map,this.startedAt=R()}targetFor(t){let e=o(t)||this.config.defaultTargetCode,n=this.targets[e];return{code:e,target:d(n)?n:{type:"echo"}}}async createAgent(t){let e=o(t.agentId);if(!e)throw Object.assign(new Error("agentId is required"),{status:400,code:"BAD_REQUEST"});let{code:n,target:r}=this.targetFor(t.targetCode||t.framework),i={agentId:e,targetCode:n,framework:o(t.framework||n),workspace:o(t.workspace),metadata:d(t.metadata)?t.metadata:{},createdAt:R(),runtimeKind:o(r.type||"echo")};return this.agents.set(e,i),{agent:i}}runtimeFor(t,e){let{target:n}=this.targetFor(t.targetCode),r=o(n.type||"echo"),i={onPermissionRequest:c=>this.requestPermission(c)},a={sessionPromptTimeoutMs:this.config.sessionPromptTimeoutMs};return r==="stdio-acp"||r==="acp"?new O(t,n,i,a):r==="openclaw"?new v(t,n,e,i,a):r==="cli"?new D(t,n,a):new C(t)}async prompt(t,e={}){let n=o(t.agentId),r=o(t.sessionId)||$();if(!n)throw Object.assign(new Error("agentId is required"),{status:400,code:"BAD_REQUEST"});let i=this.agents.get(n)||(await this.createAgent({agentId:n,targetCode:t.targetCode,framework:t.framework,workspace:t.workspace,metadata:t.metadata})).agent,a=o(t.workspace);a&&a!==i.workspace&&(i.workspace=a);let c=`${n}:${r}`,u=this.sessions.get(c);if(!u){let I=this.runtimeFor(i,r),_=await I.sessionNew({cwd:i.workspace||process.cwd(),metadata:d(t.metadata)?t.metadata:{}});u={agentId:n,sessionId:r,runtime:I,runtimeSessionId:o(d(_)?_.sessionId:"")||r,createdAt:R()},this.sessions.set(c,u),this.runtimeSessionIndex.set(`${n}:${u.runtimeSessionId}`,u)}let l=[],f=I=>{let _=Gt(I,r,u);l.push(_),e.onUpdate?.(_)},p=await u.runtime.sessionPrompt({sessionId:u.runtimeSessionId,prompt:Array.isArray(t.prompt)?t.prompt:[],metadata:d(t.metadata)?t.metadata:{}},f);return{sessionId:r,runtimeSessionId:u.runtimeSessionId,result:d(p)?p:{},updates:l}}async cancel(t){let e=o(t.agentId),n=o(t.sessionId),r=this.sessions.get(`${e}:${n}`);return r?(await r.runtime.sessionCancel({sessionId:r.runtimeSessionId}),{cancelled:!0}):{cancelled:!1}}async dispatch(t,e={}){let n=o(t.agentId),r=o(t.taskId),i=o(t.executionId);if(!n||!r)throw Object.assign(new Error("agentId and taskId are required"),{status:400,code:"BAD_REQUEST"});let a=o(t.sessionId)||`dispatch-${i||r}`,c=o(t.instructions),u=[{type:"text",text:["Task dispatch received.",`taskId: ${r}`,i?`executionId: ${i}`:"",c?`instructions: ${c}`:""].filter(Boolean).join(`
11
+ `)}];return this.prompt({...t,agentId:n,sessionId:a,prompt:u},e)}async requestPermission({agent:t,runtimeSessionId:e,request:n,emitUpdate:r}){let i=$(),c=this.runtimeSessionIndex.get(`${t.agentId}:${e}`)?.sessionId||e||$(),u={permissionId:i,agentId:t.agentId,sessionId:c,runtimeSessionId:e,request:d(n)?n:{},status:"pending",createdAt:R()};return r?.({sessionId:e,update:{sessionUpdate:"permission_request",permission:u}}),await new Promise(l=>{let f=g(n?.timeoutMs,this.config.permissionRequestTimeoutMs),p=setTimeout(()=>{this.pendingPermissions.delete(i),l({permissionId:i,outcome:"denied",response:{reason:"permission request timed out"}})},f);this.pendingPermissions.set(i,{timer:p,resolve:l,permission:u})})}async respondPermission(t){let e=o(t.permissionId),n=this.pendingPermissions.get(e),r=o(t.outcome||"approved")||"approved";return n?(clearTimeout(n.timer),this.pendingPermissions.delete(e),n.resolve({permissionId:e,outcome:r,response:d(t.response)?t.response:{},userId:o(t.userId),metadata:d(t.metadata)?t.metadata:{}}),{accepted:!0,permissionId:e,outcome:r}):{accepted:!1,permissionId:e,outcome:r}}health(){return{status:"ok",bridgeVersion:M,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)}}};import Jt from"node:http";import zt from"node:https";import{randomBytes as rt}from"node:crypto";var j=1,z=3,q=class{constructor(t){this.url=t,this.readyState=0,this.socket=null,this.buffer=Buffer.alloc(0),this.listeners=new Map,this.connect()}addEventListener(t,e){let n=this.listeners.get(t)||new Set;n.add(e),this.listeners.set(t,n)}emit(t,e={}){let n=this.listeners.get(t);if(n)for(let r of n)r(e)}connect(){let t=new URL(this.url),e=t.protocol==="wss:"?zt:Jt,n=rt(16).toString("base64"),r=e.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"}});r.on("upgrade",(i,a,c)=>{this.socket=a,this.readyState=j,a.on("data",u=>this.onData(u)),a.on("close",()=>this.onClose()),a.on("error",u=>{this.emit("error",{error:u,message:u.message,type:"error"}),this.onClose()}),c?.length&&this.onData(c),this.emit("open")}),r.on("response",i=>{this.emit("error",{message:`websocket upgrade failed: HTTP ${i.statusCode}`,type:"error"}),i.resume(),this.onClose()}),r.on("error",i=>{this.emit("error",{error:i,message:i.message,type:"error"}),this.onClose()}),r.end()}send(t){!this.socket||this.readyState!==j||this.socket.write(K(1,Buffer.from(String(t),"utf8")))}close(){!this.socket||this.readyState===z||(this.socket.write(K(8,Buffer.alloc(0))),this.socket.end(),this.onClose())}onClose(){this.readyState!==z&&(this.readyState=z,this.emit("close"))}onData(t){for(this.buffer=Buffer.concat([this.buffer,t]);this.buffer.length>=2;){let e=this.buffer[0],n=this.buffer[1],r=e&15,i=(n&128)!==0,a=n&127,c=2;if(a===126){if(this.buffer.length<c+2)return;a=this.buffer.readUInt16BE(c),c+=2}else if(a===127){if(this.buffer.length<c+8)return;let f=this.buffer.readUInt32BE(c),p=this.buffer.readUInt32BE(c+4);a=f*2**32+p,c+=8}let u=c;if(i&&(c+=4),this.buffer.length<c+a)return;let l=this.buffer.subarray(c,c+a);if(i){let f=this.buffer.subarray(u,u+4);l=Buffer.from(l.map((p,I)=>p^f[I%4]))}this.buffer=this.buffer.subarray(c+a),r===1?this.emit("message",{data:l.toString("utf8")}):r===8?this.close():r===9&&this.socket?.write(K(10,l))}}};function K(s,t){let e=t.length,n=2;e>=126&&e<=65535?n+=2:e>65535&&(n+=8);let r=rt(4),i=Buffer.alloc(n+4+e);i[0]=128|s;let a=2;e<126?i[1]=128|e:e<=65535?(i[1]=254,i.writeUInt16BE(e,a),a+=2):(i[1]=255,i.writeUInt32BE(Math.floor(e/2**32),a),i.writeUInt32BE(e>>>0,a+4),a+=8),r.copy(i,a),a+=4;for(let c=0;c<e;c+=1)i[a+c]=t[c]^r[c%4];return i}function Kt(s){let t=new URL(s);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 Wt(s){return Object.entries(s||{}).map(([t,e])=>({targetCode:t,targetName:o(e?.name||e?.targetName||t),targetType:o(e?.type||"echo"),status:"available",metadata:d(e)?e:{}}))}var G=class{constructor(t,e){this.config=t,this.bridge=e,this.ws=null,this.stopped=!1,this.connected=!1,this.reconnectTimer=null}start(){this.connect()}stop(){this.stopped=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.ws?.close()}connect(){let t=Kt(this.config.orchaUrl),e=new q(t);this.ws=e,e.addEventListener("open",()=>this.authenticate()),e.addEventListener("message",n=>this.handleMessage(n.data)),e.addEventListener("close",()=>this.scheduleReconnect("close")),e.addEventListener("error",n=>{h("warn","orcha-client","runtime node websocket error",{error:String(n?.message||n?.type||n)})})}authenticate(){this.send({type:"runtime_node.authenticate",token:this.config.nodeToken,nodeId:this.config.nodeId,nodeName:this.config.nodeName,version:M,protocolVersion:"orcha-runtime-node.v1",defaultTargetCode:this.config.defaultTargetCode,targets:Wt(this.config.targets)})}scheduleReconnect(t){this.connected=!1,!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){let e;try{e=JSON.parse(String(t))}catch(n){h("warn","orcha-client","invalid Orcha websocket frame",{error:String(n)});return}if(d(e)){if(e.type==="runtime_node.authenticated"){this.connected=!0,h("info","orcha-client","runtime node authenticated",{nodeId:this.config.nodeId,connectionId:e.connectionId});return}if(e.type==="orcha.runtime.request"){await this.handleRequest(e);return}e.type==="runtime_node.ping"&&this.send({type:"runtime_node.pong",ts:new Date().toISOString()})}}async handleRequest(t){let e=o(t.id),n=o(t.method),r=d(t.params)?t.params:{};try{let i=await this.invoke(n,r,e);this.send({type:"orcha.runtime.response",id:e,ok:!0,result:i})}catch(i){this.send({type:"orcha.runtime.response",id:e,ok:!1,error:{code:i.code||"RUNTIME_NODE_ERROR",message:i.message||String(i)}})}}async invoke(t,e,n){if(t==="health")return this.bridge.health();if(t==="agents/create")return this.bridge.createAgent(e);if(t==="agents/dispatch")return this.bridge.dispatch(e,{onUpdate:r=>this.sendUpdate(n,r)});if(t==="sessions/prompt")return this.bridge.prompt(e,{onUpdate:r=>this.sendUpdate(n,r)});if(t==="sessions/cancel")return this.bridge.cancel(e);if(t==="permissions/respond")return this.bridge.respondPermission(e);throw Object.assign(new Error(`unsupported Orcha runtime method: ${t}`),{code:"METHOD_NOT_FOUND"})}sendUpdate(t,e){this.send({type:"orcha.runtime.event",requestId:t,eventType:"runtime.update",payload:e})}send(t){return!this.ws||this.ws.readyState!==j?!1:(this.ws.send(JSON.stringify(t)),!0)}};import{existsSync as Vt,readFileSync as Qt}from"node:fs";import{resolve as it}from"node:path";var Zt=/^[A-Za-z_][A-Za-z0-9_]*$/;function ot(s=process.env,t=process.cwd()){let e=o(s.ORCHA_RUNTIME_ENV_FILE),n=e?it(t,e):it(t,".env");if(!Vt(n))return e&&h("warn","config","runtime env file not found",{path:n}),{loaded:!1,path:n,keys:[]};let r=[],i=Qt(n,"utf8");for(let a of i.split(/\r?\n/)){let c=Xt(a);if(!c)continue;let[u,l]=c;Object.prototype.hasOwnProperty.call(s,u)||(s[u]=l,r.push(u))}return h("info","config","runtime env file loaded",{path:n,keyCount:r.length}),{loaded:!0,path:n,keys:r}}function at(s=process.env){return{mode:o(s.ORCHA_RUNTIME_MODE||(s.ORCHA_RUNTIME_ORCHA_URL?"node":"server")),host:s.ORCHA_RUNTIME_BRIDGE_HOST||"127.0.0.1",port:g(s.ORCHA_RUNTIME_BRIDGE_PORT,5588),token:s.ORCHA_RUNTIME_BRIDGE_TOKEN||"",orchaUrl:o(s.ORCHA_RUNTIME_ORCHA_URL),nodeToken:s.ORCHA_RUNTIME_NODE_TOKEN||s.ORCHA_RUNTIME_BRIDGE_TOKEN||"",nodeId:o(s.ORCHA_RUNTIME_NODE_ID||s.HOSTNAME||"local-runtime-node"),nodeName:o(s.ORCHA_RUNTIME_NODE_NAME||s.ORCHA_RUNTIME_NODE_ID||s.HOSTNAME||"Local Runtime Node"),reconnectMs:g(s.ORCHA_RUNTIME_RECONNECT_MS,3e3),defaultTargetCode:s.ORCHA_RUNTIME_DEFAULT_TARGET||"echo",requestLimitBytes:g(s.ORCHA_RUNTIME_REQUEST_LIMIT_BYTES,1048576),sessionPromptTimeoutMs:g(s.ORCHA_RUNTIME_SESSION_PROMPT_TIMEOUT_MS,36e5),permissionRequestTimeoutMs:g(s.ORCHA_RUNTIME_PERMISSION_TIMEOUT_MS,3e5),targets:Yt(s.ORCHA_RUNTIME_TARGETS_JSON||"")}}function Yt(s){if(!o(s))return{};try{let t=JSON.parse(s);if(d(t))return t}catch(t){h("warn","config","invalid ORCHA_RUNTIME_TARGETS_JSON",{error:String(t)})}return{}}function Xt(s){let t=s.trim();if(!t||t.startsWith("#"))return null;let e=t.startsWith("export ")?t.slice(7).trimStart():t,n=e.indexOf("=");if(n<=0)return null;let r=e.slice(0,n).trim();if(!Zt.test(r))return null;let i=te(e.slice(n+1).trim());return[r,i]}function te(s){if(!s)return"";let t=s[0];if((t==='"'||t==="'")&&s.endsWith(t)){let e=s.slice(1,-1);return t==='"'?ee(e):e}return se(s).trim()}function ee(s){return s.replaceAll("\\n",`
12
+ `).replaceAll("\\r","\r").replaceAll("\\t"," ").replaceAll('\\"','"').replaceAll("\\\\","\\")}function se(s){let t=!1,e=!1;for(let n=0;n<s.length;n+=1){let r=s[n],i=s[n-1];if(r==="'"&&!e)t=!t;else if(r==='"'&&!t&&i!=="\\")e=!e;else if(r==="#"&&!t&&!e&&/\s/.test(i||""))return s.slice(0,n)}return s}import{createServer as ne}from"node:http";function J(s,t,e){let n=JSON.stringify(e);s.writeHead(t,{"content-type":"application/json; charset=utf-8","content-length":Buffer.byteLength(n)}),s.end(n)}function y(s={}){return{ok:!0,...s}}function W(s,t,e){return{ok:!1,error:{code:s,message:t,...e===void 0?{}:{detail:e}}}}async function ct(s,t){let e=[],n=0;for await(let i of s){if(n+=i.length,n>t)throw Object.assign(new Error("request body too large"),{status:413,code:"REQUEST_TOO_LARGE"});e.push(i)}if(e.length===0)return{};let r=Buffer.concat(e).toString("utf8");if(!r.trim())return{};try{let i=JSON.parse(r);if(!d(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 dt(s,t){if(!t)return;if((s.headers.authorization||"")!==`Bearer ${t}`)throw Object.assign(new Error("runtime bridge token is invalid"),{status:401,code:"UNAUTHORIZED"})}function ut(s,t){let e={"GET /health":async()=>y(t.health()),"POST /agents/create":async n=>y(await t.createAgent(n)),"POST /agents/dispatch":async n=>y(await t.dispatch(n)),"POST /sessions/prompt":async n=>y(await t.prompt(n)),"POST /sessions/cancel":async n=>y(await t.cancel(n)),"POST /permissions/respond":async n=>y(await t.respondPermission(n))};return ne(async(n,r)=>{let i=new URL(n.url||"/",`http://${n.headers.host||`${s.host}:${s.port}`}`),a=`${n.method||"GET"} ${i.pathname}`,c=e[a];if(!c){J(r,404,W("NOT_FOUND",`No route for ${a}`));return}try{dt(n,s.token);let u=n.method==="GET"?{}:await ct(n,s.requestLimitBytes);J(r,200,await c(u))}catch(u){let l=u.status||500,f=u.code||"BRIDGE_INTERNAL";J(r,l,W(f,u.message||String(u)))}})}var fe=pe(import.meta.url),me=".orcha-runtime-bridge.pid",ge=".orcha-runtime-bridge.log",{command:we,options:wt}=ye(process.argv.slice(2));Te(wt);ot();var Ie=at();await _e(we,Ie,wt);async function _e(s,t,e){switch(s){case"run":case"foreground":lt(t);return;case"start":if(e.foreground){lt(t);return}ht();return;case"reload":case"restart":await pt({quiet:!0}),ht();return;case"stop":await pt();return;case"status":Ee();return;case"help":case"--help":case"-h":Se();return;default:throw new Error(`Unknown command: ${s}`)}}function lt(s){let t=new B(s);if(s.mode==="server"){ut(s,t).listen(s.port,s.host,()=>{h("info","runtime-bridge","Orcha runtime bridge HTTP server started",{host:s.host,port:s.port,targets:Object.keys(t.targets)})});return}if(!s.orchaUrl)throw new Error("ORCHA_RUNTIME_ORCHA_URL is required in runtime node mode");new G(s,t).start(),h("info","runtime-bridge","Orcha runtime node started",{nodeId:s.nodeId,nodeName:s.nodeName,orchaUrl:s.orchaUrl,targets:Object.keys(t.targets)})}function ht(){let s=Q(),t=It(),e=Z(s);if(e&&x(e)){console.log(JSON.stringify({status:"already_running",pid:e,pidFile:s,logFile:t}));return}e&&V(s),mt(s),mt(t);let n=ce(t,"a"),r=re(process.execPath,[fe,"run"],{cwd:process.cwd(),detached:!0,env:process.env,stdio:["ignore",n,n]});r.unref(),ie(n),le(s,`${r.pid}
13
+ `),console.log(JSON.stringify({status:"started",pid:r.pid,pidFile:s,logFile:t}))}async function pt({quiet:s=!1}={}){let t=Q(),e=Z(t);if(!e){s||console.log(JSON.stringify({status:"not_running",pidFile:t}));return}if(!x(e)){V(t),s||console.log(JSON.stringify({status:"not_running",pid:e,pidFile:t}));return}process.kill(e,"SIGTERM"),!await ft(e,1e4)&&x(e)&&(process.kill(e,"SIGKILL"),await ft(e,3e3)),V(t),s||console.log(JSON.stringify({status:"stopped",pid:e,pidFile:t}))}function Ee(){let s=Q(),t=It(),e=Z(s),n=!!(e&&x(e));console.log(JSON.stringify({status:n?"running":"not_running",running:n,pid:n?e:null,pidFile:s,logFile:t}))}function ye(s){let t=[],e={};for(let r=0;r<s.length;r+=1){let i=s[r];i==="--daemon"?e.daemon=!0:i==="--foreground"?e.foreground=!0:i==="--env-file"?e.envFile=s[++r]:i==="--pid-file"?e.pidFile=s[++r]:i==="--log-file"?e.logFile=s[++r]:t.push(i)}return{command:t[0]||"run",options:e}}function Te(s){s.envFile&&(process.env.ORCHA_RUNTIME_ENV_FILE=s.envFile),s.pidFile&&(process.env.ORCHA_RUNTIME_PID_FILE=s.pidFile),s.logFile&&(process.env.ORCHA_RUNTIME_LOG_FILE=s.logFile)}function Q(){return gt(process.cwd(),process.env.ORCHA_RUNTIME_PID_FILE||me)}function It(){return gt(process.cwd(),process.env.ORCHA_RUNTIME_LOG_FILE||ge)}function Z(s){if(!oe(s))return null;let t=Number.parseInt(de(s,"utf8").trim(),10);return Number.isInteger(t)&&t>0?t:null}function x(s){try{return process.kill(s,0),!0}catch(t){return t?.code==="EPERM"}}async function ft(s,t){let e=Date.now();for(;Date.now()-e<t;){if(!x(s))return!0;await new Promise(n=>setTimeout(n,100))}return!x(s)}function mt(s){ae(he(s),{recursive:!0})}function V(s){try{ue(s,{force:!0})}catch{}}function Se(){console.log(`Usage: orcha-runtime-bridge [command] [options]
14
+
15
+ Commands:
16
+ run, foreground Run in the foreground. This is the default.
17
+ start Start in the background and write a pid file.
18
+ reload, restart Stop the background process and start it again.
19
+ stop Stop the background process.
20
+ status Print background process status as JSON.
21
+
22
+ Options:
23
+ --env-file <path> Load runtime environment from this file.
24
+ --pid-file <path> Override ORCHA_RUNTIME_PID_FILE.
25
+ --log-file <path> Override ORCHA_RUNTIME_LOG_FILE.
26
+ --foreground Run "start" in the foreground.
27
+ `)}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@orcha-ai/runtime-bridge",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Local Orcha runtime bridge for ACP-compatible agent runtimes.",
7
+ "license": "UNLICENSED",
8
+ "homepage": "https://orcha.tansuo.cloud",
9
+ "bin": {
10
+ "orcha-runtime-bridge": "./bin/orcha-runtime-bridge.js"
11
+ },
12
+ "files": [
13
+ "bin",
14
+ "README.md",
15
+ ".env.example"
16
+ ],
17
+ "scripts": {
18
+ "start": "node bin/orcha-runtime-bridge.js"
19
+ },
20
+ "keywords": [
21
+ "orcha",
22
+ "runtime",
23
+ "agent",
24
+ "acp",
25
+ "codex",
26
+ "openclaw"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "engines": {
32
+ "node": ">=20"
33
+ }
34
+ }