grix-connector 4.2.6 → 4.2.7

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.
@@ -1 +1 @@
1
- const c=25e3,d=6e4,l=18e5;class m{config;callbacks;running=new Map;queued=[];timers=new Map;composingTimers=new Map;adapterDoneEventIds=new Set;pauseReasons=new Set;heldEventIds=new Map;get ready(){return this.pauseReasons.size===0}constructor(e,t){this.config=e,this.callbacks=t}pause(e){this.pauseReasons.add(e)}resume(e){this.pauseReasons.delete(e)&&this.ready&&this.drainNext()}submit(e){return this.running.has(e.event_id)||this.queued.some(t=>t.event_id===e.event_id)?"accepted":this.ready&&this.running.size<this.config.maxConcurrent?(this.startRunning(e),"accepted"):this.config.maxQueued<=0||this.queued.length>=this.config.maxQueued?(this.callbacks.onRejected(e,"queue full"),"rejected"):(this.enqueue(e),"accepted")}cancel(e){const t=this.queued.findIndex(i=>i.event_id===e);if(t>=0){if(!this.config.cancelableQueued)return!1;const[i]=this.queued.splice(t,1);return this.clearTimer(e),this.clearHold(e),this.callbacks.onStateChange(e,i.session_id,"canceled",{reason:"canceled by user"}),this.broadcastQueuePositions(),this.drainNext(),this.checkStopComposing(i.session_id),!0}return this.running.has(e)&&this.config.cancelableRunning?(this.callbacks.onCancelRunning(e),!0):!1}removeQueued(e){const t=this.queued.findIndex(u=>u.event_id===e);if(t<0)return!1;const[i]=this.queued.splice(t,1);this.clearTimer(e);const n=this.clearHold(e);return this.broadcastQueuePositions(),n&&this.drainNext(),this.checkStopComposing(i.session_id),!0}complete(e){const t=this.running.get(e);if(!t)return!1;const i=t?.session_id;return this.running.delete(e),this.adapterDoneEventIds.delete(e),this.clearTimer(e),queueMicrotask(()=>this.drainNext()),i&&this.checkStopComposing(i),!0}clear(e,t="queue cleared"){const i=[],n=[];let u=!1;for(const s of this.queued)s.session_id===e?(this.clearTimer(s.event_id),this.clearHold(s.event_id)&&(u=!0),this.callbacks.onStateChange(s.event_id,e,"canceled",{reason:t}),i.push(s.event_id)):n.push(s);return this.queued=n,i.length>0&&this.broadcastQueuePositions(),u&&this.drainNext(),this.checkStopComposing(e),i}reorder(e,t){const i=[],n=[];if(this.queued.forEach((o,r)=>{o.session_id===e&&(i.push(r),n.push(o))}),n.length===0)return[];const u=new Map(n.map(o=>[o.event_id,o])),s=[];for(const o of t){const r=u.get(o);r&&(u.delete(o),s.push(r))}for(const o of n)u.has(o.event_id)&&s.push(o);return s.some((o,r)=>o!==n[r])&&(i.forEach((o,r)=>{this.queued[o]=s[r]}),this.drainNext()),s.map(o=>o.event_id)}hold(e,t,i){if(!this.queued.find(r=>r.event_id===e))return"not_found";const s=Number.isFinite(i)&&i>0?Math.min(18e5,Math.max(6e4,Math.floor(i))):0,a=this.heldEventIds.get(e);a?a.timer&&clearTimeout(a.timer):this.clearTimer(e);const o=s>0?setTimeout(()=>{this.expireHold(e)},s):null;return o?.unref(),this.heldEventIds.set(e,{reason:t||"manual",expireAt:s>0?Date.now()+s:0,timer:o}),this.broadcastQueuePositions(),"ok"}release(e){return this.queued.findIndex(i=>i.event_id===e)<0?"not_found":(this.clearHold(e)&&(this.armQueueTimeout(e),this.broadcastQueuePositions(),queueMicrotask(()=>this.drainNext())),"ok")}editQueued(e,t){if(typeof t!="string"||t.trim().length===0)return"empty_content";const i=this.queued.find(n=>n.event_id===e);return i?(i.content=t,this.heldEventIds.has(e)?this.release(e):this.broadcastQueuePositions(),"ok"):"not_found"}expireHold(e){this.heldEventIds.has(e)&&this.release(e)==="not_found"&&this.clearHold(e)}clearHold(e){const t=this.heldEventIds.get(e);return t?(t.timer&&clearTimeout(t.timer),this.heldEventIds.delete(e),!0):!1}armQueueTimeout(e){if(this.config.queueTimeoutMs<=0)return;this.clearTimer(e);const t=setTimeout(()=>{this.timeoutEvent(e)},this.config.queueTimeoutMs);t.unref(),this.timers.set(e,t)}drainQueuedForSession(e){const t=[],i=[];for(const n of this.queued)n.session_id===e?(this.clearTimer(n.event_id),this.clearHold(n.event_id),t.push(n)):i.push(n);return this.queued=i,t}snapshot(e){const t=[...this.running.values()].filter(s=>s.session_id===e),i=t.map(s=>s.event_id),n=t.map(s=>({event_id:s.event_id,content_preview:this.buildQueueItemTitle(s.content),title:this.buildQueueItemTitle(s.content),summary:this.buildQueueItemTitle(s.content)})),u=this.queued.flatMap((s,a)=>{if(s.session_id!==e)return[];const o=this.heldEventIds.get(s.event_id);return[{event_id:s.event_id,position:a+1,content_preview:this.buildQueueItemTitle(s.content),content:s.content,title:this.buildQueueItemTitle(s.content),summary:this.buildQueueItemTitle(s.content),held:!!o,held_reason:o?.reason??""}]});return{running:i,running_items:n,queued:u}}hasCapacity(){return this.running.size<this.config.maxConcurrent}get runningCount(){return this.running.size}get queuedCount(){return this.queued.length}destroy(){for(const e of this.timers.values())clearTimeout(e);this.timers.clear();for(const e of this.heldEventIds.values())e.timer&&clearTimeout(e.timer);this.heldEventIds.clear();for(const e of this.composingTimers.values())clearInterval(e);this.composingTimers.clear(),this.queued=[],this.running.clear(),this.pauseReasons.clear()}enqueue(e){this.queued.push(e);const t=this.queued.length;this.callbacks.onStateChange(e.event_id,e.session_id,"queued",{queue_position:t,queue_total:t,actions:this.config.cancelableQueued?[{type:"cancel"}]:[],content_preview:this.buildQueueItemTitle(e.content),content:e.content,held:!1,held_reason:""}),this.armQueueTimeout(e.event_id),this.ensureComposing(e.session_id)}timeoutEvent(e){const t=this.queued.findIndex(n=>n.event_id===e);if(t<0||this.heldEventIds.has(e))return;const[i]=this.queued.splice(t,1);this.timers.delete(e),this.callbacks.onStateChange(e,i.session_id,"failed",{reason:"queue timeout"}),this.broadcastQueuePositions(),this.drainNext(),this.checkStopComposing(i.session_id)}startRunning(e){this.running.set(e.event_id,e),this.callbacks.onStateChange(e.event_id,e.session_id,"running",{actions:this.config.cancelableRunning?[{type:"stop"}]:[],content_preview:this.buildQueueItemTitle(e.content),content:e.content}),this.ensureComposing(e.session_id),this.callbacks.onDeliver(e)}drainNext(){for(;this.ready&&this.running.size<this.config.maxConcurrent&&this.queued.length>0&&!this.heldEventIds.has(this.queued[0].event_id);){const e=this.queued.shift();this.clearTimer(e.event_id),this.startRunning(e)}this.queued.length>0&&this.broadcastQueuePositions()}broadcastQueuePositions(){const e=this.queued.length;for(let t=0;t<e;t++){const i=this.queued[t],n=this.heldEventIds.get(i.event_id);this.callbacks.onStateChange(i.event_id,i.session_id,"queued",{queue_position:t+1,queue_total:e,actions:this.config.cancelableQueued?[{type:"cancel"}]:[],content_preview:this.buildQueueItemTitle(i.content),content:i.content,held:!!n,held_reason:n?.reason??""})}}clearTimer(e){const t=this.timers.get(e);t&&(clearTimeout(t),this.timers.delete(e))}buildQueueItemTitle(e){const t=String(e??"").replace(/\s+/g," ").trim();return t?t.length>64?`${t.slice(0,64)}...`:t:"Message"}ensureComposing(e){if(!this.callbacks.onComposing||this.composingTimers.has(e))return;this.callbacks.onComposing(e,!0,this.getFirstRunningEventId(e));const t=setInterval(()=>{this.sessionHasEvents(e)?this.callbacks.onComposing(e,!0,this.getFirstRunningEventId(e)):this.stopComposing(e)},25e3);t.unref(),this.composingTimers.set(e,t)}checkStopComposing(e){this.sessionHasEvents(e)||this.stopComposing(e)}markAdapterDone(e){const t=this.running.get(e);t&&(this.adapterDoneEventIds.add(e),this.sessionHasEvents(t.session_id)||this.stopComposing(t.session_id))}stopComposing(e){const t=this.composingTimers.get(e);t&&(clearInterval(t),this.composingTimers.delete(e)),this.callbacks.onComposing?.(e,!1)}sessionHasEvents(e){for(const t of this.running.values())if(t.session_id===e&&!this.adapterDoneEventIds.has(t.event_id))return!0;return this.queued.some(t=>t.session_id===e)}getFirstRunningEventId(e){for(const t of this.running.values())if(t.session_id===e&&!this.adapterDoneEventIds.has(t.event_id))return t.event_id}}export{m as EventQueue};
1
+ const c=25e3,d=45e3,l=6e4,m=18e5;class f{config;callbacks;running=new Map;queued=[];timers=new Map;composingTimers=new Map;adapterDoneEventIds=new Set;pauseReasons=new Set;heldEventIds=new Map;get ready(){return this.pauseReasons.size===0}constructor(e,t){this.config=e,this.callbacks=t}pause(e){this.pauseReasons.add(e)}resume(e){this.pauseReasons.delete(e)&&this.ready&&this.drainNext()}submit(e){return this.running.has(e.event_id)||this.queued.some(t=>t.event_id===e.event_id)?"accepted":this.ready&&this.running.size<this.config.maxConcurrent?(this.startRunning(e),"accepted"):this.config.maxQueued<=0||this.queued.length>=this.config.maxQueued?(this.callbacks.onRejected(e,"queue full"),"rejected"):(this.enqueue(e),"accepted")}cancel(e){const t=this.queued.findIndex(i=>i.event_id===e);if(t>=0){if(!this.config.cancelableQueued)return!1;const[i]=this.queued.splice(t,1);return this.clearTimer(e),this.clearHold(e),this.callbacks.onStateChange(e,i.session_id,"canceled",{reason:"canceled by user"}),this.broadcastQueuePositions(),this.drainNext(),this.checkStopComposing(i.session_id),!0}return this.running.has(e)&&this.config.cancelableRunning?(this.callbacks.onCancelRunning(e),!0):!1}removeQueued(e){const t=this.queued.findIndex(u=>u.event_id===e);if(t<0)return!1;const[i]=this.queued.splice(t,1);this.clearTimer(e);const n=this.clearHold(e);return this.broadcastQueuePositions(),n&&this.drainNext(),this.checkStopComposing(i.session_id),!0}complete(e){const t=this.running.get(e);if(!t)return!1;const i=t?.session_id;return this.running.delete(e),this.adapterDoneEventIds.delete(e),this.clearTimer(e),queueMicrotask(()=>this.drainNext()),i&&this.checkStopComposing(i),!0}clear(e,t="queue cleared"){const i=[],n=[];let u=!1;for(const s of this.queued)s.session_id===e?(this.clearTimer(s.event_id),this.clearHold(s.event_id)&&(u=!0),this.callbacks.onStateChange(s.event_id,e,"canceled",{reason:t}),i.push(s.event_id)):n.push(s);return this.queued=n,i.length>0&&this.broadcastQueuePositions(),u&&this.drainNext(),this.checkStopComposing(e),i}reorder(e,t){const i=[],n=[];if(this.queued.forEach((o,r)=>{o.session_id===e&&(i.push(r),n.push(o))}),n.length===0)return[];const u=new Map(n.map(o=>[o.event_id,o])),s=[];for(const o of t){const r=u.get(o);r&&(u.delete(o),s.push(r))}for(const o of n)u.has(o.event_id)&&s.push(o);return s.some((o,r)=>o!==n[r])&&(i.forEach((o,r)=>{this.queued[o]=s[r]}),this.drainNext()),s.map(o=>o.event_id)}hold(e,t,i){if(!this.queued.find(r=>r.event_id===e))return"not_found";const s=Number.isFinite(i)&&i>0?Math.min(18e5,Math.max(6e4,Math.floor(i))):0,a=this.heldEventIds.get(e);a?a.timer&&clearTimeout(a.timer):this.clearTimer(e);const o=s>0?setTimeout(()=>{this.expireHold(e)},s):null;return o?.unref(),this.heldEventIds.set(e,{reason:t||"manual",expireAt:s>0?Date.now()+s:0,timer:o}),this.broadcastQueuePositions(),"ok"}release(e){return this.queued.findIndex(i=>i.event_id===e)<0?"not_found":(this.clearHold(e)&&(this.armQueueTimeout(e),this.broadcastQueuePositions(),queueMicrotask(()=>this.drainNext())),"ok")}editQueued(e,t){if(typeof t!="string"||t.trim().length===0)return"empty_content";const i=this.queued.find(n=>n.event_id===e);return i?(i.content=t,this.heldEventIds.has(e)?this.release(e):this.broadcastQueuePositions(),"ok"):"not_found"}expireHold(e){this.heldEventIds.has(e)&&this.release(e)==="not_found"&&this.clearHold(e)}clearHold(e){const t=this.heldEventIds.get(e);return t?(t.timer&&clearTimeout(t.timer),this.heldEventIds.delete(e),!0):!1}armQueueTimeout(e){if(this.config.queueTimeoutMs<=0)return;this.clearTimer(e);const t=setTimeout(()=>{this.timeoutEvent(e)},this.config.queueTimeoutMs);t.unref(),this.timers.set(e,t)}drainQueuedForSession(e){const t=[],i=[];for(const n of this.queued)n.session_id===e?(this.clearTimer(n.event_id),this.clearHold(n.event_id),t.push(n)):i.push(n);return this.queued=i,t}snapshot(e){const t=[...this.running.values()].filter(s=>s.session_id===e),i=t.map(s=>s.event_id),n=t.map(s=>({event_id:s.event_id,content_preview:this.buildQueueItemTitle(s.content),title:this.buildQueueItemTitle(s.content),summary:this.buildQueueItemTitle(s.content)})),u=this.queued.flatMap((s,a)=>{if(s.session_id!==e)return[];const o=this.heldEventIds.get(s.event_id);return[{event_id:s.event_id,position:a+1,content_preview:this.buildQueueItemTitle(s.content),content:s.content,title:this.buildQueueItemTitle(s.content),summary:this.buildQueueItemTitle(s.content),held:!!o,held_reason:o?.reason??""}]});return{running:i,running_items:n,queued:u}}hasCapacity(){return this.running.size<this.config.maxConcurrent}get runningCount(){return this.running.size}get queuedCount(){return this.queued.length}destroy(){for(const e of this.timers.values())clearTimeout(e);this.timers.clear();for(const e of this.heldEventIds.values())e.timer&&clearTimeout(e.timer);this.heldEventIds.clear();for(const e of this.composingTimers.values())clearInterval(e);this.composingTimers.clear(),this.queued=[],this.running.clear(),this.pauseReasons.clear()}enqueue(e){this.queued.push(e);const t=this.queued.length;this.callbacks.onStateChange(e.event_id,e.session_id,"queued",{queue_position:t,queue_total:t,actions:this.config.cancelableQueued?[{type:"cancel"}]:[],content_preview:this.buildQueueItemTitle(e.content),content:e.content,held:!1,held_reason:""}),this.armQueueTimeout(e.event_id),this.ensureComposing(e.session_id)}timeoutEvent(e){const t=this.queued.findIndex(n=>n.event_id===e);if(t<0||this.heldEventIds.has(e))return;const[i]=this.queued.splice(t,1);this.timers.delete(e),this.callbacks.onStateChange(e,i.session_id,"failed",{reason:"queue timeout"}),this.broadcastQueuePositions(),this.drainNext(),this.checkStopComposing(i.session_id)}startRunning(e){this.running.set(e.event_id,e),this.callbacks.onStateChange(e.event_id,e.session_id,"running",{actions:this.config.cancelableRunning?[{type:"stop"}]:[],content_preview:this.buildQueueItemTitle(e.content),content:e.content}),this.ensureComposing(e.session_id),this.callbacks.onDeliver(e)}drainNext(){for(;this.ready&&this.running.size<this.config.maxConcurrent&&this.queued.length>0&&!this.heldEventIds.has(this.queued[0].event_id);){const e=this.queued.shift();this.clearTimer(e.event_id),this.startRunning(e)}this.queued.length>0&&this.broadcastQueuePositions()}broadcastQueuePositions(){const e=this.queued.length;for(let t=0;t<e;t++){const i=this.queued[t],n=this.heldEventIds.get(i.event_id);this.callbacks.onStateChange(i.event_id,i.session_id,"queued",{queue_position:t+1,queue_total:e,actions:this.config.cancelableQueued?[{type:"cancel"}]:[],content_preview:this.buildQueueItemTitle(i.content),content:i.content,held:!!n,held_reason:n?.reason??""})}}clearTimer(e){const t=this.timers.get(e);t&&(clearTimeout(t),this.timers.delete(e))}buildQueueItemTitle(e){const t=String(e??"").replace(/\s+/g," ").trim();return t?t.length>64?`${t.slice(0,64)}...`:t:"Message"}ensureComposing(e){if(!this.callbacks.onComposing||this.composingTimers.has(e))return;this.callbacks.onComposing(e,!0,this.getFirstRunningEventId(e));const t=setInterval(()=>{this.sessionHasEvents(e)?this.callbacks.onComposing(e,!0,this.getFirstRunningEventId(e)):this.stopComposing(e)},25e3);t.unref(),this.composingTimers.set(e,t)}checkStopComposing(e){this.sessionHasEvents(e)||this.stopComposing(e)}markAdapterDone(e){const t=this.running.get(e);t&&(this.adapterDoneEventIds.add(e),this.sessionHasEvents(t.session_id)||this.stopComposing(t.session_id))}stopComposing(e){const t=this.composingTimers.get(e);t&&(clearInterval(t),this.composingTimers.delete(e)),this.callbacks.onComposing?.(e,!1)}sessionHasEvents(e){for(const t of this.running.values())if(t.session_id===e&&!this.adapterDoneEventIds.has(t.event_id))return!0;return this.queued.some(t=>t.session_id===e)}getFirstRunningEventId(e){for(const t of this.running.values())if(t.session_id===e&&!this.adapterDoneEventIds.has(t.event_id))return t.event_id}}export{f as EventQueue,c as QUEUE_COMPOSING_INTERVAL_MS,d as QUEUE_COMPOSING_TTL_MS};
@@ -1 +1 @@
1
- import{readJSONFile as o,writeJSONFileAtomic as e}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(i=>typeof i=="string"&&i.trim().length>0):[]}async function s(t,r){await e(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};
1
+ import{readJSONFile as o,writeJSONFileAtomic as i}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(e=>typeof e=="string"&&e.trim().length>0):[]}async function s(t,r){await i(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};
@@ -1,2 +1,2 @@
1
- import{EventEmitter as A}from"node:events";import{randomUUID as T}from"node:crypto";import $ from"node:os";import y from"ws";import{log as m}from"../log/index.js";import{getMachineName as S}from"../util/index.js";import{detectTailnetIPv4 as I,ensureServerAndGetPort as P,getFileServerHttpsPort as F}from"../files/file-serve.js";import{TerminalOutbox as M}from"../persistence/terminal-outbox.js";import{TerminalCommitTokenStore as q}from"../persistence/terminal-commit-token-store.js";import{StopResultOutbox as B}from"../persistence/stop-result-outbox.js";import{AUTH_CODE_AGENT_DELETED as w,KICKED_REASON_AGENT_DELETED as R,AgentDeletedError as C,RequestTimeoutError as N}from"./errors.js";function D(E){let e="",t=0,n=!1,s=!1;for(;t<E.length;){const i=E[t];if(n){e+=i,s?s=!1:i==="\\"?s=!0:i==='"'&&(n=!1),t++;continue}if(i==='"'){n=!0,e+=i,t++;continue}if(i==="-"||i>="0"&&i<="9"){const r=t;i==="-"&&t++;const u=t;for(;t<E.length&&E[t]>="0"&&E[t]<="9";)t++;let o=!1;if(E[t]===".")for(o=!0,t++;t<E.length&&E[t]>="0"&&E[t]<="9";)t++;if(E[t]==="e"||E[t]==="E")for(o=!0,t++,(E[t]==="+"||E[t]==="-")&&t++;t<E.length&&E[t]>="0"&&E[t]<="9";)t++;const h=E.slice(r,t),a=t-u;e+=!o&&a>=16?`"${h}"`:h;continue}e+=i,t++}return e}function x(E){const e=[...E??["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("terminal_commit_v1")||e.push("terminal_commit_v1"),e.includes("audit_replay_v2")||e.push("audit_replay_v2"),e.includes("session_send_quote_v1")||e.push("session_send_quote_v1"),e}function W(E){const e=[...E??["exec_approve","exec_reject"]];return e.includes("apply_relay_state")||e.push("apply_relay_state"),e}const U="aibot-agent-api-v1",L=1;class p extends A{static DROPPABLE_COMMANDS=new Set(["update_binding_card"]);static BUFFER_OVERFLOW_RETAIN_COMMANDS=new Set(["event_result","codex_event","client_stream_chunk","send_msg","audit_state"]);static MAX_OUTBOUND_BUFFER_SIZE=1e3;static MAX_OUTBOUND_BUFFER_HARD_SIZE=1200;static BACKPRESSURE_THRESHOLD=64*1024;static TERMINAL_RETRY_DELAY_MS=15e3;static MAX_TOKENIZED_TERMINAL_REJECTIONS=5;static EVENT_CORRELATION_TTL_MS=5*6e4;static MAX_EVENT_CORRELATIONS=1024;static MAX_BLOCKED_OUTPUT_EVENTS=4096;static MAX_COMMITTED_TERMINAL_EVENTS=4096;static OUTBOUND_WRITE_CALLBACK_TIMEOUT_MS=1e4;static MIN_REQUIRED_OUTPUT_ACK_TIMEOUT_MS=2e4;static ORDERED_OUTPUT_COMMANDS=new Set(["client_stream_chunk","send_msg","codex_event"]);ws=null;seq=0;heartbeatTimer=null;heartbeatSec=30;heartbeatFailures=0;static HEARTBEAT_MAX_FAILURES=2;connected=!1;reconnecting=!1;reconnectAttempts=0;reconnectRunGeneration=0;everConnected=!1;agentDeleted=!1;config;packetLog;pendingInvokes=new Map;eventCorrelations=new Map;clientMsgEventMap=new Map;eventCorrelationCleanupTimer=null;lastCorrelationPruneAt=0;pendingRequests=new Map;outboundBuffer=[];outboundEntryOrders=new WeakMap;nextOutboundEntryOrder=0;connectionGeneration=0;nextOutboundFlushGeneration=0;outboundFlushInFlight=null;pendingOutputWrites=new Map;pendingOutputSeqsByEvent=new Map;pendingAcceptedOutputs=new Map;pendingAcceptedOutputSeqsByEvent=new Map;pendingAcceptedSeqsByClientMsgId=new Map;nonReplayableOutputEventsBySocket=new Map;provisionalRespondedTerminals=new Map;outputIntegrityFailed=new Map;blockedOutputEvents=new Map;committedTerminalEvents=new Set;ackPolicy=null;negotiatedCapabilities=new Set;terminalOutbox;terminalCommitTokens;stopResultOutbox;terminalInFlight=new Set;terminalRetryTimers=new Map;terminalReplayAfterFlight=new Set;tokenizedTerminalRejections=new Map;stopResultInFlight=new Set;stopResultRetryTimers=new Map;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:x(e.capabilities),localActions:W(e.localActions),skills:e.skills,librarySkills:e.librarySkills,sharedOwnerId:e.sharedOwnerId,concurrency:e.concurrency,terminalOutboxPath:e.terminalOutboxPath,terminalCommitTokenStorePath:e.terminalCommitTokenStorePath,stopResultOutboxPath:e.stopResultOutboxPath},this.terminalOutbox=new M(this.config.terminalOutboxPath),this.terminalCommitTokens=new q(this.config.terminalCommitTokenStorePath??(this.config.terminalOutboxPath?`${this.config.terminalOutboxPath}.tokens`:void 0)),this.stopResultOutbox=new B(this.config.stopResultOutboxPath??(this.config.terminalOutboxPath?`${this.config.terminalOutboxPath}.stops`:void 0));for(const n of this.terminalOutbox.listPending())n.payload.code==="agent_output_integrity_failed"&&this.blockEventOutput(n.payload.event_id)}get isConnected(){return this.connected}async connect(){this.negotiatedCapabilities.clear();const e=this.ws,t=this.connectionGeneration;if(this.pendingRequests.size>0&&this.rejectAllPendingRequests("connection generation replaced"),e){this.connected=!1,this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers();const o=this.outboundFlushInFlight;o&&o.socket===e&&o.connectionGeneration===t&&this.cancelOutboundFlush(o,"connection_lost","connection generation replaced"),this.failNonReplayableOutputsForSocket(e,"connection generation replaced"),this.abortPendingOutputWrites(!0,e,t,"connection generation replaced"),this.abortPendingAcceptedOutputs(!0,e,t),this.clearAllEventCorrelations(),this.connectionGeneration++;try{e.close(1012,"connection generation replaced")}catch{}this.ws===e&&(this.ws=null)}else this.outboundFlushInFlight&&this.cancelOutboundFlush(this.outboundFlushInFlight,"discard","detached connection generation replaced");const n=++this.connectionGeneration;let s,i,r;const u=(async()=>{try{if(s=await I(),s!==void 0)try{i=await P(s);const o=F();o>0&&(r=o)}catch(o){m.warn("aibot",`file server pre-start failed: ${o}`)}}catch(o){m.warn("aibot",`tailnet detect failed: ${o}`)}})();return new Promise((o,h)=>{const a=new y(this.config.url);this.ws=a;const d=setTimeout(()=>{if(!this.isConnectionCurrent(a,n))return;const c=this.pendingRequests.get(_);c&&(this.pendingRequests.delete(_),clearTimeout(c.timer),c.reject(new Error("Auth timeout: no auth_ack received within 15s"))),this.cleanupSocket(a,n)},15e3),_=++this.seq,b=setTimeout(()=>{if(!this.isConnectionCurrent(a,n))return;const c=this.pendingRequests.get(_);c&&(this.pendingRequests.delete(_),c.reject(new Error("Auth request timeout"))),this.cleanupSocket(a,n)},15e3);this.pendingRequests.set(_,{expected:["auth_ack"],resolve:c=>{clearTimeout(d);const l=c.payload;if(l.code===0){this.negotiatedCapabilities=new Set(Array.isArray(l.supported_capabilities)?l.supported_capabilities:[]),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,m.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();const f=this.flushOutboundBuffer(a,n);this.emit("auth",l),o(l),f.then(g=>{this.isConnectionCurrent(a,n)&&(g?(this.replayTerminalOutbox(),this.replayStopResultOutbox()):this.reconnectAfterOutboundFlushFailure(a,n))})}else l.code===w?(this.agentDeleted=!0,h(new C(`Agent deleted: code=${l.code} msg=${l.msg}`))):h(new Error(`Auth failed: code=${l.code} msg=${l.msg}`))},reject:c=>{clearTimeout(d),h(c)},timer:b}),a.on("open",async()=>{if(await u,!this.isConnectionCurrent(a,n))return;const c={agent_id:this.config.agentId,api_key:this.config.apiKey,client_type:this.config.clientType,protocol_version:U,contract_version:L,capabilities:this.config.capabilities??[],local_actions:this.config.localActions,skills:this.config.skills,library_skills:this.config.librarySkills};this.config.sharedOwnerId&&(c.shared_owner_id=this.config.sharedOwnerId),this.config.clientVersion&&(c.client="grix-connector",c.client_version=this.config.clientVersion,c.host_type=this.config.clientType,c.host_version=this.config.clientVersion),this.config.adapterHint&&(c.adapter_hint=this.config.adapterHint),c.host_meta={hostname:S(),platform:$.platform(),arch:$.arch(),os_release:$.release(),...s!==void 0&&{tailnet_ip:s},...i!==void 0&&i>0&&{file_server_port:i},...r!==void 0&&r>0&&{file_server_https_port:r}},this.config.concurrency&&(c.concurrency=this.config.concurrency),this.sendPacket("auth",c,_)}),a.on("message",c=>{if(!this.isConnectionCurrent(a,n))return;let l;try{l=JSON.parse(D(c.toString()))}catch{return}try{this.handlePacket(l)}catch(f){this.emitClientError(new Error(`handlePacket error: ${f}`))}}),a.on("close",(c,l)=>{if(!this.isConnectionCurrent(a,n))return;const f=this.everConnected&&!this.agentDeleted;this.connected=!1,this.negotiatedCapabilities.clear(),this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers(),this.rejectAllPendingRequests("websocket closed");const g=`websocket closed code=${c} reason=${l.toString()||"<none>"}`,O=this.outboundFlushInFlight;O&&O.socket===a&&O.connectionGeneration===n&&this.cancelOutboundFlush(O,f?"connection_lost":"discard",g),f?this.failNonReplayableOutputsForSocket(a,g):this.nonReplayableOutputEventsBySocket.delete(a),this.abortPendingOutputWrites(f,a,n,f?g:void 0),this.abortPendingAcceptedOutputs(f,a,n),this.clearAllEventCorrelations(),this.ws===a&&(this.ws=null),this.connectionGeneration++,this.emit("close",c,l.toString());const k=f;m.info("aibot",`ws closed agent=${this.config.clientType}:${this.config.agentId} code=${c} reason=${l.toString()||"<none>"} everConnected=${this.everConnected} reconnecting=${this.reconnecting} agentDeleted=${this.agentDeleted} willReconnect=${k}`),k&&this.attemptReconnect(c===1e3||c===1001)}),a.on("error",c=>{if(this.isConnectionCurrent(a,n)&&(this.emitClientError(c instanceof Error?c:new Error(String(c))),!this.connected)){const l=this.pendingRequests.get(_);l&&(this.pendingRequests.delete(_),clearTimeout(l.timer),l.reject(c instanceof Error?c:new Error(String(c))))}})})}handlePacket(e){if(this.packetLog?.logInboundPacket(e.cmd,e.seq,e.payload),this.handleCorrelatedSendResponse(e),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":{const t=e.payload;if(!this.captureInboundTerminalCommitToken(t.event_id,t.terminal_commit_token))break;this.emit("event",t);break}case"local_action":{this.emit("localAction",e.payload);break}case"event_stop":{const t=e.payload;if(!this.captureInboundTerminalCommitToken(t.event_id,t.terminal_commit_token))break;this.emit("stop",t);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;this.emit("kicked",t),this.connected=!1,this.negotiatedCapabilities.clear(),this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers(),this.rejectAllPendingRequests("kicked");const n=this.ws,s=this.connectionGeneration,i=this.outboundFlushInFlight;if(i&&n&&i.socket===n&&i.connectionGeneration===this.connectionGeneration&&this.cancelOutboundFlush(i,t?.reason===R?"discard":"connection_lost",`kicked reason=${t?.reason??"<none>"}`),t?.reason!==R&&n&&this.failNonReplayableOutputsForSocket(n,`kicked reason=${t?.reason??"<none>"}`),this.abortPendingOutputWrites(t?.reason!==R,n??void 0,s,t?.reason!==R?`kicked reason=${t?.reason??"<none>"}`:void 0),this.abortPendingAcceptedOutputs(t?.reason!==R,n??void 0,s),this.clearAllEventCorrelations(),this.connectionGeneration++,t?.reason===R){if(this.agentDeleted=!0,this.reconnecting=!1,this.outboundBuffer.length=0,this.outputIntegrityFailed.clear(),this.nonReplayableOutputEventsBySocket.clear(),this.ws){try{this.ws.close(4001,"kicked")}catch{}this.ws=null}m.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===n&&(this.ws=null)}this.attemptReconnect();break}case"error":{const t=e.payload,n=[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}${n?` ${n}`:""}`));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":break;case"local_action_ack":break;default:break}}captureInboundTerminalCommitToken(e,t){const n=t?.trim();if(!n)return!0;if(!e?.trim())return this.rejectInboundTerminalCommitToken("tokenized event is missing event_id"),!1;if(!this.negotiatedCapabilities.has("terminal_commit_v1"))return this.rejectInboundTerminalCommitToken(`tokenized event received without terminal_commit_v1 negotiation event=${e}`),!1;try{return this.terminalCommitTokens.register(e,n),!0}catch(s){return this.rejectInboundTerminalCommitToken(`terminal commit token persist failed event=${e}: ${s instanceof Error?s.message:s}`),!1}}rejectInboundTerminalCommitToken(e){this.emitClientError(new Error(e));const t=this.ws;if(t)try{t.close(1011,"terminal commit token persistence failed")}catch{}}withTerminalCommitToken(e){const t=e.event_id.trim();if(!t)throw new Error("terminal event_result is missing event_id");const n=e.terminal_commit_token?.trim(),s=this.terminalCommitTokens.get(t);if(n&&s&&n!==s)throw new Error(`terminal commit token mismatch for event=${t}`);n&&!s&&this.terminalCommitTokens.register(t,n);const i=s??n;return i?{...e,event_id:t,terminal_commit_token:i}:{...e,event_id:t}}sendEventAck(e){this.sendPacket("event_ack",e)||m.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&&(m.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){const t={...e,client_msg_id:e.client_msg_id?.trim()||T()};this.sendPacket("send_msg",t)||m.warn("aibot",`send_msg NOT sent (ws not open) event=${t.event_id??""} session=${t.session_id??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}editMsg(e){this.sendPacket("edit_msg",e)}sendEventResult(e){try{e=this.withTerminalCommitToken(e)}catch(o){this.emitClientError(new Error(`event_result token validation failed: event=${e.event_id}: ${o instanceof Error?o.message:o}`));return}const t=this.terminalOutbox.get(e.event_id);let n,s=this.outputIntegrityFailed.get(e.event_id);const i=t;if(!s&&i?.payload.code==="agent_output_integrity_failed"&&(s={reason:i.payload.msg??"required agent output was discarded before delivery",terminalObserved:!1,terminalSettled:!1},this.outputIntegrityFailed.set(e.event_id,s)),s){if(s.terminalObserved=!0,this.provisionalRespondedTerminals.delete(e.event_id),i&&i.payload.code!=="agent_output_integrity_failed"&&!this.canReplaceUnsentOutputGuard(i)){this.scheduleTerminalDelivery(e.event_id,{ignoreNotBefore:!0});return}if(i?.payload.code==="agent_output_integrity_failed"){this.scheduleTerminalDelivery(e.event_id,{ignoreNotBefore:!0});return}if(s.terminalSettled||this.committedTerminalEvents.has(e.event_id)&&!i){this.outputIntegrityFailed.delete(e.event_id);return}try{n=this.terminalOutbox.enqueue(this.makeOutputIntegrityFailurePayload(e.event_id,s.reason))}catch(o){this.emitClientError(new Error(`output-integrity terminal persist failed: event=${e.event_id}: ${o instanceof Error?o.message:o}`));return}this.scheduleTerminalDelivery(n.payload.event_id,{ignoreNotBefore:!0});return}if(this.committedTerminalEvents.has(e.event_id)&&!t){m.info("aibot",`ignored duplicate terminal after committed ACK event=${e.event_id} status=${e.status}`);return}if(t){if(!(this.canReplaceUnsentOutputGuard(t)&&(e.status==="canceled"||e.status==="failed"))){m.info("aibot",`preserving first durable terminal event=${e.event_id} existing_status=${t.payload.status} ignored_status=${e.status}`),this.scheduleTerminalDelivery(e.event_id,{ignoreNotBefore:!0});return}this.provisionalRespondedTerminals.delete(e.event_id)}if(e.status==="responded"&&this.hasNonReplayableOutput(e.event_id)&&!this.hasPendingOutputAcceptanceFence(e.event_id)){this.markOutputIntegrityFailed(e.event_id,"terminal requested before a complete output acceptance fence");const o=this.outputIntegrityFailed.get(e.event_id);o&&(o.terminalObserved=!0);return}const r=e.status==="responded"&&this.hasUnconfirmedEventOutput(e.event_id),u=r?{...e,status:"failed",code:"agent_output_unconfirmed",msg:"required agent output was not durably confirmed before connector restart",updated_at:Date.now()}:e;r?this.provisionalRespondedTerminals.set(e.event_id,{...e}):this.provisionalRespondedTerminals.delete(e.event_id);try{n=this.terminalOutbox.enqueue(u)}catch(o){this.provisionalRespondedTerminals.delete(e.event_id),this.emitClientError(new Error(`event_result outbox persist failed: event=${e.event_id} status=${e.status}: ${o instanceof Error?o.message:o}`));return}this.scheduleTerminalDelivery(n.payload.event_id,{ignoreNotBefore:!0})}sendLocalActionResult(e){this.sendPacket("local_action_result",e)}sendEventStopAck(e){this.sendPacket("event_stop_ack",e)}sendEventStopResult(e){const t=e.event_id?.trim(),n=e.terminal_commit_token?.trim(),s=t?this.terminalCommitTokens.get(t):void 0;if(n&&s&&n!==s){this.emitClientError(new Error(`event_stop_result token mismatch event=${t??""}`));return}const i=s??n;if(t&&i&&(e.status==="stopped"||e.status==="already_finished")){try{const r=this.stopResultOutbox.enqueue({...e,event_id:t,terminal_commit_token:i});this.scheduleStopResultDelivery(r,{ignoreNotBefore:!0})}catch(r){this.emitClientError(new Error(`event_stop_result outbox persist failed: event=${t} stop=${e.stop_id}: ${r instanceof Error?r.message:r}`))}return}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,n=15e3){return new Promise((s,i)=>{const r=T(),u=Math.max(1e3,Math.min(n,75e3)),o=setTimeout(()=>{this.pendingInvokes.delete(r),i(new Error(`agent_invoke timeout: ${e}`))},u);this.pendingInvokes.set(r,{resolve:s,reject:i,timer:o}),this.sendPacket("agent_invoke",{invoke_id:r,action:e,params:t,timeout_ms:u})})}sendMcpFrame(e,t){this.sendPacket("mcp_frame",{session_id:e,frame:t})}async request(e,t,n){const s=this.outboundFlushInFlight;if(s){if(!await s.promise)throw new Error(`outbound flush failed before request: ${e}`);if(!this.isConnectionCurrent(s.socket,s.connectionGeneration))throw new Error(`connection changed while waiting for outbound flush: ${e}`)}if(!this.connected||!this.ws||this.ws.readyState!==y.OPEN)throw new Error(`send failed: ${e} (websocket not connected)`);return new Promise((i,r)=>{const u=++this.seq,o=setTimeout(()=>{this.pendingRequests.delete(u),r(new N(`request timeout: ${e} (expected ${n.expected.join("/")})`))},n.timeoutMs);this.pendingRequests.set(u,{expected:n.expected,resolve:i,reject:r,timer:o}),this.sendPacket(e,t,u)||(this.pendingRequests.delete(u),clearTimeout(o),r(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 relayStateSyncRequest(e,t=15e3){return this.request("relay_state_sync_request",e,{expected:["relay_state_sync_result","error"],timeoutMs:t})}sendRelayStateReport(e){this.sendPacket("relay_state_report",e)}async sendText(e,t=2e4){return this.request("send_msg",{msg_type:1,...e,client_msg_id:e.client_msg_id?.trim()||T()},{expected:["send_ack","send_nack","error"],timeoutMs:t})}async sendMedia(e,t=2e4){return this.request("send_msg",{...e,msg_type:2,client_msg_id:e.client_msg_id?.trim()||T()},{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,n=2e4){return this.request("delete_msg",{session_id:e,msg_id:t},{expected:["send_ack","send_nack","error"],timeoutMs:n})}async sendEventResultRequest(e,t=5e3){return this.request("event_result",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}disconnect(){m.info("aibot",`disconnect() agent=${this.config.clientType}:${this.config.agentId} wasConnected=${this.connected} reconnecting=${this.reconnecting} reconnectAttempts=${this.reconnectAttempts}`),this.connected=!1,this.negotiatedCapabilities.clear(),this.everConnected=!1,this.reconnecting=!1,this.reconnectRunGeneration++,this.reconnectAttempts=0,this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers();const e=this.ws,t=this.connectionGeneration,n=this.outboundFlushInFlight;n&&this.cancelOutboundFlush(n,"discard","explicit disconnect"),this.connectionGeneration++,this.rejectAllPendingInvokes("disconnect"),this.rejectAllPendingRequests("disconnect"),this.abortPendingOutputWrites(!1,e??void 0,t),this.abortPendingAcceptedOutputs(!1,e??void 0,t),this.clearAllEventCorrelations(),this.outboundBuffer.length=0,this.provisionalRespondedTerminals.clear(),this.outputIntegrityFailed.clear(),this.nonReplayableOutputEventsBySocket.clear(),this.ws&&(this.ws.close(1e3,"client disconnect"),this.ws=null)}static MAX_CONSECUTIVE_AUTH_FAILURES=5;async attemptReconnect(e=!1){if(this.reconnecting||this.agentDeleted)return;this.reconnecting=!0;const t=++this.reconnectRunGeneration;m.info("aibot",`attemptReconnect start agent=${this.config.clientType}:${this.config.agentId} fromAttempts=${this.reconnectAttempts} fastFirstAttempt=${e}`),this.emit("disconnected");let n=0;for(;this.reconnecting&&this.reconnectRunGeneration===t;){const s=e&&this.reconnectAttempts===0,i=s?Math.floor(Math.random()*500):Math.min(1e3*2**this.reconnectAttempts,3e4),r=s?0:Math.floor(i*.2*Math.random());if(this.reconnectAttempts++,await new Promise(h=>setTimeout(h,i+r)),!this.reconnecting||this.reconnectRunGeneration!==t)return;let u=null,o=this.connectionGeneration;try{const h=this.connect();if(u=this.ws,o=this.connectionGeneration,await h,this.reconnectRunGeneration!==t)return;if(!u||!this.isConnectionCurrent(u,o)){if(this.connected&&this.ws){this.reconnecting=!1;return}continue}const a=this.reconnectAttempts;this.reconnectAttempts=0,this.reconnecting=!1,m.info("aibot",`reconnect succeeded agent=${this.config.clientType}:${this.config.agentId} attempt=${a}`);return}catch(h){if(this.reconnectRunGeneration!==t)return;if(u&&!this.isConnectionCurrent(u,o)&&this.connected&&this.ws){this.reconnecting=!1;return}if(u&&this.isConnectionCurrent(u,o)){this.connectionGeneration++;try{u.close()}catch{}this.ws===u&&(this.ws=null)}const a=h instanceof Error?h.message:String(h);if(m.warn("aibot",`reconnect failed agent=${this.config.clientType}:${this.config.agentId} attempt=${this.reconnectAttempts} err=${a}`),h instanceof C){this.agentDeleted=!0,this.reconnecting=!1,m.error("aibot",`reconnect aborted: agent deleted on platform agent=${this.config.clientType}:${this.config.agentId}`),this.emit("agentDeleted",{source:"auth_ack",code:w});return}if(/Auth failed/i.test(a)){if(n++,n>=p.MAX_CONSECUTIVE_AUTH_FAILURES){this.reconnecting=!1,m.error("aibot",`reconnect giving up after ${n} consecutive auth failures agent=${this.config.clientType}:${this.config.agentId}`);return}}else n=0}}}sendPacket(e,t,n){const s=this.outboundEventId(e,t);if(s&&this.blockedOutputEvents.has(s))return this.packetLog?.logOutboundPacket(e,n??0,t,"dropped"),m.warn("aibot",`blocked late output after irreversible event failure event=${s} cmd=${e}`),!1;const i=n===void 0?this.createOutboundEntry(e,t):void 0;if(i&&this.outboundFlushInFlight&&!this.outboundFlushInFlight.finalized&&this.isConnectionCurrent(this.outboundFlushInFlight.socket,this.outboundFlushInFlight.connectionGeneration)&&!p.DROPPABLE_COMMANDS.has(e))return this.bufferOutboundEntry(i),!1;if(this.ws&&this.ws.readyState===y.OPEN&&(e==="auth"||this.connected)){const u=this.ws.bufferedAmount>p.BACKPRESSURE_THRESHOLD;if(!u||!p.DROPPABLE_COMMANDS.has(e)){if(u&&p.DROPPABLE_COMMANDS.has(e))return!1;const o=n??++this.seq,h={cmd:e,seq:o,payload:t};this.packetLog?.logOutboundPacket(e,o,t,"sent");const a=this.ws,d=this.connectionGeneration,_=s;_&&this.trackOutboundEventCorrelation(e,o,t),i&&_&&(this.registerPendingOutputWrite(o,_,i,a,d),this.isAckRequiredOutput(e,t)&&this.registerPendingAcceptedOutput(o,_,i,a,d));let b=!1;try{const c=a.readyState,l=a.bufferedAmount;let f=!1;return a.send(JSON.stringify(h),g=>{if(g&&!f&&(b=!0),e==="event_result"){const v=t;g?m.warn("aibot",`event_result ws send callback failed event=${v.event_id??""} status=${v.status??""} seq=${o} readyState=${c} bufferedAmount=${l} err=${g.message}`):m.info("aibot",`event_result ws send callback ok event=${v.event_id??""} status=${v.status??""} seq=${o} readyState=${c} bufferedAmount=${l}`)}else if(e==="client_stream_chunk"){const v=t;g?m.warn("aibot",`stream_chunk ws send failed event=${v.event_id??""} session=${v.session_id??""} seq=${o} chunk_seq=${v.chunk_seq??""} is_finish=${v.is_finish??""} readyState=${c} bufferedAmount=${l} err=${g.message}`):m.info("aibot",`stream_chunk ws send ok event=${v.event_id??""} session=${v.session_id??""} seq=${o} chunk_seq=${v.chunk_seq??""} is_finish=${v.is_finish??""} client_msg_id=${v.client_msg_id??""} quoted_message_id=${v.quoted_message_id??""} readyState=${c} bufferedAmount=${l}`)}else if(e==="event_ack"){const v=t;g?m.warn("aibot",`event_ack ws send failed event=${v.event_id??""} seq=${o} readyState=${c} bufferedAmount=${l} err=${g.message}`):m.info("aibot",`event_ack ws send ok event=${v.event_id??""} seq=${o} readyState=${c} bufferedAmount=${l}`)}else if(e==="send_msg"){const v=t;g?m.warn("aibot",`send_msg ws send failed event=${v.event_id??""} session=${v.session_id??""} seq=${o} readyState=${c} bufferedAmount=${l} err=${g.message}`):m.info("aibot",`send_msg ws send ok event=${v.event_id??""} session=${v.session_id??""} seq=${o} readyState=${c} bufferedAmount=${l}`)}else if(g){const v=t;m.warn("aibot",`${e} ws send failed seq=${o} session=${v.session_id??""} event=${v.event_id??""} client_msg_id=${v.client_msg_id??""} readyState=${c} bufferedAmount=${l} err=${g.message}`)}const O=this.pendingOutputWrites.get(o),k=!!(O&&O.socket===a&&O.connectionGeneration===d);if(!this.isConnectionCurrent(a,d)){k&&(this.settlePendingOutputWrite(o,!1,!1,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d));return}if(!(i&&_&&!k)){if(g)this.removeSeqFromEventCorrelation(o),_?(this.settlePendingOutputWrite(o,!1,!0,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d)):i&&this.bufferOutboundEntry(i),n!==void 0?this.rejectPendingRequestAfterWriteFailure(o,e,g):i&&this.reconnectAfterOutboundWriteFailure(a,`${e} callback failed`);else if(_){const v=k;this.settlePendingOutputWrite(o,!0,!1,a,d),v&&this.trackNonReplayableOutput(a,e,t,o)}}}),f=!0,!b}catch(c){return this.isConnectionCurrent(a,d)?(this.removeSeqFromEventCorrelation(o),_?(this.settlePendingOutputWrite(o,!1,!0,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d)):i&&this.bufferOutboundEntry(i),this.emitClientError(new Error(`sendPacket failed: ${c}`)),i&&this.reconnectAfterOutboundWriteFailure(a,`${e} send threw`),!1):(this.settlePendingOutputWrite(o,!1,!1,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d),!1)}}}if(p.DROPPABLE_COMMANDS.has(e))return this.packetLog?.logOutboundPacket(e,n??0,t,"dropped"),!1;if(n!==void 0)return this.packetLog?.logOutboundPacket(e,n,t,"dropped"),!1;const r=this.bufferOutboundEntry(i??this.createOutboundEntry(e,t));if(this.packetLog?.logOutboundPacket(e,n??0,t,r?"buffered":"dropped"),r&&e==="client_stream_chunk"){const u=t;m.info("aibot",`stream_chunk buffered (ws not open) event=${u.event_id??""} session=${u.session_id??""} chunk_seq=${u.chunk_seq??""} is_finish=${u.is_finish??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}return!1}replayTerminalOutbox(){for(const e of this.terminalOutbox.listPending())this.scheduleTerminalDelivery(e.payload.event_id,{ignoreNotBefore:!0})}outboundEventId(e,t){if(!p.ORDERED_OUTPUT_COMMANDS.has(e)||!t||typeof t!="object")return"";const n=t.event_id;return typeof n=="string"?n.trim():""}blockEventOutput(e){const t=e.trim();if(t)for(this.blockedOutputEvents.delete(t),this.blockedOutputEvents.set(t,Date.now()),this.outboundBuffer=this.outboundBuffer.filter(n=>this.outboundEventId(n.cmd,n.payload)!==t);this.blockedOutputEvents.size>p.MAX_BLOCKED_OUTPUT_EVENTS;){const n=this.blockedOutputEvents.keys().next().value;if(!n)break;this.blockedOutputEvents.delete(n)}}isAckRequiredOutput(e,t){return e==="send_msg"?!0:e==="client_stream_chunk"&&!!t&&typeof t=="object"&&t.is_finish===!0}isNonReplayableOutput(e,t){return e==="codex_event"?!0:e==="client_stream_chunk"&&!!t&&typeof t=="object"&&t.is_finish!==!0}trackNonReplayableOutput(e,t,n,s){if(!this.isNonReplayableOutput(t,n))return;const i=this.outboundEventId(t,n);if(!i||this.outputIntegrityFailed.has(i)||this.blockedOutputEvents.has(i))return;let r=this.nonReplayableOutputEventsBySocket.get(e);r||(r=new Map,this.nonReplayableOutputEventsBySocket.set(e,r)),r.set(i,Math.max(r.get(i)??0,s))}clearNonReplayableOutputThrough(e,t,n){if(!e||n<=0)return;const s=this.nonReplayableOutputEventsBySocket.get(e);if(!s)return;const i=s.get(t);i===void 0||i>n||(s.delete(t),s.size===0&&this.nonReplayableOutputEventsBySocket.delete(e))}clearNonReplayableOutputEvent(e){for(const[t,n]of this.nonReplayableOutputEventsBySocket)n.delete(e),n.size===0&&this.nonReplayableOutputEventsBySocket.delete(t)}failNonReplayableOutputsForSocket(e,t){const n=this.nonReplayableOutputEventsBySocket.get(e);if(n){this.nonReplayableOutputEventsBySocket.delete(e);for(const s of n.keys())this.markOutputIntegrityFailed(s,`connection lost before a complete output acceptance fence: ${t}`)}}hasNonReplayableOutput(e){for(const t of this.nonReplayableOutputEventsBySocket.values())if(t.has(e))return!0;return!1}hasPendingOutputAcceptanceFence(e){return!!(this.pendingAcceptedOutputSeqsByEvent.get(e)?.size||this.outboundBuffer.some(t=>this.outboundEventId(t.cmd,t.payload)===e&&this.isAckRequiredOutput(t.cmd,t.payload)))}hasUnconfirmedEventOutput(e){return!!(this.pendingOutputSeqsByEvent.get(e)?.size||this.pendingAcceptedOutputSeqsByEvent.get(e)?.size||this.outboundBuffer.some(t=>this.outboundEventId(t.cmd,t.payload)===e))}trackOutboundEventCorrelation(e,t,n){const s=this.outboundEventId(e,n);if(!s)return;const i=n,r=typeof i.client_msg_id=="string"?i.client_msg_id.trim():"";this.pruneExpiredEventCorrelations();const u=Date.now();let o=this.eventCorrelations.get(s);if(!o){if(this.eventCorrelations.size>=p.MAX_EVENT_CORRELATIONS){let a;for(const d of this.eventCorrelations.values())this.eventHasCriticalDeliveryState(d.eventId)||(!a||d.touchedAt<a.touchedAt)&&(a=d);a&&this.releaseEventCorrelations(a.eventId)}o={eventId:s,clientMsgIds:new Set,seqRanges:[],touchedAt:u,expiresAt:u+p.EVENT_CORRELATION_TTL_MS},this.eventCorrelations.set(s,o)}o.touchedAt=u,o.expiresAt=u+p.EVENT_CORRELATION_TTL_MS;const h=o.seqRanges[o.seqRanges.length-1];if(h&&t===h.end+1?h.end=t:(!h||t<h.start||t>h.end)&&o.seqRanges.push({start:t,end:t}),r){o.clientMsgIds.add(r);let a=this.clientMsgEventMap.get(r);a||(a=new Set,this.clientMsgEventMap.set(r,a)),a.add(s)}this.scheduleEventCorrelationCleanup()}uniqueEventIdForClientMsgId(e){const t=this.clientMsgEventMap.get(e);if(t?.size===1)return t.values().next().value}eventHasCriticalDeliveryState(e){return!!(this.terminalOutbox.get(e)||this.pendingAcceptedOutputSeqsByEvent.get(e)?.size)}eventIdForSeq(e){if(!(e<=0)){for(const t of this.eventCorrelations.values())if(t.seqRanges.some(n=>e>=n.start&&e<=n.end))return t.eventId}}removeSeqFromEventCorrelation(e){if(!(e<=0))for(const t of this.eventCorrelations.values()){const n=t.seqRanges.findIndex(i=>e>=i.start&&e<=i.end);if(n<0)continue;const s=t.seqRanges[n];s.start===s.end?t.seqRanges.splice(n,1):e===s.start?s.start++:e===s.end?s.end--:t.seqRanges.splice(n,1,{start:s.start,end:e-1},{start:e+1,end:s.end});return}}releaseEventCorrelations(e){const t=e.trim();if(!t)return;const n=this.eventCorrelations.get(t);if(n){for(const s of n.clientMsgIds){const i=this.clientMsgEventMap.get(s);i?.delete(t),i?.size===0&&this.clientMsgEventMap.delete(s)}this.eventCorrelations.delete(t)}this.cancelEventCorrelationCleanupIfEmpty()}clearAllEventCorrelations(){this.eventCorrelationCleanupTimer&&(clearTimeout(this.eventCorrelationCleanupTimer),this.eventCorrelationCleanupTimer=null),this.eventCorrelations.clear(),this.clientMsgEventMap.clear(),this.lastCorrelationPruneAt=0}pruneExpiredEventCorrelations(e=Date.now(),t=!1){if(!(!t&&e-this.lastCorrelationPruneAt<1e3)){this.lastCorrelationPruneAt=e;for(const n of[...this.eventCorrelations.values()])n.expiresAt<=e&&!this.eventHasCriticalDeliveryState(n.eventId)&&this.releaseEventCorrelations(n.eventId);this.cancelEventCorrelationCleanupIfEmpty()}}scheduleEventCorrelationCleanup(){if(this.eventCorrelationCleanupTimer||this.eventCorrelations.size===0)return;let e=Number.POSITIVE_INFINITY;for(const t of this.eventCorrelations.values())this.eventHasCriticalDeliveryState(t.eventId)||(e=Math.min(e,t.expiresAt));Number.isFinite(e)&&(this.eventCorrelationCleanupTimer=setTimeout(()=>{this.eventCorrelationCleanupTimer=null,this.pruneExpiredEventCorrelations(Date.now(),!0),this.scheduleEventCorrelationCleanup()},Math.max(1,e-Date.now())),this.eventCorrelationCleanupTimer.unref?.())}cancelEventCorrelationCleanupIfEmpty(){!this.eventCorrelationCleanupTimer||this.eventCorrelations.size>0||(clearTimeout(this.eventCorrelationCleanupTimer),this.eventCorrelationCleanupTimer=null)}handleCorrelatedSendResponse(e){if(e.cmd==="send_ack"){const h=e.payload,a=typeof h.client_msg_id=="string"?h.client_msg_id.trim():"";let d=e.seq>0&&this.pendingAcceptedOutputs.has(e.seq)?e.seq:void 0,_;if(d===void 0&&a){const l=this.pendingAcceptedSeqsByClientMsgId.get(a);if(l?.size===1){const f=l.values().next().value,g=this.pendingAcceptedOutputs.get(f),O=this.uniqueEventIdForClientMsgId(a);g&&O&&g.eventId===O&&(d=f,_=O)}}const b=(d!==void 0?this.pendingAcceptedOutputs.get(d)?.eventId:void 0)??_??this.eventIdForSeq(e.seq),c=d??e.seq;if(d!==void 0){const l=this.pendingOutputWrites.get(d);l&&this.settlePendingOutputWrite(d,!0,!1,l.socket,l.connectionGeneration),this.settlePendingAcceptedOutput(d,"accepted",!1)}else if(e.seq>0){const l=this.pendingOutputWrites.get(e.seq);l&&this.settlePendingOutputWrite(e.seq,!0,!1,l.socket,l.connectionGeneration)}b&&this.clearNonReplayableOutputThrough(this.ws,b,c);return}if(e.cmd!=="send_nack"&&e.cmd!=="error")return;this.pruneExpiredEventCorrelations();const t=e.payload,n=typeof t.client_msg_id=="string"?t.client_msg_id.trim():"",s=e.cmd==="error"&&typeof t.ref_id=="string"?t.ref_id.trim():"",i=e.cmd==="error"&&typeof t.ref_cmd=="string"?t.ref_cmd.trim():"",r=this.eventIdForSeq(e.seq),u=s&&(!i||p.ORDERED_OUTPUT_COMMANDS.has(i))?this.uniqueEventIdForClientMsgId(s)??(this.eventCorrelations.has(s)?s:void 0):void 0,o=r??(n?this.uniqueEventIdForClientMsgId(n):void 0)??u;o&&(this.blockEventOutput(o),this.settlePendingOutputWritesForEvent(o,!0),this.clearNonReplayableOutputEvent(o),e.seq>0&&this.pendingAcceptedOutputs.get(e.seq)?.eventId===o?this.settlePendingAcceptedOutput(e.seq,"rejected",!1):this.settlePendingAcceptedOutputsForEvent(o,"rejected",!1),t.code===4003&&(this.purgeBufferedStreamChunks(o),m.warn("aibot",`event payload rejected (4003), purging buffered chunks for event=${o}`)),this.promotePendingTerminalAfterOutputRejection(o,Number(t.code??0),t.msg),this.emit("streamRejected",o,Number(t.code??0)))}promotePendingTerminalAfterOutputRejection(e,t,n){this.provisionalRespondedTerminals.delete(e);const s=this.terminalOutbox.get(e);if(!(!s||s.payload.status!=="responded"&&s.payload.code!=="agent_output_unconfirmed"||s.deliveryStartedAt))try{const i=this.terminalOutbox.enqueue({...s.payload,status:"failed",code:"agent_output_rejected",msg:n?`required agent output was rejected: ${n}`:`required agent output was rejected by the server (code=${t})`,updated_at:Date.now()});this.scheduleTerminalDelivery(i.payload.event_id,{ignoreNotBefore:!0})}catch(i){this.emitClientError(new Error(`failed to persist output-rejection terminal promotion: event=${e} code=${t}: ${i instanceof Error?i.message:i}`))}}scheduleTerminalDelivery(e,t){if(!this.connected||!this.ws||this.ws.readyState!==y.OPEN)return;if(this.terminalInFlight.has(e)){t?.ignoreNotBefore&&this.terminalReplayAfterFlight.add(e);return}const n=this.terminalOutbox.get(e);if(!n)return;const s=this.terminalRetryTimers.get(e);s&&(clearTimeout(s),this.terminalRetryTimers.delete(e));const i=t?.ignoreNotBefore?0:Math.max(0,n.nextAttemptAt-Date.now()),r=Math.max(i,t?.minimumDelayMs??0);if(r>0){const u=setTimeout(()=>{this.terminalRetryTimers.delete(e),this.scheduleTerminalDelivery(e,{ignoreNotBefore:!0})},r);this.terminalRetryTimers.set(e,u);return}this.deliverTerminalEntry(n)}async deliverTerminalEntry(e){const t=e.payload.event_id;if(this.terminalInFlight.has(t)||!this.terminalOutbox.isCurrent(e))return;this.terminalInFlight.add(t);let n=0;try{n=await this.sendEventResultReliable(e)}finally{this.terminalInFlight.delete(t);const s=this.terminalReplayAfterFlight.delete(t);this.terminalOutbox.get(t)&&this.scheduleTerminalDelivery(t,s?{ignoreNotBefore:!0}:{minimumDelayMs:n})}}clearTerminalRetryTimers(){for(const e of this.terminalRetryTimers.values())clearTimeout(e);this.terminalRetryTimers.clear()}async sendEventResultReliable(e){const t=e.payload.event_id,n=e.payload.terminal_commit_token?.trim();if(n&&!this.negotiatedCapabilities.has("terminal_commit_v1")){const d=this.ws;return this.emitClientError(new Error(`refusing tokenized event_result on an unnegotiated connection: event=${t}`)),d&&this.reconnectAfterOutboundWriteFailure(d,"terminal_commit_v1 not negotiated"),p.TERMINAL_RETRY_DELAY_MS}if(!await this.awaitOutputDeliveryBarrier(t))return p.TERMINAL_RETRY_DELAY_MS;const s=this.provisionalRespondedTerminals.get(t);if(s&&this.terminalOutbox.isCurrent(e))if(!this.canReplaceUnsentOutputGuard(e))this.provisionalRespondedTerminals.delete(t);else try{return this.terminalOutbox.enqueue(s),this.provisionalRespondedTerminals.delete(t),0}catch(d){return this.emitClientError(new Error(`failed to promote confirmed output terminal to responded: event=${t}: ${d instanceof Error?d.message:d}`)),p.TERMINAL_RETRY_DELAY_MS}const i=e.payload;try{if(!this.terminalOutbox.markDeliveryStarted(e))return 0}catch(d){return this.emitClientError(new Error(`event_result delivery-start persist failed: event=${t}: ${d instanceof Error?d.message:d}`)),p.TERMINAL_RETRY_DELAY_MS}const r=Math.max(1,this.ackPolicy?.max_retries??3),u=this.ackPolicy?.push_ack_timeout_ms??5e3,o=750;let h="unknown delivery failure";for(let d=1;d<=r;d++){if(!this.terminalOutbox.isCurrent(e))return 0;const _=this.ws?.readyState??-1,b=this.ws?.bufferedAmount??0;m.info("aibot",`event_result send attempt event=${i.event_id} status=${i.status} attempt=${d}/${r} readyState=${_} bufferedAmount=${b}`);try{const c=await this.sendEventResultRequest(i,u);if(!this.terminalOutbox.isCurrent(e))return 0;if(c.cmd==="send_ack"){const f=c.payload;if(m.info("aibot",`event_result ack event=${i.event_id} status=${i.status} attempt=${d}/${r} ack_event=${f.event_id??""} ack_status=${f.status??""}`),f.event_id!==i.event_id||f.status!==i.status)throw new Error(`event_result ACK mismatch: expected event=${i.event_id} status=${i.status}, got event=${f.event_id??""} status=${f.status??""}`);if(n&&(f.terminal_commit_token?.trim()!==n||f.terminal_committed!==!0))throw new Error(`event_result terminal commit ACK mismatch: event=${i.event_id}`);if(n)try{this.terminalCommitTokens.remove(i.event_id,n)}catch(g){throw new Error(`terminal commit token cleanup failed: event=${i.event_id}: ${g instanceof Error?g.message:g}`)}return this.terminalOutbox.acknowledge(e,f.event_id,f.status,f.terminal_commit_token,f.terminal_committed)&&(this.rememberCommittedTerminalEvent(i.event_id),this.tokenizedTerminalRejections.delete(i.event_id),this.blockEventOutput(i.event_id),this.releaseEventCorrelations(i.event_id),this.clearNonReplayableOutputEvent(i.event_id),this.settleOutputIntegrityTerminal(i.event_id),this.scheduleStopResultsForEvent(i.event_id)),0}const l=c.payload;if(m.warn("aibot",`event_result rejected event=${i.event_id} status=${i.status} attempt=${d}/${r} cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}${l.ref_cmd?` ref_cmd=${l.ref_cmd}`:""}${l.ref_id?` ref_id=${l.ref_id}`:""}`),n){h=`tokenized terminal rejected: cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}`;const f=(this.tokenizedTerminalRejections.get(i.event_id)??0)+1;if(this.tokenizedTerminalRejections.set(i.event_id,f),f<p.MAX_TOKENIZED_TERMINAL_REJECTIONS)break;this.tokenizedTerminalRejections.delete(i.event_id);try{this.terminalCommitTokens.remove(i.event_id,n),this.terminalOutbox.moveToDeadLetter(e,{responseCmd:c.cmd,code:l.code,message:l.msg})&&(this.blockEventOutput(i.event_id),this.releaseEventCorrelations(i.event_id),this.clearNonReplayableOutputEvent(i.event_id),this.settleOutputIntegrityTerminal(i.event_id),this.emitClientError(new Error(`tokenized event_result permanently rejected after ${f} rejections, moved to dead-letter: event=${i.event_id} status=${i.status} cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}`)))}catch(g){h=`dead-letter persist failed: ${g instanceof Error?g.message:g}`,this.emitClientError(new Error(`tokenized event_result dead-letter persist failed: event=${i.event_id} status=${i.status}: ${h}`));break}return 0}try{return this.terminalOutbox.moveToDeadLetter(e,{responseCmd:c.cmd,code:l.code,message:l.msg})&&(this.tokenizedTerminalRejections.delete(i.event_id),this.blockEventOutput(i.event_id),this.releaseEventCorrelations(i.event_id),this.clearNonReplayableOutputEvent(i.event_id),this.settleOutputIntegrityTerminal(i.event_id),this.emitClientError(new Error(`event_result rejected and moved to dead-letter: event=${i.event_id} status=${i.status} cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}`))),0}catch(f){h=`dead-letter persist failed: ${f instanceof Error?f.message:f}`,this.emitClientError(new Error(`event_result dead-letter persist failed: event=${i.event_id} status=${i.status}: ${h}`));break}}catch(c){const l=c instanceof Error?c.message:String(c);if(h=l,m.warn("aibot",`event_result attempt failed event=${i.event_id} status=${i.status} attempt=${d}/${r} err=${l}`),d===r)break;await new Promise(f=>setTimeout(f,o*d))}}const a=Date.now()+p.TERMINAL_RETRY_DELAY_MS;try{this.terminalOutbox.recordRetry(e,a,h)}catch(d){this.emitClientError(new Error(`event_result retry state persist failed: event=${i.event_id} status=${i.status}: ${d instanceof Error?d.message:d}`))}return this.emitClientError(new Error(`event_result ack failed after ${r} attempts; retained for retry: event=${i.event_id} status=${i.status} err=${h}`)),p.TERMINAL_RETRY_DELAY_MS}purgeBufferedStreamChunks(e){const t=this.outboundBuffer.length;this.outboundBuffer=this.outboundBuffer.filter(n=>n.cmd!=="client_stream_chunk"?!0:n.payload?.event_id!==e),this.outboundBuffer.length<t&&m.info("aibot",`purged ${t-this.outboundBuffer.length} buffered stream chunks for event=${e}`)}emitClientError(e){if(this.listenerCount("error")===0){m.warn("aibot",`Client error (no listeners): ${e.message}`);return}this.emit("error",e)}createOutboundEntry(e,t){const n={cmd:e,payload:t};return this.outboundEntryOrders.set(n,++this.nextOutboundEntryOrder),n}makeOutputIntegrityFailurePayload(e,t){return this.withTerminalCommitToken({event_id:e,status:"failed",code:"agent_output_integrity_failed",msg:`required agent output was discarded before delivery: ${t}`,updated_at:Date.now()})}canReplaceUnsentOutputGuard(e){return e.payload.code==="agent_output_unconfirmed"&&!e.deliveryStartedAt}rememberCommittedTerminalEvent(e){for(this.committedTerminalEvents.delete(e),this.committedTerminalEvents.add(e);this.committedTerminalEvents.size>p.MAX_COMMITTED_TERMINAL_EVENTS;){const t=this.committedTerminalEvents.values().next().value;if(!t)break;this.committedTerminalEvents.delete(t)}}replayStopResultOutbox(){for(const e of this.stopResultOutbox.listPending())this.scheduleStopResultDelivery(e,{ignoreNotBefore:!0})}scheduleStopResultsForEvent(e){for(const t of this.stopResultOutbox.listPending())t.payload.event_id===e&&this.scheduleStopResultDelivery(t,{ignoreNotBefore:!0})}scheduleStopResultDelivery(e,t){if(!this.connected||!this.ws||this.ws.readyState!==y.OPEN||!this.stopResultOutbox.isCurrent(e))return;const n=e.payload.event_id;if(this.terminalOutbox.get(n)||this.terminalCommitTokens.get(n))return;const s=this.stopResultRetryTimers.get(e.key);s&&(clearTimeout(s),this.stopResultRetryTimers.delete(e.key));const i=t?.ignoreNotBefore?0:Math.max(0,e.nextAttemptAt-Date.now());if(i>0){const r=setTimeout(()=>{this.stopResultRetryTimers.delete(e.key),this.scheduleStopResultDelivery(e,{ignoreNotBefore:!0})},i);this.stopResultRetryTimers.set(e.key,r);return}this.deliverStopResultEntry(e)}async deliverStopResultEntry(e){if(this.stopResultInFlight.has(e.key)||!this.stopResultOutbox.isCurrent(e))return;this.stopResultInFlight.add(e.key);let t=p.TERMINAL_RETRY_DELAY_MS;try{t=await this.sendStopResultReliable(e)}finally{if(this.stopResultInFlight.delete(e.key),this.stopResultOutbox.isCurrent(e)){const n=setTimeout(()=>{this.stopResultRetryTimers.delete(e.key),this.scheduleStopResultDelivery(e,{ignoreNotBefore:!0})},t);this.stopResultRetryTimers.set(e.key,n)}}}async sendStopResultReliable(e){const t=this.ackPolicy?.push_ack_timeout_ms??5e3;let n="unknown delivery failure";try{const i=await this.request("event_stop_result",e.payload,{expected:["send_ack","send_nack","error"],timeoutMs:t});if(!this.stopResultOutbox.isCurrent(e))return 0;if(i.cmd==="send_ack"){const r=i.payload;if(this.stopResultOutbox.acknowledge(e,r.event_id,r.terminal_commit_token,r.terminal_committed))return 0;n=`event_stop_result ACK mismatch event=${e.payload.event_id}`}else{const r=i.payload;if(n=`event_stop_result rejected: cmd=${i.cmd} code=${r.code??""} msg=${r.msg??""}`,r.code===4001||r.code===4003){try{this.stopResultOutbox.discard(e)&&this.emitClientError(new Error(`event_stop_result permanently rejected and discarded: event=${e.payload.event_id} stop=${e.payload.stop_id} code=${r.code} msg=${r.msg??""}`))}catch(u){this.emitClientError(new Error(`event_stop_result discard persist failed: event=${e.payload.event_id} stop=${e.payload.stop_id}: ${u instanceof Error?u.message:u}`))}return 0}}}catch(i){n=i instanceof Error?i.message:String(i)}const s=Date.now()+p.TERMINAL_RETRY_DELAY_MS;try{this.stopResultOutbox.recordRetry(e,s,n)}catch(i){this.emitClientError(new Error(`event_stop_result retry state persist failed: event=${e.payload.event_id} stop=${e.payload.stop_id}: ${i instanceof Error?i.message:i}`))}return this.emitClientError(new Error(`event_stop_result retained for retry: event=${e.payload.event_id} stop=${e.payload.stop_id} err=${n}`)),p.TERMINAL_RETRY_DELAY_MS}clearStopResultRetryTimers(){for(const e of this.stopResultRetryTimers.values())clearTimeout(e);this.stopResultRetryTimers.clear()}markOutputIntegrityFailed(e,t){if(this.blockEventOutput(e),this.outputIntegrityFailed.has(e))return;const n={reason:t,terminalObserved:!!(this.provisionalRespondedTerminals.has(e)||this.terminalOutbox.get(e)),terminalSettled:!1};this.outputIntegrityFailed.set(e,n),this.provisionalRespondedTerminals.delete(e),this.clearNonReplayableOutputEvent(e);const s=this.outboundBuffer.length;this.outboundBuffer=this.outboundBuffer.filter(u=>this.outboundEventId(u.cmd,u.payload)!==e);const i=this.terminalOutbox.get(e),r=i?this.canReplaceUnsentOutputGuard(i):!1;if(i&&!r)n.terminalObserved=!0,this.scheduleTerminalDelivery(e,{ignoreNotBefore:!0});else if(!this.committedTerminalEvents.has(e))try{const u=this.terminalOutbox.enqueue(this.makeOutputIntegrityFailurePayload(e,t));this.scheduleTerminalDelivery(u.payload.event_id,{ignoreNotBefore:!0})}catch(u){this.emitClientError(new Error(`output-integrity terminal persist failed: event=${e}: ${u instanceof Error?u.message:u}`))}for(const u of[...this.pendingOutputSeqsByEvent.get(e)??[]])this.settlePendingOutputWrite(u,!1,!1);this.settlePendingAcceptedOutputsForEvent(e,"rejected",!1),this.emit("streamRejected",e,0),this.emitClientError(new Error(`required output integrity failed: event=${e} removed=${s-this.outboundBuffer.length} reason=${t}`))}settleOutputIntegrityTerminal(e){const t=this.outputIntegrityFailed.get(e);t&&(t.terminalSettled=!0,t.terminalObserved&&this.outputIntegrityFailed.delete(e))}bufferOutboundEntry(e){if(this.outboundEntryOrders.has(e)||this.outboundEntryOrders.set(e,++this.nextOutboundEntryOrder),this.outboundBuffer.includes(e))return!0;const t=this.outboundEventId(e.cmd,e.payload);return t&&(this.outputIntegrityFailed.has(t)||this.blockedOutputEvents.has(t))?!1:(this.outboundBuffer.length>=p.MAX_OUTBOUND_BUFFER_SIZE&&(this.outboundBuffer=this.outboundBuffer.filter(n=>p.BUFFER_OVERFLOW_RETAIN_COMMANDS.has(n.cmd)),this.outboundBuffer.length>=p.MAX_OUTBOUND_BUFFER_SIZE&&m.warn("aibot",`outbound buffer soft limit exceeded by ${this.outboundBuffer.length} retained packet(s); preserving required output`)),this.outboundBuffer.length>=p.MAX_OUTBOUND_BUFFER_HARD_SIZE?(t?this.markOutputIntegrityFailed(t,`outbound buffer hard limit ${p.MAX_OUTBOUND_BUFFER_HARD_SIZE} reached`):this.emitClientError(new Error(`outbound buffer hard limit ${p.MAX_OUTBOUND_BUFFER_HARD_SIZE} reached; rejected non-event packet cmd=${e.cmd}`)),!1):(this.outboundBuffer.push(e),this.outboundBuffer.sort((n,s)=>(this.outboundEntryOrders.get(n)??Number.MAX_SAFE_INTEGER)-(this.outboundEntryOrders.get(s)??Number.MAX_SAFE_INTEGER)),!0))}registerPendingOutputWrite(e,t,n,s,i){let r;const u=new Promise(a=>{r=a}),o=setTimeout(()=>{const a=this.pendingOutputWrites.get(e);if(!a||a.socket!==s||a.connectionGeneration!==i)return;if(!this.isConnectionCurrent(s,i)){this.settlePendingOutputWrite(e,!1,!1,s,i);return}this.removeSeqFromEventCorrelation(e);const d=this.isNonReplayableOutput(n.cmd,n.payload);this.settlePendingOutputWrite(e,!1,!d,s,i),d&&this.markOutputIntegrityFailed(t,`websocket write callback timed out for non-replayable ${n.cmd} seq=${e}`),this.emitClientError(new Error(`outbound websocket write callback timeout: cmd=${n.cmd} event=${t} seq=${e} delivery_unknown=${d}`)),this.reconnectAfterOutboundWriteFailure(s,`${n.cmd} callback timeout`)},p.OUTBOUND_WRITE_CALLBACK_TIMEOUT_MS);o.unref?.(),this.pendingOutputWrites.set(e,{eventId:t,entry:n,socket:s,connectionGeneration:i,promise:u,resolve:r,timer:o});let h=this.pendingOutputSeqsByEvent.get(t);h||(h=new Set,this.pendingOutputSeqsByEvent.set(t,h)),h.add(e)}settlePendingOutputWrite(e,t,n,s,i){const r=this.pendingOutputWrites.get(e);if(!r||s&&(r.socket!==s||r.connectionGeneration!==i))return;this.pendingOutputWrites.delete(e),clearTimeout(r.timer);const u=this.pendingOutputSeqsByEvent.get(r.eventId);u?.delete(e),u?.size===0&&this.pendingOutputSeqsByEvent.delete(r.eventId),n&&this.bufferOutboundEntry(r.entry),r.resolve(t)}settlePendingOutputWritesForEvent(e,t){const n=this.pendingOutputSeqsByEvent.get(e);if(n)for(const s of[...n]){const i=this.pendingOutputWrites.get(s);i&&this.settlePendingOutputWrite(s,t,!1,i.socket,i.connectionGeneration)}}abortPendingOutputWrites(e,t,n,s){for(const[i,r]of[...this.pendingOutputWrites.entries()])if(!(t&&(r.socket!==t||r.connectionGeneration!==n))){if(this.removeSeqFromEventCorrelation(i),s&&this.isNonReplayableOutput(r.entry.cmd,r.entry.payload)){this.settlePendingOutputWrite(i,!1,!1,t,n),this.markOutputIntegrityFailed(r.eventId,`connection lost while websocket write completion was unknown: ${s}`);continue}this.settlePendingOutputWrite(i,!1,e,t,n)}}registerPendingAcceptedOutput(e,t,n,s,i){let r;const u=new Promise(f=>{r=f}),o=Math.max(1,this.ackPolicy?.push_ack_timeout_ms??5e3),h=Math.max(1,this.ackPolicy?.max_retries??3),a=Math.max(1e3,Math.ceil(o*.25)),d=Math.max(p.MIN_REQUIRED_OUTPUT_ACK_TIMEOUT_MS,o*h+a),_=setTimeout(()=>{const f=this.pendingAcceptedOutputs.get(e);if(!(!f||f.socket!==s||f.connectionGeneration!==i)){if(!this.isConnectionCurrent(s,i)){this.settlePendingAcceptedOutput(e,"retry",!1,s,i);return}this.settlePendingAcceptedOutput(e,"retry",!0,s,i),this.emitClientError(new Error(`required output ACK timeout; retained for reconnect retry: event=${t} seq=${e}`)),this.reconnectAfterOutboundWriteFailure(s,"required output ACK timeout")}},d);_.unref?.(),this.pendingAcceptedOutputs.set(e,{eventId:t,entry:n,socket:s,connectionGeneration:i,promise:u,resolve:r,timer:_});const b=n.payload,c=typeof b.client_msg_id=="string"?b.client_msg_id.trim():"";if(c){let f=this.pendingAcceptedSeqsByClientMsgId.get(c);f||(f=new Set,this.pendingAcceptedSeqsByClientMsgId.set(c,f)),f.add(e)}let l=this.pendingAcceptedOutputSeqsByEvent.get(t);l||(l=new Set,this.pendingAcceptedOutputSeqsByEvent.set(t,l)),l.add(e)}settlePendingAcceptedOutput(e,t,n,s,i){const r=this.pendingAcceptedOutputs.get(e);if(!r||s&&(r.socket!==s||r.connectionGeneration!==i))return;this.pendingAcceptedOutputs.delete(e),clearTimeout(r.timer);const u=this.pendingAcceptedOutputSeqsByEvent.get(r.eventId);u?.delete(e),u?.size===0&&this.pendingAcceptedOutputSeqsByEvent.delete(r.eventId);const o=r.entry.payload,h=typeof o.client_msg_id=="string"?o.client_msg_id.trim():"";if(h){const a=this.pendingAcceptedSeqsByClientMsgId.get(h);a?.delete(e),a?.size===0&&this.pendingAcceptedSeqsByClientMsgId.delete(h)}n&&this.bufferOutboundEntry(r.entry),r.resolve(t)}settlePendingAcceptedOutputsForEvent(e,t,n){const s=this.pendingAcceptedOutputSeqsByEvent.get(e);if(s)for(const i of[...s])this.settlePendingAcceptedOutput(i,t,n)}abortPendingAcceptedOutputs(e,t,n){for(const[s,i]of[...this.pendingAcceptedOutputs.entries()])t&&(i.socket!==t||i.connectionGeneration!==n)||this.settlePendingAcceptedOutput(s,"retry",e,t,n)}rejectPendingRequestAfterWriteFailure(e,t,n){const s=this.pendingRequests.get(e);s&&(this.pendingRequests.delete(e),clearTimeout(s.timer),s.reject(new Error(`websocket write failed: ${t}: ${n.message}`)))}async awaitOutputDeliveryBarrier(e){const t=this.outboundFlushInFlight;if(t&&!await t.promise)return!1;for(;;){const n=this.pendingOutputSeqsByEvent.get(e);if(!n||n.size===0)break;const s=[...n].map(r=>this.pendingOutputWrites.get(r)?.promise).filter(r=>!!r);if(s.length===0)break;if((await Promise.all(s)).some(r=>!r))return!1}for(;;){const n=this.pendingAcceptedOutputSeqsByEvent.get(e);if(!n||n.size===0)break;const s=[...n].map(r=>this.pendingAcceptedOutputs.get(r)?.promise).filter(r=>!!r);if(s.length===0)break;const i=await Promise.all(s);if(i.includes("retry"))return!1;if(i.includes("rejected")){const r=this.terminalOutbox.get(e);if(!r||r.payload.status==="responded")return!1}}return this.outboundBuffer.some(n=>this.outboundEventId(n.cmd,n.payload)===e)?!1:this.hasNonReplayableOutput(e)?(this.markOutputIntegrityFailed(e,"output flush completed without a complete acceptance fence"),!1):!!(this.connected&&this.ws&&this.ws.readyState===y.OPEN)}isConnectionCurrent(e,t){return this.ws===e&&this.connectionGeneration===t}isOutboundFlushCurrent(e){return!e.finalized&&this.outboundFlushInFlight===e&&this.isConnectionCurrent(e.socket,e.connectionGeneration)}flushOutboundBuffer(e=this.ws,t=this.connectionGeneration){if(!e||!this.isConnectionCurrent(e,t))return Promise.resolve(!1);const n=this.outboundFlushInFlight;if(n){if(!n.finalized&&n.socket===e&&n.connectionGeneration===t)return n.promise;this.cancelOutboundFlush(n,"discard","superseded stale flush")}if(this.outboundBuffer.length===0)return Promise.resolve(!0);const s={connectionGeneration:t,flushGeneration:++this.nextOutboundFlushGeneration,socket:e,promise:Promise.resolve(!1),finalized:!1,activeBatch:null,nextIndex:0,currentWritePending:!1,currentWriteOutcome:null,cancelCurrentWrite:null,remainderHandled:!1};return this.outboundFlushInFlight=s,s.promise=this.performOutboundBufferFlush(s),s.promise.finally(()=>{s.finalized=!0,s.cancelCurrentWrite?.(),s.cancelCurrentWrite=null,this.outboundFlushInFlight===s&&(this.outboundFlushInFlight=null)}),s.promise}async performOutboundBufferFlush(e){for(;this.isOutboundFlushCurrent(e)&&this.outboundBuffer.length>0;){const{socket:t}=e;if(t.readyState!==y.OPEN)return!1;const n=this.outboundBuffer;this.outboundBuffer=[],e.activeBatch=n,e.nextIndex=0,e.remainderHandled=!1;for(let s=0;s<n.length;s++){if(!this.isOutboundFlushCurrent(e))return!1;const i=n[s],{cmd:r,payload:u}=i,o=this.outboundEventId(r,u);if(o&&this.blockedOutputEvents.has(o)){this.packetLog?.logOutboundPacket(r,0,u,"dropped"),e.nextIndex=s+1,e.currentWritePending=!1,e.currentWriteOutcome=null;continue}const h=++this.seq,a={cmd:r,seq:h,payload:u};e.nextIndex=s,e.currentWritePending=!0,e.currentWriteOutcome=null,o&&this.isAckRequiredOutput(r,u)&&this.registerPendingAcceptedOutput(h,o,i,t,e.connectionGeneration);const d=await new Promise(_=>{let b=!1;const c=f=>{b||(b=!0,clearTimeout(l),e.currentWriteOutcome=f,_(f))},l=setTimeout(()=>c("uncertain"),p.OUTBOUND_WRITE_CALLBACK_TIMEOUT_MS);l.unref?.(),e.cancelCurrentWrite=()=>c("canceled");try{this.trackOutboundEventCorrelation(r,h,u),t.send(JSON.stringify(a),f=>{c(f?"retry":"written")})}catch{c("retry")}});if(e.cancelCurrentWrite=null,!this.isOutboundFlushCurrent(e))return!1;if(d!=="written"||t.readyState!==y.OPEN){d==="retry"&&this.removeSeqFromEventCorrelation(h),this.settlePendingAcceptedOutput(h,"retry",!1);const _=this.retainOutboundFlushRemainder(e,d,`auth flush write failed for ${r} seq=${h} outcome=${d}`);return this.emitClientError(new Error(`outbound buffer flush failed at cmd=${r} seq=${h} outcome=${d}; ${_} packet(s) retained`)),!1}this.trackNonReplayableOutput(t,r,u,h),e.currentWritePending=!1,e.currentWriteOutcome="written",e.nextIndex=s+1}e.activeBatch=null,e.currentWritePending=!1,e.currentWriteOutcome=null,e.remainderHandled=!0}return this.isOutboundFlushCurrent(e)}retainOutboundFlushRemainder(e,t,n){if(e.remainderHandled||!e.activeBatch)return 0;e.remainderHandled=!0;const s=e.activeBatch,i=Math.min(e.nextIndex,s.length);let r=i;if(e.currentWritePending&&i<s.length){const o=s[i],h=this.outboundEventId(o.cmd,o.payload);t!=="retry"&&this.isNonReplayableOutput(o.cmd,o.payload)&&h&&(this.markOutputIntegrityFailed(h,n),r=i+1)}let u=0;for(const o of s.slice(r))this.bufferOutboundEntry(o)&&u++;return e.activeBatch=null,e.nextIndex=s.length,e.currentWritePending=!1,u}cancelOutboundFlush(e,t,n){if(e.finalized){this.outboundFlushInFlight===e&&(this.outboundFlushInFlight=null);return}e.finalized=!0,this.outboundFlushInFlight===e&&(this.outboundFlushInFlight=null),t==="connection_lost"?this.retainOutboundFlushRemainder(e,e.currentWriteOutcome,`connection lost during auth flush: ${n}`):(e.remainderHandled=!0,e.activeBatch=null,e.currentWritePending=!1);const s=e.cancelCurrentWrite;e.cancelCurrentWrite=null,s?.()}reconnectAfterOutboundFlushFailure(e,t){this.agentDeleted||!this.isConnectionCurrent(e,t)||this.reconnectAfterOutboundWriteFailure(e,"outbound flush failed")}reconnectAfterOutboundWriteFailure(e,t){if(this.agentDeleted||this.ws!==e)return;const n=this.connectionGeneration;this.connected=!1,this.negotiatedCapabilities.clear(),this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers(),this.rejectAllPendingRequests(t);const s=this.outboundFlushInFlight;s&&s.socket===e&&s.connectionGeneration===n&&this.cancelOutboundFlush(s,"connection_lost",t),this.failNonReplayableOutputsForSocket(e,t),this.abortPendingOutputWrites(!0,e,n,t),this.abortPendingAcceptedOutputs(!0,e,n),this.clearAllEventCorrelations(),this.connectionGeneration++;try{e.close(1011,t)}catch{}this.ws===e&&(this.ws=null),this.attemptReconnect()}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(e=this.ws,t=this.connectionGeneration){if(!(!e||!this.isConnectionCurrent(e,t)))try{e.close()}catch{}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatFailures=0,this.heartbeatTimer=setInterval(()=>{const e=this.ws,t=this.connectionGeneration;!this.connected||!e||this.request("ping",{ts:Date.now()},{expected:["pong"],timeoutMs:5e3}).then(()=>{this.isConnectionCurrent(e,t)&&(this.heartbeatFailures=0)}).catch(()=>{!this.connected||!this.isConnectionCurrent(e,t)||(this.heartbeatFailures++,!(this.heartbeatFailures<p.HEARTBEAT_MAX_FAILURES)&&(this.cleanupSocket(e,t),this.attemptReconnect()))})},this.heartbeatSec*1e3)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}}export{p as AibotClient,D as preprocessLargeIntegers,x as withRequiredCapabilities};
1
+ import{EventEmitter as A}from"node:events";import{randomUUID as T}from"node:crypto";import $ from"node:os";import y from"ws";import{log as p}from"../log/index.js";import{getMachineName as S}from"../util/index.js";import{detectTailnetIPv4 as I,ensureServerAndGetPort as P,getFileServerHttpsPort as F}from"../files/file-serve.js";import{TerminalOutbox as M}from"../persistence/terminal-outbox.js";import{TerminalCommitTokenStore as q}from"../persistence/terminal-commit-token-store.js";import{StopResultOutbox as N}from"../persistence/stop-result-outbox.js";import{AUTH_CODE_AGENT_DELETED as w,KICKED_REASON_AGENT_DELETED as R,AgentDeletedError as C,RequestTimeoutError as B}from"./errors.js";function D(E){let e="",t=0,n=!1,s=!1;for(;t<E.length;){const i=E[t];if(n){e+=i,s?s=!1:i==="\\"?s=!0:i==='"'&&(n=!1),t++;continue}if(i==='"'){n=!0,e+=i,t++;continue}if(i==="-"||i>="0"&&i<="9"){const r=t;i==="-"&&t++;const u=t;for(;t<E.length&&E[t]>="0"&&E[t]<="9";)t++;let o=!1;if(E[t]===".")for(o=!0,t++;t<E.length&&E[t]>="0"&&E[t]<="9";)t++;if(E[t]==="e"||E[t]==="E")for(o=!0,t++,(E[t]==="+"||E[t]==="-")&&t++;t<E.length&&E[t]>="0"&&E[t]<="9";)t++;const h=E.slice(r,t),a=t-u;e+=!o&&a>=16?`"${h}"`:h;continue}e+=i,t++}return e}function U(E){const e=[...E??["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("terminal_commit_v1")||e.push("terminal_commit_v1"),e.includes("audit_replay_v2")||e.push("audit_replay_v2"),e.includes("session_send_quote_v1")||e.push("session_send_quote_v1"),e}function x(E){const e=[...E??["exec_approve","exec_reject"]];return e.includes("apply_relay_state")||e.push("apply_relay_state"),e}const W="aibot-agent-api-v1",L=1;class m extends A{static DROPPABLE_COMMANDS=new Set(["update_binding_card"]);static OUTPUT_NACK_CMDS=new Set(["send_msg","client_stream_chunk"]);static UNMATCHED_NACK_LOG_WINDOW_MS=5*6e4;unmatchedNackLoggedAt=new Map;static BUFFER_OVERFLOW_RETAIN_COMMANDS=new Set(["event_result","codex_event","client_stream_chunk","send_msg","audit_state"]);static MAX_OUTBOUND_BUFFER_SIZE=1e3;static MAX_OUTBOUND_BUFFER_HARD_SIZE=1200;static BACKPRESSURE_THRESHOLD=64*1024;static TERMINAL_RETRY_DELAY_MS=15e3;static MAX_TOKENIZED_TERMINAL_REJECTIONS=5;static EVENT_CORRELATION_TTL_MS=5*6e4;static MAX_EVENT_CORRELATIONS=1024;static MAX_BLOCKED_OUTPUT_EVENTS=4096;static MAX_COMMITTED_TERMINAL_EVENTS=4096;static OUTBOUND_WRITE_CALLBACK_TIMEOUT_MS=1e4;static MIN_REQUIRED_OUTPUT_ACK_TIMEOUT_MS=2e4;static ORDERED_OUTPUT_COMMANDS=new Set(["client_stream_chunk","send_msg","codex_event"]);ws=null;seq=0;heartbeatTimer=null;heartbeatSec=30;heartbeatFailures=0;static HEARTBEAT_MAX_FAILURES=2;connected=!1;reconnecting=!1;reconnectAttempts=0;reconnectRunGeneration=0;everConnected=!1;agentDeleted=!1;config;packetLog;pendingInvokes=new Map;eventCorrelations=new Map;clientMsgEventMap=new Map;eventCorrelationCleanupTimer=null;lastCorrelationPruneAt=0;pendingRequests=new Map;outboundBuffer=[];outboundEntryOrders=new WeakMap;nextOutboundEntryOrder=0;connectionGeneration=0;nextOutboundFlushGeneration=0;outboundFlushInFlight=null;pendingOutputWrites=new Map;pendingOutputSeqsByEvent=new Map;pendingAcceptedOutputs=new Map;pendingAcceptedOutputSeqsByEvent=new Map;pendingAcceptedSeqsByClientMsgId=new Map;nonReplayableOutputEventsBySocket=new Map;provisionalRespondedTerminals=new Map;outputIntegrityFailed=new Map;blockedOutputEvents=new Map;committedTerminalEvents=new Set;ackPolicy=null;negotiatedCapabilities=new Set;terminalOutbox;terminalCommitTokens;stopResultOutbox;terminalInFlight=new Set;terminalRetryTimers=new Map;terminalReplayAfterFlight=new Set;tokenizedTerminalRejections=new Map;stopResultInFlight=new Set;stopResultRetryTimers=new Map;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:U(e.capabilities),localActions:x(e.localActions),skills:e.skills,librarySkills:e.librarySkills,sharedOwnerId:e.sharedOwnerId,concurrency:e.concurrency,terminalOutboxPath:e.terminalOutboxPath,terminalCommitTokenStorePath:e.terminalCommitTokenStorePath,stopResultOutboxPath:e.stopResultOutboxPath},this.terminalOutbox=new M(this.config.terminalOutboxPath),this.terminalCommitTokens=new q(this.config.terminalCommitTokenStorePath??(this.config.terminalOutboxPath?`${this.config.terminalOutboxPath}.tokens`:void 0)),this.stopResultOutbox=new N(this.config.stopResultOutboxPath??(this.config.terminalOutboxPath?`${this.config.terminalOutboxPath}.stops`:void 0));for(const n of this.terminalOutbox.listPending())n.payload.code==="agent_output_integrity_failed"&&this.blockEventOutput(n.payload.event_id)}get isConnected(){return this.connected}async connect(){this.negotiatedCapabilities.clear();const e=this.ws,t=this.connectionGeneration;if(this.pendingRequests.size>0&&this.rejectAllPendingRequests("connection generation replaced"),e){this.connected=!1,this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers();const o=this.outboundFlushInFlight;o&&o.socket===e&&o.connectionGeneration===t&&this.cancelOutboundFlush(o,"connection_lost","connection generation replaced"),this.failNonReplayableOutputsForSocket(e,"connection generation replaced"),this.abortPendingOutputWrites(!0,e,t,"connection generation replaced"),this.abortPendingAcceptedOutputs(!0,e,t),this.clearAllEventCorrelations(),this.connectionGeneration++;try{e.close(1012,"connection generation replaced")}catch{}this.ws===e&&(this.ws=null)}else this.outboundFlushInFlight&&this.cancelOutboundFlush(this.outboundFlushInFlight,"discard","detached connection generation replaced");const n=++this.connectionGeneration;let s,i,r;const u=(async()=>{try{if(s=await I(),s!==void 0)try{i=await P(s);const o=F();o>0&&(r=o)}catch(o){p.warn("aibot",`file server pre-start failed: ${o}`)}}catch(o){p.warn("aibot",`tailnet detect failed: ${o}`)}})();return new Promise((o,h)=>{const a=new y(this.config.url);this.ws=a;const d=setTimeout(()=>{if(!this.isConnectionCurrent(a,n))return;const c=this.pendingRequests.get(_);c&&(this.pendingRequests.delete(_),clearTimeout(c.timer),c.reject(new Error("Auth timeout: no auth_ack received within 15s"))),this.cleanupSocket(a,n)},15e3),_=++this.seq,b=setTimeout(()=>{if(!this.isConnectionCurrent(a,n))return;const c=this.pendingRequests.get(_);c&&(this.pendingRequests.delete(_),c.reject(new Error("Auth request timeout"))),this.cleanupSocket(a,n)},15e3);this.pendingRequests.set(_,{expected:["auth_ack"],resolve:c=>{clearTimeout(d);const l=c.payload;if(l.code===0){this.negotiatedCapabilities=new Set(Array.isArray(l.supported_capabilities)?l.supported_capabilities:[]),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,p.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();const f=this.flushOutboundBuffer(a,n);this.emit("auth",l),o(l),f.then(g=>{this.isConnectionCurrent(a,n)&&(g?(this.replayTerminalOutbox(),this.replayStopResultOutbox()):this.reconnectAfterOutboundFlushFailure(a,n))})}else l.code===w?(this.agentDeleted=!0,h(new C(`Agent deleted: code=${l.code} msg=${l.msg}`))):h(new Error(`Auth failed: code=${l.code} msg=${l.msg}`))},reject:c=>{clearTimeout(d),h(c)},timer:b}),a.on("open",async()=>{if(await u,!this.isConnectionCurrent(a,n))return;const c={agent_id:this.config.agentId,api_key:this.config.apiKey,client_type:this.config.clientType,protocol_version:W,contract_version:L,capabilities:this.config.capabilities??[],local_actions:this.config.localActions,skills:this.config.skills,library_skills:this.config.librarySkills};this.config.sharedOwnerId&&(c.shared_owner_id=this.config.sharedOwnerId),this.config.clientVersion&&(c.client="grix-connector",c.client_version=this.config.clientVersion,c.host_type=this.config.clientType,c.host_version=this.config.clientVersion),this.config.adapterHint&&(c.adapter_hint=this.config.adapterHint),c.host_meta={hostname:S(),platform:$.platform(),arch:$.arch(),os_release:$.release(),...s!==void 0&&{tailnet_ip:s},...i!==void 0&&i>0&&{file_server_port:i},...r!==void 0&&r>0&&{file_server_https_port:r}},this.config.concurrency&&(c.concurrency=this.config.concurrency),this.sendPacket("auth",c,_)}),a.on("message",c=>{if(!this.isConnectionCurrent(a,n))return;let l;try{l=JSON.parse(D(c.toString()))}catch{return}try{this.handlePacket(l)}catch(f){this.emitClientError(new Error(`handlePacket error: ${f}`))}}),a.on("close",(c,l)=>{if(!this.isConnectionCurrent(a,n))return;const f=this.everConnected&&!this.agentDeleted;this.connected=!1,this.negotiatedCapabilities.clear(),this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers(),this.rejectAllPendingRequests("websocket closed");const g=`websocket closed code=${c} reason=${l.toString()||"<none>"}`,O=this.outboundFlushInFlight;O&&O.socket===a&&O.connectionGeneration===n&&this.cancelOutboundFlush(O,f?"connection_lost":"discard",g),f?this.failNonReplayableOutputsForSocket(a,g):this.nonReplayableOutputEventsBySocket.delete(a),this.abortPendingOutputWrites(f,a,n,f?g:void 0),this.abortPendingAcceptedOutputs(f,a,n),this.clearAllEventCorrelations(),this.ws===a&&(this.ws=null),this.connectionGeneration++,this.emit("close",c,l.toString());const k=f;p.info("aibot",`ws closed agent=${this.config.clientType}:${this.config.agentId} code=${c} reason=${l.toString()||"<none>"} everConnected=${this.everConnected} reconnecting=${this.reconnecting} agentDeleted=${this.agentDeleted} willReconnect=${k}`),k&&this.attemptReconnect(c===1e3||c===1001)}),a.on("error",c=>{if(this.isConnectionCurrent(a,n)&&(this.emitClientError(c instanceof Error?c:new Error(String(c))),!this.connected)){const l=this.pendingRequests.get(_);l&&(this.pendingRequests.delete(_),clearTimeout(l.timer),l.reject(c instanceof Error?c:new Error(String(c))))}})})}handlePacket(e){if(this.packetLog?.logInboundPacket(e.cmd,e.seq,e.payload),this.handleCorrelatedSendResponse(e),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":{const t=e.payload;if(!this.captureInboundTerminalCommitToken(t.event_id,t.terminal_commit_token))break;this.emit("event",t);break}case"local_action":{this.emit("localAction",e.payload);break}case"event_stop":{const t=e.payload;if(!this.captureInboundTerminalCommitToken(t.event_id,t.terminal_commit_token))break;this.emit("stop",t);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;this.emit("kicked",t),this.connected=!1,this.negotiatedCapabilities.clear(),this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers(),this.rejectAllPendingRequests("kicked");const n=this.ws,s=this.connectionGeneration,i=this.outboundFlushInFlight;if(i&&n&&i.socket===n&&i.connectionGeneration===this.connectionGeneration&&this.cancelOutboundFlush(i,t?.reason===R?"discard":"connection_lost",`kicked reason=${t?.reason??"<none>"}`),t?.reason!==R&&n&&this.failNonReplayableOutputsForSocket(n,`kicked reason=${t?.reason??"<none>"}`),this.abortPendingOutputWrites(t?.reason!==R,n??void 0,s,t?.reason!==R?`kicked reason=${t?.reason??"<none>"}`:void 0),this.abortPendingAcceptedOutputs(t?.reason!==R,n??void 0,s),this.clearAllEventCorrelations(),this.connectionGeneration++,t?.reason===R){if(this.agentDeleted=!0,this.reconnecting=!1,this.outboundBuffer.length=0,this.outputIntegrityFailed.clear(),this.nonReplayableOutputEventsBySocket.clear(),this.ws){try{this.ws.close(4001,"kicked")}catch{}this.ws=null}p.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===n&&(this.ws=null)}this.attemptReconnect();break}case"error":{const t=e.payload,n=[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}${n?` ${n}`:""}`));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":this.logUnmatchedNack(e);break;case"local_action_ack":break;default:break}}captureInboundTerminalCommitToken(e,t){const n=t?.trim();if(!n)return!0;if(!e?.trim())return this.rejectInboundTerminalCommitToken("tokenized event is missing event_id"),!1;if(!this.negotiatedCapabilities.has("terminal_commit_v1"))return this.rejectInboundTerminalCommitToken(`tokenized event received without terminal_commit_v1 negotiation event=${e}`),!1;try{return this.terminalCommitTokens.register(e,n),!0}catch(s){return this.rejectInboundTerminalCommitToken(`terminal commit token persist failed event=${e}: ${s instanceof Error?s.message:s}`),!1}}rejectInboundTerminalCommitToken(e){this.emitClientError(new Error(e));const t=this.ws;if(t)try{t.close(1011,"terminal commit token persistence failed")}catch{}}withTerminalCommitToken(e){const t=e.event_id.trim();if(!t)throw new Error("terminal event_result is missing event_id");const n=e.terminal_commit_token?.trim(),s=this.terminalCommitTokens.get(t);if(n&&s&&n!==s)throw new Error(`terminal commit token mismatch for event=${t}`);n&&!s&&this.terminalCommitTokens.register(t,n);const i=s??n;return i?{...e,event_id:t,terminal_commit_token:i}:{...e,event_id:t}}sendEventAck(e){this.sendPacket("event_ack",e)||p.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&&(p.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){const t={...e,client_msg_id:e.client_msg_id?.trim()||T()};this.sendPacket("send_msg",t)||p.warn("aibot",`send_msg NOT sent (ws not open) event=${t.event_id??""} session=${t.session_id??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}editMsg(e){this.sendPacket("edit_msg",e)}sendEventResult(e){try{e=this.withTerminalCommitToken(e)}catch(o){this.emitClientError(new Error(`event_result token validation failed: event=${e.event_id}: ${o instanceof Error?o.message:o}`));return}const t=this.terminalOutbox.get(e.event_id);let n,s=this.outputIntegrityFailed.get(e.event_id);const i=t;if(!s&&i?.payload.code==="agent_output_integrity_failed"&&(s={reason:i.payload.msg??"required agent output was discarded before delivery",terminalObserved:!1,terminalSettled:!1},this.outputIntegrityFailed.set(e.event_id,s)),s){if(s.terminalObserved=!0,this.provisionalRespondedTerminals.delete(e.event_id),i&&i.payload.code!=="agent_output_integrity_failed"&&!this.canReplaceUnsentOutputGuard(i)){this.scheduleTerminalDelivery(e.event_id,{ignoreNotBefore:!0});return}if(i?.payload.code==="agent_output_integrity_failed"){this.scheduleTerminalDelivery(e.event_id,{ignoreNotBefore:!0});return}if(s.terminalSettled||this.committedTerminalEvents.has(e.event_id)&&!i){this.outputIntegrityFailed.delete(e.event_id);return}try{n=this.terminalOutbox.enqueue(this.makeOutputIntegrityFailurePayload(e.event_id,s.reason))}catch(o){this.emitClientError(new Error(`output-integrity terminal persist failed: event=${e.event_id}: ${o instanceof Error?o.message:o}`));return}this.scheduleTerminalDelivery(n.payload.event_id,{ignoreNotBefore:!0});return}if(this.committedTerminalEvents.has(e.event_id)&&!t){p.info("aibot",`ignored duplicate terminal after committed ACK event=${e.event_id} status=${e.status}`);return}if(t){if(!(this.canReplaceUnsentOutputGuard(t)&&(e.status==="canceled"||e.status==="failed"))){p.info("aibot",`preserving first durable terminal event=${e.event_id} existing_status=${t.payload.status} ignored_status=${e.status}`),this.scheduleTerminalDelivery(e.event_id,{ignoreNotBefore:!0});return}this.provisionalRespondedTerminals.delete(e.event_id)}if(e.status==="responded"&&this.hasNonReplayableOutput(e.event_id)&&!this.hasPendingOutputAcceptanceFence(e.event_id)){this.markOutputIntegrityFailed(e.event_id,"terminal requested before a complete output acceptance fence");const o=this.outputIntegrityFailed.get(e.event_id);o&&(o.terminalObserved=!0);return}const r=e.status==="responded"&&this.hasUnconfirmedEventOutput(e.event_id),u=r?{...e,status:"failed",code:"agent_output_unconfirmed",msg:"required agent output was not durably confirmed before connector restart",updated_at:Date.now()}:e;r?this.provisionalRespondedTerminals.set(e.event_id,{...e}):this.provisionalRespondedTerminals.delete(e.event_id);try{n=this.terminalOutbox.enqueue(u)}catch(o){this.provisionalRespondedTerminals.delete(e.event_id),this.emitClientError(new Error(`event_result outbox persist failed: event=${e.event_id} status=${e.status}: ${o instanceof Error?o.message:o}`));return}this.scheduleTerminalDelivery(n.payload.event_id,{ignoreNotBefore:!0})}sendLocalActionResult(e){this.sendPacket("local_action_result",e)}sendEventStopAck(e){this.sendPacket("event_stop_ack",e)}sendEventStopResult(e){const t=e.event_id?.trim(),n=e.terminal_commit_token?.trim(),s=t?this.terminalCommitTokens.get(t):void 0;if(n&&s&&n!==s){this.emitClientError(new Error(`event_stop_result token mismatch event=${t??""}`));return}const i=s??n;if(t&&i&&(e.status==="stopped"||e.status==="already_finished")){try{const r=this.stopResultOutbox.enqueue({...e,event_id:t,terminal_commit_token:i});this.scheduleStopResultDelivery(r,{ignoreNotBefore:!0})}catch(r){this.emitClientError(new Error(`event_stop_result outbox persist failed: event=${t} stop=${e.stop_id}: ${r instanceof Error?r.message:r}`))}return}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,n=15e3){return new Promise((s,i)=>{const r=T(),u=Math.max(1e3,Math.min(n,75e3)),o=setTimeout(()=>{this.pendingInvokes.delete(r),i(new Error(`agent_invoke timeout: ${e}`))},u);this.pendingInvokes.set(r,{resolve:s,reject:i,timer:o}),this.sendPacket("agent_invoke",{invoke_id:r,action:e,params:t,timeout_ms:u})})}sendMcpFrame(e,t){this.sendPacket("mcp_frame",{session_id:e,frame:t})}async request(e,t,n){const s=this.outboundFlushInFlight;if(s){if(!await s.promise)throw new Error(`outbound flush failed before request: ${e}`);if(!this.isConnectionCurrent(s.socket,s.connectionGeneration))throw new Error(`connection changed while waiting for outbound flush: ${e}`)}if(!this.connected||!this.ws||this.ws.readyState!==y.OPEN)throw new Error(`send failed: ${e} (websocket not connected)`);return new Promise((i,r)=>{const u=++this.seq,o=setTimeout(()=>{this.pendingRequests.delete(u),r(new B(`request timeout: ${e} (expected ${n.expected.join("/")})`))},n.timeoutMs);this.pendingRequests.set(u,{expected:n.expected,resolve:i,reject:r,timer:o}),this.sendPacket(e,t,u)||(this.pendingRequests.delete(u),clearTimeout(o),r(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 relayStateSyncRequest(e,t=15e3){return this.request("relay_state_sync_request",e,{expected:["relay_state_sync_result","error"],timeoutMs:t})}sendRelayStateReport(e){this.sendPacket("relay_state_report",e)}async sendText(e,t=2e4){return this.request("send_msg",{msg_type:1,...e,client_msg_id:e.client_msg_id?.trim()||T()},{expected:["send_ack","send_nack","error"],timeoutMs:t})}async sendMedia(e,t=2e4){return this.request("send_msg",{...e,msg_type:2,client_msg_id:e.client_msg_id?.trim()||T()},{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,n=2e4){return this.request("delete_msg",{session_id:e,msg_id:t},{expected:["send_ack","send_nack","error"],timeoutMs:n})}async sendEventResultRequest(e,t=5e3){return this.request("event_result",e,{expected:["send_ack","send_nack","error"],timeoutMs:t})}disconnect(){p.info("aibot",`disconnect() agent=${this.config.clientType}:${this.config.agentId} wasConnected=${this.connected} reconnecting=${this.reconnecting} reconnectAttempts=${this.reconnectAttempts}`),this.connected=!1,this.negotiatedCapabilities.clear(),this.everConnected=!1,this.reconnecting=!1,this.reconnectRunGeneration++,this.reconnectAttempts=0,this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers();const e=this.ws,t=this.connectionGeneration,n=this.outboundFlushInFlight;n&&this.cancelOutboundFlush(n,"discard","explicit disconnect"),this.connectionGeneration++,this.rejectAllPendingInvokes("disconnect"),this.rejectAllPendingRequests("disconnect"),this.abortPendingOutputWrites(!1,e??void 0,t),this.abortPendingAcceptedOutputs(!1,e??void 0,t),this.clearAllEventCorrelations(),this.outboundBuffer.length=0,this.provisionalRespondedTerminals.clear(),this.outputIntegrityFailed.clear(),this.nonReplayableOutputEventsBySocket.clear(),this.ws&&(this.ws.close(1e3,"client disconnect"),this.ws=null)}static MAX_CONSECUTIVE_AUTH_FAILURES=5;async attemptReconnect(e=!1){if(this.reconnecting||this.agentDeleted)return;this.reconnecting=!0;const t=++this.reconnectRunGeneration;p.info("aibot",`attemptReconnect start agent=${this.config.clientType}:${this.config.agentId} fromAttempts=${this.reconnectAttempts} fastFirstAttempt=${e}`),this.emit("disconnected");let n=0;for(;this.reconnecting&&this.reconnectRunGeneration===t;){const s=e&&this.reconnectAttempts===0,i=s?Math.floor(Math.random()*500):Math.min(1e3*2**this.reconnectAttempts,3e4),r=s?0:Math.floor(i*.2*Math.random());if(this.reconnectAttempts++,await new Promise(h=>setTimeout(h,i+r)),!this.reconnecting||this.reconnectRunGeneration!==t)return;let u=null,o=this.connectionGeneration;try{const h=this.connect();if(u=this.ws,o=this.connectionGeneration,await h,this.reconnectRunGeneration!==t)return;if(!u||!this.isConnectionCurrent(u,o)){if(this.connected&&this.ws){this.reconnecting=!1;return}continue}const a=this.reconnectAttempts;this.reconnectAttempts=0,this.reconnecting=!1,p.info("aibot",`reconnect succeeded agent=${this.config.clientType}:${this.config.agentId} attempt=${a}`);return}catch(h){if(this.reconnectRunGeneration!==t)return;if(u&&!this.isConnectionCurrent(u,o)&&this.connected&&this.ws){this.reconnecting=!1;return}if(u&&this.isConnectionCurrent(u,o)){this.connectionGeneration++;try{u.close()}catch{}this.ws===u&&(this.ws=null)}const a=h instanceof Error?h.message:String(h);if(p.warn("aibot",`reconnect failed agent=${this.config.clientType}:${this.config.agentId} attempt=${this.reconnectAttempts} err=${a}`),h instanceof C){this.agentDeleted=!0,this.reconnecting=!1,p.error("aibot",`reconnect aborted: agent deleted on platform agent=${this.config.clientType}:${this.config.agentId}`),this.emit("agentDeleted",{source:"auth_ack",code:w});return}if(/Auth failed/i.test(a)){if(n++,n>=m.MAX_CONSECUTIVE_AUTH_FAILURES){this.reconnecting=!1,p.error("aibot",`reconnect giving up after ${n} consecutive auth failures agent=${this.config.clientType}:${this.config.agentId}`);return}}else n=0}}}sendPacket(e,t,n){const s=this.outboundEventId(e,t);if(s&&this.blockedOutputEvents.has(s))return this.packetLog?.logOutboundPacket(e,n??0,t,"dropped"),p.warn("aibot",`blocked late output after irreversible event failure event=${s} cmd=${e}`),!1;const i=n===void 0?this.createOutboundEntry(e,t):void 0;if(i&&this.outboundFlushInFlight&&!this.outboundFlushInFlight.finalized&&this.isConnectionCurrent(this.outboundFlushInFlight.socket,this.outboundFlushInFlight.connectionGeneration)&&!m.DROPPABLE_COMMANDS.has(e))return this.bufferOutboundEntry(i),!1;if(this.ws&&this.ws.readyState===y.OPEN&&(e==="auth"||this.connected)){const u=this.ws.bufferedAmount>m.BACKPRESSURE_THRESHOLD;if(!u||!m.DROPPABLE_COMMANDS.has(e)){if(u&&m.DROPPABLE_COMMANDS.has(e))return!1;const o=n??++this.seq,h={cmd:e,seq:o,payload:t};this.packetLog?.logOutboundPacket(e,o,t,"sent");const a=this.ws,d=this.connectionGeneration,_=s;_&&this.trackOutboundEventCorrelation(e,o,t),i&&_&&(this.registerPendingOutputWrite(o,_,i,a,d),this.isAckRequiredOutput(e,t)&&this.registerPendingAcceptedOutput(o,_,i,a,d));let b=!1;try{const c=a.readyState,l=a.bufferedAmount;let f=!1;return a.send(JSON.stringify(h),g=>{if(g&&!f&&(b=!0),e==="event_result"){const v=t;g?p.warn("aibot",`event_result ws send callback failed event=${v.event_id??""} status=${v.status??""} seq=${o} readyState=${c} bufferedAmount=${l} err=${g.message}`):p.info("aibot",`event_result ws send callback ok event=${v.event_id??""} status=${v.status??""} seq=${o} readyState=${c} bufferedAmount=${l}`)}else if(e==="client_stream_chunk"){const v=t;g?p.warn("aibot",`stream_chunk ws send failed event=${v.event_id??""} session=${v.session_id??""} seq=${o} chunk_seq=${v.chunk_seq??""} is_finish=${v.is_finish??""} readyState=${c} bufferedAmount=${l} err=${g.message}`):p.info("aibot",`stream_chunk ws send ok event=${v.event_id??""} session=${v.session_id??""} seq=${o} chunk_seq=${v.chunk_seq??""} is_finish=${v.is_finish??""} client_msg_id=${v.client_msg_id??""} quoted_message_id=${v.quoted_message_id??""} readyState=${c} bufferedAmount=${l}`)}else if(e==="event_ack"){const v=t;g?p.warn("aibot",`event_ack ws send failed event=${v.event_id??""} seq=${o} readyState=${c} bufferedAmount=${l} err=${g.message}`):p.info("aibot",`event_ack ws send ok event=${v.event_id??""} seq=${o} readyState=${c} bufferedAmount=${l}`)}else if(e==="send_msg"){const v=t;g?p.warn("aibot",`send_msg ws send failed event=${v.event_id??""} session=${v.session_id??""} seq=${o} readyState=${c} bufferedAmount=${l} err=${g.message}`):p.info("aibot",`send_msg ws send ok event=${v.event_id??""} session=${v.session_id??""} seq=${o} readyState=${c} bufferedAmount=${l}`)}else if(g){const v=t;p.warn("aibot",`${e} ws send failed seq=${o} session=${v.session_id??""} event=${v.event_id??""} client_msg_id=${v.client_msg_id??""} readyState=${c} bufferedAmount=${l} err=${g.message}`)}const O=this.pendingOutputWrites.get(o),k=!!(O&&O.socket===a&&O.connectionGeneration===d);if(!this.isConnectionCurrent(a,d)){k&&(this.settlePendingOutputWrite(o,!1,!1,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d));return}if(!(i&&_&&!k)){if(g)this.removeSeqFromEventCorrelation(o),_?(this.settlePendingOutputWrite(o,!1,!0,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d)):i&&this.bufferOutboundEntry(i),n!==void 0?this.rejectPendingRequestAfterWriteFailure(o,e,g):i&&this.reconnectAfterOutboundWriteFailure(a,`${e} callback failed`);else if(_){const v=k;this.settlePendingOutputWrite(o,!0,!1,a,d),v&&this.trackNonReplayableOutput(a,e,t,o)}}}),f=!0,!b}catch(c){return this.isConnectionCurrent(a,d)?(this.removeSeqFromEventCorrelation(o),_?(this.settlePendingOutputWrite(o,!1,!0,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d)):i&&this.bufferOutboundEntry(i),this.emitClientError(new Error(`sendPacket failed: ${c}`)),i&&this.reconnectAfterOutboundWriteFailure(a,`${e} send threw`),!1):(this.settlePendingOutputWrite(o,!1,!1,a,d),this.settlePendingAcceptedOutput(o,"retry",!1,a,d),!1)}}}if(m.DROPPABLE_COMMANDS.has(e))return this.packetLog?.logOutboundPacket(e,n??0,t,"dropped"),!1;if(n!==void 0)return this.packetLog?.logOutboundPacket(e,n,t,"dropped"),!1;const r=this.bufferOutboundEntry(i??this.createOutboundEntry(e,t));if(this.packetLog?.logOutboundPacket(e,n??0,t,r?"buffered":"dropped"),r&&e==="client_stream_chunk"){const u=t;p.info("aibot",`stream_chunk buffered (ws not open) event=${u.event_id??""} session=${u.session_id??""} chunk_seq=${u.chunk_seq??""} is_finish=${u.is_finish??""} ws=${this.ws?`state=${this.ws.readyState}`:"null"}`)}return!1}replayTerminalOutbox(){for(const e of this.terminalOutbox.listPending())this.scheduleTerminalDelivery(e.payload.event_id,{ignoreNotBefore:!0})}outboundEventId(e,t){if(!m.ORDERED_OUTPUT_COMMANDS.has(e)||!t||typeof t!="object")return"";const n=t.event_id;return typeof n=="string"?n.trim():""}blockEventOutput(e){const t=e.trim();if(t)for(this.blockedOutputEvents.delete(t),this.blockedOutputEvents.set(t,Date.now()),this.outboundBuffer=this.outboundBuffer.filter(n=>this.outboundEventId(n.cmd,n.payload)!==t);this.blockedOutputEvents.size>m.MAX_BLOCKED_OUTPUT_EVENTS;){const n=this.blockedOutputEvents.keys().next().value;if(!n)break;this.blockedOutputEvents.delete(n)}}isAckRequiredOutput(e,t){return e==="send_msg"?!0:e==="client_stream_chunk"&&!!t&&typeof t=="object"&&t.is_finish===!0}isNonReplayableOutput(e,t){return e==="codex_event"?!0:e==="client_stream_chunk"&&!!t&&typeof t=="object"&&t.is_finish!==!0}trackNonReplayableOutput(e,t,n,s){if(!this.isNonReplayableOutput(t,n))return;const i=this.outboundEventId(t,n);if(!i||this.outputIntegrityFailed.has(i)||this.blockedOutputEvents.has(i))return;let r=this.nonReplayableOutputEventsBySocket.get(e);r||(r=new Map,this.nonReplayableOutputEventsBySocket.set(e,r)),r.set(i,Math.max(r.get(i)??0,s))}clearNonReplayableOutputThrough(e,t,n){if(!e||n<=0)return;const s=this.nonReplayableOutputEventsBySocket.get(e);if(!s)return;const i=s.get(t);i===void 0||i>n||(s.delete(t),s.size===0&&this.nonReplayableOutputEventsBySocket.delete(e))}clearNonReplayableOutputEvent(e){for(const[t,n]of this.nonReplayableOutputEventsBySocket)n.delete(e),n.size===0&&this.nonReplayableOutputEventsBySocket.delete(t)}failNonReplayableOutputsForSocket(e,t){const n=this.nonReplayableOutputEventsBySocket.get(e);if(n){this.nonReplayableOutputEventsBySocket.delete(e);for(const s of n.keys())this.markOutputIntegrityFailed(s,`connection lost before a complete output acceptance fence: ${t}`)}}hasNonReplayableOutput(e){for(const t of this.nonReplayableOutputEventsBySocket.values())if(t.has(e))return!0;return!1}hasPendingOutputAcceptanceFence(e){return!!(this.pendingAcceptedOutputSeqsByEvent.get(e)?.size||this.outboundBuffer.some(t=>this.outboundEventId(t.cmd,t.payload)===e&&this.isAckRequiredOutput(t.cmd,t.payload)))}hasUnconfirmedEventOutput(e){return!!(this.pendingOutputSeqsByEvent.get(e)?.size||this.pendingAcceptedOutputSeqsByEvent.get(e)?.size||this.outboundBuffer.some(t=>this.outboundEventId(t.cmd,t.payload)===e))}trackOutboundEventCorrelation(e,t,n){const s=this.outboundEventId(e,n);if(!s)return;const i=n,r=typeof i.client_msg_id=="string"?i.client_msg_id.trim():"";this.pruneExpiredEventCorrelations();const u=Date.now();let o=this.eventCorrelations.get(s);if(!o){if(this.eventCorrelations.size>=m.MAX_EVENT_CORRELATIONS){let a;for(const d of this.eventCorrelations.values())this.eventHasCriticalDeliveryState(d.eventId)||(!a||d.touchedAt<a.touchedAt)&&(a=d);a&&this.releaseEventCorrelations(a.eventId)}o={eventId:s,clientMsgIds:new Set,seqRanges:[],touchedAt:u,expiresAt:u+m.EVENT_CORRELATION_TTL_MS},this.eventCorrelations.set(s,o)}o.touchedAt=u,o.expiresAt=u+m.EVENT_CORRELATION_TTL_MS;const h=o.seqRanges[o.seqRanges.length-1];if(h&&t===h.end+1?h.end=t:(!h||t<h.start||t>h.end)&&o.seqRanges.push({start:t,end:t}),r){o.clientMsgIds.add(r);let a=this.clientMsgEventMap.get(r);a||(a=new Set,this.clientMsgEventMap.set(r,a)),a.add(s)}this.scheduleEventCorrelationCleanup()}uniqueEventIdForClientMsgId(e){const t=this.clientMsgEventMap.get(e);if(t?.size===1)return t.values().next().value}eventHasCriticalDeliveryState(e){return!!(this.terminalOutbox.get(e)||this.pendingAcceptedOutputSeqsByEvent.get(e)?.size)}eventIdForSeq(e){if(!(e<=0)){for(const t of this.eventCorrelations.values())if(t.seqRanges.some(n=>e>=n.start&&e<=n.end))return t.eventId}}removeSeqFromEventCorrelation(e){if(!(e<=0))for(const t of this.eventCorrelations.values()){const n=t.seqRanges.findIndex(i=>e>=i.start&&e<=i.end);if(n<0)continue;const s=t.seqRanges[n];s.start===s.end?t.seqRanges.splice(n,1):e===s.start?s.start++:e===s.end?s.end--:t.seqRanges.splice(n,1,{start:s.start,end:e-1},{start:e+1,end:s.end});return}}releaseEventCorrelations(e){const t=e.trim();if(!t)return;const n=this.eventCorrelations.get(t);if(n){for(const s of n.clientMsgIds){const i=this.clientMsgEventMap.get(s);i?.delete(t),i?.size===0&&this.clientMsgEventMap.delete(s)}this.eventCorrelations.delete(t)}this.cancelEventCorrelationCleanupIfEmpty()}clearAllEventCorrelations(){this.eventCorrelationCleanupTimer&&(clearTimeout(this.eventCorrelationCleanupTimer),this.eventCorrelationCleanupTimer=null),this.eventCorrelations.clear(),this.clientMsgEventMap.clear(),this.lastCorrelationPruneAt=0}pruneExpiredEventCorrelations(e=Date.now(),t=!1){if(!(!t&&e-this.lastCorrelationPruneAt<1e3)){this.lastCorrelationPruneAt=e;for(const n of[...this.eventCorrelations.values()])n.expiresAt<=e&&!this.eventHasCriticalDeliveryState(n.eventId)&&this.releaseEventCorrelations(n.eventId);this.cancelEventCorrelationCleanupIfEmpty()}}scheduleEventCorrelationCleanup(){if(this.eventCorrelationCleanupTimer||this.eventCorrelations.size===0)return;let e=Number.POSITIVE_INFINITY;for(const t of this.eventCorrelations.values())this.eventHasCriticalDeliveryState(t.eventId)||(e=Math.min(e,t.expiresAt));Number.isFinite(e)&&(this.eventCorrelationCleanupTimer=setTimeout(()=>{this.eventCorrelationCleanupTimer=null,this.pruneExpiredEventCorrelations(Date.now(),!0),this.scheduleEventCorrelationCleanup()},Math.max(1,e-Date.now())),this.eventCorrelationCleanupTimer.unref?.())}cancelEventCorrelationCleanupIfEmpty(){!this.eventCorrelationCleanupTimer||this.eventCorrelations.size>0||(clearTimeout(this.eventCorrelationCleanupTimer),this.eventCorrelationCleanupTimer=null)}logUnmatchedNack(e){const t=e.payload??{},n=typeof t.cmd=="string"?t.cmd.trim():"";if(!n||m.OUTPUT_NACK_CMDS.has(n))return;const s=typeof t.session_id=="string"?t.session_id.trim():"",i=typeof t.code=="number"?t.code:Number(t.code??0)||0,r=`${n}|${s}|${i}`,u=Date.now(),o=this.unmatchedNackLoggedAt.get(r)??0;if(o>0&&u-o<m.UNMATCHED_NACK_LOG_WINDOW_MS)return;if(this.unmatchedNackLoggedAt.size>=256){for(const[a,d]of this.unmatchedNackLoggedAt)u-d>=m.UNMATCHED_NACK_LOG_WINDOW_MS&&this.unmatchedNackLoggedAt.delete(a);this.unmatchedNackLoggedAt.size>=256&&this.unmatchedNackLoggedAt.clear()}this.unmatchedNackLoggedAt.set(r,u);const h=typeof t.msg=="string"?t.msg:"";p.warn("aibot",`backend rejected ${n} session=${s||"<none>"} code=${i} msg=${h||"<none>"} seq=${e.seq} (repeats suppressed for ${m.UNMATCHED_NACK_LOG_WINDOW_MS/1e3}s)`)}handleCorrelatedSendResponse(e){if(e.cmd==="send_ack"){const h=e.payload,a=typeof h.client_msg_id=="string"?h.client_msg_id.trim():"";let d=e.seq>0&&this.pendingAcceptedOutputs.has(e.seq)?e.seq:void 0,_;if(d===void 0&&a){const l=this.pendingAcceptedSeqsByClientMsgId.get(a);if(l?.size===1){const f=l.values().next().value,g=this.pendingAcceptedOutputs.get(f),O=this.uniqueEventIdForClientMsgId(a);g&&O&&g.eventId===O&&(d=f,_=O)}}const b=(d!==void 0?this.pendingAcceptedOutputs.get(d)?.eventId:void 0)??_??this.eventIdForSeq(e.seq),c=d??e.seq;if(d!==void 0){const l=this.pendingOutputWrites.get(d);l&&this.settlePendingOutputWrite(d,!0,!1,l.socket,l.connectionGeneration),this.settlePendingAcceptedOutput(d,"accepted",!1)}else if(e.seq>0){const l=this.pendingOutputWrites.get(e.seq);l&&this.settlePendingOutputWrite(e.seq,!0,!1,l.socket,l.connectionGeneration)}b&&this.clearNonReplayableOutputThrough(this.ws,b,c);return}if(e.cmd!=="send_nack"&&e.cmd!=="error")return;this.pruneExpiredEventCorrelations();const t=e.payload,n=typeof t.client_msg_id=="string"?t.client_msg_id.trim():"",s=e.cmd==="error"&&typeof t.ref_id=="string"?t.ref_id.trim():"",i=e.cmd==="error"&&typeof t.ref_cmd=="string"?t.ref_cmd.trim():"",r=this.eventIdForSeq(e.seq),u=s&&(!i||m.ORDERED_OUTPUT_COMMANDS.has(i))?this.uniqueEventIdForClientMsgId(s)??(this.eventCorrelations.has(s)?s:void 0):void 0,o=r??(n?this.uniqueEventIdForClientMsgId(n):void 0)??u;o&&(this.blockEventOutput(o),this.settlePendingOutputWritesForEvent(o,!0),this.clearNonReplayableOutputEvent(o),e.seq>0&&this.pendingAcceptedOutputs.get(e.seq)?.eventId===o?this.settlePendingAcceptedOutput(e.seq,"rejected",!1):this.settlePendingAcceptedOutputsForEvent(o,"rejected",!1),t.code===4003&&(this.purgeBufferedStreamChunks(o),p.warn("aibot",`event payload rejected (4003), purging buffered chunks for event=${o}`)),this.promotePendingTerminalAfterOutputRejection(o,Number(t.code??0),t.msg),this.emit("streamRejected",o,Number(t.code??0)))}promotePendingTerminalAfterOutputRejection(e,t,n){this.provisionalRespondedTerminals.delete(e);const s=this.terminalOutbox.get(e);if(!(!s||s.payload.status!=="responded"&&s.payload.code!=="agent_output_unconfirmed"||s.deliveryStartedAt))try{const i=this.terminalOutbox.enqueue({...s.payload,status:"failed",code:"agent_output_rejected",msg:n?`required agent output was rejected: ${n}`:`required agent output was rejected by the server (code=${t})`,updated_at:Date.now()});this.scheduleTerminalDelivery(i.payload.event_id,{ignoreNotBefore:!0})}catch(i){this.emitClientError(new Error(`failed to persist output-rejection terminal promotion: event=${e} code=${t}: ${i instanceof Error?i.message:i}`))}}scheduleTerminalDelivery(e,t){if(!this.connected||!this.ws||this.ws.readyState!==y.OPEN)return;if(this.terminalInFlight.has(e)){t?.ignoreNotBefore&&this.terminalReplayAfterFlight.add(e);return}const n=this.terminalOutbox.get(e);if(!n)return;const s=this.terminalRetryTimers.get(e);s&&(clearTimeout(s),this.terminalRetryTimers.delete(e));const i=t?.ignoreNotBefore?0:Math.max(0,n.nextAttemptAt-Date.now()),r=Math.max(i,t?.minimumDelayMs??0);if(r>0){const u=setTimeout(()=>{this.terminalRetryTimers.delete(e),this.scheduleTerminalDelivery(e,{ignoreNotBefore:!0})},r);this.terminalRetryTimers.set(e,u);return}this.deliverTerminalEntry(n)}async deliverTerminalEntry(e){const t=e.payload.event_id;if(this.terminalInFlight.has(t)||!this.terminalOutbox.isCurrent(e))return;this.terminalInFlight.add(t);let n=0;try{n=await this.sendEventResultReliable(e)}finally{this.terminalInFlight.delete(t);const s=this.terminalReplayAfterFlight.delete(t);this.terminalOutbox.get(t)&&this.scheduleTerminalDelivery(t,s?{ignoreNotBefore:!0}:{minimumDelayMs:n})}}clearTerminalRetryTimers(){for(const e of this.terminalRetryTimers.values())clearTimeout(e);this.terminalRetryTimers.clear()}async sendEventResultReliable(e){const t=e.payload.event_id,n=e.payload.terminal_commit_token?.trim();if(n&&!this.negotiatedCapabilities.has("terminal_commit_v1")){const d=this.ws;return this.emitClientError(new Error(`refusing tokenized event_result on an unnegotiated connection: event=${t}`)),d&&this.reconnectAfterOutboundWriteFailure(d,"terminal_commit_v1 not negotiated"),m.TERMINAL_RETRY_DELAY_MS}if(!await this.awaitOutputDeliveryBarrier(t))return m.TERMINAL_RETRY_DELAY_MS;const s=this.provisionalRespondedTerminals.get(t);if(s&&this.terminalOutbox.isCurrent(e))if(!this.canReplaceUnsentOutputGuard(e))this.provisionalRespondedTerminals.delete(t);else try{return this.terminalOutbox.enqueue(s),this.provisionalRespondedTerminals.delete(t),0}catch(d){return this.emitClientError(new Error(`failed to promote confirmed output terminal to responded: event=${t}: ${d instanceof Error?d.message:d}`)),m.TERMINAL_RETRY_DELAY_MS}const i=e.payload;try{if(!this.terminalOutbox.markDeliveryStarted(e))return 0}catch(d){return this.emitClientError(new Error(`event_result delivery-start persist failed: event=${t}: ${d instanceof Error?d.message:d}`)),m.TERMINAL_RETRY_DELAY_MS}const r=Math.max(1,this.ackPolicy?.max_retries??3),u=this.ackPolicy?.push_ack_timeout_ms??5e3,o=750;let h="unknown delivery failure";for(let d=1;d<=r;d++){if(!this.terminalOutbox.isCurrent(e))return 0;const _=this.ws?.readyState??-1,b=this.ws?.bufferedAmount??0;p.info("aibot",`event_result send attempt event=${i.event_id} status=${i.status} attempt=${d}/${r} readyState=${_} bufferedAmount=${b}`);try{const c=await this.sendEventResultRequest(i,u);if(!this.terminalOutbox.isCurrent(e))return 0;if(c.cmd==="send_ack"){const f=c.payload;if(p.info("aibot",`event_result ack event=${i.event_id} status=${i.status} attempt=${d}/${r} ack_event=${f.event_id??""} ack_status=${f.status??""}`),f.event_id!==i.event_id||f.status!==i.status)throw new Error(`event_result ACK mismatch: expected event=${i.event_id} status=${i.status}, got event=${f.event_id??""} status=${f.status??""}`);if(n&&(f.terminal_commit_token?.trim()!==n||f.terminal_committed!==!0))throw new Error(`event_result terminal commit ACK mismatch: event=${i.event_id}`);if(n)try{this.terminalCommitTokens.remove(i.event_id,n)}catch(g){throw new Error(`terminal commit token cleanup failed: event=${i.event_id}: ${g instanceof Error?g.message:g}`)}return this.terminalOutbox.acknowledge(e,f.event_id,f.status,f.terminal_commit_token,f.terminal_committed)&&(this.rememberCommittedTerminalEvent(i.event_id),this.tokenizedTerminalRejections.delete(i.event_id),this.blockEventOutput(i.event_id),this.releaseEventCorrelations(i.event_id),this.clearNonReplayableOutputEvent(i.event_id),this.settleOutputIntegrityTerminal(i.event_id),this.scheduleStopResultsForEvent(i.event_id)),0}const l=c.payload;if(p.warn("aibot",`event_result rejected event=${i.event_id} status=${i.status} attempt=${d}/${r} cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}${l.ref_cmd?` ref_cmd=${l.ref_cmd}`:""}${l.ref_id?` ref_id=${l.ref_id}`:""}`),n){h=`tokenized terminal rejected: cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}`;const f=(this.tokenizedTerminalRejections.get(i.event_id)??0)+1;if(this.tokenizedTerminalRejections.set(i.event_id,f),f<m.MAX_TOKENIZED_TERMINAL_REJECTIONS)break;this.tokenizedTerminalRejections.delete(i.event_id);try{this.terminalCommitTokens.remove(i.event_id,n),this.terminalOutbox.moveToDeadLetter(e,{responseCmd:c.cmd,code:l.code,message:l.msg})&&(this.blockEventOutput(i.event_id),this.releaseEventCorrelations(i.event_id),this.clearNonReplayableOutputEvent(i.event_id),this.settleOutputIntegrityTerminal(i.event_id),this.emitClientError(new Error(`tokenized event_result permanently rejected after ${f} rejections, moved to dead-letter: event=${i.event_id} status=${i.status} cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}`)))}catch(g){h=`dead-letter persist failed: ${g instanceof Error?g.message:g}`,this.emitClientError(new Error(`tokenized event_result dead-letter persist failed: event=${i.event_id} status=${i.status}: ${h}`));break}return 0}try{return this.terminalOutbox.moveToDeadLetter(e,{responseCmd:c.cmd,code:l.code,message:l.msg})&&(this.tokenizedTerminalRejections.delete(i.event_id),this.blockEventOutput(i.event_id),this.releaseEventCorrelations(i.event_id),this.clearNonReplayableOutputEvent(i.event_id),this.settleOutputIntegrityTerminal(i.event_id),this.emitClientError(new Error(`event_result rejected and moved to dead-letter: event=${i.event_id} status=${i.status} cmd=${c.cmd} code=${l.code??""} msg=${l.msg??""}`))),0}catch(f){h=`dead-letter persist failed: ${f instanceof Error?f.message:f}`,this.emitClientError(new Error(`event_result dead-letter persist failed: event=${i.event_id} status=${i.status}: ${h}`));break}}catch(c){const l=c instanceof Error?c.message:String(c);if(h=l,p.warn("aibot",`event_result attempt failed event=${i.event_id} status=${i.status} attempt=${d}/${r} err=${l}`),d===r)break;await new Promise(f=>setTimeout(f,o*d))}}const a=Date.now()+m.TERMINAL_RETRY_DELAY_MS;try{this.terminalOutbox.recordRetry(e,a,h)}catch(d){this.emitClientError(new Error(`event_result retry state persist failed: event=${i.event_id} status=${i.status}: ${d instanceof Error?d.message:d}`))}return this.emitClientError(new Error(`event_result ack failed after ${r} attempts; retained for retry: event=${i.event_id} status=${i.status} err=${h}`)),m.TERMINAL_RETRY_DELAY_MS}purgeBufferedStreamChunks(e){const t=this.outboundBuffer.length;this.outboundBuffer=this.outboundBuffer.filter(n=>n.cmd!=="client_stream_chunk"?!0:n.payload?.event_id!==e),this.outboundBuffer.length<t&&p.info("aibot",`purged ${t-this.outboundBuffer.length} buffered stream chunks for event=${e}`)}emitClientError(e){if(this.listenerCount("error")===0){p.warn("aibot",`Client error (no listeners): ${e.message}`);return}this.emit("error",e)}createOutboundEntry(e,t){const n={cmd:e,payload:t};return this.outboundEntryOrders.set(n,++this.nextOutboundEntryOrder),n}makeOutputIntegrityFailurePayload(e,t){return this.withTerminalCommitToken({event_id:e,status:"failed",code:"agent_output_integrity_failed",msg:`required agent output was discarded before delivery: ${t}`,updated_at:Date.now()})}canReplaceUnsentOutputGuard(e){return e.payload.code==="agent_output_unconfirmed"&&!e.deliveryStartedAt}rememberCommittedTerminalEvent(e){for(this.committedTerminalEvents.delete(e),this.committedTerminalEvents.add(e);this.committedTerminalEvents.size>m.MAX_COMMITTED_TERMINAL_EVENTS;){const t=this.committedTerminalEvents.values().next().value;if(!t)break;this.committedTerminalEvents.delete(t)}}replayStopResultOutbox(){for(const e of this.stopResultOutbox.listPending())this.scheduleStopResultDelivery(e,{ignoreNotBefore:!0})}scheduleStopResultsForEvent(e){for(const t of this.stopResultOutbox.listPending())t.payload.event_id===e&&this.scheduleStopResultDelivery(t,{ignoreNotBefore:!0})}scheduleStopResultDelivery(e,t){if(!this.connected||!this.ws||this.ws.readyState!==y.OPEN||!this.stopResultOutbox.isCurrent(e))return;const n=e.payload.event_id;if(this.terminalOutbox.get(n)||this.terminalCommitTokens.get(n))return;const s=this.stopResultRetryTimers.get(e.key);s&&(clearTimeout(s),this.stopResultRetryTimers.delete(e.key));const i=t?.ignoreNotBefore?0:Math.max(0,e.nextAttemptAt-Date.now());if(i>0){const r=setTimeout(()=>{this.stopResultRetryTimers.delete(e.key),this.scheduleStopResultDelivery(e,{ignoreNotBefore:!0})},i);this.stopResultRetryTimers.set(e.key,r);return}this.deliverStopResultEntry(e)}async deliverStopResultEntry(e){if(this.stopResultInFlight.has(e.key)||!this.stopResultOutbox.isCurrent(e))return;this.stopResultInFlight.add(e.key);let t=m.TERMINAL_RETRY_DELAY_MS;try{t=await this.sendStopResultReliable(e)}finally{if(this.stopResultInFlight.delete(e.key),this.stopResultOutbox.isCurrent(e)){const n=setTimeout(()=>{this.stopResultRetryTimers.delete(e.key),this.scheduleStopResultDelivery(e,{ignoreNotBefore:!0})},t);this.stopResultRetryTimers.set(e.key,n)}}}async sendStopResultReliable(e){const t=this.ackPolicy?.push_ack_timeout_ms??5e3;let n="unknown delivery failure";try{const i=await this.request("event_stop_result",e.payload,{expected:["send_ack","send_nack","error"],timeoutMs:t});if(!this.stopResultOutbox.isCurrent(e))return 0;if(i.cmd==="send_ack"){const r=i.payload;if(this.stopResultOutbox.acknowledge(e,r.event_id,r.terminal_commit_token,r.terminal_committed))return 0;n=`event_stop_result ACK mismatch event=${e.payload.event_id}`}else{const r=i.payload;if(n=`event_stop_result rejected: cmd=${i.cmd} code=${r.code??""} msg=${r.msg??""}`,r.code===4001||r.code===4003){try{this.stopResultOutbox.discard(e)&&this.emitClientError(new Error(`event_stop_result permanently rejected and discarded: event=${e.payload.event_id} stop=${e.payload.stop_id} code=${r.code} msg=${r.msg??""}`))}catch(u){this.emitClientError(new Error(`event_stop_result discard persist failed: event=${e.payload.event_id} stop=${e.payload.stop_id}: ${u instanceof Error?u.message:u}`))}return 0}}}catch(i){n=i instanceof Error?i.message:String(i)}const s=Date.now()+m.TERMINAL_RETRY_DELAY_MS;try{this.stopResultOutbox.recordRetry(e,s,n)}catch(i){this.emitClientError(new Error(`event_stop_result retry state persist failed: event=${e.payload.event_id} stop=${e.payload.stop_id}: ${i instanceof Error?i.message:i}`))}return this.emitClientError(new Error(`event_stop_result retained for retry: event=${e.payload.event_id} stop=${e.payload.stop_id} err=${n}`)),m.TERMINAL_RETRY_DELAY_MS}clearStopResultRetryTimers(){for(const e of this.stopResultRetryTimers.values())clearTimeout(e);this.stopResultRetryTimers.clear()}markOutputIntegrityFailed(e,t){if(this.blockEventOutput(e),this.outputIntegrityFailed.has(e))return;const n={reason:t,terminalObserved:!!(this.provisionalRespondedTerminals.has(e)||this.terminalOutbox.get(e)),terminalSettled:!1};this.outputIntegrityFailed.set(e,n),this.provisionalRespondedTerminals.delete(e),this.clearNonReplayableOutputEvent(e);const s=this.outboundBuffer.length;this.outboundBuffer=this.outboundBuffer.filter(u=>this.outboundEventId(u.cmd,u.payload)!==e);const i=this.terminalOutbox.get(e),r=i?this.canReplaceUnsentOutputGuard(i):!1;if(i&&!r)n.terminalObserved=!0,this.scheduleTerminalDelivery(e,{ignoreNotBefore:!0});else if(!this.committedTerminalEvents.has(e))try{const u=this.terminalOutbox.enqueue(this.makeOutputIntegrityFailurePayload(e,t));this.scheduleTerminalDelivery(u.payload.event_id,{ignoreNotBefore:!0})}catch(u){this.emitClientError(new Error(`output-integrity terminal persist failed: event=${e}: ${u instanceof Error?u.message:u}`))}for(const u of[...this.pendingOutputSeqsByEvent.get(e)??[]])this.settlePendingOutputWrite(u,!1,!1);this.settlePendingAcceptedOutputsForEvent(e,"rejected",!1),this.emit("streamRejected",e,0),this.emitClientError(new Error(`required output integrity failed: event=${e} removed=${s-this.outboundBuffer.length} reason=${t}`))}settleOutputIntegrityTerminal(e){const t=this.outputIntegrityFailed.get(e);t&&(t.terminalSettled=!0,t.terminalObserved&&this.outputIntegrityFailed.delete(e))}bufferOutboundEntry(e){if(this.outboundEntryOrders.has(e)||this.outboundEntryOrders.set(e,++this.nextOutboundEntryOrder),this.outboundBuffer.includes(e))return!0;const t=this.outboundEventId(e.cmd,e.payload);return t&&(this.outputIntegrityFailed.has(t)||this.blockedOutputEvents.has(t))?!1:(this.outboundBuffer.length>=m.MAX_OUTBOUND_BUFFER_SIZE&&(this.outboundBuffer=this.outboundBuffer.filter(n=>m.BUFFER_OVERFLOW_RETAIN_COMMANDS.has(n.cmd)),this.outboundBuffer.length>=m.MAX_OUTBOUND_BUFFER_SIZE&&p.warn("aibot",`outbound buffer soft limit exceeded by ${this.outboundBuffer.length} retained packet(s); preserving required output`)),this.outboundBuffer.length>=m.MAX_OUTBOUND_BUFFER_HARD_SIZE?(t?this.markOutputIntegrityFailed(t,`outbound buffer hard limit ${m.MAX_OUTBOUND_BUFFER_HARD_SIZE} reached`):this.emitClientError(new Error(`outbound buffer hard limit ${m.MAX_OUTBOUND_BUFFER_HARD_SIZE} reached; rejected non-event packet cmd=${e.cmd}`)),!1):(this.outboundBuffer.push(e),this.outboundBuffer.sort((n,s)=>(this.outboundEntryOrders.get(n)??Number.MAX_SAFE_INTEGER)-(this.outboundEntryOrders.get(s)??Number.MAX_SAFE_INTEGER)),!0))}registerPendingOutputWrite(e,t,n,s,i){let r;const u=new Promise(a=>{r=a}),o=setTimeout(()=>{const a=this.pendingOutputWrites.get(e);if(!a||a.socket!==s||a.connectionGeneration!==i)return;if(!this.isConnectionCurrent(s,i)){this.settlePendingOutputWrite(e,!1,!1,s,i);return}this.removeSeqFromEventCorrelation(e);const d=this.isNonReplayableOutput(n.cmd,n.payload);this.settlePendingOutputWrite(e,!1,!d,s,i),d&&this.markOutputIntegrityFailed(t,`websocket write callback timed out for non-replayable ${n.cmd} seq=${e}`),this.emitClientError(new Error(`outbound websocket write callback timeout: cmd=${n.cmd} event=${t} seq=${e} delivery_unknown=${d}`)),this.reconnectAfterOutboundWriteFailure(s,`${n.cmd} callback timeout`)},m.OUTBOUND_WRITE_CALLBACK_TIMEOUT_MS);o.unref?.(),this.pendingOutputWrites.set(e,{eventId:t,entry:n,socket:s,connectionGeneration:i,promise:u,resolve:r,timer:o});let h=this.pendingOutputSeqsByEvent.get(t);h||(h=new Set,this.pendingOutputSeqsByEvent.set(t,h)),h.add(e)}settlePendingOutputWrite(e,t,n,s,i){const r=this.pendingOutputWrites.get(e);if(!r||s&&(r.socket!==s||r.connectionGeneration!==i))return;this.pendingOutputWrites.delete(e),clearTimeout(r.timer);const u=this.pendingOutputSeqsByEvent.get(r.eventId);u?.delete(e),u?.size===0&&this.pendingOutputSeqsByEvent.delete(r.eventId),n&&this.bufferOutboundEntry(r.entry),r.resolve(t)}settlePendingOutputWritesForEvent(e,t){const n=this.pendingOutputSeqsByEvent.get(e);if(n)for(const s of[...n]){const i=this.pendingOutputWrites.get(s);i&&this.settlePendingOutputWrite(s,t,!1,i.socket,i.connectionGeneration)}}abortPendingOutputWrites(e,t,n,s){for(const[i,r]of[...this.pendingOutputWrites.entries()])if(!(t&&(r.socket!==t||r.connectionGeneration!==n))){if(this.removeSeqFromEventCorrelation(i),s&&this.isNonReplayableOutput(r.entry.cmd,r.entry.payload)){this.settlePendingOutputWrite(i,!1,!1,t,n),this.markOutputIntegrityFailed(r.eventId,`connection lost while websocket write completion was unknown: ${s}`);continue}this.settlePendingOutputWrite(i,!1,e,t,n)}}registerPendingAcceptedOutput(e,t,n,s,i){let r;const u=new Promise(f=>{r=f}),o=Math.max(1,this.ackPolicy?.push_ack_timeout_ms??5e3),h=Math.max(1,this.ackPolicy?.max_retries??3),a=Math.max(1e3,Math.ceil(o*.25)),d=Math.max(m.MIN_REQUIRED_OUTPUT_ACK_TIMEOUT_MS,o*h+a),_=setTimeout(()=>{const f=this.pendingAcceptedOutputs.get(e);if(!(!f||f.socket!==s||f.connectionGeneration!==i)){if(!this.isConnectionCurrent(s,i)){this.settlePendingAcceptedOutput(e,"retry",!1,s,i);return}this.settlePendingAcceptedOutput(e,"retry",!0,s,i),this.emitClientError(new Error(`required output ACK timeout; retained for reconnect retry: event=${t} seq=${e}`)),this.reconnectAfterOutboundWriteFailure(s,"required output ACK timeout")}},d);_.unref?.(),this.pendingAcceptedOutputs.set(e,{eventId:t,entry:n,socket:s,connectionGeneration:i,promise:u,resolve:r,timer:_});const b=n.payload,c=typeof b.client_msg_id=="string"?b.client_msg_id.trim():"";if(c){let f=this.pendingAcceptedSeqsByClientMsgId.get(c);f||(f=new Set,this.pendingAcceptedSeqsByClientMsgId.set(c,f)),f.add(e)}let l=this.pendingAcceptedOutputSeqsByEvent.get(t);l||(l=new Set,this.pendingAcceptedOutputSeqsByEvent.set(t,l)),l.add(e)}settlePendingAcceptedOutput(e,t,n,s,i){const r=this.pendingAcceptedOutputs.get(e);if(!r||s&&(r.socket!==s||r.connectionGeneration!==i))return;this.pendingAcceptedOutputs.delete(e),clearTimeout(r.timer);const u=this.pendingAcceptedOutputSeqsByEvent.get(r.eventId);u?.delete(e),u?.size===0&&this.pendingAcceptedOutputSeqsByEvent.delete(r.eventId);const o=r.entry.payload,h=typeof o.client_msg_id=="string"?o.client_msg_id.trim():"";if(h){const a=this.pendingAcceptedSeqsByClientMsgId.get(h);a?.delete(e),a?.size===0&&this.pendingAcceptedSeqsByClientMsgId.delete(h)}n&&this.bufferOutboundEntry(r.entry),r.resolve(t)}settlePendingAcceptedOutputsForEvent(e,t,n){const s=this.pendingAcceptedOutputSeqsByEvent.get(e);if(s)for(const i of[...s])this.settlePendingAcceptedOutput(i,t,n)}abortPendingAcceptedOutputs(e,t,n){for(const[s,i]of[...this.pendingAcceptedOutputs.entries()])t&&(i.socket!==t||i.connectionGeneration!==n)||this.settlePendingAcceptedOutput(s,"retry",e,t,n)}rejectPendingRequestAfterWriteFailure(e,t,n){const s=this.pendingRequests.get(e);s&&(this.pendingRequests.delete(e),clearTimeout(s.timer),s.reject(new Error(`websocket write failed: ${t}: ${n.message}`)))}async awaitOutputDeliveryBarrier(e){const t=this.outboundFlushInFlight;if(t&&!await t.promise)return!1;for(;;){const n=this.pendingOutputSeqsByEvent.get(e);if(!n||n.size===0)break;const s=[...n].map(r=>this.pendingOutputWrites.get(r)?.promise).filter(r=>!!r);if(s.length===0)break;if((await Promise.all(s)).some(r=>!r))return!1}for(;;){const n=this.pendingAcceptedOutputSeqsByEvent.get(e);if(!n||n.size===0)break;const s=[...n].map(r=>this.pendingAcceptedOutputs.get(r)?.promise).filter(r=>!!r);if(s.length===0)break;const i=await Promise.all(s);if(i.includes("retry"))return!1;if(i.includes("rejected")){const r=this.terminalOutbox.get(e);if(!r||r.payload.status==="responded")return!1}}return this.outboundBuffer.some(n=>this.outboundEventId(n.cmd,n.payload)===e)?!1:this.hasNonReplayableOutput(e)?(this.markOutputIntegrityFailed(e,"output flush completed without a complete acceptance fence"),!1):!!(this.connected&&this.ws&&this.ws.readyState===y.OPEN)}isConnectionCurrent(e,t){return this.ws===e&&this.connectionGeneration===t}isOutboundFlushCurrent(e){return!e.finalized&&this.outboundFlushInFlight===e&&this.isConnectionCurrent(e.socket,e.connectionGeneration)}flushOutboundBuffer(e=this.ws,t=this.connectionGeneration){if(!e||!this.isConnectionCurrent(e,t))return Promise.resolve(!1);const n=this.outboundFlushInFlight;if(n){if(!n.finalized&&n.socket===e&&n.connectionGeneration===t)return n.promise;this.cancelOutboundFlush(n,"discard","superseded stale flush")}if(this.outboundBuffer.length===0)return Promise.resolve(!0);const s={connectionGeneration:t,flushGeneration:++this.nextOutboundFlushGeneration,socket:e,promise:Promise.resolve(!1),finalized:!1,activeBatch:null,nextIndex:0,currentWritePending:!1,currentWriteOutcome:null,cancelCurrentWrite:null,remainderHandled:!1};return this.outboundFlushInFlight=s,s.promise=this.performOutboundBufferFlush(s),s.promise.finally(()=>{s.finalized=!0,s.cancelCurrentWrite?.(),s.cancelCurrentWrite=null,this.outboundFlushInFlight===s&&(this.outboundFlushInFlight=null)}),s.promise}async performOutboundBufferFlush(e){for(;this.isOutboundFlushCurrent(e)&&this.outboundBuffer.length>0;){const{socket:t}=e;if(t.readyState!==y.OPEN)return!1;const n=this.outboundBuffer;this.outboundBuffer=[],e.activeBatch=n,e.nextIndex=0,e.remainderHandled=!1;for(let s=0;s<n.length;s++){if(!this.isOutboundFlushCurrent(e))return!1;const i=n[s],{cmd:r,payload:u}=i,o=this.outboundEventId(r,u);if(o&&this.blockedOutputEvents.has(o)){this.packetLog?.logOutboundPacket(r,0,u,"dropped"),e.nextIndex=s+1,e.currentWritePending=!1,e.currentWriteOutcome=null;continue}const h=++this.seq,a={cmd:r,seq:h,payload:u};e.nextIndex=s,e.currentWritePending=!0,e.currentWriteOutcome=null,o&&this.isAckRequiredOutput(r,u)&&this.registerPendingAcceptedOutput(h,o,i,t,e.connectionGeneration);const d=await new Promise(_=>{let b=!1;const c=f=>{b||(b=!0,clearTimeout(l),e.currentWriteOutcome=f,_(f))},l=setTimeout(()=>c("uncertain"),m.OUTBOUND_WRITE_CALLBACK_TIMEOUT_MS);l.unref?.(),e.cancelCurrentWrite=()=>c("canceled");try{this.trackOutboundEventCorrelation(r,h,u),t.send(JSON.stringify(a),f=>{c(f?"retry":"written")})}catch{c("retry")}});if(e.cancelCurrentWrite=null,!this.isOutboundFlushCurrent(e))return!1;if(d!=="written"||t.readyState!==y.OPEN){d==="retry"&&this.removeSeqFromEventCorrelation(h),this.settlePendingAcceptedOutput(h,"retry",!1);const _=this.retainOutboundFlushRemainder(e,d,`auth flush write failed for ${r} seq=${h} outcome=${d}`);return this.emitClientError(new Error(`outbound buffer flush failed at cmd=${r} seq=${h} outcome=${d}; ${_} packet(s) retained`)),!1}this.trackNonReplayableOutput(t,r,u,h),e.currentWritePending=!1,e.currentWriteOutcome="written",e.nextIndex=s+1}e.activeBatch=null,e.currentWritePending=!1,e.currentWriteOutcome=null,e.remainderHandled=!0}return this.isOutboundFlushCurrent(e)}retainOutboundFlushRemainder(e,t,n){if(e.remainderHandled||!e.activeBatch)return 0;e.remainderHandled=!0;const s=e.activeBatch,i=Math.min(e.nextIndex,s.length);let r=i;if(e.currentWritePending&&i<s.length){const o=s[i],h=this.outboundEventId(o.cmd,o.payload);t!=="retry"&&this.isNonReplayableOutput(o.cmd,o.payload)&&h&&(this.markOutputIntegrityFailed(h,n),r=i+1)}let u=0;for(const o of s.slice(r))this.bufferOutboundEntry(o)&&u++;return e.activeBatch=null,e.nextIndex=s.length,e.currentWritePending=!1,u}cancelOutboundFlush(e,t,n){if(e.finalized){this.outboundFlushInFlight===e&&(this.outboundFlushInFlight=null);return}e.finalized=!0,this.outboundFlushInFlight===e&&(this.outboundFlushInFlight=null),t==="connection_lost"?this.retainOutboundFlushRemainder(e,e.currentWriteOutcome,`connection lost during auth flush: ${n}`):(e.remainderHandled=!0,e.activeBatch=null,e.currentWritePending=!1);const s=e.cancelCurrentWrite;e.cancelCurrentWrite=null,s?.()}reconnectAfterOutboundFlushFailure(e,t){this.agentDeleted||!this.isConnectionCurrent(e,t)||this.reconnectAfterOutboundWriteFailure(e,"outbound flush failed")}reconnectAfterOutboundWriteFailure(e,t){if(this.agentDeleted||this.ws!==e)return;const n=this.connectionGeneration;this.connected=!1,this.negotiatedCapabilities.clear(),this.stopHeartbeat(),this.clearTerminalRetryTimers(),this.clearStopResultRetryTimers(),this.rejectAllPendingRequests(t);const s=this.outboundFlushInFlight;s&&s.socket===e&&s.connectionGeneration===n&&this.cancelOutboundFlush(s,"connection_lost",t),this.failNonReplayableOutputsForSocket(e,t),this.abortPendingOutputWrites(!0,e,n,t),this.abortPendingAcceptedOutputs(!0,e,n),this.clearAllEventCorrelations(),this.connectionGeneration++;try{e.close(1011,t)}catch{}this.ws===e&&(this.ws=null),this.attemptReconnect()}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(e=this.ws,t=this.connectionGeneration){if(!(!e||!this.isConnectionCurrent(e,t)))try{e.close()}catch{}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatFailures=0,this.heartbeatTimer=setInterval(()=>{const e=this.ws,t=this.connectionGeneration;!this.connected||!e||this.request("ping",{ts:Date.now()},{expected:["pong"],timeoutMs:5e3}).then(()=>{this.isConnectionCurrent(e,t)&&(this.heartbeatFailures=0)}).catch(()=>{!this.connected||!this.isConnectionCurrent(e,t)||(this.heartbeatFailures++,!(this.heartbeatFailures<m.HEARTBEAT_MAX_FAILURES)&&(this.cleanupSocket(e,t),this.attemptReconnect()))})},this.heartbeatSec*1e3)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}}export{m as AibotClient,D as preprocessLargeIntegers,U as withRequiredCapabilities};
@@ -1 +1 @@
1
- import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const t of c){if(!p&&t.name.startsWith("."))continue;const i=l(a,t.name),e={id:i,name:t.name,is_directory:t.isDirectory()};try{if(t.isDirectory()){const o=await m(i);e.modified_at=o.mtime.toISOString()}else{const o=await m(i);e.size=o.size,e.modified_at=o.mtime.toISOString(),e.mime_type=n(t.name)}}catch{}s.push(e)}return s.sort((t,i)=>t.is_directory!==i.is_directory?t.is_directory?-1:1:t.name.localeCompare(i.name)),s}export{f as listFiles,n as resolveMimeType};
1
+ import{readdir as r,stat as m}from"node:fs/promises";import{join as l,extname as d}from"node:path";const x={pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",txt:"text/plain",md:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",yaml:"text/yaml",yml:"text/yaml",html:"text/html",css:"text/css",js:"text/javascript",ts:"text/typescript",zip:"application/zip",rar:"application/x-rar-compressed","7z":"application/x-7z-compressed",tar:"application/x-tar",gz:"application/gzip",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",mp4:"video/mp4",mov:"video/quicktime",avi:"video/x-msvideo",mkv:"video/x-matroska",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",flac:"audio/flac",aac:"audio/aac"};function n(a){const p=d(a).slice(1).toLowerCase();return x[p]}async function f(a,p=!1){const c=await r(a,{withFileTypes:!0}),s=[];for(const i of c){if(!p&&i.name.startsWith("."))continue;const t=l(a,i.name),e={id:t,name:i.name,is_directory:i.isDirectory()};try{if(i.isDirectory()){const o=await m(t);e.modified_at=o.mtime.toISOString()}else{const o=await m(t);e.size=o.size,e.modified_at=o.mtime.toISOString(),e.mime_type=n(i.name)}}catch{}s.push(e)}return s.sort((i,t)=>i.is_directory!==t.is_directory?i.is_directory?-1:1:i.name.localeCompare(t.name)),s}export{f as listFiles,n as resolveMimeType};
@@ -1,2 +1,2 @@
1
- import{readJSONFile as S,writeJSONFileAtomic as b}from"../util/json-file.js";import{log as l}from"../log/index.js";import{SESSION_MODE_IDS as u}from"../../adapter/claude/protocol-contract.js";import{normalizeClaudeEffort as g}from"../config/claude-direct-env.js";import{chmodSync as M,copyFileSync as y,existsSync as f,renameSync as v,rmSync as w,writeFileSync as C}from"node:fs";import{randomUUID as A}from"node:crypto";const x=u.fullAuto;function a(h){const t=String(h??"").trim().toLowerCase();return t===u.approval||t===u.fullAuto?t:x}class N{bindings=new Map;filePath;legacyFilePath;writePromise=Promise.resolve();constructor(t,e){this.filePath=t??null,this.legacyFilePath=e&&e!==t?e:null}load(){if(!this.filePath)return;const t=f(this.filePath);let e=S(this.filePath),d=!1;if(t&&!Array.isArray(e)){const s=this.quarantineUnreadablePrimary();throw new Error(`Refusing to start with unreadable session bindings: primary=${this.filePath}`+(s?` quarantined=${s}`:"")+(this.legacyFilePath?` legacy=${this.legacyFilePath}`:"")+" (legacy fallback disabled to avoid clobbering newer bindings)")}if(!t&&this.legacyFilePath){d=f(this.legacyFilePath);const s=S(this.legacyFilePath);Array.isArray(s)&&(this.writeMigratedSnapshot(s),e=s,l.info("session-binding-store",`Migrated legacy bindings from ${this.legacyFilePath} to ${this.filePath}; legacy file retained`))}if(!Array.isArray(e)){if(t||d)throw new Error(`Refusing to start with unreadable session bindings: primary=${this.filePath}${this.legacyFilePath?` legacy=${this.legacyFilePath}`:""}`);return}this.bindings.clear();for(const s of e)s.aibotSessionId&&this.bindings.set(s.aibotSessionId,{...s,modeId:a(s.modeId),effort:g(s.effort),dshProviderId:typeof s.dshProviderId=="string"&&s.dshProviderId.trim()?s.dshProviderId.trim():void 0,dshModelId:typeof s.dshModelId=="string"&&s.dshModelId.trim()?s.dshModelId.trim():void 0,dshModeId:s.dshModeId===void 0?void 0:s.dshModeId==="full_auto"?"full_auto":"approval",dshThinking:s.dshThinking==="disabled"?"disabled":s.dshThinking==="enabled"?"enabled":void 0,dshReasoningEffort:s.dshReasoningEffort==="max"?"max":s.dshReasoningEffort==="high"?"high":void 0,dshMaxTokens:Number.isSafeInteger(s.dshMaxTokens)&&Number(s.dshMaxTokens)>0?Number(s.dshMaxTokens):void 0,dshAgentPreset:typeof s.dshAgentPreset=="string"&&s.dshAgentPreset.trim()?s.dshAgentPreset.trim():void 0,dshPluginIds:r(s.dshPluginIds),dshSkillIds:r(s.dshSkillIds),dshSettingsRevision:s.dshSettingsRevision===void 0?void 0:Number.isSafeInteger(s.dshSettingsRevision)&&Number(s.dshSettingsRevision)>=0?Number(s.dshSettingsRevision):0,dshProfileName:typeof s.dshProfileName=="string"&&s.dshProfileName.trim()?s.dshProfileName.trim():void 0,dshProfileSessionId:typeof s.dshProfileSessionId=="string"&&s.dshProfileSessionId.trim()?s.dshProfileSessionId.trim():void 0,dshProfileSessionCreated:s.dshProfileSessionCreated===!0,dshProfileEventCursor:Number.isSafeInteger(s.dshProfileEventCursor)&&Number(s.dshProfileEventCursor)>=0?Number(s.dshProfileEventCursor):0})}set(t,e,d){const s=this.bindings.get(t),i=a(d?.modeId??s?.modeId),n=e!==void 0?e:s?.cwd;this.bindings.set(t,{aibotSessionId:t,cwd:n,acpSessionId:s?.acpSessionId,claudeSessionId:s?.claudeSessionId,codexThreadId:s?.codexThreadId,codexModelId:s?.codexModelId,codexModeId:s?.codexModeId,codewhaleThreadId:s?.codewhaleThreadId,agyConversationId:s?.agyConversationId,codexReasoningEffort:s?.codexReasoningEffort,codexServiceTier:s?.codexServiceTier,codexSandboxMode:s?.codexSandboxMode,piSessionPath:s?.piSessionPath,modeId:i,modelId:s?.modelId,effort:s?.effort,cursorModeId:s?.cursorModeId,acpModelId:s?.acpModelId,acpModeId:s?.acpModeId,dshProviderId:s?.dshProviderId,dshModelId:s?.dshModelId,dshModeId:s?.dshModeId,dshThinking:s?.dshThinking,dshReasoningEffort:s?.dshReasoningEffort,dshMaxTokens:s?.dshMaxTokens,dshAgentPreset:s?.dshAgentPreset,dshPluginIds:s?.dshPluginIds,dshSkillIds:s?.dshSkillIds,dshSettingsRevision:s?.dshSettingsRevision,dshSettingsUpdatedAt:s?.dshSettingsUpdatedAt,dshProfileName:s?.dshProfileName,dshProfileSessionId:s?.dshProfileSessionId,dshProfileSessionCreated:s?.dshProfileSessionCreated,dshProfileEventCursor:s?.dshProfileEventCursor,updatedAt:Date.now()}),this.scheduleWrite()}setAcpSessionId(t,e){this.updateBinding(t,{acpSessionId:e})}setClaudeSessionId(t,e){this.updateBinding(t,{claudeSessionId:e})}getClaudeSessionId(t){return this.bindings.get(t)?.claudeSessionId}setCodexThreadId(t,e){this.updateBinding(t,{codexThreadId:e})}getCodexThreadId(t){return this.bindings.get(t)?.codexThreadId}setAgyConversationId(t,e){this.updateBinding(t,{agyConversationId:e})}getAgyConversationId(t){return this.bindings.get(t)?.agyConversationId}setCodexContext(t,e){this.updateBinding(t,{codexModelId:e.modelId,codexModeId:e.modeId,codexReasoningEffort:e.reasoningEffort,codexServiceTier:e.serviceTier,codexSandboxMode:e.sandboxMode})}getCodexModelId(t){return this.bindings.get(t)?.codexModelId}setCodexModelId(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e??"").trim();!s||d.codexModelId===s||(this.bindings.set(t,{...d,codexModelId:s,updatedAt:Date.now()}),this.scheduleWrite())}setCodexModeId(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e??"").trim();!s||d.codexModeId===s||(this.bindings.set(t,{...d,codexModeId:s,updatedAt:Date.now()}),this.scheduleWrite())}setCodexServiceTier(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e??"").trim();!s||d.codexServiceTier===s||(this.bindings.set(t,{...d,codexServiceTier:s,updatedAt:Date.now()}),this.scheduleWrite())}getCodexModeId(t){return this.bindings.get(t)?.codexModeId}getCodexReasoningEffort(t){return this.bindings.get(t)?.codexReasoningEffort}getCodexServiceTier(t){return this.bindings.get(t)?.codexServiceTier}getCodexSandboxMode(t){return this.bindings.get(t)?.codexSandboxMode}setPiSessionPath(t,e){this.updateBinding(t,{piSessionPath:e})}getPiSessionPath(t){return this.bindings.get(t)?.piSessionPath}setCodeWhaleThreadId(t,e){this.updateBinding(t,{codewhaleThreadId:e})}getCodeWhaleThreadId(t){return this.bindings.get(t)?.codewhaleThreadId}setModeId(t,e){const d=this.bindings.get(t);if(!d)return;const s=a(e);d.modeId!==s&&(this.bindings.set(t,{...d,modeId:s,updatedAt:Date.now()}),this.scheduleWrite())}ensureModeId(t,e=x){const d=this.bindings.get(t);d&&(d.modeId||(this.bindings.set(t,{...d,modeId:a(e),updatedAt:Date.now()}),this.scheduleWrite()))}getAcpSessionId(t){return this.bindings.get(t)?.acpSessionId}getModeId(t){const e=this.bindings.get(t)?.modeId;return e?a(e):void 0}setModelId(t,e){const d=this.bindings.get(t);if(!d)return;const s=e.trim();d.modelId!==s&&(this.bindings.set(t,{...d,modelId:s,updatedAt:Date.now()}),this.scheduleWrite())}getModelId(t){return this.bindings.get(t)?.modelId}setEffort(t,e){const d=this.bindings.get(t);if(!d)return;const s=g(e);s&&d.effort!==s&&(this.bindings.set(t,{...d,effort:s,updatedAt:Date.now()}),this.scheduleWrite())}getEffort(t){return g(this.bindings.get(t)?.effort)}setCursorModeId(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e??"").trim().toLowerCase(),i=s===""?void 0:s;d.cursorModeId!==i&&(this.bindings.set(t,{...d,cursorModeId:i,updatedAt:Date.now()}),this.scheduleWrite())}getCursorModeId(t){return this.bindings.get(t)?.cursorModeId}setAcpModelId(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e??"").trim(),i=s===""?void 0:s;d.acpModelId!==i&&(this.bindings.set(t,{...d,acpModelId:i,updatedAt:Date.now()}),this.scheduleWrite())}getAcpModelId(t){return this.bindings.get(t)?.acpModelId}setAcpModeId(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e??"").trim(),i=s===""?void 0:s;d.acpModeId!==i&&(this.bindings.set(t,{...d,acpModeId:i,updatedAt:Date.now()}),this.scheduleWrite())}getAcpModeId(t){return this.bindings.get(t)?.acpModeId}getDshSettings(t){const e=this.bindings.get(t);if(e)return{...e.dshProviderId?{providerId:e.dshProviderId}:{},...e.dshModelId?{modelId:e.dshModelId}:{},modeId:e.dshModeId==="full_auto"?"full_auto":"approval",...e.dshThinking?{thinking:e.dshThinking}:{},...e.dshReasoningEffort?{reasoningEffort:e.dshReasoningEffort}:{},...e.dshMaxTokens?{maxTokens:e.dshMaxTokens}:{},...e.dshAgentPreset?{agentPreset:e.dshAgentPreset}:{},pluginIds:r(e.dshPluginIds),skillIds:r(e.dshSkillIds),revision:e.dshSettingsRevision??0,...e.dshSettingsUpdatedAt?{updatedAt:e.dshSettingsUpdatedAt}:{}}}updateDshSettings(t,e){const d=this.bindings.get(t);if(!d)return;const s=Object.prototype.hasOwnProperty.call(e,"providerId")?String(e.providerId??"").trim()||void 0:d.dshProviderId,i=Object.prototype.hasOwnProperty.call(e,"modelId")?String(e.modelId??"").trim()||void 0:d.dshModelId,n=Object.prototype.hasOwnProperty.call(e,"modeId")?e.modeId==="full_auto"?"full_auto":"approval":d.dshModeId,o=Object.prototype.hasOwnProperty.call(e,"thinking")?e.thinking==="disabled"?"disabled":"enabled":d.dshThinking,c=Object.prototype.hasOwnProperty.call(e,"reasoningEffort")?e.reasoningEffort==="max"?"max":"high":d.dshReasoningEffort,I=Object.prototype.hasOwnProperty.call(e,"maxTokens")?Number.isSafeInteger(e.maxTokens)&&Number(e.maxTokens)>0?Number(e.maxTokens):void 0:d.dshMaxTokens;if(s===d.dshProviderId&&i===d.dshModelId&&n===d.dshModeId&&o===d.dshThinking&&c===d.dshReasoningEffort&&I===d.dshMaxTokens)return d.dshSettingsRevision??0;const P=Date.now(),m=(d.dshSettingsRevision??0)+1;return this.bindings.set(t,{...d,dshProviderId:s,dshModelId:i,dshModeId:n,dshThinking:o,dshReasoningEffort:c,dshMaxTokens:I,dshSettingsRevision:m,dshSettingsUpdatedAt:P,updatedAt:P}),this.scheduleWrite(),m}getDshSelectedProfile(t){const e=this.bindings.get(t)?.dshProfileName;return typeof e=="string"&&e.trim()?e.trim():void 0}isDshProfileLocked(t){return this.bindings.get(t)?.dshProfileSessionCreated===!0}setDshSelectedProfile(t,e){const d=this.bindings.get(t);if(!d)return!1;const s=String(e??"").trim();return s?d.dshProfileName===s?!0:d.dshProfileSessionCreated===!0?!1:(this.bindings.set(t,{...d,dshProfileName:s,dshProfileSessionId:void 0,dshProfileSessionCreated:!1,dshProfileEventCursor:0,updatedAt:Date.now()}),this.scheduleWrite(),!0):!1}getDshAgentPreset(t){const e=this.bindings.get(t)?.dshAgentPreset;return typeof e=="string"&&e.trim()?e.trim():void 0}isDshAgentPresetLocked(t){return this.bindings.get(t)?.dshProfileSessionCreated===!0}setDshAgentPreset(t,e){const d=this.bindings.get(t);if(!d||d.dshProfileSessionCreated===!0)return!1;const s=String(e??"").trim();return!s||d.dshAgentPreset===s?d.dshAgentPreset===s:(this.bindings.set(t,{...d,dshAgentPreset:s,updatedAt:Date.now()}),this.scheduleWrite(),!0)}getDshEnabledPlugins(t){return r(this.bindings.get(t)?.dshPluginIds)}setDshEnabledPlugins(t,e){const d=this.bindings.get(t);if(!d)return;const s=r(e),i=r(d.dshPluginIds);if(p(i,s))return d.dshSettingsRevision??0;const n=Date.now(),o=(d.dshSettingsRevision??0)+1;return this.bindings.set(t,{...d,dshPluginIds:s,dshSettingsRevision:o,dshSettingsUpdatedAt:n,updatedAt:n}),this.scheduleWrite(),o}getDshEnabledSkills(t){return r(this.bindings.get(t)?.dshSkillIds)}setDshEnabledSkills(t,e){const d=this.bindings.get(t);if(!d)return;const s=r(e),i=r(d.dshSkillIds);if(p(i,s))return d.dshSettingsRevision??0;const n=Date.now(),o=(d.dshSettingsRevision??0)+1;return this.bindings.set(t,{...d,dshSkillIds:s,dshSettingsRevision:o,dshSettingsUpdatedAt:n,updatedAt:n}),this.scheduleWrite(),o}getDshProfileBinding(t,e){const d=this.bindings.get(t);if(!(!d?.dshProfileSessionId||d.dshProfileName!==e))return{profileName:e,sessionId:d.dshProfileSessionId,sessionCreated:d.dshProfileSessionCreated===!0,eventCursor:d.dshProfileEventCursor??0}}setDshProfileBinding(t,e){const d=this.bindings.get(t);if(!d)return;const s=String(e.profileName).trim(),i=String(e.sessionId).trim();if(!s||!i)return;const n=Number.isSafeInteger(e.eventCursor)&&e.eventCursor>=0?e.eventCursor:0;d.dshProfileName===s&&d.dshProfileSessionId===i&&d.dshProfileSessionCreated===e.sessionCreated&&(d.dshProfileEventCursor??0)===n||(this.bindings.set(t,{...d,dshProfileName:s,dshProfileSessionId:i,dshProfileSessionCreated:e.sessionCreated,dshProfileEventCursor:n,updatedAt:Date.now()}),this.scheduleWrite())}get(t){return this.bindings.get(t)}getMostRecentlyUpdatedSessionId(t){const e=t?.requireCwd!==!1;let d,s=-1;for(const i of this.bindings.values())e&&!String(i.cwd??"").trim()||i.updatedAt>s&&(s=i.updatedAt,d=i.aibotSessionId);return d}delete(t){const e=this.bindings.get(t);e&&(l.info("session-binding-store",`delete binding session_id=${t} cwd=${e.cwd??""} codexThreadId=${e.codexThreadId??""}`),this.bindings.delete(t),this.scheduleWrite())}quarantineUnreadablePrimary(){if(!this.filePath||!f(this.filePath))return;const t=`${this.filePath}.corrupt.${Date.now()}`;try{return y(this.filePath,t),l.error("session-binding-store",`Copied unreadable primary bindings to ${t} (original retained to block legacy clobber)`),t}catch(e){l.error("session-binding-store",`Failed to copy unreadable primary ${this.filePath}: ${e instanceof Error?e.message:String(e)}`);return}}entries(){return this.bindings.entries()}async flush(){await this.writePromise}scheduleWrite(){this.filePath&&(this.writePromise=this.writePromise.then(()=>this.write()).catch(t=>{l.error("session-binding-store",`Persist failed: ${t instanceof Error?t.message:t}`)}))}async write(){if(!this.filePath)return;const t=Array.from(this.bindings.values());await b(this.filePath,t)}writeMigratedSnapshot(t){if(!this.filePath)return;const e=`${this.filePath}.${A()}.migration.tmp`;try{C(e,`${JSON.stringify(t,null,2)}
2
- `,{encoding:"utf8",mode:384,flag:"wx"}),v(e,this.filePath);try{M(this.filePath,384)}catch{}}catch(d){if(f(e))try{w(e)}catch{}throw new Error(`Failed to migrate legacy session bindings from ${this.legacyFilePath} to ${this.filePath}: ${d instanceof Error?d.message:String(d)}`)}}updateBinding(t,e){const d=this.bindings.get(t),s={aibotSessionId:t,acpSessionId:Object.prototype.hasOwnProperty.call(e,"acpSessionId")?e.acpSessionId:d?.acpSessionId,claudeSessionId:Object.prototype.hasOwnProperty.call(e,"claudeSessionId")?e.claudeSessionId:d?.claudeSessionId,codexThreadId:Object.prototype.hasOwnProperty.call(e,"codexThreadId")?e.codexThreadId:d?.codexThreadId,codexModelId:Object.prototype.hasOwnProperty.call(e,"codexModelId")?e.codexModelId:d?.codexModelId,codexModeId:Object.prototype.hasOwnProperty.call(e,"codexModeId")?e.codexModeId:d?.codexModeId,codewhaleThreadId:Object.prototype.hasOwnProperty.call(e,"codewhaleThreadId")?e.codewhaleThreadId:d?.codewhaleThreadId,agyConversationId:Object.prototype.hasOwnProperty.call(e,"agyConversationId")?e.agyConversationId:d?.agyConversationId,codexReasoningEffort:Object.prototype.hasOwnProperty.call(e,"codexReasoningEffort")?e.codexReasoningEffort:d?.codexReasoningEffort,codexServiceTier:Object.prototype.hasOwnProperty.call(e,"codexServiceTier")?e.codexServiceTier:d?.codexServiceTier,codexSandboxMode:Object.prototype.hasOwnProperty.call(e,"codexSandboxMode")?e.codexSandboxMode:d?.codexSandboxMode,piSessionPath:Object.prototype.hasOwnProperty.call(e,"piSessionPath")?e.piSessionPath:d?.piSessionPath,cwd:d?.cwd,modeId:a(d?.modeId),modelId:d?.modelId,effort:Object.prototype.hasOwnProperty.call(e,"effort")?g(e.effort):g(d?.effort),cursorModeId:d?.cursorModeId,acpModelId:d?.acpModelId,acpModeId:d?.acpModeId,dshProviderId:d?.dshProviderId,dshModelId:d?.dshModelId,dshModeId:d?.dshModeId,dshMaxTokens:d?.dshMaxTokens,dshAgentPreset:d?.dshAgentPreset,dshPluginIds:d?.dshPluginIds,dshSkillIds:d?.dshSkillIds,dshSettingsRevision:d?.dshSettingsRevision,dshSettingsUpdatedAt:d?.dshSettingsUpdatedAt,dshProfileName:d?.dshProfileName,dshProfileSessionId:d?.dshProfileSessionId,dshProfileSessionCreated:d?.dshProfileSessionCreated,dshProfileEventCursor:d?.dshProfileEventCursor,updatedAt:Date.now()};this.bindings.set(t,s),this.scheduleWrite()}}function r(h){const t=new Set,e=[];for(const d of h??[]){const s=String(d??"").trim();!s||t.has(s)||(t.add(s),e.push(s))}return e}function p(h,t){return h.length===t.length&&h.every((e,d)=>e===t[d])}export{N as SessionBindingStore};
1
+ import{readJSONFile as x,writeJSONFileAtomic as b}from"../util/json-file.js";import{log as l}from"../log/index.js";import{SESSION_MODE_IDS as u}from"../../adapter/claude/protocol-contract.js";import{normalizeClaudeEffort as g}from"../config/claude-direct-env.js";import{chmodSync as M,copyFileSync as y,existsSync as f,renameSync as v,rmSync as w,writeFileSync as C}from"node:fs";import{randomUUID as A}from"node:crypto";const S=u.fullAuto;function a(h){const t=String(h??"").trim().toLowerCase();return t===u.approval||t===u.fullAuto?t:S}class N{bindings=new Map;filePath;legacyFilePath;writePromise=Promise.resolve();constructor(t,e){this.filePath=t??null,this.legacyFilePath=e&&e!==t?e:null}load(){if(!this.filePath)return;const t=f(this.filePath);let e=x(this.filePath),s=!1;if(t&&!Array.isArray(e)){const i=this.quarantineUnreadablePrimary();throw new Error(`Refusing to start with unreadable session bindings: primary=${this.filePath}`+(i?` quarantined=${i}`:"")+(this.legacyFilePath?` legacy=${this.legacyFilePath}`:"")+" (legacy fallback disabled to avoid clobbering newer bindings)")}if(!t&&this.legacyFilePath){s=f(this.legacyFilePath);const i=x(this.legacyFilePath);Array.isArray(i)&&(this.writeMigratedSnapshot(i),e=i,l.info("session-binding-store",`Migrated legacy bindings from ${this.legacyFilePath} to ${this.filePath}; legacy file retained`))}if(!Array.isArray(e)){if(t||s)throw new Error(`Refusing to start with unreadable session bindings: primary=${this.filePath}${this.legacyFilePath?` legacy=${this.legacyFilePath}`:""}`);return}this.bindings.clear();for(const i of e)i.aibotSessionId&&this.bindings.set(i.aibotSessionId,{...i,modeId:a(i.modeId),effort:g(i.effort),dshProviderId:typeof i.dshProviderId=="string"&&i.dshProviderId.trim()?i.dshProviderId.trim():void 0,dshModelId:typeof i.dshModelId=="string"&&i.dshModelId.trim()?i.dshModelId.trim():void 0,dshModeId:i.dshModeId===void 0?void 0:i.dshModeId==="full_auto"?"full_auto":"approval",dshThinking:i.dshThinking==="disabled"?"disabled":i.dshThinking==="enabled"?"enabled":void 0,dshReasoningEffort:i.dshReasoningEffort==="max"?"max":i.dshReasoningEffort==="high"?"high":void 0,dshMaxTokens:Number.isSafeInteger(i.dshMaxTokens)&&Number(i.dshMaxTokens)>0?Number(i.dshMaxTokens):void 0,dshAgentPreset:typeof i.dshAgentPreset=="string"&&i.dshAgentPreset.trim()?i.dshAgentPreset.trim():void 0,dshPluginIds:r(i.dshPluginIds),dshSkillIds:r(i.dshSkillIds),dshSettingsRevision:i.dshSettingsRevision===void 0?void 0:Number.isSafeInteger(i.dshSettingsRevision)&&Number(i.dshSettingsRevision)>=0?Number(i.dshSettingsRevision):0,dshProfileName:typeof i.dshProfileName=="string"&&i.dshProfileName.trim()?i.dshProfileName.trim():void 0,dshProfileSessionId:typeof i.dshProfileSessionId=="string"&&i.dshProfileSessionId.trim()?i.dshProfileSessionId.trim():void 0,dshProfileSessionCreated:i.dshProfileSessionCreated===!0,dshProfileEventCursor:Number.isSafeInteger(i.dshProfileEventCursor)&&Number(i.dshProfileEventCursor)>=0?Number(i.dshProfileEventCursor):0})}set(t,e,s){const i=this.bindings.get(t),d=a(s?.modeId??i?.modeId),n=e!==void 0?e:i?.cwd;this.bindings.set(t,{aibotSessionId:t,cwd:n,acpSessionId:i?.acpSessionId,claudeSessionId:i?.claudeSessionId,codexThreadId:i?.codexThreadId,codexModelId:i?.codexModelId,codexModeId:i?.codexModeId,codewhaleThreadId:i?.codewhaleThreadId,agyConversationId:i?.agyConversationId,codexReasoningEffort:i?.codexReasoningEffort,codexServiceTier:i?.codexServiceTier,codexSandboxMode:i?.codexSandboxMode,piSessionPath:i?.piSessionPath,modeId:d,modelId:i?.modelId,effort:i?.effort,cursorModeId:i?.cursorModeId,acpModelId:i?.acpModelId,acpModeId:i?.acpModeId,dshProviderId:i?.dshProviderId,dshModelId:i?.dshModelId,dshModeId:i?.dshModeId,dshThinking:i?.dshThinking,dshReasoningEffort:i?.dshReasoningEffort,dshMaxTokens:i?.dshMaxTokens,dshAgentPreset:i?.dshAgentPreset,dshPluginIds:i?.dshPluginIds,dshSkillIds:i?.dshSkillIds,dshSettingsRevision:i?.dshSettingsRevision,dshSettingsUpdatedAt:i?.dshSettingsUpdatedAt,dshProfileName:i?.dshProfileName,dshProfileSessionId:i?.dshProfileSessionId,dshProfileSessionCreated:i?.dshProfileSessionCreated,dshProfileEventCursor:i?.dshProfileEventCursor,updatedAt:Date.now()}),this.scheduleWrite()}setAcpSessionId(t,e){this.updateBinding(t,{acpSessionId:e})}setClaudeSessionId(t,e){this.updateBinding(t,{claudeSessionId:e})}getClaudeSessionId(t){return this.bindings.get(t)?.claudeSessionId}setCodexThreadId(t,e){this.updateBinding(t,{codexThreadId:e})}getCodexThreadId(t){return this.bindings.get(t)?.codexThreadId}setAgyConversationId(t,e){this.updateBinding(t,{agyConversationId:e})}getAgyConversationId(t){return this.bindings.get(t)?.agyConversationId}setCodexContext(t,e){this.updateBinding(t,{codexModelId:e.modelId,codexModeId:e.modeId,codexReasoningEffort:e.reasoningEffort,codexServiceTier:e.serviceTier,codexSandboxMode:e.sandboxMode})}getCodexModelId(t){return this.bindings.get(t)?.codexModelId}setCodexModelId(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim();!i||s.codexModelId===i||(this.bindings.set(t,{...s,codexModelId:i,updatedAt:Date.now()}),this.scheduleWrite())}setCodexModeId(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim();!i||s.codexModeId===i||(this.bindings.set(t,{...s,codexModeId:i,updatedAt:Date.now()}),this.scheduleWrite())}setCodexServiceTier(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim();!i||s.codexServiceTier===i||(this.bindings.set(t,{...s,codexServiceTier:i,updatedAt:Date.now()}),this.scheduleWrite())}setCodexReasoningEffort(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim();!i||s.codexReasoningEffort===i||(this.bindings.set(t,{...s,codexReasoningEffort:i,updatedAt:Date.now()}),this.scheduleWrite())}setCodexSandboxMode(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim();!i||s.codexSandboxMode===i||(this.bindings.set(t,{...s,codexSandboxMode:i,updatedAt:Date.now()}),this.scheduleWrite())}getCodexModeId(t){return this.bindings.get(t)?.codexModeId}getCodexReasoningEffort(t){return this.bindings.get(t)?.codexReasoningEffort}getCodexServiceTier(t){return this.bindings.get(t)?.codexServiceTier}getCodexSandboxMode(t){return this.bindings.get(t)?.codexSandboxMode}setPiSessionPath(t,e){this.updateBinding(t,{piSessionPath:e})}getPiSessionPath(t){return this.bindings.get(t)?.piSessionPath}setCodeWhaleThreadId(t,e){this.updateBinding(t,{codewhaleThreadId:e})}getCodeWhaleThreadId(t){return this.bindings.get(t)?.codewhaleThreadId}setModeId(t,e){const s=this.bindings.get(t);if(!s)return;const i=a(e);s.modeId!==i&&(this.bindings.set(t,{...s,modeId:i,updatedAt:Date.now()}),this.scheduleWrite())}ensureModeId(t,e=S){const s=this.bindings.get(t);s&&(s.modeId||(this.bindings.set(t,{...s,modeId:a(e),updatedAt:Date.now()}),this.scheduleWrite()))}getAcpSessionId(t){return this.bindings.get(t)?.acpSessionId}getModeId(t){const e=this.bindings.get(t)?.modeId;return e?a(e):void 0}setModelId(t,e){const s=this.bindings.get(t);if(!s)return;const i=e.trim();s.modelId!==i&&(this.bindings.set(t,{...s,modelId:i,updatedAt:Date.now()}),this.scheduleWrite())}getModelId(t){return this.bindings.get(t)?.modelId}setEffort(t,e){const s=this.bindings.get(t);if(!s)return;const i=g(e);i&&s.effort!==i&&(this.bindings.set(t,{...s,effort:i,updatedAt:Date.now()}),this.scheduleWrite())}getEffort(t){return g(this.bindings.get(t)?.effort)}setCursorModeId(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim().toLowerCase(),d=i===""?void 0:i;s.cursorModeId!==d&&(this.bindings.set(t,{...s,cursorModeId:d,updatedAt:Date.now()}),this.scheduleWrite())}getCursorModeId(t){return this.bindings.get(t)?.cursorModeId}setAcpModelId(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim(),d=i===""?void 0:i;s.acpModelId!==d&&(this.bindings.set(t,{...s,acpModelId:d,updatedAt:Date.now()}),this.scheduleWrite())}getAcpModelId(t){return this.bindings.get(t)?.acpModelId}setAcpModeId(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e??"").trim(),d=i===""?void 0:i;s.acpModeId!==d&&(this.bindings.set(t,{...s,acpModeId:d,updatedAt:Date.now()}),this.scheduleWrite())}getAcpModeId(t){return this.bindings.get(t)?.acpModeId}getDshSettings(t){const e=this.bindings.get(t);if(e)return{...e.dshProviderId?{providerId:e.dshProviderId}:{},...e.dshModelId?{modelId:e.dshModelId}:{},modeId:e.dshModeId==="full_auto"?"full_auto":"approval",...e.dshThinking?{thinking:e.dshThinking}:{},...e.dshReasoningEffort?{reasoningEffort:e.dshReasoningEffort}:{},...e.dshMaxTokens?{maxTokens:e.dshMaxTokens}:{},...e.dshAgentPreset?{agentPreset:e.dshAgentPreset}:{},pluginIds:r(e.dshPluginIds),skillIds:r(e.dshSkillIds),revision:e.dshSettingsRevision??0,...e.dshSettingsUpdatedAt?{updatedAt:e.dshSettingsUpdatedAt}:{}}}updateDshSettings(t,e){const s=this.bindings.get(t);if(!s)return;const i=Object.prototype.hasOwnProperty.call(e,"providerId")?String(e.providerId??"").trim()||void 0:s.dshProviderId,d=Object.prototype.hasOwnProperty.call(e,"modelId")?String(e.modelId??"").trim()||void 0:s.dshModelId,n=Object.prototype.hasOwnProperty.call(e,"modeId")?e.modeId==="full_auto"?"full_auto":"approval":s.dshModeId,o=Object.prototype.hasOwnProperty.call(e,"thinking")?e.thinking==="disabled"?"disabled":"enabled":s.dshThinking,c=Object.prototype.hasOwnProperty.call(e,"reasoningEffort")?e.reasoningEffort==="max"?"max":"high":s.dshReasoningEffort,I=Object.prototype.hasOwnProperty.call(e,"maxTokens")?Number.isSafeInteger(e.maxTokens)&&Number(e.maxTokens)>0?Number(e.maxTokens):void 0:s.dshMaxTokens;if(i===s.dshProviderId&&d===s.dshModelId&&n===s.dshModeId&&o===s.dshThinking&&c===s.dshReasoningEffort&&I===s.dshMaxTokens)return s.dshSettingsRevision??0;const P=Date.now(),m=(s.dshSettingsRevision??0)+1;return this.bindings.set(t,{...s,dshProviderId:i,dshModelId:d,dshModeId:n,dshThinking:o,dshReasoningEffort:c,dshMaxTokens:I,dshSettingsRevision:m,dshSettingsUpdatedAt:P,updatedAt:P}),this.scheduleWrite(),m}getDshSelectedProfile(t){const e=this.bindings.get(t)?.dshProfileName;return typeof e=="string"&&e.trim()?e.trim():void 0}isDshProfileLocked(t){return this.bindings.get(t)?.dshProfileSessionCreated===!0}setDshSelectedProfile(t,e){const s=this.bindings.get(t);if(!s)return!1;const i=String(e??"").trim();return i?s.dshProfileName===i?!0:s.dshProfileSessionCreated===!0?!1:(this.bindings.set(t,{...s,dshProfileName:i,dshProfileSessionId:void 0,dshProfileSessionCreated:!1,dshProfileEventCursor:0,updatedAt:Date.now()}),this.scheduleWrite(),!0):!1}getDshAgentPreset(t){const e=this.bindings.get(t)?.dshAgentPreset;return typeof e=="string"&&e.trim()?e.trim():void 0}isDshAgentPresetLocked(t){return this.bindings.get(t)?.dshProfileSessionCreated===!0}setDshAgentPreset(t,e){const s=this.bindings.get(t);if(!s||s.dshProfileSessionCreated===!0)return!1;const i=String(e??"").trim();return!i||s.dshAgentPreset===i?s.dshAgentPreset===i:(this.bindings.set(t,{...s,dshAgentPreset:i,updatedAt:Date.now()}),this.scheduleWrite(),!0)}getDshEnabledPlugins(t){return r(this.bindings.get(t)?.dshPluginIds)}setDshEnabledPlugins(t,e){const s=this.bindings.get(t);if(!s)return;const i=r(e),d=r(s.dshPluginIds);if(p(d,i))return s.dshSettingsRevision??0;const n=Date.now(),o=(s.dshSettingsRevision??0)+1;return this.bindings.set(t,{...s,dshPluginIds:i,dshSettingsRevision:o,dshSettingsUpdatedAt:n,updatedAt:n}),this.scheduleWrite(),o}getDshEnabledSkills(t){return r(this.bindings.get(t)?.dshSkillIds)}setDshEnabledSkills(t,e){const s=this.bindings.get(t);if(!s)return;const i=r(e),d=r(s.dshSkillIds);if(p(d,i))return s.dshSettingsRevision??0;const n=Date.now(),o=(s.dshSettingsRevision??0)+1;return this.bindings.set(t,{...s,dshSkillIds:i,dshSettingsRevision:o,dshSettingsUpdatedAt:n,updatedAt:n}),this.scheduleWrite(),o}getDshProfileBinding(t,e){const s=this.bindings.get(t);if(!(!s?.dshProfileSessionId||s.dshProfileName!==e))return{profileName:e,sessionId:s.dshProfileSessionId,sessionCreated:s.dshProfileSessionCreated===!0,eventCursor:s.dshProfileEventCursor??0}}setDshProfileBinding(t,e){const s=this.bindings.get(t);if(!s)return;const i=String(e.profileName).trim(),d=String(e.sessionId).trim();if(!i||!d)return;const n=Number.isSafeInteger(e.eventCursor)&&e.eventCursor>=0?e.eventCursor:0;s.dshProfileName===i&&s.dshProfileSessionId===d&&s.dshProfileSessionCreated===e.sessionCreated&&(s.dshProfileEventCursor??0)===n||(this.bindings.set(t,{...s,dshProfileName:i,dshProfileSessionId:d,dshProfileSessionCreated:e.sessionCreated,dshProfileEventCursor:n,updatedAt:Date.now()}),this.scheduleWrite())}get(t){return this.bindings.get(t)}getMostRecentlyUpdatedSessionId(t){const e=t?.requireCwd!==!1;let s,i=-1;for(const d of this.bindings.values())e&&!String(d.cwd??"").trim()||d.updatedAt>i&&(i=d.updatedAt,s=d.aibotSessionId);return s}delete(t){const e=this.bindings.get(t);e&&(l.info("session-binding-store",`delete binding session_id=${t} cwd=${e.cwd??""} codexThreadId=${e.codexThreadId??""}`),this.bindings.delete(t),this.scheduleWrite())}quarantineUnreadablePrimary(){if(!this.filePath||!f(this.filePath))return;const t=`${this.filePath}.corrupt.${Date.now()}`;try{return y(this.filePath,t),l.error("session-binding-store",`Copied unreadable primary bindings to ${t} (original retained to block legacy clobber)`),t}catch(e){l.error("session-binding-store",`Failed to copy unreadable primary ${this.filePath}: ${e instanceof Error?e.message:String(e)}`);return}}entries(){return this.bindings.entries()}async flush(){await this.writePromise}scheduleWrite(){this.filePath&&(this.writePromise=this.writePromise.then(()=>this.write()).catch(t=>{l.error("session-binding-store",`Persist failed: ${t instanceof Error?t.message:t}`)}))}async write(){if(!this.filePath)return;const t=Array.from(this.bindings.values());await b(this.filePath,t)}writeMigratedSnapshot(t){if(!this.filePath)return;const e=`${this.filePath}.${A()}.migration.tmp`;try{C(e,`${JSON.stringify(t,null,2)}
2
+ `,{encoding:"utf8",mode:384,flag:"wx"}),v(e,this.filePath);try{M(this.filePath,384)}catch{}}catch(s){if(f(e))try{w(e)}catch{}throw new Error(`Failed to migrate legacy session bindings from ${this.legacyFilePath} to ${this.filePath}: ${s instanceof Error?s.message:String(s)}`)}}updateBinding(t,e){const s=this.bindings.get(t),i={aibotSessionId:t,acpSessionId:Object.prototype.hasOwnProperty.call(e,"acpSessionId")?e.acpSessionId:s?.acpSessionId,claudeSessionId:Object.prototype.hasOwnProperty.call(e,"claudeSessionId")?e.claudeSessionId:s?.claudeSessionId,codexThreadId:Object.prototype.hasOwnProperty.call(e,"codexThreadId")?e.codexThreadId:s?.codexThreadId,codexModelId:Object.prototype.hasOwnProperty.call(e,"codexModelId")?e.codexModelId:s?.codexModelId,codexModeId:Object.prototype.hasOwnProperty.call(e,"codexModeId")?e.codexModeId:s?.codexModeId,codewhaleThreadId:Object.prototype.hasOwnProperty.call(e,"codewhaleThreadId")?e.codewhaleThreadId:s?.codewhaleThreadId,agyConversationId:Object.prototype.hasOwnProperty.call(e,"agyConversationId")?e.agyConversationId:s?.agyConversationId,codexReasoningEffort:Object.prototype.hasOwnProperty.call(e,"codexReasoningEffort")?e.codexReasoningEffort:s?.codexReasoningEffort,codexServiceTier:Object.prototype.hasOwnProperty.call(e,"codexServiceTier")?e.codexServiceTier:s?.codexServiceTier,codexSandboxMode:Object.prototype.hasOwnProperty.call(e,"codexSandboxMode")?e.codexSandboxMode:s?.codexSandboxMode,piSessionPath:Object.prototype.hasOwnProperty.call(e,"piSessionPath")?e.piSessionPath:s?.piSessionPath,cwd:s?.cwd,modeId:a(s?.modeId),modelId:s?.modelId,effort:Object.prototype.hasOwnProperty.call(e,"effort")?g(e.effort):g(s?.effort),cursorModeId:s?.cursorModeId,acpModelId:s?.acpModelId,acpModeId:s?.acpModeId,dshProviderId:s?.dshProviderId,dshModelId:s?.dshModelId,dshModeId:s?.dshModeId,dshMaxTokens:s?.dshMaxTokens,dshAgentPreset:s?.dshAgentPreset,dshPluginIds:s?.dshPluginIds,dshSkillIds:s?.dshSkillIds,dshSettingsRevision:s?.dshSettingsRevision,dshSettingsUpdatedAt:s?.dshSettingsUpdatedAt,dshProfileName:s?.dshProfileName,dshProfileSessionId:s?.dshProfileSessionId,dshProfileSessionCreated:s?.dshProfileSessionCreated,dshProfileEventCursor:s?.dshProfileEventCursor,updatedAt:Date.now()};this.bindings.set(t,i),this.scheduleWrite()}}function r(h){const t=new Set,e=[];for(const s of h??[]){const i=String(s??"").trim();!i||t.has(i)||(t.add(i),e.push(i))}return e}function p(h,t){return h.length===t.length&&h.every((e,s)=>e===t[s])}export{N as SessionBindingStore};
package/dist/log.js CHANGED
@@ -1,3 +1,3 @@
1
- import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as t}from"node:path";import{homedir as m}from"node:os";const i=t(m(),".grix"),s={base:i,config:t(i,"config"),log:t(i,"log"),data:t(i,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=t(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...n){const e=`${c()} [${o}] ${r}${n.length?" "+n.map(String).join(" "):""}`;console.log(e),a?.write(e+`
2
- `)},error(o,r,...n){const e=`${c()} [${o}] ERROR ${r}${n.length?" "+n.map(String).join(" "):""}`;console.error(e),a?.write(e+`
1
+ import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as i}from"node:path";import{homedir as m}from"node:os";const n=i(m(),".grix"),s={base:n,config:i(n,"config"),log:i(n,"log"),data:i(n,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=i(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...t){const e=`${c()} [${o}] ${r}${t.length?" "+t.map(String).join(" "):""}`;console.log(e),a?.write(e+`
2
+ `)},error(o,r,...t){const e=`${c()} [${o}] ERROR ${r}${t.length?" "+t.map(String).join(" "):""}`;console.error(e),a?.write(e+`
3
3
  `)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
@@ -1 +1 @@
1
- import*as i from"node:net";const e={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function n(o){const u={bind:o?.bind??e.bind,port:o?.port??e.port,endpoint:o?.endpoint??e.endpoint,sessionTimeoutMs:o?.sessionTimeoutMs??e.sessionTimeoutMs,invokeTimeoutMs:o?.invokeTimeoutMs??e.invokeTimeoutMs,allowedOrigins:o?.allowedOrigins,allowedHosts:o?.allowedHosts};return s(u.bind),u.port!==0&&t(u.port),r(u.sessionTimeoutMs),u}function s(o){if(!o||!i.isIPv4(o)&&!i.isIPv6(o))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${o}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function t(o){if(!Number.isInteger(o)||o<1||o>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(o){if(!Number.isInteger(o)||o<1e3||o>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{n as createDefaultGatewayConfig};
1
+ import*as n from"node:net";const i={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function s(u){const e={bind:u?.bind??i.bind,port:u?.port??i.port,endpoint:u?.endpoint??i.endpoint,sessionTimeoutMs:u?.sessionTimeoutMs??i.sessionTimeoutMs,invokeTimeoutMs:u?.invokeTimeoutMs??i.invokeTimeoutMs,allowedOrigins:u?.allowedOrigins,allowedHosts:u?.allowedHosts};return t(e.bind),e.port!==0&&o(e.port),r(e.sessionTimeoutMs),e}function t(u){if(!u||!n.isIPv4(u)&&!n.isIPv6(u))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${u}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function o(u){if(!Number.isInteger(u)||u<1||u>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(u){if(!Number.isInteger(u)||u<1e3||u>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{s as createDefaultGatewayConfig};
@@ -1 +1 @@
1
- const r=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
1
+ const a=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
@@ -1 +1 @@
1
- import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(t,e,r,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,r);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(t.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${t.status}`);if(p(e))return this.executeEventTool(t,e,r);const o=i(e,r);try{const u=await t.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(t){if(t==null||typeof t!="object")return this.successResult(t??null);const e=t,r=typeof e.code=="number"?e.code:0;if(r===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${r}]: ${n}`)}successResult(t){return{content:[{type:"text",text:JSON.stringify(t)}],isError:!1}}errorResult(t){return{content:[{type:"text",text:t}],isError:!0}}async executeEventTool(t,e,r){return e==="grix_access_control"?this.executeAccessControl(t,r):d(t,e,r)}async executeAccessControl(t,e){const r=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[r];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${r}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await t.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
1
+ import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(r,e,t,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,t);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(r.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${r.status}`);if(p(e))return this.executeEventTool(r,e,t);const o=i(e,t);try{const u=await r.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(r){if(r==null||typeof r!="object")return this.successResult(r??null);const e=r,t=typeof e.code=="number"?e.code:0;if(t===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${t}]: ${n}`)}successResult(r){return{content:[{type:"text",text:JSON.stringify(r)}],isError:!1}}errorResult(r){return{content:[{type:"text",text:r}],isError:!0}}async executeEventTool(r,e,t){return e==="grix_access_control"?this.executeAccessControl(r,t):d(r,e,t)}async executeAccessControl(r,e){const t=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[t];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${t}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await r.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
@@ -1 +1 @@
1
- import{TOOLS as s,EVENT_TOOLS as t}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...s.filter(o=>e.has(o.name)),...t.filter(o=>r.has(o.name))],this.toolMap=new Map(this.tools.map(o=>[o.name,o]))}getTools(){return this.tools}getTool(o){return this.toolMap.get(o)}hasTool(o){return this.toolMap.has(o)}}export{a as ToolRegistryImpl};
1
+ import{TOOLS as o,EVENT_TOOLS as s}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...o.filter(t=>e.has(t.name)),...s.filter(t=>r.has(t.name))],this.toolMap=new Map(this.tools.map(t=>[t.name,t]))}getTools(){return this.tools}getTool(t){return this.toolMap.get(t)}hasTool(t){return this.toolMap.has(t)}}export{a as ToolRegistryImpl};
@@ -1 +1 @@
1
- const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(u,t){const e=C[u];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${u}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,r]of Object.entries(t)){if(r==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,r,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(u,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${u} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${u} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const r=t[i];if(e.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.enum&&!e.items.enum.includes(r))return`\u53C2\u6570 ${u}[${i}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
1
+ const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(r,t){const e=C[r];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${r}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,u]of Object.entries(t)){if(u==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,u,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(r,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${r} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${r} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${r} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${r} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${r} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${r} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const u=t[i];if(e.items.type==="string"&&typeof u!="string")return`\u53C2\u6570 ${r}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof u}`;if(e.items.type==="integer"){if(typeof u!="number"||!Number.isInteger(u))return`\u53C2\u6570 ${r}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof u}`;if(e.items.enum&&!e.items.enum.includes(u))return`\u53C2\u6570 ${r}[${i}] \u503C ${u} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "4.2.6",
3
+ "version": "4.2.7",
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",