@messenger-agent/messenger-agent 0.37.0-alpha.1 → 0.37.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/dist/tunnel-client.js +1 -1
- package/package.json +2 -2
package/dist/tunnel-client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createRequire as f}from"node:module";import p from"ws";import{logger as
|
|
1
|
+
import{createRequire as f}from"node:module";import{hostname as m,platform as k,userInfo as w}from"node:os";import p from"ws";import{logger as u}from"@messenger-agent/shared/logger";import{createIncomingRequestStream as R}from"@messenger-agent/shared/incoming-request-stream";import{reconnectDelayWithJitter as g}from"@messenger-agent/shared/reconnect-backoff";import{createAgentFileRoutes as q}from"@messenger-agent/shared/agent-files";import{createPrefixedRouteRequest as y,createWorkspaceRouteRequest as b,isAgentFileHttpTunnelRequest as T,isWorkspaceHttpTunnelRequest as v,sendHttpTunnelResponse as E}from"@messenger-agent/shared/tunnel-http";import{CODING_AGENT_TUNNEL_DUPLICATE_CLOSE_CODE as h,CODING_AGENT_TUNNEL_PROTOCOL_VERSION as I}from"@messenger-agent/shared/tunnel-protocol";import{createAgentWorkspaceRoutes as M}from"@messenger-agent/shared/workspace-routes";import{appConfig as W}from"./config.js";const S=f(import.meta.url)("../package.json").version;function _(){const o=m().trim();if(!o)return{};if(k()!=="linux")return{hostname:o};try{const e=w().username.trim();return{hostname:o,...e?{username:e}:{}}}catch{return{hostname:o}}}const O=o=>new Promise(e=>setTimeout(e,o)),C=3;function x(o){try{const e=JSON.parse(o.toString());return e&&typeof e=="object"&&"type"in e?e:void 0}catch{return}}class V{config;stopped=!1;socket;running=new Map;streamedRequests=new Map;workspaceRoutes;fileRoutes=q();constructor(e=W){this.config=e,this.workspaceRoutes=M({config:e,textMaxBytes:e.textMaxBytes,uploadLimits:e.workspaceUploadLimits,allowManagement:!0,onWorkspacesChanged:()=>{process.send?.({type:"client.workspaces.changed"})}})}async start(){if(!this.config.tunnel.enabled)return;if(!this.config.tunnel.serverUrl||!this.config.tunnel.tunnelId||!this.config.tunnel.token)throw new Error("Workspace tunnel requires server_url, tunnel_id, and token when enabled");let e=this.config.tunnel.reconnectInitialMs;for(;!this.stopped;){try{e=await this.connectOnce()==="duplicate"?this.config.tunnel.reconnectMaxMs:this.config.tunnel.reconnectInitialMs}catch(s){this.stopped||u.warn("[WorkspaceTunnel] connection failed:",s)}this.stopped||(await O(g(e)),e=Math.min(e*2,this.config.tunnel.reconnectMaxMs))}}stop(){this.stopped=!0;for(const e of this.running.values())e.abort();this.running.clear();for(const e of this.streamedRequests.values())e.stream.error(new Error("Workspace tunnel stopped"));this.streamedRequests.clear(),this.socket?.close()}connectOnce(){return new Promise((e,s)=>{const r=new p(this.config.tunnel.serverUrl,{headers:{Authorization:`Bearer ${this.config.tunnel.token}`}});this.socket=r;let a,i=0,c=!1;const l=()=>{a&&clearInterval(a),this.socket===r&&(this.socket=void 0);for(const n of this.running.values())n.abort(new Error("Workspace tunnel closed"));this.running.clear();for(const n of this.streamedRequests.values())n.stream.error(new Error("Workspace tunnel closed"));this.streamedRequests.clear()};r.on("open",()=>{i=Date.now(),this.send({type:"hello",protocolVersion:I,tunnelId:this.config.tunnel.tunnelId,agentType:"workspace",capabilities:["workspace.files","workspace.files.upload.v1","workspace.git","workspace.tasks"],clientVersion:S,..._(),workspaces:[...this.config.workspaces.values()].map(({id:n,name:t,path:d})=>({id:n,name:t,path:d})).sort((n,t)=>n.id.localeCompare(t.id))}),a=setInterval(()=>{if(Date.now()-i>=this.config.tunnel.heartbeatIntervalMs*C){u.warn("[WorkspaceTunnel] websocket tunnel server is not responding; terminating stale connection"),r.terminate();return}this.send({type:"heartbeat"})},this.config.tunnel.heartbeatIntervalMs),u.info(`[WorkspaceTunnel] connected to ${this.config.tunnel.serverUrl} as ${this.config.tunnel.tunnelId}`)}),r.on("message",n=>{i=Date.now();const t=x(n);if(!(!t||t.type==="heartbeat"))if(t.type==="cancel")this.running.get(t.id)?.abort(),this.streamedRequests.get(t.id)?.stream.error(new Error("Workspace tunnel request cancelled")),this.streamedRequests.delete(t.id);else if(t.type==="request")this.handleRequest(t);else if(t.type==="request.start")this.startStreamedRequest(t);else if(t.type==="request.chunk"){const d=this.streamedRequests.get(t.id);d&&!d.stream.enqueue(Buffer.from(t.body.data,"base64"))&&(this.running.get(t.id)?.abort(new Error("Streamed request body exceeded its buffer limit")),this.streamedRequests.delete(t.id))}else t.type==="request.end"&&(this.streamedRequests.get(t.id)?.stream.close(),this.streamedRequests.delete(t.id))}),r.once("error",n=>{c||(c=!0,l(),s(n))}),r.once("close",(n,t)=>{l(),n===h?u.warn(`[WorkspaceTunnel] duplicate connection rejected; retrying with backoff: ${t.toString()}`):n===1008&&(this.stopped=!0,u.warn(`[WorkspaceTunnel] connection rejected with code ${n}; reconnect disabled until service restart: ${t.toString()}`)),c||(c=!0,e(n===h?"duplicate":"closed"))})})}send(e){this.socket?.readyState===p.OPEN&&this.socket.send(JSON.stringify(e))}startStreamedRequest(e){if(this.streamedRequests.has(e.id)||this.running.has(e.id))return;const s=R({onConsumed:r=>this.send({type:"request.ack",id:e.id,bytes:r}),onCancel:()=>this.running.get(e.id)?.abort()});this.streamedRequests.set(e.id,{stream:s,request:e}),this.handleRequest(e,s.body)}async handleRequest(e,s){const r=T(e);if(!r&&!v(e)){this.send({type:"response.error",id:e.id,code:"unsupported_request",errorText:`Unsupported workspace tunnel request: ${e.method} ${e.path}`}),this.streamedRequests.delete(e.id);return}const a=new AbortController;this.running.set(e.id,a);try{const i=r?y(e,"/v1/files",a.signal,s):b(e,a.signal,s),c=await(r?this.fileRoutes:this.workspaceRoutes).fetch(i);await E(e.id,c,l=>this.send(l))}catch(i){this.send({type:"response.error",id:e.id,code:"request_failed",errorText:i instanceof Error?i.message:"Workspace tunnel request failed"})}finally{this.running.delete(e.id),this.streamedRequests.delete(e.id)}}}export{V as WorkspaceTunnelClient};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@messenger-agent/messenger-agent",
|
|
3
|
-
"version": "0.37.0
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"ws": "^8.18.3",
|
|
21
21
|
"yaml": "^2.9.0",
|
|
22
22
|
"zod": "^4.4.3",
|
|
23
|
-
"@messenger-agent/shared": "0.37.0
|
|
23
|
+
"@messenger-agent/shared": "0.37.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/ws": "^8.18.1"
|