grix-connector 3.26.3 → 3.26.4

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
- import c from"node:http";import{randomUUID as d}from"node:crypto";import{log as o}from"../../core/log/index.js";function l(t){t.writeHead(401,{"content-type":"application/json"}),t.end(JSON.stringify({error:"unauthorized"}))}function u(t){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not_found"}))}function h(t,e){t.writeHead(400,{"content-type":"application/json"}),t.end(JSON.stringify({error:e}))}function p(t,e={ok:!0}){t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify(e))}async function v(t){const e=[];for await(const r of t)e.push(r);const n=Buffer.concat(e).toString("utf8").trim();return n?JSON.parse(n):{}}function k(t){const e=(t.headers.authorization??"").trim();return e.toLowerCase().startsWith("bearer ")?e.slice(7).trim():""}class w{host="127.0.0.1";port=0;token;callbacks;server=null;address=null;constructor(e){this.token=d(),this.callbacks=e}getToken(){return this.token}getURL(){return this.address?`http://${this.address.address}:${this.address.port}`:""}async start(){this.server||(this.server=c.createServer(async(e,n)=>{try{await this.handleRequest(e,n)}catch(r){h(n,r instanceof Error?r.message:String(r))}}),await new Promise((e,n)=>{this.server.once("error",n),this.server.listen(this.port,this.host,()=>{this.server.off("error",n),e()})}),this.address=this.server.address(),o.info("claude-bridge",`Bridge server listening on ${this.getURL()}`))}async stop(){if(!this.server)return;const e=this.server;this.server=null,this.address=null,e.closeIdleConnections?.(),e.closeAllConnections?.(),await new Promise((n,r)=>{e.close(s=>s?r(s):n())})}async handleRequest(e,n){if(k(e)!==this.token){l(n);return}if(e.method!=="POST"){n.writeHead(405,{"content-type":"application/json"}),n.end(JSON.stringify({error:"method_not_allowed"}));return}const r=new URL(e.url,"http://localhost").pathname,s=await v(e),i=f.get(r);if(!i){u(n);return}const a=await i(this.callbacks,s);p(n,a??{ok:!0})}}const f=new Map([["/v1/worker/register",async(t,e)=>(o.info("claude-bridge",`Worker registered: ${e.worker_id} (pid=${e.pid})`),t.onRegisterWorker(e))],["/v1/worker/status",async(t,e)=>(o.info("claude-bridge",`Worker status: ${e.status}`),t.onStatusUpdate(e))],["/v1/worker/send-text",async(t,e)=>t.onSendText(e)],["/v1/worker/send-stream-chunk",async(t,e)=>t.onSendStreamChunk(e)],["/v1/worker/send-media",async(t,e)=>t.onSendMedia(e)],["/v1/worker/delete-message",async(t,e)=>t.onDeleteMessage(e)],["/v1/worker/ack-event",async(t,e)=>t.onAckEvent(e)],["/v1/worker/event-result",async(t,e)=>t.onSendEventResult(e)],["/v1/worker/event-stop-ack",async(t,e)=>t.onSendEventStopAck(e)],["/v1/worker/event-stop-result",async(t,e)=>t.onSendEventStopResult(e)],["/v1/worker/session-composing",async(t,e)=>t.onSetSessionComposing(e)],["/v1/worker/agent-invoke",async(t,e)=>t.onAgentInvoke(e)],["/v1/worker/local-action-result",async(t,e)=>t.onLocalActionResult(e)]]);export{w as ClaudeBridgeServer};
1
+ import c from"node:http";import{randomUUID as d}from"node:crypto";import{log as o}from"../../core/log/index.js";function l(t){t.writeHead(401,{"content-type":"application/json"}),t.end(JSON.stringify({error:"unauthorized"}))}function u(t){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not_found"}))}function h(t,e){t.writeHead(400,{"content-type":"application/json"}),t.end(JSON.stringify({error:e}))}function p(t,e={ok:!0}){t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify(e))}async function v(t){const e=[];for await(const n of t)e.push(n);const r=Buffer.concat(e).toString("utf8").trim();return r?JSON.parse(r):{}}function k(t){const e=(t.headers.authorization??"").trim();return e.toLowerCase().startsWith("bearer ")?e.slice(7).trim():""}class w{host="127.0.0.1";port=0;token;callbacks;server=null;address=null;constructor(e){this.token=d(),this.callbacks=e}getToken(){return this.token}getURL(){return this.address?`http://${this.address.address}:${this.address.port}`:""}async start(){this.server||(this.server=c.createServer(async(e,r)=>{try{await this.handleRequest(e,r)}catch(n){h(r,n instanceof Error?n.message:String(n))}}),await new Promise((e,r)=>{this.server.once("error",r),this.server.listen(this.port,this.host,()=>{this.server.off("error",r),e()})}),this.address=this.server.address(),o.info("claude-bridge",`Bridge server listening on ${this.getURL()}`))}async stop(){if(!this.server)return;const e=this.server;this.server=null,this.address=null,e.closeIdleConnections?.(),e.closeAllConnections?.(),await new Promise((r,n)=>{e.close(s=>s?n(s):r())})}async handleRequest(e,r){if(k(e)!==this.token){l(r);return}if(e.method!=="POST"){r.writeHead(405,{"content-type":"application/json"}),r.end(JSON.stringify({error:"method_not_allowed"}));return}const n=new URL(e.url,"http://localhost").pathname,s=await v(e),i=f.get(n);if(!i){u(r);return}const a=await i(this.callbacks,s);p(r,a??{ok:!0})}}const f=new Map([["/v1/worker/register",async(t,e)=>(o.info("claude-bridge",`Worker registered: ${e.worker_id} (pid=${e.pid})`),t.onRegisterWorker(e))],["/v1/worker/status",async(t,e)=>(o.info("claude-bridge",`Worker status: ${e.status}`),t.onStatusUpdate(e))],["/v1/worker/send-text",async(t,e)=>t.onSendText(e)],["/v1/worker/send-stream-chunk",async(t,e)=>t.onSendStreamChunk(e)],["/v1/worker/send-media",async(t,e)=>t.onSendMedia(e)],["/v1/worker/delete-message",async(t,e)=>t.onDeleteMessage(e)],["/v1/worker/ack-event",async(t,e)=>t.onAckEvent(e)],["/v1/worker/event-result",async(t,e)=>t.onSendEventResult(e)],["/v1/worker/event-stop-ack",async(t,e)=>t.onSendEventStopAck(e)],["/v1/worker/event-stop-result",async(t,e)=>t.onSendEventStopResult(e)],["/v1/worker/session-composing",async(t,e)=>t.onSetSessionComposing(e)],["/v1/worker/agent-invoke",async(t,e)=>t.onAgentInvoke(e)],["/v1/worker/local-action-result",async(t,e)=>t.onLocalActionResult(e)]]);export{w as ClaudeBridgeServer};
@@ -1 +1 @@
1
- import{randomUUID as x}from"node:crypto";import{CallToolRequestSchema as S,ListToolsRequestSchema as w}from"@modelcontextprotocol/sdk/types.js";import{log as f}from"../../core/log/index.js";import{toolCallToInvoke as k}from"../../core/mcp/tools.js";const E=new Set(["contact_search","session_search","message_history","message_search","group_create","group_detail_read","group_leave_self","group_member_add","group_member_remove","group_member_role_update","group_all_members_muted_update","group_member_speaking_update","group_dissolve","send_msg","delete_msg","agent_api_create","agent_category_list","agent_category_create","agent_category_update","agent_category_assign","agent_api_key_rotate"]),y=3e4,I=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},files:{type:"array",items:{type:"string"},description:"Optional absolute local file paths. Each file is uploaded through Agent API OSS presign before sending."},final:{type:"boolean",description:"Whether this is the final reply for the event. Defaults to false \u2014 the event stays open while Claude continues working, and auto-completes after inactivity. Set true only when this is definitively the last message for the event."}},required:["chat_id","event_id"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},code:{type:"string"},msg:{type:"string"}},required:["event_id","status"]}},{name:"delete_message",description:"Delete a previously sent message in the same grix-claude chat.",inputSchema:{type:"object",properties:{chat_id:{type:"string"},message_id:{type:"string"}},required:["chat_id","message_id"]}},{name:"status",description:"Show grix-claude runtime status, upstream access state, bridge health, and startup hints.",inputSchema:{type:"object",properties:{}}},{name:"send",description:"Send a message to a chat session proactively, without requiring an inbound event. Use for notifications or scheduled reports.",inputSchema:{type:"object",properties:{chat_id:{type:"string",description:"The target chat/session id."},text:{type:"string",description:"The message text to send."}},required:["chat_id","text"]}},{name:"access_pair",description:"Forward a sender pairing approval code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"access_deny",description:"Forward a sender pairing denial code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"allow_sender",description:"Ask upstream access control to allow a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"remove_sender",description:"Ask upstream access control to remove a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"access_policy",description:"Ask upstream access control to update the sender access policy.",inputSchema:{type:"object",properties:{policy:{type:"string",enum:["allowlist","open","disabled"]}},required:["policy"]}},{name:"grix_query",description:"Search contacts, sessions, message history, or messages by keyword in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},keyword:{type:"string"},id:{type:"string"},sessionId:{type:"string"},limit:{type:"number"},offset:{type:"number"},beforeId:{type:"string"}},required:["action"]}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",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"},memberIds:{type:"array",items:{type:"string"}},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer",description:"Member type (for update_member_role / update_member_speaking)."},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted (for update_member_speaking)."}},required:["action"]}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},content:{type:"string"},msgType:{type:"number"},quotedMessageId:{type:"string"},threadId:{type:"string"}},required:["sessionId","content"]}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},msgId:{type:"string"}},required:["sessionId","msgId"]}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentId:{type:"string"},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"number"}},required:["action"]}}];function q(r,e){r.setRequestHandler(w,async()=>({tools:I})),r.setRequestHandler(S,async i=>{const{name:n,arguments:t}=i.params,s=t??{};try{switch(n){case"reply":return await A(s,e);case"complete":return await $(s,e);case"delete_message":return await T(s,e);case"status":return j(e);case"send":return await M(s,e);case"access_pair":case"access_deny":case"allow_sender":case"remove_sender":case"access_policy":return await R(n,s,e);case"grix_query":case"grix_group":case"grix_message_send":case"grix_message_unsend":case"grix_admin":return await O(n,s,e);default:return{content:[{type:"text",text:`Unknown tool: ${n}`}],isError:!0}}}catch(a){return f.error("claude-tools",`Tool ${n} error: ${a}`),{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],isError:!0}}})}async function A(r,e){const i=e.getActiveEvent();if(!i)return{content:[{type:"text",text:"No active event to reply to"}],isError:!0};const n=String(r.text??""),t=String(r.chat_id??""),s=String(r.event_id??i.eventId),a=r.reply_to,d=r.files,_=r.final===!0;if(!t||!s)return{content:[{type:"text",text:"reply requires chat_id and event_id"}],isError:!0};if(!n.trim()&&(!d||d.length===0))return{content:[{type:"text",text:"reply requires at least one of text or files"}],isError:!0};const{text:g,quotedMessageId:v}=e.resolveQuotedMessageId(a,n),b=[];let m=0;const h=`reply_${s}_${Date.now()}`;try{if(g){const p=e.splitText(g);for(let o=0;o<p.length;o++){if(!e.isEventActive(s))return c("ignored: event no longer active");m++,e.bridge.sendStreamChunk(s,t,p[o],++i.chunkSeq,!1,h)}}if(d&&d.length>0)for(const p of d){if(!e.isEventActive(s))return c("ignored: event no longer active");m++;const o=await e.uploadFile(p,t),l=`${x()}_${m}`;e.bridge.sendMedia(s,t,o.access_url,o.file_name,v,l,o.extra),f.info("claude-tools",`File sent: ${o.file_name}`)}e.bridge.sendStreamChunk(s,t,"",++i.chunkSeq,!0,h)}catch(p){if(g&&b.length===0)try{const o=`fallback_${s}_${Date.now()}`,l=e.splitText(g);for(let u=0;u<l.length;u++)e.bridge.sendStreamChunk("",t,l[u],u+1,!1,o);return e.bridge.sendStreamChunk("",t,"",l.length+1,!0,o),e.markReplySent(s),_&&e.finalizeEvent(s,"responded"),c("sent via fallback")}catch{}if(!e.isEventActive(s))return c("ignored: event no longer active");throw e.bridge.sendEventResult(s,"failed",String(p),"send_msg_failed"),p}return e.markReplySent(s),_?e.finalizeEvent(s,"responded"):(i.responded=!0,e.clearActiveEvent("completed")),c("Reply sent")}async function $(r,e){const i=e.getActiveEvent(),n=String(r.event_id??""),t=r.status??"",s=r.code,a=r.msg;if(!n||!t)return{content:[{type:"text",text:"complete requires event_id and status"}],isError:!0};const d=["responded","canceled","failed"];return d.includes(t)?e.isEventActive(n)?(e.bridge.sendEventResult(n,t,a,s),e.clearActiveEvent(t),c("Event completed")):c("ignored: event no longer active"):{content:[{type:"text",text:`status must be one of: ${d.join(", ")}`}],isError:!0}}async function T(r,e){const i=String(r.chat_id??""),n=String(r.message_id??"");if(!i||!n)return{content:[{type:"text",text:"chat_id and message_id are required"}],isError:!0};try{return await e.bridge.agentInvoke("grix_message_unsend",{sessionId:i,msgId:n},y),c(`deleted (${n})`)}catch(t){return{content:[{type:"text",text:`Delete failed: ${t}`}],isError:!0}}}function j(r){const e=r.getStatusInfo();return{content:[{type:"text",text:JSON.stringify({alive:e.alive,active_event:e.activeEvent,pending_approvals:e.pendingPermissions,pending_questions:e.pendingElicitations})}]}}async function M(r,e){const i=String(r.chat_id??""),n=String(r.text??"");if(!i||!n)return{content:[{type:"text",text:"chat_id and text are required"}],isError:!0};try{const t=e.splitText(n),s=`send_${i}_${Date.now()}`;for(let a=0;a<t.length;a++)e.bridge.sendStreamChunk("",i,t[a],a+1,!1,s);return e.bridge.sendStreamChunk("",i,"",t.length+1,!0,s),c("sent")}catch(t){return{content:[{type:"text",text:`Send failed: ${t}`}],isError:!0}}}const C={access_pair:{verb:"pair_approve",payloadKey:"code"},access_deny:{verb:"pair_deny",payloadKey:"code"},allow_sender:{verb:"sender_allow",payloadKey:"sender_id"},remove_sender:{verb:"sender_remove",payloadKey:"sender_id"},access_policy:{verb:"policy_set",payloadKey:"policy"}};async function R(r,e,i){try{const n=C[r];if(!n)throw new Error(`Unknown access control tool: ${r}`);const t={};e.code!=null&&(t.code=e.code),e.sender_id!=null&&(t.sender_id=e.sender_id),e.policy!=null&&(t.policy=e.policy);const s=await i.bridge.agentInvoke("claude_access_control",{verb:n.verb,payload:t},y);return{content:[{type:"text",text:typeof s=="string"?s:JSON.stringify(s)}]}}catch(n){return{content:[{type:"text",text:`${r} failed: ${n}`}],isError:!0}}}async function O(r,e,i){try{const n=k(r,e);if(!E.has(n.action))throw new Error(`Action not allowed: ${n.action}`);const t=await i.bridge.agentInvoke(n.action,n.params,y);if(t&&Number(t.code??0)!==0)throw new Error(String(t.msg??"invoke failed"));return{content:[{type:"text",text:t?.data!=null?typeof t.data=="string"?t.data:JSON.stringify(t.data):JSON.stringify(t)}]}}catch(n){return{content:[{type:"text",text:`${r} failed: ${n}`}],isError:!0}}}function c(r){return{content:[{type:"text",text:r}]}}export{q as registerClaudeTools};
1
+ import{randomUUID as x}from"node:crypto";import{CallToolRequestSchema as S,ListToolsRequestSchema as w}from"@modelcontextprotocol/sdk/types.js";import{log as f}from"../../core/log/index.js";import{toolCallToInvoke as k}from"../../core/mcp/tools.js";const E=new Set(["contact_search","session_search","message_history","message_search","group_create","group_detail_read","group_leave_self","group_member_add","group_member_remove","group_member_role_update","group_all_members_muted_update","group_member_speaking_update","group_dissolve","send_msg","delete_msg","agent_api_create","agent_category_list","agent_category_create","agent_category_update","agent_category_assign","agent_api_key_rotate"]),y=3e4,I=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},files:{type:"array",items:{type:"string"},description:"Optional absolute local file paths. Each file is uploaded through Agent API OSS presign before sending."},final:{type:"boolean",description:"Whether this is the final reply for the event. Defaults to false \u2014 the event stays open while Claude continues working, and auto-completes after inactivity. Set true only when this is definitively the last message for the event."}},required:["chat_id","event_id"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},code:{type:"string"},msg:{type:"string"}},required:["event_id","status"]}},{name:"delete_message",description:"Delete a previously sent message in the same grix-claude chat.",inputSchema:{type:"object",properties:{chat_id:{type:"string"},message_id:{type:"string"}},required:["chat_id","message_id"]}},{name:"status",description:"Show grix-claude runtime status, upstream access state, bridge health, and startup hints.",inputSchema:{type:"object",properties:{}}},{name:"send",description:"Send a message to a chat session proactively, without requiring an inbound event. Use for notifications or scheduled reports.",inputSchema:{type:"object",properties:{chat_id:{type:"string",description:"The target chat/session id."},text:{type:"string",description:"The message text to send."}},required:["chat_id","text"]}},{name:"access_pair",description:"Forward a sender pairing approval code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"access_deny",description:"Forward a sender pairing denial code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"allow_sender",description:"Ask upstream access control to allow a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"remove_sender",description:"Ask upstream access control to remove a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"access_policy",description:"Ask upstream access control to update the sender access policy.",inputSchema:{type:"object",properties:{policy:{type:"string",enum:["allowlist","open","disabled"]}},required:["policy"]}},{name:"grix_query",description:"Search contacts, sessions, message history, or messages by keyword in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},keyword:{type:"string"},id:{type:"string"},sessionId:{type:"string"},limit:{type:"number"},offset:{type:"number"},beforeId:{type:"string"}},required:["action"]}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",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"},memberIds:{type:"array",items:{type:"string"}},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer",description:"Member type (for update_member_role / update_member_speaking)."},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted (for update_member_speaking)."}},required:["action"]}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},content:{type:"string"},msgType:{type:"number"},quotedMessageId:{type:"string"},threadId:{type:"string"}},required:["sessionId","content"]}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},msgId:{type:"string"}},required:["sessionId","msgId"]}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentId:{type:"string"},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"number"}},required:["action"]}}];function q(n,e){n.setRequestHandler(w,async()=>({tools:I})),n.setRequestHandler(S,async i=>{const{name:r,arguments:t}=i.params,s=t??{};try{switch(r){case"reply":return await A(s,e);case"complete":return await $(s,e);case"delete_message":return await T(s,e);case"status":return j(e);case"send":return await M(s,e);case"access_pair":case"access_deny":case"allow_sender":case"remove_sender":case"access_policy":return await R(r,s,e);case"grix_query":case"grix_group":case"grix_message_send":case"grix_message_unsend":case"grix_admin":return await O(r,s,e);default:return{content:[{type:"text",text:`Unknown tool: ${r}`}],isError:!0}}}catch(a){return f.error("claude-tools",`Tool ${r} error: ${a}`),{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],isError:!0}}})}async function A(n,e){const i=e.getActiveEvent();if(!i)return{content:[{type:"text",text:"No active event to reply to"}],isError:!0};const r=String(n.text??""),t=String(n.chat_id??""),s=String(n.event_id??i.eventId),a=n.reply_to,d=n.files,_=n.final===!0;if(!t||!s)return{content:[{type:"text",text:"reply requires chat_id and event_id"}],isError:!0};if(!r.trim()&&(!d||d.length===0))return{content:[{type:"text",text:"reply requires at least one of text or files"}],isError:!0};const{text:g,quotedMessageId:v}=e.resolveQuotedMessageId(a,r),b=[];let m=0;const h=`reply_${s}_${Date.now()}`;try{if(g){const p=e.splitText(g);for(let o=0;o<p.length;o++){if(!e.isEventActive(s))return c("ignored: event no longer active");m++,e.bridge.sendStreamChunk(s,t,p[o],++i.chunkSeq,!1,h)}}if(d&&d.length>0)for(const p of d){if(!e.isEventActive(s))return c("ignored: event no longer active");m++;const o=await e.uploadFile(p,t),l=`${x()}_${m}`;e.bridge.sendMedia(s,t,o.access_url,o.file_name,v,l,o.extra),f.info("claude-tools",`File sent: ${o.file_name}`)}e.bridge.sendStreamChunk(s,t,"",++i.chunkSeq,!0,h)}catch(p){if(g&&b.length===0)try{const o=`fallback_${s}_${Date.now()}`,l=e.splitText(g);for(let u=0;u<l.length;u++)e.bridge.sendStreamChunk("",t,l[u],u+1,!1,o);return e.bridge.sendStreamChunk("",t,"",l.length+1,!0,o),e.markReplySent(s),_&&e.finalizeEvent(s,"responded"),c("sent via fallback")}catch{}if(!e.isEventActive(s))return c("ignored: event no longer active");throw e.bridge.sendEventResult(s,"failed",String(p),"send_msg_failed"),p}return e.markReplySent(s),_?e.finalizeEvent(s,"responded"):(i.responded=!0,e.clearActiveEvent("completed")),c("Reply sent")}async function $(n,e){const i=e.getActiveEvent(),r=String(n.event_id??""),t=n.status??"",s=n.code,a=n.msg;if(!r||!t)return{content:[{type:"text",text:"complete requires event_id and status"}],isError:!0};const d=["responded","canceled","failed"];return d.includes(t)?e.isEventActive(r)?(e.bridge.sendEventResult(r,t,a,s),e.clearActiveEvent(t),c("Event completed")):c("ignored: event no longer active"):{content:[{type:"text",text:`status must be one of: ${d.join(", ")}`}],isError:!0}}async function T(n,e){const i=String(n.chat_id??""),r=String(n.message_id??"");if(!i||!r)return{content:[{type:"text",text:"chat_id and message_id are required"}],isError:!0};try{return await e.bridge.agentInvoke("grix_message_unsend",{sessionId:i,msgId:r},y),c(`deleted (${r})`)}catch(t){return{content:[{type:"text",text:`Delete failed: ${t}`}],isError:!0}}}function j(n){const e=n.getStatusInfo();return{content:[{type:"text",text:JSON.stringify({alive:e.alive,active_event:e.activeEvent,pending_approvals:e.pendingPermissions,pending_questions:e.pendingElicitations})}]}}async function M(n,e){const i=String(n.chat_id??""),r=String(n.text??"");if(!i||!r)return{content:[{type:"text",text:"chat_id and text are required"}],isError:!0};try{const t=e.splitText(r),s=`send_${i}_${Date.now()}`;for(let a=0;a<t.length;a++)e.bridge.sendStreamChunk("",i,t[a],a+1,!1,s);return e.bridge.sendStreamChunk("",i,"",t.length+1,!0,s),c("sent")}catch(t){return{content:[{type:"text",text:`Send failed: ${t}`}],isError:!0}}}const C={access_pair:{verb:"pair_approve",payloadKey:"code"},access_deny:{verb:"pair_deny",payloadKey:"code"},allow_sender:{verb:"sender_allow",payloadKey:"sender_id"},remove_sender:{verb:"sender_remove",payloadKey:"sender_id"},access_policy:{verb:"policy_set",payloadKey:"policy"}};async function R(n,e,i){try{const r=C[n];if(!r)throw new Error(`Unknown access control tool: ${n}`);const t={};e.code!=null&&(t.code=e.code),e.sender_id!=null&&(t.sender_id=e.sender_id),e.policy!=null&&(t.policy=e.policy);const s=await i.bridge.agentInvoke("claude_access_control",{verb:r.verb,payload:t},y);return{content:[{type:"text",text:typeof s=="string"?s:JSON.stringify(s)}]}}catch(r){return{content:[{type:"text",text:`${n} failed: ${r}`}],isError:!0}}}async function O(n,e,i){try{const r=k(n,e);if(!E.has(r.action))throw new Error(`Action not allowed: ${r.action}`);const t=await i.bridge.agentInvoke(r.action,r.params,y);if(t&&Number(t.code??0)!==0)throw new Error(String(t.msg??"invoke failed"));return{content:[{type:"text",text:t?.data!=null?typeof t.data=="string"?t.data:JSON.stringify(t.data):JSON.stringify(t)}]}}catch(r){return{content:[{type:"text",text:`${n} failed: ${r}`}],isError:!0}}}function c(n){return{content:[{type:"text",text:n}]}}export{q as registerClaudeTools};
@@ -1 +1 @@
1
- import{log as l}from"../../core/log/index.js";class c{controlURL="";token="";isConfigured(){return!!(this.controlURL&&this.token)}configure(r,e){this.controlURL=r.replace(/\/+$/,""),this.token=e.trim(),l.info("claude-worker-client",`Configured with control URL: ${this.controlURL}`)}async post(r,e,s){if(!this.isConfigured())throw new Error("worker control not configured");const i=new AbortController,o=setTimeout(()=>i.abort(),s);try{const t=await fetch(`${this.controlURL}${r}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${this.token}`},body:JSON.stringify(e),signal:i.signal}),n=await t.text(),a=n.trim()?JSON.parse(n):{};if(!t.ok)throw new Error(a.error||`worker control failed ${t.status}`);return a}finally{clearTimeout(o)}}isRetryableError(r){const e=r instanceof Error?r.message:String(r);return/fetch failed|network|ECONNRESET|ETIMEDOUT|EAI_AGAIN|socket hang up|aborted/i.test(e)}async postWithRetry(r,e,s,i=1){let o;for(let t=0;t<=i;t++)try{return t>0&&l.info("claude-worker-client",`Retrying ${r} attempt=${t+1}`),await this.post(r,e,s)}catch(n){if(o=n,t>=i||!this.isRetryableError(n))break;await new Promise(a=>setTimeout(a,150))}throw o instanceof Error?o:new Error(String(o))}async deliverEvent(r){return this.postWithRetry("/v1/worker/deliver-event",{payload:r},1e4,1)}async deliverStop(r){return this.postWithRetry("/v1/worker/deliver-stop",{payload:r},1e4,1)}async deliverLocalAction(r){return this.postWithRetry("/v1/worker/deliver-local-action",{payload:r},1e4,1)}async ping(){try{return await this.postWithRetry("/v1/worker/ping",{},5e3,1),!0}catch{return!1}}}export{c as ClaudeWorkerClient};
1
+ import{log as l}from"../../core/log/index.js";class c{controlURL="";token="";isConfigured(){return!!(this.controlURL&&this.token)}configure(t,e){this.controlURL=t.replace(/\/+$/,""),this.token=e.trim(),l.info("claude-worker-client",`Configured with control URL: ${this.controlURL}`)}async post(t,e,s){if(!this.isConfigured())throw new Error("worker control not configured");const i=new AbortController,o=setTimeout(()=>i.abort(),s);try{const r=await fetch(`${this.controlURL}${t}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${this.token}`},body:JSON.stringify(e),signal:i.signal}),n=await r.text(),a=n.trim()?JSON.parse(n):{};if(!r.ok)throw new Error(a.error||`worker control failed ${r.status}`);return a}finally{clearTimeout(o)}}isRetryableError(t){const e=t instanceof Error?t.message:String(t);return/fetch failed|network|ECONNRESET|ETIMEDOUT|EAI_AGAIN|socket hang up|aborted/i.test(e)}async postWithRetry(t,e,s,i=1){let o;for(let r=0;r<=i;r++)try{return r>0&&l.info("claude-worker-client",`Retrying ${t} attempt=${r+1}`),await this.post(t,e,s)}catch(n){if(o=n,r>=i||!this.isRetryableError(n))break;await new Promise(a=>setTimeout(a,150))}throw o instanceof Error?o:new Error(String(o))}async deliverEvent(t){return this.postWithRetry("/v1/worker/deliver-event",{payload:t},1e4,1)}async deliverStop(t){return this.postWithRetry("/v1/worker/deliver-stop",{payload:t},1e4,1)}async deliverLocalAction(t){return this.postWithRetry("/v1/worker/deliver-local-action",{payload:t},1e4,1)}async ping(){try{return await this.postWithRetry("/v1/worker/ping",{},5e3,1),!0}catch{return!1}}}export{c as ClaudeWorkerClient};
@@ -1,2 +1,2 @@
1
- import{spawn as x,execSync as y}from"node:child_process";import{randomUUID as v}from"node:crypto";import{mkdir as S}from"node:fs/promises";import{readFileSync as C}from"node:fs";import{join as d}from"node:path";import{homedir as T,tmpdir as I}from"node:os";import{log as o}from"../../core/log/index.js";import{MCP_HTTP_CHANNEL_NAME as m}from"./protocol-contract.js";function P(t){let e=null,r=0,n=!1,i=!1;const a=v(),s=t.gatewayUrl??"http://127.0.0.1:19580/mcp";return{async start(){await F(t.command,s,t.env);const c=E(t.grix),u=[...t.args??[],"--name",`grix-mcp-${t.name}`,"--session-id",a];t.fullAuto&&u.push("--dangerously-skip-permissions"),u.push("--dangerously-load-development-channels",`server:${m}`,"--append-system-prompt",c);const f=d(I(),`grix-mcp-claude-${t.name}`);await S(f,{recursive:!0});const{expectPath:$,pidPath:g}=await M(f,t.command,u),_={...process.env,...t.env??{}};e=x("/usr/bin/expect",[$],{cwd:t.cwd,env:_,stdio:["ignore","pipe","pipe"],detached:!0}),o.info("mcp-http-launcher",`\u542F\u52A8 Claude: name=${t.name} cwd=${t.cwd} pid=${e.pid}`),r=await k(g),n=!0,o.info("mcp-http-launcher",`Claude \u5B50\u8FDB\u7A0B PID: ${r}`),e.on("exit",(l,p)=>{o.info("mcp-http-launcher",`Claude \u9000\u51FA: code=${l} signal=${p}`),n=!1,e=null,r=0,i||(o.info("mcp-http-launcher","3 \u79D2\u540E\u81EA\u52A8\u91CD\u542F..."),setTimeout(()=>{i||this.start().catch(w=>{o.error("mcp-http-launcher",`\u91CD\u542F\u5931\u8D25: ${w}`)})},3e3))}),e.stdout?.on("data",l=>{const p=l.toString().trim();p&&o.info("mcp-http-launcher",`[stdout] ${p.slice(0,300)}`)}),e.stderr?.on("data",l=>{const p=l.toString().trim();p&&o.info("mcp-http-launcher",`[stderr] ${p.slice(0,300)}`)})},async stop(){if(i=!0,n=!1,r>0)try{process.kill(r,"SIGTERM")}catch{}if(e?.pid){try{process.kill(-e.pid,"SIGTERM")}catch{}await new Promise(c=>{const u=setTimeout(()=>{if(r>0)try{process.kill(r,"SIGKILL")}catch{}if(e?.pid)try{process.kill(-e.pid,"SIGKILL")}catch{}c()},5e3);e?.once("exit",()=>{clearTimeout(u),c()})})}e=null,r=0},getStatus(){return{name:t.name,alive:n,pid:r}}}}function E(t){return["You are connected to a chat via the grix MCP server.",`On startup, immediately call grix_authorize with: agentId="${t.agentId}", apiKey="${t.apiKey}", wsUrl="${t.wsUrl}", clientType="${t.clientType}".`,"When you receive a <channel> message, you MUST respond by calling the grix_reply tool (or the grix_complete tool if no response is needed).","Never write your reply as plain text \u2014 it will NOT reach the user. Only the grix_reply tool delivers your response to the chat.","The <channel> message contains event_id and session_id \u2014 pass them to grix_reply."].join(" ")}async function F(t,e,r){const n=d(T(),".claude.json");let i=null;try{const s=C(n,"utf8");i=JSON.parse(s)?.mcpServers?.[m]??null}catch{}if(i&&String(i.type??"").trim()==="http"&&String(i.url??"").trim()===e)return;o.info("mcp-http-launcher",`\u6CE8\u518C MCP Server: ${m} -> ${e}`);const a={...process.env,...r??{}};try{y(`${t} mcp remove -s user ${m}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}catch{}y(`${t} mcp add --scope user --transport http ${m} ${e}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}async function M(t,e,r){const{writeFile:n}=await import("node:fs/promises"),i=d(t,"claude.pid"),a=d(t,"claude.expect"),s=["log_user 1","set timeout -1","set startup_prompt_armed 1",`set claude_command [list {${h(e)}}${r.map(c=>` {${h(c)}}`).join("")}]`,"spawn -noecho {*}$claude_command",`set pid_file [open {${h(i)}} w]`,"puts $pid_file [exp_pid -i $spawn_id]","close $pid_file","expect {"," -re {(?i)(Quick.*safety.*check|trust.*folder)} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)I am using this for local development} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)(Enter.*confirm|Press.*Enter|Hit.*Enter)} {",' if {$startup_prompt_armed} { send -- "\\r"; after 300 }; exp_continue'," }"," -re {Listening for channel} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," -re {bypass permissions} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," eof {}","}","expect eof",""];return await n(i,"","utf8"),await n(a,s.join(`
2
- `),"utf8"),{expectPath:a,pidPath:i}}function h(t){return t.replace(/[\\{}$\[\]"]/g,"\\$&")}async function k(t,e=1e4){const{readFile:r}=await import("node:fs/promises"),n=Math.ceil(e/100);for(let i=0;i<n;i++){try{const a=await r(t,"utf8"),s=parseInt(String(a).trim(),10);if(Number.isFinite(s)&&s>0)return s}catch{}await new Promise(a=>setTimeout(a,100))}return 0}export{P as createMcpHttpLauncher};
1
+ import{spawn as x,execSync as y}from"node:child_process";import{randomUUID as v}from"node:crypto";import{mkdir as S}from"node:fs/promises";import{readFileSync as C}from"node:fs";import{join as d}from"node:path";import{homedir as T,tmpdir as I}from"node:os";import{log as o}from"../../core/log/index.js";import{MCP_HTTP_CHANNEL_NAME as l}from"./protocol-contract.js";function P(e){let t=null,r=0,n=!1,i=!1;const a=v(),s=e.gatewayUrl??"http://127.0.0.1:19580/mcp";return{async start(){await F(e.command,s,e.env);const c=E(e.grix),u=[...e.args??[],"--name",`grix-mcp-${e.name}`,"--session-id",a];e.fullAuto&&u.push("--dangerously-skip-permissions"),u.push("--dangerously-load-development-channels",`server:${l}`,"--append-system-prompt",c);const f=d(I(),`grix-mcp-claude-${e.name}`);await S(f,{recursive:!0});const{expectPath:$,pidPath:g}=await M(f,e.command,u),_={...process.env,...e.env??{}};t=x("/usr/bin/expect",[$],{cwd:e.cwd,env:_,stdio:["ignore","pipe","pipe"],detached:!0}),o.info("mcp-http-launcher",`\u542F\u52A8 Claude: name=${e.name} cwd=${e.cwd} pid=${t.pid}`),r=await k(g),n=!0,o.info("mcp-http-launcher",`Claude \u5B50\u8FDB\u7A0B PID: ${r}`),t.on("exit",(m,p)=>{o.info("mcp-http-launcher",`Claude \u9000\u51FA: code=${m} signal=${p}`),n=!1,t=null,r=0,i||(o.info("mcp-http-launcher","3 \u79D2\u540E\u81EA\u52A8\u91CD\u542F..."),setTimeout(()=>{i||this.start().catch(w=>{o.error("mcp-http-launcher",`\u91CD\u542F\u5931\u8D25: ${w}`)})},3e3))}),t.stdout?.on("data",m=>{const p=m.toString().trim();p&&o.info("mcp-http-launcher",`[stdout] ${p.slice(0,300)}`)}),t.stderr?.on("data",m=>{const p=m.toString().trim();p&&o.info("mcp-http-launcher",`[stderr] ${p.slice(0,300)}`)})},async stop(){if(i=!0,n=!1,r>0)try{process.kill(r,"SIGTERM")}catch{}if(t?.pid){try{process.kill(-t.pid,"SIGTERM")}catch{}await new Promise(c=>{const u=setTimeout(()=>{if(r>0)try{process.kill(r,"SIGKILL")}catch{}if(t?.pid)try{process.kill(-t.pid,"SIGKILL")}catch{}c()},5e3);t?.once("exit",()=>{clearTimeout(u),c()})})}t=null,r=0},getStatus(){return{name:e.name,alive:n,pid:r}}}}function E(e){return["You are connected to a chat via the grix MCP server.",`On startup, immediately call grix_authorize with: agentId="${e.agentId}", apiKey="${e.apiKey}", wsUrl="${e.wsUrl}", clientType="${e.clientType}".`,"When you receive a <channel> message, you MUST respond by calling the grix_reply tool (or the grix_complete tool if no response is needed).","Never write your reply as plain text \u2014 it will NOT reach the user. Only the grix_reply tool delivers your response to the chat.","The <channel> message contains event_id and session_id \u2014 pass them to grix_reply."].join(" ")}async function F(e,t,r){const n=d(T(),".claude.json");let i=null;try{const s=C(n,"utf8");i=JSON.parse(s)?.mcpServers?.[l]??null}catch{}if(i&&String(i.type??"").trim()==="http"&&String(i.url??"").trim()===t)return;o.info("mcp-http-launcher",`\u6CE8\u518C MCP Server: ${l} -> ${t}`);const a={...process.env,...r??{}};try{y(`${e} mcp remove -s user ${l}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}catch{}y(`${e} mcp add --scope user --transport http ${l} ${t}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}async function M(e,t,r){const{writeFile:n}=await import("node:fs/promises"),i=d(e,"claude.pid"),a=d(e,"claude.expect"),s=["log_user 1","set timeout -1","set startup_prompt_armed 1",`set claude_command [list {${h(t)}}${r.map(c=>` {${h(c)}}`).join("")}]`,"spawn -noecho {*}$claude_command",`set pid_file [open {${h(i)}} w]`,"puts $pid_file [exp_pid -i $spawn_id]","close $pid_file","expect {"," -re {(?i)(Quick.*safety.*check|trust.*folder)} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)I am using this for local development} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)(Enter.*confirm|Press.*Enter|Hit.*Enter)} {",' if {$startup_prompt_armed} { send -- "\\r"; after 300 }; exp_continue'," }"," -re {Listening for channel} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," -re {bypass permissions} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," eof {}","}","expect eof",""];return await n(i,"","utf8"),await n(a,s.join(`
2
+ `),"utf8"),{expectPath:a,pidPath:i}}function h(e){return e.replace(/[\\{}$\[\]"]/g,"\\$&")}async function k(e,t=1e4){const{readFile:r}=await import("node:fs/promises"),n=Math.ceil(t/100);for(let i=0;i<n;i++){try{const a=await r(e,"utf8"),s=parseInt(String(a).trim(),10);if(Number.isFinite(s)&&s>0)return s}catch{}await new Promise(a=>setTimeout(a,100))}return 0}export{P as createMcpHttpLauncher};
@@ -1 +1 @@
1
- class m{defaultTimeoutMs;onTimeout;timers=new Map;constructor(e){this.defaultTimeoutMs=e.defaultTimeoutMs??9e4,this.onTimeout=e.onTimeout}arm(e,t){this.cancel(e);const s=t?.timeoutMs??this.defaultTimeoutMs,i=Date.now()+s,o=setTimeout(()=>{this.timers.delete(e),this.onTimeout(e).catch(()=>{})},s);return this.timers.set(e,o),i}cancel(e){const t=this.timers.get(e);t&&(clearTimeout(t),this.timers.delete(e))}has(e){return this.timers.has(e)}close(){for(const e of this.timers.values())clearTimeout(e);this.timers.clear()}}export{m as ResultTimeoutManager};
1
+ class m{defaultTimeoutMs;onTimeout;timers=new Map;constructor(t){this.defaultTimeoutMs=t.defaultTimeoutMs??9e4,this.onTimeout=t.onTimeout}arm(t,e){this.cancel(t);const s=e?.timeoutMs??this.defaultTimeoutMs,i=Date.now()+s,o=setTimeout(()=>{this.timers.delete(t),this.onTimeout(t).catch(()=>{})},s);return this.timers.set(t,o),i}cancel(t){const e=this.timers.get(t);e&&(clearTimeout(e),this.timers.delete(t))}has(t){return this.timers.has(t)}close(){for(const t of this.timers.values())clearTimeout(t);this.timers.clear()}}export{m as ResultTimeoutManager};
@@ -1,12 +1,12 @@
1
- import P from"node:path";import{realpath as be,stat as W}from"node:fs/promises";import{tmpdir as we,homedir as N}from"node:os";import{createHash as Ce,randomUUID as K}from"node:crypto";import{ConnectionManager as Ae}from"../core/aibot/index.js";import{AUDIT_LOCAL_ACTION_TYPES as ke}from"../core/aibot/types.js";import{ClaudeAdapter as M}from"../adapter/claude/index.js";import{CodexAdapter as ie}from"../adapter/codex/index.js";import{PiAdapter as Re}from"../adapter/pi/index.js";import{AcpAdapter as y}from"../adapter/acp/index.js";import{OpenHumanAdapter as ye}from"../adapter/openhuman/index.js";import{CursorAdapter as q,CURSOR_MODE_OPTIONS as Ee,fetchCursorAccountUsage as $e}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as se}from"../adapter/codewhale/index.js";import{OpenCodeAdapter as G}from"../adapter/opencode/index.js";import{AgyAdapter as ne}from"../adapter/agy/index.js";import{getCachedAgyModels as Te}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as Pe,primeAgyQuotaInfo as xe}from"../adapter/agy/quota.js";import{LOCAL_ACTION_ERROR_CODES as x,LOCAL_ACTION_TYPES as C,SESSION_CONTROL_ERROR_CODES as p,SESSION_CONTROL_VERBS as _,SESSION_MODE_IDS as R}from"../adapter/claude/protocol-contract.js";import{AuditLocalActionHandler as He,isAuditLocalActionType as Le}from"../audit/query/audit-local-actions.js";import{AuditReplayQueryService as Me}from"../audit/query/audit-replay-query-service.js";import{resolveDefaultAuditStorageRootDir as Ie}from"../audit/runtime/default-audit-recorder.js";import{FileAuditReplayStore as De}from"../audit/storage/file-audit-replay-store.js";import{shouldEnableRawApiCapture as oe}from"../audit/raw-capture/types.js";import{parseClaudeSessionUsage as Qe}from"../adapter/claude/usage-parser.js";import"../adapter/claude/session-history.js";import"../adapter/codex/session-history.js";import"../adapter/pi/session-history.js";import"../adapter/opencode/session-history.js";import"../adapter/codewhale/session-history.js";import{SESSION_HISTORY_ERROR_CODES as O,SessionHistoryError as Be,getSessionHistoryReader as qe}from"../adapter/shared/session-history.js";import{resolveSkillScanMode as I}from"../adapter/claude/skill-scanner.js";import{buildReportedSkills as Oe}from"../default-skills/index.js";import{buildWireSkills as re}from"../core/skill-sync/sync-state.js";import{uploadSkill as Ue}from"../core/skill-sync/skill-upload.js";import{buildLibrarySkills as Fe}from"../core/skill-sync/library-skills.js";import{enableSkill as We,disableSkill as Ne,SkillEnableError as ae}from"../core/skill-sync/skill-enable.js";import{fetchAvailableModels as z,getCachedModels as j,readSettingsEnv as Ke}from"../adapter/claude/model-list.js";import{parseAcpSessionUsage as Ge}from"../adapter/acp/usage-parser.js";import{applyProxyEnv as ze,getProxyManager as de,relayHostsForClientType as je,buildGatewayRoute as Ve}from"../core/proxy/index.js";import{getKiroRelaySpawnEnv as Ye}from"../core/proxy/kiro-relay.js";import{supportsKiroCwRelay as ce}from"../core/config/provider-env.js";import{RelayFetchError as Je,deriveGatewayBaseUrls as le,fetchRelayCredentialWithRetry as Xe}from"../core/proxy/relay-credential-fetch.js";import{RelayStateSyncer as Ze}from"../core/proxy/relay-state-sync.js";import{isDirectRelayExplicitlyUnsupported as et}from"../core/proxy/relay-credential.js";import{buildProviderEnv as tt}from"../core/config/provider-env.js";import{CLAUDE_EFFORT_LEVELS as D,isClaudeDirectEnv as it,normalizeClaudeEffort as V,stripGrixRelayEnv as st}from"../core/config/claude-direct-env.js";import{sweepNativeProviderResidue as nt}from"./native-provider-sweep.js";import{parseCodexSessionUsage as ot}from"../adapter/codex/usage-parser.js";import{readCodexProviderSettings as rt}from"../adapter/codex/codex-trust.js";import{resolveKimiProviderSettings as at}from"../core/provider-quota/index.js";import{scanCodexSessions as dt}from"../adapter/codex/session-scanner.js";import{scanClaudeSessions as ct}from"../adapter/claude/session-scanner.js";import{reasonixStampFromSessionId as lt,resolveAcpAgentTypes as ut,scanAcpSessions as ht,scanReasonixSessionTitles as gt}from"../adapter/acp/session-scanner.js";import{scanPiSessions as pt}from"../adapter/pi/session-scanner.js";import{scanCodeWhaleSessions as ft}from"../adapter/codewhale/session-scanner.js";import{scanCursorSessions as mt}from"../adapter/cursor/session-scanner.js";import{scanOpenCodeSessions as _t}from"../adapter/opencode/session-scanner.js";import{parsePiSessionUsage as vt}from"../adapter/pi/usage-parser.js";import{SessionScanCache as E,resolveCodexLeafDirs as St,resolveClaudeLeafDirs as bt,resolveAcpLeafDirs as wt,resolvePiLeafDirs as Ct,resolveCodeWhaleLeafDirs as At,resolveCursorLeafDirs as kt,resolveOpenCodeLeafDirs as Rt,resolveReasonixLeafDirs as yt}from"./session-scan-cache.js";import{log as h,ConversationLog as Et,AgentApiPacketLog as $t,BridgeEventLog as Tt,GRIX_PATHS as T}from"../core/log/index.js";import{RevokeHandler as Pt}from"./revoke-handler.js";import{AdapterPool as xt,PoolFullError as Ht}from"./adapter-pool.js";import{parseSessionControlCommand as Lt,handleSessionControlCommand as ue,handleSessionControlLocalAction as Mt}from"./session-controller.js";import{isOpenSessionDirectiveMessage as It,parseAgentQuestionReplyMessage as Dt}from"../core/protocol/interaction-parser.js";import{handleAcpSetModel as he,handleAcpSetMode as ge,resolveAcpInitialDefaults as Qt}from"./acp-toolbar-persist.js";import{SessionBindingStore as Bt}from"../core/persistence/session-binding-store.js";import{handleFileListAction as qt,handleCreateFolderAction as Ot,serveLocalFile as Ut,realHomeDir as pe}from"../core/files/index.js";import{getMachineName as Ft}from"../core/util/index.js";import{uploadReplyFileToAgentMedia as Wt}from"../core/protocol/agent-api-media.js";import{ActiveEventStore as Nt}from"../core/persistence/active-event-store.js";import{DEFAULT_CONNECTOR_RUNTIME_CONFIG as Kt,applyConnectorRuntimeConfigPatch as Gt,extractConnectorRuntimeConfigPatch as zt}from"./runtime-config.js";import{DEFAULT_QUOTE_TRIGGER_BY_ADAPTER as jt,SendController as Vt}from"./send-controller.js";import{sharedProviderQuotaService as Y,detectProviderFromModel as Q,normalizeProviderId as J,readPiProviderSettings as Yt,readOpenCodeProviderSettings as Jt,providerQuotaToRateLimits as fe,providerQuotaToCodexRateLimits as me,isOpenaiCodexProviderName as Xt,queryOpenaiCodexQuota as _e,openaiCodexQuotaCacheKey as Zt}from"../core/provider-quota/index.js";import{queryKiroQuota as X}from"../core/provider-quota/kiro.js";import{buildToolUseCard as H,buildToolResultCard as L,buildLocalGrixCardLink as ve}from"./tool-card-utils.js";import{planRawEventDelivery as ei,buildAuxiliaryDetailText as ti}from"./raw-event-delivery.js";import{DeferredEventManager as ii}from"./deferred-events.js";import{buildAgentProbeResult as si,PROBE_CACHE_TTL_STATIC_MS as ni,PROBE_CACHE_TTL_FULL_MS as oi}from"./probe-helper.js";import{BridgeAuditController as ri}from"../audit/integration/bridge-audit-controller.js";import{isSettlableAuditProducer as ai,NoopAuditProducer as di}from"../audit/producer/audit-producer.js";import{buildAuditStatePayload as Z,AuditPreparationFailedError as ci,AuditTurnScopeUnsupportedError as li}from"../audit/core/audit-state.js";import{extractAuditOptions as ui,stripAuditOptions as hi}from"../audit/core/audit-options.js";const gi=600*1e3,pi=60*1e3,Se=30*1e3,fi=10*1e3,mi=10*1e3;function ee(B,e){return JSON.stringify({skills:B,library_skills:e})}function _i(B,e,s){const t=Ce("sha256").update(B).update("\0").update(e).update("\0").update(s).digest("hex");return P.join(T.data,"audit-source","reasonix",`${t}.jsonl`)}const U=new Set(["claude","acp","agy","cursor","codex"]),vi=new Set(["claude","codex","cursor","codewhale","opencode","pi","openhuman","agy","acp"]),te=3;class zs{config;name;aibotHandle;aibotConfig;pool;stopped=!1;revokeHandler=new Pt;sessionBindings=new Map;deferredMgr;sendCtrl=new Vt(Kt);bindingStore;globalConfigStore;upgradeTrigger=null;agentDeletedHandler=null;shareSetHandler=null;skillSyncHandler=null;providerConfigHandler=null;relayStateApplyPorts=null;relayStateSyncer=null;agentProfile={agentName:"",introduction:""};activeEventStore;cachedRateLimits=null;cachedRateLimitsSampledAtMs=null;cachedCodexContextWindow=null;cachedCodexTokenUsage=null;cachedCodexUsageSampledAtMs=null;cachedAcpContextWindow=null;cachedAcpContextWindowSampledAtMs=null;cachedClaudeRateLimitState=null;cachedProviderQuota=null;cachedProviderQuotaSampledAtMs=null;cachedProviderQuotaKey=null;sessionProviderHints=new Map;sessionProviderQuotas=new Map;sessionProviderMeta=new Map;lastModelSwitchQuotaRefresh=null;claudeWorkerStatus=new Map;lastReportedSkillsHash="";lastReportedSkillsWireHash="";conversationLog=null;packetLog=null;providerQuotaTimer=null;eventSessionIndex=new Map;inflightEvents=new Map;restartCount=new Map;selfDrivenSessions=new Set;selfDrivenLabels=new Map;probeCache=new Map;auditController;auditLocalActionHandler=null;sessionScanCache;reasonixTitleScan=null;isRateLimitsCacheFresh(e){if(!Number.isFinite(e))return!1;const s=Number(e);return s>0&&Date.now()-s<=pi}async resolveProviderQuotaSource(e){if(e?.disabled||e?.providerId==="openai_codex")return null;let s=this.config.providerBaseUrl??this.config.agent.provider?.baseUrl,t=this.config.providerApiKey??this.config.agent.provider?.apiKey;if((!s||!t)&&(this.config.adapterType??"acp")==="claude"){const i=Ke();s||(s=(i.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(i.ANTHROPIC_API_KEY??"").trim()||(i.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!s||!t)&&(this.config.adapterType??"acp")==="codex"){const i=rt();!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if((!s||!t)&&(this.config.adapterType??"acp")==="acp"&&this.config.aibot.clientType==="kimi"){const i=await at();!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if((!s||!t)&&(this.config.adapterType??"acp")==="pi"){const i=Yt(e);!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if((!s||!t)&&(this.config.adapterType??"acp")==="opencode"){const i=Jt(e);!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if(!s||!t)return null;const o=J(e?.providerId)??Q(e?.model)?.id??J(this.config.agent.provider?.providerId)??Q(this.config.agent.provider?.model)?.id;return{baseUrl:s,...this.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:this.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...o?{providerId:o}:{}}}async maybeQueryProviderQuota(e=!1,s){if(this.config.aibot.clientType==="kiro"){if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota)return this.cachedProviderQuota;try{const i=await X();return this.cachedProviderQuota=i,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro",h.info(this.name,`[provider-quota] kiro queried: success=${i.success}`+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.planName?` plan=${i.planName}`:"")+(i.error?` error=${i.error}`:"")),i}catch(i){return h.warn(this.name,`[provider-quota] kiro query failed: ${i instanceof Error?i.message:String(i)}`),null}}if(s?.providerId==="openai_codex")try{const i=await _e();return i.quota.success?i.quota:null}catch(i){return h.warn(this.name,`[provider-quota] openai_codex query failed: ${i instanceof Error?i.message:String(i)}`),null}const t=await this.resolveProviderQuotaSource(s);if(!t)return null;const o=Y.cacheKey(t);if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota&&this.cachedProviderQuotaKey===o)return this.cachedProviderQuota;try{const i=await Y.query(t,{fresh:e}),n=i.quota;return this.cachedProviderQuota=n,this.cachedProviderQuotaSampledAtMs=i.sampledAt,this.cachedProviderQuotaKey=i.cacheKey,h.info(this.name,`[provider-quota] queried: provider=${n.provider} success=${n.success}`+(n.tiers.length>0?` tiers=${n.tiers.map(r=>`${r.name}=${r.usedPercent}%`).join(",")}`:"")+(n.balance?` balance=${n.balance.remaining} ${n.balance.unit}`:"")+(n.error?` error=${n.error}`:"")),n}catch(i){return h.warn(this.name,`[provider-quota] query failed: ${i instanceof Error?i.message:String(i)}`),null}}startProviderQuotaTimer(){this.providerQuotaTimer||(this.providerQuotaTimer=setInterval(()=>{if(this.stopped){this.stopProviderQuotaTimer();return}this.refreshAndPushProviderQuota().catch(()=>{})},Se),h.info(this.name,`[provider-quota-timer] started (interval=${Se}ms)`))}stopProviderQuotaTimer(){this.providerQuotaTimer&&(clearInterval(this.providerQuotaTimer),this.providerQuotaTimer=null,h.info(this.name,"[provider-quota-timer] stopped"))}async refreshAndPushProviderQuota(e=!1){try{let s;if(this.config.aibot.clientType==="kiro")s=await X(),this.cachedProviderQuota=s,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro";else{const t=[...this.sessionBindings.entries()].filter(([o,i])=>!!i&&this.sessionProviderHints.has(o));if(t.length>0&&await Promise.all(t.map(([o,i])=>this.refreshProviderQuotaForSession(o,i,e))),t.length===this.sessionBindings.size&&t.length>0)return;s=await this.maybeQueryProviderQuota(e)}s?.success&&this.pushProviderQuotaToBindings(s,this.sessionProviderHints.size>0)}catch{}}pushProviderQuotaToBindings(e,s=!1){const t=this.providerQuotaToRateLimits(e);for(const[o,i]of this.sessionBindings.entries()){if(!i||s&&this.sessionProviderHints.has(o))continue;const n={provider_quota:e};t&&(n.rate_limits=t);const r=this.cachedAcpContextWindow;r&&("usedPercentage"in r?n.context_window={usedPercentage:r.usedPercentage,remainingPercentage:100-r.usedPercentage}:n.context_window=r),this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"ready",cwd:i,meta:n})}}enrichProviderQuotaMeta(e,s="standard",t=this.cachedProviderQuota,o=this.cachedProviderQuotaSampledAtMs){const i={...e??{}};if(!t?.success||(i.provider_quota||(i.provider_quota=t),i.rate_limits))return i;if(s==="codex"){const r=me(t,o??Date.now());return r&&(i.rate_limits=r.rateLimits,i.rate_limit_primary_percent=r.primaryPercent,i.rate_limit_secondary_percent=r.secondaryPercent,i.rate_limit_primary_window_min=r.primaryWindowMin,i.rate_limit_secondary_window_min=r.secondaryWindowMin),i}const n=fe(t,o??Date.now());return n&&(i.rate_limits=n),i}providerQuotaMetaPayload(e,s,t){let o=this.cachedProviderQuota,i=this.cachedProviderQuotaSampledAtMs,n=!1;if(s){const a=typeof e?.model_provider=="string"?e.model_provider:void 0,d=typeof e?.model_id=="string"?e.model_id:void 0,c=J(a)??Q(a)?.id??Q(d)?.id??(Xt(a)?"openai_codex":null);if(c||d){const u=a?.trim().toLowerCase()??"",g=u==="grix"||u.startsWith("grix-"),f={...c?{providerId:c}:{},...d?{model:d}:{},...!!a&&!g&&!c?{disabled:!0}:{}},S=this.sessionProviderHints.get(s),m=S?.providerId!==f.providerId||S?.model!==f.model||S?.disabled!==f.disabled;this.sessionProviderHints.set(s,f),this.sessionProviderMeta.set(s,{...e??{}}),m&&this.sessionProviderQuotas.delete(s),(m||!this.sessionProviderQuotas.has(s))&&t&&this.refreshProviderQuotaForSession(s,t,!1)}const l=this.sessionProviderQuotas.get(s);n=this.sessionProviderHints.has(s),n&&(o=null,i=null),l&&(o=l.quota,i=l.sampledAt)}const r=this.enrichProviderQuotaMeta(e,"standard",o,i);return n&&(r.provider_quota||(r.provider_quota=null),r.rate_limits||(r.rate_limits=null)),Object.keys(r).length>0?{meta:r}:{}}async refreshProviderQuotaForSession(e,s,t){const o=this.sessionProviderHints.get(e);if(!o)return;if(o.disabled){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=hint_disabled providerId=${o.providerId??""} model=${o.model??""}`);return}const i=`${o.providerId??""}|${o.model??""}|false`;try{let n,r,a;if(o.providerId==="openai_codex"){const u=this.sessionProviderQuotas.get(e);if(!t&&u&&u.quota.success&&u.cacheKey.startsWith("openai_codex|")&&this.isRateLimitsCacheFresh(u.sampledAt))n=u.quota,r=u.sampledAt,a=u.cacheKey;else{const g=await _e();n=g.quota,r=Date.now(),a=Zt(g.accountKey)}}else{const u=await this.resolveProviderQuotaSource(o);if(!u){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=no_source providerId=${o.providerId??""} model=${o.model??""}`);return}const g=await Y.query(u,{fresh:t});n=g.quota,r=g.sampledAt,a=g.cacheKey}const d=this.sessionProviderHints.get(e);if(`${d?.providerId??""}|${d?.model??""}|${d?.disabled===!0}`!==i)return;if(h.info(this.name,`[provider-quota] queried: provider=${n.provider} success=${n.success}`+(n.tiers.length>0?` tiers=${n.tiers.map(u=>`${u.name}=${u.usedPercent}%`).join(",")}`:"")+(n.balance?` balance=${n.balance.remaining} ${n.balance.unit}`:"")+(n.error?` error=${n.error}`:"")+` session=${e}`),!n.success){const u=this.sessionProviderQuotas.get(e);(!u?.quota.success||u.cacheKey!==a)&&this.sessionProviderQuotas.delete(e);return}this.sessionProviderQuotas.set(e,{quota:n,sampledAt:r,cacheKey:a});const l=this.enrichProviderQuotaMeta(this.sessionProviderMeta.get(e),"standard",n,r);this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:s,meta:l})}catch(n){h.warn(this.name,`[provider-quota] session query failed: session=${e} ${n instanceof Error?n.message:String(n)}`)}}refreshQuotaAfterModelSwitch(e,s,t){const o=s.trim();if(!e||!o)return;const i=t?.trim()||void 0,n=`${e}|${i??""}|${o}`,r=Date.now();this.lastModelSwitchQuotaRefresh&&this.lastModelSwitchQuotaRefresh.key===n&&r-this.lastModelSwitchQuotaRefresh.at<fi||(this.lastModelSwitchQuotaRefresh={key:n,at:r},this.doRefreshQuotaAfterModelSwitch(e,o,i).catch(a=>{h.warn(this.name,`[provider-quota] model-switch refresh failed: session=${e} model=${o} ${a instanceof Error?a.message:String(a)}`)}))}async doRefreshQuotaAfterModelSwitch(e,s,t){const o=this.sessionProviderHints.get(e);if(o||t){const n=t??Q(s)?.id??o?.providerId,r={...n?{providerId:n}:{},model:s,...o?.disabled?{disabled:!0}:{}},a=o?.providerId!==r.providerId||o?.model!==r.model||o?.disabled!==r.disabled;this.sessionProviderHints.set(e,r),a&&this.sessionProviderQuotas.delete(e);const d=this.sessionBindings.get(e)??this.bindingStore.get(e)?.cwd??"";(a||!this.sessionProviderQuotas.has(e))&&d&&await this.refreshProviderQuotaForSession(e,d,!0);return}const i=await this.maybeQueryProviderQuota(!0,{model:s});i?.success&&this.pushProviderQuotaToBindings(i,this.sessionProviderHints.size>0)}getFreshClaudeRateLimitState(){const e=this.cachedClaudeRateLimitState;return e&&this.isRateLimitsCacheFresh(e.sampledAt)?e:null}getFreshCodexGlobalRateLimitCache(){const e=this.cachedRateLimits,s=this.cachedCodexContextWindow,t=this.cachedCodexTokenUsage;return{sampledAt:Math.max(this.cachedRateLimitsSampledAtMs??0,this.cachedCodexUsageSampledAtMs??0)||null,rateLimits:e,contextWindow:s,tokenUsage:t,hasData:!!(e||s||t)}}getStatus(){const e=this.pool?.getStatus()??{total:0,ready:0,busy:0};return{name:this.name,agentId:this.config.aibot.agentId,alive:!this.stopped,busy:e.busy>0,exhausted:this.pool?[...this.pool.getAllSlots()].some(s=>s.respawn.exhausted):!1,adapterType:this.config.adapterType??"acp",clientType:this.config.aibot.clientType,pool:e}}hasPendingWork(){return this.pool?.hasPendingWork()??!1}hasPendingOrBackgroundWork(){return this.pool?.hasPendingOrBackgroundWork()??!1}relayEnvStale=!1;relayEnvSettledHandler;async recycleAdaptersForRelayChange(){if(!this.pool)return this.relayEnvStale=!1,!0;if(this.hasPendingWork())return this.relayEnvStale=!0,h.info(this.name,"relay changed but agent is busy; adapters keep the old env until the next message (marked stale)"),!1;const e=[...this.pool.getAllSlots()];let s=0,t=!1;for(const o of e){if(this.hasPendingWork())return this.relayEnvStale=!0,h.info(this.name,"new work arrived while recycling; remaining adapters stay stale until the next message"),!1;let i=!1;await this.pool.removeSlot(o.sessionId).catch(n=>{t=!0,i=!0,h.warn(this.name,`failed to recycle adapter slot ${o.sessionId} after relay change: ${n}`)}),i||(s+=1)}return s>0&&h.info(this.name,`recycled ${s} adapter slot(s) so the new Grix relay env takes effect`),t?(this.relayEnvStale=!0,!1):(this.relayEnvStale=!1,this.relayEnvSettledHandler?.(),!0)}setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}providerResolver;setProviderResolver(e){this.providerResolver=e}hasStaleRelayEnv(){return this.relayEnvStale}markRelayEnvStale(){this.relayEnvStale=!0}async probe(e={}){const s=e.conversation?"full":"static",t=e.conversation?oi:ni;if(!e.fresh){const a=this.probeCache.get(s);if(a&&Date.now()-a.sampledAt<t)return{...a.result,cached:!0}}const o=this.config.adapterType??"acp",i=this.createAdapter(o,"__probe__"),n=e.conversation&&o==="acp"?()=>this.runAcpConversationProbe(i,e.timeoutMs??1e4):void 0;let r;try{r=await si({adapter:i,agentName:this.name,clientType:this.config.aibot.clientType,adapterType:o,providerBaseUrl:this.config.providerBaseUrl??null,opts:e,launchConversationProbe:n})}finally{i.stop().catch(()=>{})}return this.probeCache.set(s,{result:r,sampledAt:r.probed_at}),r}async runAcpConversationProbe(e,s){const t=Date.now(),o="__probe__",i=`probe-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,n=this.config.agent.cwd||we(),r=()=>Date.now()-t;try{await e.start()}catch(u){return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_failed",message:`start failed: ${u instanceof Error?u.message:String(u)}`}}}if(!e.isAlive())return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"process_not_started",message:"agent process not alive"}};if(e instanceof y)try{await e.bindSession(o,n)}catch{}let a=null;const d=new Promise(u=>{a=g=>{g===i&&u()},e.on("eventDone",a)});e.deliverInboundEvent({event_id:i,session_id:o,content:"ping",msg_id:i}),e.deliverStopEvent(i,o);let c=null;const l=await Promise.race([d.then(()=>!1),new Promise(u=>{c=setTimeout(()=>u(!0),s)})]);return c&&clearTimeout(c),a&&e.removeListener("eventDone",a),l?{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_timeout",message:`no eventDone within ${s}ms`}}:{attempted:!0,ok:!0,latency_ms:r()}}constructor(e,s,t=new di){this.config=e,this.auditController=new ri(t,{onAuditState:i=>{try{this.aibotHandle.sendAuditState(Z(i,Date.now()))}catch{}}}),ai(t)&&t.addJobSettledHandler((i,n)=>{this.auditController.handleJobSettled(i,n)}),this.name=e.name;const o=e.adapterType??"acp";if(this.sendCtrl.setDefaultQuoteTrigger(jt[o]),this.aibotConfig={...e.aibot,...o==="claude"?{localActions:e.aibot.localActions??["session_control","claude_interaction_reply","get_session_usage","get_rate_limits","set_model","set_mode","set_reasoning_effort","thread_compact","get_agent_global_config",...ke]}:{}},e.eventQueue&&(this.aibotConfig.concurrency={max_concurrent:e.eventQueue.maxConcurrent,max_queued:e.eventQueue.maxQueued,queue_timeout_ms:e.eventQueue.queueTimeoutMs,cancelable_queued:e.eventQueue.cancelableQueued,cancelable_running:e.eventQueue.cancelableRunning}),this.conversationLog=e.logDir?new Et(e.logDir):null,this.packetLog=e.logDir?new $t(e.logDir):null,this.bindingStore=new Bt(e.bindingsPath,e.legacyBindingsPath),this.bindingStore.load(),this.globalConfigStore=s??null,this.deferredMgr=new ii(this.name),this.activeEventStore=e.activeEventStorePath?new Nt(e.activeEventStorePath):null,o==="codex")this.sessionScanCache=new E(dt,St);else if(o==="claude")this.sessionScanCache=new E(ct,bt);else if(o==="pi"){const i=e.agent.env?.PI_CODING_AGENT_DIR;this.sessionScanCache=new E(()=>pt(void 0,i),()=>Ct(void 0,i))}else if(o==="codewhale")this.sessionScanCache=new E(ft,At);else if(o==="cursor")this.sessionScanCache=new E(mt,kt);else if(o==="opencode")this.sessionScanCache=new E(_t,Rt);else if(o==="agy")this.sessionScanCache=new E(()=>[],()=>[]);else{e.aibot.clientType?.trim().toLowerCase()==="reasonix"&&(this.reasonixTitleScan=new E(gt,yt));const i=ut(e.aibot.clientType);this.sessionScanCache=i?new E(()=>ht(void 0,i),()=>wt(void 0,i)):new E(()=>[],()=>[])}}async start(){await nt({agentName:this.name,adapterType:this.config.adapterType??"acp",command:this.config.agent.command,piConfigDir:this.config.agent.env?.PI_CODING_AGENT_DIR,hasProvider:!!this.config.agent.provider,boundCwds:[...this.bindingStore.entries()].map(([,i])=>String(i.cwd??""))}).then(i=>{i.length>0&&h.info(this.name,`restored native provider config after relay disable: ${i.join(", ")}`)}).catch(i=>{h.warn(this.name,`native provider residue sweep failed: ${i instanceof Error?i.message:String(i)}`)}),(this.config.adapterType??"acp")==="claude"&&(await z().catch(()=>{}),this.maybeQueryProviderQuota().catch(()=>{}));const e=!!(this.config.providerBaseUrl&&this.config.providerApiKey||this.config.agent.provider?.baseUrl&&this.config.agent.provider?.apiKey),s=(this.config.adapterType??"acp")==="pi",t=(this.config.adapterType??"acp")==="opencode";this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi"||e?(this.maybeQueryProviderQuota().catch(()=>{}),this.startProviderQuotaTimer()):(s||t)&&this.startProviderQuotaTimer(),(this.config.adapterType??"acp")==="codex"&&this.maybeQueryProviderQuota().catch(()=>{}),(this.config.adapterType??"acp")==="opencode"&&this.maybeQueryProviderQuota().catch(()=>{}),await this.connectAibot(),this.sendCtrl.bind(this.aibotHandle);const o=this.config.adapterType??"acp";this.pool=new xt({maxPoolSize:this.config.poolMaxSize??20,idleTimeoutMs:this.config.poolIdleTimeoutMs??18e5,eventQueue:this.config.eventQueue},i=>{const n=this.createAdapter(o,i);return n instanceof y&&n.on("acpSessionReady",r=>{this.bindingStore.setAcpSessionId(i,r),this.sessionScanCache.invalidate()}),n},(i,n)=>{this.aibotHandle.sendEventAck({event_id:i,session_id:n,received_at:Date.now()})}),this.pool.setEventStateHandler((i,n,r,a)=>{if(h.info(this.name,`[queue-debug] send event_state session=${n} event=${i} state=${r} queue_pos=${a?.queue_position??""} queue_total=${a?.queue_total??""}`),this.aibotHandle.sendEventState({event_id:i,session_id:n,state:r,content_preview:a?.content_preview,content:a?.content,queue_position:a?.queue_position,queue_total:a?.queue_total,actions:a?.actions,reason:a?.reason,held:a?.held,held_reason:a?.held_reason,updated_at:Date.now()}),this.pushQueueSnapshotForSession(n),r==="canceled"||r==="failed"){const d=r==="canceled"?"canceled":"failed";this.aibotHandle.sendEventResult({event_id:i,status:d,msg:a?.reason,updated_at:Date.now()}),this.auditController.closeWithoutAdapter(i,d,a?.reason,{queueTerminalState:r}),this.discardEventTrackingState(i)}}),this.pool.setQueueComposingHandler((i,n,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:"composing",active:n,...n?{ttl_ms:3e4,ref_event_id:r}:{}})}),this.pool.setInternalErrorHandler(i=>{this.handleSessionInternalError(i).catch(n=>{h.error(this.name,`[recovery] handleSessionInternalError failed event=${i.eventId} session=${i.sessionId}: ${n instanceof Error?n.message:String(n)}`)})}),this.pool.setEventStartedHandler((i,n)=>{if(this.reportSessionSkills(n),this.config.adapterType!=="claude")return;this.claudeWorkerStatus.set(n,"busy");const r=this.bindingStore.get(n);r?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"busy",cwd:r.cwd,meta:this.buildClaudeToolbarMeta(n)})}),this.pool.setEventDoneHandler((i,n)=>{this.markAuditAdapterClosed(i,n);const r=this.config.adapterType??"acp";if(r==="claude"){this.claudeWorkerStatus.set(n,"ready");const a=this.bindingStore.get(n);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:a.cwd,meta:this.buildClaudeToolbarMeta(n)})}else if(r==="agy"){const a=this.bindingStore.get(n);if(a?.cwd){const d=this.buildAgyToolbarMeta(n),c=d?.available_models??[];h.info(this.name,`[agy-toolbar-diag] eventDone push binding card session=${n} model_id=${String(d?.model_id??"")} available_models=${c.length} meta_keys=${d?Object.keys(d).join(","):"<none>"}`),this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:a.cwd,meta:d})}else h.info(this.name,`[agy-toolbar-diag] eventDone skip binding card: no binding cwd session=${n}`)}}),this.pool.setSessionActivityHandler((i,n,r)=>{const a=this.selfDrivenSessions.has(i),d=this.selfDrivenLabels.get(i);n?(this.selfDrivenSessions.add(i),r&&this.selfDrivenLabels.set(i,r),this.aibotHandle.sendSessionActivitySet({session_id:i,kind:"composing",active:!0,ttl_ms:9e4})):(this.selfDrivenSessions.delete(i),this.selfDrivenLabels.delete(i),a&&this.aibotHandle.sendSessionActivitySet({session_id:i,kind:"composing",active:!1})),(a!==n||n&&r!==void 0&&r!==d)&&this.pushQueueSnapshotForSession(i)}),this.pool.startIdleSweep(),h.info(this.name,`Ready (adapter: ${o}, poolMax: ${this.config.poolMaxSize??20})`)}async stop(){this.stopped=!0,this.pool?.stopIdleSweep(),this.stopProviderQuotaTimer();const e=this.pool?.collectActiveEventIds()??[],s=new Map(e.map(i=>[i,this.eventSessionIndex.get(i)]));e.length>0&&this.activeEventStore&&await this.activeEventStore.save(e);for(const i of e)h.info(this.name,`Canceling active event on shutdown: ${i}`),this.sendEventResultWithCleanup(i,"canceled","process shutting down");e.length>0&&await new Promise(i=>setTimeout(i,100)),this.pool?.clearActiveEventsForShutdown();for(const i of e){const n=s.get(i),r=n?this.pool?.getSlot(n):void 0;this.auditController.markAdapterClosed(i,r?.adapter.takeAuditBoundary?.(i)??{processTerminated:!0})}const t=this.deferredMgr.getAllDeferredEvents();for(const i of t)h.info(this.name,`Failing deferred event on shutdown: ${i.event_id}`),this.sendEventResultWithCleanup(i.event_id,"failed","process shutting down"),this.auditController.markAdapterClosed(i.event_id,{adapterNotStarted:!0,processTerminated:!0});const o=this.pool?.drainAllQueuedEvents()??[];for(const i of o)h.info(this.name,`Failing queued event on shutdown: ${i.event_id}`),this.sendEventResultWithCleanup(i.event_id,"failed","process shutting down"),this.auditController.markAdapterClosed(i.event_id,{adapterNotStarted:!0,processTerminated:!0});this.deferredMgr.clearAll(),await this.pool?.stop(),this.aibotHandle?.disconnect(),e.length>0&&this.activeEventStore&&await this.activeEventStore.save([]),this.eventSessionIndex.clear(),this.inflightEvents.clear(),this.restartCount.clear(),this.auditController.dispose()}resolveSpawnEnv(){const e=this.providerResolver?this.providerResolver():this.config.agent.provider,s=tt(this.config.agent.clientType,e),t=this.config.agent.env;let o=Object.keys(s).length>0?{...s,...t}:t;if(it(s)){const i=de()?.getRuntimeInfo(),n={...t??{},...s},r=st(n,{proxyUrl:i?.proxyUrl,caCertPath:i?.caCertPath,caBundlePath:i?.caBundlePath});return delete r.ANTHROPIC_API_KEY,delete r.CLAUDE_CODE_OAUTH_TOKEN,r}if(ce(this.config.agent.clientType)){const i=Ye(this.name);i&&(o={...o??{},...i})}return ze(o,this.name,this.config.agent.clientType)}createAdapter(e,s){switch(e){case"claude":return this.createClaudeAdapter(s);case"codex":return this.createCodexAdapter(s);case"pi":return this.createPiAdapter(s);case"openhuman":return this.createOpenHumanAdapter(s);case"codewhale":return this.createCodeWhaleAdapter(s);case"cursor":return this.createCursorAdapter(s);case"opencode":return this.createOpenCodeAdapter(s);case"agy":return this.createAgyAdapter(s);default:return this.createAcpAdapter(s)}}createCursorAdapter(e){const s={...this.config.adapterOptions??{}};s.bindingStore=this.bindingStore,s.aibotSessionId=e;const t=this.bindingStore.get(e),o=this.resolveSessionModelId(e);o&&(s.model=o);const i=this.bindingStore.getCursorModeId(e),n=i??"full_auto";i||this.bindingStore.setCursorModeId(e,n),s.mode=n,t?.cwd&&(s.workspace=t.cwd);const r={sendStreamChunk:(a,d,c,l,u,g,v)=>{this.sendStreamChunkByRuntimeConfig(a,d,c,l,u,g,v)},sendEventResult:(a,d,c)=>{this.sendEventResultWithCleanup(a,d,c)},sendEventAck:(a,d)=>{this.aibotHandle.sendEventAck({event_id:a,session_id:d,received_at:Date.now()})},sendRawEventEnvelope:(a,d,c)=>{this.deliverRawEventEnvelope(a,d,c,"cursor",this.buildCursorRawEventFallbackText(c))},sendAgentQuestionCard:(a,d,c)=>{const l=c.questions.map(g=>g.header).join(", "),u=ve(`[Agent Question] ${c.request_id}`,"agent_question",c);this.aibotHandle.sendText({event_id:a,session_id:d,content:u,msg_type:1,extra:{card_type:"agent_question",summary_text:l}})},agentInvoke:async(a,d,c)=>this.platformInvoke(a,d,c),sendLocalActionResult:(a,d,c,l,u)=>{this.aibotHandle.sendLocalActionResult({action_id:a,status:d,...c!==void 0?{result:c}:{},...l?{error_code:l}:{},...u?{error_msg:u}:{}})},sendUpdateBindingCard:(a,d,c,l)=>{this.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:d,cwd:c,...l?{meta:l}:{}})},getAgentProfile:()=>this.agentProfile};return new q({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:s},r)}createClaudeAdapter(e){const s={sendReply:(i,n,r,a,d)=>{this.sendReplyByRuntimeConfig(i,n,r,a,d)},sendStreamChunk:(i,n,r,a,d,c,l)=>{this.sendStreamChunkByRuntimeConfig(i,n,r,a,d,c,l)},sendMedia:(i,n,r,a,d,c,l)=>{this.aibotHandle.sendMedia({event_id:i,session_id:n,content:r,msg_type:2,quoted_message_id:d||void 0,client_msg_id:c||void 0,extra:l?{media_caption:a,...l}:{media_caption:a}})},sendEventResult:(i,n,r,a)=>{this.sendEventResultWithCleanup(i,n,r,a)},sendEventAck:(i,n)=>{this.aibotHandle.sendEventAck({event_id:i,session_id:n,received_at:Date.now()})},agentInvoke:async(i,n,r)=>this.platformInvoke(i,n,r),sendLocalActionResult:(i,n,r,a,d)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:n,...r!==void 0?{result:r}:{},...a?{error_code:a}:{},...d?{error_msg:d}:{}})},sendToolUse:(i,n,r,a)=>{this.sendToolExecutionCard(i,n,H(r,a))},sendToolResult:(i,n,r,a)=>{this.sendToolExecutionCard(i,n,L(r,a))},getWsUrl:()=>this.config.aibot.url,getAgentId:()=>this.config.aibot.agentId,getAgentProfile:()=>this.agentProfile,getApiKey:()=>this.config.aibot.apiKey,getActiveEventCount:()=>0,getPendingPermissionCount:()=>0,getPendingElicitationCount:()=>0,sendAgentQuestionCard:(i,n,r)=>{this.sendGrixAgentQuestionCard(i,n,r)},sendPermissionCard:i=>{this.sendGrixApprovalCard(i,"claude")},sendDirectMessage:i=>{this.aibotHandle.sendMsg({session_id:i.sessionId,msg_type:1,content:i.content,...i.clientMsgId?{client_msg_id:i.clientMsgId}:{},...i.quotedMessageId?{quoted_message_id:i.quotedMessageId}:{}})},onStatusLineUpdated:i=>{(i.rateLimits?.fiveHour||i.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=i);const n=this.bindingStore.get(e);n?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:this.claudeWorkerStatus.get(e)??"ready",cwd:n.cwd,meta:this.buildClaudeToolbarMeta(e)})},sendMcpFrame:i=>{this.aibotHandle.sendMcpFrame(e,i)}},t=this.config.adapterOptions??{},o={...t,sessionRuntimeResolver:()=>{const i=this.bindingStore.get(e),n=this.auditController.getSession(e);return{cwd:i?.cwd,modeId:i?.modeId??R.fullAuto,modelId:this.resolveSessionModelId(e),effort:this.resolveClaudeSessionEffort(e),pluginDir:t.pluginDir,claudeSessionId:i?.claudeSessionId,...n?{audit:{enabled:!0,profile:n.options.profile,capture:n.options.capture}}:{},onSessionIdAssigned:r=>{this.bindingStore.setClaudeSessionId(e,r),this.sessionScanCache.invalidate()}}}};return new M({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:o},s)}createCodexAdapter(e){let s=null;const t={sendEventResult:(r,a,d)=>{if(a!=="responded"){this.sendEventResultWithCleanup(r,a,d);return}this.sendCtrl.sendFinalStreamChunkReliable(r,e,`codex_terminal_fence_${r}`,5e3,!0).then(()=>this.sendEventResultWithCleanup(r,a,d),c=>{const l=`codex output acceptance fence failed: ${c instanceof Error?c.message:String(c)}`;this.sendEventResultWithCleanup(r,a==="responded"?"failed":a,a==="responded"?l:d)})},sendEventAck:(r,a)=>this.aibotHandle.sendEventAck({event_id:r,session_id:a,received_at:Date.now()}),sendCodexEvent:r=>{this.shouldDropCodexDisplayEvent(r.event_id,r.codex_method)||(this.captureCodexAuditOutput(r),this.aibotHandle.sendCodexEvent(this.stampCodexEventQuote(r)),this.logCodexEventToConversation(r))},sendRunError:(r,a,d)=>{this.sendRunErrorAsChunk(r,a,d)},sendUpdateBindingCard:(r,a,d,c)=>{const l={...c??{}};if(!l.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const u=this.providerQuotaToCodexRateLimits(this.cachedProviderQuota);u&&(l.rate_limits=u.rateLimits,l.rate_limit_primary_percent=u.primaryPercent,l.rate_limit_secondary_percent=u.secondaryPercent,l.rate_limit_primary_window_min=u.primaryWindowMin,l.rate_limit_secondary_window_min=u.secondaryWindowMin)}!l.provider_quota&&this.cachedProviderQuota?.success&&(l.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:r,worker_status:a,cwd:d,...Object.keys(l).length>0?{meta:l}:{}})},agentInvoke:async(r,a,d)=>this.platformInvoke(r,a,d),sendLocalActionResult:(r,a,d,c,l)=>this.aibotHandle.sendLocalActionResult({action_id:r,status:a,...d!==void 0?{result:d}:{},...c?{error_code:c}:{},...l?{error_msg:l}:{}}),sendSessionActivitySet:(r,a,d,c)=>{this.aibotHandle.sendSessionActivitySet({session_id:r,kind:a,active:d,...c??{}})},getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,onRateLimitsUpdated:r=>{this.cachedRateLimits=r,this.cachedRateLimitsSampledAtMs=Date.now(),this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const a=this.bindingStore.get(e);if(a?.cwd){const d=this.cachedRateLimitsSampledAtMs,c={rate_limits:{...r.primary.windowMinutes>0?{primary:r.primary}:{},...r.secondary.windowMinutes>0?{secondary:r.secondary}:{},sampledAt:d},rate_limit_primary_percent:r.primary.usedPercent,rate_limit_secondary_percent:r.secondary.usedPercent,rate_limit_primary_window_min:r.primary.windowMinutes,rate_limit_secondary_window_min:r.secondary.windowMinutes,credits:r.credits,...r.extras&&r.extras.length>0?{extra_limits:r.extras}:{},...s?.getEffortMeta()};this.cachedProviderQuota?.success&&(c.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:c})}},onContextWindowUpdated:r=>{if(!r)return;this.cachedCodexContextWindow=r,this.cachedCodexUsageSampledAtMs=Date.now();const a=this.bindingStore.get(e);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:{context_window:r,...s?.getEffortMeta()}})},onTokenUsageUpdated:r=>{r&&(this.cachedCodexTokenUsage=r,this.cachedCodexUsageSampledAtMs=Date.now())}},o=this.config.adapterOptions??{},i=this.globalConfigStore?.get(this.name),n=this.auditController.getAdapterPreparation(e);return s=new ie({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...o,model:this.resolveCodexSessionModelId(e)??o.model,collaborationMode:this.bindingStore.getCodexModeId(e)??this.resolveCodexNewSessionGlobalDefault(e,i?.codexModeId,r=>this.bindingStore.setCodexModeId(e,r))??o.collaborationMode,reasoningEffort:i?.codexReasoningEffort??o.reasoningEffort,serviceTier:this.bindingStore.getCodexServiceTier(e)??this.resolveCodexNewSessionGlobalDefault(e,i?.codexServiceTier,r=>this.bindingStore.setCodexServiceTier(e,r))??o.serviceTier,sandboxMode:i?.codexSandboxMode??o.sandboxMode,aibotSessionId:e,bindingStore:this.bindingStore,...oe(n?.options)?{rawApiCapture:{auditId:n.auditId,sessionId:e,spoolRootDir:P.join(T.data,"audit-replay","raw-spool")}}:{}}},t),s}createCodeWhaleAdapter(e){const s={sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),sendLocalActionResult:(o,i,n,r,a)=>this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}}),sendSessionActivitySet:(o,i,n,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:o,kind:i,active:n,...r??{}})},sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new se({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},s)}createPiAdapter(e){const s={sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n),h.info("bridge",`[pi] sendEventResult event=${o} status=${i}`)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),sendLocalActionResult:(o,i,n,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}})},sendSessionActivitySet:(o,i,n,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:o,kind:i,active:n,...r??{}})},sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d),a&&h.info("bridge",`[pi] sendFinalStreamChunk event=${o} seq=${r}`)},sendFinalStreamChunkReliable:this.reliableFinalWiring("pi"),sendThinking:(o,i,n)=>{this.sendThinkingByRuntimeConfig(o,i,n)},sendRunError:(o,i,n,r,a)=>{this.sendStreamChunkByRuntimeConfig(o,i,`
1
+ import T from"node:path";import{realpath as be,stat as W}from"node:fs/promises";import{tmpdir as we,homedir as N}from"node:os";import{createHash as Ce,randomUUID as K}from"node:crypto";import{ConnectionManager as Ae}from"../core/aibot/index.js";import{AUDIT_LOCAL_ACTION_TYPES as ke}from"../core/aibot/types.js";import{ClaudeAdapter as M}from"../adapter/claude/index.js";import{CodexAdapter as ie}from"../adapter/codex/index.js";import{PiAdapter as Re}from"../adapter/pi/index.js";import{AcpAdapter as y}from"../adapter/acp/index.js";import{OpenHumanAdapter as ye}from"../adapter/openhuman/index.js";import{CursorAdapter as q,CURSOR_MODE_OPTIONS as Ee,fetchCursorAccountUsage as $e}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as se}from"../adapter/codewhale/index.js";import{OpenCodeAdapter as G}from"../adapter/opencode/index.js";import{AgyAdapter as ne}from"../adapter/agy/index.js";import{getCachedAgyModels as Pe}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as Te,primeAgyQuotaInfo as xe}from"../adapter/agy/quota.js";import{LOCAL_ACTION_ERROR_CODES as x,LOCAL_ACTION_TYPES as C,SESSION_CONTROL_ERROR_CODES as p,SESSION_CONTROL_VERBS as _,SESSION_MODE_IDS as R}from"../adapter/claude/protocol-contract.js";import{AuditLocalActionHandler as He,isAuditLocalActionType as Le}from"../audit/query/audit-local-actions.js";import{AuditReplayQueryService as Me}from"../audit/query/audit-replay-query-service.js";import{resolveDefaultAuditStorageRootDir as Ie}from"../audit/runtime/default-audit-recorder.js";import{FileAuditReplayStore as De}from"../audit/storage/file-audit-replay-store.js";import{shouldEnableRawApiCapture as oe}from"../audit/raw-capture/types.js";import{parseClaudeSessionUsage as Qe}from"../adapter/claude/usage-parser.js";import"../adapter/claude/session-history.js";import"../adapter/codex/session-history.js";import"../adapter/pi/session-history.js";import"../adapter/opencode/session-history.js";import"../adapter/codewhale/session-history.js";import{SESSION_HISTORY_ERROR_CODES as O,SessionHistoryError as Be,getSessionHistoryReader as qe}from"../adapter/shared/session-history.js";import{resolveSkillScanMode as I}from"../adapter/claude/skill-scanner.js";import{buildReportedSkills as Oe}from"../default-skills/index.js";import{buildWireSkills as re}from"../core/skill-sync/sync-state.js";import{uploadSkill as Ue}from"../core/skill-sync/skill-upload.js";import{buildLibrarySkills as Fe}from"../core/skill-sync/library-skills.js";import{enableSkill as We,disableSkill as Ne,SkillEnableError as ae}from"../core/skill-sync/skill-enable.js";import{fetchAvailableModels as z,getCachedModels as j,readSettingsEnv as Ke}from"../adapter/claude/model-list.js";import{parseAcpSessionUsage as Ge}from"../adapter/acp/usage-parser.js";import{applyProxyEnv as ze,getProxyManager as de,relayHostsForClientType as je,buildGatewayRoute as Ve}from"../core/proxy/index.js";import{getKiroRelaySpawnEnv as Ye}from"../core/proxy/kiro-relay.js";import{supportsKiroCwRelay as ce}from"../core/config/provider-env.js";import{RelayFetchError as Je,deriveGatewayBaseUrls as le,fetchRelayCredentialWithRetry as Xe}from"../core/proxy/relay-credential-fetch.js";import{RelayStateSyncer as Ze}from"../core/proxy/relay-state-sync.js";import{isDirectRelayExplicitlyUnsupported as et}from"../core/proxy/relay-credential.js";import{buildProviderEnv as tt}from"../core/config/provider-env.js";import{CLAUDE_EFFORT_LEVELS as D,isClaudeDirectEnv as it,normalizeClaudeEffort as V,stripGrixRelayEnv as st}from"../core/config/claude-direct-env.js";import{sweepNativeProviderResidue as nt}from"./native-provider-sweep.js";import{parseCodexSessionUsage as ot}from"../adapter/codex/usage-parser.js";import{readCodexProviderSettings as rt}from"../adapter/codex/codex-trust.js";import{resolveKimiProviderSettings as at}from"../core/provider-quota/index.js";import{scanCodexSessions as dt}from"../adapter/codex/session-scanner.js";import{scanClaudeSessions as ct}from"../adapter/claude/session-scanner.js";import{reasonixStampFromSessionId as lt,resolveAcpAgentTypes as ut,scanAcpSessions as ht,scanReasonixSessionTitles as gt}from"../adapter/acp/session-scanner.js";import{scanPiSessions as pt}from"../adapter/pi/session-scanner.js";import{scanCodeWhaleSessions as ft}from"../adapter/codewhale/session-scanner.js";import{scanCursorSessions as mt}from"../adapter/cursor/session-scanner.js";import{scanOpenCodeSessions as _t}from"../adapter/opencode/session-scanner.js";import{parsePiSessionUsage as vt}from"../adapter/pi/usage-parser.js";import{SessionScanCache as E,resolveCodexLeafDirs as St,resolveClaudeLeafDirs as bt,resolveAcpLeafDirs as wt,resolvePiLeafDirs as Ct,resolveCodeWhaleLeafDirs as At,resolveCursorLeafDirs as kt,resolveOpenCodeLeafDirs as Rt,resolveReasonixLeafDirs as yt}from"./session-scan-cache.js";import{log as h,ConversationLog as Et,AgentApiPacketLog as $t,BridgeEventLog as Pt,GRIX_PATHS as P}from"../core/log/index.js";import{RevokeHandler as Tt}from"./revoke-handler.js";import{AdapterPool as xt,PoolFullError as Ht}from"./adapter-pool.js";import{parseSessionControlCommand as Lt,handleSessionControlCommand as ue,handleSessionControlLocalAction as Mt}from"./session-controller.js";import{isOpenSessionDirectiveMessage as It,parseAgentQuestionReplyMessage as Dt}from"../core/protocol/interaction-parser.js";import{handleAcpSetModel as he,handleAcpSetMode as ge,resolveAcpInitialDefaults as Qt}from"./acp-toolbar-persist.js";import{SessionBindingStore as Bt}from"../core/persistence/session-binding-store.js";import{handleFileListAction as qt,handleCreateFolderAction as Ot,serveLocalFile as Ut,realHomeDir as pe}from"../core/files/index.js";import{getMachineName as Ft}from"../core/util/index.js";import{uploadReplyFileToAgentMedia as Wt}from"../core/protocol/agent-api-media.js";import{ActiveEventStore as Nt}from"../core/persistence/active-event-store.js";import{DEFAULT_CONNECTOR_RUNTIME_CONFIG as Kt,applyConnectorRuntimeConfigPatch as Gt,extractConnectorRuntimeConfigPatch as zt}from"./runtime-config.js";import{DEFAULT_QUOTE_TRIGGER_BY_ADAPTER as jt,SendController as Vt}from"./send-controller.js";import{sharedProviderQuotaService as Y,detectProviderFromModel as Q,normalizeProviderId as J,readPiProviderSettings as Yt,readOpenCodeProviderSettings as Jt,providerQuotaToRateLimits as fe,providerQuotaToCodexRateLimits as me,isOpenaiCodexProviderName as Xt,queryOpenaiCodexQuota as _e,openaiCodexQuotaCacheKey as Zt}from"../core/provider-quota/index.js";import{queryKiroQuota as X}from"../core/provider-quota/kiro.js";import{buildToolUseCard as H,buildToolResultCard as L,buildLocalGrixCardLink as ve}from"./tool-card-utils.js";import{planRawEventDelivery as ei,buildAuxiliaryDetailText as ti}from"./raw-event-delivery.js";import{DeferredEventManager as ii}from"./deferred-events.js";import{buildAgentProbeResult as si,PROBE_CACHE_TTL_STATIC_MS as ni,PROBE_CACHE_TTL_FULL_MS as oi}from"./probe-helper.js";import{BridgeAuditController as ri}from"../audit/integration/bridge-audit-controller.js";import{isSettlableAuditProducer as ai,NoopAuditProducer as di}from"../audit/producer/audit-producer.js";import{buildAuditStatePayload as Z,AuditPreparationFailedError as ci,AuditTurnScopeUnsupportedError as li}from"../audit/core/audit-state.js";import{extractAuditOptions as ui,stripAuditOptions as hi}from"../audit/core/audit-options.js";const gi=600*1e3,pi=60*1e3,Se=30*1e3,fi=10*1e3,mi=10*1e3;function ee(B,e){return JSON.stringify({skills:B,library_skills:e})}function _i(B,e,s){const t=Ce("sha256").update(B).update("\0").update(e).update("\0").update(s).digest("hex");return T.join(P.data,"audit-source","reasonix",`${t}.jsonl`)}const U=new Set(["claude","acp","agy","cursor","codex"]),vi=new Set(["claude","codex","cursor","codewhale","opencode","pi","openhuman","agy","acp"]),te=3;class zs{config;name;aibotHandle;aibotConfig;pool;stopped=!1;revokeHandler=new Tt;sessionBindings=new Map;deferredMgr;sendCtrl=new Vt(Kt);bindingStore;globalConfigStore;upgradeTrigger=null;agentDeletedHandler=null;shareSetHandler=null;skillSyncHandler=null;providerConfigHandler=null;relayStateApplyPorts=null;relayStateSyncer=null;agentProfile={agentName:"",introduction:""};activeEventStore;cachedRateLimits=null;cachedRateLimitsSampledAtMs=null;cachedCodexContextWindow=null;cachedCodexTokenUsage=null;cachedCodexUsageSampledAtMs=null;cachedAcpContextWindow=null;cachedAcpContextWindowSampledAtMs=null;cachedClaudeRateLimitState=null;cachedProviderQuota=null;cachedProviderQuotaSampledAtMs=null;cachedProviderQuotaKey=null;sessionProviderHints=new Map;sessionProviderQuotas=new Map;sessionProviderMeta=new Map;lastModelSwitchQuotaRefresh=null;claudeWorkerStatus=new Map;lastReportedSkillsHash="";lastReportedSkillsWireHash="";conversationLog=null;packetLog=null;providerQuotaTimer=null;eventSessionIndex=new Map;inflightEvents=new Map;restartCount=new Map;selfDrivenSessions=new Set;selfDrivenLabels=new Map;probeCache=new Map;auditController;auditLocalActionHandler=null;sessionScanCache;reasonixTitleScan=null;isRateLimitsCacheFresh(e){if(!Number.isFinite(e))return!1;const s=Number(e);return s>0&&Date.now()-s<=pi}async resolveProviderQuotaSource(e){if(e?.disabled||e?.providerId==="openai_codex")return null;let s=this.config.providerBaseUrl??this.config.agent.provider?.baseUrl,t=this.config.providerApiKey??this.config.agent.provider?.apiKey;if((!s||!t)&&(this.config.adapterType??"acp")==="claude"){const i=Ke();s||(s=(i.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(i.ANTHROPIC_API_KEY??"").trim()||(i.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!s||!t)&&(this.config.adapterType??"acp")==="codex"){const i=rt();!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if((!s||!t)&&(this.config.adapterType??"acp")==="acp"&&this.config.aibot.clientType==="kimi"){const i=await at();!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if((!s||!t)&&(this.config.adapterType??"acp")==="pi"){const i=Yt(e);!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if((!s||!t)&&(this.config.adapterType??"acp")==="opencode"){const i=Jt(e);!s&&i.baseUrl&&(s=i.baseUrl),!t&&i.apiKey&&(t=i.apiKey)}if(!s||!t)return null;const o=J(e?.providerId)??Q(e?.model)?.id??J(this.config.agent.provider?.providerId)??Q(this.config.agent.provider?.model)?.id;return{baseUrl:s,...this.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:this.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...o?{providerId:o}:{}}}async maybeQueryProviderQuota(e=!1,s){if(this.config.aibot.clientType==="kiro"){if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota)return this.cachedProviderQuota;try{const i=await X();return this.cachedProviderQuota=i,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro",h.info(this.name,`[provider-quota] kiro queried: success=${i.success}`+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.planName?` plan=${i.planName}`:"")+(i.error?` error=${i.error}`:"")),i}catch(i){return h.warn(this.name,`[provider-quota] kiro query failed: ${i instanceof Error?i.message:String(i)}`),null}}if(s?.providerId==="openai_codex")try{const i=await _e();return i.quota.success?i.quota:null}catch(i){return h.warn(this.name,`[provider-quota] openai_codex query failed: ${i instanceof Error?i.message:String(i)}`),null}const t=await this.resolveProviderQuotaSource(s);if(!t)return null;const o=Y.cacheKey(t);if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota&&this.cachedProviderQuotaKey===o)return this.cachedProviderQuota;try{const i=await Y.query(t,{fresh:e}),n=i.quota;return this.cachedProviderQuota=n,this.cachedProviderQuotaSampledAtMs=i.sampledAt,this.cachedProviderQuotaKey=i.cacheKey,h.info(this.name,`[provider-quota] queried: provider=${n.provider} success=${n.success}`+(n.tiers.length>0?` tiers=${n.tiers.map(r=>`${r.name}=${r.usedPercent}%`).join(",")}`:"")+(n.balance?` balance=${n.balance.remaining} ${n.balance.unit}`:"")+(n.error?` error=${n.error}`:"")),n}catch(i){return h.warn(this.name,`[provider-quota] query failed: ${i instanceof Error?i.message:String(i)}`),null}}startProviderQuotaTimer(){this.providerQuotaTimer||(this.providerQuotaTimer=setInterval(()=>{if(this.stopped){this.stopProviderQuotaTimer();return}this.refreshAndPushProviderQuota().catch(()=>{})},Se),h.info(this.name,`[provider-quota-timer] started (interval=${Se}ms)`))}stopProviderQuotaTimer(){this.providerQuotaTimer&&(clearInterval(this.providerQuotaTimer),this.providerQuotaTimer=null,h.info(this.name,"[provider-quota-timer] stopped"))}async refreshAndPushProviderQuota(e=!1){try{let s;if(this.config.aibot.clientType==="kiro")s=await X(),this.cachedProviderQuota=s,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro";else{const t=[...this.sessionBindings.entries()].filter(([o,i])=>!!i&&this.sessionProviderHints.has(o));if(t.length>0&&await Promise.all(t.map(([o,i])=>this.refreshProviderQuotaForSession(o,i,e))),t.length===this.sessionBindings.size&&t.length>0)return;s=await this.maybeQueryProviderQuota(e)}s?.success&&this.pushProviderQuotaToBindings(s,this.sessionProviderHints.size>0)}catch{}}pushProviderQuotaToBindings(e,s=!1){const t=this.providerQuotaToRateLimits(e);for(const[o,i]of this.sessionBindings.entries()){if(!i||s&&this.sessionProviderHints.has(o))continue;const n={provider_quota:e};t&&(n.rate_limits=t);const r=this.cachedAcpContextWindow;r&&("usedPercentage"in r?n.context_window={usedPercentage:r.usedPercentage,remainingPercentage:100-r.usedPercentage}:n.context_window=r),this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"ready",cwd:i,meta:n})}}enrichProviderQuotaMeta(e,s="standard",t=this.cachedProviderQuota,o=this.cachedProviderQuotaSampledAtMs){const i={...e??{}};if(!t?.success||(i.provider_quota||(i.provider_quota=t),i.rate_limits))return i;if(s==="codex"){const r=me(t,o??Date.now());return r&&(i.rate_limits=r.rateLimits,i.rate_limit_primary_percent=r.primaryPercent,i.rate_limit_secondary_percent=r.secondaryPercent,i.rate_limit_primary_window_min=r.primaryWindowMin,i.rate_limit_secondary_window_min=r.secondaryWindowMin),i}const n=fe(t,o??Date.now());return n&&(i.rate_limits=n),i}providerQuotaMetaPayload(e,s,t){let o=this.cachedProviderQuota,i=this.cachedProviderQuotaSampledAtMs,n=!1;if(s){const a=typeof e?.model_provider=="string"?e.model_provider:void 0,d=typeof e?.model_id=="string"?e.model_id:void 0,c=J(a)??Q(a)?.id??Q(d)?.id??(Xt(a)?"openai_codex":null);if(c||d){const u=a?.trim().toLowerCase()??"",g=u==="grix"||u.startsWith("grix-"),f={...c?{providerId:c}:{},...d?{model:d}:{},...!!a&&!g&&!c?{disabled:!0}:{}},S=this.sessionProviderHints.get(s),m=S?.providerId!==f.providerId||S?.model!==f.model||S?.disabled!==f.disabled;this.sessionProviderHints.set(s,f),this.sessionProviderMeta.set(s,{...e??{}}),m&&this.sessionProviderQuotas.delete(s),(m||!this.sessionProviderQuotas.has(s))&&t&&this.refreshProviderQuotaForSession(s,t,!1)}const l=this.sessionProviderQuotas.get(s);n=this.sessionProviderHints.has(s),n&&(o=null,i=null),l&&(o=l.quota,i=l.sampledAt)}const r=this.enrichProviderQuotaMeta(e,"standard",o,i);return n&&(r.provider_quota||(r.provider_quota=null),r.rate_limits||(r.rate_limits=null)),Object.keys(r).length>0?{meta:r}:{}}async refreshProviderQuotaForSession(e,s,t){const o=this.sessionProviderHints.get(e);if(!o)return;if(o.disabled){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=hint_disabled providerId=${o.providerId??""} model=${o.model??""}`);return}const i=`${o.providerId??""}|${o.model??""}|false`;try{let n,r,a;if(o.providerId==="openai_codex"){const u=this.sessionProviderQuotas.get(e);if(!t&&u&&u.quota.success&&u.cacheKey.startsWith("openai_codex|")&&this.isRateLimitsCacheFresh(u.sampledAt))n=u.quota,r=u.sampledAt,a=u.cacheKey;else{const g=await _e();n=g.quota,r=Date.now(),a=Zt(g.accountKey)}}else{const u=await this.resolveProviderQuotaSource(o);if(!u){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=no_source providerId=${o.providerId??""} model=${o.model??""}`);return}const g=await Y.query(u,{fresh:t});n=g.quota,r=g.sampledAt,a=g.cacheKey}const d=this.sessionProviderHints.get(e);if(`${d?.providerId??""}|${d?.model??""}|${d?.disabled===!0}`!==i)return;if(h.info(this.name,`[provider-quota] queried: provider=${n.provider} success=${n.success}`+(n.tiers.length>0?` tiers=${n.tiers.map(u=>`${u.name}=${u.usedPercent}%`).join(",")}`:"")+(n.balance?` balance=${n.balance.remaining} ${n.balance.unit}`:"")+(n.error?` error=${n.error}`:"")+` session=${e}`),!n.success){const u=this.sessionProviderQuotas.get(e);(!u?.quota.success||u.cacheKey!==a)&&this.sessionProviderQuotas.delete(e);return}this.sessionProviderQuotas.set(e,{quota:n,sampledAt:r,cacheKey:a});const l=this.enrichProviderQuotaMeta(this.sessionProviderMeta.get(e),"standard",n,r);this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:s,meta:l})}catch(n){h.warn(this.name,`[provider-quota] session query failed: session=${e} ${n instanceof Error?n.message:String(n)}`)}}refreshQuotaAfterModelSwitch(e,s,t){const o=s.trim();if(!e||!o)return;const i=t?.trim()||void 0,n=`${e}|${i??""}|${o}`,r=Date.now();this.lastModelSwitchQuotaRefresh&&this.lastModelSwitchQuotaRefresh.key===n&&r-this.lastModelSwitchQuotaRefresh.at<fi||(this.lastModelSwitchQuotaRefresh={key:n,at:r},this.doRefreshQuotaAfterModelSwitch(e,o,i).catch(a=>{h.warn(this.name,`[provider-quota] model-switch refresh failed: session=${e} model=${o} ${a instanceof Error?a.message:String(a)}`)}))}async doRefreshQuotaAfterModelSwitch(e,s,t){const o=this.sessionProviderHints.get(e);if(o||t){const n=t??Q(s)?.id??o?.providerId,r={...n?{providerId:n}:{},model:s,...o?.disabled?{disabled:!0}:{}},a=o?.providerId!==r.providerId||o?.model!==r.model||o?.disabled!==r.disabled;this.sessionProviderHints.set(e,r),a&&this.sessionProviderQuotas.delete(e);const d=this.sessionBindings.get(e)??this.bindingStore.get(e)?.cwd??"";(a||!this.sessionProviderQuotas.has(e))&&d&&await this.refreshProviderQuotaForSession(e,d,!0);return}const i=await this.maybeQueryProviderQuota(!0,{model:s});i?.success&&this.pushProviderQuotaToBindings(i,this.sessionProviderHints.size>0)}getFreshClaudeRateLimitState(){const e=this.cachedClaudeRateLimitState;return e&&this.isRateLimitsCacheFresh(e.sampledAt)?e:null}getFreshCodexGlobalRateLimitCache(){const e=this.cachedRateLimits,s=this.cachedCodexContextWindow,t=this.cachedCodexTokenUsage;return{sampledAt:Math.max(this.cachedRateLimitsSampledAtMs??0,this.cachedCodexUsageSampledAtMs??0)||null,rateLimits:e,contextWindow:s,tokenUsage:t,hasData:!!(e||s||t)}}getStatus(){const e=this.pool?.getStatus()??{total:0,ready:0,busy:0};return{name:this.name,agentId:this.config.aibot.agentId,alive:!this.stopped,busy:e.busy>0,exhausted:this.pool?[...this.pool.getAllSlots()].some(s=>s.respawn.exhausted):!1,adapterType:this.config.adapterType??"acp",clientType:this.config.aibot.clientType,pool:e}}hasPendingWork(){return this.pool?.hasPendingWork()??!1}hasPendingOrBackgroundWork(){return this.pool?.hasPendingOrBackgroundWork()??!1}relayEnvStale=!1;relayEnvSettledHandler;async recycleAdaptersForRelayChange(){if(!this.pool)return this.relayEnvStale=!1,!0;if(this.hasPendingWork())return this.relayEnvStale=!0,h.info(this.name,"relay changed but agent is busy; adapters keep the old env until the next message (marked stale)"),!1;const e=[...this.pool.getAllSlots()];let s=0,t=!1;for(const o of e){if(this.hasPendingWork())return this.relayEnvStale=!0,h.info(this.name,"new work arrived while recycling; remaining adapters stay stale until the next message"),!1;let i=!1;await this.pool.removeSlot(o.sessionId).catch(n=>{t=!0,i=!0,h.warn(this.name,`failed to recycle adapter slot ${o.sessionId} after relay change: ${n}`)}),i||(s+=1)}return s>0&&h.info(this.name,`recycled ${s} adapter slot(s) so the new Grix relay env takes effect`),t?(this.relayEnvStale=!0,!1):(this.relayEnvStale=!1,this.relayEnvSettledHandler?.(),!0)}setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}providerResolver;setProviderResolver(e){this.providerResolver=e}hasStaleRelayEnv(){return this.relayEnvStale}markRelayEnvStale(){this.relayEnvStale=!0}async probe(e={}){const s=e.conversation?"full":"static",t=e.conversation?oi:ni;if(!e.fresh){const a=this.probeCache.get(s);if(a&&Date.now()-a.sampledAt<t)return{...a.result,cached:!0}}const o=this.config.adapterType??"acp",i=this.createAdapter(o,"__probe__"),n=e.conversation&&o==="acp"?()=>this.runAcpConversationProbe(i,e.timeoutMs??1e4):void 0;let r;try{r=await si({adapter:i,agentName:this.name,clientType:this.config.aibot.clientType,adapterType:o,providerBaseUrl:this.config.providerBaseUrl??null,opts:e,launchConversationProbe:n})}finally{i.stop().catch(()=>{})}return this.probeCache.set(s,{result:r,sampledAt:r.probed_at}),r}async runAcpConversationProbe(e,s){const t=Date.now(),o="__probe__",i=`probe-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,n=this.config.agent.cwd||we(),r=()=>Date.now()-t;try{await e.start()}catch(u){return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_failed",message:`start failed: ${u instanceof Error?u.message:String(u)}`}}}if(!e.isAlive())return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"process_not_started",message:"agent process not alive"}};if(e instanceof y)try{await e.bindSession(o,n)}catch{}let a=null;const d=new Promise(u=>{a=g=>{g===i&&u()},e.on("eventDone",a)});e.deliverInboundEvent({event_id:i,session_id:o,content:"ping",msg_id:i}),e.deliverStopEvent(i,o);let c=null;const l=await Promise.race([d.then(()=>!1),new Promise(u=>{c=setTimeout(()=>u(!0),s)})]);return c&&clearTimeout(c),a&&e.removeListener("eventDone",a),l?{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_timeout",message:`no eventDone within ${s}ms`}}:{attempted:!0,ok:!0,latency_ms:r()}}constructor(e,s,t=new di){this.config=e,this.auditController=new ri(t,{onAuditState:i=>{try{this.aibotHandle.sendAuditState(Z(i,Date.now()))}catch{}}}),ai(t)&&t.addJobSettledHandler((i,n)=>{this.auditController.handleJobSettled(i,n)}),this.name=e.name;const o=e.adapterType??"acp";if(this.sendCtrl.setDefaultQuoteTrigger(jt[o]),this.aibotConfig={...e.aibot,...o==="claude"?{localActions:e.aibot.localActions??["session_control","claude_interaction_reply","get_session_usage","get_rate_limits","set_model","set_mode","set_reasoning_effort","thread_compact","get_agent_global_config",...ke]}:{}},e.eventQueue&&(this.aibotConfig.concurrency={max_concurrent:e.eventQueue.maxConcurrent,max_queued:e.eventQueue.maxQueued,queue_timeout_ms:e.eventQueue.queueTimeoutMs,cancelable_queued:e.eventQueue.cancelableQueued,cancelable_running:e.eventQueue.cancelableRunning}),this.conversationLog=e.logDir?new Et(e.logDir):null,this.packetLog=e.logDir?new $t(e.logDir):null,this.bindingStore=new Bt(e.bindingsPath,e.legacyBindingsPath),this.bindingStore.load(),this.globalConfigStore=s??null,this.deferredMgr=new ii(this.name),this.activeEventStore=e.activeEventStorePath?new Nt(e.activeEventStorePath):null,o==="codex")this.sessionScanCache=new E(dt,St);else if(o==="claude")this.sessionScanCache=new E(ct,bt);else if(o==="pi"){const i=e.agent.env?.PI_CODING_AGENT_DIR;this.sessionScanCache=new E(()=>pt(void 0,i),()=>Ct(void 0,i))}else if(o==="codewhale")this.sessionScanCache=new E(ft,At);else if(o==="cursor")this.sessionScanCache=new E(mt,kt);else if(o==="opencode")this.sessionScanCache=new E(_t,Rt);else if(o==="agy")this.sessionScanCache=new E(()=>[],()=>[]);else{e.aibot.clientType?.trim().toLowerCase()==="reasonix"&&(this.reasonixTitleScan=new E(gt,yt));const i=ut(e.aibot.clientType);this.sessionScanCache=i?new E(()=>ht(void 0,i),()=>wt(void 0,i)):new E(()=>[],()=>[])}}async start(){await nt({agentName:this.name,adapterType:this.config.adapterType??"acp",command:this.config.agent.command,piConfigDir:this.config.agent.env?.PI_CODING_AGENT_DIR,hasProvider:!!this.config.agent.provider,boundCwds:[...this.bindingStore.entries()].map(([,i])=>String(i.cwd??""))}).then(i=>{i.length>0&&h.info(this.name,`restored native provider config after relay disable: ${i.join(", ")}`)}).catch(i=>{h.warn(this.name,`native provider residue sweep failed: ${i instanceof Error?i.message:String(i)}`)}),(this.config.adapterType??"acp")==="claude"&&(await z().catch(()=>{}),this.maybeQueryProviderQuota().catch(()=>{}));const e=!!(this.config.providerBaseUrl&&this.config.providerApiKey||this.config.agent.provider?.baseUrl&&this.config.agent.provider?.apiKey),s=(this.config.adapterType??"acp")==="pi",t=(this.config.adapterType??"acp")==="opencode";this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi"||e?(this.maybeQueryProviderQuota().catch(()=>{}),this.startProviderQuotaTimer()):(s||t)&&this.startProviderQuotaTimer(),(this.config.adapterType??"acp")==="codex"&&this.maybeQueryProviderQuota().catch(()=>{}),(this.config.adapterType??"acp")==="opencode"&&this.maybeQueryProviderQuota().catch(()=>{}),await this.connectAibot(),this.sendCtrl.bind(this.aibotHandle);const o=this.config.adapterType??"acp";this.pool=new xt({maxPoolSize:this.config.poolMaxSize??20,idleTimeoutMs:this.config.poolIdleTimeoutMs??18e5,eventQueue:this.config.eventQueue},i=>{const n=this.createAdapter(o,i);return n instanceof y&&n.on("acpSessionReady",r=>{this.bindingStore.setAcpSessionId(i,r),this.sessionScanCache.invalidate()}),n},(i,n)=>{this.aibotHandle.sendEventAck({event_id:i,session_id:n,received_at:Date.now()})}),this.pool.setEventStateHandler((i,n,r,a)=>{if(h.info(this.name,`[queue-debug] send event_state session=${n} event=${i} state=${r} queue_pos=${a?.queue_position??""} queue_total=${a?.queue_total??""}`),this.aibotHandle.sendEventState({event_id:i,session_id:n,state:r,content_preview:a?.content_preview,content:a?.content,queue_position:a?.queue_position,queue_total:a?.queue_total,actions:a?.actions,reason:a?.reason,held:a?.held,held_reason:a?.held_reason,updated_at:Date.now()}),this.pushQueueSnapshotForSession(n),r==="canceled"||r==="failed"){const d=r==="canceled"?"canceled":"failed";this.aibotHandle.sendEventResult({event_id:i,status:d,msg:a?.reason,updated_at:Date.now()}),this.auditController.closeWithoutAdapter(i,d,a?.reason,{queueTerminalState:r}),this.discardEventTrackingState(i)}}),this.pool.setQueueComposingHandler((i,n,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:"composing",active:n,...n?{ttl_ms:3e4,ref_event_id:r}:{}})}),this.pool.setInternalErrorHandler(i=>{this.handleSessionInternalError(i).catch(n=>{h.error(this.name,`[recovery] handleSessionInternalError failed event=${i.eventId} session=${i.sessionId}: ${n instanceof Error?n.message:String(n)}`)})}),this.pool.setEventStartedHandler((i,n)=>{if(this.reportSessionSkills(n),this.config.adapterType!=="claude")return;this.claudeWorkerStatus.set(n,"busy");const r=this.bindingStore.get(n);r?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"busy",cwd:r.cwd,meta:this.buildClaudeToolbarMeta(n)})}),this.pool.setEventDoneHandler((i,n)=>{this.markAuditAdapterClosed(i,n);const r=this.config.adapterType??"acp";if(r==="claude"){this.claudeWorkerStatus.set(n,"ready");const a=this.bindingStore.get(n);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:a.cwd,meta:this.buildClaudeToolbarMeta(n)})}else if(r==="agy"){const a=this.bindingStore.get(n);if(a?.cwd){const d=this.buildAgyToolbarMeta(n),c=d?.available_models??[];h.info(this.name,`[agy-toolbar-diag] eventDone push binding card session=${n} model_id=${String(d?.model_id??"")} available_models=${c.length} meta_keys=${d?Object.keys(d).join(","):"<none>"}`),this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:a.cwd,meta:d})}else h.info(this.name,`[agy-toolbar-diag] eventDone skip binding card: no binding cwd session=${n}`)}}),this.pool.setSessionActivityHandler((i,n,r)=>{const a=this.selfDrivenSessions.has(i),d=this.selfDrivenLabels.get(i);n?(this.selfDrivenSessions.add(i),r&&this.selfDrivenLabels.set(i,r),this.aibotHandle.sendSessionActivitySet({session_id:i,kind:"composing",active:!0,ttl_ms:9e4})):(this.selfDrivenSessions.delete(i),this.selfDrivenLabels.delete(i),a&&this.aibotHandle.sendSessionActivitySet({session_id:i,kind:"composing",active:!1})),(a!==n||n&&r!==void 0&&r!==d)&&this.pushQueueSnapshotForSession(i)}),this.pool.startIdleSweep(),h.info(this.name,`Ready (adapter: ${o}, poolMax: ${this.config.poolMaxSize??20})`)}async stop(){this.stopped=!0,this.pool?.stopIdleSweep(),this.stopProviderQuotaTimer();const e=this.pool?.collectActiveEventIds()??[],s=new Map(e.map(i=>[i,this.eventSessionIndex.get(i)]));e.length>0&&this.activeEventStore&&await this.activeEventStore.save(e);for(const i of e)h.info(this.name,`Canceling active event on shutdown: ${i}`),this.sendEventResultWithCleanup(i,"canceled","process shutting down");e.length>0&&await new Promise(i=>setTimeout(i,100)),this.pool?.clearActiveEventsForShutdown();for(const i of e){const n=s.get(i),r=n?this.pool?.getSlot(n):void 0;this.auditController.markAdapterClosed(i,r?.adapter.takeAuditBoundary?.(i)??{processTerminated:!0})}const t=this.deferredMgr.getAllDeferredEvents();for(const i of t)h.info(this.name,`Failing deferred event on shutdown: ${i.event_id}`),this.sendEventResultWithCleanup(i.event_id,"failed","process shutting down"),this.auditController.markAdapterClosed(i.event_id,{adapterNotStarted:!0,processTerminated:!0});const o=this.pool?.drainAllQueuedEvents()??[];for(const i of o)h.info(this.name,`Failing queued event on shutdown: ${i.event_id}`),this.sendEventResultWithCleanup(i.event_id,"failed","process shutting down"),this.auditController.markAdapterClosed(i.event_id,{adapterNotStarted:!0,processTerminated:!0});this.deferredMgr.clearAll(),await this.pool?.stop(),this.aibotHandle?.disconnect(),e.length>0&&this.activeEventStore&&await this.activeEventStore.save([]),this.eventSessionIndex.clear(),this.inflightEvents.clear(),this.restartCount.clear(),this.auditController.dispose()}resolveSpawnEnv(){const e=this.providerResolver?this.providerResolver():this.config.agent.provider,s=tt(this.config.agent.clientType,e),t=this.config.agent.env;let o=Object.keys(s).length>0?{...s,...t}:t;if(it(s)){const i=de()?.getRuntimeInfo(),n={...t??{},...s},r=st(n,{proxyUrl:i?.proxyUrl,caCertPath:i?.caCertPath,caBundlePath:i?.caBundlePath});return delete r.ANTHROPIC_API_KEY,delete r.CLAUDE_CODE_OAUTH_TOKEN,r}if(ce(this.config.agent.clientType)){const i=Ye(this.name);i&&(o={...o??{},...i})}return ze(o,this.name,this.config.agent.clientType)}createAdapter(e,s){switch(e){case"claude":return this.createClaudeAdapter(s);case"codex":return this.createCodexAdapter(s);case"pi":return this.createPiAdapter(s);case"openhuman":return this.createOpenHumanAdapter(s);case"codewhale":return this.createCodeWhaleAdapter(s);case"cursor":return this.createCursorAdapter(s);case"opencode":return this.createOpenCodeAdapter(s);case"agy":return this.createAgyAdapter(s);default:return this.createAcpAdapter(s)}}createCursorAdapter(e){const s={...this.config.adapterOptions??{}};s.bindingStore=this.bindingStore,s.aibotSessionId=e;const t=this.bindingStore.get(e),o=this.resolveSessionModelId(e);o&&(s.model=o);const i=this.bindingStore.getCursorModeId(e),n=i??"full_auto";i||this.bindingStore.setCursorModeId(e,n),s.mode=n,t?.cwd&&(s.workspace=t.cwd);const r={sendStreamChunk:(a,d,c,l,u,g,v)=>{this.sendStreamChunkByRuntimeConfig(a,d,c,l,u,g,v)},sendEventResult:(a,d,c)=>{this.sendEventResultWithCleanup(a,d,c)},sendEventAck:(a,d)=>{this.aibotHandle.sendEventAck({event_id:a,session_id:d,received_at:Date.now()})},sendRawEventEnvelope:(a,d,c)=>{this.deliverRawEventEnvelope(a,d,c,"cursor",this.buildCursorRawEventFallbackText(c))},sendAgentQuestionCard:(a,d,c)=>{const l=c.questions.map(g=>g.header).join(", "),u=ve(`[Agent Question] ${c.request_id}`,"agent_question",c);this.aibotHandle.sendText({event_id:a,session_id:d,content:u,msg_type:1,extra:{card_type:"agent_question",summary_text:l}})},agentInvoke:async(a,d,c)=>this.platformInvoke(a,d,c),sendLocalActionResult:(a,d,c,l,u)=>{this.aibotHandle.sendLocalActionResult({action_id:a,status:d,...c!==void 0?{result:c}:{},...l?{error_code:l}:{},...u?{error_msg:u}:{}})},sendUpdateBindingCard:(a,d,c,l)=>{this.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:d,cwd:c,...l?{meta:l}:{}})},getAgentProfile:()=>this.agentProfile};return new q({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:s},r)}createClaudeAdapter(e){const s={sendReply:(i,n,r,a,d)=>{this.sendReplyByRuntimeConfig(i,n,r,a,d)},sendStreamChunk:(i,n,r,a,d,c,l)=>{this.sendStreamChunkByRuntimeConfig(i,n,r,a,d,c,l)},sendMedia:(i,n,r,a,d,c,l)=>{this.aibotHandle.sendMedia({event_id:i,session_id:n,content:r,msg_type:2,quoted_message_id:d||void 0,client_msg_id:c||void 0,extra:l?{media_caption:a,...l}:{media_caption:a}})},sendEventResult:(i,n,r,a)=>{this.sendEventResultWithCleanup(i,n,r,a)},sendEventAck:(i,n)=>{this.aibotHandle.sendEventAck({event_id:i,session_id:n,received_at:Date.now()})},agentInvoke:async(i,n,r)=>this.platformInvoke(i,n,r),sendLocalActionResult:(i,n,r,a,d)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:n,...r!==void 0?{result:r}:{},...a?{error_code:a}:{},...d?{error_msg:d}:{}})},sendToolUse:(i,n,r,a)=>{this.sendToolExecutionCard(i,n,H(r,a))},sendToolResult:(i,n,r,a)=>{this.sendToolExecutionCard(i,n,L(r,a))},getWsUrl:()=>this.config.aibot.url,getAgentId:()=>this.config.aibot.agentId,getAgentProfile:()=>this.agentProfile,getApiKey:()=>this.config.aibot.apiKey,getActiveEventCount:()=>0,getPendingPermissionCount:()=>0,getPendingElicitationCount:()=>0,sendAgentQuestionCard:(i,n,r)=>{this.sendGrixAgentQuestionCard(i,n,r)},sendPermissionCard:i=>{this.sendGrixApprovalCard(i,"claude")},sendDirectMessage:i=>{this.aibotHandle.sendMsg({session_id:i.sessionId,msg_type:1,content:i.content,...i.clientMsgId?{client_msg_id:i.clientMsgId}:{},...i.quotedMessageId?{quoted_message_id:i.quotedMessageId}:{}})},onStatusLineUpdated:i=>{(i.rateLimits?.fiveHour||i.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=i);const n=this.bindingStore.get(e);n?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:this.claudeWorkerStatus.get(e)??"ready",cwd:n.cwd,meta:this.buildClaudeToolbarMeta(e)})},sendMcpFrame:i=>{this.aibotHandle.sendMcpFrame(e,i)}},t=this.config.adapterOptions??{},o={...t,sessionRuntimeResolver:()=>{const i=this.bindingStore.get(e),n=this.auditController.getSession(e);return{cwd:i?.cwd,modeId:i?.modeId??R.fullAuto,modelId:this.resolveSessionModelId(e),effort:this.resolveClaudeSessionEffort(e),pluginDir:t.pluginDir,claudeSessionId:i?.claudeSessionId,...n?{audit:{enabled:!0,profile:n.options.profile,capture:n.options.capture}}:{},onSessionIdAssigned:r=>{this.bindingStore.setClaudeSessionId(e,r),this.sessionScanCache.invalidate()}}}};return new M({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:o},s)}createCodexAdapter(e){let s=null;const t={sendEventResult:(r,a,d)=>{if(a!=="responded"){this.sendEventResultWithCleanup(r,a,d);return}this.sendCtrl.sendFinalStreamChunkReliable(r,e,`codex_terminal_fence_${r}`,5e3,!0,!0).then(()=>this.sendEventResultWithCleanup(r,a,d),c=>{const l=`codex output acceptance fence failed: ${c instanceof Error?c.message:String(c)}`;this.sendEventResultWithCleanup(r,a==="responded"?"failed":a,a==="responded"?l:d)})},sendEventAck:(r,a)=>this.aibotHandle.sendEventAck({event_id:r,session_id:a,received_at:Date.now()}),sendCodexEvent:r=>{this.shouldDropCodexDisplayEvent(r.event_id,r.codex_method)||(this.captureCodexAuditOutput(r),this.aibotHandle.sendCodexEvent(this.stampCodexEventQuote(r)),this.logCodexEventToConversation(r))},sendRunError:(r,a,d)=>{this.sendRunErrorAsChunk(r,a,d)},sendUpdateBindingCard:(r,a,d,c)=>{const l={...c??{}};if(!l.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const u=this.providerQuotaToCodexRateLimits(this.cachedProviderQuota);u&&(l.rate_limits=u.rateLimits,l.rate_limit_primary_percent=u.primaryPercent,l.rate_limit_secondary_percent=u.secondaryPercent,l.rate_limit_primary_window_min=u.primaryWindowMin,l.rate_limit_secondary_window_min=u.secondaryWindowMin)}!l.provider_quota&&this.cachedProviderQuota?.success&&(l.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:r,worker_status:a,cwd:d,...Object.keys(l).length>0?{meta:l}:{}})},agentInvoke:async(r,a,d)=>this.platformInvoke(r,a,d),sendLocalActionResult:(r,a,d,c,l)=>this.aibotHandle.sendLocalActionResult({action_id:r,status:a,...d!==void 0?{result:d}:{},...c?{error_code:c}:{},...l?{error_msg:l}:{}}),sendSessionActivitySet:(r,a,d,c)=>{this.aibotHandle.sendSessionActivitySet({session_id:r,kind:a,active:d,...c??{}})},getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,onRateLimitsUpdated:r=>{this.cachedRateLimits=r,this.cachedRateLimitsSampledAtMs=Date.now(),this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const a=this.bindingStore.get(e);if(a?.cwd){const d=this.cachedRateLimitsSampledAtMs,c={rate_limits:{...r.primary.windowMinutes>0?{primary:r.primary}:{},...r.secondary.windowMinutes>0?{secondary:r.secondary}:{},sampledAt:d},rate_limit_primary_percent:r.primary.usedPercent,rate_limit_secondary_percent:r.secondary.usedPercent,rate_limit_primary_window_min:r.primary.windowMinutes,rate_limit_secondary_window_min:r.secondary.windowMinutes,credits:r.credits,...r.extras&&r.extras.length>0?{extra_limits:r.extras}:{},...s?.getEffortMeta()};this.cachedProviderQuota?.success&&(c.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:c})}},onContextWindowUpdated:r=>{if(!r)return;this.cachedCodexContextWindow=r,this.cachedCodexUsageSampledAtMs=Date.now();const a=this.bindingStore.get(e);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:{context_window:r,...s?.getEffortMeta()}})},onTokenUsageUpdated:r=>{r&&(this.cachedCodexTokenUsage=r,this.cachedCodexUsageSampledAtMs=Date.now())}},o=this.config.adapterOptions??{},i=this.globalConfigStore?.get(this.name),n=this.auditController.getAdapterPreparation(e);return s=new ie({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...o,model:this.resolveCodexSessionModelId(e)??o.model,collaborationMode:this.bindingStore.getCodexModeId(e)??this.resolveCodexNewSessionGlobalDefault(e,i?.codexModeId,r=>this.bindingStore.setCodexModeId(e,r))??o.collaborationMode,reasoningEffort:i?.codexReasoningEffort??o.reasoningEffort,serviceTier:this.bindingStore.getCodexServiceTier(e)??this.resolveCodexNewSessionGlobalDefault(e,i?.codexServiceTier,r=>this.bindingStore.setCodexServiceTier(e,r))??o.serviceTier,sandboxMode:i?.codexSandboxMode??o.sandboxMode,aibotSessionId:e,bindingStore:this.bindingStore,...oe(n?.options)?{rawApiCapture:{auditId:n.auditId,sessionId:e,spoolRootDir:T.join(P.data,"audit-replay","raw-spool")}}:{}}},t),s}createCodeWhaleAdapter(e){const s={sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),sendLocalActionResult:(o,i,n,r,a)=>this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}}),sendSessionActivitySet:(o,i,n,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:o,kind:i,active:n,...r??{}})},sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new se({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},s)}createPiAdapter(e){const s={sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n),h.info("bridge",`[pi] sendEventResult event=${o} status=${i}`)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),sendLocalActionResult:(o,i,n,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}})},sendSessionActivitySet:(o,i,n,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:o,kind:i,active:n,...r??{}})},sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d),a&&h.info("bridge",`[pi] sendFinalStreamChunk event=${o} seq=${r}`)},sendFinalStreamChunkReliable:this.reliableFinalWiring("pi"),sendThinking:(o,i,n)=>{this.sendThinkingByRuntimeConfig(o,i,n)},sendRunError:(o,i,n,r,a)=>{this.sendStreamChunkByRuntimeConfig(o,i,`
2
2
 
3
- Error: ${n}`,r,!1,a)},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new Re({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},s)}createOpenHumanAdapter(e){const s={sendStreamChunk:(o,i,n,r,a,d)=>{this.finalizeThinking(o,i),this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendFinalStreamChunkReliable:async(o,i,n,r)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(o,i,r)}catch(a){throw h.error("bridge",`[openhuman] sendFinalStreamChunkReliable ACK failed event=${o}: ${a}`),a}},sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n),h.info("bridge",`[openhuman] sendEventResult event=${o} status=${i}`)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},sendThinking:(o,i,n)=>{this.sendThinkingByRuntimeConfig(o,i,n)},sendRunError:(o,i,n)=>{this.sendStreamChunkByRuntimeConfig(o,i,`
3
+ Error: ${n}`,r,!1,a)},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new Re({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},s)}createOpenHumanAdapter(e){const s={sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendFinalStreamChunkReliable:async(o,i,n,r)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(o,i,r)}catch(a){throw h.error("bridge",`[openhuman] sendFinalStreamChunkReliable ACK failed event=${o}: ${a}`),a}},sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n),h.info("bridge",`[openhuman] sendEventResult event=${o} status=${i}`)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},sendThinking:(o,i,n)=>{this.sendThinkingByRuntimeConfig(o,i,n)},sendRunError:(o,i,n)=>{this.sendStreamChunkByRuntimeConfig(o,i,`
4
4
 
5
- Error: ${n}`,0,!1)},sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),sendLocalActionResult:(o,i,n,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}})},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new ye({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:t},s,{port:t.port,host:t.host,workspaceDir:t.workspace_dir,sessionToken:t.session_token,enableSessionBinding:!0,aibotSessionId:e})}createOpenCodeAdapter(e){const s={sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendFinalStreamChunkReliable:this.reliableFinalWiring("opencode"),sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n),h.info("bridge",`[opencode] sendEventResult event=${o} status=${i}`)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},sendThinking:(o,i,n)=>{this.sendThinkingByRuntimeConfig(o,i,n)},sendRunError:(o,i,n)=>{this.sendRunErrorAsChunk(o,i,n)},sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),sendLocalActionResult:(o,i,n,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}})},sendPermissionCard:o=>{this.sendGrixApprovalCard(o,"opencode")},sendAgentQuestionCard:(o,i,n)=>{this.sendGrixAgentQuestionCard(o,i,n)},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new G({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:t},s,{port:t.port,hostname:t.hostname,model:t.model??this.resolveSessionModelId(e),agent:t.agent,permissionPolicy:t.permission_policy,enableSessionBinding:!0,aibotSessionId:e,bindingStore:this.bindingStore,...this.config.agent.provider?{provider:this.config.agent.provider}:{}})}createAgyAdapter(e){const s={sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n)},sendEventAck:(o,i)=>{this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()})},agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),forceCompleteInternalEvent:(o,i)=>{this.pool.eventComplete(o,i),this.pushQueueSnapshotForSession(i)},persistConversationId:(o,i)=>{this.bindingStore.setAgyConversationId(o,i)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},t=o=>{const i=this.bindingStore.get(o);return{cwd:i?.cwd,modelId:this.resolveSessionModelId(o),conversationId:i?.agyConversationId}};return new ne({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:this.config.adapterOptions??{}},s,t)}createAcpAdapter(e){const s=this.isAcpRawTransportEnabled(),t={sendStreamChunk:(c,l,u,g,v,f,S)=>{this.finalizeThinking(c,l),this.sendStreamChunkByRuntimeConfig(c,l,u,g,v,f,S)},sendFinalStreamChunkReliable:this.reliableFinalWiring("acp",4e3),sendEventResult:(c,l,u)=>{this.sendEventResultWithCleanup(c,l,u)},sendEventAck:(c,l)=>{this.aibotHandle.sendEventAck({event_id:c,session_id:l,received_at:Date.now()})},agentInvoke:async(c,l,u)=>this.platformInvoke(c,l,u),sendLocalActionResult:(c,l,u,g,v)=>{this.aibotHandle.sendLocalActionResult({action_id:c,status:l,...u!==void 0?{result:u}:{},...g?{error_code:g}:{},...v?{error_msg:v}:{}})},sendRawEventEnvelope:(c,l,u)=>{this.sendAcpRawEventEnvelope(c,l,u)},sendToolUse:(c,l,u,g)=>{if(s){this.sendAcpRawEventEnvelope(c,l,{type:"tool_use",payload:{tool_name:u,tool_input:g??""}});return}this.sendToolExecutionCard(c,l,H(u,g))},sendToolResult:(c,l,u,g)=>{this.sendToolExecutionCard(c,l,L(u,g))},sendThinking:(c,l,u)=>{this.sendThinkingByRuntimeConfig(c,l,u)},sendRunError:(c,l,u)=>{this.sendStreamChunkByRuntimeConfig(c,l,`
5
+ Error: ${n}`,0,!1)},sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),sendLocalActionResult:(o,i,n,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}})},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new ye({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:t},s,{port:t.port,host:t.host,workspaceDir:t.workspace_dir,sessionToken:t.session_token,enableSessionBinding:!0,aibotSessionId:e})}createOpenCodeAdapter(e){const s={sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendFinalStreamChunkReliable:this.reliableFinalWiring("opencode"),sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n),h.info("bridge",`[opencode] sendEventResult event=${o} status=${i}`)},sendEventAck:(o,i)=>this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()}),sendToolUse:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,H(n,r))},sendToolResult:(o,i,n,r)=>{this.sendToolExecutionCard(o,i,L(n,r))},sendThinking:(o,i,n)=>{this.sendThinkingByRuntimeConfig(o,i,n)},sendRunError:(o,i,n)=>{this.sendRunErrorAsChunk(o,i,n)},sendUpdateBindingCard:(o,i,n,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:i,cwd:n,...this.providerQuotaMetaPayload(r,o,n)}),agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),sendLocalActionResult:(o,i,n,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:o,status:i,...n!==void 0?{result:n}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}})},sendPermissionCard:o=>{this.sendGrixApprovalCard(o,"opencode")},sendAgentQuestionCard:(o,i,n)=>{this.sendGrixAgentQuestionCard(o,i,n)},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new G({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:t},s,{port:t.port,hostname:t.hostname,model:t.model??this.resolveSessionModelId(e),agent:t.agent,permissionPolicy:t.permission_policy,enableSessionBinding:!0,aibotSessionId:e,bindingStore:this.bindingStore,...this.config.agent.provider?{provider:this.config.agent.provider}:{}})}createAgyAdapter(e){const s={sendStreamChunk:(o,i,n,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(o,i,n,r,a,d)},sendEventResult:(o,i,n)=>{this.sendEventResultWithCleanup(o,i,n)},sendEventAck:(o,i)=>{this.aibotHandle.sendEventAck({event_id:o,session_id:i,received_at:Date.now()})},agentInvoke:async(o,i,n)=>this.platformInvoke(o,i,n),forceCompleteInternalEvent:(o,i)=>{this.pool.eventComplete(o,i),this.pushQueueSnapshotForSession(i)},persistConversationId:(o,i)=>{this.bindingStore.setAgyConversationId(o,i)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},t=o=>{const i=this.bindingStore.get(o);return{cwd:i?.cwd,modelId:this.resolveSessionModelId(o),conversationId:i?.agyConversationId}};return new ne({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:this.config.adapterOptions??{}},s,t)}createAcpAdapter(e){const s=this.isAcpRawTransportEnabled(),t={sendStreamChunk:(c,l,u,g,v,f,S)=>{this.sendStreamChunkByRuntimeConfig(c,l,u,g,v,f,S)},sendFinalStreamChunkReliable:this.reliableFinalWiring("acp",4e3),sendEventResult:(c,l,u)=>{this.sendEventResultWithCleanup(c,l,u)},sendEventAck:(c,l)=>{this.aibotHandle.sendEventAck({event_id:c,session_id:l,received_at:Date.now()})},agentInvoke:async(c,l,u)=>this.platformInvoke(c,l,u),sendLocalActionResult:(c,l,u,g,v)=>{this.aibotHandle.sendLocalActionResult({action_id:c,status:l,...u!==void 0?{result:u}:{},...g?{error_code:g}:{},...v?{error_msg:v}:{}})},sendRawEventEnvelope:(c,l,u)=>{this.sendAcpRawEventEnvelope(c,l,u)},sendToolUse:(c,l,u,g)=>{if(s){this.sendAcpRawEventEnvelope(c,l,{type:"tool_use",payload:{tool_name:u,tool_input:g??""}});return}this.sendToolExecutionCard(c,l,H(u,g))},sendToolResult:(c,l,u,g)=>{this.sendToolExecutionCard(c,l,L(u,g))},sendThinking:(c,l,u)=>{this.sendThinkingByRuntimeConfig(c,l,u)},sendRunError:(c,l,u)=>{this.sendStreamChunkByRuntimeConfig(c,l,`
6
6
 
7
- Error: ${u}`,1,!1)},sendPermissionCard:c=>{h.info("bridge","sendPermissionCard callback entered",{rawTransport:s,eventId:c.eventId,sessionId:c.sessionId,toolCallId:c.toolCallId,toolName:c.toolName,toolTitle:c.toolTitle});const l=c.toolInput&&c.toolTitle&&c.toolInput!==c.toolTitle?`${c.toolTitle}: ${c.toolInput}`:c.toolTitle||c.toolInput||c.toolName;if(s){this.sendAcpRawEventEnvelope(c.eventId,c.sessionId,{type:"permission_request",payload:{tool_call_id:c.toolCallId,tool_name:c.toolName,tool_title:c.toolTitle,...c.toolInput?{tool_input:c.toolInput}:{},options:c.options}}),h.info("bridge","sendPermissionCard: sent via rawEventEnvelope",{eventId:c.eventId,toolCallId:c.toolCallId});return}const u=`perm_${K()}`,g={event_id:c.eventId,session_id:c.sessionId,client_msg_id:u,msg_type:1,content:c.toolTitle?`Permission required: ${c.toolTitle}`:"Permission request",extra:{channel_data:{execApproval:{approvalId:c.toolCallId,approvalSlug:c.toolName},grix:{execApproval:{approval_command_id:c.toolCallId,command:l,host:"acp"}}},agent_api_origin:!0}};h.info("bridge","sendPermissionCard: about to invoke aibotHandle.sendMsg",{eventId:c.eventId,sessionId:c.sessionId,clientMsgId:u,toolCallId:c.toolCallId,contentLength:g.content.length});try{this.aibotHandle.sendMsg(g),h.info("bridge","sendPermissionCard: aibotHandle.sendMsg returned",{eventId:c.eventId,clientMsgId:u})}catch(v){h.error("bridge","sendPermissionCard: aibotHandle.sendMsg threw",{eventId:c.eventId,clientMsgId:u,error:v instanceof Error?v.message:String(v)})}},sendAuthNotification:(c,l)=>{c&&this.aibotHandle.sendMsg({session_id:c,msg_type:1,content:l,extra:{biz_card:{version:1,type:"agent_error",payload:{error:{name:"AuthRequired",message:l}}}}})},sendAgentMessage:(c,l)=>{c&&l&&this.aibotHandle.sendMsg({session_id:c,msg_type:1,content:l})},sendUpdateBindingCard:(c,l,u,g)=>{const v={...g??{}};if(!v.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const f=this.providerQuotaToRateLimits(this.cachedProviderQuota);f&&(v.rate_limits=f)}!v.provider_quota&&this.cachedProviderQuota?.success&&(v.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:c,worker_status:l,cwd:u,...Object.keys(v).length>0?{meta:v}:{}})},onSkillsUpdate:(c,l)=>{try{this.aibotHandle.sendSkillsUpdate({skills:re(c,T.skills),library_skills:this.buildLibrarySkillsReport(l)})}catch(u){}},onContextWindowUpdated:c=>{this.cachedAcpContextWindow=c,this.cachedAcpContextWindowSampledAtMs=Date.now();const l="usedPercentage"in c?c.usedPercentage.toFixed(1):(c.used/c.size*100).toFixed(1);h.info(this.name,`[acp] context_window updated: ${l}%`);const u=this.bindingStore.get(e);if(u?.cwd){const g="usedPercentage"in c?c.usedPercentage:Math.min(100,c.used/c.size*100),v={context_window:{..."usedPercentage"in c?{}:c,usedPercentage:g,remainingPercentage:100-g}};if((this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi")&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{}),v.provider_quota=this.cachedProviderQuota;const f=this.providerQuotaToRateLimits(this.cachedProviderQuota);f&&(v.rate_limits=f)}this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:u.cwd,meta:v})}},sendMcpFrame:c=>{this.aibotHandle.sendMcpFrame(e,c)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},o=e?this.bindingStore.get(e):void 0,i=e?this.auditController.getSession(e):void 0,n=this.config.aibot.clientType==="reasonix"&&i?_i(this.name,e,i.auditId):void 0,r=this.globalConfigStore?.get(this.name),{initialModel:a,initialMode:d}=Qt({sessionBinding:o,globalDefaults:r,configInitialMode:this.config.acpInitialMode});return e&&a&&!o?.acpModelId&&this.bindingStore.setAcpModelId(e,a),(a||d)&&h.info(this.name,`[toolbar] hydrate from binding: session=${e} model=${a??"<none>"} mode=${d??"<none>"}`),new y({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv()},t,{acpAuthMethod:this.config.acpAuthMethod,acpInitialMode:d,acpInitialModel:a,acpMcpTools:this.config.acpMcpTools,rawTransport:s,eventResultsPath:this.config.eventResultsPath,approvalMode:this.config.approvalMode,bindingStore:this.config.enableSessionBinding?this.bindingStore:void 0,aibotSessionId:e,autoInjectArgs:this.config.autoInjectArgs,nativeProviderScope:this.name,bridgeLog:this.config.logDir?new Tt(this.config.logDir,`${this.name}-${e}`):null,reasonixAuditTranscriptPath:n,agentType:this.config.aibot.clientType})}async connectAibot(){const e=new Ae;this.aibotHandle=await e.connect(this.aibotConfig,{aborted:()=>this.stopped,label:this.name,packetLog:this.packetLog,maxRetries:this.config.connectMaxRetries});const s=this.aibotHandle.authAck;if(this.applyAgentProfile(s?.agent_name,s?.introduction,{source:"auth_ack",respawnOnChange:!1}),this.aibotHandle.onEvent(t=>{this.handleAibotEvent(t).catch(o=>{h.error(this.name,`handleAibotEvent failed: ${o}`),this.aibotHandle.sendEventAck({event_id:t.event_id,session_id:t.session_id,received_at:Date.now()});const i=o instanceof Error?o.message:String(o);if(/CWD must be|Bound directory does not exist|Bound path is not a directory/i.test(i)&&t.session_id){this.bindingStore.delete(t.session_id),this.sessionBindings.delete(t.session_id),this.sessionProviderHints.delete(t.session_id),this.sessionProviderQuotas.delete(t.session_id),this.sessionProviderMeta.delete(t.session_id);const r=this.pool.getSlot(t.session_id);r?.adapter instanceof y&&r.adapter.getSessionBindings().delete(t.session_id);const a=this.config.adapterType??"acp",d=this.resolveBindingChannelKey(a);this.aibotHandle.sendMsg({event_id:t.event_id,session_id:t.session_id,msg_type:1,content:i,extra:{channel_data:{[d]:{sessionBinding:{status:"missing",reason:"binding_stale",error_code:p.invalidCwd}}}},quoted_message_id:t.msg_id});return}this.aibotHandle.sendEventResult({event_id:t.event_id,status:"failed",msg:i,updated_at:Date.now()})})}),this.aibotHandle.onStop(t=>{try{this.handleAibotStop(t)}catch(o){h.error(this.name,`handleAibotStop failed: ${o}`)}}),this.aibotHandle.onAgentDeleted(t=>{h.warn(this.name,`agent deleted on platform (source=${t?.source??"unknown"}${t?.reason?` reason=${t.reason}`:""}), notifying manager to clean up`);try{this.agentDeletedHandler?.()}catch(o){h.error(this.name,`agentDeletedHandler failed: ${o}`)}}),this.aibotHandle.onShareSet(t=>{try{this.shareSetHandler?.(Array.isArray(t?.shared_to)?t.shared_to:[])}catch(o){h.error(this.name,`onShareSet failed: ${o}`)}}),this.aibotHandle.onProfilePush(t=>{try{this.applyAgentProfile(t?.agent_name,t?.introduction,{source:"profile_push",respawnOnChange:!0})}catch(o){h.error(this.name,`onProfilePush failed: ${o}`)}}),this.aibotHandle.onSkillSync(t=>{try{h.info(this.name,`skill_sync received owner=${t?.owner_id??""} name=${t?.name??""}`),this.skillSyncHandler?.()}catch(o){h.error(this.name,`onSkillSync failed: ${o}`)}}),this.aibotHandle.onRevoke(t=>{try{this.handleAibotRevoke(t)}catch(o){h.error(this.name,`handleAibotRevoke failed: ${o}`)}}),this.aibotHandle.onLocalAction(t=>{this.handleAibotLocalAction(t).catch(o=>{h.error(this.name,`handleAibotLocalAction failed: ${o}`)})}),this.aibotHandle.onEventCancel(t=>{h.info(this.name,`recv event_cancel event_id=${t.event_id} session_id=${t.session_id}`),this.handleEventCancel(t).catch(o=>{h.error(this.name,`handleEventCancel failed: ${o}`)})}),this.aibotHandle.onMcpFrame((t,o)=>{const i=this.pool.getSlot(t)?.adapter;i?.deliverMcpFrameToAgent?i.deliverMcpFrameToAgent(o):h.warn(this.name,`mcp_frame: no adapter for session=${t}`)}),this.aibotHandle.onQueueClear(t=>{const o=this.pool.clearQueue(t.session_id);this.aibotHandle.sendQueueClearResult({session_id:t.session_id,canceled_event_ids:o}),this.pushQueueSnapshotForSession(t.session_id)}),typeof this.aibotHandle.onQueueReorder=="function"&&this.aibotHandle.onQueueReorder(t=>{const o=Array.isArray(t.ordered_event_ids)?t.ordered_event_ids.filter(n=>typeof n=="string"&&n.length>0):[],i=this.pool.reorderQueue(t.session_id,o);this.aibotHandle.sendQueueReorderResult({session_id:t.session_id,applied_event_ids:i}),this.pushQueueSnapshotForSession(t.session_id)}),typeof this.aibotHandle.onEventHold=="function"&&this.aibotHandle.onEventHold(t=>{const o=typeof t.session_id=="string"?t.session_id:"",i=typeof t.event_id=="string"?t.event_id:"",n=t.hold!==!1;if(h.info(this.name,`recv event_hold event_id=${i} session_id=${o} hold=${n} reason=${t.reason??""}`),!o||!i){this.aibotHandle.sendEventHoldResult({session_id:o,event_id:i,ok:!1,held:!1,error:"bad_request"});return}const r=typeof t.reason=="string"?t.reason:"",a=typeof t.ttl_ms=="number"?t.ttl_ms:void 0,d=this.pool.holdEvent(o,i,n,r,a),c=d==="ok";this.aibotHandle.sendEventHoldResult({session_id:o,event_id:i,ok:c,held:c?n:!1,...c?{}:{error:d}}),c&&this.pushQueueSnapshotForSession(o)}),typeof this.aibotHandle.onQueueEdit=="function"&&this.aibotHandle.onQueueEdit(t=>{const o=typeof t.session_id=="string"?t.session_id:"",i=typeof t.event_id=="string"?t.event_id:"";if(h.info(this.name,`recv queue_edit event_id=${i} session_id=${o}`),!o||!i){this.aibotHandle.sendQueueEditResult({session_id:o,event_id:i,ok:!1,error:"bad_request"});return}const n=typeof t.content=="string"?t.content:"",r=this.pool.editQueuedEvent(o,i,n),a=r==="ok";this.aibotHandle.sendQueueEditResult({session_id:o,event_id:i,ok:a,...a?{}:{error:r}}),a&&this.pushQueueSnapshotForSession(o)}),typeof this.aibotHandle.onQueueSnapshotQuery=="function"&&this.aibotHandle.onQueueSnapshotQuery(t=>{this.replyQueueSnapshotForSession(t.session_id)}),h.info(this.name,"Connected to aibot"),this.activeEventStore){const t=await this.activeEventStore.drain();if(t.length>0){h.warn(this.name,`Recovering ${t.length} stale event(s) from previous run`);for(const o of t)h.info(this.name,`Failing stale event on startup: ${o}`),this.aibotHandle.sendEventResult({event_id:o,status:"failed",msg:"process restarted, event lost",updated_at:Date.now()})}}this.pushQueueSnapshots(),this.relayStateSyncOnConnect(),this.aibotHandle.onReconnected(()=>{this.pushQueueSnapshots();const t=this.aibotHandle.authAck;this.applyAgentProfile(t?.agent_name,t?.introduction,{source:"reconnect",respawnOnChange:!0}),this.forceRefreshSkills(void 0,{force:!0}),this.relayStateSyncOnConnect()}),this.aibotHandle.onStreamRejected((t,o)=>{this.sendCtrl.markEventRejected(t)})}applyAgentProfile(e,s,t){const o=String(e??"").trim(),i=String(s??"").trim(),n=o!==this.agentProfile.agentName||i!==this.agentProfile.introduction;this.agentProfile={agentName:o,introduction:i},o||i?h.info(this.name,`agent profile (${t.source}): GOT name="${o}" intro_len=${i.length} changed=${n}`):h.warn(this.name,`agent profile (${t.source}): EMPTY \u2014 \u670D\u52A1\u7AEF\u672A\u4E0B\u53D1 agent_name/introduction\uFF08auth_ack \u5B57\u6BB5\u7F3A\u5931\u6216\u503C\u4E3A\u7A7A\uFF09`),n&&t.respawnOnChange&&this.applyProfileChangeToAdapters("agent_profile_changed")}applyProfileChangeToAdapters(e){if(!this.pool)return;const s=this.pool.getAllSlots();let t=0;for(const r of s)if(r.adapter.onAgentProfileChanged)try{r.adapter.onAgentProfileChanged(),t++}catch(a){h.warn(this.name,`onAgentProfileChanged failed for session=${r.sessionId}: ${a}`)}const o=s.filter(r=>r.adapter instanceof M),i=o.filter(r=>{if(r.state!=="ready")return!1;const a=r.adapter.getStatus();return!a.busy&&!a.backgroundBusy}),n=o.length-i.length;h.info(this.name,`${e}: notified ${t} adapter(s) via hook; respawning ${i.length} idle Claude slot(s), skipping ${n} busy`);for(const r of i)this.pool.removeSlot(r.sessionId).catch(a=>{h.warn(this.name,`removeSlot failed during ${e}: ${a}`)})}pushQueueSnapshots(){if(!(!this.config.eventQueue||!this.pool))for(const e of this.pool.getAllSlots())this.pushQueueSnapshotForSession(e.sessionId)}buildQueueSnapshotPayload(e){const s=this.pool?.getQueueSnapshot(e)??null,t=s?[...s.running]:[],o=s?s.running_items.map(n=>({event_id:n.event_id,...n.content_preview?{content_preview:n.content_preview}:{},...n.title?{title:n.title}:{},...n.summary?{summary:n.summary}:{},actions:[{type:"stop"}]})):[],i=s?s.queued.map(n=>({event_id:n.event_id,position:n.position,...n.content_preview?{content_preview:n.content_preview}:{},...typeof n.content=="string"?{content:n.content}:{},...n.title?{title:n.title}:{},...n.summary?{summary:n.summary}:{},held:n.held===!0,held_reason:n.held_reason??"",actions:[{type:"cancel"}]})):[];if(t.length===0&&this.selfDrivenSessions.has(e)&&this.pool?.getSlot(e)){const n=`selfdrive_${e}`,r=this.selfDrivenLabels.get(e)??"Background task in progress";t.push(n),o.push({event_id:n,content_preview:r,title:r,summary:r,actions:[]})}return{session_id:e,running:t,running_items:o,queued:i}}pushQueueSnapshotForSession(e){if(!this.config.eventQueue||!this.pool)return;const s=this.buildQueueSnapshotPayload(e);h.info(this.name,`[queue-debug] push snapshot session=${e} running=${s.running.length} queued=${s.queued.length} running_ids=[${s.running.join(",")}]`),this.aibotHandle.sendQueueSnapshot(s)}replyQueueSnapshotForSession(e){!this.config.eventQueue||!this.pool||this.aibotHandle.sendQueueSnapshot(this.buildQueueSnapshotPayload(e))}async platformInvoke(e,s,t){return e==="file_link"?Ut(s):e==="file_upload"?this.uploadFileAndSendMedia(s):this.aibotHandle.agentInvoke(e,s,t)}async uploadFileAndSendMedia(e){const s=String(e.file_path??"").trim(),t=String(e.session_id??"").trim(),o=String(e.caption??"").trim(),i=String(e.reply_to_message_id??"").trim();if(!s)throw new Error("file_path is required");if(!t)throw new Error("session_id is required");const n=await Wt({wsURL:this.config.aibot.url,apiKey:this.config.aibot.apiKey,sessionID:t,filePath:s}),r=await this.aibotHandle.sendMedia({session_id:t,msg_type:2,content:o||`[${n.attachment_type}]`,client_msg_id:`file_upload_${K()}`,...i?{quoted_message_id:i}:{},extra:n.extra});if(r.cmd!=="send_ack"){const d=r.payload??{},c=String(d.msg??r.cmd);throw new Error(`media message send failed: ${c}`)}const a=r.payload??{};return{ok:!0,file_name:n.file_name,attachment_type:n.attachment_type,access_url:n.access_url,message_id:a.msg_id!=null?String(a.msg_id):null}}sendReplyByRuntimeConfig(e,s,t,o,i){const n=this.indexEventSession(e,s)??s;this.auditController.captureReply(e,t),this.sendCtrl.sendReply(e,n,t,o,i),t&&this.conversationLog?.logOutbound?.(n,e,"reply",t)}stampCodexEventQuote(e){if(e.quoted_message_id!=null){if(e.quoted_message_id)return e;const{quoted_message_id:n,...r}=e;return r}const s=e;if(s.codex_method!=="item/agentMessage/delta")return e;const o=s.codex_payload?.params?.phase;if(typeof o=="string"&&o.trim()&&o.trim().toLowerCase()!=="final_answer")return e;const i=this.sendCtrl.getDefaultQuotedMessageId(e.event_id);return i?{...e,quoted_message_id:i}:e}captureCodexAuditOutput(e){if(e.codex_method!=="item/agentMessage/delta")return;const s=e.codex_payload?.params,t=typeof s?.phase=="string"?s.phase.trim().toLowerCase():"";if(t&&t!=="final_answer")return;const o=s?.delta;typeof o!="string"||!o||this.auditController.captureUnsequencedStreamChunk(e.event_id,o)}discardEventTrackingState(e){this.inflightEvents.delete(e),this.restartCount.delete(e),this.eventSessionIndex.delete(e),this.sendCtrl.discardEventState(e)}reliableFinalWiring(e,s){return async(t,o,i)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(t,o,i,s)}catch(n){throw h.error("bridge",`[${e}] sendFinalStreamChunkReliable ACK failed event=${t}: ${n}`),n}h.info("bridge",`[${e}] sendFinalStreamChunkReliable done event=${t}`)}}sendStreamChunkByRuntimeConfig(e,s,t,o,i,n,r){const a=this.indexEventSession(e,s)??s;this.auditController.captureStreamChunk(e,o,t),this.sendCtrl.sendStreamChunk(e,a,t,o,i,n,r),(t||i)&&this.conversationLog?.logOutbound?.(a,e,i?"stream_chunk_finish":"stream_chunk",t)}surfacedRunErrorEvents=new Set;sendRunErrorAsChunk(e,s,t){this.surfacedRunErrorEvents.has(e)||(this.surfacedRunErrorEvents.add(e),this.sendStreamChunkByRuntimeConfig(e,s,`
7
+ Error: ${u}`,1,!1)},sendPermissionCard:c=>{h.info("bridge","sendPermissionCard callback entered",{rawTransport:s,eventId:c.eventId,sessionId:c.sessionId,toolCallId:c.toolCallId,toolName:c.toolName,toolTitle:c.toolTitle});const l=c.toolInput&&c.toolTitle&&c.toolInput!==c.toolTitle?`${c.toolTitle}: ${c.toolInput}`:c.toolTitle||c.toolInput||c.toolName;if(s){this.sendAcpRawEventEnvelope(c.eventId,c.sessionId,{type:"permission_request",payload:{tool_call_id:c.toolCallId,tool_name:c.toolName,tool_title:c.toolTitle,...c.toolInput?{tool_input:c.toolInput}:{},options:c.options}}),h.info("bridge","sendPermissionCard: sent via rawEventEnvelope",{eventId:c.eventId,toolCallId:c.toolCallId});return}const u=`perm_${K()}`,g={event_id:c.eventId,session_id:c.sessionId,client_msg_id:u,msg_type:1,content:c.toolTitle?`Permission required: ${c.toolTitle}`:"Permission request",extra:{channel_data:{execApproval:{approvalId:c.toolCallId,approvalSlug:c.toolName},grix:{execApproval:{approval_command_id:c.toolCallId,command:l,host:"acp"}}},agent_api_origin:!0}};h.info("bridge","sendPermissionCard: about to invoke aibotHandle.sendMsg",{eventId:c.eventId,sessionId:c.sessionId,clientMsgId:u,toolCallId:c.toolCallId,contentLength:g.content.length});try{this.aibotHandle.sendMsg(g),h.info("bridge","sendPermissionCard: aibotHandle.sendMsg returned",{eventId:c.eventId,clientMsgId:u})}catch(v){h.error("bridge","sendPermissionCard: aibotHandle.sendMsg threw",{eventId:c.eventId,clientMsgId:u,error:v instanceof Error?v.message:String(v)})}},sendAuthNotification:(c,l)=>{c&&this.aibotHandle.sendMsg({session_id:c,msg_type:1,content:l,extra:{biz_card:{version:1,type:"agent_error",payload:{error:{name:"AuthRequired",message:l}}}}})},sendAgentMessage:(c,l)=>{c&&l&&this.aibotHandle.sendMsg({session_id:c,msg_type:1,content:l})},sendUpdateBindingCard:(c,l,u,g)=>{const v={...g??{}};if(!v.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const f=this.providerQuotaToRateLimits(this.cachedProviderQuota);f&&(v.rate_limits=f)}!v.provider_quota&&this.cachedProviderQuota?.success&&(v.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:c,worker_status:l,cwd:u,...Object.keys(v).length>0?{meta:v}:{}})},onSkillsUpdate:(c,l)=>{try{this.aibotHandle.sendSkillsUpdate({skills:re(c,P.skills),library_skills:this.buildLibrarySkillsReport(l)})}catch(u){}},onContextWindowUpdated:c=>{this.cachedAcpContextWindow=c,this.cachedAcpContextWindowSampledAtMs=Date.now();const l="usedPercentage"in c?c.usedPercentage.toFixed(1):(c.used/c.size*100).toFixed(1);h.info(this.name,`[acp] context_window updated: ${l}%`);const u=this.bindingStore.get(e);if(u?.cwd){const g="usedPercentage"in c?c.usedPercentage:Math.min(100,c.used/c.size*100),v={context_window:{..."usedPercentage"in c?{}:c,usedPercentage:g,remainingPercentage:100-g}};if((this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi")&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{}),v.provider_quota=this.cachedProviderQuota;const f=this.providerQuotaToRateLimits(this.cachedProviderQuota);f&&(v.rate_limits=f)}this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:u.cwd,meta:v})}},sendMcpFrame:c=>{this.aibotHandle.sendMcpFrame(e,c)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},o=e?this.bindingStore.get(e):void 0,i=e?this.auditController.getSession(e):void 0,n=this.config.aibot.clientType==="reasonix"&&i?_i(this.name,e,i.auditId):void 0,r=this.globalConfigStore?.get(this.name),{initialModel:a,initialMode:d}=Qt({sessionBinding:o,globalDefaults:r,configInitialMode:this.config.acpInitialMode});return e&&a&&!o?.acpModelId&&this.bindingStore.setAcpModelId(e,a),(a||d)&&h.info(this.name,`[toolbar] hydrate from binding: session=${e} model=${a??"<none>"} mode=${d??"<none>"}`),new y({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv()},t,{acpAuthMethod:this.config.acpAuthMethod,acpInitialMode:d,acpInitialModel:a,acpMcpTools:this.config.acpMcpTools,rawTransport:s,eventResultsPath:this.config.eventResultsPath,approvalMode:this.config.approvalMode,bindingStore:this.config.enableSessionBinding?this.bindingStore:void 0,aibotSessionId:e,autoInjectArgs:this.config.autoInjectArgs,nativeProviderScope:this.name,bridgeLog:this.config.logDir?new Pt(this.config.logDir,`${this.name}-${e}`):null,reasonixAuditTranscriptPath:n,agentType:this.config.aibot.clientType})}async connectAibot(){const e=new Ae;this.aibotHandle=await e.connect(this.aibotConfig,{aborted:()=>this.stopped,label:this.name,packetLog:this.packetLog,maxRetries:this.config.connectMaxRetries});const s=this.aibotHandle.authAck;if(this.applyAgentProfile(s?.agent_name,s?.introduction,{source:"auth_ack",respawnOnChange:!1}),this.aibotHandle.onEvent(t=>{this.handleAibotEvent(t).catch(o=>{h.error(this.name,`handleAibotEvent failed: ${o}`),this.aibotHandle.sendEventAck({event_id:t.event_id,session_id:t.session_id,received_at:Date.now()});const i=o instanceof Error?o.message:String(o);if(/CWD must be|Bound directory does not exist|Bound path is not a directory/i.test(i)&&t.session_id){this.bindingStore.delete(t.session_id),this.sessionBindings.delete(t.session_id),this.sessionProviderHints.delete(t.session_id),this.sessionProviderQuotas.delete(t.session_id),this.sessionProviderMeta.delete(t.session_id);const r=this.pool.getSlot(t.session_id);r?.adapter instanceof y&&r.adapter.getSessionBindings().delete(t.session_id);const a=this.config.adapterType??"acp",d=this.resolveBindingChannelKey(a);this.aibotHandle.sendMsg({event_id:t.event_id,session_id:t.session_id,msg_type:1,content:i,extra:{channel_data:{[d]:{sessionBinding:{status:"missing",reason:"binding_stale",error_code:p.invalidCwd}}}},quoted_message_id:t.msg_id});return}this.aibotHandle.sendEventResult({event_id:t.event_id,status:"failed",msg:i,updated_at:Date.now()})})}),this.aibotHandle.onStop(t=>{try{this.handleAibotStop(t)}catch(o){h.error(this.name,`handleAibotStop failed: ${o}`)}}),this.aibotHandle.onAgentDeleted(t=>{h.warn(this.name,`agent deleted on platform (source=${t?.source??"unknown"}${t?.reason?` reason=${t.reason}`:""}), notifying manager to clean up`);try{this.agentDeletedHandler?.()}catch(o){h.error(this.name,`agentDeletedHandler failed: ${o}`)}}),this.aibotHandle.onShareSet(t=>{try{this.shareSetHandler?.(Array.isArray(t?.shared_to)?t.shared_to:[])}catch(o){h.error(this.name,`onShareSet failed: ${o}`)}}),this.aibotHandle.onProfilePush(t=>{try{this.applyAgentProfile(t?.agent_name,t?.introduction,{source:"profile_push",respawnOnChange:!0})}catch(o){h.error(this.name,`onProfilePush failed: ${o}`)}}),this.aibotHandle.onSkillSync(t=>{try{h.info(this.name,`skill_sync received owner=${t?.owner_id??""} name=${t?.name??""}`),this.skillSyncHandler?.()}catch(o){h.error(this.name,`onSkillSync failed: ${o}`)}}),this.aibotHandle.onRevoke(t=>{try{this.handleAibotRevoke(t)}catch(o){h.error(this.name,`handleAibotRevoke failed: ${o}`)}}),this.aibotHandle.onLocalAction(t=>{this.handleAibotLocalAction(t).catch(o=>{h.error(this.name,`handleAibotLocalAction failed: ${o}`)})}),this.aibotHandle.onEventCancel(t=>{h.info(this.name,`recv event_cancel event_id=${t.event_id} session_id=${t.session_id}`),this.handleEventCancel(t).catch(o=>{h.error(this.name,`handleEventCancel failed: ${o}`)})}),this.aibotHandle.onMcpFrame((t,o)=>{const i=this.pool.getSlot(t)?.adapter;i?.deliverMcpFrameToAgent?i.deliverMcpFrameToAgent(o):h.warn(this.name,`mcp_frame: no adapter for session=${t}`)}),this.aibotHandle.onQueueClear(t=>{const o=this.pool.clearQueue(t.session_id);this.aibotHandle.sendQueueClearResult({session_id:t.session_id,canceled_event_ids:o}),this.pushQueueSnapshotForSession(t.session_id)}),typeof this.aibotHandle.onQueueReorder=="function"&&this.aibotHandle.onQueueReorder(t=>{const o=Array.isArray(t.ordered_event_ids)?t.ordered_event_ids.filter(n=>typeof n=="string"&&n.length>0):[],i=this.pool.reorderQueue(t.session_id,o);this.aibotHandle.sendQueueReorderResult({session_id:t.session_id,applied_event_ids:i}),this.pushQueueSnapshotForSession(t.session_id)}),typeof this.aibotHandle.onEventHold=="function"&&this.aibotHandle.onEventHold(t=>{const o=typeof t.session_id=="string"?t.session_id:"",i=typeof t.event_id=="string"?t.event_id:"",n=t.hold!==!1;if(h.info(this.name,`recv event_hold event_id=${i} session_id=${o} hold=${n} reason=${t.reason??""}`),!o||!i){this.aibotHandle.sendEventHoldResult({session_id:o,event_id:i,ok:!1,held:!1,error:"bad_request"});return}const r=typeof t.reason=="string"?t.reason:"",a=typeof t.ttl_ms=="number"?t.ttl_ms:void 0,d=this.pool.holdEvent(o,i,n,r,a),c=d==="ok";this.aibotHandle.sendEventHoldResult({session_id:o,event_id:i,ok:c,held:c?n:!1,...c?{}:{error:d}}),c&&this.pushQueueSnapshotForSession(o)}),typeof this.aibotHandle.onQueueEdit=="function"&&this.aibotHandle.onQueueEdit(t=>{const o=typeof t.session_id=="string"?t.session_id:"",i=typeof t.event_id=="string"?t.event_id:"";if(h.info(this.name,`recv queue_edit event_id=${i} session_id=${o}`),!o||!i){this.aibotHandle.sendQueueEditResult({session_id:o,event_id:i,ok:!1,error:"bad_request"});return}const n=typeof t.content=="string"?t.content:"",r=this.pool.editQueuedEvent(o,i,n),a=r==="ok";this.aibotHandle.sendQueueEditResult({session_id:o,event_id:i,ok:a,...a?{}:{error:r}}),a&&this.pushQueueSnapshotForSession(o)}),typeof this.aibotHandle.onQueueSnapshotQuery=="function"&&this.aibotHandle.onQueueSnapshotQuery(t=>{this.replyQueueSnapshotForSession(t.session_id)}),h.info(this.name,"Connected to aibot"),this.activeEventStore){const t=await this.activeEventStore.drain();if(t.length>0){h.warn(this.name,`Recovering ${t.length} stale event(s) from previous run`);for(const o of t)h.info(this.name,`Failing stale event on startup: ${o}`),this.aibotHandle.sendEventResult({event_id:o,status:"failed",msg:"process restarted, event lost",updated_at:Date.now()})}}this.pushQueueSnapshots(),this.relayStateSyncOnConnect(),this.aibotHandle.onReconnected(()=>{this.pushQueueSnapshots();const t=this.aibotHandle.authAck;this.applyAgentProfile(t?.agent_name,t?.introduction,{source:"reconnect",respawnOnChange:!0}),this.forceRefreshSkills(void 0,{force:!0}),this.relayStateSyncOnConnect()}),this.aibotHandle.onStreamRejected((t,o)=>{this.sendCtrl.markEventRejected(t)})}applyAgentProfile(e,s,t){const o=String(e??"").trim(),i=String(s??"").trim(),n=o!==this.agentProfile.agentName||i!==this.agentProfile.introduction;this.agentProfile={agentName:o,introduction:i},o||i?h.info(this.name,`agent profile (${t.source}): GOT name="${o}" intro_len=${i.length} changed=${n}`):h.warn(this.name,`agent profile (${t.source}): EMPTY \u2014 \u670D\u52A1\u7AEF\u672A\u4E0B\u53D1 agent_name/introduction\uFF08auth_ack \u5B57\u6BB5\u7F3A\u5931\u6216\u503C\u4E3A\u7A7A\uFF09`),n&&t.respawnOnChange&&this.applyProfileChangeToAdapters("agent_profile_changed")}applyProfileChangeToAdapters(e){if(!this.pool)return;const s=this.pool.getAllSlots();let t=0;for(const r of s)if(r.adapter.onAgentProfileChanged)try{r.adapter.onAgentProfileChanged(),t++}catch(a){h.warn(this.name,`onAgentProfileChanged failed for session=${r.sessionId}: ${a}`)}const o=s.filter(r=>r.adapter instanceof M),i=o.filter(r=>{if(r.state!=="ready")return!1;const a=r.adapter.getStatus();return!a.busy&&!a.backgroundBusy}),n=o.length-i.length;h.info(this.name,`${e}: notified ${t} adapter(s) via hook; respawning ${i.length} idle Claude slot(s), skipping ${n} busy`);for(const r of i)this.pool.removeSlot(r.sessionId).catch(a=>{h.warn(this.name,`removeSlot failed during ${e}: ${a}`)})}pushQueueSnapshots(){if(!(!this.config.eventQueue||!this.pool))for(const e of this.pool.getAllSlots())this.pushQueueSnapshotForSession(e.sessionId)}buildQueueSnapshotPayload(e){const s=this.pool?.getQueueSnapshot(e)??null,t=s?[...s.running]:[],o=s?s.running_items.map(n=>({event_id:n.event_id,...n.content_preview?{content_preview:n.content_preview}:{},...n.title?{title:n.title}:{},...n.summary?{summary:n.summary}:{},actions:[{type:"stop"}]})):[],i=s?s.queued.map(n=>({event_id:n.event_id,position:n.position,...n.content_preview?{content_preview:n.content_preview}:{},...typeof n.content=="string"?{content:n.content}:{},...n.title?{title:n.title}:{},...n.summary?{summary:n.summary}:{},held:n.held===!0,held_reason:n.held_reason??"",actions:[{type:"cancel"}]})):[];if(t.length===0&&this.selfDrivenSessions.has(e)&&this.pool?.getSlot(e)){const n=`selfdrive_${e}`,r=this.selfDrivenLabels.get(e)??"Background task in progress";t.push(n),o.push({event_id:n,content_preview:r,title:r,summary:r,actions:[]})}return{session_id:e,running:t,running_items:o,queued:i}}pushQueueSnapshotForSession(e){if(!this.config.eventQueue||!this.pool)return;const s=this.buildQueueSnapshotPayload(e);h.info(this.name,`[queue-debug] push snapshot session=${e} running=${s.running.length} queued=${s.queued.length} running_ids=[${s.running.join(",")}]`),this.aibotHandle.sendQueueSnapshot(s)}replyQueueSnapshotForSession(e){!this.config.eventQueue||!this.pool||this.aibotHandle.sendQueueSnapshot(this.buildQueueSnapshotPayload(e))}async platformInvoke(e,s,t){return e==="file_link"?Ut(s):e==="file_upload"?this.uploadFileAndSendMedia(s):this.aibotHandle.agentInvoke(e,s,t)}async uploadFileAndSendMedia(e){const s=String(e.file_path??"").trim(),t=String(e.session_id??"").trim(),o=String(e.caption??"").trim(),i=String(e.reply_to_message_id??"").trim();if(!s)throw new Error("file_path is required");if(!t)throw new Error("session_id is required");const n=await Wt({wsURL:this.config.aibot.url,apiKey:this.config.aibot.apiKey,sessionID:t,filePath:s}),r=await this.aibotHandle.sendMedia({session_id:t,msg_type:2,content:o||`[${n.attachment_type}]`,client_msg_id:`file_upload_${K()}`,...i?{quoted_message_id:i}:{},extra:n.extra});if(r.cmd!=="send_ack"){const d=r.payload??{},c=String(d.msg??r.cmd);throw new Error(`media message send failed: ${c}`)}const a=r.payload??{};return{ok:!0,file_name:n.file_name,attachment_type:n.attachment_type,access_url:n.access_url,message_id:a.msg_id!=null?String(a.msg_id):null}}sendReplyByRuntimeConfig(e,s,t,o,i){const n=this.indexEventSession(e,s)??s;this.auditController.captureReply(e,t),this.sendCtrl.sendReply(e,n,t,o,i),t&&this.conversationLog?.logOutbound?.(n,e,"reply",t)}stampCodexEventQuote(e){if(e.quoted_message_id!=null){if(e.quoted_message_id)return e;const{quoted_message_id:n,...r}=e;return r}const s=e;if(s.codex_method!=="item/agentMessage/delta")return e;const o=s.codex_payload?.params?.phase;if(typeof o=="string"&&o.trim()&&o.trim().toLowerCase()!=="final_answer")return e;const i=this.sendCtrl.getDefaultQuotedMessageId(e.event_id);return i?{...e,quoted_message_id:i}:e}captureCodexAuditOutput(e){if(e.codex_method!=="item/agentMessage/delta")return;const s=e.codex_payload?.params,t=typeof s?.phase=="string"?s.phase.trim().toLowerCase():"";if(t&&t!=="final_answer")return;const o=s?.delta;typeof o!="string"||!o||this.auditController.captureUnsequencedStreamChunk(e.event_id,o)}discardEventTrackingState(e){this.inflightEvents.delete(e),this.restartCount.delete(e),this.eventSessionIndex.delete(e),this.sendCtrl.discardEventState(e)}reliableFinalWiring(e,s){return async(t,o,i)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(t,o,i,s)}catch(n){throw h.error("bridge",`[${e}] sendFinalStreamChunkReliable ACK failed event=${t}: ${n}`),n}h.info("bridge",`[${e}] sendFinalStreamChunkReliable done event=${t}`)}}sendStreamChunkByRuntimeConfig(e,s,t,o,i,n,r){const a=this.indexEventSession(e,s)??s;this.auditController.captureStreamChunk(e,o,t),this.sendCtrl.sendStreamChunk(e,a,t,o,i,n,r),(t||i)&&this.conversationLog?.logOutbound?.(a,e,i?"stream_chunk_finish":"stream_chunk",t)}surfacedRunErrorEvents=new Set;sendRunErrorAsChunk(e,s,t){this.surfacedRunErrorEvents.has(e)||(this.surfacedRunErrorEvents.add(e),this.sendStreamChunkByRuntimeConfig(e,s,`
8
8
 
9
- Error: ${t}`,1,!1))}sendEventResultWithCleanup(e,s,t,o){const i=this.eventSessionIndex.get(e);s==="failed"&&i&&t?.trim()&&this.sendRunErrorAsChunk(e,i,t),this.auditController.markResponded(e,s,t),this.sendCtrl.sendEventResult(e,s,t,o),i&&(this.pool.eventComplete(e,i)===!1&&h.error(this.name,`Event terminal result could not release queue slot event=${e} session=${i} status=${s}`),this.pushQueueSnapshotForSession(i),this.conversationLog?.logResult?.(i,e,s,t),this.eventSessionIndex.delete(e)),this.inflightEvents.delete(e),this.restartCount.delete(e),this.surfacedRunErrorEvents.delete(e),s==="responded"&&(this.cachedProviderQuotaSampledAtMs=null,this.refreshAndPushProviderQuota(!0).catch(()=>{}))}async handleSessionInternalError(e){const{eventId:s,sessionId:t,errorMsg:o}=e;if(this.stopped)return;const i=this.inflightEvents.get(s);if(!i){h.warn(this.name,`[recovery] no inflight event for internalError event=${s} session=${t}; surface failure directly`),this.sendRunErrorAsChunk(s,t,o),this.sendEventResultWithCleanup(s,"failed",o,"agent_stop_failure");return}const n=(this.restartCount.get(s)??0)+1;this.restartCount.set(s,n);const r=this.config.adapterType??"acp";if(n>te){h.error(this.name,`[recovery] adapter=${r} session=${t} event=${s} restart=${n}/${te} outcome=give-up err=${o}`),this.sendRunErrorAsChunk(s,t,o),this.sendEventResultWithCleanup(s,"failed",o,"agent_stop_failure");return}h.info(this.name,`[recovery] adapter=${r} session=${t} event=${s} restart=${n}/${te} outcome=restarting err=${o}`);const a=this.pool.drainQueuedForSession(t);a.length>0&&h.info(this.name,`[recovery] session=${t} preserved ${a.length} queued sibling event(s) across restart`);try{await this.pool.removeSlot(t)}catch(l){h.warn(this.name,`[recovery] removeSlot failed session=${t}: ${l instanceof Error?l.message:String(l)}`)}if(this.stopped)return;const d=e.replayOriginalContent?i.content:this.resolveRecoveryPrompt(r,i),c={...i,content:d};try{await this.pool.deliverInboundEvent(c)}catch(l){h.error(this.name,`[recovery] redeliver failed event=${s} session=${t}: ${l instanceof Error?l.message:String(l)}`),this.sendEventResultWithCleanup(s,"failed",l instanceof Error?l.message:String(l));return}for(const l of a){if(this.stopped)break;try{await this.pool.deliverInboundEvent(l)}catch(u){h.error(this.name,`[recovery] sibling redeliver failed event=${l.event_id} session=${t}: ${u instanceof Error?u.message:String(u)}`),this.sendEventResultWithCleanup(l.event_id,"failed",u instanceof Error?u.message:String(u))}}}resolveRecoveryPrompt(e,s){return e==="acp"?"continue":s.content}sendThinkingByRuntimeConfig(e,s,t){this.sendCtrl.sendThinking(e,s,t)}bufferStreamChunk(e,s,t,o,i){this.auditController.captureUnsequencedStreamChunk(e,t),this.sendCtrl.bufferOnly(e,s,t,o,i)}flushBufferedStreamText(e){}resolveEventRuntimeConfig(e){return this.sendCtrl.resolveEventRuntimeConfig(e)}captureEventRuntimeConfig(e){this.sendCtrl.captureEventRuntimeConfig(e),this.indexEventSession(e.event_id,e.session_id),this.auditController.markRecording(e.event_id),e.event_id&&!this.inflightEvents.has(e.event_id)&&this.inflightEvents.set(e.event_id,e)}indexEventSession(e,s){if(!e||!s)return;const t=this.eventSessionIndex.get(e);return t?(t!==s&&h.warn(this.name,`Ignoring event session mismatch event=${e} indexed=${t} supplied=${s}`),t):(this.eventSessionIndex.set(e,s),s)}shouldDropToolDisplayEvent(e){return this.sendCtrl.shouldDropToolDisplayEvent(e)}shouldDropThinkingDisplayEvent(e){return this.sendCtrl.shouldDropThinkingDisplayEvent(e)}shouldDropCodexDisplayEvent(e,s){return this.sendCtrl.shouldDropCodexDisplayEvent(e,s)}logCodexEventToConversation(e){if(!this.conversationLog||e.codex_method!=="item/agentMessage/delta")return;const t=e.codex_payload?.params?.delta;if(!t)return;const o=this.eventSessionIndex.get(e.event_id)??e.session_id;this.conversationLog.append(o,{ts:Date.now(),dir:"outbound",event_id:e.event_id,kind:"codex_delta",text_len:t.length,content:t})}isAcpRawTransportEnabled(){return(this.config.adapterOptions??{}).raw_transport===!0}shouldDropAcpRawDisplayEvent(e,s){return this.sendCtrl.shouldDropAcpRawDisplayEvent(e,s)}sendAcpRawEventEnvelope(e,s,t){this.shouldDropAcpRawDisplayEvent(e,t.type)||this.deliverRawEventEnvelope(e,s,t,"acp",this.buildAcpRawEventFallbackText(t))}buildAcpRawEventFallbackText(e){const s=String(e.type??"").trim();if(!s)return"[acp] event";switch(s){case"permission_request":return`Permission required: ${String(e.payload?.tool_title??e.payload?.tool_name??"permission request")}`;case"tool_use":return`[tool] ${String(e.payload?.tool_name??"tool")}`;case"tool_result":return"[tool result]";case"thinking":return"[thinking]";case"error":return`[error] ${String(e.payload?.message??"agent error")}`;case"result":return"[result]";default:return`[acp] ${s}`}}rawDetailSeq=0;deliverRawEventEnvelope(e,s,t,o,i){const n=ei({envelope:t,fallbackText:i,channelKey:o,allocateRefId:()=>`${e}_rawd_${++this.rawDetailSeq}`}),r=()=>{this.aibotHandle.sendMsg({event_id:e,session_id:s,msg_type:1,content:n.fallbackText,extra:{channel_data:{[o]:{raw_event:n.envelope}},agent_api_origin:!0}})};if(!n.sharded){r();return}h.info("bridge",`${o} raw_event oversized, sharded delivery: event=${e} fields=${n.oversizedFields.map(a=>a.field).join(",")}`),(async()=>{for(const a of n.oversizedFields)await this.sendCtrl.deliverAuxiliaryLargeText(e,s,ti({envelopeType:t.type,field:a.field,fullText:a.fullText}),a.refClientMsgId);r()})().catch(a=>{h.warn("bridge",`${o} raw_event sharded delivery failed event=${e}: ${a}`)})}buildCursorRawEventFallbackText(e){const s=String(e?.type??"").trim(),t=e?.payload&&typeof e.payload=="object"?e.payload:{};switch(s){case"permission_request":return`Permission required: ${String(t.tool_title??t.tool_name??"permission request")}`;case"tool_use":case"tool_call":case"tool_execution_start":return`[tool] ${String(t.tool_name??t.toolName??"tool")}`;case"tool_result":case"tool_execution_end":case"tool_execution_update":return"[tool result]";case"error":return`[error] ${String(t.message??"agent error")}`;default:return s?`[cursor] ${s}`:"[cursor] event"}}sendToolExecutionCard(e,s,t,o){this.sendCtrl.sendToolExecutionCard(e,s,t,o)}sendGrixApprovalCard(e,s){this.aibotHandle.sendMsg({event_id:e.eventId,session_id:e.sessionId,client_msg_id:`perm_${K()}`,msg_type:1,content:e.toolTitle?`Permission required: ${e.toolTitle}`:"Permission request",extra:{channel_data:{execApproval:{approvalId:e.approvalId,approvalSlug:e.toolName},grix:{execApproval:{approval_command_id:e.approvalId,command:e.toolTitle||e.toolName,host:s}}},agent_api_origin:!0}})}sendGrixAgentQuestionCard(e,s,t){const o=t.questions.map(n=>n.header).join(", "),i=ve(`[Agent Question] ${t.request_id}`,"agent_question",t);this.aibotHandle.sendText({event_id:e,session_id:s,content:i,msg_type:1,extra:{card_type:"agent_question",summary_text:o}})}handleOpenCodeQuestionReplyEvent(e){const s=Dt(String(e.content??""));if(!s)return!1;this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const o=this.pool.getSlot(e.session_id)?.adapter,i=o instanceof G?o.handleQuestionReplyEvent(s):{delivered:!1,errorCode:"interaction_request_not_pending",errorMsg:"The OpenCode question is no longer pending; the reply was not delivered."};return i.delivered?(h.info(this.name,`[opencode] question reply delivered event=${e.event_id} session=${e.session_id} request=${s.request_id}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()})):(h.warn(this.name,`[opencode] question reply rejected event=${e.event_id} session=${e.session_id} request=${s.request_id} code=${i.errorCode??"interaction_reply_failed"}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:i.errorCode??"interaction_reply_failed",msg:i.errorMsg??"The question reply was not delivered.",updated_at:Date.now()})),!0}async handleAibotEvent(e){if(this.relayEnvStale&&!this.hasPendingWork()&&await this.recycleAdaptersForRelayChange(),this.stopped){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:"agent shutting down",updated_at:Date.now()});return}this.logInboundConversation(e);const s=this.config.adapterType??"acp";if(s==="opencode"&&this.handleOpenCodeQuestionReplyEvent(e))return;const t=zt(e.extra);if(t.error){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"connector_config_invalid",msg:t.error,updated_at:Date.now()});return}const o=t.patch,i=ui(e.extra);if((i.state!=="absent"||i.error)&&h.info(this.name,`[audit-marker] event=${e.event_id} session=${e.session_id} msg=${e.msg_id??""} state=${i.state??"error"} scope=${i.options?.enabled?i.options.scope:""} error=${i.error??""}`),i.error){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"audit_config_invalid",msg:i.error,updated_at:Date.now()});return}if(i.state==="enabled"&&s!=="claude"&&s!=="codex"&&s!=="cursor"&&s!=="opencode"&&s!=="pi"&&s!=="codewhale"&&s!=="acp"){if(this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"audit_provider_unsupported",msg:`Audit replay is not supported for adapter: ${s}`,updated_at:Date.now()}),i.options?.enabled&&i.options.scope==="turn")try{this.aibotHandle.sendAuditState(Z({state:"failed",eventId:e.event_id,sessionId:e.session_id,...e.msg_id===void 0?{}:{msgId:e.msg_id},errorCode:"audit_provider_unsupported",errorMessage:`Audit replay is not supported for adapter: ${s}`},Date.now()))}catch{}return}const n=Lt(e);if(n){if(i.state!=="absent"||n.verb===_.open)try{this.auditController.resolveSession({sessionId:e.session_id,provider:this.resolveAuditProvider(),extra:e.extra})}catch(c){this.sendAuditConfigurationError(e,c);return}if(n.verb===_.exec){await this.handleSessionControlCommand(n,e);return}if(n.verb===_.listSessions){await this.handleListSessionsTextCommand(e);return}if(s==="claude"){await this.handleSessionControlCommand(n,e);return}if(s==="codex"&&n.verb===_.open){await this.handleCodexSessionControlOpen(n,e);return}if(s==="pi"&&n.verb===_.open){await this.handlePiSessionControlOpen(n,e);return}if(s==="pi"&&n.verb===_.restart){await this.handlePiSessionControlRestart(e);return}if((s==="openhuman"||s==="opencode")&&n.verb===_.open){await this.handleOpenHumanSessionControlOpen(n,e);return}if(s==="codewhale"&&n.verb===_.open){await this.handleCodeWhaleSessionControlOpen(n,e);return}if(this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),n.verb===_.open){const c=n.args.trim();if(!c){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:p.cwdRequired,msg:"cwd is required",updated_at:Date.now()});return}try{const l=P.resolve(c);if(!(await W(l)).isDirectory()){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:p.invalidCwd,msg:`Path is not a directory: ${l}`,updated_at:Date.now()});return}}catch(l){const u=String(l?.code??""),g=u==="ENOENT"?`Directory does not exist: ${P.resolve(c)}`:u==="EACCES"||u==="EPERM"?"Directory is not accessible":`Invalid path: ${c}`;this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:p.invalidCwd,msg:g,updated_at:Date.now()});return}}if(n.verb===_.open){const c=this.bindingStore.get(e.session_id);if(c?.cwd)try{await W(c.cwd)}catch{h.info("bridge",`Stale binding detected for session ${e.session_id}: ${c.cwd} no longer exists, clearing`),this.bindingStore.delete(e.session_id),this.sessionBindings.delete(e.session_id),this.sessionProviderHints.delete(e.session_id),this.sessionProviderQuotas.delete(e.session_id),this.sessionProviderMeta.delete(e.session_id);const l=this.pool.getSlot(e.session_id);l?.adapter instanceof y&&l.adapter.getSessionBindings().delete(e.session_id)}}if(await this.handleSessionControlForPool(n,e),s==="acp"&&n.verb===_.stop){const l=this.bindingStore.get(e.session_id)?.cwd??"";await this.pool.removeSlot(e.session_id).catch(()=>{}),this.sessionBindings.delete(e.session_id),this.sessionProviderHints.delete(e.session_id),this.sessionProviderQuotas.delete(e.session_id),this.sessionProviderMeta.delete(e.session_id),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",msg:`Session worker stopped for ${l}`,updated_at:Date.now()});return}if(ue(n,e,this.sessionControlCtx(e.session_id),{...this.sessionControlSenders(),sendEventAck:()=>{}}),n.verb===_.open&&(await this.deferredMgr.release(e.session_id,this.deferredCallbacks()),s==="agy")){const c=this.bindingStore.get(e.session_id)?.cwd??"";c&&this.aibotHandle.sendUpdateBindingCard({session_id:e.session_id,worker_status:"ready",cwd:c,meta:this.buildAgyToolbarMeta(e.session_id)})}return}if(e.mirror_mode==="record_only"){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()});return}if(this.isStaleEvent(e)){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"event_stale",msg:"event is stale and will not be processed",updated_at:Date.now()});return}let r;try{r=this.auditController.resolveSession({sessionId:e.session_id,provider:this.resolveAuditProvider(),extra:e.extra,eventId:e.event_id}).session}catch(c){this.sendAuditConfigurationError(e,c);return}if(vi.has(s)&&!this.bindingStore.get(e.session_id)?.cwd){const l=s;h.info(this.name,`[${l}] binding missing session_id=${e.session_id} event_id=${e.event_id}`),this.deferredMgr.defer(l,String(e.session_id??"").trim(),this.prepareAuditedInboundEvent(e,o,r));const u=this.resolveBindingChannelKey(s);this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendMsg({event_id:e.event_id,session_id:e.session_id,msg_type:1,content:"Session binding missing.",extra:{channel_data:{[u]:{sessionBinding:{status:"missing",reason:"binding_missing",error_code:p.bindingMissing}}}},quoted_message_id:e.msg_id});return}if((this.config.adapterType??"acp")==="acp"){const l=String(e.content??"").trim().match(/^\/(\S+)\s*(.*)/);if(l){const[,u,g]=l,f=this.pool.getSlot(e.session_id)?.adapter;if(f?.execCommand&&(f.getSupportedCommands?.()??[]).some(m=>m.name===u||m.name===`/${u}`)){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});try{const m=await f.execCommand(u,g.trim(),e.session_id);m.status==="options"&&m.data&&this.handleExecCommandOptions(e.session_id,u,m.data),this.aibotHandle.sendEventResult({event_id:e.event_id,status:m.status==="failed"?"failed":"responded",msg:m.message,updated_at:Date.now()})}catch(m){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:m instanceof Error?m.message:String(m),updated_at:Date.now()})}return}}}if(s==="codex"&&oe(r?.options)){const c=this.pool.getSlot(e.session_id);if(c?.adapter instanceof ie&&!c.adapter.hasRawApiCaptureRelay()){const l=c.eventQueue.snapshot(e.session_id);l.running.length===0&&l.queued.length===0?(h.info(this.name,`[audit-raw-capture] recreating idle Codex adapter before event=${e.event_id} session=${e.session_id}`),await this.pool.removeSlot(e.session_id)):h.warn(this.name,`[audit-raw-capture] Codex adapter lacks relay but is not idle event=${e.event_id} session=${e.session_id} running=${l.running.length} queued=${l.queued.length}`)}}const d=this.prepareAuditedInboundEvent(e,o,r);try{this.captureEventRuntimeConfig(d),await this.pool.deliverInboundEvent(d)}catch(c){if(this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.auditController.closeWithoutAdapter(e.event_id,"failed",c instanceof Error?c.message:String(c),{deliveryFailed:!0}),this.discardEventTrackingState(e.event_id),c instanceof Ht)this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:c.message,updated_at:Date.now()});else throw c}}async handleCodexSessionControlOpen(e,s){const t=s.session_id,o=e.args.trim(),i=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()}),n=(r,a)=>this.aibotHandle.sendEventResult({event_id:s.event_id,status:r,...a,updated_at:Date.now()});if(!o){i(),n("failed",{msg:"Usage: /grix open <working-directory>",code:p.cwdRequired});return}try{const r=await this.resolveCwdForBinding(o),a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{if(await this.resolveCwdForBinding(a.cwd)===r){i(),n("responded",{msg:`Session already bound to ${a.cwd}`});return}}catch{d=!0,h.info("bridge",`Stale codex binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){i(),n("failed",{msg:`Session already bound to ${a.cwd}. Rebinding is not allowed.`,code:p.rebindForbidden});return}}this.bindingStore.set(t,r),this.sessionBindings.set(t,r),this.deferredMgr.sendCodexDeferredReplayComposing(t,this.deferredCallbacks()),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),i(),n("responded",{msg:`Session bound to ${r}`})}catch(r){i(),n("failed",{code:p.invalidCwd,msg:r instanceof Error?r.message:String(r)})}}async handleSessionControlForPool(e,s){e.verb===_.open&&await this.bindSessionForPool(s.session_id,e.args.trim())}async replayDeferredEventsForSession(e){await this.deferredMgr.release(e,this.deferredCallbacks())}async handleSessionControlLocalActionForPool(e){if(String(e.action_type??"")!==C.sessionControl)return;const s=e.params??{};if(String(s.verb??"").trim().toLowerCase()!==_.open)return;const o=String(s.session_id??"").trim(),i=String(s.cwd??"").trim();!o||!i||await this.bindSessionForPool(o,i)}async handleCodexSessionControlLocalActionOpen(e){const s=e.params??{},t=String(s.session_id??"").trim(),o=String(s.cwd??"").trim(),i=String(s.agent_session_id??"").trim(),n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t||!o){n("failed",void 0,p.cwdRequired,"session cwd is required");return}try{const r=await this.resolveCwdForBinding(o);this.ensureImportedAgentSession(i,r);const a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{const c=await this.resolveCwdForBinding(a.cwd);if(c===r){this.setResolvedAgentSessionId(t,i),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,c)});return}}catch{d=!0,h.info("bridge",`Stale codex binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){n("failed",void 0,p.rebindForbidden,`Session already bound to ${a.cwd}`);return}}this.bindingStore.set(t,r),this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,r),this.deferredMgr.sendCodexDeferredReplayComposing(t,this.deferredCallbacks()),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,r)})}catch(r){n("failed",void 0,r?.sessionControlErrorCode??p.invalidCwd,r instanceof Error?r.message:String(r))}}async handleCursorSessionControlLocalActionOpen(e){const s=e.params??{},t=String(s.session_id??"").trim(),o=String(s.cwd??"").trim(),i=String(s.agent_session_id??"").trim(),n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t||!o){n("failed",void 0,p.cwdRequired,"session cwd is required");return}try{const r=await this.resolveCwdForBinding(o);this.ensureImportedAgentSession(i,r);const a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{const c=await this.resolveCwdForBinding(a.cwd);if(c===r){this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,c),await this.bindSessionForPool(t,c),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:c,meta:this.buildCursorToolbarMeta(t)}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,c)});return}}catch{d=!0,h.info("bridge",`Stale cursor binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){n("failed",void 0,p.rebindForbidden,`Session already bound to ${a.cwd}`);return}}this.bindingStore.set(t,r),this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,r),this.deferredMgr.sendCursorDeferredReplayComposing(t,this.deferredCallbacks()),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r,meta:this.buildCursorToolbarMeta(t)}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,r)})}catch(r){n("failed",void 0,r?.sessionControlErrorCode??p.invalidCwd,r instanceof Error?r.message:String(r))}}async handlePiSessionControlOpen(e,s){const t=s.session_id,o=e.args.trim(),i=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()}),n=(r,a)=>this.aibotHandle.sendEventResult({event_id:s.event_id,status:r,...a,updated_at:Date.now()});if(!o){i(),n("failed",{msg:"Usage: /grix open <working-directory>",code:p.cwdRequired});return}try{const r=await this.resolveCwdForBinding(o),a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{if(await this.resolveCwdForBinding(a.cwd)===r){i(),n("responded",{msg:`Session already bound to ${a.cwd}`}),this.aibotHandle.sendMsg({event_id:s.event_id,session_id:t,msg_type:1,content:`\u2705 Session already bound to \`${a.cwd}\``,quoted_message_id:s.msg_id});return}}catch{d=!0,h.info("bridge",`Stale pi binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){i(),n("failed",{msg:`Session already bound to ${a.cwd}. Rebinding is not allowed.`,code:p.rebindForbidden});return}}this.bindingStore.set(t,r),this.sessionBindings.set(t,r),await this.ensureSlotStarted(t).catch(d=>{h.warn("bridge",`pi ensureSlotStarted on bind failed (non-fatal): ${d instanceof Error?d.message:String(d)}`)}),await this.deferredMgr.release(t,this.deferredCallbacks()),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),i(),n("responded",{msg:`Session bound to ${r}`}),this.aibotHandle.sendMsg({event_id:s.event_id,session_id:t,msg_type:1,content:`\u2705 Working directory bound: \`${r}\``,quoted_message_id:s.msg_id})}catch(r){i(),n("failed",{code:p.invalidCwd,msg:r instanceof Error?r.message:String(r)})}}async handlePiSessionControlRestart(e){const s=e.session_id,t=()=>this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:s,received_at:Date.now()}),o=(r,a)=>this.aibotHandle.sendEventResult({event_id:e.event_id,status:r,...a,updated_at:Date.now()}),n=this.bindingStore.get(s)?.cwd??"";if(!n){t(),o("failed",{msg:"session binding was not found",code:p.bindingMissing});return}t(),await this.pool.removeSlot(s).catch(()=>{}),this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"ready",cwd:n}),o("responded",{msg:`Session worker restarted for ${n}`})}async handlePiSessionControlRestartLocalAction(e){const s=e.params??{},t=String(s.session_id??"").trim(),i=(t?this.bindingStore.get(t):void 0)?.cwd??"",n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t){n("failed",void 0,"session_id_required","session_id is required for restart");return}if(!i){n("failed",void 0,p.bindingMissing,"Session binding missing. Open a workspace first.");return}await this.pool.removeSlot(t).catch(()=>{}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:i}),n("ok",{outcome:"restarted",binding:{aibotSessionId:t,cwd:i,workerStatus:"ready"}})}async syncOpenCodeBinding(e,s){if(!e||!s)return;try{this.resolveSessionModelId(e),this.resolveSessionModeId(e)}catch(o){h.warn(this.name,`[opencode] resolve global toolbar default failed: ${o instanceof Error?o.message:String(o)}`)}let t=this.pool.getSlot(e);!t&&(this.config.adapterType??"acp")==="opencode"&&(await this.ensureSlotStarted(e),t=this.pool.getSlot(e)),t?.startPromise&&await t.startPromise,t?.adapter instanceof G&&await t.adapter.bindSession(e,s)}async bindSessionForPool(e,s){const t=String(s??"").trim();if(!e||!t)return;const o=this.pool.getOrCreateSlot(e);if(!o||(o.startPromise&&await o.startPromise,!o.adapter))return;const i=o.adapter instanceof y?o.adapter:null;if(!i?.hasSessionBinding)return;const n=await this.resolveCwdForBinding(t);i.announceDeferredComposing(e),await i.bindSession(e,n),this.sessionBindings.set(e,n),this.sessionScanCache.invalidate(),i.replayDeferredEvents(e)}deferredCallbacks(){return{captureEventRuntimeConfig:e=>this.captureEventRuntimeConfig(e),deliverInboundEvent:e=>this.pool.deliverInboundEvent(e),sendEventResult:(e,s,t)=>this.sendEventResultWithCleanup(e,s,t),sendSessionComposing:(e,s,t)=>{const o={};s&&(o.ttl_ms=t?.ttlMs??3e4,t?.activity&&(o.activity=t.activity)),this.aibotHandle.sendSessionActivitySet({session_id:e,kind:"composing",active:s,...o})}}}async handleOpenHumanSessionControlOpen(e,s){const t=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:s.session_id,received_at:Date.now()});try{const o=await this.resolveCwdForBinding(e.args.trim());await this.handleSessionControlForPool(e,s),await this.syncOpenCodeBinding(s.session_id,o),ue(e,s,this.sessionControlCtx(s.session_id),this.sessionControlSenders()),await this.deferredMgr.release(s.session_id,this.deferredCallbacks())}catch(o){t(),this.aibotHandle.sendEventResult({event_id:s.event_id,status:"failed",code:o?.cwdErrorCode,msg:o instanceof Error?o.message:String(o),updated_at:Date.now()})}}async handleCodeWhaleSessionControlOpen(e,s){const t=s.session_id,o=e.args.trim(),i=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()}),n=(r,a)=>this.aibotHandle.sendEventResult({event_id:s.event_id,status:r,...a,updated_at:Date.now()});if(!o){i(),n("failed",{msg:"Usage: /grix open <working-directory>",code:p.cwdRequired});return}try{const r=await this.resolveCwdForBinding(o),a=this.bindingStore.get(t);if(a?.cwd){if(await this.resolveCwdForBinding(a.cwd)!==r){i(),n("failed",{msg:`Session already bound to ${a.cwd}. Rebinding is not allowed.`,code:p.rebindForbidden});return}i(),n("responded",{msg:`Session already bound to ${a.cwd}`});return}this.bindingStore.set(t,r),this.sessionBindings.set(t,r),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),i(),n("responded",{msg:`Session bound to ${r}`})}catch(r){i(),n("failed",{code:p.invalidCwd,msg:r instanceof Error?r.message:String(r)})}}async handleCodeWhaleSessionControlLocalActionOpen(e){const s=e.params??{},t=String(s.session_id??"").trim(),o=String(s.cwd??"").trim(),i=String(s.agent_session_id??"").trim(),n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t||!o){n("failed",void 0,p.cwdRequired,"session cwd is required");return}try{const r=await this.resolveCwdForBinding(o);this.ensureImportedAgentSession(i,r);const a=this.bindingStore.get(t);if(a?.cwd){const d=await this.resolveCwdForBinding(a.cwd);if(d!==r){n("failed",void 0,p.rebindForbidden,`Session already bound to ${a.cwd}`);return}this.setResolvedAgentSessionId(t,i),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,d)});return}this.bindingStore.set(t,r),this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,r),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,r)})}catch(r){n("failed",void 0,r?.sessionControlErrorCode??p.invalidCwd,r instanceof Error?r.message:String(r))}}normalizeClaudeModeId(e){return String(e??"").trim().toLowerCase()===R.approval?R.approval:R.fullAuto}handleExecCommandOptions(e,s,t){const o=Array.isArray(t?.options)?t.options:[];if(o.length===0)return;const n=this.bindingStore.get(e)?.cwd??"",r={};if(s==="model"){r.available_models=o.map(d=>({id:d.id,displayName:d.label}));const a=o.find(d=>d.current);a&&(r.model_id=a.id)}else if(s==="mode"){r.available_modes=o.map(d=>({id:d.id,displayName:d.label}));const a=o.find(d=>d.current);a&&(r.mode_id=a.id)}else r[`${s}_options`]=o;this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:n,meta:r})}resolveSessionModelId(e){const s=this.bindingStore.getModelId(e);if(s)return s;const t=String(this.globalConfigStore?.get(this.name)?.modelId??"").trim();if(t)return this.bindingStore.setModelId(e,t),t}resolveSessionModeId(e){const s=this.bindingStore.getModeId(e);if(s)return s;const t=String(this.globalConfigStore?.get(this.name)?.modeId??"").trim();if(t)return this.bindingStore.setModeId(e,t),t}resolveClaudeSessionEffort(e){const s=this.bindingStore.getEffort(e);if(s)return s;if(this.bindingStore.get(e)?.claudeSessionId)return;const o=V(this.globalConfigStore?.get(this.name)?.effort);if(o)return this.bindingStore.setEffort(e,o),o}resolveCodexSessionModelId(e){const s=this.bindingStore.getCodexModelId(e);if(s)return s;if(this.bindingStore.getCodexThreadId(e))return;const t=String(this.globalConfigStore?.get(this.name)?.codexModelId??"").trim();if(t)return this.bindingStore.setCodexModelId(e,t),t}resolveCodexNewSessionGlobalDefault(e,s,t){const o=String(s??"").trim();if(o&&!this.bindingStore.getCodexThreadId(e))return t(o),o}buildCursorToolbarMeta(e){const s=this.pool.getSlot(e);if(s?.adapter instanceof q)return s.adapter.getToolbarMeta(e);const t=this.bindingStore.getModelId(e)??"auto",o=this.bindingStore.getCursorModeId(e)??"full_auto";return{model_id:t,mode_id:o,currentModelId:t,currentModeId:o,available_models:[],available_modes:Ee.map(i=>({...i}))}}buildAgyToolbarMeta(e){if(!this.bindingStore.get(e))return;const t=Te(this.config.agent.command),o=t.length>0?t[0].id:"";let i=this.resolveSessionModelId(e)||o;t.length>0&&!t.some(r=>r.id===i)&&(i=o);const n=Pe();return{model_id:i,currentModelId:i,available_models:t.map(r=>({id:r.id,displayName:r.displayName})),...n.plan!==void 0&&{plan:n.plan},...n.quota_exhausted!==void 0&&{quota_exhausted:n.quota_exhausted},...n.quota_reset_at!==void 0&&{quota_reset_at:n.quota_reset_at},...n.available_credits!==void 0&&{available_credits:n.available_credits}}}async handleAgySetModel(e,s){const t=e.params??{},o=String(t.model_id??t.modelId??"").trim();if(!s){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for set_model"});return}if(!o){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"set_model_invalid",error_msg:"model_id is required"});return}const i=this.bindingStore.get(s);if(!i?.cwd){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:p.bindingMissing,error_msg:"session binding was not found"});return}i.modelId!==o&&(this.bindingStore.setModelId(s,o),this.globalConfigStore?.set(this.name,{modelId:o})),await xe().catch(()=>{}),this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"ready",cwd:i.cwd,meta:this.buildAgyToolbarMeta(s)}),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{outcome:"model_set",model_id:o,binding:{cwd:i.cwd,model_id:o}}})}buildClaudeToolbarMeta(e){const s=this.bindingStore.get(e);if(!s)return;const t=j(),o=t.length>0?t[0].id:"";let i=this.resolveSessionModelId(e)||o;t.length>0&&!t.some(g=>g.id===i)&&(i=o);const n=this.normalizeClaudeModeId(s.modeId);let r;try{const g=this.providerResolver?this.providerResolver():this.config.agent.provider;r=V(g?.effort)}catch{}const a=this.resolveClaudeSessionEffort(e)??r??"auto",d={model_id:i,mode_id:n,currentModelId:i,currentModeId:n,available_efforts:[...D],effort:a,reasoning_effort:a,available_models:t.map(g=>({id:g.id,displayName:g.displayName}))},c=this.pool.getSlot(e),l=c?.adapter instanceof M?c.adapter.getSessionState():null;(l?.rateLimits?.fiveHour||l?.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=l);const u=l??this.getFreshClaudeRateLimitState();if(u){const g=u.rateLimits;g&&(g.fiveHour||g.sevenDay)&&(d.rate_limits={...g.fiveHour?{fiveHour:g.fiveHour}:{},...g.sevenDay?{sevenDay:g.sevenDay}:{},sampledAt:u.sampledAt||Date.now()})}if(l){const g=l.contextWindow;g.usedPercentage!=null&&(d.context_window={usedPercentage:g.usedPercentage,remainingPercentage:g.remainingPercentage})}if(!d.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const g=this.providerQuotaToRateLimits(this.cachedProviderQuota);g&&(d.rate_limits=g),h.info(this.name,`[toolbar-meta] provider quota fallback: hasCached=${!!this.cachedProviderQuota} fromProvider=${JSON.stringify(g)}`)}return d.rate_limits&&h.info(this.name,`[toolbar-meta] rate_limits included: ${JSON.stringify(d.rate_limits)}`),d}providerQuotaToCodexRateLimits(e){return me(e,this.cachedProviderQuotaSampledAtMs??Date.now())}providerQuotaToRateLimits(e){return fe(e,this.cachedProviderQuotaSampledAtMs??Date.now())}async resolveCwdForBinding(e){const s=String(e??"").trim();if(process.platform!=="win32"&&(/^[a-zA-Z]:[\\/]/.test(s)||/^\\\\/.test(s))){const i=new Error(`Specified path is not valid on this host: ${s}`);throw i.cwdErrorCode=p.invalidCwd,i}const t=P.resolve(s);let o;try{o=await W(t)}catch(i){const n=String(i?.code??"");if(n==="ENOENT"){const r=new Error(`Specified path does not exist: ${t}`);throw r.cwdErrorCode=p.invalidCwd,r}if(n==="EACCES"||n==="EPERM"){const r=new Error("Specified path is not accessible.");throw r.cwdErrorCode=p.invalidCwd,r}throw i}if(!o.isDirectory()){const i=new Error("Specified path is not a directory.");throw i.cwdErrorCode=p.invalidCwd,i}try{return await be(t)}catch{return t}}getClaudeWorkerStatus(e){const s=this.pool.getSlot(e);return s?s.state==="starting"?"starting":s.state==="stopped"?"stopped":s.adapter.getStatus().busy?"busy":"ready":"stopped"}refreshClaudeWorkerStatusCard(e,s){const t=this.getClaudeWorkerStatus(e);return this.claudeWorkerStatus.set(e,t),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:t,cwd:s,meta:this.buildClaudeToolbarMeta(e)}),t}async handleSkillUploadLocalAction(e){const s=e.params??{},t=String(s.name??"").trim(),o=String(s.session_id??"").trim();if(!t){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"MISSING_SKILL_NAME",error_msg:"name is required"});return}const i=I(this.config.adapterType,this.config.aibot.clientType),n=this.bindingStore.get(o)?.cwd||this.sessionBindings.get(o)||void 0,r=i==="kiro"?n:n||process.cwd();try{await Ue(t,{mode:i,projectDir:r},{apiKey:this.config.aibot.apiKey,wsUrl:this.config.aibot.url}),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{name:t}})}catch(a){h.warn(this.name,`skill_upload failed name=${t}: ${a instanceof Error?a.message:String(a)}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"SKILL_UPLOAD_FAILED",error_msg:a instanceof Error?a.message:String(a)})}}async handleSkillEnableLocalAction(e){const s=e.params??{},t=String(s.name??"").trim(),o=String(s.session_id??"").trim(),i=String(s.scope??"").trim(),n=String(s.actor_id??"").trim(),r=s.force==="replace_link"||s.force==="replace_with_link"?s.force:void 0,a=I(this.config.adapterType,this.config.aibot.clientType),d=this.bindingStore.get(o)?.cwd||this.sessionBindings.get(o)||void 0;try{const c=await We({skillsDir:T.skills,mode:a,home:N(),cwd:d},{name:t,scope:i,actorId:n,force:r});h.info(this.name,`skill_enable name=${t} scope=${i} actor=${n||"-"} changed=${c.changed}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{name:c.name,scope:c.scope,path:c.path,changed:c.changed,enable_state:c.status,uninstallable:!0}})}catch(c){const l=c instanceof ae?c.code:"SKILL_ENABLE_FAILED";h.warn(this.name,`skill_enable failed name=${t} scope=${i}: ${c instanceof Error?c.message:String(c)}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:l,error_msg:c instanceof Error?c.message:String(c),result:{conflict_kind:l==="CONFLICT"||l==="NEEDS_FORCE"||l==="BLOCKED"?l.toLowerCase():void 0}})}this.forceRefreshSkills()}handleSkillRefreshLocalAction(e){const s=e.params??{},t=String(s.session_id??"").trim();if(this.forceRefreshSkills(t||void 0,{force:!0})){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{session_id:t||void 0}});return}h.warn(this.name,`skill_refresh produced no report session=${t||"-"}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"SKILL_REFRESH_FAILED",error_msg:"skill rescan produced no report (scan error or empty skill set)"})}async handleSkillDisableLocalAction(e){const s=e.params??{},t=String(s.name??"").trim(),o=String(s.session_id??"").trim(),i=String(s.scope??"").trim(),n=String(s.actor_id??"").trim(),r=I(this.config.adapterType,this.config.aibot.clientType),a=this.bindingStore.get(o)?.cwd||this.sessionBindings.get(o)||void 0;try{const d=await Ne({skillsDir:T.skills,mode:r,home:N(),cwd:a},{name:t,scope:i,actorId:n});h.info(this.name,`skill_disable name=${t} scope=${i} actor=${n||"-"} removed=${d.removed}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{name:d.name,scope:d.scope,path:d.path,removed:d.removed,enable_state:"none",uninstallable:!1}})}catch(d){const c=d instanceof ae?d.code:"SKILL_DISABLE_FAILED";h.warn(this.name,`skill_disable failed name=${t} scope=${i}: ${d instanceof Error?d.message:String(d)}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:c,error_msg:d instanceof Error?d.message:String(d),result:{conflict_kind:c==="CONFLICT"||c==="BLOCKED"?c.toLowerCase():void 0}})}this.forceRefreshSkills()}computeSkillReport(e){const s=I(this.config.adapterType,this.config.aibot.clientType),t=s==="kiro"?e:e||process.cwd();let o;try{o=Oe({mode:s,projectDir:t})}catch{return null}if(o.length===0)return null;const i=JSON.stringify(o.map(n=>`${n.source}:${n.name}`));return{skills:re(o,T.skills),hash:i}}reportSessionSkills(e){const s=this.bindingStore.get(e)?.cwd||this.sessionBindings.get(e)||void 0,t=this.computeSkillReport(s);if(!t)return;const o=this.buildLibrarySkillsReport(s),i=ee(t.skills,o);if(!(t.hash===this.lastReportedSkillsHash&&i===this.lastReportedSkillsWireHash)){this.lastReportedSkillsHash=t.hash,this.lastReportedSkillsWireHash=i;try{this.aibotHandle.sendSkillsUpdate({skills:t.skills,library_skills:o})}catch{}}}skillsSyncGroupKey(){const e=String(this.config.aibot.clientType??"").trim().toLowerCase()||"unknown",s=String(this.config.aibot.sharedOwnerId??"").trim();return s?`shared:${s}:${e}`:`primary:${e}`}forceRefreshSkills(e,s){const t=e?.trim(),o=t||this.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0}),i=t?this.bindingStore.get(t)?.cwd||this.sessionBindings.get(t)||void 0:o?this.bindingStore.get(o)?.cwd:void 0,n=this.computeSkillReport(i);if(!n)return!1;const r=this.buildLibrarySkillsReport(i),a=ee(n.skills,r);if(!s?.force&&a===this.lastReportedSkillsWireHash)return this.lastReportedSkillsHash=n.hash,!0;this.lastReportedSkillsHash=n.hash,this.lastReportedSkillsWireHash=a;try{return this.aibotHandle.sendSkillsUpdate({skills:n.skills,library_skills:r,...s?.ownerLibrarySync?{owner_library_sync:!0}:{}}),!0}catch{return!1}}adoptSkillsWireHashFromDisk(){const e=this.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0}),s=e?this.bindingStore.get(e)?.cwd:void 0,t=this.computeSkillReport(s);if(!t)return;const o=this.buildLibrarySkillsReport(s);this.lastReportedSkillsHash=t.hash,this.lastReportedSkillsWireHash=ee(t.skills,o)}buildLibrarySkillsReport(e){const s=I(this.config.adapterType,this.config.aibot.clientType);return Fe({skillsDir:T.skills,mode:s,home:N(),cwd:e})}async ensureSlotStarted(e,s=6e4){const t=this.pool.getOrCreateSlot(e);if(!t)throw new Error("Failed to allocate session slot");t.startPromise&&(h.info(this.name,`ensureSlotStarted: awaiting startPromise for session=${e}`),await Promise.race([t.startPromise,new Promise((o,i)=>setTimeout(()=>i(new Error(`ensureSlotStarted timeout (${s}ms) session=${e}`)),s))]),h.info(this.name,`ensureSlotStarted: startPromise resolved for session=${e}`))}resolveOrphanTitle(e){if(e){if(this.reasonixTitleScan){const s=lt(e);if(!s)return;const t=this.reasonixTitleScan.get().filter(o=>o.stamp===s);return t.length===1?t[0].title:void 0}if((this.config.adapterType??"acp")==="cursor")return this.sessionScanCache.get().find(t=>t.sessionId===e)?.title}}resolveAgentSessionId(e){switch(this.config.adapterType??"acp"){case"claude":return e.claudeSessionId;case"codex":return e.codexThreadId;case"pi":return e.piSessionPath;case"codewhale":return e.codewhaleThreadId;case"agy":return e.agyConversationId;default:return e.acpSessionId}}providerKeyForAdapter(){const e=this.config.adapterType??"acp";switch(e){case"claude":case"codex":case"pi":case"codewhale":return e;default:return"acp"}}setResolvedAgentSessionId(e,s){const t=String(e??"").trim(),o=String(s??"").trim();if(!t||!o)return;switch(this.config.adapterType??"acp"){case"claude":this.bindingStore.setClaudeSessionId(t,o);break;case"codex":this.bindingStore.setCodexThreadId(t,o);break;case"pi":this.bindingStore.setPiSessionPath(t,o);break;case"codewhale":this.bindingStore.setCodeWhaleThreadId(t,o);break;case"agy":this.bindingStore.setAgyConversationId(t,o);break;default:this.bindingStore.setAcpSessionId(t,o);break}this.sessionScanCache.invalidate()}normalizePathForCompare(e){const s=String(e??"").trim();if(!s)return"";const t=P.resolve(s);return process.platform==="win32"?t.toLowerCase():t}ensureImportedAgentSession(e,s){const t=String(e??"").trim();if(!t)return;const o=this.normalizePathForCompare(s);let i="";const n=this.config.adapterType??"acp";if(n==="codex"?i=this.sessionScanCache.get().find(d=>d.threadId===t)?.cwd??"":n==="claude"?i=this.sessionScanCache.get().find(d=>d.sessionId===t)?.cwd??"":n==="cursor"?i=this.sessionScanCache.get().find(d=>d.sessionId===t)?.cwd??"":n==="acp"&&(i=this.sessionScanCache.get().find(d=>d.sessionId===t)?.cwd??""),!i){for(const[,a]of this.bindingStore.entries())if(this.resolveAgentSessionId(a)===t){i=a.cwd??"";break}}if(!i){const a=new Error(`agent session not found: ${t}`);throw a.sessionControlErrorCode=p.invalidAgentSession,a}const r=this.normalizePathForCompare(i);if(r&&o&&r!==o){const a=new Error(`agent session cwd mismatch: expected ${s}, got ${i}`);throw a.sessionControlErrorCode=p.invalidAgentSession,a}}buildOpenedBindingResult(e,s,t="ready"){const o=this.bindingStore.get(e),i=o?String(this.resolveAgentSessionId(o)??"").trim():"",n={aibotSessionId:e,providerKey:this.providerKeyForAdapter(),cwd:s,workerStatus:t};return i&&(n.bindingId=i,n.agentSessionId=i),n}hasDiskScanner(){const e=this.config.adapterType??"acp";return e==="codex"||e==="claude"||e==="acp"}async handleListSessionsTextCommand(e){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const s=this.config.adapterType??"acp",t=new Map;for(const a of this.pool.getAllSlots())t.set(a.sessionId,a);const o=Array.from(this.bindingStore.entries()),i=new Map;for(const[a,d]of o){const c=this.resolveAgentSessionId(d);if(c){const l=t.get(a),u=l?l.adapter.getStatus().busy?"busy":"ready":"inactive";i.set(c,{aibotSessionId:a,workerStatus:u})}}const n=[],r=new Set;if(s==="codex"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.threadId);const c=i.get(d.threadId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.threadId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??(d.archived?"archived":"inactive")}`),n.push(` Created: ${new Date(d.createdAt).toISOString()}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="claude"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="acp"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="pi"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionPath);const c=i.get(d.sessionPath);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionPath}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="codewhale"||s==="opencode"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}for(const[a,d]of o){const c=this.resolveAgentSessionId(d);if(c&&r.has(c))continue;const l=t.get(a),u=l?l.adapter.getStatus().busy?"busy":"ready":"closed",g=this.resolveOrphanTitle(c)??(c?c.slice(0,8)+"\u2026":a.slice(0,8)+"\u2026");n.push(` Title: ${g}`),n.push(` AIBot: ${a}`),c&&n.push(` Agent: ${c}`),n.push(` CWD: ${d.cwd??"-"}`),n.push(` State: ${u}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}if(n.length===0){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",msg:"No sessions found.",updated_at:Date.now()});return}this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",msg:`Sessions (${n.filter(a=>a==="---").length}):
9
+ Error: ${t}`,1,!1))}sendEventResultWithCleanup(e,s,t,o){const i=this.eventSessionIndex.get(e);s==="failed"&&i&&t?.trim()&&this.sendRunErrorAsChunk(e,i,t),this.auditController.markResponded(e,s,t),this.sendCtrl.sendEventResult(e,s,t,o),i&&(this.pool.eventComplete(e,i)===!1&&h.error(this.name,`Event terminal result could not release queue slot event=${e} session=${i} status=${s}`),this.pushQueueSnapshotForSession(i),this.conversationLog?.logResult?.(i,e,s,t),this.eventSessionIndex.delete(e)),this.inflightEvents.delete(e),this.restartCount.delete(e),this.surfacedRunErrorEvents.delete(e),s==="responded"&&(this.cachedProviderQuotaSampledAtMs=null,this.refreshAndPushProviderQuota(!0).catch(()=>{}))}async handleSessionInternalError(e){const{eventId:s,sessionId:t,errorMsg:o}=e;if(this.stopped)return;const i=this.inflightEvents.get(s);if(!i){h.warn(this.name,`[recovery] no inflight event for internalError event=${s} session=${t}; surface failure directly`),this.sendRunErrorAsChunk(s,t,o),this.sendEventResultWithCleanup(s,"failed",o,"agent_stop_failure");return}const n=(this.restartCount.get(s)??0)+1;this.restartCount.set(s,n);const r=this.config.adapterType??"acp";if(n>te){h.error(this.name,`[recovery] adapter=${r} session=${t} event=${s} restart=${n}/${te} outcome=give-up err=${o}`),this.sendRunErrorAsChunk(s,t,o),this.sendEventResultWithCleanup(s,"failed",o,"agent_stop_failure");return}h.info(this.name,`[recovery] adapter=${r} session=${t} event=${s} restart=${n}/${te} outcome=restarting err=${o}`);const a=this.pool.drainQueuedForSession(t);a.length>0&&h.info(this.name,`[recovery] session=${t} preserved ${a.length} queued sibling event(s) across restart`);try{await this.pool.removeSlot(t)}catch(l){h.warn(this.name,`[recovery] removeSlot failed session=${t}: ${l instanceof Error?l.message:String(l)}`)}if(this.stopped)return;const d=e.replayOriginalContent?i.content:this.resolveRecoveryPrompt(r,i),c={...i,content:d};try{await this.pool.deliverInboundEvent(c)}catch(l){h.error(this.name,`[recovery] redeliver failed event=${s} session=${t}: ${l instanceof Error?l.message:String(l)}`),this.sendEventResultWithCleanup(s,"failed",l instanceof Error?l.message:String(l));return}for(const l of a){if(this.stopped)break;try{await this.pool.deliverInboundEvent(l)}catch(u){h.error(this.name,`[recovery] sibling redeliver failed event=${l.event_id} session=${t}: ${u instanceof Error?u.message:String(u)}`),this.sendEventResultWithCleanup(l.event_id,"failed",u instanceof Error?u.message:String(u))}}}resolveRecoveryPrompt(e,s){return e==="acp"?"continue":s.content}sendThinkingByRuntimeConfig(e,s,t){this.sendCtrl.sendThinking(e,s,t)}bufferStreamChunk(e,s,t,o,i){this.auditController.captureUnsequencedStreamChunk(e,t),this.sendCtrl.bufferOnly(e,s,t,o,i)}flushBufferedStreamText(e){}resolveEventRuntimeConfig(e){return this.sendCtrl.resolveEventRuntimeConfig(e)}captureEventRuntimeConfig(e){this.sendCtrl.captureEventRuntimeConfig(e),this.indexEventSession(e.event_id,e.session_id),this.auditController.markRecording(e.event_id),e.event_id&&!this.inflightEvents.has(e.event_id)&&this.inflightEvents.set(e.event_id,e)}indexEventSession(e,s){if(!e||!s)return;const t=this.eventSessionIndex.get(e);return t?(t!==s&&h.warn(this.name,`Ignoring event session mismatch event=${e} indexed=${t} supplied=${s}`),t):(this.eventSessionIndex.set(e,s),s)}shouldDropToolDisplayEvent(e){return this.sendCtrl.shouldDropToolDisplayEvent(e)}shouldDropThinkingDisplayEvent(e){return this.sendCtrl.shouldDropThinkingDisplayEvent(e)}shouldDropCodexDisplayEvent(e,s){return this.sendCtrl.shouldDropCodexDisplayEvent(e,s)}logCodexEventToConversation(e){if(!this.conversationLog||e.codex_method!=="item/agentMessage/delta")return;const t=e.codex_payload?.params?.delta;if(!t)return;const o=this.eventSessionIndex.get(e.event_id)??e.session_id;this.conversationLog.append(o,{ts:Date.now(),dir:"outbound",event_id:e.event_id,kind:"codex_delta",text_len:t.length,content:t})}isAcpRawTransportEnabled(){return(this.config.adapterOptions??{}).raw_transport===!0}shouldDropAcpRawDisplayEvent(e,s){return this.sendCtrl.shouldDropAcpRawDisplayEvent(e,s)}sendAcpRawEventEnvelope(e,s,t){this.shouldDropAcpRawDisplayEvent(e,t.type)||this.deliverRawEventEnvelope(e,s,t,"acp",this.buildAcpRawEventFallbackText(t))}buildAcpRawEventFallbackText(e){const s=String(e.type??"").trim();if(!s)return"[acp] event";switch(s){case"permission_request":return`Permission required: ${String(e.payload?.tool_title??e.payload?.tool_name??"permission request")}`;case"tool_use":return`[tool] ${String(e.payload?.tool_name??"tool")}`;case"tool_result":return"[tool result]";case"thinking":return"[thinking]";case"error":return`[error] ${String(e.payload?.message??"agent error")}`;case"result":return"[result]";default:return`[acp] ${s}`}}rawDetailSeq=0;deliverRawEventEnvelope(e,s,t,o,i){const n=ei({envelope:t,fallbackText:i,channelKey:o,allocateRefId:()=>`${e}_rawd_${++this.rawDetailSeq}`}),r=()=>{this.aibotHandle.sendMsg({event_id:e,session_id:s,msg_type:1,content:n.fallbackText,extra:{channel_data:{[o]:{raw_event:n.envelope}},agent_api_origin:!0}})};if(!n.sharded){r();return}h.info("bridge",`${o} raw_event oversized, sharded delivery: event=${e} fields=${n.oversizedFields.map(a=>a.field).join(",")}`),(async()=>{for(const a of n.oversizedFields)await this.sendCtrl.deliverAuxiliaryLargeText(e,s,ti({envelopeType:t.type,field:a.field,fullText:a.fullText}),a.refClientMsgId);r()})().catch(a=>{h.warn("bridge",`${o} raw_event sharded delivery failed event=${e}: ${a}`)})}buildCursorRawEventFallbackText(e){const s=String(e?.type??"").trim(),t=e?.payload&&typeof e.payload=="object"?e.payload:{};switch(s){case"permission_request":return`Permission required: ${String(t.tool_title??t.tool_name??"permission request")}`;case"tool_use":case"tool_call":case"tool_execution_start":return`[tool] ${String(t.tool_name??t.toolName??"tool")}`;case"tool_result":case"tool_execution_end":case"tool_execution_update":return"[tool result]";case"error":return`[error] ${String(t.message??"agent error")}`;default:return s?`[cursor] ${s}`:"[cursor] event"}}sendToolExecutionCard(e,s,t,o){this.sendCtrl.sendToolExecutionCard(e,s,t,o)}sendGrixApprovalCard(e,s){this.aibotHandle.sendMsg({event_id:e.eventId,session_id:e.sessionId,client_msg_id:`perm_${K()}`,msg_type:1,content:e.toolTitle?`Permission required: ${e.toolTitle}`:"Permission request",extra:{channel_data:{execApproval:{approvalId:e.approvalId,approvalSlug:e.toolName},grix:{execApproval:{approval_command_id:e.approvalId,command:e.toolTitle||e.toolName,host:s}}},agent_api_origin:!0}})}sendGrixAgentQuestionCard(e,s,t){const o=t.questions.map(n=>n.header).join(", "),i=ve(`[Agent Question] ${t.request_id}`,"agent_question",t);this.aibotHandle.sendText({event_id:e,session_id:s,content:i,msg_type:1,extra:{card_type:"agent_question",summary_text:o}})}handleOpenCodeQuestionReplyEvent(e){const s=Dt(String(e.content??""));if(!s)return!1;this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const o=this.pool.getSlot(e.session_id)?.adapter,i=o instanceof G?o.handleQuestionReplyEvent(s):{delivered:!1,errorCode:"interaction_request_not_pending",errorMsg:"The OpenCode question is no longer pending; the reply was not delivered."};return i.delivered?(h.info(this.name,`[opencode] question reply delivered event=${e.event_id} session=${e.session_id} request=${s.request_id}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()})):(h.warn(this.name,`[opencode] question reply rejected event=${e.event_id} session=${e.session_id} request=${s.request_id} code=${i.errorCode??"interaction_reply_failed"}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:i.errorCode??"interaction_reply_failed",msg:i.errorMsg??"The question reply was not delivered.",updated_at:Date.now()})),!0}async handleAibotEvent(e){if(this.relayEnvStale&&!this.hasPendingWork()&&await this.recycleAdaptersForRelayChange(),this.stopped){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:"agent shutting down",updated_at:Date.now()});return}this.logInboundConversation(e);const s=this.config.adapterType??"acp";if(s==="opencode"&&this.handleOpenCodeQuestionReplyEvent(e))return;const t=zt(e.extra);if(t.error){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"connector_config_invalid",msg:t.error,updated_at:Date.now()});return}const o=t.patch,i=ui(e.extra);if((i.state!=="absent"||i.error)&&h.info(this.name,`[audit-marker] event=${e.event_id} session=${e.session_id} msg=${e.msg_id??""} state=${i.state??"error"} scope=${i.options?.enabled?i.options.scope:""} error=${i.error??""}`),i.error){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"audit_config_invalid",msg:i.error,updated_at:Date.now()});return}if(i.state==="enabled"&&s!=="claude"&&s!=="codex"&&s!=="cursor"&&s!=="opencode"&&s!=="pi"&&s!=="codewhale"&&s!=="acp"){if(this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"audit_provider_unsupported",msg:`Audit replay is not supported for adapter: ${s}`,updated_at:Date.now()}),i.options?.enabled&&i.options.scope==="turn")try{this.aibotHandle.sendAuditState(Z({state:"failed",eventId:e.event_id,sessionId:e.session_id,...e.msg_id===void 0?{}:{msgId:e.msg_id},errorCode:"audit_provider_unsupported",errorMessage:`Audit replay is not supported for adapter: ${s}`},Date.now()))}catch{}return}const n=Lt(e);if(n){if(i.state!=="absent"||n.verb===_.open)try{this.auditController.resolveSession({sessionId:e.session_id,provider:this.resolveAuditProvider(),extra:e.extra})}catch(c){this.sendAuditConfigurationError(e,c);return}if(n.verb===_.exec){await this.handleSessionControlCommand(n,e);return}if(n.verb===_.listSessions){await this.handleListSessionsTextCommand(e);return}if(s==="claude"){await this.handleSessionControlCommand(n,e);return}if(s==="codex"&&n.verb===_.open){await this.handleCodexSessionControlOpen(n,e);return}if(s==="pi"&&n.verb===_.open){await this.handlePiSessionControlOpen(n,e);return}if(s==="pi"&&n.verb===_.restart){await this.handlePiSessionControlRestart(e);return}if((s==="openhuman"||s==="opencode")&&n.verb===_.open){await this.handleOpenHumanSessionControlOpen(n,e);return}if(s==="codewhale"&&n.verb===_.open){await this.handleCodeWhaleSessionControlOpen(n,e);return}if(this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),n.verb===_.open){const c=n.args.trim();if(!c){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:p.cwdRequired,msg:"cwd is required",updated_at:Date.now()});return}try{const l=T.resolve(c);if(!(await W(l)).isDirectory()){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:p.invalidCwd,msg:`Path is not a directory: ${l}`,updated_at:Date.now()});return}}catch(l){const u=String(l?.code??""),g=u==="ENOENT"?`Directory does not exist: ${T.resolve(c)}`:u==="EACCES"||u==="EPERM"?"Directory is not accessible":`Invalid path: ${c}`;this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:p.invalidCwd,msg:g,updated_at:Date.now()});return}}if(n.verb===_.open){const c=this.bindingStore.get(e.session_id);if(c?.cwd)try{await W(c.cwd)}catch{h.info("bridge",`Stale binding detected for session ${e.session_id}: ${c.cwd} no longer exists, clearing`),this.bindingStore.delete(e.session_id),this.sessionBindings.delete(e.session_id),this.sessionProviderHints.delete(e.session_id),this.sessionProviderQuotas.delete(e.session_id),this.sessionProviderMeta.delete(e.session_id);const l=this.pool.getSlot(e.session_id);l?.adapter instanceof y&&l.adapter.getSessionBindings().delete(e.session_id)}}if(await this.handleSessionControlForPool(n,e),s==="acp"&&n.verb===_.stop){const l=this.bindingStore.get(e.session_id)?.cwd??"";await this.pool.removeSlot(e.session_id).catch(()=>{}),this.sessionBindings.delete(e.session_id),this.sessionProviderHints.delete(e.session_id),this.sessionProviderQuotas.delete(e.session_id),this.sessionProviderMeta.delete(e.session_id),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",msg:`Session worker stopped for ${l}`,updated_at:Date.now()});return}if(ue(n,e,this.sessionControlCtx(e.session_id),{...this.sessionControlSenders(),sendEventAck:()=>{}}),n.verb===_.open&&(await this.deferredMgr.release(e.session_id,this.deferredCallbacks()),s==="agy")){const c=this.bindingStore.get(e.session_id)?.cwd??"";c&&this.aibotHandle.sendUpdateBindingCard({session_id:e.session_id,worker_status:"ready",cwd:c,meta:this.buildAgyToolbarMeta(e.session_id)})}return}if(e.mirror_mode==="record_only"){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()});return}if(this.isStaleEvent(e)){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:"event_stale",msg:"event is stale and will not be processed",updated_at:Date.now()});return}let r;try{r=this.auditController.resolveSession({sessionId:e.session_id,provider:this.resolveAuditProvider(),extra:e.extra,eventId:e.event_id}).session}catch(c){this.sendAuditConfigurationError(e,c);return}if(vi.has(s)&&!this.bindingStore.get(e.session_id)?.cwd){const l=s;h.info(this.name,`[${l}] binding missing session_id=${e.session_id} event_id=${e.event_id}`),this.deferredMgr.defer(l,String(e.session_id??"").trim(),this.prepareAuditedInboundEvent(e,o,r));const u=this.resolveBindingChannelKey(s);this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.aibotHandle.sendMsg({event_id:e.event_id,session_id:e.session_id,msg_type:1,content:"Session binding missing.",extra:{channel_data:{[u]:{sessionBinding:{status:"missing",reason:"binding_missing",error_code:p.bindingMissing}}}},quoted_message_id:e.msg_id});return}if((this.config.adapterType??"acp")==="acp"){const l=String(e.content??"").trim().match(/^\/(\S+)\s*(.*)/);if(l){const[,u,g]=l,f=this.pool.getSlot(e.session_id)?.adapter;if(f?.execCommand&&(f.getSupportedCommands?.()??[]).some(m=>m.name===u||m.name===`/${u}`)){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});try{const m=await f.execCommand(u,g.trim(),e.session_id);m.status==="options"&&m.data&&this.handleExecCommandOptions(e.session_id,u,m.data),this.aibotHandle.sendEventResult({event_id:e.event_id,status:m.status==="failed"?"failed":"responded",msg:m.message,updated_at:Date.now()})}catch(m){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:m instanceof Error?m.message:String(m),updated_at:Date.now()})}return}}}if(s==="codex"&&oe(r?.options)){const c=this.pool.getSlot(e.session_id);if(c?.adapter instanceof ie&&!c.adapter.hasRawApiCaptureRelay()){const l=c.eventQueue.snapshot(e.session_id);l.running.length===0&&l.queued.length===0?(h.info(this.name,`[audit-raw-capture] recreating idle Codex adapter before event=${e.event_id} session=${e.session_id}`),await this.pool.removeSlot(e.session_id)):h.warn(this.name,`[audit-raw-capture] Codex adapter lacks relay but is not idle event=${e.event_id} session=${e.session_id} running=${l.running.length} queued=${l.queued.length}`)}}const d=this.prepareAuditedInboundEvent(e,o,r);try{this.captureEventRuntimeConfig(d),await this.pool.deliverInboundEvent(d)}catch(c){if(this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.auditController.closeWithoutAdapter(e.event_id,"failed",c instanceof Error?c.message:String(c),{deliveryFailed:!0}),this.discardEventTrackingState(e.event_id),c instanceof Ht)this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:c.message,updated_at:Date.now()});else throw c}}async handleCodexSessionControlOpen(e,s){const t=s.session_id,o=e.args.trim(),i=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()}),n=(r,a)=>this.aibotHandle.sendEventResult({event_id:s.event_id,status:r,...a,updated_at:Date.now()});if(!o){i(),n("failed",{msg:"Usage: /grix open <working-directory>",code:p.cwdRequired});return}try{const r=await this.resolveCwdForBinding(o),a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{if(await this.resolveCwdForBinding(a.cwd)===r){i(),n("responded",{msg:`Session already bound to ${a.cwd}`});return}}catch{d=!0,h.info("bridge",`Stale codex binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){i(),n("failed",{msg:`Session already bound to ${a.cwd}. Rebinding is not allowed.`,code:p.rebindForbidden});return}}this.bindingStore.set(t,r),this.sessionBindings.set(t,r),this.deferredMgr.sendCodexDeferredReplayComposing(t,this.deferredCallbacks()),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),i(),n("responded",{msg:`Session bound to ${r}`})}catch(r){i(),n("failed",{code:p.invalidCwd,msg:r instanceof Error?r.message:String(r)})}}async handleSessionControlForPool(e,s){e.verb===_.open&&await this.bindSessionForPool(s.session_id,e.args.trim())}async replayDeferredEventsForSession(e){await this.deferredMgr.release(e,this.deferredCallbacks())}async handleSessionControlLocalActionForPool(e){if(String(e.action_type??"")!==C.sessionControl)return;const s=e.params??{};if(String(s.verb??"").trim().toLowerCase()!==_.open)return;const o=String(s.session_id??"").trim(),i=String(s.cwd??"").trim();!o||!i||await this.bindSessionForPool(o,i)}async handleCodexSessionControlLocalActionOpen(e){const s=e.params??{},t=String(s.session_id??"").trim(),o=String(s.cwd??"").trim(),i=String(s.agent_session_id??"").trim(),n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t||!o){n("failed",void 0,p.cwdRequired,"session cwd is required");return}try{const r=await this.resolveCwdForBinding(o);this.ensureImportedAgentSession(i,r);const a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{const c=await this.resolveCwdForBinding(a.cwd);if(c===r){this.setResolvedAgentSessionId(t,i),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,c)});return}}catch{d=!0,h.info("bridge",`Stale codex binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){n("failed",void 0,p.rebindForbidden,`Session already bound to ${a.cwd}`);return}}this.bindingStore.set(t,r),this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,r),this.deferredMgr.sendCodexDeferredReplayComposing(t,this.deferredCallbacks()),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,r)})}catch(r){n("failed",void 0,r?.sessionControlErrorCode??p.invalidCwd,r instanceof Error?r.message:String(r))}}async handleCursorSessionControlLocalActionOpen(e){const s=e.params??{},t=String(s.session_id??"").trim(),o=String(s.cwd??"").trim(),i=String(s.agent_session_id??"").trim(),n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t||!o){n("failed",void 0,p.cwdRequired,"session cwd is required");return}try{const r=await this.resolveCwdForBinding(o);this.ensureImportedAgentSession(i,r);const a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{const c=await this.resolveCwdForBinding(a.cwd);if(c===r){this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,c),await this.bindSessionForPool(t,c),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:c,meta:this.buildCursorToolbarMeta(t)}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,c)});return}}catch{d=!0,h.info("bridge",`Stale cursor binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){n("failed",void 0,p.rebindForbidden,`Session already bound to ${a.cwd}`);return}}this.bindingStore.set(t,r),this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,r),this.deferredMgr.sendCursorDeferredReplayComposing(t,this.deferredCallbacks()),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r,meta:this.buildCursorToolbarMeta(t)}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,r)})}catch(r){n("failed",void 0,r?.sessionControlErrorCode??p.invalidCwd,r instanceof Error?r.message:String(r))}}async handlePiSessionControlOpen(e,s){const t=s.session_id,o=e.args.trim(),i=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()}),n=(r,a)=>this.aibotHandle.sendEventResult({event_id:s.event_id,status:r,...a,updated_at:Date.now()});if(!o){i(),n("failed",{msg:"Usage: /grix open <working-directory>",code:p.cwdRequired});return}try{const r=await this.resolveCwdForBinding(o),a=this.bindingStore.get(t);if(a?.cwd){let d=!1;try{if(await this.resolveCwdForBinding(a.cwd)===r){i(),n("responded",{msg:`Session already bound to ${a.cwd}`}),this.aibotHandle.sendMsg({event_id:s.event_id,session_id:t,msg_type:1,content:`\u2705 Session already bound to \`${a.cwd}\``,quoted_message_id:s.msg_id});return}}catch{d=!0,h.info("bridge",`Stale pi binding for session ${t}: ${a.cwd} no longer exists, allowing rebind`)}if(!d){i(),n("failed",{msg:`Session already bound to ${a.cwd}. Rebinding is not allowed.`,code:p.rebindForbidden});return}}this.bindingStore.set(t,r),this.sessionBindings.set(t,r),await this.ensureSlotStarted(t).catch(d=>{h.warn("bridge",`pi ensureSlotStarted on bind failed (non-fatal): ${d instanceof Error?d.message:String(d)}`)}),await this.deferredMgr.release(t,this.deferredCallbacks()),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),i(),n("responded",{msg:`Session bound to ${r}`}),this.aibotHandle.sendMsg({event_id:s.event_id,session_id:t,msg_type:1,content:`\u2705 Working directory bound: \`${r}\``,quoted_message_id:s.msg_id})}catch(r){i(),n("failed",{code:p.invalidCwd,msg:r instanceof Error?r.message:String(r)})}}async handlePiSessionControlRestart(e){const s=e.session_id,t=()=>this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:s,received_at:Date.now()}),o=(r,a)=>this.aibotHandle.sendEventResult({event_id:e.event_id,status:r,...a,updated_at:Date.now()}),n=this.bindingStore.get(s)?.cwd??"";if(!n){t(),o("failed",{msg:"session binding was not found",code:p.bindingMissing});return}t(),await this.pool.removeSlot(s).catch(()=>{}),this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"ready",cwd:n}),o("responded",{msg:`Session worker restarted for ${n}`})}async handlePiSessionControlRestartLocalAction(e){const s=e.params??{},t=String(s.session_id??"").trim(),i=(t?this.bindingStore.get(t):void 0)?.cwd??"",n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t){n("failed",void 0,"session_id_required","session_id is required for restart");return}if(!i){n("failed",void 0,p.bindingMissing,"Session binding missing. Open a workspace first.");return}await this.pool.removeSlot(t).catch(()=>{}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:i}),n("ok",{outcome:"restarted",binding:{aibotSessionId:t,cwd:i,workerStatus:"ready"}})}async syncOpenCodeBinding(e,s){if(!e||!s)return;try{this.resolveSessionModelId(e),this.resolveSessionModeId(e)}catch(o){h.warn(this.name,`[opencode] resolve global toolbar default failed: ${o instanceof Error?o.message:String(o)}`)}let t=this.pool.getSlot(e);!t&&(this.config.adapterType??"acp")==="opencode"&&(await this.ensureSlotStarted(e),t=this.pool.getSlot(e)),t?.startPromise&&await t.startPromise,t?.adapter instanceof G&&await t.adapter.bindSession(e,s)}async bindSessionForPool(e,s){const t=String(s??"").trim();if(!e||!t)return;const o=this.pool.getOrCreateSlot(e);if(!o||(o.startPromise&&await o.startPromise,!o.adapter))return;const i=o.adapter instanceof y?o.adapter:null;if(!i?.hasSessionBinding)return;const n=await this.resolveCwdForBinding(t);i.announceDeferredComposing(e),await i.bindSession(e,n),this.sessionBindings.set(e,n),this.sessionScanCache.invalidate(),i.replayDeferredEvents(e)}deferredCallbacks(){return{captureEventRuntimeConfig:e=>this.captureEventRuntimeConfig(e),deliverInboundEvent:e=>this.pool.deliverInboundEvent(e),sendEventResult:(e,s,t)=>this.sendEventResultWithCleanup(e,s,t),sendSessionComposing:(e,s,t)=>{const o={};s&&(o.ttl_ms=t?.ttlMs??3e4,t?.activity&&(o.activity=t.activity)),this.aibotHandle.sendSessionActivitySet({session_id:e,kind:"composing",active:s,...o})}}}async handleOpenHumanSessionControlOpen(e,s){const t=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:s.session_id,received_at:Date.now()});try{const o=await this.resolveCwdForBinding(e.args.trim());await this.handleSessionControlForPool(e,s),await this.syncOpenCodeBinding(s.session_id,o),ue(e,s,this.sessionControlCtx(s.session_id),this.sessionControlSenders()),await this.deferredMgr.release(s.session_id,this.deferredCallbacks())}catch(o){t(),this.aibotHandle.sendEventResult({event_id:s.event_id,status:"failed",code:o?.cwdErrorCode,msg:o instanceof Error?o.message:String(o),updated_at:Date.now()})}}async handleCodeWhaleSessionControlOpen(e,s){const t=s.session_id,o=e.args.trim(),i=()=>this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()}),n=(r,a)=>this.aibotHandle.sendEventResult({event_id:s.event_id,status:r,...a,updated_at:Date.now()});if(!o){i(),n("failed",{msg:"Usage: /grix open <working-directory>",code:p.cwdRequired});return}try{const r=await this.resolveCwdForBinding(o),a=this.bindingStore.get(t);if(a?.cwd){if(await this.resolveCwdForBinding(a.cwd)!==r){i(),n("failed",{msg:`Session already bound to ${a.cwd}. Rebinding is not allowed.`,code:p.rebindForbidden});return}i(),n("responded",{msg:`Session already bound to ${a.cwd}`});return}this.bindingStore.set(t,r),this.sessionBindings.set(t,r),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),i(),n("responded",{msg:`Session bound to ${r}`})}catch(r){i(),n("failed",{code:p.invalidCwd,msg:r instanceof Error?r.message:String(r)})}}async handleCodeWhaleSessionControlLocalActionOpen(e){const s=e.params??{},t=String(s.session_id??"").trim(),o=String(s.cwd??"").trim(),i=String(s.agent_session_id??"").trim(),n=(r,a,d,c)=>{this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:r,...a!==void 0?{result:a}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}})};if(!t||!o){n("failed",void 0,p.cwdRequired,"session cwd is required");return}try{const r=await this.resolveCwdForBinding(o);this.ensureImportedAgentSession(i,r);const a=this.bindingStore.get(t);if(a?.cwd){const d=await this.resolveCwdForBinding(a.cwd);if(d!==r){n("failed",void 0,p.rebindForbidden,`Session already bound to ${a.cwd}`);return}this.setResolvedAgentSessionId(t,i),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,d)});return}this.bindingStore.set(t,r),this.setResolvedAgentSessionId(t,i),this.sessionBindings.set(t,r),await this.bindSessionForPool(t,r),await this.deferredMgr.release(t,this.deferredCallbacks(),{announceComposing:!1}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"ready",cwd:r}),n("ok",{outcome:"opened",binding:this.buildOpenedBindingResult(t,r)})}catch(r){n("failed",void 0,r?.sessionControlErrorCode??p.invalidCwd,r instanceof Error?r.message:String(r))}}normalizeClaudeModeId(e){return String(e??"").trim().toLowerCase()===R.approval?R.approval:R.fullAuto}handleExecCommandOptions(e,s,t){const o=Array.isArray(t?.options)?t.options:[];if(o.length===0)return;const n=this.bindingStore.get(e)?.cwd??"",r={};if(s==="model"){r.available_models=o.map(d=>({id:d.id,displayName:d.label}));const a=o.find(d=>d.current);a&&(r.model_id=a.id)}else if(s==="mode"){r.available_modes=o.map(d=>({id:d.id,displayName:d.label}));const a=o.find(d=>d.current);a&&(r.mode_id=a.id)}else r[`${s}_options`]=o;this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:n,meta:r})}resolveSessionModelId(e){const s=this.bindingStore.getModelId(e);if(s)return s;const t=String(this.globalConfigStore?.get(this.name)?.modelId??"").trim();if(t)return this.bindingStore.setModelId(e,t),t}resolveSessionModeId(e){const s=this.bindingStore.getModeId(e);if(s)return s;const t=String(this.globalConfigStore?.get(this.name)?.modeId??"").trim();if(t)return this.bindingStore.setModeId(e,t),t}resolveClaudeSessionEffort(e){const s=this.bindingStore.getEffort(e);if(s)return s;if(this.bindingStore.get(e)?.claudeSessionId)return;const o=V(this.globalConfigStore?.get(this.name)?.effort);if(o)return this.bindingStore.setEffort(e,o),o}resolveCodexSessionModelId(e){const s=this.bindingStore.getCodexModelId(e);if(s)return s;if(this.bindingStore.getCodexThreadId(e))return;const t=String(this.globalConfigStore?.get(this.name)?.codexModelId??"").trim();if(t)return this.bindingStore.setCodexModelId(e,t),t}resolveCodexNewSessionGlobalDefault(e,s,t){const o=String(s??"").trim();if(o&&!this.bindingStore.getCodexThreadId(e))return t(o),o}buildCursorToolbarMeta(e){const s=this.pool.getSlot(e);if(s?.adapter instanceof q)return s.adapter.getToolbarMeta(e);const t=this.bindingStore.getModelId(e)??"auto",o=this.bindingStore.getCursorModeId(e)??"full_auto";return{model_id:t,mode_id:o,currentModelId:t,currentModeId:o,available_models:[],available_modes:Ee.map(i=>({...i}))}}buildAgyToolbarMeta(e){if(!this.bindingStore.get(e))return;const t=Pe(this.config.agent.command),o=t.length>0?t[0].id:"";let i=this.resolveSessionModelId(e)||o;t.length>0&&!t.some(r=>r.id===i)&&(i=o);const n=Te();return{model_id:i,currentModelId:i,available_models:t.map(r=>({id:r.id,displayName:r.displayName})),...n.plan!==void 0&&{plan:n.plan},...n.quota_exhausted!==void 0&&{quota_exhausted:n.quota_exhausted},...n.quota_reset_at!==void 0&&{quota_reset_at:n.quota_reset_at},...n.available_credits!==void 0&&{available_credits:n.available_credits}}}async handleAgySetModel(e,s){const t=e.params??{},o=String(t.model_id??t.modelId??"").trim();if(!s){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for set_model"});return}if(!o){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"set_model_invalid",error_msg:"model_id is required"});return}const i=this.bindingStore.get(s);if(!i?.cwd){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:p.bindingMissing,error_msg:"session binding was not found"});return}i.modelId!==o&&(this.bindingStore.setModelId(s,o),this.globalConfigStore?.set(this.name,{modelId:o})),await xe().catch(()=>{}),this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"ready",cwd:i.cwd,meta:this.buildAgyToolbarMeta(s)}),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{outcome:"model_set",model_id:o,binding:{cwd:i.cwd,model_id:o}}})}buildClaudeToolbarMeta(e){const s=this.bindingStore.get(e);if(!s)return;const t=j(),o=t.length>0?t[0].id:"";let i=this.resolveSessionModelId(e)||o;t.length>0&&!t.some(g=>g.id===i)&&(i=o);const n=this.normalizeClaudeModeId(s.modeId);let r;try{const g=this.providerResolver?this.providerResolver():this.config.agent.provider;r=V(g?.effort)}catch{}const a=this.resolveClaudeSessionEffort(e)??r??"auto",d={model_id:i,mode_id:n,currentModelId:i,currentModeId:n,available_efforts:[...D],effort:a,reasoning_effort:a,available_models:t.map(g=>({id:g.id,displayName:g.displayName}))},c=this.pool.getSlot(e),l=c?.adapter instanceof M?c.adapter.getSessionState():null;(l?.rateLimits?.fiveHour||l?.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=l);const u=l??this.getFreshClaudeRateLimitState();if(u){const g=u.rateLimits;g&&(g.fiveHour||g.sevenDay)&&(d.rate_limits={...g.fiveHour?{fiveHour:g.fiveHour}:{},...g.sevenDay?{sevenDay:g.sevenDay}:{},sampledAt:u.sampledAt||Date.now()})}if(l){const g=l.contextWindow;g.usedPercentage!=null&&(d.context_window={usedPercentage:g.usedPercentage,remainingPercentage:g.remainingPercentage})}if(!d.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const g=this.providerQuotaToRateLimits(this.cachedProviderQuota);g&&(d.rate_limits=g),h.info(this.name,`[toolbar-meta] provider quota fallback: hasCached=${!!this.cachedProviderQuota} fromProvider=${JSON.stringify(g)}`)}return d.rate_limits&&h.info(this.name,`[toolbar-meta] rate_limits included: ${JSON.stringify(d.rate_limits)}`),d}providerQuotaToCodexRateLimits(e){return me(e,this.cachedProviderQuotaSampledAtMs??Date.now())}providerQuotaToRateLimits(e){return fe(e,this.cachedProviderQuotaSampledAtMs??Date.now())}async resolveCwdForBinding(e){const s=String(e??"").trim();if(process.platform!=="win32"&&(/^[a-zA-Z]:[\\/]/.test(s)||/^\\\\/.test(s))){const i=new Error(`Specified path is not valid on this host: ${s}`);throw i.cwdErrorCode=p.invalidCwd,i}const t=T.resolve(s);let o;try{o=await W(t)}catch(i){const n=String(i?.code??"");if(n==="ENOENT"){const r=new Error(`Specified path does not exist: ${t}`);throw r.cwdErrorCode=p.invalidCwd,r}if(n==="EACCES"||n==="EPERM"){const r=new Error("Specified path is not accessible.");throw r.cwdErrorCode=p.invalidCwd,r}throw i}if(!o.isDirectory()){const i=new Error("Specified path is not a directory.");throw i.cwdErrorCode=p.invalidCwd,i}try{return await be(t)}catch{return t}}getClaudeWorkerStatus(e){const s=this.pool.getSlot(e);return s?s.state==="starting"?"starting":s.state==="stopped"?"stopped":s.adapter.getStatus().busy?"busy":"ready":"stopped"}refreshClaudeWorkerStatusCard(e,s){const t=this.getClaudeWorkerStatus(e);return this.claudeWorkerStatus.set(e,t),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:t,cwd:s,meta:this.buildClaudeToolbarMeta(e)}),t}async handleSkillUploadLocalAction(e){const s=e.params??{},t=String(s.name??"").trim(),o=String(s.session_id??"").trim();if(!t){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"MISSING_SKILL_NAME",error_msg:"name is required"});return}const i=I(this.config.adapterType,this.config.aibot.clientType),n=this.bindingStore.get(o)?.cwd||this.sessionBindings.get(o)||void 0,r=i==="kiro"?n:n||process.cwd();try{await Ue(t,{mode:i,projectDir:r},{apiKey:this.config.aibot.apiKey,wsUrl:this.config.aibot.url}),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{name:t}})}catch(a){h.warn(this.name,`skill_upload failed name=${t}: ${a instanceof Error?a.message:String(a)}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"SKILL_UPLOAD_FAILED",error_msg:a instanceof Error?a.message:String(a)})}}async handleSkillEnableLocalAction(e){const s=e.params??{},t=String(s.name??"").trim(),o=String(s.session_id??"").trim(),i=String(s.scope??"").trim(),n=String(s.actor_id??"").trim(),r=s.force==="replace_link"||s.force==="replace_with_link"?s.force:void 0,a=I(this.config.adapterType,this.config.aibot.clientType),d=this.bindingStore.get(o)?.cwd||this.sessionBindings.get(o)||void 0;try{const c=await We({skillsDir:P.skills,mode:a,home:N(),cwd:d},{name:t,scope:i,actorId:n,force:r});h.info(this.name,`skill_enable name=${t} scope=${i} actor=${n||"-"} changed=${c.changed}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{name:c.name,scope:c.scope,path:c.path,changed:c.changed,enable_state:c.status,uninstallable:!0}})}catch(c){const l=c instanceof ae?c.code:"SKILL_ENABLE_FAILED";h.warn(this.name,`skill_enable failed name=${t} scope=${i}: ${c instanceof Error?c.message:String(c)}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:l,error_msg:c instanceof Error?c.message:String(c),result:{conflict_kind:l==="CONFLICT"||l==="NEEDS_FORCE"||l==="BLOCKED"?l.toLowerCase():void 0}})}this.forceRefreshSkills()}handleSkillRefreshLocalAction(e){const s=e.params??{},t=String(s.session_id??"").trim();if(this.forceRefreshSkills(t||void 0,{force:!0})){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{session_id:t||void 0}});return}h.warn(this.name,`skill_refresh produced no report session=${t||"-"}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"SKILL_REFRESH_FAILED",error_msg:"skill rescan produced no report (scan error or empty skill set)"})}async handleSkillDisableLocalAction(e){const s=e.params??{},t=String(s.name??"").trim(),o=String(s.session_id??"").trim(),i=String(s.scope??"").trim(),n=String(s.actor_id??"").trim(),r=I(this.config.adapterType,this.config.aibot.clientType),a=this.bindingStore.get(o)?.cwd||this.sessionBindings.get(o)||void 0;try{const d=await Ne({skillsDir:P.skills,mode:r,home:N(),cwd:a},{name:t,scope:i,actorId:n});h.info(this.name,`skill_disable name=${t} scope=${i} actor=${n||"-"} removed=${d.removed}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{name:d.name,scope:d.scope,path:d.path,removed:d.removed,enable_state:"none",uninstallable:!1}})}catch(d){const c=d instanceof ae?d.code:"SKILL_DISABLE_FAILED";h.warn(this.name,`skill_disable failed name=${t} scope=${i}: ${d instanceof Error?d.message:String(d)}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:c,error_msg:d instanceof Error?d.message:String(d),result:{conflict_kind:c==="CONFLICT"||c==="BLOCKED"?c.toLowerCase():void 0}})}this.forceRefreshSkills()}computeSkillReport(e){const s=I(this.config.adapterType,this.config.aibot.clientType),t=s==="kiro"?e:e||process.cwd();let o;try{o=Oe({mode:s,projectDir:t})}catch{return null}if(o.length===0)return null;const i=JSON.stringify(o.map(n=>`${n.source}:${n.name}`));return{skills:re(o,P.skills),hash:i}}reportSessionSkills(e){const s=this.bindingStore.get(e)?.cwd||this.sessionBindings.get(e)||void 0,t=this.computeSkillReport(s);if(!t)return;const o=this.buildLibrarySkillsReport(s),i=ee(t.skills,o);if(!(t.hash===this.lastReportedSkillsHash&&i===this.lastReportedSkillsWireHash)){this.lastReportedSkillsHash=t.hash,this.lastReportedSkillsWireHash=i;try{this.aibotHandle.sendSkillsUpdate({skills:t.skills,library_skills:o})}catch{}}}skillsSyncGroupKey(){const e=String(this.config.aibot.clientType??"").trim().toLowerCase()||"unknown",s=String(this.config.aibot.sharedOwnerId??"").trim();return s?`shared:${s}:${e}`:`primary:${e}`}forceRefreshSkills(e,s){const t=e?.trim(),o=t||this.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0}),i=t?this.bindingStore.get(t)?.cwd||this.sessionBindings.get(t)||void 0:o?this.bindingStore.get(o)?.cwd:void 0,n=this.computeSkillReport(i);if(!n)return!1;const r=this.buildLibrarySkillsReport(i),a=ee(n.skills,r);if(!s?.force&&a===this.lastReportedSkillsWireHash)return this.lastReportedSkillsHash=n.hash,!0;this.lastReportedSkillsHash=n.hash,this.lastReportedSkillsWireHash=a;try{return this.aibotHandle.sendSkillsUpdate({skills:n.skills,library_skills:r,...s?.ownerLibrarySync?{owner_library_sync:!0}:{}}),!0}catch{return!1}}adoptSkillsWireHashFromDisk(){const e=this.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0}),s=e?this.bindingStore.get(e)?.cwd:void 0,t=this.computeSkillReport(s);if(!t)return;const o=this.buildLibrarySkillsReport(s);this.lastReportedSkillsHash=t.hash,this.lastReportedSkillsWireHash=ee(t.skills,o)}buildLibrarySkillsReport(e){const s=I(this.config.adapterType,this.config.aibot.clientType);return Fe({skillsDir:P.skills,mode:s,home:N(),cwd:e})}async ensureSlotStarted(e,s=6e4){const t=this.pool.getOrCreateSlot(e);if(!t)throw new Error("Failed to allocate session slot");t.startPromise&&(h.info(this.name,`ensureSlotStarted: awaiting startPromise for session=${e}`),await Promise.race([t.startPromise,new Promise((o,i)=>setTimeout(()=>i(new Error(`ensureSlotStarted timeout (${s}ms) session=${e}`)),s))]),h.info(this.name,`ensureSlotStarted: startPromise resolved for session=${e}`))}resolveOrphanTitle(e){if(e){if(this.reasonixTitleScan){const s=lt(e);if(!s)return;const t=this.reasonixTitleScan.get().filter(o=>o.stamp===s);return t.length===1?t[0].title:void 0}if((this.config.adapterType??"acp")==="cursor")return this.sessionScanCache.get().find(t=>t.sessionId===e)?.title}}resolveAgentSessionId(e){switch(this.config.adapterType??"acp"){case"claude":return e.claudeSessionId;case"codex":return e.codexThreadId;case"pi":return e.piSessionPath;case"codewhale":return e.codewhaleThreadId;case"agy":return e.agyConversationId;default:return e.acpSessionId}}providerKeyForAdapter(){const e=this.config.adapterType??"acp";switch(e){case"claude":case"codex":case"pi":case"codewhale":return e;default:return"acp"}}setResolvedAgentSessionId(e,s){const t=String(e??"").trim(),o=String(s??"").trim();if(!t||!o)return;switch(this.config.adapterType??"acp"){case"claude":this.bindingStore.setClaudeSessionId(t,o);break;case"codex":this.bindingStore.setCodexThreadId(t,o);break;case"pi":this.bindingStore.setPiSessionPath(t,o);break;case"codewhale":this.bindingStore.setCodeWhaleThreadId(t,o);break;case"agy":this.bindingStore.setAgyConversationId(t,o);break;default:this.bindingStore.setAcpSessionId(t,o);break}this.sessionScanCache.invalidate()}normalizePathForCompare(e){const s=String(e??"").trim();if(!s)return"";const t=T.resolve(s);return process.platform==="win32"?t.toLowerCase():t}ensureImportedAgentSession(e,s){const t=String(e??"").trim();if(!t)return;const o=this.normalizePathForCompare(s);let i="";const n=this.config.adapterType??"acp";if(n==="codex"?i=this.sessionScanCache.get().find(d=>d.threadId===t)?.cwd??"":n==="claude"?i=this.sessionScanCache.get().find(d=>d.sessionId===t)?.cwd??"":n==="cursor"?i=this.sessionScanCache.get().find(d=>d.sessionId===t)?.cwd??"":n==="acp"&&(i=this.sessionScanCache.get().find(d=>d.sessionId===t)?.cwd??""),!i){for(const[,a]of this.bindingStore.entries())if(this.resolveAgentSessionId(a)===t){i=a.cwd??"";break}}if(!i){const a=new Error(`agent session not found: ${t}`);throw a.sessionControlErrorCode=p.invalidAgentSession,a}const r=this.normalizePathForCompare(i);if(r&&o&&r!==o){const a=new Error(`agent session cwd mismatch: expected ${s}, got ${i}`);throw a.sessionControlErrorCode=p.invalidAgentSession,a}}buildOpenedBindingResult(e,s,t="ready"){const o=this.bindingStore.get(e),i=o?String(this.resolveAgentSessionId(o)??"").trim():"",n={aibotSessionId:e,providerKey:this.providerKeyForAdapter(),cwd:s,workerStatus:t};return i&&(n.bindingId=i,n.agentSessionId=i),n}hasDiskScanner(){const e=this.config.adapterType??"acp";return e==="codex"||e==="claude"||e==="acp"}async handleListSessionsTextCommand(e){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const s=this.config.adapterType??"acp",t=new Map;for(const a of this.pool.getAllSlots())t.set(a.sessionId,a);const o=Array.from(this.bindingStore.entries()),i=new Map;for(const[a,d]of o){const c=this.resolveAgentSessionId(d);if(c){const l=t.get(a),u=l?l.adapter.getStatus().busy?"busy":"ready":"inactive";i.set(c,{aibotSessionId:a,workerStatus:u})}}const n=[],r=new Set;if(s==="codex"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.threadId);const c=i.get(d.threadId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.threadId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??(d.archived?"archived":"inactive")}`),n.push(` Created: ${new Date(d.createdAt).toISOString()}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="claude"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="acp"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="pi"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionPath);const c=i.get(d.sessionPath);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionPath}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}else if(s==="codewhale"||s==="opencode"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId);d.title&&n.push(` Title: ${d.title}`),n.push(` Agent: ${d.sessionId}`),c&&n.push(` AIBot: ${c.aibotSessionId}`),n.push(` CWD: ${d.cwd||"-"}`),n.push(` State: ${c?.workerStatus??"inactive"}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}}for(const[a,d]of o){const c=this.resolveAgentSessionId(d);if(c&&r.has(c))continue;const l=t.get(a),u=l?l.adapter.getStatus().busy?"busy":"ready":"closed",g=this.resolveOrphanTitle(c)??(c?c.slice(0,8)+"\u2026":a.slice(0,8)+"\u2026");n.push(` Title: ${g}`),n.push(` AIBot: ${a}`),c&&n.push(` Agent: ${c}`),n.push(` CWD: ${d.cwd??"-"}`),n.push(` State: ${u}`),n.push(` Updated: ${new Date(d.updatedAt).toISOString()}`),n.push("---")}if(n.length===0){this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",msg:"No sessions found.",updated_at:Date.now()});return}this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",msg:`Sessions (${n.filter(a=>a==="---").length}):
10
10
  ${n.join(`
11
11
  `)}`,updated_at:Date.now()})}async handleListSessionsLocalAction(e){const s=this.config.adapterType??"acp",t=new Map;for(const a of this.pool.getAllSlots())t.set(a.sessionId,a);const o=Array.from(this.bindingStore.entries()),i=new Map;for(const[a,d]of o){const c=this.resolveAgentSessionId(d);if(c){const l=t.get(a),u=l?l.adapter.getStatus().busy?"busy":"ready":"inactive";i.set(c,{aibotSessionId:a,workerStatus:u,bindingUpdatedAt:d.updatedAt??0})}}const n=[],r=new Set;if(s==="codex"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.threadId);const c=i.get(d.threadId),l={agentSessionId:d.threadId,cwd:d.cwd||null,workerStatus:c?.workerStatus??(d.archived?"archived":"inactive"),createdAt:d.createdAt,updatedAt:d.updatedAt,archived:d.archived};c&&(l.aibotSessionId=c.aibotSessionId),d.title&&(l.title=d.title),n.push(l)}}else if(s==="claude"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId),l={agentSessionId:d.sessionId,cwd:d.cwd||null,workerStatus:c?.workerStatus??"inactive",updatedAt:d.updatedAt};c&&(l.aibotSessionId=c.aibotSessionId),d.title&&(l.title=d.title),n.push(l)}}else if(s==="acp"){const a=this.sessionScanCache.get();for(const d of a){r.add(d.sessionId);const c=i.get(d.sessionId),l=c&&c.bindingUpdatedAt>0?c.bindingUpdatedAt:d.updatedAt,u={agentSessionId:d.sessionId,cwd:d.cwd||null,agentType:d.agentType,workerStatus:c?.workerStatus??"inactive",updatedAt:l};c&&(u.aibotSessionId=c.aibotSessionId),d.title&&(u.title=d.title),d.createdAt&&(u.createdAt=d.createdAt),n.push(u)}}else if(s==="pi"||s==="codewhale"||s==="opencode"){const a=this.sessionScanCache.get();for(const d of a){const c="sessionPath"in d?d.sessionPath:d.sessionId;r.add(c);const l=i.get(c),u={agentSessionId:c,cwd:d.cwd||null,workerStatus:l?.workerStatus??("archived"in d&&d.archived?"archived":"inactive"),updatedAt:l&&l.bindingUpdatedAt>0?l.bindingUpdatedAt:d.updatedAt};l&&(u.aibotSessionId=l.aibotSessionId),d.title&&(u.title=d.title),d.createdAt&&(u.createdAt=d.createdAt),"archived"in d&&(u.archived=d.archived),n.push(u)}}for(const[a,d]of o){const c=this.resolveAgentSessionId(d);if(c&&r.has(c))continue;const l=t.get(a),u=l?l.adapter.getStatus().busy?"busy":"ready":"closed",g={aibotSessionId:a,cwd:d.cwd??null,workerStatus:u,updatedAt:d.updatedAt,title:this.resolveOrphanTitle(c)??(c?`${c.slice(0,8)}\u2026`:`${a.slice(0,8)}\u2026`)};c&&(g.agentSessionId=c),n.push(g)}n.sort((a,d)=>d.updatedAt-a.updatedAt),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{outcome:"sessions_listed",sessions:n,total:n.length}})}async handleSyncHistoryLocalAction(e){const s=e.params??{},t=String(s.provider_key??this.config.adapterType??"acp").trim().toLowerCase(),o=String(s.agent_session_id??"").trim(),i=String(s.cwd??"").trim(),n=typeof s.sync_run_id=="string"&&s.sync_run_id?s.sync_run_id:void 0,r=(d,c)=>{h.warn(this.name,`sync_history failed action_id=${e.action_id} provider=${t} code=${d} msg=${c}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:d,error_msg:c})};if(!o){r(O.agentSessionRequired,"agent_session_id is required for sync_history");return}if(!i){r(O.cwdRequired,"cwd is required for sync_history");return}const a=qe(t);if(!a){r(O.providerUnsupported,`provider ${t} does not support sync_history`);return}try{const d=await a({session_id:String(s.session_id??""),provider_key:t,agent_session_id:o,cwd:i,cursor:typeof s.cursor=="string"&&s.cursor?s.cursor:void 0,limit:typeof s.limit=="number"?s.limit:void 0,sync_run_id:n});h.debug(this.name,`sync_history ok action_id=${e.action_id} provider=${t} agent_session_id=${o} messages=${d.messages.length} has_more=${d.has_more}`),this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{outcome:"history_synced",messages:d.messages,has_more:d.has_more,next_cursor:d.next_cursor,...n?{sync_run_id:n}:{}}})}catch(d){d instanceof Be?r(d.code,d.message):r(O.runtimeError,String(d))}}async handleSessionControlCommand(e,s){const t=s.session_id,o=(i,n,r)=>{this.aibotHandle.sendEventResult({event_id:s.event_id,status:i,...n?{msg:n}:{},...r?{code:r}:{},updated_at:Date.now()})};this.aibotHandle.sendEventAck({event_id:s.event_id,session_id:t,received_at:Date.now()});try{switch(e.verb){case _.open:{await z().catch(()=>{});const i=e.args.trim();if(!i){o("failed","Usage: /grix open <working-directory>",p.cwdRequired);return}let n="";try{n=await this.resolveCwdForBinding(i)}catch(a){o("failed",a instanceof Error?a.message:String(a),p.invalidCwd);return}const r=this.bindingStore.get(t);if(r?.cwd){const a=await this.resolveCwdForBinding(r.cwd);if(a!==n){o("failed","session binding cannot be changed to another working directory",p.rebindForbidden);return}this.bindingStore.ensureModeId(t,R.fullAuto),this.sessionBindings.set(t,a),await this.ensureSlotStarted(t),await this.deferredMgr.release(t,this.deferredCallbacks()),this.refreshClaudeWorkerStatusCard(t,a),o("responded",`Working directory already bound: ${a}`);return}this.bindingStore.set(t,n,{modeId:R.fullAuto}),this.sessionBindings.set(t,n),await this.ensureSlotStarted(t),await this.deferredMgr.release(t,this.deferredCallbacks()),this.refreshClaudeWorkerStatusCard(t,n),o("responded",`Session bound to ${n}`);return}case _.where:{const i=this.bindingStore.get(t);if(!i?.cwd){o("failed","session binding was not found",p.bindingMissing);return}o("responded",`Working directory: ${i.cwd}`);return}case _.status:{const i=this.bindingStore.get(t);if(!i?.cwd){o("failed","session binding was not found",p.bindingMissing);return}const n=this.normalizeClaudeModeId(i.modeId),r=this.getClaudeWorkerStatus(t);o("responded",`Status: worker=${r} mode=${n} cwd=${i.cwd}`);return}case _.stop:{const i=this.bindingStore.get(t);if(!i?.cwd){o("failed","session binding was not found",p.bindingMissing);return}await this.pool.removeSlot(t),this.claudeWorkerStatus.set(t,"stopped"),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"stopped",cwd:i.cwd}),this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:"stopped",cwd:i.cwd,meta:this.buildClaudeToolbarMeta(t)}),o("responded",`Session worker stopped for ${i.cwd}`);return}case _.restart:{const i=this.bindingStore.get(t);if(!i?.cwd){o("failed","session binding was not found",p.bindingMissing);return}await this.pool.removeSlot(t),await this.ensureSlotStarted(t),this.refreshClaudeWorkerStatusCard(t,i.cwd),o("responded",`Session worker restarted for ${i.cwd}`);return}case _.setMode:{const i=e.args.trim();if(!i){o("failed","Usage: /grix set_mode <mode-id>",x.modeInvalid);return}const n=this.normalizeClaudeModeId(i);if(n!==i.toLowerCase()){o("failed","set mode_id is invalid",x.modeInvalid);return}const r=this.bindingStore.get(t);if(!r?.cwd){o("failed","session binding was not found",p.bindingMissing);return}if(this.normalizeClaudeModeId(r.modeId)===n){o("responded",`Mode unchanged: ${n}`);return}if(this.getClaudeWorkerStatus(t)==="busy"){o("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F",p.workerBusy);return}this.bindingStore.setModeId(t,n),await this.pool.removeSlot(t),await this.ensureSlotStarted(t),this.refreshClaudeWorkerStatusCard(t,r.cwd),o("responded",`Mode set to ${n}`);return}case _.setModel:{const i=e.args.trim();if(!i){o("failed","Usage: /grix set_model <model-id>");return}const n=this.bindingStore.get(t);if(!n?.cwd){o("failed","session binding was not found",p.bindingMissing);return}if((n.modelId??"")===i){o("responded",`Model unchanged: ${i}`);return}if(this.getClaudeWorkerStatus(t)==="busy"){o("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B",p.workerBusy);return}this.bindingStore.setModelId(t,i),this.globalConfigStore?.set(this.name,{modelId:i}),await this.pool.removeSlot(t),await this.ensureSlotStarted(t),this.refreshClaudeWorkerStatusCard(t,n.cwd),this.refreshQuotaAfterModelSwitch(t,i),o("responded",`Model set to ${i}`);return}case _.listOptions:{const i=j(),n=this.bindingStore.get(t),r=i.map(c=>c.id).join(", "),a=`${R.fullAuto}, ${R.approval}`,d=this.resolveClaudeSessionEffort(t)??"auto";o("responded",`Modes (current: ${this.normalizeClaudeModeId(n?.modeId)}): ${a}
12
12
  Models (current: ${n?.modelId??"default"}): ${r}
@@ -1,3 +1,3 @@
1
- import{isRequestTimeoutError as E}from"../core/aibot/errors.js";import{log as u}from"../core/log/index.js";import{splitTextForAibotProtocol as g,AIBOT_PROTOCOL_MAX_RUNES as C}from"../core/protocol/protocol-text.js";import{isThinkingEventDropped as k,isToolEventDropped as y,normalizeRuntimeConfigSnapshot as T}from"./runtime-config.js";const v={claude:!1,acp:!1,codex:!0,codewhale:!0,pi:!0,openhuman:!1,cursor:!1,opencode:!0,agy:!0};class p{handle;connectorRuntimeConfig;eventRuntimeConfigs=new Map;eventQuotedMessageIds=new Map;defaultQuoteTrigger=!1;thinkingSeqMap=new Map;toolCardSeq=0;bufferedEventTexts=new Map;singleMessageDeliveries=new Map;chunkSeqMap=new Map;rejectedEvents=new Set;terminalEvents=new Set;static MAX_TERMINAL_EVENTS=1e3;stoppedEvents=new Set;streamCoalesce=new Map;streamCoalesceMs=S();static STREAM_COALESCE_MAX_RUNES=2048;recentToolCards=new Map;static TOOL_CARD_DEDUP_MS=100;constructor(e){this.connectorRuntimeConfig={...e}}bind(e){this.handle=e}markEventRejected(e){if(!e)return;this.rejectedEvents.add(e);const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])if(s.startsWith(t)){const n=this.streamCoalesce.get(s);n.timer&&clearTimeout(n.timer),this.streamCoalesce.delete(s)}u.info("send-ctrl",`event marked as stream-rejected, future chunks will be dropped event=${e}`)}markEventTerminal(e){if(!(!e||this.terminalEvents.has(e))&&(this.terminalEvents.add(e),this.terminalEvents.size>p.MAX_TERMINAL_EVENTS)){const t=this.terminalEvents.values().next().value;t!==void 0&&this.terminalEvents.delete(t)}}isEventClosed(e){return!!e&&(this.rejectedEvents.has(e)||this.terminalEvents.has(e))}markEventStopped(e){e&&(this.stoppedEvents.add(e),u.info("send-ctrl",`[stop-trace] event marked stopped; subsequent outbound will be flagged event=${e}`))}flagOutboundAfterStop(e,t,s,n,o,a){!e||!this.stoppedEvents.has(e)||u.warn("send-ctrl",`[stop-trace] OUTBOUND AFTER STOP ${s} event=${e} session=${t} seq=${n} is_finish=${o} len=${a}`)}getGlobalRuntimeConfig(){return this.connectorRuntimeConfig}setStreamCoalesceMs(e){this.streamCoalesceMs=Number.isFinite(e)&&e>0?Math.floor(e):0}captureEventRuntimeConfig(e){this.terminalEvents.delete(e.event_id);const t=T(e.connector_runtime_config);if(t||!this.eventRuntimeConfigs.has(e.event_id)){const s=t??this.connectorRuntimeConfig;this.eventRuntimeConfigs.set(e.event_id,{responseDelivery:s.responseDelivery,toolEvents:s.toolEvents,thinkingEvents:s.thinkingEvents})}e.msg_id&&!this.eventQuotedMessageIds.has(e.event_id)&&this.eventQuotedMessageIds.set(e.event_id,e.msg_id)}discardEventState(e){e&&(this.markEventTerminal(e),this.clearEventTrackingState(e))}clearEventTrackingState(e){this.eventRuntimeConfigs.delete(e),this.eventQuotedMessageIds.delete(e),this.rejectedEvents.delete(e),this.singleMessageDeliveries.delete(e),this.bufferedEventTexts.delete(e);for(const t of[...this.streamCoalesce.keys()])if(t.startsWith(`${e}:`)){const s=this.streamCoalesce.get(t);s.timer&&clearTimeout(s.timer),this.streamCoalesce.delete(t)}this.stoppedEvents.delete(e)&&u.info("send-ctrl",`[stop-trace] event tracking cleared stop flag event=${e}`);for(const t of this.chunkSeqMap.keys())t.startsWith(`${e}:`)&&this.chunkSeqMap.delete(t);for(const t of this.recentToolCards.keys())t.startsWith(`${e}:`)&&this.recentToolCards.delete(t)}setDefaultQuoteTrigger(e){this.defaultQuoteTrigger=e}getDefaultQuotedMessageId(e){if(!(!this.defaultQuoteTrigger||!e))return this.eventQuotedMessageIds.get(e)}resolveEventRuntimeConfig(e){if(e){const t=this.eventRuntimeConfigs.get(e);if(t)return t}return this.connectorRuntimeConfig}shouldDropToolDisplayEvent(e){return y(this.resolveEventRuntimeConfig(e))}shouldDropThinkingDisplayEvent(e){return k(this.resolveEventRuntimeConfig(e))}shouldDropCodexDisplayEvent(e,t){return this.shouldDropToolDisplayEvent(e)?t==="item/completed":!1}shouldDropAcpRawDisplayEvent(e,t){return!!(this.shouldDropToolDisplayEvent(e)&&(t==="tool_use"||t==="tool_result")||this.shouldDropThinkingDisplayEvent(e)&&t==="thinking")}sendReply(e,t,s,n,o,a){if(!a?.skipToolFilter&&this.shouldDropToolDisplayEvent(e)&&D(s,o)||this.isEventClosed(e))return;if(this.flagOutboundAfterStop(e,t,"reply",0,!1,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="stream"&&!o){const i=g(s),l=e?`reply_stream_${e}`:`reply_stream_${Date.now()}`;if(i.length===0){this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s||" ",quoted_message_id:n||void 0});return}for(let h=0;h<i.length;h++){const f=h===i.length-1;this.sendStreamChunk(e,t,i[h],h+1,f,l,n)}return}this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s,quoted_message_id:n||void 0,...o?{extra:o}:{}})}sendStreamChunk(e,t,s,n,o,a,r){if(this.isEventClosed(e))return;if(r=r??this.getDefaultQuotedMessageId(e),this.flagOutboundAfterStop(e,t,"stream_chunk",n,o,(s||"").length),this.finalizeThinking(e,t),this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){this.bufferStreamChunk(e,t,s,o,r);return}if(this.streamCoalesceMs<=0){this.emitStreamChunkParts(e,t,s,n,o,a,r);return}this.coalesceStreamChunk(e,t,s,o,a,r)}async sendFinalStreamChunkReliable(e,t,s,n,o=!1){if(this.isEventClosed(e))throw new Error(`required agent output was already rejected or the event is terminal: event=${e}`);this.finalizeThinking(e,t);const a=this.resolveEventRuntimeConfig(e);if(!o&&a.responseDelivery==="single_message"&&e){if(this.flushCoalesceForEvent(e),await this.ensureSingleMessageDelivery(e,n),this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`);return}const r=`${e}:${s??"default"}`;this.flushCoalesce(r,!1),this.streamCoalesce.delete(r);const i=(this.chunkSeqMap.get(r)??0)+1;this.chunkSeqMap.set(r,i);const l=this.getDefaultQuotedMessageId(e),h={event_id:e,session_id:t,delta_content:"",chunk_seq:i,is_finish:!0,...s?{client_msg_id:s}:{},...l?{quoted_message_id:l}:{}};this.flagOutboundAfterStop(e,t,"stream_chunk_final",i,!0,0);const f=async()=>{const c=await this.handle.sendStreamChunkRequest(h,n);if(c.cmd!=="send_ack"){const m=c.payload;throw new Error(`final chunk rejected: cmd=${c.cmd} code=${m?.code??""} msg=${m?.msg??""}`)}};try{await f()}catch(c){if(E(c))u.warn("send-ctrl",`final chunk ACK timed out, retry request with same chunk_seq=${i} event=${e}`),await f();else throw u.warn("send-ctrl",`final chunk send failed (no resend) event=${e}: ${c}`),c}if(this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`)}async deliverAuxiliaryLargeText(e,t,s,n){if(!s||this.isEventClosed(e))return!1;if(this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){const r=this.getDefaultQuotedMessageId(e),i=g(s);for(let l=0;l<i.length;l++)this.flagOutboundAfterStop(e,t,"aux_detail_msg",l+1,!1,i[l].length),this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:i[l],...l===0&&r?{quoted_message_id:r}:{},client_msg_id:i.length>1?`${n}_p${l+1}`:n});return!0}const a=g(s);for(const r of a)this.sendStreamChunk(e,t,r,0,!1,n);return await this.sendFinalStreamChunkReliable(e,t,n),!0}coalesceStreamChunk(e,t,s,n,o,a){if(!s&&!n)return;const r=`${e}:${o??"default"}`;let i=this.streamCoalesce.get(r);if(i||(i={eventId:e,sessionId:t,clientMsgId:o,quotedMessageId:a,text:"",flushedOnce:!1},this.streamCoalesce.set(r,i)),s&&(i.text+=s),i.sessionId=t,o!==void 0&&(i.clientMsgId=o),!i.quotedMessageId&&a&&(i.quotedMessageId=a),n){this.flushCoalesce(r,!0);return}if(!i.flushedOnce||i.text.length>=p.STREAM_COALESCE_MAX_RUNES){this.flushCoalesce(r,!1);return}i.timer||(i.timer=setTimeout(()=>this.flushCoalesce(r,!1),this.streamCoalesceMs))}flushCoalesce(e,t){const s=this.streamCoalesce.get(e);if(!s)return;s.timer&&(clearTimeout(s.timer),s.timer=void 0);const n=s.text;s.text="",s.flushedOnce=!0,t&&this.streamCoalesce.delete(e),!(!n&&!t)&&this.emitStreamChunkParts(s.eventId,s.sessionId,n,0,t,s.clientMsgId,s.quotedMessageId)}flushCoalesceForEvent(e){const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])s.startsWith(t)&&(this.flushCoalesce(s,!1),this.streamCoalesce.delete(s))}emitStreamChunkParts(e,t,s,n,o,a,r){const i=s||(o?`
2
- `:"");if(!i&&!o)return;const l=g(i,C);l.length===0&&l.push(i||`
3
- `);const h=`${e}:${a??"default"}`;for(let f=0;f<l.length;f++){const c=f===l.length-1,m=this.chunkSeqMap.get(h)??0,_=f===0&&n>m?n:m+1;this.chunkSeqMap.set(h,_),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:l[f],chunk_seq:_,is_finish:c&&o,...a?{client_msg_id:a}:{},...r?{quoted_message_id:r}:{}})}}sendEventResult(e,t,s,n){this.finalizeThinking(e,""),this.flushCoalesceForEvent(e);const o=this.ensureSingleMessageDelivery(e),a=(r,i=s,l=n)=>{r==="responded"&&this.rejectedEvents.has(e)&&(r="failed",l=l||"agent_output_rejected",i=i||"required agent output was rejected by the server"),this.markEventTerminal(e),this.handle.sendEventResult({event_id:e,status:r,...i?{msg:i}:{},...l?{code:l}:{},updated_at:Date.now()}),this.clearEventTrackingState(e)};if(!o){a(t);return}o.then(()=>a(t),r=>{const i=`final output delivery failed: ${r instanceof Error?r.message:String(r)}`;a(t==="responded"?"failed":t,t==="responded"?i:s,t==="responded"?"agent_output_delivery_failed":n)})}sendThinking(e,t,s){if(this.shouldDropThinkingDisplayEvent(e)||this.isEventClosed(e))return;this.flagOutboundAfterStop(e,t,"thinking",this.thinkingSeqMap.get(e)??0,!1,(s||"").length);const n=(this.thinkingSeqMap.get(e)??0)+1;this.thinkingSeqMap.set(e,n),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:s,chunk_seq:n,is_finish:!1,client_msg_id:`${e}_thinking`,is_thinking:!0})}sendToolExecutionCard(e,t,s,n){if(this.shouldDropToolDisplayEvent(e)){u.info("send-ctrl",`[tool-card] DROP event=${e} session=${t} summary=${s.summaryText}`);return}const a=Date.now(),r=`${e}:${s.summaryText}:${s.detailText??""}`,i=this.recentToolCards.get(r);if(i!==void 0&&a-i<p.TOOL_CARD_DEDUP_MS){u.info("send-ctrl",`[tool-card] DEDUP event=${e} session=${t} summary=${s.summaryText}`);return}this.recentToolCards.set(r,a);const l={summary_text:s.summaryText};s.detailText&&(l.detail_text=s.detailText),u.info("send-ctrl",`[tool-card] SEND event=${e} session=${t} summary=${s.summaryText}`),this.handle.sendMsg({event_id:e,session_id:t,client_msg_id:n??`tool_${++this.toolCardSeq}_${Date.now()}`,msg_type:1,content:"",extra:{channel_data:{grix:{toolExecution:l}},agent_api_origin:!0}})}finalizeThinking(e,t){const s=this.thinkingSeqMap.get(e);s!==void 0&&(this.thinkingSeqMap.delete(e),t&&(this.isEventClosed(e)||this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:"",chunk_seq:s+1,is_finish:!0,client_msg_id:`${e}_thinking`,is_thinking:!0})))}bufferOnly(e,t,s,n,o){o=o??this.getDefaultQuotedMessageId(e),this.bufferStreamChunk(e,t,s,n,o)}bufferStreamChunk(e,t,s,n,o){const a=this.bufferedEventTexts.get(e);a?(s&&(a.text+=s),!a.quotedMessageId&&o&&(a.quotedMessageId=o)):this.bufferedEventTexts.set(e,{sessionId:t,text:s??"",quotedMessageId:o||void 0}),n&&this.ensureSingleMessageDelivery(e)?.catch(i=>{u.warn("send-ctrl",`single-message output delivery failed event=${e}: ${i instanceof Error?i.message:String(i)}`)})}ensureSingleMessageDelivery(e,t){const s=this.singleMessageDeliveries.get(e);if(s)return s;const n=this.bufferedEventTexts.get(e);if(!n||(this.bufferedEventTexts.delete(e),!n.text))return;const o=(async()=>{const a={event_id:e,session_id:n.sessionId,content:n.text,client_msg_id:`agent_single_${e}`,...n.quotedMessageId?{quoted_message_id:n.quotedMessageId}:{}},r=async()=>{const i=t===void 0?await this.handle.sendText(a):await this.handle.sendText(a,t);if(i.cmd!=="send_ack"){const l=i.payload;throw new Error(`single-message output rejected: cmd=${i.cmd} code=${l?.code??""} msg=${l?.msg??""}`)}};try{await r()}catch(i){if(!E(i))throw i;u.warn("send-ctrl",`single-message ACK timed out, retry request with stable client_msg_id=${a.client_msg_id} event=${e}`),await r()}})();return this.singleMessageDeliveries.set(e,o),o}}function S(){const d=process.env.GRIX_STREAM_COALESCE_MS;if(d===void 0||d==="")return 500;const e=Number(d);return Number.isFinite(e)&&e>=0?Math.floor(e):500}function D(d,e){return e&&typeof e=="object"&&e.channel_data?.grix?.toolExecution?!0:/^\[tool\]/.test(d)||/^\[tool result\]/.test(d)}export{v as DEFAULT_QUOTE_TRIGGER_BY_ADAPTER,p as SendController};
1
+ import{isRequestTimeoutError as E}from"../core/aibot/errors.js";import{log as f}from"../core/log/index.js";import{splitTextForAibotProtocol as p,AIBOT_PROTOCOL_MAX_RUNES as C}from"../core/protocol/protocol-text.js";import{isThinkingEventDropped as k,isToolEventDropped as y,normalizeRuntimeConfigSnapshot as S}from"./runtime-config.js";const q={claude:!1,acp:!1,codex:!0,codewhale:!0,pi:!0,openhuman:!1,cursor:!1,opencode:!0,agy:!0};class _{handle;connectorRuntimeConfig;eventRuntimeConfigs=new Map;eventQuotedMessageIds=new Map;defaultQuoteTrigger=!1;thinkingSeqMap=new Map;thinkingSessionMap=new Map;toolCardSeq=0;bufferedEventTexts=new Map;singleMessageDeliveries=new Map;chunkSeqMap=new Map;rejectedEvents=new Set;terminalEvents=new Set;static MAX_TERMINAL_EVENTS=1e3;stoppedEvents=new Set;streamCoalesce=new Map;streamCoalesceMs=T();static STREAM_COALESCE_MAX_RUNES=2048;recentToolCards=new Map;static TOOL_CARD_DEDUP_MS=100;constructor(e){this.connectorRuntimeConfig={...e}}bind(e){this.handle=e}markEventRejected(e){if(!e)return;this.rejectedEvents.add(e);const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])if(s.startsWith(t)){const n=this.streamCoalesce.get(s);n.timer&&clearTimeout(n.timer),this.streamCoalesce.delete(s)}f.info("send-ctrl",`event marked as stream-rejected, future chunks will be dropped event=${e}`)}markEventTerminal(e){if(!(!e||this.terminalEvents.has(e))&&(this.terminalEvents.add(e),this.terminalEvents.size>_.MAX_TERMINAL_EVENTS)){const t=this.terminalEvents.values().next().value;t!==void 0&&this.terminalEvents.delete(t)}}isEventClosed(e){return!!e&&(this.rejectedEvents.has(e)||this.terminalEvents.has(e))}markEventStopped(e){e&&(this.stoppedEvents.add(e),f.info("send-ctrl",`[stop-trace] event marked stopped; subsequent outbound will be flagged event=${e}`))}flagOutboundAfterStop(e,t,s,n,r,a){!e||!this.stoppedEvents.has(e)||f.warn("send-ctrl",`[stop-trace] OUTBOUND AFTER STOP ${s} event=${e} session=${t} seq=${n} is_finish=${r} len=${a}`)}getGlobalRuntimeConfig(){return this.connectorRuntimeConfig}setStreamCoalesceMs(e){this.streamCoalesceMs=Number.isFinite(e)&&e>0?Math.floor(e):0}captureEventRuntimeConfig(e){this.terminalEvents.delete(e.event_id);const t=S(e.connector_runtime_config);if(t||!this.eventRuntimeConfigs.has(e.event_id)){const s=t??this.connectorRuntimeConfig;this.eventRuntimeConfigs.set(e.event_id,{responseDelivery:s.responseDelivery,toolEvents:s.toolEvents,thinkingEvents:s.thinkingEvents})}e.msg_id&&!this.eventQuotedMessageIds.has(e.event_id)&&this.eventQuotedMessageIds.set(e.event_id,e.msg_id)}discardEventState(e){e&&(this.markEventTerminal(e),this.clearEventTrackingState(e))}clearEventTrackingState(e){this.eventRuntimeConfigs.delete(e),this.eventQuotedMessageIds.delete(e),this.rejectedEvents.delete(e),this.singleMessageDeliveries.delete(e),this.thinkingSeqMap.delete(e),this.thinkingSessionMap.delete(e),this.bufferedEventTexts.delete(e);for(const t of[...this.streamCoalesce.keys()])if(t.startsWith(`${e}:`)){const s=this.streamCoalesce.get(t);s.timer&&clearTimeout(s.timer),this.streamCoalesce.delete(t)}this.stoppedEvents.delete(e)&&f.info("send-ctrl",`[stop-trace] event tracking cleared stop flag event=${e}`);for(const t of this.chunkSeqMap.keys())t.startsWith(`${e}:`)&&this.chunkSeqMap.delete(t);for(const t of this.recentToolCards.keys())t.startsWith(`${e}:`)&&this.recentToolCards.delete(t)}setDefaultQuoteTrigger(e){this.defaultQuoteTrigger=e}getDefaultQuotedMessageId(e){if(!(!this.defaultQuoteTrigger||!e))return this.eventQuotedMessageIds.get(e)}resolveEventRuntimeConfig(e){if(e){const t=this.eventRuntimeConfigs.get(e);if(t)return t}return this.connectorRuntimeConfig}shouldDropToolDisplayEvent(e){return y(this.resolveEventRuntimeConfig(e))}shouldDropThinkingDisplayEvent(e){return k(this.resolveEventRuntimeConfig(e))}shouldDropCodexDisplayEvent(e,t){return this.shouldDropToolDisplayEvent(e)?t==="item/completed":!1}shouldDropAcpRawDisplayEvent(e,t){return!!(this.shouldDropToolDisplayEvent(e)&&(t==="tool_use"||t==="tool_result")||this.shouldDropThinkingDisplayEvent(e)&&t==="thinking")}sendReply(e,t,s,n,r,a){if(!a?.skipToolFilter&&this.shouldDropToolDisplayEvent(e)&&D(s,r)||this.isEventClosed(e))return;if(this.flagOutboundAfterStop(e,t,"reply",0,!1,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="stream"&&!r){const i=p(s),l=e?`reply_stream_${e}`:`reply_stream_${Date.now()}`;if(i.length===0){this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s||" ",quoted_message_id:n||void 0});return}for(let u=0;u<i.length;u++){const c=u===i.length-1;this.sendStreamChunk(e,t,i[u],u+1,c,l,n)}return}this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s,quoted_message_id:n||void 0,...r?{extra:r}:{}})}sendStreamChunk(e,t,s,n,r,a,o){if(this.isEventClosed(e))return;if(o=o??this.getDefaultQuotedMessageId(e),this.flagOutboundAfterStop(e,t,"stream_chunk",n,r,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){this.bufferStreamChunk(e,t,s,r,o);return}if(this.streamCoalesceMs<=0){this.emitStreamChunkParts(e,t,s,n,r,a,o);return}this.coalesceStreamChunk(e,t,s,r,a,o)}async sendFinalStreamChunkReliable(e,t,s,n,r=!1,a=!1){if(this.isEventClosed(e))throw new Error(`required agent output was already rejected or the event is terminal: event=${e}`);a||this.finalizeThinking(e,t);const o=this.resolveEventRuntimeConfig(e);if(!r&&o.responseDelivery==="single_message"&&e){if(this.flushCoalesceForEvent(e),await this.ensureSingleMessageDelivery(e,n),this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`);return}const i=`${e}:${s??"default"}`;this.flushCoalesce(i,!1),this.streamCoalesce.delete(i);const l=(this.chunkSeqMap.get(i)??0)+1;this.chunkSeqMap.set(i,l);const u=this.getDefaultQuotedMessageId(e),c={event_id:e,session_id:t,delta_content:"",chunk_seq:l,is_finish:!0,...s?{client_msg_id:s}:{},...u?{quoted_message_id:u}:{}};this.flagOutboundAfterStop(e,t,"stream_chunk_final",l,!0,0);const m=async()=>{const h=await this.handle.sendStreamChunkRequest(c,n);if(h.cmd!=="send_ack"){const g=h.payload;throw new Error(`final chunk rejected: cmd=${h.cmd} code=${g?.code??""} msg=${g?.msg??""}`)}};try{await m()}catch(h){if(E(h))f.warn("send-ctrl",`final chunk ACK timed out, retry request with same chunk_seq=${l} event=${e}`),await m();else throw f.warn("send-ctrl",`final chunk send failed (no resend) event=${e}: ${h}`),h}if(this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`)}async deliverAuxiliaryLargeText(e,t,s,n){if(!s||this.isEventClosed(e))return!1;if(this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){const o=this.getDefaultQuotedMessageId(e),i=p(s);for(let l=0;l<i.length;l++)this.flagOutboundAfterStop(e,t,"aux_detail_msg",l+1,!1,i[l].length),this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:i[l],...l===0&&o?{quoted_message_id:o}:{},client_msg_id:i.length>1?`${n}_p${l+1}`:n});return!0}const a=p(s);for(const o of a)this.sendStreamChunk(e,t,o,0,!1,n);return await this.sendFinalStreamChunkReliable(e,t,n,void 0,!1,!0),!0}coalesceStreamChunk(e,t,s,n,r,a){if(!s&&!n)return;const o=`${e}:${r??"default"}`;let i=this.streamCoalesce.get(o);if(i||(i={eventId:e,sessionId:t,clientMsgId:r,quotedMessageId:a,text:"",flushedOnce:!1},this.streamCoalesce.set(o,i)),s&&(i.text+=s),i.sessionId=t,r!==void 0&&(i.clientMsgId=r),!i.quotedMessageId&&a&&(i.quotedMessageId=a),n){this.flushCoalesce(o,!0);return}if(!i.flushedOnce||i.text.length>=_.STREAM_COALESCE_MAX_RUNES){this.flushCoalesce(o,!1);return}i.timer||(i.timer=setTimeout(()=>this.flushCoalesce(o,!1),this.streamCoalesceMs))}flushCoalesce(e,t){const s=this.streamCoalesce.get(e);if(!s)return;s.timer&&(clearTimeout(s.timer),s.timer=void 0);const n=s.text;s.text="",s.flushedOnce=!0,t&&this.streamCoalesce.delete(e),!(!n&&!t)&&this.emitStreamChunkParts(s.eventId,s.sessionId,n,0,t,s.clientMsgId,s.quotedMessageId)}flushCoalesceForEvent(e){const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])s.startsWith(t)&&(this.flushCoalesce(s,!1),this.streamCoalesce.delete(s))}emitStreamChunkParts(e,t,s,n,r,a,o){const i=s||(r?`
2
+ `:"");if(!i&&!r)return;const l=p(i,C);l.length===0&&l.push(i||`
3
+ `);const u=`${e}:${a??"default"}`;for(let c=0;c<l.length;c++){const m=c===l.length-1,h=this.chunkSeqMap.get(u)??0,g=c===0&&n>h?n:h+1;this.chunkSeqMap.set(u,g),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:l[c],chunk_seq:g,is_finish:m&&r,...a?{client_msg_id:a}:{},...o?{quoted_message_id:o}:{}})}}sendEventResult(e,t,s,n){this.finalizeThinking(e,""),this.flushCoalesceForEvent(e);const r=this.ensureSingleMessageDelivery(e),a=(o,i=s,l=n)=>{o==="responded"&&this.rejectedEvents.has(e)&&(o="failed",l=l||"agent_output_rejected",i=i||"required agent output was rejected by the server"),this.markEventTerminal(e),this.handle.sendEventResult({event_id:e,status:o,...i?{msg:i}:{},...l?{code:l}:{},updated_at:Date.now()}),this.clearEventTrackingState(e)};if(!r){a(t);return}r.then(()=>a(t),o=>{const i=`final output delivery failed: ${o instanceof Error?o.message:String(o)}`;a(t==="responded"?"failed":t,t==="responded"?i:s,t==="responded"?"agent_output_delivery_failed":n)})}sendThinking(e,t,s){if(this.shouldDropThinkingDisplayEvent(e)||this.isEventClosed(e))return;this.flagOutboundAfterStop(e,t,"thinking",this.thinkingSeqMap.get(e)??0,!1,(s||"").length);const n=(this.thinkingSeqMap.get(e)??0)+1;this.thinkingSeqMap.set(e,n),this.thinkingSessionMap.set(e,t),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:s,chunk_seq:n,is_finish:!1,client_msg_id:`${e}_thinking`,is_thinking:!0})}sendToolExecutionCard(e,t,s,n){if(this.shouldDropToolDisplayEvent(e)){f.info("send-ctrl",`[tool-card] DROP event=${e} session=${t} summary=${s.summaryText}`);return}const a=Date.now(),o=`${e}:${s.summaryText}:${s.detailText??""}`,i=this.recentToolCards.get(o);if(i!==void 0&&a-i<_.TOOL_CARD_DEDUP_MS){f.info("send-ctrl",`[tool-card] DEDUP event=${e} session=${t} summary=${s.summaryText}`);return}this.recentToolCards.set(o,a);const l={summary_text:s.summaryText};s.detailText&&(l.detail_text=s.detailText),f.info("send-ctrl",`[tool-card] SEND event=${e} session=${t} summary=${s.summaryText}`),this.handle.sendMsg({event_id:e,session_id:t,client_msg_id:n??`tool_${++this.toolCardSeq}_${Date.now()}`,msg_type:1,content:"",extra:{channel_data:{grix:{toolExecution:l}},agent_api_origin:!0}})}finalizeThinking(e,t){const s=this.thinkingSeqMap.get(e);s!==void 0&&(this.thinkingSeqMap.delete(e),t=t||this.thinkingSessionMap.get(e)||"",this.thinkingSessionMap.delete(e),t&&(this.isEventClosed(e)||this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:"",chunk_seq:s+1,is_finish:!0,client_msg_id:`${e}_thinking`,is_thinking:!0})))}bufferOnly(e,t,s,n,r){r=r??this.getDefaultQuotedMessageId(e),this.bufferStreamChunk(e,t,s,n,r)}bufferStreamChunk(e,t,s,n,r){const a=this.bufferedEventTexts.get(e);a?(s&&(a.text+=s),!a.quotedMessageId&&r&&(a.quotedMessageId=r)):this.bufferedEventTexts.set(e,{sessionId:t,text:s??"",quotedMessageId:r||void 0}),n&&this.ensureSingleMessageDelivery(e)?.catch(i=>{f.warn("send-ctrl",`single-message output delivery failed event=${e}: ${i instanceof Error?i.message:String(i)}`)})}ensureSingleMessageDelivery(e,t){const s=this.singleMessageDeliveries.get(e);if(s)return s;const n=this.bufferedEventTexts.get(e);if(!n||(this.bufferedEventTexts.delete(e),!n.text))return;const r=(async()=>{const a={event_id:e,session_id:n.sessionId,content:n.text,client_msg_id:`agent_single_${e}`,...n.quotedMessageId?{quoted_message_id:n.quotedMessageId}:{}},o=async()=>{const i=t===void 0?await this.handle.sendText(a):await this.handle.sendText(a,t);if(i.cmd!=="send_ack"){const l=i.payload;throw new Error(`single-message output rejected: cmd=${i.cmd} code=${l?.code??""} msg=${l?.msg??""}`)}};try{await o()}catch(i){if(!E(i))throw i;f.warn("send-ctrl",`single-message ACK timed out, retry request with stable client_msg_id=${a.client_msg_id} event=${e}`),await o()}})();return this.singleMessageDeliveries.set(e,r),r}}function T(){const d=process.env.GRIX_STREAM_COALESCE_MS;if(d===void 0||d==="")return 500;const e=Number(d);return Number.isFinite(e)&&e>=0?Math.floor(e):500}function D(d,e){return e&&typeof e=="object"&&e.channel_data?.grix?.toolExecution?!0:/^\[tool\]/.test(d)||/^\[tool result\]/.test(d)}export{q as DEFAULT_QUOTE_TRIGGER_BY_ADAPTER,_ as SendController};
@@ -1 +1 @@
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
+ 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 +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 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
+ 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};
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 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+`
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+`
3
3
  `)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
