acp-chat 0.2.9 → 0.2.10
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/dist/acp-client.d.ts +4 -0
- package/dist/cli.js +4 -4
- package/dist/index.js +3 -3
- package/package.json +1 -1
package/dist/acp-client.d.ts
CHANGED
|
@@ -76,6 +76,10 @@ export interface ACPClient extends EventEmitter {
|
|
|
76
76
|
sessionPrompt(sessionId: string, text: string, role?: string): Promise<PromptResult>;
|
|
77
77
|
sessionConfigure(sessionId: string, options: ConfigOption[]): Promise<void>;
|
|
78
78
|
sessionCancel(sessionId: string): void;
|
|
79
|
+
/** Send a JSON-RPC response to an incoming request (e.g. permission request). */
|
|
80
|
+
sendResponse(id: string | number, result: unknown): void;
|
|
81
|
+
/** Send a JSON-RPC error response to an incoming request. */
|
|
82
|
+
sendErrorResponse(id: string | number, code: number, message: string): void;
|
|
79
83
|
readonly requestTracker: RequestTracker;
|
|
80
84
|
}
|
|
81
85
|
export interface PermissionRequest {
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{EventEmitter as
|
|
3
|
-
`}function
|
|
4
|
-
`))!==-1;){let i=this.lineBuffer.slice(0,t);if(this.lineBuffer=this.lineBuffer.slice(t+1),i.length!==0)try{this.emit("message",
|
|
5
|
-
`),console.error(`STOP=${r.stopReason} UPDATES=${r.updates.length}`)}finally{await
|
|
2
|
+
import{EventEmitter as L}from"node:events";import*as O from"node:net";function D(o){let e=JSON.stringify(o);if(e===void 0)throw new TypeError("Value is not JSON-serializable");return e+`
|
|
3
|
+
`}function U(o){return JSON.parse(o)}var k={CAPACITY_EXCEEDED:-32e3,REQUEST_TIMEOUT:-32001,DISCONNECTED:-32004},E=class extends Error{code;data;constructor(e,t,i){super(t),this.name="ACPError",this.code=e,this.data=i}},S=class extends E{constructor(e="Capacity exceeded",t){super(k.CAPACITY_EXCEEDED,e,t),this.name="CapacityExceededError"}},T=class extends E{constructor(e="Request timeout",t){super(k.REQUEST_TIMEOUT,e,t),this.name="RequestTimeoutError"}},P=class extends E{constructor(e="Disconnected",t){super(k.DISCONNECTED,e,t),this.name="DisconnectedError"}};var y=class extends L{opts;socket=null;state="disconnected";reconnectAttempt=0;reconnectTimer=null;lineBuffer="";closedByUser=!1;constructor(e){super(),this.opts=e}connect(){return this.state==="connected"||this.state==="connecting"?Promise.resolve():this.state==="closed"?Promise.reject(new Error("Client has been closed")):(this.closedByUser=!1,this.reconnectAttempt=0,this.createConnection())}send(e){if(this.state!=="connected"||!this.socket)throw new P("Cannot send: not connected to stdio Bus");this.socket.write(D(e))}close(){this.closedByUser=!0,this.clearReconnectTimer();let e=this.state;return this.state="closed",e==="closed"||e==="disconnected"?Promise.resolve():new Promise(t=>{if(this.socket){let i=this.socket;if(this.socket=null,i.destroyed){t();return}i.once("close",()=>t()),i.destroy()}else t()})}isConnected(){return this.state==="connected"}getState(){return this.state}createConnection(){return new Promise((e,t)=>{this.state=this.reconnectAttempt===0?"connecting":"reconnecting",this.lineBuffer="";let i=this.buildConnectOptions(),d=O.createConnection(i);this.socket=d;let m=()=>{a(),this.state="connected",this.reconnectAttempt=0,this.wireSocketEvents(d),e()},r=l=>{a(),this.reconnectAttempt===0&&this.state==="connecting"&&(this.state="disconnected",t(l))},a=()=>{d.removeListener("connect",m),d.removeListener("error",r)};d.once("connect",m),d.once("error",r)})}buildConnectOptions(){if(this.opts.connectionType==="unix")return{path:this.opts.address};let e=this.opts.address.lastIndexOf(":");if(e===-1)throw new Error(`Invalid TCP address: expected "host:port", got "${this.opts.address}"`);let t=this.opts.address.slice(0,e),i=parseInt(this.opts.address.slice(e+1),10);if(isNaN(i))throw new Error(`Invalid TCP port in address "${this.opts.address}"`);return{host:t,port:i}}wireSocketEvents(e){e.on("data",t=>this.handleData(t.toString("utf-8"))),e.on("error",t=>this.emit("error",t)),e.on("close",()=>{this.closedByUser||this.state==="closed"||(this.state="disconnected",this.emit("disconnect"),this.scheduleReconnect())})}handleData(e){this.lineBuffer+=e;let t;for(;(t=this.lineBuffer.indexOf(`
|
|
4
|
+
`))!==-1;){let i=this.lineBuffer.slice(0,t);if(this.lineBuffer=this.lineBuffer.slice(t+1),i.length!==0)try{this.emit("message",U(i))}catch(d){this.emit("framingError",i,d instanceof Error?d:new Error(String(d)))}}}scheduleReconnect(){if(this.closedByUser||this.state==="closed")return;if(this.reconnectAttempt>=this.opts.maxReconnectAttempts){this.state="disconnected",this.emit("disconnect");return}this.state="reconnecting";let e=this.reconnectAttempt++,t=Math.random()*this.opts.baseReconnectDelayMs,i=Math.min(this.opts.baseReconnectDelayMs*Math.pow(2,e)+t,this.opts.maxReconnectDelayMs);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.emit("reconnect",this.reconnectAttempt),this.attemptReconnect()},i)}attemptReconnect(){if(this.closedByUser||this.state==="closed")return;this.lineBuffer="";let e=O.createConnection(this.buildConnectOptions());this.socket=e,e.once("connect",()=>{e.removeAllListeners("error"),this.state="connected",this.reconnectAttempt=0,this.wireSocketEvents(e)}),e.once("error",()=>{e.destroy(),this.scheduleReconnect()})}clearReconnectTimer(){this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}};var H={maxPending:4096,defaultTimeoutMs:3e4},I=1e3;function M(o){let e={...H,...o};e.defaultTimeoutMs<I&&(e.defaultTimeoutMs=I);let t=new Map;function i(r,a){if(t.size>=e.maxPending)return Promise.reject(new S(`Maximum pending requests (${e.maxPending}) exceeded`));let l=a??e.defaultTimeoutMs;return l<I&&(l=I),new Promise((C,h)=>{let w=setTimeout(()=>{t.delete(r),h(new T(`Request ${String(r)} timed out after ${l}ms`,{id:r,timeoutMs:l}))},l);w.unref&&w.unref(),t.set(r,{id:r,registeredAt:Date.now(),timeoutMs:l,timeoutHandle:w,resolve:C,reject:h})})}function d(r){let a=t.get(r.id);return a?(clearTimeout(a.timeoutHandle),t.delete(r.id),a.resolve(r),!0):!1}function m(r){for(let[,a]of t)clearTimeout(a.timeoutHandle),a.reject(r);t.clear()}return{register:i,resolve:d,cancelAll:m,pendingCount:()=>t.size,hasPending:r=>t.has(r)}}import{EventEmitter as V}from"node:events";function _(o,e){let{agentId:t,requestTimeoutMs:i=12e4,clientInfo:d,permissionHandler:m}=e,r=new V,a=M({defaultTimeoutMs:i}),l=1,C=e.clientSessionId??`client-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,h=new Map;function w(n,s){o.isConnected()&&o.send({jsonrpc:"2.0",id:n,result:s})}function N(n,s,c){o.isConnected()&&o.send({jsonrpc:"2.0",id:n,error:{code:s,message:c}})}async function q(n,s,c){if(s==="session/request_permission"){if(r.emit("permissionRequest",{id:n,method:s,params:c}),m)try{let p=await m({id:n,method:s,params:c});w(n,{permission:p.approved?"granted":"denied",option:p.option??(p.approved?"approved-execpolicy-amendment":"denied")})}catch(p){let f=p instanceof Error?p.message:String(p);N(n,-32e3,`Permission handler error: ${f}`)}return}r.emit("incomingRequest",n,s,c)}o.on("message",n=>{let s=n;if(!s||s.jsonrpc!=="2.0")return;let c="id"in s,p="method"in s,f="result"in s,v="error"in s;if(c&&(f||v)){a.resolve(s);return}if(c&&p&&!f&&!v){let g=s.id,u=s.method,R=s.params;q(g,u,R).catch(()=>{});return}if(p&&!c){let g=s.method,u=s.params;if(g==="session/update"&&u){let R=u.sessionId,b=u.update,A=h.get(R);A&&A.push(b),r.emit("update",R,b)}r.emit("notification",g,u)}});function x(n,s){let c=l++,p={jsonrpc:"2.0",id:c,method:n,agentId:t,sessionId:C,params:s},f=a.register(c);return o.send(p),f}async function J(){let n=await x("initialize",{protocolVersion:1,clientCapabilities:{},clientInfo:d??{name:"acp-chat",version:"1.0.0"}});if(n.error)throw new Error(`initialize: [${n.error.code}] ${n.error.message}`);return n.result}async function $(n){let s={cwd:process.cwd(),mcpServers:[]};n?.length&&(s.configOptions=n);let c=await x("session/new",s);if(c.error)throw new Error(`session/new: [${c.error.code}] ${c.error.message}`);return{...c.result,clientSessionId:C}}async function B(n,s,c="user"){h.set(n,[]);let p=await x("session/prompt",{sessionId:n,prompt:[{type:"text",role:c,text:s}]});await new Promise(u=>setTimeout(u,200));let f=h.get(n)??[];if(h.delete(n),p.error)throw new Error(`session/prompt: [${p.error.code}] ${p.error.message}`);let v=p.result,g=[];for(let u of f)if(u.sessionUpdate==="agent_message_chunk"&&u.content?.text&&g.push(u.content.text),u.sessionUpdate==="tool_call_update"&&u.content)for(let R of u.content)R.content?.text&&g.push(R.content.text);return{stopReason:v.stopReason,updates:f,text:g.join("")}}async function z(n,s){let c=await x("session/configure",{sessionId:n,options:s});if(c.error)throw new Error(`session/configure: [${c.error.code}] ${c.error.message}`)}function j(n){o.send({jsonrpc:"2.0",method:"session/cancel",params:{sessionId:n},agentId:t,sessionId:C})}return Object.assign(r,{initialize:J,sessionNew:$,sessionPrompt:B,sessionConfigure:z,sessionCancel:j,sendResponse:w,sendErrorResponse:N,requestTracker:a})}var G=process.env.ACP_BUS_ADDRESS??"127.0.0.1:9800",Q=process.env.ACP_AGENT_ID??"codex-acp";async function X(){let o=process.argv.slice(2),e,t,i;o[0]==="new"?(o.length<2&&(console.error('Usage: acp-chat new "<message>"'),process.exit(1)),i=o[1]):(o.length<3&&(console.error('Usage: acp-chat <clientSessionId> <sessionId> "<message>"'),process.exit(1)),e=o[0],t=o[1],i=o[2]);let d=new y({address:G,connectionType:"tcp",maxReconnectAttempts:3,baseReconnectDelayMs:500,maxReconnectDelayMs:5e3});try{await d.connect();let m=_(d,{agentId:Q,requestTimeoutMs:300*1e3,clientInfo:{name:"acp-chat-cli",version:"1.0.0"},clientSessionId:e});if(m.on("update",(a,l)=>{l.sessionUpdate==="agent_message_chunk"&&process.stdout.write(l.content.text)}),await m.initialize(),t)console.error(`CLIENT_SESSION_ID=${e}`),console.error(`SESSION_ID=${t} (continued)`);else{let a=await m.sessionNew();t=a.sessionId,console.error(`CLIENT_SESSION_ID=${a.clientSessionId}`),console.error(`SESSION_ID=${t}`)}let r=await m.sessionPrompt(t,i);process.stdout.write(`
|
|
5
|
+
`),console.error(`STOP=${r.stopReason} UPDATES=${r.updates.length}`)}finally{await d.close()}}X().catch(o=>{console.error("ERROR:",o.message),process.exit(1)});
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{EventEmitter as
|
|
2
|
-
`}function
|
|
3
|
-
`))!==-1;){let
|
|
1
|
+
import{EventEmitter as j}from"node:events";import*as I from"node:net";function M(c){let e=JSON.stringify(c);if(e===void 0)throw new TypeError("Value is not JSON-serializable");return e+`
|
|
2
|
+
`}function q(c){return JSON.parse(c)}var k={CAPACITY_EXCEEDED:-32e3,REQUEST_TIMEOUT:-32001,DISCONNECTED:-32004},w=class extends Error{code;data;constructor(e,t,i){super(t),this.name="ACPError",this.code=e,this.data=i}},E=class extends w{constructor(e="Capacity exceeded",t){super(k.CAPACITY_EXCEEDED,e,t),this.name="CapacityExceededError"}},x=class extends w{constructor(e="Request timeout",t){super(k.REQUEST_TIMEOUT,e,t),this.name="RequestTimeoutError"}},v=class extends w{constructor(e="Disconnected",t){super(k.DISCONNECTED,e,t),this.name="DisconnectedError"}};var O=class extends j{opts;socket=null;state="disconnected";reconnectAttempt=0;reconnectTimer=null;lineBuffer="";closedByUser=!1;constructor(e){super(),this.opts=e}connect(){return this.state==="connected"||this.state==="connecting"?Promise.resolve():this.state==="closed"?Promise.reject(new Error("Client has been closed")):(this.closedByUser=!1,this.reconnectAttempt=0,this.createConnection())}send(e){if(this.state!=="connected"||!this.socket)throw new v("Cannot send: not connected to stdio Bus");this.socket.write(M(e))}close(){this.closedByUser=!0,this.clearReconnectTimer();let e=this.state;return this.state="closed",e==="closed"||e==="disconnected"?Promise.resolve():new Promise(t=>{if(this.socket){let i=this.socket;if(this.socket=null,i.destroyed){t();return}i.once("close",()=>t()),i.destroy()}else t()})}isConnected(){return this.state==="connected"}getState(){return this.state}createConnection(){return new Promise((e,t)=>{this.state=this.reconnectAttempt===0?"connecting":"reconnecting",this.lineBuffer="";let i=this.buildConnectOptions(),u=I.createConnection(i);this.socket=u;let g=()=>{p(),this.state="connected",this.reconnectAttempt=0,this.wireSocketEvents(u),e()},r=l=>{p(),this.reconnectAttempt===0&&this.state==="connecting"&&(this.state="disconnected",t(l))},p=()=>{u.removeListener("connect",g),u.removeListener("error",r)};u.once("connect",g),u.once("error",r)})}buildConnectOptions(){if(this.opts.connectionType==="unix")return{path:this.opts.address};let e=this.opts.address.lastIndexOf(":");if(e===-1)throw new Error(`Invalid TCP address: expected "host:port", got "${this.opts.address}"`);let t=this.opts.address.slice(0,e),i=parseInt(this.opts.address.slice(e+1),10);if(isNaN(i))throw new Error(`Invalid TCP port in address "${this.opts.address}"`);return{host:t,port:i}}wireSocketEvents(e){e.on("data",t=>this.handleData(t.toString("utf-8"))),e.on("error",t=>this.emit("error",t)),e.on("close",()=>{this.closedByUser||this.state==="closed"||(this.state="disconnected",this.emit("disconnect"),this.scheduleReconnect())})}handleData(e){this.lineBuffer+=e;let t;for(;(t=this.lineBuffer.indexOf(`
|
|
3
|
+
`))!==-1;){let i=this.lineBuffer.slice(0,t);if(this.lineBuffer=this.lineBuffer.slice(t+1),i.length!==0)try{this.emit("message",q(i))}catch(u){this.emit("framingError",i,u instanceof Error?u:new Error(String(u)))}}}scheduleReconnect(){if(this.closedByUser||this.state==="closed")return;if(this.reconnectAttempt>=this.opts.maxReconnectAttempts){this.state="disconnected",this.emit("disconnect");return}this.state="reconnecting";let e=this.reconnectAttempt++,t=Math.random()*this.opts.baseReconnectDelayMs,i=Math.min(this.opts.baseReconnectDelayMs*Math.pow(2,e)+t,this.opts.maxReconnectDelayMs);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.emit("reconnect",this.reconnectAttempt),this.attemptReconnect()},i)}attemptReconnect(){if(this.closedByUser||this.state==="closed")return;this.lineBuffer="";let e=I.createConnection(this.buildConnectOptions());this.socket=e,e.once("connect",()=>{e.removeAllListeners("error"),this.state="connected",this.reconnectAttempt=0,this.wireSocketEvents(e)}),e.once("error",()=>{e.destroy(),this.scheduleReconnect()})}clearReconnectTimer(){this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}};var H={maxPending:4096,defaultTimeoutMs:3e4},S=1e3;function N(c){let e={...H,...c};e.defaultTimeoutMs<S&&(e.defaultTimeoutMs=S);let t=new Map;function i(r,p){if(t.size>=e.maxPending)return Promise.reject(new E(`Maximum pending requests (${e.maxPending}) exceeded`));let l=p??e.defaultTimeoutMs;return l<S&&(l=S),new Promise((y,h)=>{let C=setTimeout(()=>{t.delete(r),h(new x(`Request ${String(r)} timed out after ${l}ms`,{id:r,timeoutMs:l}))},l);C.unref&&C.unref(),t.set(r,{id:r,registeredAt:Date.now(),timeoutMs:l,timeoutHandle:C,resolve:y,reject:h})})}function u(r){let p=t.get(r.id);return p?(clearTimeout(p.timeoutHandle),t.delete(r.id),p.resolve(r),!0):!1}function g(r){for(let[,p]of t)clearTimeout(p.timeoutHandle),p.reject(r);t.clear()}return{register:i,resolve:u,cancelAll:g,pendingCount:()=>t.size,hasPending:r=>t.has(r)}}import{EventEmitter as L}from"node:events";function V(c,e){let{agentId:t,requestTimeoutMs:i=12e4,clientInfo:u,permissionHandler:g}=e,r=new L,p=N({defaultTimeoutMs:i}),l=1,y=e.clientSessionId??`client-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,h=new Map;function C(n,s){c.isConnected()&&c.send({jsonrpc:"2.0",id:n,result:s})}function b(n,s,o){c.isConnected()&&c.send({jsonrpc:"2.0",id:n,error:{code:s,message:o}})}async function D(n,s,o){if(s==="session/request_permission"){if(r.emit("permissionRequest",{id:n,method:s,params:o}),g)try{let a=await g({id:n,method:s,params:o});C(n,{permission:a.approved?"granted":"denied",option:a.option??(a.approved?"approved-execpolicy-amendment":"denied")})}catch(a){let m=a instanceof Error?a.message:String(a);b(n,-32e3,`Permission handler error: ${m}`)}return}r.emit("incomingRequest",n,s,o)}c.on("message",n=>{let s=n;if(!s||s.jsonrpc!=="2.0")return;let o="id"in s,a="method"in s,m="result"in s,T="error"in s;if(o&&(m||T)){p.resolve(s);return}if(o&&a&&!m&&!T){let f=s.id,d=s.method,R=s.params;D(f,d,R).catch(()=>{});return}if(a&&!o){let f=s.method,d=s.params;if(f==="session/update"&&d){let R=d.sessionId,A=d.update,U=h.get(R);U&&U.push(A),r.emit("update",R,A)}r.emit("notification",f,d)}});function P(n,s){let o=l++,a={jsonrpc:"2.0",id:o,method:n,agentId:t,sessionId:y,params:s},m=p.register(o);return c.send(a),m}async function J(){let n=await P("initialize",{protocolVersion:1,clientCapabilities:{},clientInfo:u??{name:"acp-chat",version:"1.0.0"}});if(n.error)throw new Error(`initialize: [${n.error.code}] ${n.error.message}`);return n.result}async function _(n){let s={cwd:process.cwd(),mcpServers:[]};n?.length&&(s.configOptions=n);let o=await P("session/new",s);if(o.error)throw new Error(`session/new: [${o.error.code}] ${o.error.message}`);return{...o.result,clientSessionId:y}}async function z(n,s,o="user"){h.set(n,[]);let a=await P("session/prompt",{sessionId:n,prompt:[{type:"text",role:o,text:s}]});await new Promise(d=>setTimeout(d,200));let m=h.get(n)??[];if(h.delete(n),a.error)throw new Error(`session/prompt: [${a.error.code}] ${a.error.message}`);let T=a.result,f=[];for(let d of m)if(d.sessionUpdate==="agent_message_chunk"&&d.content?.text&&f.push(d.content.text),d.sessionUpdate==="tool_call_update"&&d.content)for(let R of d.content)R.content?.text&&f.push(R.content.text);return{stopReason:T.stopReason,updates:m,text:f.join("")}}async function B(n,s){let o=await P("session/configure",{sessionId:n,options:s});if(o.error)throw new Error(`session/configure: [${o.error.code}] ${o.error.message}`)}function $(n){c.send({jsonrpc:"2.0",method:"session/cancel",params:{sessionId:n},agentId:t,sessionId:y})}return Object.assign(r,{initialize:J,sessionNew:_,sessionPrompt:z,sessionConfigure:B,sessionCancel:$,sendResponse:C,sendErrorResponse:b,requestTracker:p})}export{w as ACPError,E as CapacityExceededError,v as DisconnectedError,k as ErrorCodes,O as NDJSONClient,x as RequestTimeoutError,V as createACPClient,N as createRequestTracker};
|