grix-connector 3.16.0 → 3.17.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/adapter/acp/acp-adapter.js +14 -14
- package/dist/adapter/claude/claude-adapter.js +20 -19
- package/dist/adapter/claude/protocol-contract.js +1 -1
- package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
- package/dist/adapter/codex/codex-bridge.js +10 -10
- package/dist/adapter/codex/session-activity.js +3 -1
- package/dist/adapter/cursor/cursor-adapter.js +5 -5
- package/dist/adapter/opencode/opencode-adapter.js +3 -3
- package/dist/adapter/openhuman/openhuman-adapter.js +3 -3
- package/dist/adapter/pi/pi-adapter.js +5 -5
- package/dist/audit/adapters/acp/acp-audit-adapter.js +1 -0
- package/dist/audit/adapters/acp/generic-acp-audit-adapter.js +2 -0
- package/dist/audit/adapters/acp/kimi-audit-adapter.js +2 -0
- package/dist/audit/adapters/acp/reasonix-audit-adapter.js +1 -0
- package/dist/audit/adapters/acp/reasonix-transcript-source.js +1 -0
- package/dist/audit/adapters/claude/claude-audit-adapter.js +1 -0
- package/dist/audit/adapters/claude/claude-otel-source.js +2 -0
- package/dist/audit/adapters/claude/claude-transcript-source.js +1 -0
- package/dist/audit/adapters/claude/claude-usage-merger.js +1 -0
- package/dist/audit/adapters/codewhale/codewhale-audit-adapter.js +1 -0
- package/dist/audit/adapters/codex/codex-audit-adapter.js +1 -0
- package/dist/audit/adapters/cursor/cursor-audit-adapter.js +1 -0
- package/dist/audit/adapters/opencode/opencode-audit-adapter.js +1 -0
- package/dist/audit/adapters/pi/pi-audit-adapter.js +1 -0
- package/dist/audit/adapters/pi/pi-transcript-source.js +1 -0
- package/dist/audit/core/audit-options.js +1 -0
- package/dist/audit/core/audit-session-registry.js +3 -0
- package/dist/audit/core/audit-state.js +1 -0
- package/dist/audit/core/audit-turn-lifecycle.js +1 -0
- package/dist/audit/core/content-reference.js +1 -0
- package/dist/audit/core/replay-finalizer.js +1 -0
- package/dist/audit/core/types.js +1 -0
- package/dist/audit/core/usage.js +1 -0
- package/dist/audit/integration/bridge-audit-controller.js +1 -0
- package/dist/audit/producer/audit-producer.js +1 -0
- package/dist/audit/producer/ipc-audit-producer.js +1 -0
- package/dist/audit/query/audit-local-actions.js +1 -0
- package/dist/audit/query/audit-replay-query-service.js +1 -0
- package/dist/audit/runtime/default-audit-recorder.js +1 -0
- package/dist/audit/storage/file-audit-replay-store.js +2 -0
- package/dist/audit/worker/audit-recorder-ipc-protocol.js +1 -0
- package/dist/audit/worker/audit-recorder-worker-entry.js +1 -0
- package/dist/audit/worker/audit-recorder-worker.js +1 -0
- package/dist/bridge/bridge.js +10 -10
- package/dist/core/aibot/client.js +2 -2
- package/dist/core/aibot/connection-handle.js +1 -1
- package/dist/core/aibot/types.js +1 -0
- package/dist/core/config/provider-env.js +1 -1
- package/dist/core/mcp/internal-api-server.js +1 -1
- package/dist/core/observability/sentry.js +1 -1
- package/dist/core/proxy/compat/kiro-cw/eventstream.js +1 -0
- package/dist/core/proxy/compat/kiro-cw/index.js +1 -0
- package/dist/core/proxy/compat/kiro-cw/request-builder.js +3 -0
- package/dist/core/proxy/compat/kiro-cw/server.js +7 -0
- package/dist/core/proxy/compat/kiro-cw/stream-converter.js +5 -0
- package/dist/core/proxy/index.js +1 -1
- package/dist/core/proxy/kiro-relay.js +2 -0
- package/dist/core/proxy/relay-credential.js +1 -1
- package/dist/grix.js +1 -1
- package/dist/manager.js +2 -2
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/service/platform-adapter.js +4 -1
- package/package.json +8 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{EventEmitter as $}from"node:events";import{randomUUID as b}from"node:crypto";import k from"node:os";import m from"ws";import{log as a}from"../log/index.js";import{getMachineName as w}from"../util/index.js";import{detectTailnetIPv4 as E,ensureServerAndGetPort as q,getFileServerHttpsPort as y}from"../files/file-serve.js";import{AUTH_CODE_AGENT_DELETED as p,KICKED_REASON_AGENT_DELETED as S,AgentDeletedError as v,RequestTimeoutError as A}from"./errors.js";function R(g){return g.replace(/(?<=[\[:,\[]\s*)(\d{16,})(?=\s*[,}\]\n])/g,'"$1"')}function P(g){const e=[...g??["stream_chunk","local_action_v1","agent_invoke"]];return e.includes("agent_invoke")||e.push("agent_invoke"),e.includes("event_result_ack")||e.push("event_result_ack"),e}const T="aibot-agent-api-v1",I=1;class
|
|
2
|
-
`}),this.sendPacket("client_stream_chunk",e)}sendMsg(e){this.sendPacket("send_msg",e)||a.warn("aibot",`send_msg NOT sent (ws not open) event=${e.event_id??""} session=${e.session_id??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}editMsg(e){this.sendPacket("edit_msg",e)}sendEventResult(e){if(!this.ws||this.ws.readyState!==m.OPEN){this.sendPacket("event_result",e);return}this.sendEventResultReliable(e)}sendLocalActionResult(e){this.sendPacket("local_action_result",e)}sendEventStopAck(e){this.sendPacket("event_stop_ack",e)}sendEventStopResult(e){this.sendPacket("event_stop_result",e)}sendSessionActivitySet(e){this.sendPacket("session_activity_set",e)}sendCodexEvent(e){this.sendPacket("codex_event",e)}sendUpdateBindingCard(e){this.sendPacket("update_binding_card",e)}sendSkillsUpdate(e){this.sendPacket("agent_skills_update",e)}sendPing(){this.sendPacket("ping",{})}sendEventState(e){this.sendPacket("event_state",e)}sendEventCancelResult(e){this.sendPacket("event_cancel_result",e)}sendQueueClearResult(e){this.sendPacket("queue_clear_result",e)}sendQueueReorderResult(e){this.sendPacket("queue_reorder_result",e)}sendEventHoldResult(e){this.sendPacket("event_hold_result",e)}sendQueueEditResult(e){this.sendPacket("queue_edit_result",e)}sendQueueSnapshot(e){this.sendPacket("queue_snapshot",e)}agentInvoke(e,t,s=15e3){return new Promise((i,n)=>{const h=b(),c=Math.max(1e3,Math.min(s,6e4)),o=setTimeout(()=>{this.pendingInvokes.delete(h),n(new Error(`agent_invoke timeout: ${e}`))},c);this.pendingInvokes.set(h,{resolve:i,reject:n,timer:o}),this.sendPacket("agent_invoke",{invoke_id:h,action:e,params:t,timeout_ms:c})})}sendMcpFrame(e,t){this.sendPacket("mcp_frame",{session_id:e,frame:t})}request(e,t,s){return new Promise((i,n)=>{const h=++this.seq,c=setTimeout(()=>{this.pendingRequests.delete(h),n(new A(`request timeout: ${e} (expected ${s.expected.join("/")})`))},s.timeoutMs);this.pendingRequests.set(h,{expected:s.expected,resolve:i,reject:n,timer:c}),this.sendPacket(e,t,h)||(this.pendingRequests.delete(h),clearTimeout(c),n(new Error(`send failed: ${e}`)))})}async sendStreamChunkRequest(e,t=2e4){return this.request("client_stream_chunk",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}async relayCredentialRequest(e,t=15e3){return this.request("relay_credential_request",e,{expected:["relay_credential_result","error"],timeoutMs:t})}async sendText(e,t=2e4){return this.request("send_msg",{msg_type:1,...e},{expected:["send_ack","send_nack","error"],timeoutMs:t})}async sendMedia(e,t=2e4){return this.request("send_msg",{...e,msg_type:2},{expected:["send_ack","send_nack","error"],timeoutMs:t})}async editMessage(e,t=2e4){return this.request("edit_msg",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}async deleteMessage(e,t,s=2e4){return this.request("delete_msg",{session_id:e,msg_id:t},{expected:["send_ack","send_nack","error"],timeoutMs:s})}async sendEventResultRequest(e,t=5e3){return this.request("event_result",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}disconnect(){a.info("aibot",`disconnect() agent=${this.config.clientType}:${this.config.agentId} wasConnected=${this.connected} reconnecting=${this.reconnecting} reconnectAttempts=${this.reconnectAttempts}`),this.connected=!1,this.everConnected=!1,this.reconnecting=!1,this.reconnectAttempts=0,this.stopHeartbeat(),this.rejectAllPendingInvokes("disconnect"),this.rejectAllPendingRequests("disconnect"),this.outboundBuffer.length=0,this.ws&&(this.ws.close(1e3,"client disconnect"),this.ws=null)}static MAX_CONSECUTIVE_AUTH_FAILURES=5;async attemptReconnect(){if(this.reconnecting||this.agentDeleted)return;this.reconnecting=!0,a.info("aibot",`attemptReconnect start agent=${this.config.clientType}:${this.config.agentId} fromAttempts=${this.reconnectAttempts}`),this.emit("disconnected");let e=0;for(;this.reconnecting;){const t=Math.min(1e3*2**this.reconnectAttempts,3e4),s=Math.floor(t*.2*Math.random());if(this.reconnectAttempts++,await new Promise(i=>setTimeout(i,t+s)),!this.reconnecting)return;try{await this.connect();const i=this.reconnectAttempts;this.reconnectAttempts=0,this.reconnecting=!1,a.info("aibot",`reconnect succeeded agent=${this.config.clientType}:${this.config.agentId} attempt=${i}`);return}catch(i){if(this.ws){try{this.ws.close()}catch{}this.ws=null}const n=i instanceof Error?i.message:String(i);if(a.warn("aibot",`reconnect failed agent=${this.config.clientType}:${this.config.agentId} attempt=${this.reconnectAttempts} err=${n}`),i instanceof v){this.agentDeleted=!0,this.reconnecting=!1,a.error("aibot",`reconnect aborted: agent deleted on platform agent=${this.config.clientType}:${this.config.agentId}`),this.emit("agentDeleted",{source:"auth_ack",code:p});return}if(/Auth failed/i.test(n)){if(e++,e>=f.MAX_CONSECUTIVE_AUTH_FAILURES){this.reconnecting=!1,a.error("aibot",`reconnect giving up after ${e} consecutive auth failures agent=${this.config.clientType}:${this.config.agentId}`);return}}else e=0}}}sendPacket(e,t,s){if(this.ws&&this.ws.readyState===m.OPEN){const i=this.ws.bufferedAmount>f.BACKPRESSURE_THRESHOLD;if(!i||!f.DROPPABLE_COMMANDS.has(e)){if(i&&f.DROPPABLE_COMMANDS.has(e))return!1;const n=s??++this.seq;if(e==="client_stream_chunk"&&t&&typeof t=="object"){const c=t.event_id;if(c&&(this.seqEventMap.set(n,c),this.seqEventMap.size>200)){const o=this.seqEventMap.keys().next().value;o!==void 0&&this.seqEventMap.delete(o)}}const h={cmd:e,seq:n,payload:t};this.packetLog?.logOutboundPacket(e,n,t,"sent");try{const c=this.ws.readyState,o=this.ws.bufferedAmount;return this.ws.send(JSON.stringify(h),d=>{if(e==="event_result"){const r=t;d?a.warn("aibot",`event_result ws send callback failed event=${r.event_id??""} status=${r.status??""} seq=${n} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`event_result ws send callback ok event=${r.event_id??""} status=${r.status??""} seq=${n} readyState=${c} bufferedAmount=${o}`)}else if(e==="client_stream_chunk"){const r=t;d?a.warn("aibot",`stream_chunk ws send failed event=${r.event_id??""} session=${r.session_id??""} seq=${n} chunk_seq=${r.chunk_seq??""} is_finish=${r.is_finish??""} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`stream_chunk ws send ok event=${r.event_id??""} session=${r.session_id??""} seq=${n} chunk_seq=${r.chunk_seq??""} is_finish=${r.is_finish??""} client_msg_id=${r.client_msg_id??""} quoted_message_id=${r.quoted_message_id??""} readyState=${c} bufferedAmount=${o}`)}else if(e==="event_ack"){const r=t;d?a.warn("aibot",`event_ack ws send failed event=${r.event_id??""} seq=${n} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`event_ack ws send ok event=${r.event_id??""} seq=${n} readyState=${c} bufferedAmount=${o}`)}else if(e==="send_msg"){const r=t;d?a.warn("aibot",`send_msg ws send failed event=${r.event_id??""} session=${r.session_id??""} seq=${n} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`send_msg ws send ok event=${r.event_id??""} session=${r.session_id??""} seq=${n} readyState=${c} bufferedAmount=${o}`)}else if(d){const r=t;a.warn("aibot",`${e} ws send failed seq=${n} session=${r.session_id??""} event=${r.event_id??""} client_msg_id=${r.client_msg_id??""} readyState=${c} bufferedAmount=${o} err=${d.message}`)}}),!0}catch(c){return this.emitClientError(new Error(`sendPacket failed: ${c}`)),!1}}}if(f.DROPPABLE_COMMANDS.has(e))return this.packetLog?.logOutboundPacket(e,s??0,t,"dropped"),!1;if(s!==void 0)return this.packetLog?.logOutboundPacket(e,s,t,"dropped"),!1;if(this.outboundBuffer.length>=f.MAX_OUTBOUND_BUFFER_SIZE&&(this.outboundBuffer=this.outboundBuffer.filter(i=>f.BUFFER_OVERFLOW_RETAIN_COMMANDS.has(i.cmd)),this.outboundBuffer.length>=f.MAX_OUTBOUND_BUFFER_SIZE&&this.outboundBuffer.shift()),this.outboundBuffer.push({cmd:e,payload:t}),this.packetLog?.logOutboundPacket(e,s??0,t,"buffered"),e==="client_stream_chunk"){const i=t;a.info("aibot",`stream_chunk buffered (ws not open) event=${i.event_id??""} session=${i.session_id??""} chunk_seq=${i.chunk_seq??""} is_finish=${i.is_finish??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}return!1}async sendEventResultReliable(e){const t=this.ackPolicy?.max_retries??3,s=this.ackPolicy?.push_ack_timeout_ms??5e3,i=750;for(let n=1;n<=t;n++){const h=this.ws?.readyState??-1,c=this.ws?.bufferedAmount??0;a.info("aibot",`event_result send attempt event=${e.event_id} status=${e.status} attempt=${n}/${t} readyState=${h} bufferedAmount=${c}`);try{const o=await this.sendEventResultRequest(e,s);if(o.cmd==="send_ack"){const r=o.payload;a.info("aibot",`event_result ack event=${e.event_id} status=${e.status} attempt=${n}/${t} ack_event=${r.event_id??""} ack_status=${r.status??""}`);return}const d=o.payload;if(a.warn("aibot",`event_result rejected event=${e.event_id} status=${e.status} attempt=${n}/${t} cmd=${o.cmd} code=${d.code??""} msg=${d.msg??""}${d.ref_cmd?` ref_cmd=${d.ref_cmd}`:""}${d.ref_id?` ref_id=${d.ref_id}`:""}`),d.code===4003){a.warn("aibot",`event_result stopping retries: 4003 ownership denied event=${e.event_id}`);return}return}catch(o){const d=o instanceof Error?o.message:String(o);if(a.warn("aibot",`event_result attempt failed event=${e.event_id} status=${e.status} attempt=${n}/${t} err=${d}`),n===t){this.emitClientError(new Error(`event_result ack failed after ${t} attempts: event=${e.event_id} status=${e.status}`));return}await new Promise(r=>setTimeout(r,i*n))}}}purgeBufferedStreamChunks(e){const t=this.outboundBuffer.length;this.outboundBuffer=this.outboundBuffer.filter(s=>s.cmd!=="client_stream_chunk"?!0:s.payload?.event_id!==e),this.outboundBuffer.length<t&&a.info("aibot",`purged ${t-this.outboundBuffer.length} buffered stream chunks for event=${e}`)}emitClientError(e){if(this.listenerCount("error")===0){a.warn("aibot",`Client error (no listeners): ${e.message}`);return}this.emit("error",e)}flushOutboundBuffer(){if(this.outboundBuffer.length===0||!this.ws||this.ws.readyState!==m.OPEN)return;const e=this.outboundBuffer;this.outboundBuffer=[];for(const{cmd:t,payload:s}of e){const i=++this.seq;if(t==="client_stream_chunk"&&s&&typeof s=="object"){const h=s.event_id;h&&this.seqEventMap.set(i,h)}const n={cmd:t,seq:i,payload:s};try{this.ws.send(JSON.stringify(n))}catch{break}}if(this.seqEventMap.size>200){const t=[...this.seqEventMap.entries()].sort((s,i)=>s[0]-i[0]);this.seqEventMap.clear();for(const[s,i]of t.slice(-100))this.seqEventMap.set(s,i)}}handleInvokeResult(e){const t=this.pendingInvokes.get(e.invoke_id);t&&(this.pendingInvokes.delete(e.invoke_id),clearTimeout(t.timer),e.code===0?t.resolve(e.data??null):t.reject(new Error(`agent_invoke error code=${e.code}: ${e.msg??""}`)))}rejectAllPendingInvokes(e){for(const[,t]of this.pendingInvokes)clearTimeout(t.timer),t.reject(new Error(`agent_invoke canceled: ${e}`));this.pendingInvokes.clear()}rejectAllPendingRequests(e){for(const[,t]of this.pendingRequests)clearTimeout(t.timer),t.reject(new Error(`request canceled: ${e}`));this.pendingRequests.clear()}cleanupSocket(){if(this.ws)try{this.ws.close()}catch{}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatFailures=0,this.heartbeatTimer=setInterval(()=>{this.connected&&this.request("ping",{ts:Date.now()},{expected:["pong"],timeoutMs:5e3}).then(()=>{this.heartbeatFailures=0}).catch(()=>{this.connected&&(this.heartbeatFailures++,!(this.heartbeatFailures<f.HEARTBEAT_MAX_FAILURES)&&(this.cleanupSocket(),this.attemptReconnect()))})},this.heartbeatSec*1e3)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}}export{f as AibotClient};
|
|
1
|
+
import{EventEmitter as $}from"node:events";import{randomUUID as b}from"node:crypto";import k from"node:os";import m from"ws";import{log as a}from"../log/index.js";import{getMachineName as w}from"../util/index.js";import{detectTailnetIPv4 as E,ensureServerAndGetPort as q,getFileServerHttpsPort as y}from"../files/file-serve.js";import{AUTH_CODE_AGENT_DELETED as p,KICKED_REASON_AGENT_DELETED as S,AgentDeletedError as v,RequestTimeoutError as A}from"./errors.js";function R(g){return g.replace(/(?<=[\[:,\[]\s*)(\d{16,})(?=\s*[,}\]\n])/g,'"$1"')}function P(g){const e=[...g??["stream_chunk","local_action_v1","agent_invoke"]];return e.includes("agent_invoke")||e.push("agent_invoke"),e.includes("event_result_ack")||e.push("event_result_ack"),e.includes("audit_replay_v2")||e.push("audit_replay_v2"),e}const T="aibot-agent-api-v1",I=1;class _ extends ${static DROPPABLE_COMMANDS=new Set(["update_binding_card"]);static BUFFER_OVERFLOW_RETAIN_COMMANDS=new Set(["event_result","codex_event","client_stream_chunk","audit_state"]);static MAX_OUTBOUND_BUFFER_SIZE=1e3;static BACKPRESSURE_THRESHOLD=64*1024;ws=null;seq=0;heartbeatTimer=null;heartbeatSec=30;heartbeatFailures=0;static HEARTBEAT_MAX_FAILURES=2;connected=!1;reconnecting=!1;reconnectAttempts=0;everConnected=!1;agentDeleted=!1;config;packetLog;pendingInvokes=new Map;seqEventMap=new Map;pendingRequests=new Map;outboundBuffer=[];ackPolicy=null;constructor(e,t){super(),this.packetLog=t?.packetLog??null,this.config={url:e.url,agentId:e.agentId,apiKey:e.apiKey,clientType:e.clientType,clientVersion:e.clientVersion??"",adapterHint:e.adapterHint??"",capabilities:P(e.capabilities),localActions:e.localActions??["exec_approve","exec_reject"],skills:e.skills,librarySkills:e.librarySkills}}get isConnected(){return this.connected}async connect(){let e,t,s;const i=(async()=>{try{if(e=await E(),e!==void 0)try{t=await q(e);const n=y();n>0&&(s=n)}catch(n){a.warn("aibot",`file server pre-start failed: ${n}`)}}catch(n){a.warn("aibot",`tailnet detect failed: ${n}`)}})();return new Promise((n,h)=>{const c=new m(this.config.url);this.ws=c;const o=setTimeout(()=>{h(new Error("Auth timeout: no auth_ack received within 15s")),this.cleanupSocket()},15e3),d=++this.seq,r=setTimeout(()=>{this.pendingRequests.delete(d),h(new Error("Auth request timeout")),this.cleanupSocket()},15e3);this.pendingRequests.set(d,{expected:["auth_ack"],resolve:u=>{clearTimeout(o);const l=u.payload;l.code===0?(this.connected=!0,this.everConnected=!0,this.reconnectAttempts=0,l.heartbeat_sec&&(this.heartbeatSec=l.heartbeat_sec),l.ack_policy&&(this.ackPolicy=l.ack_policy,a.info("aibot",`ack_policy received: push_ack_timeout_ms=${l.ack_policy.push_ack_timeout_ms??"default"} max_retries=${l.ack_policy.max_retries??"default"} timeout_action=${l.ack_policy.timeout_action??"default"}`)),this.startHeartbeat(),this.flushOutboundBuffer(),this.emit("auth",l),n(l)):l.code===p?(this.agentDeleted=!0,h(new v(`Agent deleted: code=${l.code} msg=${l.msg}`))):h(new Error(`Auth failed: code=${l.code} msg=${l.msg}`))},reject:u=>{clearTimeout(o),h(u)},timer:r}),c.on("open",async()=>{await i;const u={agent_id:this.config.agentId,api_key:this.config.apiKey,client_type:this.config.clientType,protocol_version:T,contract_version:I,capabilities:this.config.capabilities??[],local_actions:this.config.localActions,skills:this.config.skills,library_skills:this.config.librarySkills};this.config.sharedOwnerId&&(u.shared_owner_id=this.config.sharedOwnerId),this.config.clientVersion&&(u.client="grix-connector",u.client_version=this.config.clientVersion,u.host_type=this.config.clientType,u.host_version=this.config.clientVersion),this.config.adapterHint&&(u.adapter_hint=this.config.adapterHint),u.host_meta={hostname:w(),platform:k.platform(),arch:k.arch(),os_release:k.release(),...e!==void 0&&{tailnet_ip:e},...t!==void 0&&t>0&&{file_server_port:t},...s!==void 0&&s>0&&{file_server_https_port:s}},this.config.concurrency&&(u.concurrency=this.config.concurrency),this.sendPacket("auth",u,d)}),c.on("message",u=>{if(this.ws!==c)return;let l;try{l=JSON.parse(R(u.toString()))}catch{return}try{this.handlePacket(l)}catch(f){this.emitClientError(new Error(`handlePacket error: ${f}`))}}),c.on("close",(u,l)=>{if(this.ws!==c)return;this.connected=!1,this.stopHeartbeat(),this.rejectAllPendingRequests("websocket closed"),this.emit("close",u,l.toString());const f=u!==1e3&&this.everConnected&&!this.agentDeleted;a.info("aibot",`ws closed agent=${this.config.clientType}:${this.config.agentId} code=${u} reason=${l.toString()||"<none>"} everConnected=${this.everConnected} reconnecting=${this.reconnecting} agentDeleted=${this.agentDeleted} willReconnect=${f}`),f&&this.attemptReconnect()}),c.on("error",u=>{this.ws===c&&(this.emitClientError(u instanceof Error?u:new Error(String(u))),this.connected||h(u))})})}handlePacket(e){if(this.packetLog?.logInboundPacket(e.cmd,e.seq,e.payload),e.seq>0&&this.pendingRequests.has(e.seq)){const t=this.pendingRequests.get(e.seq);this.pendingRequests.delete(e.seq),clearTimeout(t.timer),t.expected.includes(e.cmd)?t.resolve(e):t.reject(new Error(`unexpected response: got ${e.cmd}, expected ${t.expected.join("/")}`));return}switch(e.cmd){case"auth_ack":break;case"ping":{this.sendPacket("pong",e.payload??{});break}case"event_msg":{this.emit("event",e.payload);break}case"local_action":{this.emit("localAction",e.payload);break}case"event_stop":{this.emit("stop",e.payload);break}case"event_revoke":{this.emit("revoke",e.payload);break}case"event_edit":{this.emit("edit",e.payload);break}case"event_cancel":{this.emit("eventCancel",e.payload);break}case"queue_clear":{this.emit("queueClear",e.payload);break}case"queue_reorder":{this.emit("queueReorder",e.payload);break}case"queue_snapshot_query":{this.emit("queueSnapshotQuery",e.payload);break}case"event_hold":{this.emit("eventHold",e.payload);break}case"queue_edit":{this.emit("queueEdit",e.payload);break}case"control_share_set":{this.emit("shareSet",e.payload);break}case"agent_profile_push":{this.emit("profilePush",e.payload);break}case"skill_sync":{this.emit("skillSync",e.payload);break}case"kicked":{const t=e.payload;if(this.emit("kicked",t),this.connected=!1,this.stopHeartbeat(),this.rejectAllPendingRequests("kicked"),this.outboundBuffer.length=0,t?.reason===S){if(this.agentDeleted=!0,this.reconnecting=!1,this.ws){try{this.ws.close(4001,"kicked")}catch{}this.ws=null}a.error("aibot",`kicked: agent deleted on platform agent=${this.config.clientType}:${this.config.agentId}, reconnect disabled`),this.emit("agentDeleted",{source:"kicked",reason:t.reason});break}if(this.reconnectAttempts=Math.max(this.reconnectAttempts,3),this.ws){try{this.ws.close(4001,"kicked")}catch{}this.ws=null}break}case"error":{const t=e.payload,s=[t.ref_cmd?`ref_cmd=${t.ref_cmd}`:"",t.ref_id?`ref_id=${t.ref_id}`:""].filter(Boolean).join(" ");this.emitClientError(new Error(`Server error: code=${t.code} msg=${t.msg}${s?` ${s}`:""}`));break}case"agent_invoke_result":{this.handleInvokeResult(e.payload);break}case"mcp_frame":{const t=e.payload;this.emit("mcpFrame",t.session_id??"",t.frame??null);break}case"send_ack":break;case"send_nack":{const t=e.payload;if(t.code===4003&&e.seq>0){const s=this.seqEventMap.get(e.seq);s&&(this.seqEventMap.delete(e.seq),this.purgeBufferedStreamChunks(s),a.warn("aibot",`stream chunk rejected (4003), purging buffered chunks for event=${s}`),this.emit("streamRejected",s,t.code))}break}case"local_action_ack":break;default:break}}sendEventAck(e){this.sendPacket("event_ack",e)||a.warn("aibot",`event_ack NOT sent (ws not open) event=${e.event_id} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}sendStreamChunk(e){!e.delta_content&&!e.is_finish&&(a.warn("aibot",`stream_chunk delta_content empty, patched to newline event=${e.event_id??""} session=${e.session_id} chunk_seq=${e.chunk_seq} is_finish=${e.is_finish}`),e={...e,delta_content:`
|
|
2
|
+
`}),this.sendPacket("client_stream_chunk",e)}sendMsg(e){this.sendPacket("send_msg",e)||a.warn("aibot",`send_msg NOT sent (ws not open) event=${e.event_id??""} session=${e.session_id??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}editMsg(e){this.sendPacket("edit_msg",e)}sendEventResult(e){if(!this.ws||this.ws.readyState!==m.OPEN){this.sendPacket("event_result",e);return}this.sendEventResultReliable(e)}sendLocalActionResult(e){this.sendPacket("local_action_result",e)}sendEventStopAck(e){this.sendPacket("event_stop_ack",e)}sendEventStopResult(e){this.sendPacket("event_stop_result",e)}sendSessionActivitySet(e){this.sendPacket("session_activity_set",e)}sendCodexEvent(e){this.sendPacket("codex_event",e)}sendUpdateBindingCard(e){this.sendPacket("update_binding_card",e)}sendAuditState(e){this.sendPacket("audit_state",e)}sendSkillsUpdate(e){this.sendPacket("agent_skills_update",e)}sendPing(){this.sendPacket("ping",{})}sendEventState(e){this.sendPacket("event_state",e)}sendEventCancelResult(e){this.sendPacket("event_cancel_result",e)}sendQueueClearResult(e){this.sendPacket("queue_clear_result",e)}sendQueueReorderResult(e){this.sendPacket("queue_reorder_result",e)}sendEventHoldResult(e){this.sendPacket("event_hold_result",e)}sendQueueEditResult(e){this.sendPacket("queue_edit_result",e)}sendQueueSnapshot(e){this.sendPacket("queue_snapshot",e)}agentInvoke(e,t,s=15e3){return new Promise((i,n)=>{const h=b(),c=Math.max(1e3,Math.min(s,6e4)),o=setTimeout(()=>{this.pendingInvokes.delete(h),n(new Error(`agent_invoke timeout: ${e}`))},c);this.pendingInvokes.set(h,{resolve:i,reject:n,timer:o}),this.sendPacket("agent_invoke",{invoke_id:h,action:e,params:t,timeout_ms:c})})}sendMcpFrame(e,t){this.sendPacket("mcp_frame",{session_id:e,frame:t})}request(e,t,s){return new Promise((i,n)=>{const h=++this.seq,c=setTimeout(()=>{this.pendingRequests.delete(h),n(new A(`request timeout: ${e} (expected ${s.expected.join("/")})`))},s.timeoutMs);this.pendingRequests.set(h,{expected:s.expected,resolve:i,reject:n,timer:c}),this.sendPacket(e,t,h)||(this.pendingRequests.delete(h),clearTimeout(c),n(new Error(`send failed: ${e}`)))})}async sendStreamChunkRequest(e,t=2e4){return this.request("client_stream_chunk",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}async relayCredentialRequest(e,t=15e3){return this.request("relay_credential_request",e,{expected:["relay_credential_result","error"],timeoutMs:t})}async sendText(e,t=2e4){return this.request("send_msg",{msg_type:1,...e},{expected:["send_ack","send_nack","error"],timeoutMs:t})}async sendMedia(e,t=2e4){return this.request("send_msg",{...e,msg_type:2},{expected:["send_ack","send_nack","error"],timeoutMs:t})}async editMessage(e,t=2e4){return this.request("edit_msg",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}async deleteMessage(e,t,s=2e4){return this.request("delete_msg",{session_id:e,msg_id:t},{expected:["send_ack","send_nack","error"],timeoutMs:s})}async sendEventResultRequest(e,t=5e3){return this.request("event_result",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}disconnect(){a.info("aibot",`disconnect() agent=${this.config.clientType}:${this.config.agentId} wasConnected=${this.connected} reconnecting=${this.reconnecting} reconnectAttempts=${this.reconnectAttempts}`),this.connected=!1,this.everConnected=!1,this.reconnecting=!1,this.reconnectAttempts=0,this.stopHeartbeat(),this.rejectAllPendingInvokes("disconnect"),this.rejectAllPendingRequests("disconnect"),this.outboundBuffer.length=0,this.ws&&(this.ws.close(1e3,"client disconnect"),this.ws=null)}static MAX_CONSECUTIVE_AUTH_FAILURES=5;async attemptReconnect(){if(this.reconnecting||this.agentDeleted)return;this.reconnecting=!0,a.info("aibot",`attemptReconnect start agent=${this.config.clientType}:${this.config.agentId} fromAttempts=${this.reconnectAttempts}`),this.emit("disconnected");let e=0;for(;this.reconnecting;){const t=Math.min(1e3*2**this.reconnectAttempts,3e4),s=Math.floor(t*.2*Math.random());if(this.reconnectAttempts++,await new Promise(i=>setTimeout(i,t+s)),!this.reconnecting)return;try{await this.connect();const i=this.reconnectAttempts;this.reconnectAttempts=0,this.reconnecting=!1,a.info("aibot",`reconnect succeeded agent=${this.config.clientType}:${this.config.agentId} attempt=${i}`);return}catch(i){if(this.ws){try{this.ws.close()}catch{}this.ws=null}const n=i instanceof Error?i.message:String(i);if(a.warn("aibot",`reconnect failed agent=${this.config.clientType}:${this.config.agentId} attempt=${this.reconnectAttempts} err=${n}`),i instanceof v){this.agentDeleted=!0,this.reconnecting=!1,a.error("aibot",`reconnect aborted: agent deleted on platform agent=${this.config.clientType}:${this.config.agentId}`),this.emit("agentDeleted",{source:"auth_ack",code:p});return}if(/Auth failed/i.test(n)){if(e++,e>=_.MAX_CONSECUTIVE_AUTH_FAILURES){this.reconnecting=!1,a.error("aibot",`reconnect giving up after ${e} consecutive auth failures agent=${this.config.clientType}:${this.config.agentId}`);return}}else e=0}}}sendPacket(e,t,s){if(this.ws&&this.ws.readyState===m.OPEN){const i=this.ws.bufferedAmount>_.BACKPRESSURE_THRESHOLD;if(!i||!_.DROPPABLE_COMMANDS.has(e)){if(i&&_.DROPPABLE_COMMANDS.has(e))return!1;const n=s??++this.seq;if(e==="client_stream_chunk"&&t&&typeof t=="object"){const c=t.event_id;if(c&&(this.seqEventMap.set(n,c),this.seqEventMap.size>200)){const o=this.seqEventMap.keys().next().value;o!==void 0&&this.seqEventMap.delete(o)}}const h={cmd:e,seq:n,payload:t};this.packetLog?.logOutboundPacket(e,n,t,"sent");try{const c=this.ws.readyState,o=this.ws.bufferedAmount;return this.ws.send(JSON.stringify(h),d=>{if(e==="event_result"){const r=t;d?a.warn("aibot",`event_result ws send callback failed event=${r.event_id??""} status=${r.status??""} seq=${n} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`event_result ws send callback ok event=${r.event_id??""} status=${r.status??""} seq=${n} readyState=${c} bufferedAmount=${o}`)}else if(e==="client_stream_chunk"){const r=t;d?a.warn("aibot",`stream_chunk ws send failed event=${r.event_id??""} session=${r.session_id??""} seq=${n} chunk_seq=${r.chunk_seq??""} is_finish=${r.is_finish??""} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`stream_chunk ws send ok event=${r.event_id??""} session=${r.session_id??""} seq=${n} chunk_seq=${r.chunk_seq??""} is_finish=${r.is_finish??""} client_msg_id=${r.client_msg_id??""} quoted_message_id=${r.quoted_message_id??""} readyState=${c} bufferedAmount=${o}`)}else if(e==="event_ack"){const r=t;d?a.warn("aibot",`event_ack ws send failed event=${r.event_id??""} seq=${n} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`event_ack ws send ok event=${r.event_id??""} seq=${n} readyState=${c} bufferedAmount=${o}`)}else if(e==="send_msg"){const r=t;d?a.warn("aibot",`send_msg ws send failed event=${r.event_id??""} session=${r.session_id??""} seq=${n} readyState=${c} bufferedAmount=${o} err=${d.message}`):a.info("aibot",`send_msg ws send ok event=${r.event_id??""} session=${r.session_id??""} seq=${n} readyState=${c} bufferedAmount=${o}`)}else if(d){const r=t;a.warn("aibot",`${e} ws send failed seq=${n} session=${r.session_id??""} event=${r.event_id??""} client_msg_id=${r.client_msg_id??""} readyState=${c} bufferedAmount=${o} err=${d.message}`)}}),!0}catch(c){return this.emitClientError(new Error(`sendPacket failed: ${c}`)),!1}}}if(_.DROPPABLE_COMMANDS.has(e))return this.packetLog?.logOutboundPacket(e,s??0,t,"dropped"),!1;if(s!==void 0)return this.packetLog?.logOutboundPacket(e,s,t,"dropped"),!1;if(this.outboundBuffer.length>=_.MAX_OUTBOUND_BUFFER_SIZE&&(this.outboundBuffer=this.outboundBuffer.filter(i=>_.BUFFER_OVERFLOW_RETAIN_COMMANDS.has(i.cmd)),this.outboundBuffer.length>=_.MAX_OUTBOUND_BUFFER_SIZE&&this.outboundBuffer.shift()),this.outboundBuffer.push({cmd:e,payload:t}),this.packetLog?.logOutboundPacket(e,s??0,t,"buffered"),e==="client_stream_chunk"){const i=t;a.info("aibot",`stream_chunk buffered (ws not open) event=${i.event_id??""} session=${i.session_id??""} chunk_seq=${i.chunk_seq??""} is_finish=${i.is_finish??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}return!1}async sendEventResultReliable(e){const t=this.ackPolicy?.max_retries??3,s=this.ackPolicy?.push_ack_timeout_ms??5e3,i=750;for(let n=1;n<=t;n++){const h=this.ws?.readyState??-1,c=this.ws?.bufferedAmount??0;a.info("aibot",`event_result send attempt event=${e.event_id} status=${e.status} attempt=${n}/${t} readyState=${h} bufferedAmount=${c}`);try{const o=await this.sendEventResultRequest(e,s);if(o.cmd==="send_ack"){const r=o.payload;a.info("aibot",`event_result ack event=${e.event_id} status=${e.status} attempt=${n}/${t} ack_event=${r.event_id??""} ack_status=${r.status??""}`);return}const d=o.payload;if(a.warn("aibot",`event_result rejected event=${e.event_id} status=${e.status} attempt=${n}/${t} cmd=${o.cmd} code=${d.code??""} msg=${d.msg??""}${d.ref_cmd?` ref_cmd=${d.ref_cmd}`:""}${d.ref_id?` ref_id=${d.ref_id}`:""}`),d.code===4003){a.warn("aibot",`event_result stopping retries: 4003 ownership denied event=${e.event_id}`);return}return}catch(o){const d=o instanceof Error?o.message:String(o);if(a.warn("aibot",`event_result attempt failed event=${e.event_id} status=${e.status} attempt=${n}/${t} err=${d}`),n===t){this.emitClientError(new Error(`event_result ack failed after ${t} attempts: event=${e.event_id} status=${e.status}`));return}await new Promise(r=>setTimeout(r,i*n))}}}purgeBufferedStreamChunks(e){const t=this.outboundBuffer.length;this.outboundBuffer=this.outboundBuffer.filter(s=>s.cmd!=="client_stream_chunk"?!0:s.payload?.event_id!==e),this.outboundBuffer.length<t&&a.info("aibot",`purged ${t-this.outboundBuffer.length} buffered stream chunks for event=${e}`)}emitClientError(e){if(this.listenerCount("error")===0){a.warn("aibot",`Client error (no listeners): ${e.message}`);return}this.emit("error",e)}flushOutboundBuffer(){if(this.outboundBuffer.length===0||!this.ws||this.ws.readyState!==m.OPEN)return;const e=this.outboundBuffer;this.outboundBuffer=[];for(const{cmd:t,payload:s}of e){const i=++this.seq;if(t==="client_stream_chunk"&&s&&typeof s=="object"){const h=s.event_id;h&&this.seqEventMap.set(i,h)}const n={cmd:t,seq:i,payload:s};try{this.ws.send(JSON.stringify(n))}catch{break}}if(this.seqEventMap.size>200){const t=[...this.seqEventMap.entries()].sort((s,i)=>s[0]-i[0]);this.seqEventMap.clear();for(const[s,i]of t.slice(-100))this.seqEventMap.set(s,i)}}handleInvokeResult(e){const t=this.pendingInvokes.get(e.invoke_id);t&&(this.pendingInvokes.delete(e.invoke_id),clearTimeout(t.timer),e.code===0?t.resolve(e.data??null):t.reject(new Error(`agent_invoke error code=${e.code}: ${e.msg??""}`)))}rejectAllPendingInvokes(e){for(const[,t]of this.pendingInvokes)clearTimeout(t.timer),t.reject(new Error(`agent_invoke canceled: ${e}`));this.pendingInvokes.clear()}rejectAllPendingRequests(e){for(const[,t]of this.pendingRequests)clearTimeout(t.timer),t.reject(new Error(`request canceled: ${e}`));this.pendingRequests.clear()}cleanupSocket(){if(this.ws)try{this.ws.close()}catch{}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatFailures=0,this.heartbeatTimer=setInterval(()=>{this.connected&&this.request("ping",{ts:Date.now()},{expected:["pong"],timeoutMs:5e3}).then(()=>{this.heartbeatFailures=0}).catch(()=>{this.connected&&(this.heartbeatFailures++,!(this.heartbeatFailures<_.HEARTBEAT_MAX_FAILURES)&&(this.cleanupSocket(),this.attemptReconnect()))})},this.heartbeatSec*1e3)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}}export{_ as AibotClient};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
class r{client;_status="ready";connectedAt;listeners=[];authAck=null;constructor(e){this.client=e,this.connectedAt=Date.now(),this.addInternalListener("close",()=>{this._status!=="closing"&&(this._status="reconnecting")}),this.addInternalListener("auth",t=>{this._status="ready",t&&(this.authAck=t)}),this.addInternalListener("disconnected",()=>{this._status!=="closing"&&this._status!=="closed"&&(this._status="reconnecting")})}get status(){return this._status}getStatusSnapshot(){return{status:this._status,connectedAt:this.connectedAt,reconnectAttempts:0}}sendEventAck(e){this.client.sendEventAck(e)}sendStreamChunk(e){this.client.sendStreamChunk(e)}sendMsg(e){this.client.sendMsg(e)}editMsg(e){this.client.editMsg(e)}sendEventResult(e){this.client.sendEventResult(e)}sendLocalActionResult(e){this.client.sendLocalActionResult(e)}sendEventStopAck(e){this.client.sendEventStopAck(e)}sendEventStopResult(e){this.client.sendEventStopResult(e)}sendSessionActivitySet(e){this.client.sendSessionActivitySet(e)}sendCodexEvent(e){this.client.sendCodexEvent(e)}sendUpdateBindingCard(e){this.client.sendUpdateBindingCard(e)}sendSkillsUpdate(e){this.client.sendSkillsUpdate(e)}sendPing(){this.client.sendPing()}sendEventState(e){this.client.sendEventState(e)}sendEventCancelResult(e){this.client.sendEventCancelResult(e)}sendQueueClearResult(e){this.client.sendQueueClearResult(e)}sendQueueReorderResult(e){this.client.sendQueueReorderResult(e)}sendEventHoldResult(e){this.client.sendEventHoldResult(e)}sendQueueEditResult(e){this.client.sendQueueEditResult(e)}sendQueueSnapshot(e){this.client.sendQueueSnapshot(e)}agentInvoke(e,t,s){return this.client.agentInvoke(e,t,s)}sendStreamChunkRequest(e,t){return this.client.sendStreamChunkRequest(e,t)}sendText(e,t){return this.client.sendText(e,t)}sendMedia(e,t){return this.client.sendMedia(e,t)}editMessage(e,t){return this.client.editMessage(e,t)}deleteMessage(e,t,s){return this.client.deleteMessage(e,t,s)}sendEventResultRequest(e,t){return this.client.sendEventResultRequest(e,t)}sendCodexEventReliable(e,t){
|
|
1
|
+
class r{client;_status="ready";connectedAt;listeners=[];authAck=null;constructor(e){this.client=e,this.connectedAt=Date.now(),this.addInternalListener("close",()=>{this._status!=="closing"&&(this._status="reconnecting")}),this.addInternalListener("auth",t=>{this._status="ready",t&&(this.authAck=t)}),this.addInternalListener("disconnected",()=>{this._status!=="closing"&&this._status!=="closed"&&(this._status="reconnecting")})}get status(){return this._status}getStatusSnapshot(){return{status:this._status,connectedAt:this.connectedAt,reconnectAttempts:0}}sendEventAck(e){this.client.sendEventAck(e)}sendStreamChunk(e){this.client.sendStreamChunk(e)}sendMsg(e){this.client.sendMsg(e)}editMsg(e){this.client.editMsg(e)}sendEventResult(e){this.client.sendEventResult(e)}sendLocalActionResult(e){this.client.sendLocalActionResult(e)}sendEventStopAck(e){this.client.sendEventStopAck(e)}sendEventStopResult(e){this.client.sendEventStopResult(e)}sendSessionActivitySet(e){this.client.sendSessionActivitySet(e)}sendCodexEvent(e){this.client.sendCodexEvent(e)}sendUpdateBindingCard(e){this.client.sendUpdateBindingCard(e)}sendAuditState(e){this.client.sendAuditState(e)}sendSkillsUpdate(e){this.client.sendSkillsUpdate(e)}sendPing(){this.client.sendPing()}sendEventState(e){this.client.sendEventState(e)}sendEventCancelResult(e){this.client.sendEventCancelResult(e)}sendQueueClearResult(e){this.client.sendQueueClearResult(e)}sendQueueReorderResult(e){this.client.sendQueueReorderResult(e)}sendEventHoldResult(e){this.client.sendEventHoldResult(e)}sendQueueEditResult(e){this.client.sendQueueEditResult(e)}sendQueueSnapshot(e){this.client.sendQueueSnapshot(e)}agentInvoke(e,t,s){return this.client.agentInvoke(e,t,s)}sendStreamChunkRequest(e,t){return this.client.sendStreamChunkRequest(e,t)}sendText(e,t){return this.client.sendText(e,t)}sendMedia(e,t){return this.client.sendMedia(e,t)}editMessage(e,t){return this.client.editMessage(e,t)}deleteMessage(e,t,s){return this.client.deleteMessage(e,t,s)}sendEventResultRequest(e,t){return this.client.sendEventResultRequest(e,t)}async sendCodexEventReliable(e,t){const s=await this.client.request("codex_event",e,{expected:["send_ack","send_nack","error"],timeoutMs:t??2e4});if(s.cmd!=="send_ack"){const n=s.payload;throw new Error(`codex_event ${s.cmd} code=${String(n?.code??"")} msg=${String(n?.msg??"")}`)}return s}relayCredentialRequest(e,t){return this.client.relayCredentialRequest(e,t)}onEvent(e){return this.subscribe("event",e)}onLocalAction(e){return this.subscribe("localAction",e)}onStop(e){return this.subscribe("stop",e)}onRevoke(e){return this.subscribe("revoke",e)}onEdit(e){return this.subscribe("edit",e)}onEventCancel(e){return this.subscribe("eventCancel",e)}onQueueClear(e){return this.subscribe("queueClear",e)}onQueueReorder(e){return this.subscribe("queueReorder",e)}onQueueSnapshotQuery(e){return this.subscribe("queueSnapshotQuery",e)}onEventHold(e){return this.subscribe("eventHold",e)}onQueueEdit(e){return this.subscribe("queueEdit",e)}onKicked(e){return this.subscribe("kicked",e)}onAgentDeleted(e){return this.subscribe("agentDeleted",e)}onShareSet(e){return this.subscribe("shareSet",e)}onProfilePush(e){return this.subscribe("profilePush",e)}onSkillSync(e){return this.subscribe("skillSync",e)}onError(e){return this.subscribe("error",e)}onClose(e){return this.subscribe("close",e)}onDisconnected(e){return this.subscribe("disconnected",e)}onStreamRejected(e){return this.subscribe("streamRejected",e)}onReconnected(e){return this.subscribe("auth",e)}disconnect(){this._status="closing",this.removeAllListeners(),this.client.disconnect(),this._status="closed"}sendMcpFrame(e,t){this.client.sendMcpFrame(e,t)}onMcpFrame(e){return this.subscribe("mcpFrame",e)}subscribe(e,t){return this.client.on(e,t),this.listeners.push({event:e,handler:t}),()=>{this.client.removeListener(e,t);const s=this.listeners.findIndex(n=>n.event===e&&n.handler===t);s>=0&&this.listeners.splice(s,1)}}addInternalListener(e,t){this.client.on(e,t),this.listeners.push({event:e,handler:t})}removeAllListeners(){for(const{event:e,handler:t}of this.listeners)this.client.removeListener(e,t);this.listeners.length=0}}export{r as AibotConnectionHandleImpl};
|
package/dist/core/aibot/types.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const _=["audit_get_manifest","audit_list_spans","audit_get_content_chunk"],t={invalidParams:"AUDIT_INVALID_PARAMS",notFound:"AUDIT_NOT_FOUND",revisionNotFound:"AUDIT_REVISION_NOT_FOUND",cursorInvalid:"AUDIT_CURSOR_INVALID",contentForbidden:"AUDIT_CONTENT_FORBIDDEN",contentNotFound:"AUDIT_CONTENT_NOT_FOUND",contentCorrupt:"AUDIT_CONTENT_CORRUPT",internal:"AUDIT_INTERNAL"};export{t as AUDIT_LOCAL_ACTION_ERROR_CODES,_ as AUDIT_LOCAL_ACTION_TYPES};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const s={qwen:{baseUrl:"OPENAI_BASE_URL",apiKey:"OPENAI_API_KEY",model:"OPENAI_MODEL"},reasonix:{baseUrl:"DEEPSEEK_BASE_URL",apiKey:"DEEPSEEK_API_KEY"},codewhale:{apiKey:"OPENAI_API_KEY"},hermes:{baseUrl:"GRIX_HERMES_BASE_URL",apiKey:"GRIX_PROVIDER_API_KEY",model:"HERMES_INFERENCE_MODEL",fixed:{HERMES_INFERENCE_PROVIDER:"grix"}},pi:{apiKey:"GRIX_PROVIDER_API_KEY"}},_=["qwen","reasonix","codewhale","hermes","pi","opencode"],a=["kiro"];function R(e){const r=e?.trim().toLowerCase();return!!r&&_.includes(r)}function p(e){const r=e?.trim().toLowerCase();return!!r&&a.includes(r)}function I(e){return R(e)||p(e)}function P(e){return!!e&&e.trim().toLowerCase()in s}function c(e,r){if(!r)return{};const o=s[e?.trim().toLowerCase()??""];if(!o)return{};const t=r.baseUrl?.trim(),i=r.apiKey?.trim(),n=r.model?.trim();if(!t&&!i&&!n)return{};const E={...o.fixed??{}};return o.baseUrl&&t&&(E[o.baseUrl]=t),o.apiKey&&i&&(E[o.apiKey]=i),o.model&&n&&(E[o.model]=n),E}export{_ as DIRECT_PROVIDER_CLIENT_TYPES,a as KIRO_CW_RELAY_CLIENT_TYPES,s as PROVIDER_ENV_SPECS,c as buildProviderEnv,R as supportsDirectProviderConfig,p as supportsKiroCwRelay,I as supportsNonMitmRelayConfig,P as supportsProviderEnv};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import y from"node:http";import{randomBytes as O}from"node:crypto";import{log as c}from"../log/index.js";import{PHASE1_INVOKE_ACTIONS as S}from"./tools.js";import{WebSocketServer as w,WebSocket as k}from"ws";const f=1024*1024,v=32*1024*1024,H=50,b=1e3,g=6e4,N=256,J=new Set([...S,"event_tool_call"]);class E{server=null;port=0;authToken;invokeHandler=null;statusLineHandler=null;otelHandler=null;activeInvokes=0;wss=null;bridgeWs=null;mcpBridgeUpHandler=null;downstreamOutbox=[];constructor(){this.authToken=O(32).toString("hex")}setInvokeHandler(e){this.invokeHandler=e}setStatusLineHandler(e){this.statusLineHandler=e}setOtelHandler(e){this.otelHandler=e}async start(e=0){return new Promise((t,r)=>{this.server=y.createServer((o,i)=>this.handleRequest(o,i)),this.wss=new w({noServer:!0}),this.server.on("upgrade",(o,i,n)=>{const s=new URL(o.url??"/",`http://127.0.0.1:${this.port}`);if(s.pathname!=="/mcp-bridge"||s.searchParams.get("token")!==this.authToken){i.destroy();return}this.wss.handleUpgrade(o,i,n,d=>{if(this.bridgeWs=d,c.info("internal-api","mcp bridge connected"),this.downstreamOutbox.length>0){const a=this.downstreamOutbox;this.downstreamOutbox=[];for(const l of a)d.send(l);c.info("internal-api",`mcp bridge flushed ${a.length} buffered downstream frame(s)`)}d.on("message",a=>{let l;try{l=JSON.parse(a.toString("utf8"))}catch{return}this.mcpBridgeUpHandler?.(l)}),d.on("close",()=>{this.bridgeWs===d&&(this.bridgeWs=null),c.info("internal-api","mcp bridge disconnected")}),d.on("error",()=>{})})}),this.server.on("error",r),this.server.listen(e,"127.0.0.1",()=>{const o=this.server.address();typeof o=="object"&&o&&(this.port=o.port),this.server.removeListener("error",r),t(this.port)})})}get url(){return`http://127.0.0.1:${this.port}?token=${this.authToken}`}get baseUrl(){return`http://127.0.0.1:${this.port}`}get mcpBridgeWsUrl(){return`ws://127.0.0.1:${this.port}/mcp-bridge?token=${this.authToken}`}setMcpBridgeUpHandler(e){this.mcpBridgeUpHandler=e}sendMcpFrameToBridge(e){const t=JSON.stringify(e);if(this.bridgeWs&&this.bridgeWs.readyState===k.OPEN){this.bridgeWs.send(t);return}this.downstreamOutbox.length>=N&&(this.downstreamOutbox.shift(),c.warn("internal-api","mcp downstream outbox full, dropping oldest frame")),this.downstreamOutbox.push(t)}get token(){return this.authToken}async stop(){if(this.server)return new Promise(e=>{this.server.close(()=>{this.server=null,e()})})}checkAuth(e){return e.headers.authorization===`Bearer ${this.authToken}`||new URL(e.url??"/",`http://127.0.0.1:${this.port}`).searchParams.get("token")===this.authToken}handleRequest(e,t){if(e.method!=="POST"){t.writeHead(405),t.end(JSON.stringify({error:"method not allowed"}));return}if(!this.checkAuth(e)){t.writeHead(401),t.end(JSON.stringify({ok:!1,error:"unauthorized"}));return}const r=new URL(e.url??"/",`http://127.0.0.1:${this.port}`);if(r.pathname==="/api/status-line"){this.handleStatusLine(e,t);return}if(r.pathname==="/v1/logs"||r.pathname==="/v1/traces"){this.handleOtel(r.pathname==="/v1/logs"?"logs":"traces",e,t);return}if(!r.pathname.startsWith("/api/invoke")){t.writeHead(404),t.end(JSON.stringify({error:"not found"}));return}const o=[];let i=0;e.on("data",n=>{if(i+=n.length,i>f){t.writeHead(413),t.end(JSON.stringify({ok:!1,error:"request body too large"})),e.destroy();return}o.push(n)}),e.on("end",async()=>{let n;try{n=JSON.parse(Buffer.concat(o).toString("utf8"))}catch{t.writeHead(400),t.end(JSON.stringify({ok:!1,error:"invalid JSON"}));return}const s=n.action,d=n.params??{};if(!s||!this.invokeHandler){t.writeHead(400),t.end(JSON.stringify({ok:!1,error:"missing action or no handler"}));return}if(!J.has(s)){t.writeHead(400),t.end(JSON.stringify({ok:!1,error:`action '${s}' is not allowed`}));return}if(this.activeInvokes>=H){t.writeHead(429),t.end(JSON.stringify({ok:!1,error:"too many concurrent invokes"}));return}const a=n.timeout_ms!=null?Math.max(b,Math.min(n.timeout_ms,g)):g,l=Date.now();this.activeInvokes++;const u=new AbortController;try{const h=await Promise.race([this.invokeHandler(s,d,u.signal,a),new Promise((p,m)=>setTimeout(()=>{u.abort(),m(new Error("invoke timeout"))},a))]);t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,data:h})),c.info("internal-api",`invoke ok action=${s} tool=${d.tool_name??"-"} ms=${Date.now()-l}`)}catch(h){u.abort();const p=h instanceof Error?h.message:String(h);t.writeHead(500),t.end(JSON.stringify({ok:!1,error:p})),c.error("internal-api",`invoke error action=${s} tool=${d.tool_name??"-"} ms=${Date.now()-l} err=${p}`)}finally{this.activeInvokes--}})}handleStatusLine(e,t){const r=[];let o=0;e.on("data",i=>{if(o+=i.length,o>f){t.writeHead(413),t.end(JSON.stringify({ok:!1,error:"request body too large"})),e.destroy();return}r.push(i)}),e.on("end",async()=>{let i;try{i=JSON.parse(Buffer.concat(r).toString("utf8"))}catch{t.writeHead(400),t.end(JSON.stringify({ok:!1,error:"invalid JSON"}));return}if(!this.statusLineHandler){t.writeHead(200),t.end(JSON.stringify({ok:!0}));return}try{await this.statusLineHandler(i),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0}))}catch(n){console.error("[internal-api] statusLine handler error:",n instanceof Error?n.message:n),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0}))}})}handleOtel(e,t,r){const o=[];let i=0,n=!1;t.on("data",s=>{if(!n){if(i+=s.length,i>v){n=!0,r.writeHead(413,{"content-type":"application/json"}),r.end(JSON.stringify({error:"OTLP request body too large"}));return}o.push(s)}}),t.on("end",async()=>{if(n)return;const s=Buffer.concat(o).toString("utf8");let d;try{const a=JSON.parse(s);if(!a||typeof a!="object"||Array.isArray(a))throw new Error("OTLP body is not an object");d=a}catch{r.writeHead(400,{"content-type":"application/json"}),r.end(JSON.stringify({error:"invalid OTLP JSON"}));return}try{await this.otelHandler?.(e,d,s)}catch(a){c.warn("internal-api",`OTLP ${e} evidence persistence failed: ${a instanceof Error?a.message:String(a)}`)}r.writeHead(200,{"content-type":"application/json"}),r.end("{}")})}}export{E as InternalApiServer};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{log as
|
|
1
|
+
import{log as i}from"../log/logger.js";import{resolveClientVersion as g}from"../util/client-version.js";let s=null,a=!1;const E="https://e8e202d7625372b1314b3ff4e85a7ff9@o119262.ingest.us.sentry.io/4511410543329280";function l(){if(!process.env.GRIX_SENTRY_DISABLE)return process.env.SENTRY_DSN||process.env.GRIX_SENTRY_DSN||E}async function I(){const e=l();if(!e){i.info("sentry","Sentry \u9519\u8BEF\u4E0A\u62A5\u5DF2\u7981\u7528\uFF08GRIX_SENTRY_DISABLE\uFF09");return}try{s=await import("@sentry/node")}catch(n){i.warn("sentry",`Sentry \u6A21\u5757\u52A0\u8F7D\u5931\u8D25\uFF08\u5E73\u53F0\u4E0D\u517C\u5BB9\uFF09\uFF0C\u9519\u8BEF\u4E0A\u62A5\u5DF2\u7981\u7528: ${n instanceof Error?n.message:String(n)}`);return}try{s.init({dsn:e,release:`grix-connector@${g()}`,environment:process.env.SENTRY_ENVIRONMENT||process.env.NODE_ENV||"production",sendDefaultPii:!1,initialScope:{tags:{component:"grix-connector"}},defaultIntegrations:!1,tracesSampleRate:0,beforeSend(n){const r=u(n);return r&&c(r)?null:n}}),a=!0,i.info("sentry","Sentry \u9519\u8BEF\u4E0A\u62A5\u5DF2\u542F\u7528")}catch(n){i.error("sentry",`Sentry \u521D\u59CB\u5316\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}function u(e){if(typeof e.message=="string"&&e.message)return e.message;const n=e.exception?.values;if(!n?.length)return"";const r=n[0],o=typeof r?.value=="string"?r.value:"",t=typeof r?.type=="string"?r.type:"";return o||t}function R(){return a}const S=new Set(["INSTALL_FAILED","INSTALL_TIMEOUT","FALLBACK_EXHAUSTED","PREREQ_INSTALL_FAILED","VERIFICATION_FAILED","ENVIRONMENT_UNSUPPORTED","INTERNAL"]);function y(e){if(e.ok)return!1;const n=e.error?.code;return!!n&&S.has(n)}function d(e){if(!a||!s||!y(e))return;const n=e.error?.code??"INTERNAL",r=e.error?.message??"unknown install failure",o=e.environment;try{s.withScope(t=>{t.setLevel("error"),t.setTags({agent_type:e.agentType,error_code:n,phase:e.phase}),t.setContext("install",{agentType:e.agentType,code:n,phase:e.phase,durationMs:e.durationMs,os:o?.platform,osVersion:o?.osVersion,arch:o?.arch,nodeVersion:o?.nodeVersion,npmVersion:o?.npmVersion,isDocker:o?.isDocker,isCI:o?.isCI,outputTail:(e.output??"").slice(-2e3)}),t.setFingerprint(["agent-install-failure",e.agentType,n]),s.captureException(new Error(`Agent install failed [${e.agentType}/${n}]: ${r}`))}),i.info("sentry",`\u5DF2\u4E0A\u62A5\u5B89\u88C5\u5931\u8D25: ${e.agentType}/${n}`)}catch(t){i.error("sentry",`\u4E0A\u62A5\u5B89\u88C5\u5931\u8D25\u65F6\u51FA\u9519: ${t instanceof Error?t.message:String(t)}`)}}const N=[/No config files found/];function c(e){const n=e instanceof Error?e.message:String(e);return N.some(r=>r.test(n))}const f=new Set;function _(e,n){if(!a||!s||c(e))return;const r=e instanceof Error?e.message:String(e),o=`${n}:${r}`;if(!f.has(o)){f.add(o);try{s.withScope(t=>{t.setLevel("fatal"),t.setTag("crash_type",n);const p=e instanceof Error?e:new Error(String(e));s.captureException(p)}),i.info("sentry",`\u5DF2\u4E0A\u62A5\u5D29\u6E83: ${n}`)}catch(t){i.error("sentry",`\u4E0A\u62A5\u5D29\u6E83\u65F6\u51FA\u9519: ${t instanceof Error?t.message:String(t)}`)}}}async function L(e=2e3){if(!(!a||!s))try{await s.close(e)}catch{}}export{L as closeSentry,u as extractEventMessage,I as initSentry,c as isNonReportable,R as isSentryEnabled,_ as reportFatal,d as reportInstallFailure,y as shouldReportInstallFailure};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const l=7,E=(()=>{const n=new Uint32Array(256);for(let t=0;t<256;t++){let o=t;for(let r=0;r<8;r++)o=o&1?o>>>1^3988292384:o>>>1;n[t]=o>>>0}return n})();function f(n,t,o){let r=4294967295;for(let i=t;i<o;i++)r=E[(r^n[i])&255]^r>>>8;return(r^-1)>>>0}function a(n,t){const o=Buffer.from(n,"utf8"),r=Buffer.from(t,"utf8"),i=Buffer.alloc(1+o.length+1+2+r.length);let e=0;return i.writeUInt8(o.length,e),e+=1,o.copy(i,e),e+=o.length,i.writeUInt8(7,e),e+=1,i.writeUInt16BE(r.length,e),e+=2,r.copy(i,e),i}function c(n,t){const o=n.length,r=12+o+t.length+4,i=Buffer.alloc(r);let e=0;return i.writeUInt32BE(r,e),e+=4,i.writeUInt32BE(o,e),e+=4,i.writeUInt32BE(f(i,0,8),e),e+=4,n.copy(i,e),e+=o,t.copy(i,e),e+=t.length,i.writeUInt32BE(f(i,0,e),e),i}function s(n,t){const o=Buffer.concat([a(":message-type","event"),a(":event-type",n),a(":content-type","application/json")]);return c(o,Buffer.from(JSON.stringify(t),"utf8"))}function u(n,t){const o=Buffer.concat([a(":message-type","exception"),a(":exception-type",n),a(":content-type","application/json")]);return c(o,Buffer.from(JSON.stringify(t),"utf8"))}const p="application/vnd.amazon.eventstream";function g(n,t){"assistantResponseEvent"in t?n.write(s("assistantResponseEvent",t.assistantResponseEvent)):"messageMetadataEvent"in t?n.write(s("messageMetadataEvent",t.messageMetadataEvent)):"toolUseEvent"in t?n.write(s("toolUseEvent",{...t.toolUseEvent,stop:!0})):"reasoningContentEvent"in t?n.write(s("reasoningContentEvent",t.reasoningContentEvent)):"contextUsageEvent"in t?n.write(s("contextUsageEvent",t.contextUsageEvent)):"meteringEvent"in t?n.write(s("meteringEvent",t.meteringEvent)):"metadataEvent"in t&&n.write(s("metadataEvent",t.metadataEvent))}export{p as EVENT_STREAM_CONTENT_TYPE,s as encodeEvent,u as encodeException,g as writeCwEvent};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{encodeEvent as o,encodeException as t,EVENT_STREAM_CONTENT_TYPE as n,writeCwEvent as p}from"./eventstream.js";import{buildAnthropicRequest as E,conversationIdOf as c}from"./request-builder.js";import{AnthropicStreamConverter as f,parseAnthropicSse as m}from"./stream-converter.js";import{startKiroCwServer as x,kiroCwUrlHelpers as C}from"./server.js";export{f as AnthropicStreamConverter,n as EVENT_STREAM_CONTENT_TYPE,E as buildAnthropicRequest,c as conversationIdOf,o as encodeEvent,t as encodeException,C as kiroCwUrlHelpers,m as parseAnthropicSse,x as startKiroCwServer,p as writeCwEvent};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
function e(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function A(t){return typeof t=="string"?t:Array.isArray(t)?t.map(s=>{const o=e(s);return typeof o.text=="string"?o.text:JSON.stringify(s)}).join(`
|
|
2
|
+
`):t==null?"":JSON.stringify(t)}function b(t){if(typeof t=="string")try{return JSON.parse(t)}catch{return{raw:t}}return t??{}}function _(t){const s=e(t),o=e(s.toolSpecification??s),c=String(o.name??s.name??"tool"),y=typeof o.description=="string"?o.description:void 0,u=e(o.inputSchema??o.input_schema),l=e(u.json??u);return{name:c,description:y,schema:l}}function I(t){const s=t.content;return typeof s=="string"?s:Array.isArray(s)?s.map(o=>{const c=e(o);return typeof c.text=="string"?c.text:""}).filter(Boolean).join(`
|
|
3
|
+
`):""}function x(t){const s=e(t.conversationState);return typeof s.conversationId=="string"?s.conversationId:""}function R(t){return/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(t)}function w(t,s){const o=e(t.conversationState),c=[...Array.isArray(o.history)?o.history:[]];o.currentMessage&&c.push(o.currentMessage);const y=[];let u;for(const S of c){const m=e(S);if(m.userInputMessage){const r=e(m.userInputMessage),n=e(r.userInputMessageContext),i=[];for(const g of Array.isArray(n.toolResults)?n.toolResults:[]){const a=e(g),f={type:"tool_result",tool_use_id:String(a.toolUseId??""),content:A(a.content)};typeof a.status=="string"&&a.status.toLowerCase()==="error"&&(f.is_error=!0),i.push(f)}const p=I(r);p&&i.push({type:"text",text:p});for(const g of Array.isArray(r.images)?r.images:[]){const a=e(g),f=e(a.source),d=String(a.format??"png").toLowerCase();typeof f.bytes=="string"&&i.push({type:"image",source:{type:"base64",media_type:`image/${d}`,data:f.bytes}})}i.length>0&&y.push({role:"user",content:i.length===1&&e(i[0]).type==="text"?String(e(i[0]).text):i}),Array.isArray(n.tools)&&n.tools.length>0&&(u=n.tools.map(g=>{const{name:a,description:f,schema:d}=_(g);return{name:a,description:f,input_schema:{...d??{},type:"object",properties:d?.properties??{}}}}))}if(m.assistantResponseMessage){const r=e(m.assistantResponseMessage),n=[];typeof r.content=="string"&&r.content&&n.push({type:"text",text:r.content});for(const i of Array.isArray(r.toolUses)?r.toolUses:[]){const p=e(i);n.push({type:"tool_use",id:String(p.toolUseId??""),name:String(p.name??""),input:b(p.input)})}n.length===0&&n.push({type:"text",text:"(no content)"}),y.push({role:"assistant",content:n.length===1&&e(n[0]).type==="text"?String(e(n[0]).text):n})}}const l={model:s.model,messages:y,max_tokens:s.maxTokens??8192,stream:!0},h=x(t);return R(h)&&(l.metadata={user_id:JSON.stringify({session_id:h})}),u&&u.length>0&&(l.tools=u),l}function M(t){return x(t)||`kiro-${Date.now()}`}export{w as buildAnthropicRequest,M as conversationIdOf};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import C from"node:http";import $ from"node:https";import{URL as M}from"node:url";import{EVENT_STREAM_CONTENT_TYPE as v,encodeException as w,writeCwEvent as h}from"./eventstream.js";import{buildAnthropicRequest as I,conversationIdOf as O}from"./request-builder.js";import{AnthropicStreamConverter as P,parseAnthropicSse as E}from"./stream-converter.js";function x(t){const n=t.replace(/\/+$/,"");return n.endsWith("/v1")?`${n}/messages`:n.endsWith("/messages")?n:`${n}/v1/messages`}function U(t){const n=t.replace(/\/+$/,"");return n.endsWith("/v1")?`${n}/models`:n.endsWith("/models")?n:`${n}/v1/models`}function W(t){return new Promise((n,a)=>{const r=[];t.on("data",o=>r.push(Buffer.isBuffer(o)?o:Buffer.from(o))),t.on("end",()=>n(Buffer.concat(r))),t.on("error",a)})}function b(t){return Array.isArray(t)?String(t[0]??"").trim():String(t??"").trim()}function N(t){return t==="AmazonCodeWhispererStreamingService.GenerateAssistantResponse"||t.endsWith(".GenerateAssistantResponse")||t==="AmazonCodeWhispererService.SendMessageStreaming"}function z(t){return t==="AmazonCodeWhispererService.ListAvailableModels"||t.endsWith(".ListAvailableModels")}async function H(t,n,a,r){const o=new M(t),i=o.protocol==="https:"?$:C;return await new Promise((e,c)=>{const p=i.request({protocol:o.protocol,hostname:o.hostname,port:o.port||(o.protocol==="https:"?443:80),path:`${o.pathname}${o.search}`,method:n,headers:a},m=>e({status:m.statusCode??0,headers:m.headers,stream:m}));p.on("error",c),p.setTimeout(18e4,()=>p.destroy(new Error("upstream timeout"))),r&&p.write(r),p.end()})}function R(t){return{models:[{modelId:t,modelName:t,description:`Grix relay model (${t})`,rateUnit:"Credit",supportedInputTypes:["TEXT","IMAGE"],tokenLimits:{maxInputTokens:2e5,maxOutputTokens:64e3},promptCaching:{maximumCacheCheckpointsPerRequest:4,minimumTokensPerCacheCheckpoint:1024,supportsPromptCaching:!0}}]}}async function q(t,n=0){let a={...t};const r=C.createServer((i,e)=>{(async()=>{const c=await W(i),p=b(i.headers["x-amz-target"]);let m={};try{m=c.length?JSON.parse(c.toString("utf8")):{}}catch{m={}}if(z(p)){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(R(a.model)));return}if(!N(p)&&!String(c.toString("utf8")).includes("conversationState")){e.writeHead(200,{"Content-Type":"application/json"}),e.end("{}");return}const g=O(m),S=I(m,{model:a.model,maxTokens:a.maxTokens}),k=x(a.baseUrl),y=Buffer.from(JSON.stringify(S),"utf8");let d;try{d=await H(k,"POST",{"content-type":"application/json",accept:"text/event-stream","x-api-key":a.apiKey,authorization:`Bearer ${a.apiKey}`,"anthropic-version":"2023-06-01","content-length":String(y.length)},y)}catch(s){e.writeHead(200,{"Content-Type":v,"Transfer-Encoding":"chunked"}),e.write(w("InternalServerException",{message:s instanceof Error?s.message:String(s)})),e.end();return}if(d.status>=400){const s=[];for await(const l of d.stream)s.push(Buffer.isBuffer(l)?l:Buffer.from(l));const f=Buffer.concat(s).toString("utf8").slice(0,2e3);e.writeHead(200,{"Content-Type":v,"Transfer-Encoding":"chunked"}),h(e,{messageMetadataEvent:{conversationId:g}}),e.write(w("InternalServerException",{message:`upstream ${d.status}: ${f}`})),e.end();return}e.writeHead(200,{"Content-Type":v,"Transfer-Encoding":"chunked"}),h(e,{messageMetadataEvent:{conversationId:g}});const T=new P(S.model);let u="";d.stream.setEncoding("utf8"),d.stream.on("data",s=>{u+=s;const f=u.split(`
|
|
2
|
+
|
|
3
|
+
`);u=f.pop()??"";for(const l of f)for(const A of E(l+`
|
|
4
|
+
|
|
5
|
+
`))for(const B of T.handle(A))h(e,B)}),d.stream.on("end",()=>{if(u.trim())for(const s of E(u+`
|
|
6
|
+
|
|
7
|
+
`))for(const f of T.handle(s))h(e,f);h(e,{metadataEvent:{conversationId:g}}),e.end()}),d.stream.on("error",s=>{e.write(w("InternalServerException",{message:s.message})),e.end()})})().catch(c=>{e.headersSent?e.writableEnded||e.end():(e.writeHead(500,{"Content-Type":"application/json"}),e.end(JSON.stringify({message:c instanceof Error?c.message:String(c)})))})});return await new Promise((i,e)=>{r.once("error",e),r.listen(n,"127.0.0.1",()=>{r.off("error",e),i()})}),{port:r.address().port,updateUpstream:i=>{a={...i}},stop:async()=>{await new Promise(i=>{r.close(()=>i()),r.closeAllConnections?.()})}}}const V={normalizeMessagesUrl:x,normalizeModelsUrl:U};export{V as kiroCwUrlHelpers,q as startKiroCwServer};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
class a{inToolUse=!1;inThinking=!1;currentToolId="";currentToolName="";currentToolInput="";curSignature="";modelId;constructor(e){this.modelId=e}handle(e){const n=[],i=String(e.type??"");if(i==="content_block_start"){const t=e.content_block??{};return t.type==="tool_use"?(this.inToolUse=!0,this.currentToolId=String(t.id??""),this.currentToolName=String(t.name??""),this.currentToolInput=""):t.type==="thinking"&&(this.inThinking=!0,this.curSignature=""),n}if(i==="content_block_delta"){const t=e.delta??{};return t.type==="text_delta"&&typeof t.text=="string"&&t.text?n.push({assistantResponseEvent:{content:t.text,modelId:this.modelId}}):t.type==="thinking_delta"&&typeof t.thinking=="string"&&t.thinking?n.push({reasoningContentEvent:{text:t.thinking}}):t.type==="signature_delta"&&typeof t.signature=="string"&&t.signature?this.curSignature+=t.signature:t.type==="input_json_delta"&&typeof t.partial_json=="string"&&(this.currentToolInput+=t.partial_json),n}if(i==="content_block_stop")return this.inThinking&&(this.curSignature&&n.push({reasoningContentEvent:{signature:this.curSignature}}),this.inThinking=!1,this.curSignature=""),this.inToolUse&&(n.push({toolUseEvent:{toolUseId:this.currentToolId,name:this.currentToolName,input:this.currentToolInput||"{}"}}),this.inToolUse=!1,this.currentToolId="",this.currentToolName="",this.currentToolInput=""),n;if(i==="message_delta"){const o=(e.delta??{}).stop_reason;return o!=null&&n.push({metadataEvent:{stopReason:r(String(o))}}),n}return n}}function r(s){switch(s){case"tool_use":return"tool_use";case"max_tokens":return"max_tokens";default:return"end_turn"}}function*u(s){const e=s.split(`
|
|
2
|
+
|
|
3
|
+
`);for(const n of e){const i=n.split(`
|
|
4
|
+
`).filter(o=>o.startsWith("data:")).map(o=>o.slice(5).trimStart());if(i.length===0)continue;const t=i.join(`
|
|
5
|
+
`).trim();if(!(!t||t==="[DONE]"))try{yield JSON.parse(t)}catch{}}}export{a as AnthropicStreamConverter,u as parseAnthropicSse};
|
package/dist/core/proxy/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ProxyManager as
|
|
1
|
+
import{ProxyManager as y}from"./proxy-manager.js";import{ProxyManager as g,ProxyNoRelayRouteError as E}from"./proxy-manager.js";import{RelayFetchError as A,RelayToggleCoordinator as d,deriveGatewayBaseUrls as h,fetchRelayCredentialWithRetry as m}from"./relay-credential-fetch.js";import{relayHostsForClientType as N}from"./relay-hosts.js";import{buildGatewayRoute as T}from"./gateway-route.js";import{ensureKiroRelay as w,stopKiroRelay as C,stopAllKiroRelays as b,getKiroRelaySpawnEnv as M,getKiroRelayDebug as H,kiroRelayHomeDir as v}from"./kiro-relay.js";let e=null;function c(r){return e||(e=new y(r)),e}function p(){return e}function u(){e=null}class s extends Error{agentName;code="RELAY_PROXY_UNAVAILABLE";constructor(o){super(`agent "${o}" has Grix relay enabled but the local MITM proxy is not running; refusing to start it (it would silently fall back to your own account). Fix the proxy or turn relay off.`),this.agentName=o,this.name="ProxyRelayUnavailableError"}}const l="localhost,127.0.0.1,::1",x="grix-relay-placeholder";function P(r,o,i){if(e?.isRelayExpectedButUnavailable(o))throw new s(o);const n=e?.getInjectionEnv(o);if(!n)return r;const t={...r,...n};i?.trim().toLowerCase()==="claude"&&!t.ANTHROPIC_API_KEY&&!t.ANTHROPIC_AUTH_TOKEN&&(t.ANTHROPIC_API_KEY=x);const a=r?.NO_PROXY??r?.no_proxy??process.env.NO_PROXY??process.env.no_proxy;return t.NO_PROXY=a&&a.trim()?`${a},${l}`:l,t}export{x as GRIX_RELAY_ANTHROPIC_API_KEY,g as ProxyManager,E as ProxyNoRelayRouteError,s as ProxyRelayUnavailableError,A as RelayFetchError,d as RelayToggleCoordinator,P as applyProxyEnv,T as buildGatewayRoute,h as deriveGatewayBaseUrls,w as ensureKiroRelay,m as fetchRelayCredentialWithRetry,H as getKiroRelayDebug,M as getKiroRelaySpawnEnv,p as getProxyManager,c as initProxyManager,v as kiroRelayHomeDir,N as relayHostsForClientType,u as resetProxyManagerForTest,b as stopAllKiroRelays,C as stopKiroRelay};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{mkdir as m,writeFile as f,rm as y}from"node:fs/promises";import{join as p}from"node:path";import{resolveRuntimePaths as g}from"../config/paths.js";import{startKiroCwServer as w}from"./compat/kiro-cw/index.js";const o=new Map;function h(r){return r.trim().replace(/[^a-zA-Z0-9._-]+/g,"_")||"agent"}function v(r,t){const e=t??g().rootDir;return p(e,"runtime","kiro-relay",h(r))}async function u(r,t){const e=p(r,"settings");await m(e,{recursive:!0});const i={endpoint:`http://127.0.0.1:${t}`,region:"us-east-1"},a={"api.krs.service":i,"api.cps.service":i};await f(p(e,"cli.json"),`${JSON.stringify(a,null,2)}
|
|
2
|
+
`,"utf8")}async function k(r,t){const e=t.baseUrl.trim(),i=t.apiKey.trim(),a=t.model.trim();if(!e||!i||!a)throw new Error("kiro relay requires baseUrl, apiKey, and model");const c={baseUrl:e,apiKey:i,model:a},n=v(r),s=o.get(r);if(s)return s.server.updateUpstream(c),s.upstream=c,await u(n,s.server.port),{homeDir:n,port:s.server.port};const l=await w(c);return await u(n,l.port),o.set(r,{server:l,homeDir:n,upstream:c}),{homeDir:n,port:l.port}}async function K(r){const t=o.get(r);if(t){o.delete(r);try{await t.server.stop()}catch{}try{await y(p(t.homeDir,"settings","cli.json"),{force:!0})}catch{}}}async function b(){const r=[...o.keys()];await Promise.all(r.map(t=>K(t)))}function E(r){const t=o.get(r);return t?{KIRO_HOME:t.homeDir}:null}function S(r){const t=o.get(r);return t?{port:t.server.port,homeDir:t.homeDir}:null}export{k as ensureKiroRelay,S as getKiroRelayDebug,E as getKiroRelaySpawnEnv,v as kiroRelayHomeDir,b as stopAllKiroRelays,K as stopKiroRelay};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{relayHostsForClientType as
|
|
1
|
+
import{relayHostsForClientType as A}from"./relay-hosts.js";import{buildGatewayRoute as T}from"./gateway-route.js";import{setOneAgentRelayAndRestart as E}from"./relay-orchestration.js";import{supportsDirectProviderConfig as U,supportsKiroCwRelay as g}from"../config/provider-env.js";class e extends Error{code;constructor(s,l){super(s),this.code=l,this.name="RelayCredentialError"}}async function G(i,s,l,p,t,I){const o=t.localName.trim(),R=t.agentId.trim(),c=t.virtualKey.trim();if(!o)throw new e("agent name is required","INVALID_ARGUMENT");if(!R)throw new e("agent_id is required","MISSING_AGENT_ID");if(!c)throw new e("virtual_key is required","MISSING_VIRTUAL_KEY");const a=l(o);if(!a)throw new e(`Agent "${o}" not found`,"NOT_FOUND");if(a.agentId&&a.agentId!==R)throw new e(`agent_id does not match local agent "${o}"`,"AGENT_ID_MISMATCH");const r=String(a.clientType??"").trim().toLowerCase(),u=A(r);if(u.length===0){const n=g(r);if((U(r)||n)&&I){const w=(n?t.anthropicBaseUrl:t.openaiBaseUrl)?.trim(),y=n?"anthropic_base_url":"openai_base_url";if(!w)throw new e(`${y} is required`,"MISSING_TARGET_BASE_URL");try{new URL(w)}catch{throw new e(`${y} must be a valid URL`,"INVALID_TARGET_BASE_URL")}const f=t.model?.trim();if(!f)throw new e(`model is required for client type "${r}"`,"MISSING_MODEL");return await I(o,{base_url:w,api_key:c,model:f}),{restarted:!0,busy:!1}}throw new e(`client type "${r}" does not support Grix relay`,"UNSUPPORTED_CLIENT_TYPE")}const _=r==="claude",d=(_?t.anthropicBaseUrl:t.openaiBaseUrl)?.trim();if(!d)throw new e(`${_?"anthropic_base_url":"openai_base_url"} is required`,"MISSING_TARGET_BASE_URL");try{new URL(d)}catch{throw new e(`${_?"anthropic_base_url":"openai_base_url"} must be a valid URL`,"INVALID_TARGET_BASE_URL")}const h=T(r,d,c);i.setRoute(h);for(const n of u)i.setHostDefaultRoute(n,h.routeKey);return E(i,s,p,{agentName:o,enabled:!0,relayHosts:u})}export{e as RelayCredentialError,G as setAgentRelayCredential};
|
package/dist/grix.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import I from"node:path";import{writeFileSync as W}from"node:fs";import{Manager as de}from"./manager.js";import{ensureGrixDirs as pe,initLogger as me,log as a,installProcessLogRotation as fe,setConsoleOutput as ue}from"./core/log/index.js";import{HealthServer as ge,bindPortOrFail as X}from"./core/runtime/index.js";import{writePidFile as he,removePidFile as k,readDaemonPid as ye}from"./core/runtime/index.js";import{resolveRuntimePaths as F}from"./core/config/index.js";import{
|
|
2
|
+
import I from"node:path";import{writeFileSync as W}from"node:fs";import{Manager as de}from"./manager.js";import{ensureGrixDirs as pe,initLogger as me,log as a,installProcessLogRotation as fe,setConsoleOutput as ue}from"./core/log/index.js";import{HealthServer as ge,bindPortOrFail as X}from"./core/runtime/index.js";import{writePidFile as he,removePidFile as k,readDaemonPid as ye}from"./core/runtime/index.js";import{resolveRuntimePaths as F}from"./core/config/index.js";import{supportsNonMitmRelayConfig as H}from"./core/config/provider-env.js";import{ServiceManager as we}from"./service/service-manager.js";import{killProcessesByCommandLine as Re,isWindowsElevated as Ae}from"./service/process-control.js";import{acquireDaemonLock as Se,isLockHolderSameProcess as xe,readDaemonLock as Ee,releaseDaemonLock as T}from"./runtime/daemon-lock.js";import{writeDaemonStatus as L,removeDaemonStatus as ve}from"./runtime/service-state.js";import{AdminServer as be,generateToken as Pe,writeTokenFile as De}from"./core/admin/index.js";import{initSentry as Ie,closeSentry as _,reportFatal as B}from"./core/observability/sentry.js";import{initProxyManager as ke,getProxyManager as g,relayHostsForClientType as J}from"./core/proxy/index.js";import{stopProxyIfNobodyNeedsIt as Te,disableAllRelayAndRestart as Ce,setOneAgentRelayAndRestart as Y}from"./core/proxy/relay-orchestration.js";import{setAgentRelayCredential as q,RelayCredentialError as Ue}from"./core/proxy/relay-credential.js";import{RelayFetchError as z,RelayToggleCoordinator as $e}from"./core/proxy/relay-credential-fetch.js";import{applyHermesProfileRelay as Oe,clearHermesProfileRelay as Fe,discoverHermesProfiles as He}from"./core/proxy/hermes-profile-relay.js";import{disableRelayCredential as Le,enableRelayCredential as _e,RelayRouteError as Q}from"./core/proxy/relay-credential-router.js";import{resolveClientVersion as Be}from"./core/util/client-version.js";import{parseCliArgs as Me}from"./core/util/cli-args.js";const{command:w,flags:h,unknownFlags:M}=Me(process.argv.slice(2));if(M.length>0&&(console.error(`Unknown option${M.length>1?"s":""}: ${M.map(r=>`--${r}`).join(", ")}
|
|
3
3
|
Run \`grix-connector --help\` to see the supported commands and options.`),process.exit(1)),h.version&&(console.log(Be()),process.exit(0)),h.help&&(console.log(`grix-connector \u2014 Unified AI Agent Bridge
|
|
4
4
|
|
|
5
5
|
Usage: grix-connector <command> [options]
|
package/dist/manager.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readFileSync as J,readdirSync as V,writeFileSync as X}from"node:fs";import{join as v}from"node:path";import{homedir as Y}from"node:os";import{AgentInstance as I}from"./bridge/bridge.js";import{buildSharedInstanceConfig as Z,diffSharedOwners as ee,sharedInstanceKey as te,SharedOwnersCache as ne}from"./manager-share-config.js";import{isAgentDeletedError as O}from"./core/aibot/errors.js";import{GRIX_PATHS as w,log as l}from"./core/log/index.js";import{resolveClientVersion as ae}from"./core/util/client-version.js";import{UpgradeChecker as re}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as se}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as oe}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as ie}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as ce}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as le}from"./core/skill-sync/library-skills.js";import{buildReportedSkills as de,logDefaultSkillsCheck as pe,cleanupProjectedSkills as P}from"./default-skills/index.js";import{supportsDirectProviderConfig as me}from"./core/config/provider-env.js";import{resolveCopilotCommand as q}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as H}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ue,resolveCliPath as ge}from"./core/util/cli-probe.js";import{AgentInstaller as he}from"./core/installer/installer.js";import{reportInstallFailure as fe}from"./core/observability/sentry.js";const _e=8e3;function ye(){const n=q();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:H()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:n.command},{clientType:"agy",command:"agy"}]}async function we(){return Promise.all(ye().map(async n=>{const e=await ge(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await ue(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function Se(n){switch(n){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:H()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=q();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function R(n,e){return String(n??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function ve(n,e){return v(w.data,`session-bindings-${R(n,e)}.json`)}function Ae(n,e){return v(w.data,`active-events-${R(n,e)}.json`)}function ke(...n){const e=[],t=new Set;for(const r of n)for(const s of r??[]){const i=String(s??"").trim(),o=i.toLowerCase();!i||t.has(o)||(t.add(o),e.push(i))}return e.length>0?e:void 0}function be(n,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},r=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??r.maxConcurrent??1,maxQueued:e?.max_queued??r.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??r.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function k(n,e={}){const t=ae(),r=String(n.client_type??"").trim().toLowerCase(),s=Se(r),i=String(n.ws_url??"").trim(),o="get_session_usage",p="get_rate_limits",c="get_agent_global_config";if(!n.name?.trim())throw new Error("agent name is required");if(!i)throw new Error(`agent ${n.name}: ws_url is required`);if(!n.agent_id?.trim())throw new Error(`agent ${n.name}: agent_id is required`);if(!n.api_key?.trim())throw new Error(`agent ${n.name}: api_key is required`);const a=s.adapterType,u=a==="acp",m=r==="qwen",_={...s.options??{}},S=a==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",o,p]}:null,d=a==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",o,p]}:null,f=m?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o],adapterHint:"qwen/base"}:null,h=a==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",o]}:null,g=a==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,y=a==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder","thread_compact","claude_interaction_reply",p]}:null,A=a==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,C=a==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","file_list","create_folder"]}:null,$=a==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,E=new Set(["hermes","reasonix","kimi","copilot"]),U=u&&!E.has(r),B=u&&!m?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",...U?[o]:[]]}:null,F=r==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",o,p]}:null,L=a==="codex"||a==="claude"||r==="gemini"?["session_control","set_model","set_mode"]:void 0,Q=a==="cursor"||a==="opencode"||a==="openhuman"||a==="agy"||u&&E.has(r)?[p]:[o,p];u&&_.raw_transport===void 0&&(_.raw_transport=r==="gemini");const W=`${r}/base`,x=ie(a,r),K=x==="kiro"?void 0:process.cwd(),M=de({mode:x,projectDir:K}),j=M.filter(T=>T.source==="connector").map(T=>T.name);j.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${j.join(", ")}]`);const D=ce(M,w.skills);let G=D.length>0?D:void 0;const z=le({skillsDir:w.skills,mode:x,home:Y()});return{name:n.name,adapterType:a,aibot:{url:i,agentId:n.agent_id,apiKey:n.api_key,clientType:r,clientVersion:t,adapterHint:s.adapterHint??f?.adapterHint??h?.adapterHint??g?.adapterHint??y?.adapterHint??C?.adapterHint??$?.adapterHint??W,capabilities:S?.capabilities??A?.capabilities??h?.capabilities??g?.capabilities??y?.capabilities??C?.capabilities??$?.capabilities??f?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:ke(S?.localActions??A?.localActions??d?.localActions??h?.localActions??g?.localActions??y?.localActions??C?.localActions??$?.localActions??f?.localActions??F?.localActions??B?.localActions??["exec_approve","exec_reject"],L,Q,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh"]),skills:G,librarySkills:z},agent:{command:s.command,args:[...s.args??[],...n.args??[]],env:n.env,clientType:r,...n.provider?{provider:{...n.provider.provider_id?.trim()?{providerId:n.provider.provider_id.trim()}:{},...n.provider.base_url?.trim()?{baseUrl:n.provider.base_url.trim()}:{},...n.provider.quota_base_url?.trim()?{quotaBaseUrl:n.provider.quota_base_url.trim()}:{},...n.provider.api_key?.trim()?{apiKey:n.provider.api_key.trim()}:{},...n.provider.model?.trim()?{model:n.provider.model.trim()}:{}}}:{}},adapterOptions:_,acpAuthMethod:_.auth_method,acpInitialMode:_.initial_mode,acpMcpTools:_.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:ve(n.name,n.agent_id),activeEventStorePath:Ae(n.name,n.agent_id),...s.enableSessionBinding||u?{enableSessionBinding:!0}:{},...s.autoInjectArgs||r==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...s.autoInjectArgs??{},...r==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize,poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:be(a,n.event_queue),logDir:w.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Ce(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):_e}function N(n){const e=[],t=[],r=[],s=V(n).filter(i=>i.endsWith(".json")).sort();for(const i of s)try{const o=JSON.parse(J(v(n,i),"utf-8"));if(o===null||typeof o!="object"||Array.isArray(o)||!("agents"in o)){r.push(i);continue}if(!Array.isArray(o.agents)){t.push({file:i,error:"agents is not an array"});continue}if(o.agents.length===0){t.push({file:i,error:"agents array is empty"});continue}for(const p of o.agents)e.push({entry:p,file:i})}catch(o){t.push({file:i,error:o instanceof Error?o.message:String(o)})}return{entries:e,fileErrors:t,skipped:r}}function b(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(b).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${b(e[r])}`).join(",")}}`}function $e(n,e){return b(n)===b(e)}class Ve{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=w.config;sharedOwnersCache=new ne(w.data);installer=new he;async start(e){const t=e??w.config;this.configDir=t,l.info("manager",`Loading configs from ${t}`),pe(),P(),this.globalConfigStore=new oe(v(w.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:r,fileErrors:s,skipped:i}=N(t);for(const a of s)l.error("manager",`Failed to load ${a.file}: ${a.error}`);for(const a of i)l.info("manager",`Skipped ${a}: not an agent config (no "agents" key)`);if(r.length===0&&s.length===0&&i.length===0)throw new Error(`No config files found in ${t}`);const o=[];let p=s.length;for(const{entry:a,file:u}of r)try{const m=k(a);o.push({config:m,entry:a,file:u}),l.info("manager",`Loaded ${m.name} (${m.adapterType??"acp"}) from ${u}`)}catch(m){const _=typeof a?.name=="string"?a.name:"<unknown>";l.error("manager",`Invalid agent config in ${u} (name=${_}): ${m}`),p++}let c=0;if(o.length>0){const a=Ce();l.info("manager",`Starting ${o.length} agent(s), startup wait=${a}ms`);const u=()=>this.upgradeChecker?.triggerCheck(),m=d=>{this.instances=this.instances.filter(f=>f!==d)},_=o.map(({config:d,entry:f,file:h})=>{const g=new I(d,this.globalConfigStore);return g.setUpgradeTrigger(u),g.setShareSetHandler(y=>this.onShareSet(d,y)),g.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(d.name)),g.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),this.instances.push(g),this.configMap.set(d.name,d),this.rawConfigMap.set(d.name,{entry:f,file:h}),{config:d,instance:g,startPromise:g.start()}}),S=await Promise.all(_.map(async d=>{const f=await new Promise(h=>{let g=!1;const y=setTimeout(()=>{g||(g=!0,h({kind:"timeout"}))},a);d.startPromise.then(()=>{g||(g=!0,clearTimeout(y),h({kind:"started"}))}).catch(A=>{g||(g=!0,clearTimeout(y),h({kind:"failed",error:A}))})});return{task:d,outcome:f}}));for(const{task:d,outcome:f}of S){if(f.kind==="started"){this.restoreCachedSharedInstances(d.config);continue}if(f.kind==="failed"){if(O(f.error)){this.onAgentDeletedByPlatform(d.config.name);continue}m(d.instance),l.error("manager",`Failed to start ${d.config.name}: ${f.error}`);continue}c++,l.warn("manager",`Startup pending for ${d.config.name}, continue retrying in background`),d.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${d.config.name}`),this.restoreCachedSharedInstances(d.config)}).catch(h=>{if(O(h)){this.onAgentDeletedByPlatform(d.config.name);return}m(d.instance),l.error("manager",`Delayed start failed: ${d.config.name}: ${h}`)})}if(this.instances.length>0){const d=Math.max(0,this.instances.length-c);l.info("manager",`${d}/${o.length} agent(s) running now`)}c>0&&l.warn("manager",`${c} agent(s) still connecting in background`)}if(this.instances.length===0&&o.length>0)throw new Error("All agent configurations failed to start");o.length>0&&(this.upgradeChecker=new re(o.map(({config:a})=>({apiKey:a.aibot.apiKey,wsUrl:a.aibot.url})),()=>this.instances.some(a=>a.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(a=>a.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),o.length>0&&(this.skillSyncer=new se(o.map(({config:a})=>({apiKey:a.aibot.apiKey,wsUrl:a.aibot.url})),w.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshAllInstanceSkills()),await this.skillSyncer.start())}refreshAllInstanceSkills(){for(const e of this.instances)try{e.forceRefreshSkills()}catch(t){l.warn("manager",`forceRefreshSkills failed for ${e.name}: ${t}`)}for(const e of this.sharedInstances.values())try{e.forceRefreshSkills()}catch(t){l.warn("manager",`forceRefreshSkills failed for shared instance: ${t}`)}}async stop(){l.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),this.instances=[],P(),l.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const s=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,s)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:r,toRemove:s}=ee(e.name,this.sharedInstances.keys(),t);for(const i of r){if(this.stopping)break;const o=te(e.name,i);try{const p=Z(e,i),c=new I(p,this.globalConfigStore);this.sharedInstances.set(o,c),await c.start(),l.info("manager",`shared instance started: ${o}`)}catch(p){this.sharedInstances.delete(o);const c=p instanceof Error?p.message:String(p);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,i),l.warn("manager",`shared instance auth rejected, removed from cache: ${o}`)):l.error("manager",`start shared instance failed ${o}: ${p}`)}}for(const{key:i}of s){const o=this.sharedInstances.get(i);o&&(this.sharedInstances.delete(i),o.stop().catch(p=>l.error("manager",`stop shared instance failed ${i}: ${p}`)),l.info("manager",`shared instance stopped: ${i}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(l.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),l.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const r=k(e);if(this.instances.some(s=>s.name===r.name))throw new Error(`Agent "${r.name}" already exists`);await this.startInstanceFromConfig(r,e,t)}async startInstanceFromConfig(e,t,r){const s=new I(e,this.globalConfigStore);s.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),s.setShareSetHandler(i=>this.onShareSet(e,i)),s.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),s.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),s.setProviderConfigHandler(i=>this.setAgentProvider(e.name,i)),s.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),await s.start(),this.instances.push(s),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:r}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const r=this.instances.findIndex(p=>p.name===e),s=r===-1?void 0:this.instances[r];r!==-1&&this.instances.splice(r,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const i=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),i&&await i.catch(()=>{});const o=`${e}#shared:`;for(const[p,c]of[...this.sharedInstances.entries()])p.startsWith(o)&&(this.sharedInstances.delete(p),c.stop().catch(a=>l.error("manager",`stop shared instance failed ${p}: ${a}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),s&&await s.stop()}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(r=>r.name===e)))return;l.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){l.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=v(this.configDir,"agents.json");try{const t=[];for(const[,s]of this.configMap){const i=this.rawConfigMap.get(s.name)?.entry.provider;t.push({name:s.name,ws_url:s.aibot.url,agent_id:s.aibot.agentId,api_key:s.aibot.apiKey,client_type:s.aibot.clientType,...i?{provider:i}:{}})}X(e,JSON.stringify({agents:t},null,4)+`
|
|
2
|
-
`,"utf-8")}catch(t){l.error("manager",`Failed to persist agents config: ${t}`)}}isAgentBusy(e){return this.instances.find(
|
|
1
|
+
import{readFileSync as Z,readdirSync as ee,writeFileSync as te}from"node:fs";import{join as k}from"node:path";import{homedir as ne}from"node:os";import{AgentInstance as I}from"./bridge/bridge.js";import{buildSharedInstanceConfig as ae,diffSharedOwners as re,sharedInstanceKey as se,SharedOwnersCache as ie}from"./manager-share-config.js";import{isAgentDeletedError as O}from"./core/aibot/errors.js";import{GRIX_PATHS as S,log as l}from"./core/log/index.js";import{resolveClientVersion as oe}from"./core/util/client-version.js";import{UpgradeChecker as ce}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as le}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as de}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as pe}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as me}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as ue}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as ge}from"./core/aibot/types.js";import{buildReportedSkills as he,logDefaultSkillsCheck as fe,cleanupProjectedSkills as R}from"./default-skills/index.js";import{supportsKiroCwRelay as q,supportsNonMitmRelayConfig as _e}from"./core/config/provider-env.js";import{ensureKiroRelay as H,stopKiroRelay as N}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as U}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as B}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ye,resolveCliPath as we}from"./core/util/cli-probe.js";import{AgentInstaller as Se}from"./core/installer/installer.js";import{reportInstallFailure as Ae}from"./core/observability/sentry.js";import{createDefaultAuditProducer as ke}from"./audit/runtime/default-audit-recorder.js";const ve=8e3;function be(){const n=U();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:B()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:n.command},{clientType:"agy",command:"agy"}]}async function Ce(){return Promise.all(be().map(async n=>{const e=await we(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await ye(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function $e(n){switch(n){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:B()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=U();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function F(n,e){return String(n??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function xe(n,e){return k(S.data,`session-bindings-${F(n,e)}.json`)}function Te(n,e){return k(S.data,`active-events-${F(n,e)}.json`)}function Ie(...n){const e=[],t=new Set;for(const a of n)for(const r of a??[]){const o=String(r??"").trim(),s=o.toLowerCase();!o||t.has(s)||(t.add(s),e.push(o))}return e.length>0?e:void 0}function Ee(n,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},a=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??a.maxConcurrent??1,maxQueued:e?.max_queued??a.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??a.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function v(n,e={}){const t=oe(),a=String(n.client_type??"").trim().toLowerCase(),r=$e(a),o=String(n.ws_url??"").trim(),s="get_session_usage",m="get_rate_limits",c="get_agent_global_config",i=ge;if(!n.name?.trim())throw new Error("agent name is required");if(!o)throw new Error(`agent ${n.name}: ws_url is required`);if(!n.agent_id?.trim())throw new Error(`agent ${n.name}: agent_id is required`);if(!n.api_key?.trim())throw new Error(`agent ${n.name}: api_key is required`);const d=r.adapterType,u=d==="acp",y=a==="qwen",w={...r.options??{}},p=d==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",s,m]}:null,f=d==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",s,m]}:null,h=y?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",s],adapterHint:"qwen/base"}:null,g=d==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",s,m]}:null,_=d==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,A=d==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder","thread_compact","claude_interaction_reply",m]}:null,E=d==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",s]}:null,C=d==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","file_list","create_folder"]}:null,$=d==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,M=new Set(["hermes","reasonix","kimi","copilot"]),Q=u&&!M.has(a),K=u&&!y?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",...Q?[s]:[]]}:null,W=a==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",s,m]}:null,z=d==="codex"||d==="claude"||a==="gemini"?["session_control","set_model","set_mode"]:void 0,G=d==="cursor"||d==="opencode"||d==="openhuman"||d==="agy"||u&&M.has(a)?[m]:[s,m];u&&w.raw_transport===void 0&&(w.raw_transport=a==="gemini");const J=`${a}/base`,x=pe(d,a),V=x==="kiro"?void 0:process.cwd(),j=he({mode:x,projectDir:V}),D=j.filter(T=>T.source==="connector").map(T=>T.name);D.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${D.join(", ")}]`);const P=me(j,S.skills);let X=P.length>0?P:void 0;const Y=ue({skillsDir:S.skills,mode:x,home:ne()});return{name:n.name,adapterType:d,aibot:{url:o,agentId:n.agent_id,apiKey:n.api_key,clientType:a,clientVersion:t,adapterHint:r.adapterHint??h?.adapterHint??g?.adapterHint??_?.adapterHint??A?.adapterHint??C?.adapterHint??$?.adapterHint??J,capabilities:p?.capabilities??E?.capabilities??g?.capabilities??_?.capabilities??A?.capabilities??C?.capabilities??$?.capabilities??h?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:Ie(p?.localActions??E?.localActions??f?.localActions??g?.localActions??_?.localActions??A?.localActions??C?.localActions??$?.localActions??h?.localActions??W?.localActions??K?.localActions??["exec_approve","exec_reject"],z,G,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh",...i]),skills:X,librarySkills:Y},agent:{command:r.command,args:[...r.args??[],...n.args??[]],env:n.env,clientType:a,...n.provider?{provider:{...n.provider.provider_id?.trim()?{providerId:n.provider.provider_id.trim()}:{},...n.provider.base_url?.trim()?{baseUrl:n.provider.base_url.trim()}:{},...n.provider.quota_base_url?.trim()?{quotaBaseUrl:n.provider.quota_base_url.trim()}:{},...n.provider.api_key?.trim()?{apiKey:n.provider.api_key.trim()}:{},...n.provider.model?.trim()?{model:n.provider.model.trim()}:{}}}:{}},adapterOptions:w,acpAuthMethod:w.auth_method,acpInitialMode:w.initial_mode,acpMcpTools:w.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:xe(n.name,n.agent_id),activeEventStorePath:Te(n.name,n.agent_id),...r.enableSessionBinding||u?{enableSessionBinding:!0}:{},...r.autoInjectArgs||a==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...r.autoInjectArgs??{},...a==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize,poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:Ee(d,n.event_queue),logDir:S.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Me(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):ve}function L(n){const e=[],t=[],a=[],r=ee(n).filter(o=>o.endsWith(".json")).sort();for(const o of r)try{const s=JSON.parse(Z(k(n,o),"utf-8"));if(s===null||typeof s!="object"||Array.isArray(s)||!("agents"in s)){a.push(o);continue}if(!Array.isArray(s.agents)){t.push({file:o,error:"agents is not an array"});continue}if(s.agents.length===0){t.push({file:o,error:"agents array is empty"});continue}for(const m of s.agents)e.push({entry:m,file:o})}catch(s){t.push({file:o,error:s instanceof Error?s.message:String(s)})}return{entries:e,fileErrors:t,skipped:a}}function b(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(b).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(a=>`${JSON.stringify(a)}:${b(e[a])}`).join(",")}}`}function je(n,e){return b(n)===b(e)}class st{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=S.config;sharedOwnersCache=new ie(S.data);installer=new Se;auditProducer=ke();async start(e){const t=e??S.config;this.configDir=t,l.info("manager",`Loading configs from ${t}`),fe(),R(),this.globalConfigStore=new de(k(S.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:a,fileErrors:r,skipped:o}=L(t);for(const i of r)l.error("manager",`Failed to load ${i.file}: ${i.error}`);for(const i of o)l.info("manager",`Skipped ${i}: not an agent config (no "agents" key)`);if(a.length===0&&r.length===0&&o.length===0){l.warn("manager",`No config files found in ${t}; daemon idle (waiting for config). Add agents under this directory then run: grix-connector reload`);return}const s=[];let m=r.length;for(const{entry:i,file:d}of a)try{const u=v(i);s.push({config:u,entry:i,file:d}),l.info("manager",`Loaded ${u.name} (${u.adapterType??"acp"}) from ${d}`)}catch(u){const y=typeof i?.name=="string"?i.name:"<unknown>";l.error("manager",`Invalid agent config in ${d} (name=${y}): ${u}`),m++}let c=0;if(s.length>0){const i=Me();l.info("manager",`Starting ${s.length} agent(s), startup wait=${i}ms`);const d=()=>this.upgradeChecker?.triggerCheck(),u=p=>{this.instances=this.instances.filter(f=>f!==p)},y=s.map(({config:p,entry:f,file:h})=>{const g=new I(p,this.globalConfigStore,this.auditProducer);return g.setUpgradeTrigger(d),g.setShareSetHandler(_=>this.onShareSet(p,_)),g.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(p.name)),g.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),this.instances.push(g),this.configMap.set(p.name,p),this.rawConfigMap.set(p.name,{entry:f,file:h}),{config:p,instance:g,startPromise:g.start()}}),w=await Promise.all(y.map(async p=>{const f=await new Promise(h=>{let g=!1;const _=setTimeout(()=>{g||(g=!0,h({kind:"timeout"}))},i);p.startPromise.then(()=>{g||(g=!0,clearTimeout(_),h({kind:"started"}))}).catch(A=>{g||(g=!0,clearTimeout(_),h({kind:"failed",error:A}))})});return{task:p,outcome:f}}));for(const{task:p,outcome:f}of w){if(f.kind==="started"){this.restoreCachedSharedInstances(p.config);continue}if(f.kind==="failed"){if(O(f.error)){this.onAgentDeletedByPlatform(p.config.name);continue}u(p.instance),l.error("manager",`Failed to start ${p.config.name}: ${f.error}`);continue}c++,l.warn("manager",`Startup pending for ${p.config.name}, continue retrying in background`),p.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${p.config.name}`),this.restoreCachedSharedInstances(p.config)}).catch(h=>{if(O(h)){this.onAgentDeletedByPlatform(p.config.name);return}u(p.instance),l.error("manager",`Delayed start failed: ${p.config.name}: ${h}`)})}if(this.instances.length>0){const p=Math.max(0,this.instances.length-c);l.info("manager",`${p}/${s.length} agent(s) running now`)}c>0&&l.warn("manager",`${c} agent(s) still connecting in background`)}if(this.instances.length===0&&s.length>0)throw new Error("All agent configurations failed to start");await this.ensureAuxServices()}async ensureAuxServices(){if(this.configMap.size===0)return;const e=[...this.configMap.values()].map(t=>({apiKey:t.aibot.apiKey,wsUrl:t.aibot.url}));this.upgradeChecker||(this.upgradeChecker=new ce(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new le(e,S.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshAllInstanceSkills()),await this.skillSyncer.start())}refreshAllInstanceSkills(){for(const e of this.instances)try{e.forceRefreshSkills()}catch(t){l.warn("manager",`forceRefreshSkills failed for ${e.name}: ${t}`)}for(const e of this.sharedInstances.values())try{e.forceRefreshSkills()}catch(t){l.warn("manager",`forceRefreshSkills failed for shared instance: ${t}`)}}async stop(){l.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),await this.auditProducer.stop({timeoutMs:5e3}).catch(()=>!1),this.instances=[],R(),l.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const r=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,r)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:a,toRemove:r}=re(e.name,this.sharedInstances.keys(),t);for(const o of a){if(this.stopping)break;const s=se(e.name,o);try{const m=ae(e,o),c=new I(m,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(s,c),await c.start(),l.info("manager",`shared instance started: ${s}`)}catch(m){this.sharedInstances.delete(s);const c=m instanceof Error?m.message:String(m);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,o),l.warn("manager",`shared instance auth rejected, removed from cache: ${s}`)):l.error("manager",`start shared instance failed ${s}: ${m}`)}}for(const{key:o}of r){const s=this.sharedInstances.get(o);s&&(this.sharedInstances.delete(o),s.stop().catch(m=>l.error("manager",`stop shared instance failed ${o}: ${m}`)),l.info("manager",`shared instance stopped: ${o}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(l.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),await this.ensureAuxServices(),l.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const a=v(e);if(this.instances.some(r=>r.name===a.name))throw new Error(`Agent "${a.name}" already exists`);await this.startInstanceFromConfig(a,e,t)}async startInstanceFromConfig(e,t,a){q(t.client_type)&&t.provider?.base_url?.trim()&&t.provider?.api_key?.trim()&&t.provider?.model?.trim()&&await H(e.name,{baseUrl:t.provider.base_url.trim(),apiKey:t.provider.api_key.trim(),model:t.provider.model.trim()});const r=new I(e,this.globalConfigStore,this.auditProducer);r.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),r.setShareSetHandler(o=>this.onShareSet(e,o)),r.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),r.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),r.setProviderConfigHandler(o=>this.setAgentProvider(e.name,o)),r.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),await r.start(),this.instances.push(r),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:a}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const a=this.instances.findIndex(m=>m.name===e),r=a===-1?void 0:this.instances[a];a!==-1&&this.instances.splice(a,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const o=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),o&&await o.catch(()=>{});const s=`${e}#shared:`;for(const[m,c]of[...this.sharedInstances.entries()])m.startsWith(s)&&(this.sharedInstances.delete(m),c.stop().catch(i=>l.error("manager",`stop shared instance failed ${m}: ${i}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),r&&await r.stop(),t?.keepShareCache||await N(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(a=>a.name===e)))return;l.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){l.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=k(this.configDir,"agents.json");try{const t=[];for(const[,r]of this.configMap){const o=this.rawConfigMap.get(r.name)?.entry.provider;t.push({name:r.name,ws_url:r.aibot.url,agent_id:r.aibot.agentId,api_key:r.aibot.apiKey,client_type:r.aibot.clientType,...o?{provider:o}:{}})}te(e,JSON.stringify({agents:t},null,4)+`
|
|
2
|
+
`,"utf-8")}catch(t){l.error("manager",`Failed to persist agents config: ${t}`)}}isAgentBusy(e){return this.instances.find(a=>a.name===e)?.hasPendingWork()??!1}getAgentsWithStaleRelayEnv(){return this.instances.filter(e=>e.hasStaleRelayEnv()).map(e=>e.name)}markAgentRelayEnvStale(e){const t=this.instances.find(a=>a.name===e);return t?(t.markRelayEnvStale(),!0):!1}relayEnvSettledHandler;setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}async restartAgent(e){const t=this.rawConfigMap.get(e);if(!t)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.replaceInstance(e,t.entry,t.file),l.info("manager",`Restarted agent: ${e}`)}async setAgentProvider(e,t){const a=this.rawConfigMap.get(e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});const r=String(a.entry.client_type??"").trim().toLowerCase();q(r)&&(t?.base_url?.trim()&&t?.api_key?.trim()&&t?.model?.trim()?await H(e,{baseUrl:t.base_url.trim(),apiKey:t.api_key.trim(),model:t.model.trim()}):await N(e));const o={...a.entry,provider:t};await this.replaceInstance(e,o,a.file),this.persistAgentsConfig(),l.info("manager",`Updated provider config for agent: ${e}`)}async fetchRelayCredential(e,t){const a=this.instances.find(r=>r.name===e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return a.fetchRelayCredential(t)}async clearDirectProviderConfigs(){const e=[...this.rawConfigMap.entries()].filter(([,a])=>!!a.entry.provider&&_e(a.entry.client_type)).map(([a])=>a),t=[];for(const a of e)try{await this.setAgentProvider(a,void 0),t.push(a)}catch(r){l.warn("manager",`Failed to clear provider config for "${a}": ${r instanceof Error?r.message:String(r)}`)}return t}async replaceInstance(e,t,a){const r=v(t);await this.removeAgentInternal(e,{keepShareCache:!0}),await this.startInstanceFromConfig(r,t,a),this.restoreCachedSharedInstances(r)}async reload(){const e=this.reloadChain.catch(()=>{}).then(()=>this.doReload());return this.reloadChain=e.catch(()=>{}),e}async doReload(){if(this.stopping)throw Object.assign(new Error("manager is stopping"),{code:"RELOAD_UNSAFE"});const{entries:e,fileErrors:t,skipped:a}=L(this.configDir);for(const c of a)l.info("manager",`reload: skipped ${c}: not an agent config (no "agents" key)`);if(t.length>0){const c=t.map(i=>`${i.file}: ${i.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${t.length} config file(s) failed to parse [${c}]`),{code:"RELOAD_UNSAFE"})}if(e.length===0)throw Object.assign(new Error("reload aborted: no valid agent config found"),{code:"RELOAD_UNSAFE"});const r=[];for(const{entry:c}of e)try{v(c,{quiet:!0})}catch(i){const d=c?.name,u=typeof d=="string"&&d.trim()?d:"<unknown>";r.push({name:u,error:i instanceof Error?i.message:String(i)})}if(r.length>0){const c=r.map(i=>`${i.name}: ${i.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${r.length} agent config(s) invalid [${c}]`),{code:"RELOAD_UNSAFE"})}const o=new Map;for(const c of e){const i=String(c.entry?.name??"").trim();i&&(o.has(i)&&l.warn("manager",`reload: duplicate agent name "${i}", last one wins`),o.set(i,c))}const s={added:[],removed:[],restarted:[],unchanged:[],failed:[]},m=new Set(this.rawConfigMap.keys());for(const c of m)if(!o.has(c))try{await this.removeAgentInternal(c),s.removed.push(c)}catch(i){s.failed.push({name:c,error:i instanceof Error?i.message:String(i)})}for(const[c,i]of o){const d=this.rawConfigMap.get(c);if(d)if(je(d.entry,i.entry))this.rawConfigMap.set(c,i),s.unchanged.push(c);else try{await this.replaceInstance(c,i.entry,i.file),s.restarted.push(c)}catch(u){s.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}else try{await this.addAgentInternal(i.entry,i.file),s.added.push(c)}catch(u){s.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}}return l.info("manager",`reload done: +${s.added.length} -${s.removed.length} ~${s.restarted.length} =${s.unchanged.length} !${s.failed.length}`),await this.ensureAuxServices(),s}async checkUpgrade(){return this.upgradeChecker?this.upgradeChecker.checkForUpdate():{available:!1}}triggerUpgrade(){this.upgradeChecker?.triggerCheck()}async probeAll(e={}){return De(this.instances,e)}async probeOne(e,t={}){return Pe(this.instances,e,t)}listInstallable(){return this.installer.listInstallable()}async installAgent(e){const t=await this.installer.install(e);return Ae(t),t}getInstallProgress(e){return this.installer.getProgress(e)??null}}async function De(n,e){const t=e.concurrency??4,a=Date.now(),r=new Array(n.length);await new Promise(i=>{let d=0,u=0;const y=n.length;if(y===0){i();return}function w(h){const g=n[h];g.probe(e).then(_=>{r[h]=_,p()},_=>{r[h]={agent_name:g.name,client_type:"unknown",adapter_type:"acp",ok:!1,status:"error",probed_at:Date.now(),duration_ms:0,cached:!1,cli:{command:"",installed:!1,path:null,version:null,error:{code:"internal",message:_?.message??String(_)}},conversation:{attempted:!1,ok:!1,latency_ms:null},config:{model:null,base_url:null,source:{model:"unknown",base_url:"unknown"}},process:{started:!1,alive:!1,busy:!1}},p()})}function p(){u++,d<y?w(d++):u===y&&i()}const f=Math.min(t,y);for(let h=0;h<f;h++)w(d++)});const o=r.filter(i=>i.status==="healthy").length,s=r.filter(i=>i.status==="degraded").length,m=r.filter(i=>i.status==="unavailable").length,c=await Ce();return{ok:o===r.length&&r.length>0,total:r.length,healthy:o,degraded:s,unavailable:m,installed_clients:c,agents:r,probed_at:a,duration_ms:Date.now()-a}}async function Pe(n,e,t){const a=n.find(r=>r.name===e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return a.probe(t)}export{st as Manager,Ce as probeInstalledClientCommands,De as probeInstances,Pe as probeOneInstance};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a(
|
|
1
|
+
function a(t){const o=new Set([`http://127.0.0.1:${t.serverPort}`,`http://localhost:${t.serverPort}`,...t.allowedOrigins]),e=new Set([`127.0.0.1:${t.serverPort}`,`localhost:${t.serverPort}`,...t.allowedHosts]);return{validateRequest(s){const r=i(s,o);if(!r.ok)return r;const n=l(s,e);return n.ok?{ok:!0}:n}}}function i(t,o){const e=t.headers.origin;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${e}`}:{ok:!0}}function l(t,o){const e=t.headers.host;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${e}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
|
|
@@ -13,6 +13,9 @@ ${e.map(r=>` <string>${p(r)}</string>`).join(`
|
|
|
13
13
|
<true/>
|
|
14
14
|
<key>KeepAlive</key>
|
|
15
15
|
<true/>
|
|
16
|
+
<!-- \u5D29\u6E83\u72C2\u62C9\u65F6\u81F3\u5C11\u9694 30s\uFF0C\u907F\u514D\u7F3A\u914D\u7F6E/\u542F\u52A8\u5931\u8D25\u65F6\u77AC\u65F6\u7A7A\u8F6C\u5360\u6EE1 CPU \u4E0E\u65E5\u5FD7 -->
|
|
17
|
+
<key>ThrottleInterval</key>
|
|
18
|
+
<integer>30</integer>
|
|
16
19
|
<key>WorkingDirectory</key>
|
|
17
20
|
<string>${p(u.dirname(t.cliPath))}</string>
|
|
18
21
|
${t.environmentPath?` <key>EnvironmentVariables</key>
|
|
@@ -35,7 +38,7 @@ Type=simple
|
|
|
35
38
|
ExecStart=${e}
|
|
36
39
|
WorkingDirectory=${u.dirname(t.cliPath)}
|
|
37
40
|
Restart=always
|
|
38
|
-
RestartSec=
|
|
41
|
+
RestartSec=30
|
|
39
42
|
StandardOutput=append:${t.stdoutPath}
|
|
40
43
|
StandardError=append:${t.stderrPath}
|
|
41
44
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.17.0",
|
|
4
4
|
"description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
"test:watch": "node --experimental-vm-modules node_modules/vitest/vitest.mjs",
|
|
31
31
|
"test:e2e": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e",
|
|
32
32
|
"test:e2e:smoke": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/smoke.test.ts",
|
|
33
|
+
"test:e2e:claude-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/claude-audit-replay.test.ts",
|
|
34
|
+
"test:e2e:codex-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/codex-audit-replay.test.ts",
|
|
35
|
+
"test:e2e:native-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/native-event-audit-replay.test.ts",
|
|
36
|
+
"test:e2e:kimi-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/native-event-audit-replay.test.ts -t \"kimi:\"",
|
|
37
|
+
"test:e2e:pi-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/pi-audit-replay.test.ts",
|
|
38
|
+
"test:e2e:reasonix-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/reasonix-audit-replay.test.ts",
|
|
39
|
+
"test:e2e:codewhale-audit": "RUN_REAL_AGENT_E2E=1 node --experimental-vm-modules node_modules/vitest/vitest.mjs run tests/e2e/codewhale-audit-replay.test.ts",
|
|
33
40
|
"lint": "npm run check:isolation && tsc --noEmit",
|
|
34
41
|
"start": "node dist/grix.js start",
|
|
35
42
|
"stop": "node dist/grix.js stop",
|