@@ -1 +1 @@
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
+ 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 +1 @@
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
+ 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 +1 @@
1
- function a(e){const t=new Set([`http://127.0.0.1:${e.serverPort}`,`http://localhost:${e.serverPort}`,...e.allowedOrigins]),o=new Set([`127.0.0.1:${e.serverPort}`,`localhost:${e.serverPort}`,...e.allowedHosts]);return{validateRequest(s){const r=i(s,t);if(!r.ok)return r;const n=l(s,o);return n.ok?{ok:!0}:n}}}function i(e,t){const o=e.headers.origin;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${o}`}:{ok:!0}}function l(e,t){const o=e.headers.host;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${o}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
1
+ function a(o){const e=new Set([`http://127.0.0.1:${o.serverPort}`,`http://localhost:${o.serverPort}`,...o.allowedOrigins]),t=new Set([`127.0.0.1:${o.serverPort}`,`localhost:${o.serverPort}`,...o.allowedHosts]);return{validateRequest(s){const r=i(s,e);if(!r.ok)return r;const n=l(s,t);return n.ok?{ok:!0}:n}}}function i(o,e){const t=o.headers.origin;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${t}`}:{ok:!0}}function l(o,e){const t=o.headers.host;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${t}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
@@ -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(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
+ 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 +1 @@
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
+ 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 +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(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};
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "3.26.3",
3
+ "version": "3.26.4",
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",