grix-connector 4.3.5 → 4.3.6

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,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "bridgeVersion": "4.3.5",
4
- "tarball": "grix-dsh-bridge-4.3.5.tgz",
5
- "size": 22490,
6
- "unpackedSize": 89865,
7
- "shasum": "38e2356ae7b0d90fd13e1b559a2bb5cb181a8478",
8
- "integrity": "sha512-ossM+JJHkOWD3QTxJ0pDybFilFWjIz7f0l/nWeYBtr0XLwkwwO8s0uK6XV6SN//YlizvPUibwo7+HRUMawPMBQ=="
3
+ "bridgeVersion": "4.3.6",
4
+ "tarball": "grix-dsh-bridge-4.3.6.tgz",
5
+ "size": 22663,
6
+ "unpackedSize": 90315,
7
+ "shasum": "c992fb41caa4dffbb44075691e0f7d37f40966de",
8
+ "integrity": "sha512-jhhappFq/vk0W78nKYD2PjkMWkLHBLUss9hwLJxP3rg+39bgjZJq2T7mw0Y88dWRicEpSaStAvdd45aEfMQsFg=="
9
9
  }
@@ -1,9 +1,9 @@
1
- import y from"node:path";import{tmpdir as U}from"node:os";import{createHash as M,randomUUID as R}from"node:crypto";import{ConnectionManager as q}from"../core/aibot/index.js";import{AUDIT_LOCAL_ACTION_TYPES as N}from"../core/aibot/types.js";import{ClaudeAdapter as L}from"../adapter/claude/index.js";import{CodexAdapter as D}from"../adapter/codex/index.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"../adapter/deepseek-harness/session-history.js";import{PiAdapter as W}from"../adapter/pi/index.js";import{AcpAdapter as S}from"../adapter/acp/index.js";import{OpenHumanAdapter as G}from"../adapter/openhuman/index.js";import{CursorAdapter as j}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as K}from"../adapter/codewhale/index.js";import{OpenCodeAdapter as k}from"../adapter/opencode/index.js";import{AgyAdapter as H}from"../adapter/agy/index.js";import{DshJsonRpcAdapter as z}from"../adapter/deepseek-harness/index.js";import{LOCAL_ACTION_TYPES as f,SESSION_CONTROL_ERROR_CODES as $,SESSION_CONTROL_VERBS as E,SESSION_MODE_IDS as J}from"../adapter/claude/protocol-contract.js";import{isAuditLocalActionType as Y}from"../audit/query/audit-local-actions.js";import{shouldEnableRawApiCapture as Q}from"../audit/raw-capture/types.js";import{buildWireSkills as X}from"../core/skill-sync/sync-state.js";import{executeEventTool as V}from"../core/mcp/event-tool-executor.js";import{fetchAvailableModels as Z}from"../adapter/claude/model-list.js";import{applyProxyEnv as ee,getProxyManager as te}from"../core/proxy/index.js";import{getKiroRelaySpawnEnv as ne}from"../core/proxy/kiro-relay.js";import{supportsKiroCwRelay as ie}from"../core/config/provider-env.js";import{buildProviderEnv as se}from"../core/config/provider-env.js";import{isClaudeDirectEnv as oe,stripGrixRelayEnv as re}from"../core/config/claude-direct-env.js";import{sweepNativeProviderResidue as ae}from"./native-provider-sweep.js";import{scanCodexSessions as de}from"../adapter/codex/session-scanner.js";import{scanClaudeSessions as le}from"../adapter/claude/session-scanner.js";import{resolveAcpAgentTypes as ce,scanAcpSessions as he,scanReasonixSessionTitles as ue}from"../adapter/acp/session-scanner.js";import{scanPiSessions as pe}from"../adapter/pi/session-scanner.js";import{scanCodeWhaleSessions as ge}from"../adapter/codewhale/session-scanner.js";import{scanCursorSessions as fe}from"../adapter/cursor/session-scanner.js";import{scanOpenCodeSessions as me}from"../adapter/opencode/session-scanner.js";import{scanDshSessions as ve}from"../adapter/deepseek-harness/session-scanner.js";import{SessionScanCache as v,resolveCodexLeafDirs as _e,resolveClaudeLeafDirs as Se,resolveAcpLeafDirs as Ce,resolvePiLeafDirs as be,resolveCodeWhaleLeafDirs as Ae,resolveCursorLeafDirs as Ee,resolveOpenCodeLeafDirs as we,resolveDshLeafDirs as ye,resolveReasonixLeafDirs as Re}from"./session-scan-cache.js";import{log as h,ConversationLog as ke,AgentApiPacketLog as Te,BridgeEventLog as Pe,GRIX_PATHS as w}from"../core/log/index.js";import{routeSessionControlCommand as xe,routeSessionControlLocalAction as Me}from"./session-control-router.js";import{maybeOfferCliInstall as Le,handleCliInstallQuestionReply as De,handleCliInstallInteractionReply as He,runConfirmedCliInstall as $e}from"./cli-install-flow.js";import{handleEventCancel as Qe,waitForEventDone as Ie,handleAibotStop as Oe,killAndResumeStopSlot as Be,handleAibotRevoke as Fe}from"./event-stop.js";import{handleConfigureGatewayProvider as Ue,getAuditLocalActionHandler as qe,handleAuditLocalAction as Ne,handleConnectorRollback as We,getRelayStateSyncer as Ge,relayStateSyncOnConnect as je,reportRelayStateLocalChange as Ke,handleApplyRelayState as ze,fetchRelayCredential as Je,isSharedInstance as Ye}from"./connector-ops.js";import{unbindSession as Xe,handleUnbindTextCommand as Ve,handleUnbindLocalAction as Ze,handleListSessionsTextCommand as et,handleListSessionsLocalAction as tt,handleSyncHistoryLocalAction as nt}from"./session-list.js";import{handleCodexSessionControlOpen as it,handleSessionControlForPool as st,handleSessionControlLocalActionForPool as ot,handleCodexSessionControlLocalActionOpen as rt,handleCursorSessionControlLocalActionOpen as at,handlePiSessionControlOpen as dt,handlePiSessionControlRestart as lt,handlePiSessionControlRestartLocalAction as ct,syncOpenCodeBinding as ht,isWorkspaceFreeClient as ut,ensureDefaultBindingForWorkspaceFreeClient as pt,bindSessionForPool as gt,deferredCallbacks as ft,handleOpenHumanSessionControlOpen as mt,handleCodeWhaleSessionControlOpen as vt,handleCodeWhaleSessionControlLocalActionOpen as _t,handleDeepSeekSessionControlLocalActionOpen as St}from"./session-control-open.js";import{handleGetSessionUsage as Ct,handleThreadCompact as bt}from"./session-usage.js";import{handleSkillDeleteLocalAction as At,handleSkillUploadLocalAction as Et,handleSkillEnableLocalAction as wt,handleSkillRefreshLocalAction as yt,handleSkillDisableLocalAction as Rt,computeSkillReport as kt,reportSessionSkills as Tt,skillsSyncGroupKey as Pt,forceRefreshSkills as xt,adoptSkillsWireHashFromDisk as Mt,buildLibrarySkillsReport as Lt,skillLookupEnv as Dt}from"./skill-actions.js";import{normalizeClaudeModeId as Ht,handleExecCommandOptions as $t,resolveSessionModelId as Qt,resolveSessionModeId as It,resolveCursorSessionModeId as Ot,resolveClaudeSessionEffort as Bt,resolveClaudeSessionModeId as Ft,currentClaudeModeId as Ut,resolveCodexSessionModelId as qt,resolveCodexNewSessionGlobalDefault as Nt,pinCodexGlobalDefault as Wt,buildCursorToolbarMeta as Gt,buildAgyToolbarMeta as jt,buildAgyQuotaMeta as Kt,sendAgyBindingCard as zt,refreshAndPushAgyQuota as Jt,handleAgySetModel as Yt,buildClaudeToolbarMeta as Xt}from"./toolbar-meta.js";import{resolveProviderQuotaSource as Vt,maybeQueryProviderQuota as Zt,startProviderQuotaTimer as en,stopProviderQuotaTimer as tn,refreshAndPushProviderQuota as nn,pushProviderQuotaToBindings as sn,enrichProviderQuotaMeta as on,providerQuotaMetaPayload as rn,refreshProviderQuotaForSession as an,refreshQuotaAfterModelSwitch as dn,doRefreshQuotaAfterModelSwitch as ln}from"./provider-quota.js";import{handleGetRateLimits as cn,resolveRateLimitWakeSessionId as hn,wakeRateLimitSlot as un}from"./rate-limits.js";import{RevokeHandler as pn}from"./revoke-handler.js";import{AdapterPool as gn}from"./adapter-pool.js";import{parseSessionControlCommand as fn}from"./session-controller.js";import{isOpenSessionDirectiveMessage as mn,parseExecApprovalResolutionMessage as vn,parseAgentQuestionReplyMessage as _n}from"../core/protocol/interaction-parser.js";import{rejectUnusableAuditOptions as Sn}from"./inbound-audit-gate.js";import{interceptUnboundInboundEvent as Cn}from"./inbound-binding-gate.js";import{dispatchSessionControlTextCommand as bn}from"./text-command-session-control.js";import{dispatchSessionControlLocalAction as An}from"./local-action-session-control.js";import{handleCreateFolderLocalAction as En,handleFileListLocalAction as wn}from"./local-action-files.js";import{handleAcpToolbarLocalAction as yn,persistToolbarSelection as Rn}from"./local-action-toolbar.js";import{buildOpenedBindingResult as kn,ensureImportedAgentSession as Tn,hasDiskScanner as Pn,normalizePathForCompare as xn,providerKeyForAdapter as Mn,resolveAgentSessionId as Ln,resolveOrphanTitle as Dn,setResolvedAgentSessionId as Hn}from"./session-identity.js";import{buildDshOpenedToolbarMeta as $n,dshCatalogDataRoot as Qn}from"./dsh-toolbar.js";import{ensureSlotStarted as In,failSessionOpen as On,getClaudeWorkerStatus as Bn,refreshClaudeWorkerStatusCard as Fn,resolveCwdForBinding as Un}from"./session-open-helpers.js";import{handleAcpSetModel as qn,handleAcpSetMode as Nn,resolveAcpInitialDefaults as Wn}from"./acp-toolbar-persist.js";import{SessionBindingStore as Gn}from"../core/persistence/session-binding-store.js";import{serveLocalFile as jn}from"../core/files/index.js";import{uploadReplyFileToAgentMedia as Kn}from"../core/protocol/agent-api-media.js";import{ActiveEventStore as zn}from"../core/persistence/active-event-store.js";import{PendingEventCoordinator as Jn}from"./pending-event-coordinator.js";import{LifecycleBarrier as Yn}from"./lifecycle-barrier.js";import{QUEUE_COMPOSING_TTL_MS as Xn}from"./event-queue.js";import{DEFAULT_CONNECTOR_RUNTIME_CONFIG as Vn,applyConnectorRuntimeConfigPatch as Zn,extractConnectorRuntimeConfigPatch as ei}from"./runtime-config.js";import{DEFAULT_QUOTE_TRIGGER_BY_ADAPTER as ti,SendController as ni}from"./send-controller.js";import{providerQuotaToRateLimits as ii,providerQuotaToCodexRateLimits as si}from"../core/provider-quota/index.js";import{buildToolUseCard as C,buildToolResultCard as b,buildDshOnlineToolCard as oi,buildLocalGrixCardLink as I}from"./tool-card-utils.js";import{planRawEventDelivery as ri,buildAuxiliaryDetailText as ai}from"./raw-event-delivery.js";import{DeferredEventManager as di}from"./deferred-events.js";import{buildAgentProbeResult as li,PROBE_CACHE_TTL_STATIC_MS as ci,PROBE_CACHE_TTL_FULL_MS as hi}from"./probe-helper.js";import{BridgeAuditController as ui}from"../audit/integration/bridge-audit-controller.js";import{isSettlableAuditProducer as pi,NoopAuditProducer as gi}from"../audit/producer/audit-producer.js";import{buildAuditStatePayload as O,AuditPreparationFailedError as fi,AuditTurnScopeUnsupportedError as mi}from"../audit/core/audit-state.js";import{extractAuditOptions as B,freezeAuditOptions as vi,stripAuditOptions as _i}from"../audit/core/audit-options.js";import{AuditSessionOptionsError as Si}from"../audit/core/audit-session-registry.js";const Ci=600*1e3,F=1800*1e3,bi=60*1e3,Ai=4e3;function Ei(x,e,i){const r=M("sha256").update(x).update("\0").update(e).update("\0").update(i).digest("hex");return y.join(w.data,"audit-source","reasonix",`${r}.jsonl`)}const T=new Set(["claude","acp","agy","cursor","codex","deepseek-harness"]),wi=new Set(["claude","codex","cursor","codewhale","opencode","pi","openhuman","agy","acp","deepseek-harness"]),P=3;class oo{config;name;aibotHandle;aibotConfig;pool;stopped=!1;startupAbortController=new AbortController;stopPromise=null;dropPendingEventsRequested=!1;pendingEventsDropped=!1;revokeHandler=new pn;sessionBindings=new Map;deferredMgr;sendCtrl=new ni(Vn);bindingStore;globalConfigStore;upgradeTrigger=null;daemonShutdownRequester=null;lifecycleBusyChecker=null;lifecycleAdmissionCloser=null;lifecycleAdmissionRestorer=null;installAgentHandler=null;pendingCliInstalls=new Map;agentDeletedHandler=null;shareSetHandler=null;skillSyncHandler=null;providerConfigHandler=null;relayStateApplyPorts=null;relayStateSyncer=null;agentProfile={agentName:"",introduction:""};agentSystemPrompt="";activeEventStore;pendingEvents;pendingStartedEventIds=new Set;lifecycleBarrier=new Yn;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 i=Number(e);return i>0&&Date.now()-i<=bi}resolveProviderQuotaSource(e){return Vt(this,e)}maybeQueryProviderQuota(e=!1,i){return Zt(this,e,i)}startProviderQuotaTimer(){en(this)}stopProviderQuotaTimer(){tn(this)}refreshAndPushProviderQuota(e=!1){return nn(this,e)}pushProviderQuotaToBindings(e,i=!1){sn(this,e,i)}enrichProviderQuotaMeta(e,i="standard",r=this.cachedProviderQuota,n=this.cachedProviderQuotaSampledAtMs){return on(this,e,i,r,n)}providerQuotaMetaPayload(e,i,r){return rn(this,e,i,r)}refreshProviderQuotaForSession(e,i,r){return an(this,e,i,r)}refreshQuotaAfterModelSwitch(e,i,r){dn(this,e,i,r)}doRefreshQuotaAfterModelSwitch(e,i,r){return ln(this,e,i,r)}getFreshClaudeRateLimitState(){const e=this.cachedClaudeRateLimitState;return e&&this.isRateLimitsCacheFresh(e.sampledAt)?e:null}getFreshCodexGlobalRateLimitCache(){const e=this.cachedRateLimits,i=this.cachedCodexContextWindow,r=this.cachedCodexTokenUsage;return{sampledAt:Math.max(this.cachedRateLimitsSampledAtMs??0,this.cachedCodexUsageSampledAtMs??0)||null,rateLimits:e,contextWindow:i,tokenUsage:r,hasData:!!(e||i||r)}}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,wsConnected:this.aibotHandle?.status==="ready",exhausted:this.pool?[...this.pool.getAllSlots()].some(i=>i.respawn.exhausted):!1,adapterType:this.config.adapterType??"acp",clientType:this.config.aibot.clientType,pool:e}}hasPendingWork(){return this.pool?.hasPendingWork()??!1}hasPendingOrBackgroundWork(){return this.lifecycleBarrier.hasActiveAdmissions()||(this.pool?.hasPendingOrBackgroundWork()??!1)}async waitUntilLifecycleIdle(e){const i=()=>this.lifecycleBusyChecker?.()??this.hasPendingOrBackgroundWork();if(i()){const r=Math.round(F/6e4);h.info(this.name,`${e}: active tasks detected, waiting up to ${r}min until idle before restart (admission stays open while waiting)`);const n=Date.now()+F,t=5e3,s=600*1e3;let o=Date.now();for(;i()&&!this.stopped;){if(Date.now()>=n)return h.warn(this.name,`${e}: idle wait exceeded ${r}min; abandoning this restart. Admission was never closed, so agents kept serving. A busy state that never clears usually means an adapter leaked its busy flag \u2014 check for a turn that never completed.`),!1;await new Promise(a=>setTimeout(a,t)),Date.now()-o>=s&&(o=Date.now(),h.info(this.name,`${e}: still waiting for active tasks to finish before restart`))}}return this.stopped?!1:(this.closeLifecycleAdmissionForRestart(),i()?(h.warn(this.name,`${e}: work arrived while closing admission; reopening and abandoning this restart`),this.reopenLifecycleAdmissionAfterAbort(),!1):(h.info(this.name,`${e}: all tasks completed, proceeding with restart`),!0))}reopenLifecycleAdmissionAfterAbort(){if(this.lifecycleAdmissionRestorer){this.lifecycleAdmissionRestorer();return}this.openLifecycleAdmission()}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 i=0,r=!1;for(const n 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 t=!1;await this.pool.removeSlot(n.sessionId).catch(s=>{r=!0,t=!0,h.warn(this.name,`failed to recycle adapter slot ${n.sessionId} after relay change: ${s}`)}),t||(i+=1)}return i>0&&h.info(this.name,`recycled ${i} adapter slot(s) so the new Grix relay env takes effect`),r?(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 i=e.conversation?"full":"static",r=e.conversation?hi:ci;if(!e.fresh){const a=this.probeCache.get(i);if(a&&Date.now()-a.sampledAt<r)return{...a.result,cached:!0}}const n=this.config.adapterType??"acp",t=this.createAdapter(n,"__probe__"),s=e.conversation&&n==="acp"?()=>this.runAcpConversationProbe(t,e.timeoutMs??1e4):void 0;let o;try{o=await li({adapter:t,agentName:this.name,clientType:this.config.aibot.clientType,adapterType:n,providerBaseUrl:this.config.providerBaseUrl??null,opts:e,launchConversationProbe:s})}finally{t.stop().catch(()=>{})}return this.probeCache.set(i,{result:o,sampledAt:o.probed_at}),o}async runAcpConversationProbe(e,i){const r=Date.now(),n="__probe__",t=`probe-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,s=this.config.agent.cwd||U(),o=()=>Date.now()-r;try{await e.start()}catch(u){return{attempted:!0,ok:!1,latency_ms:o(),error:{code:"conversation_failed",message:`start failed: ${u instanceof Error?u.message:String(u)}`}}}if(!e.isAlive())return{attempted:!0,ok:!1,latency_ms:o(),error:{code:"process_not_started",message:"agent process not alive"}};if(e instanceof S)try{await e.bindSession(n,s)}catch{}let a=null;const l=new Promise(u=>{a=g=>{g===t&&u()},e.on("eventDone",a)});e.deliverInboundEvent({event_id:t,session_id:n,content:"ping",msg_id:t}),e.deliverStopEvent(t,n);let d=null;const c=await Promise.race([l.then(()=>!1),new Promise(u=>{d=setTimeout(()=>u(!0),i)})]);return d&&clearTimeout(d),a&&e.removeListener("eventDone",a),c?{attempted:!0,ok:!1,latency_ms:o(),error:{code:"conversation_timeout",message:`no eventDone within ${i}ms`}}:{attempted:!0,ok:!0,latency_ms:o()}}constructor(e,i,r=new gi){this.config=e,this.auditController=new ui(r,{onAuditState:t=>{try{this.aibotHandle.sendAuditState(O(t,Date.now()))}catch{}}}),pi(r)&&r.addJobSettledHandler((t,s)=>{this.auditController.handleJobSettled(t,s)}),this.name=e.name;const n=e.adapterType??"acp";if(this.sendCtrl.setDefaultQuoteTrigger(ti[n]),this.aibotConfig={...e.aibot,...n==="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",...N]}:{}},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 ke(e.logDir):null,this.packetLog=e.logDir?new Te(e.logDir):null,this.bindingStore=new Gn(e.bindingsPath,e.legacyBindingsPath),this.bindingStore.load(),this.globalConfigStore=i??null,this.deferredMgr=new di(this.name),this.activeEventStore=e.activeEventStorePath?new zn(e.activeEventStorePath):null,this.pendingEvents=new Jn(e.pendingEventStorePath),n==="codex")this.sessionScanCache=new v(de,_e);else if(n==="claude")this.sessionScanCache=new v(le,Se);else if(n==="pi"){const t=e.agent.env?.PI_CODING_AGENT_DIR;this.sessionScanCache=new v(()=>pe(void 0,t),()=>be(void 0,t))}else if(n==="codewhale")this.sessionScanCache=new v(ge,Ae);else if(n==="cursor")this.sessionScanCache=new v(fe,Ee);else if(n==="opencode")this.sessionScanCache=new v(me,we);else if(n==="deepseek-harness"){const t=typeof e.adapterOptions?.dshHome=="string"?e.adapterOptions.dshHome:e.agent.env?.DSH_HOME;this.sessionScanCache=new v(()=>ve(t),()=>ye(t))}else if(n==="agy")this.sessionScanCache=new v(()=>[],()=>[]);else{e.aibot.clientType?.trim().toLowerCase()==="reasonix"&&(this.reasonixTitleScan=new v(ue,Re));const t=ce(e.aibot.clientType);this.sessionScanCache=t?new v(()=>he(void 0,t),()=>Ce(void 0,t)):new v(()=>[],()=>[])}}async start(){if(this.stopped)throw new Error("agent start aborted");if(await ae({agentName:this.name,adapterType:this.config.adapterType??"acp",command:this.config.agent.command,piConfigDir:this.config.agent.env?.PI_CODING_AGENT_DIR,dshHome:typeof this.config.adapterOptions?.dshHome=="string"?this.config.adapterOptions.dshHome:this.config.agent.env?.DSH_HOME,hasProvider:!!this.config.agent.provider,boundCwds:[...this.bindingStore.entries()].map(([,t])=>String(t.cwd??""))}).then(t=>{t.length>0&&h.info(this.name,`restored native provider config after relay disable: ${t.join(", ")}`)}).catch(t=>{h.warn(this.name,`native provider residue sweep failed: ${t instanceof Error?t.message:String(t)}`)}),this.stopped)throw new Error("agent start aborted");if((this.config.adapterType??"acp")==="claude"){if(await Z().catch(()=>{}),this.stopped)throw new Error("agent start aborted");this.maybeQueryProviderQuota().catch(()=>{})}if(this.stopped)throw new Error("agent start aborted");const e=!!(this.config.providerBaseUrl&&this.config.providerApiKey||this.config.agent.provider?.baseUrl&&this.config.agent.provider?.apiKey),i=(this.config.adapterType??"acp")==="pi",r=(this.config.adapterType??"acp")==="opencode";if(this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi"||e?(this.maybeQueryProviderQuota().catch(()=>{}),this.startProviderQuotaTimer()):(i||r)&&this.startProviderQuotaTimer(),(this.config.adapterType??"acp")==="codex"&&this.maybeQueryProviderQuota().catch(()=>{}),(this.config.adapterType??"acp")==="opencode"&&this.maybeQueryProviderQuota().catch(()=>{}),this.stopped)throw new Error("agent start aborted");if(await this.connectAibot(),this.stopped)throw this.aibotHandle?.disconnect(),new Error("agent start aborted");this.sendCtrl.bind(this.aibotHandle);const n=this.config.adapterType??"acp";if(this.pool=new gn({maxPoolSize:this.config.poolMaxSize??20,idleTimeoutMs:this.config.poolIdleTimeoutMs??18e5,eventQueue:this.config.eventQueue},t=>{const s=this.createAdapter(n,t);return s instanceof S&&s.on("acpSessionReady",o=>{this.bindingStore.setAcpSessionId(t,o),this.sessionScanCache.invalidate()}),s},(t,s)=>{this.aibotHandle.sendEventAck({event_id:t,session_id:s,received_at:Date.now()})}),this.pool.setEventStateHandler((t,s,o,a)=>{if(h.info(this.name,`[queue-debug] send event_state session=${s} event=${t} state=${o} queue_pos=${a?.queue_position??""} queue_total=${a?.queue_total??""}`),this.aibotHandle.sendEventState({event_id:t,session_id:s,state:o,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(s),o==="running"&&(this.pendingStartedEventIds.add(t),this.pendingEvents.remove(t).catch(l=>{h.warn(this.name,`Failed to remove running event from pending store event=${t}: ${l instanceof Error?l.message:String(l)}`)})),o==="canceled"||o==="failed"){const l=o==="canceled"?"canceled":"failed";this.aibotHandle.sendEventResult({event_id:t,status:l,msg:a?.reason,updated_at:Date.now()}),this.auditController.closeWithoutAdapter(t,l,a?.reason,{queueTerminalState:o}),this.discardEventTrackingState(t),this.pendingEvents.remove(t).catch(d=>{h.warn(this.name,`Failed to remove queued terminal event from pending store event=${t}: ${d instanceof Error?d.message:String(d)}`)})}}),this.pool.setQueueComposingHandler((t,s,o)=>{this.aibotHandle.sendSessionActivitySet({session_id:t,kind:"composing",active:s,...s?{ttl_ms:Xn,ref_event_id:o}:{}})}),this.pool.setInternalErrorHandler(t=>{this.handleSessionInternalError(t).catch(s=>{h.error(this.name,`[recovery] handleSessionInternalError failed event=${t.eventId} session=${t.sessionId}: ${s instanceof Error?s.message:String(s)}`)})}),this.pool.setEventStartedHandler((t,s)=>{if(this.reportSessionSkills(s),this.config.adapterType!=="claude")return;this.claudeWorkerStatus.set(s,"busy");const o=this.bindingStore.get(s);o?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"busy",cwd:o.cwd,meta:this.buildClaudeToolbarMeta(s)})}),this.pool.setEventDoneHandler((t,s)=>{this.markAuditAdapterClosed(t,s);const o=this.config.adapterType??"acp";if(o==="claude"){this.claudeWorkerStatus.set(s,"ready");const a=this.bindingStore.get(s);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"ready",cwd:a.cwd,meta:this.buildClaudeToolbarMeta(s)})}else if(o==="agy"){const a=this.bindingStore.get(s);if(a?.cwd){const l=this.buildAgyToolbarMeta(s),d=l?.available_models??[];h.info(this.name,`[agy-toolbar-diag] eventDone push binding card session=${s} model_id=${String(l?.model_id??"")} available_models=${d.length} meta_keys=${l?Object.keys(l).join(","):"<none>"}`),this.sendAgyBindingCard(s,a.cwd,l),this.refreshAndPushAgyQuota(s)}else h.info(this.name,`[agy-toolbar-diag] eventDone skip binding card: no binding cwd session=${s}`)}}),this.pool.setSessionActivityHandler((t,s,o)=>{const a=this.selfDrivenSessions.has(t),l=this.selfDrivenLabels.get(t);s?(this.selfDrivenSessions.add(t),o&&this.selfDrivenLabels.set(t,o),this.aibotHandle.sendSessionActivitySet({session_id:t,kind:"composing",active:!0,ttl_ms:9e4})):(this.selfDrivenSessions.delete(t),this.selfDrivenLabels.delete(t),a&&this.aibotHandle.sendSessionActivitySet({session_id:t,kind:"composing",active:!1})),(a!==s||s&&o!==void 0&&o!==l)&&this.pushQueueSnapshotForSession(t)}),await this.replayPendingEventsOnStartup(),this.stopped)throw new Error("agent start aborted");this.pool.startIdleSweep(),h.info(this.name,`Ready (adapter: ${n}, poolMax: ${this.config.poolMaxSize??20})`)}requestStop(){this.stopped=!0,this.lifecycleBarrier.close(),this.startupAbortController.abort(),this.pool?.stopIdleSweep(),this.stopProviderQuotaTimer(),this.pool?.pauseAllQueues("shutdown")}async stop(e){if(e?.dropPendingEvents&&(this.dropPendingEventsRequested=!0),this.requestStop(),!this.stopPromise){const i=this.stopOnce();this.stopPromise=i,i.catch(()=>{this.stopPromise===i&&(this.stopPromise=null)})}await this.stopPromise,this.dropPendingEventsRequested&&!this.pendingEventsDropped&&await this.dropPendingEventsBestEffort()}async stopOnce(){this.lifecycleBarrier.close(),this.pool?.stopIdleSweep(),this.stopProviderQuotaTimer(),this.pool?.pauseAllQueues("shutdown");const e=this.pool?.collectActiveEventIds()??[],i=new Map(e.map(o=>[o,this.eventSessionIndex.get(o)]));e.length>0&&this.activeEventStore&&await this.activeEventStore.save(e);for(const o of e)h.info(this.name,`Canceling active event on shutdown: ${o}`),this.sendEventResultWithCleanup(o,"canceled","process shutting down");e.length>0&&await new Promise(o=>setTimeout(o,100)),this.pool?.clearActiveEventsForShutdown();for(const o of e){const a=i.get(o),l=a?this.pool?.getSlot(a):void 0;this.auditController.markAdapterClosed(o,l?.adapter.takeAuditBoundary?.(o)??{processTerminated:!0})}const r=this.deferredMgr.getAllDeferredEntries(),n=this.pool?.drainAllQueuedEvents()??[],t=this.pendingEvents.dedupe([...this.pendingEvents.replaySnapshot(),...r.map(o=>({kind:"deferred",channel:o.channel,sessionId:o.sessionId,event:o.event})),...n.map(o=>({kind:"queued",event:o}))]);let s=!1;if(this.dropPendingEventsRequested)try{await this.pendingEvents.clear(),this.pendingEventsDropped=!0}catch(o){h.warn(this.name,`Failed to clear pending event store on removal: ${o instanceof Error?o.message:String(o)}`)}else try{s=await this.pendingEvents.mergeForShutdown(t)}catch(o){h.error(this.name,`Failed to persist pending events on shutdown: ${o instanceof Error?o.message:String(o)}`)}if(!s)for(const o of t){const a=o.event;h.info(this.name,`Failing pending event on shutdown: ${a.event_id}`),this.sendEventResultWithCleanup(a.event_id,"failed","process shutting down"),this.auditController.markAdapterClosed(a.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()}async dropPendingEventsBestEffort(){try{await this.pendingEvents.clear(),this.pendingEventsDropped=!0}catch(e){h.warn(this.name,`Failed to clear pending event store on removal: ${e instanceof Error?e.message:String(e)}`)}}resolveSpawnEnv(){const e=this.providerResolver?this.providerResolver():this.config.agent.provider,i=se(this.config.agent.clientType,e),r=this.config.agent.env;let n=Object.keys(i).length>0?{...i,...r}:r;if(oe(i)){const t=te()?.getRuntimeInfo(),s={...r??{},...i},o=re(s,{proxyUrl:t?.proxyUrl,caCertPath:t?.caCertPath,caBundlePath:t?.caBundlePath});return delete o.ANTHROPIC_API_KEY,delete o.CLAUDE_CODE_OAUTH_TOKEN,o}if(ie(this.config.agent.clientType)){const t=ne(this.name);t&&(n={...n??{},...t})}return ee(n,this.name,this.config.agent.clientType)}createAdapter(e,i){switch(e){case"claude":return this.createClaudeAdapter(i);case"codex":return this.createCodexAdapter(i);case"pi":return this.createPiAdapter(i);case"openhuman":return this.createOpenHumanAdapter(i);case"codewhale":return this.createCodeWhaleAdapter(i);case"cursor":return this.createCursorAdapter(i);case"opencode":return this.createOpenCodeAdapter(i);case"agy":return this.createAgyAdapter(i);case"deepseek-harness":return this.createDshAdapter(i);default:return this.createAcpAdapter(i)}}createDshAdapter(e){const i={sendStreamChunk:(t,s,o,a,l,d,c)=>{this.sendStreamChunkByRuntimeConfig(t,s,o,a,l,d,c)},sendFinalStreamChunkReliable:this.reliableFinalWiring("deepseek-harness",Ai),sendThinking:(t,s,o)=>this.sendThinkingByRuntimeConfig(t,s,o),sendEventResult:(t,s,o,a)=>{this.sendEventResultWithCleanup(t,s,o,void 0,a)},sendRawEventEnvelope:(t,s,o,a)=>{const l=oi(o);if(l){this.sendToolExecutionCard(t,s,l);return}this.deliverRawEventEnvelope(t,s,o,"deepseek",a)},sendLocalActionResult:(t,s,o,a,l)=>{this.aibotHandle.sendLocalActionResult({action_id:t,status:s,...o!==void 0?{result:o}:{},...a?{error_code:a}:{},...l?{error_msg:l}:{}},e)},sendPermissionCard:t=>{this.sendGrixApprovalCard(t,"deepseek")},sendUpdateBindingCard:(t,s,o,a)=>{this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:s,cwd:o,meta:a})},getAgentProfile:()=>({...this.agentProfile,systemPrompt:this.agentSystemPrompt}),getAgentId:()=>this.config.aibot.agentId,queryProviderQuota:t=>this.maybeQueryProviderQuota(t===!0,{providerId:"deepseek"}),agentInvoke:async(t,s,o)=>this.platformInvoke(t,s,o),eventToolInvoke:async(t,s)=>this.invokeDshEventTool(t,s)},r=M("sha256").update(this.config.aibot.agentId).digest("hex").slice(0,24),n=this.config.adapterOptions??{};return new z({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:n},i,{aibotSessionId:e,bindingStore:this.bindingStore,globalConfigStore:this.globalConfigStore,agentName:this.name,dataRoot:y.join(w.data,"deepseek-harness",r),...typeof n.cordisPath=="string"?{cordisPath:n.cordisPath}:{},...typeof n.defaultModel=="string"?{defaultModel:n.defaultModel}:{},...typeof n.maxTokens=="number"?{maxTokens:n.maxTokens}:{},...typeof n.maxLineBytes=="number"?{maxLineBytes:n.maxLineBytes}:{},...n.integrationMode==="embedded_jsonrpc"||n.integrationMode==="profile_bridge"?{integrationMode:n.integrationMode}:{},...typeof n.dshHome=="string"?{dshHome:n.dshHome}:{},...typeof n.dshProfile=="string"?{dshProfile:n.dshProfile}:{},...typeof n.autoInstallBridge=="boolean"?{autoInstallBridge:n.autoInstallBridge}:{},...typeof n.autoStartProfile=="boolean"?{autoStartProfile:n.autoStartProfile}:{},...this.config.agent.provider?{provider:this.config.agent.provider}:{},promptTimeoutMs:this.config.promptTimeoutMs})}createCursorAdapter(e){const i={...this.config.adapterOptions??{}};i.bindingStore=this.bindingStore,i.aibotSessionId=e;const r=this.bindingStore.get(e),n=this.resolveSessionModelId(e);n&&(i.model=n);const t=this.resolveCursorSessionModeId(e),s=t??"full_auto";t||this.bindingStore.setCursorModeId(e,s),i.mode=s,r?.cwd&&(i.workspace=r.cwd);const o={sendStreamChunk:(a,l,d,c,u,g,p)=>{this.sendStreamChunkByRuntimeConfig(a,l,d,c,u,g,p)},sendEventResult:(a,l,d)=>{this.sendEventResultWithCleanup(a,l,d)},sendEventAck:(a,l)=>{this.aibotHandle.sendEventAck({event_id:a,session_id:l,received_at:Date.now()})},sendRawEventEnvelope:(a,l,d)=>{this.deliverRawEventEnvelope(a,l,d,"cursor",this.buildCursorRawEventFallbackText(d))},sendAgentQuestionCard:(a,l,d)=>{const c=d.questions.map(g=>g.header).join(", "),u=I(`[Agent Question] ${d.request_id}`,"agent_question",d);this.aibotHandle.sendText({event_id:a,session_id:l,content:u,msg_type:1,extra:{card_type:"agent_question",summary_text:c}})},agentInvoke:async(a,l,d)=>this.platformInvoke(a,l,d),sendLocalActionResult:(a,l,d,c,u)=>{this.aibotHandle.sendLocalActionResult({action_id:a,status:l,...d!==void 0?{result:d}:{},...c?{error_code:c}:{},...u?{error_msg:u}:{}},e)},sendUpdateBindingCard:(a,l,d,c)=>{this.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:l,cwd:d,...c?{meta:c}:{}})},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId};return new j({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:i},o)}createClaudeAdapter(e){const i={sendReply:(t,s,o,a,l)=>{this.sendReplyByRuntimeConfig(t,s,o,a,l)},sendStreamChunk:(t,s,o,a,l,d,c)=>{this.sendStreamChunkByRuntimeConfig(t,s,o,a,l,d,c)},sendMedia:(t,s,o,a,l,d,c)=>{this.aibotHandle.sendMedia({event_id:t,session_id:s,content:o,msg_type:2,quoted_message_id:l||void 0,client_msg_id:d||void 0,extra:c?{media_caption:a,...c}:{media_caption:a}})},sendEventResult:(t,s,o,a)=>{this.sendEventResultWithCleanup(t,s,o,a)},sendEventAck:(t,s)=>{this.aibotHandle.sendEventAck({event_id:t,session_id:s,received_at:Date.now()})},agentInvoke:async(t,s,o)=>this.platformInvoke(t,s,o),sendLocalActionResult:(t,s,o,a,l)=>{this.aibotHandle.sendLocalActionResult({action_id:t,status:s,...o!==void 0?{result:o}:{},...a?{error_code:a}:{},...l?{error_msg:l}:{}},e)},sendToolUse:(t,s,o,a)=>{this.sendToolExecutionCard(t,s,C(o,a))},sendToolResult:(t,s,o,a)=>{this.sendToolExecutionCard(t,s,b(o,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:(t,s,o)=>{this.sendGrixAgentQuestionCard(t,s,o)},sendPermissionCard:t=>{this.sendGrixApprovalCard(t,"claude")},sendDirectMessage:t=>{this.aibotHandle.sendMsg({session_id:t.sessionId,msg_type:1,content:t.content,...t.clientMsgId?{client_msg_id:t.clientMsgId}:{},...t.quotedMessageId?{quoted_message_id:t.quotedMessageId}:{}})},onStatusLineUpdated:t=>{(t.rateLimits?.fiveHour||t.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=t);const s=this.bindingStore.get(e);s?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:this.claudeWorkerStatus.get(e)??"ready",cwd:s.cwd,meta:this.buildClaudeToolbarMeta(e)})},sendMcpFrame:t=>{this.aibotHandle.sendMcpFrame(e,t)}},r=this.config.adapterOptions??{},n={...r,sessionRuntimeResolver:()=>{const t=this.bindingStore.get(e),s=this.auditController.getSession(e);return{cwd:t?.cwd,modeId:this.resolveClaudeSessionModeId(e)??J.fullAuto,modelId:this.resolveSessionModelId(e),effort:this.resolveClaudeSessionEffort(e),pluginDir:r.pluginDir,claudeSessionId:t?.claudeSessionId,...s?{audit:{enabled:!0,profile:s.options.profile,capture:s.options.capture}}:{},onSessionIdAssigned:o=>{this.bindingStore.setClaudeSessionId(e,o),this.sessionScanCache.invalidate()}}}};return new L({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:n},i)}createCodexAdapter(e){let i=null;const r={sendEventResult:(o,a,l)=>{if(a!=="responded"){this.sendEventResultWithCleanup(o,a,l);return}this.sendCtrl.sendFinalStreamChunkReliable(o,e,`codex_terminal_fence_${o}`,5e3,!0,!0).then(()=>this.sendEventResultWithCleanup(o,a,l),d=>{const c=`codex output acceptance fence failed: ${d instanceof Error?d.message:String(d)}`;this.sendEventResultWithCleanup(o,a==="responded"?"failed":a,a==="responded"?c:l)})},sendEventAck:(o,a)=>this.aibotHandle.sendEventAck({event_id:o,session_id:a,received_at:Date.now()}),sendCodexEvent:o=>{this.shouldDropCodexDisplayEvent(o.event_id,o.codex_method)||(this.captureCodexAuditOutput(o),this.aibotHandle.sendCodexEvent(this.stampCodexEventQuote(o)),this.logCodexEventToConversation(o))},sendThinking:(o,a,l)=>{this.sendThinkingByRuntimeConfig(o,a,l)},sendRunError:(o,a,l)=>{this.sendRunErrorAsChunk(o,a,l)},sendUpdateBindingCard:(o,a,l,d)=>{const c={...d??{}};if(!c.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const u=this.providerQuotaToCodexRateLimits(this.cachedProviderQuota);u&&(c.rate_limits=u.rateLimits,c.rate_limit_primary_percent=u.primaryPercent,c.rate_limit_secondary_percent=u.secondaryPercent,c.rate_limit_primary_window_min=u.primaryWindowMin,c.rate_limit_secondary_window_min=u.secondaryWindowMin)}!c.provider_quota&&this.cachedProviderQuota?.success&&(c.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:a,cwd:l,...Object.keys(c).length>0?{meta:c}:{}})},agentInvoke:async(o,a,l)=>this.platformInvoke(o,a,l),sendLocalActionResult:(o,a,l,d,c)=>this.aibotHandle.sendLocalActionResult({action_id:o,status:a,...l!==void 0?{result:l}:{},...d?{error_code:d}:{},...c?{error_msg:c}:{}},e),sendSessionActivitySet:(o,a,l,d)=>{this.aibotHandle.sendSessionActivitySet({session_id:o,kind:a,active:l,...d??{}})},getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId,onRateLimitsUpdated:o=>{this.cachedRateLimits=o,this.cachedRateLimitsSampledAtMs=Date.now(),this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const a=this.bindingStore.get(e);if(a?.cwd){const l=this.cachedRateLimitsSampledAtMs,d={rate_limits:{...o.primary.windowMinutes>0?{primary:o.primary}:{},...o.secondary.windowMinutes>0?{secondary:o.secondary}:{},sampledAt:l},rate_limit_primary_percent:o.primary.usedPercent,rate_limit_secondary_percent:o.secondary.usedPercent,rate_limit_primary_window_min:o.primary.windowMinutes,rate_limit_secondary_window_min:o.secondary.windowMinutes,credits:o.credits,...o.extras&&o.extras.length>0?{extra_limits:o.extras}:{},...i?.getEffortMeta()};this.cachedProviderQuota?.success&&(d.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:d})}},onContextWindowUpdated:o=>{if(!o)return;this.cachedCodexContextWindow=o,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:o,...i?.getEffortMeta()}})},onTokenUsageUpdated:o=>{o&&(this.cachedCodexTokenUsage=o,this.cachedCodexUsageSampledAtMs=Date.now())}},n=this.config.adapterOptions??{},t=this.globalConfigStore?.get(this.name),s=this.auditController.getAdapterPreparation(e);return i=new D({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...n,model:this.resolveCodexSessionModelId(e)??n.model,collaborationMode:this.bindingStore.getCodexModeId(e)??this.resolveCodexNewSessionGlobalDefault(e,t?.codexModeId,o=>this.bindingStore.setCodexModeId(e,o))??n.collaborationMode,reasoningEffort:this.bindingStore.getCodexReasoningEffort(e)??this.pinCodexGlobalDefault(t?.codexReasoningEffort,o=>this.bindingStore.setCodexReasoningEffort(e,o))??n.reasoningEffort,serviceTier:this.bindingStore.getCodexServiceTier(e)??this.resolveCodexNewSessionGlobalDefault(e,t?.codexServiceTier,o=>this.bindingStore.setCodexServiceTier(e,o))??n.serviceTier,sandboxMode:this.bindingStore.getCodexSandboxMode(e)??this.pinCodexGlobalDefault(t?.codexSandboxMode,o=>this.bindingStore.setCodexSandboxMode(e,o))??n.sandboxMode,aibotSessionId:e,bindingStore:this.bindingStore,...Q(s?.options)?{rawApiCapture:{auditId:s.auditId,sessionId:e,spoolRootDir:y.join(w.data,"audit-replay","raw-spool")}}:{}}},r),i}createCodeWhaleAdapter(e){const i={sendEventResult:(n,t,s)=>{this.sendEventResultWithCleanup(n,t,s)},sendEventAck:(n,t)=>this.aibotHandle.sendEventAck({event_id:n,session_id:t,received_at:Date.now()}),sendStreamChunk:(n,t,s,o,a,l)=>{this.sendStreamChunkByRuntimeConfig(n,t,s,o,a,l)},sendUpdateBindingCard:(n,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,n,s)}),sendLocalActionResult:(n,t,s,o,a)=>this.aibotHandle.sendLocalActionResult({action_id:n,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e),sendSessionActivitySet:(n,t,s,o)=>{this.aibotHandle.sendSessionActivitySet({session_id:n,kind:t,active:s,...o??{}})},sendToolUse:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,C(s,o))},sendToolResult:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,b(s,o))},agentInvoke:async(n,t,s)=>this.platformInvoke(n,t,s),getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=this.config.adapterOptions??{};return new K({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...r,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,model:this.resolveSessionModelId(e)??r.model,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},i)}createPiAdapter(e){const i={sendEventResult:(n,t,s)=>{this.sendEventResultWithCleanup(n,t,s),h.info("bridge",`[pi] sendEventResult event=${n} status=${t}`)},sendEventAck:(n,t)=>this.aibotHandle.sendEventAck({event_id:n,session_id:t,received_at:Date.now()}),sendUpdateBindingCard:(n,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,n,s)}),agentInvoke:async(n,t,s)=>this.platformInvoke(n,t,s),sendLocalActionResult:(n,t,s,o,a)=>{this.aibotHandle.sendLocalActionResult({action_id:n,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e)},sendSessionActivitySet:(n,t,s,o)=>{this.aibotHandle.sendSessionActivitySet({session_id:n,kind:t,active:s,...o??{}})},sendToolUse:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,C(s,o))},sendToolResult:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,b(s,o))},sendStreamChunk:(n,t,s,o,a,l)=>{this.sendStreamChunkByRuntimeConfig(n,t,s,o,a,l),a&&h.info("bridge",`[pi] sendFinalStreamChunk event=${n} seq=${o}`)},sendFinalStreamChunkReliable:this.reliableFinalWiring("pi"),sendThinking:(n,t,s)=>{this.sendThinkingByRuntimeConfig(n,t,s)},sendRunError:(n,t,s,o,a)=>{this.sendStreamChunkByRuntimeConfig(n,t,`
1
+ import y from"node:path";import{tmpdir as U}from"node:os";import{createHash as M,randomUUID as R}from"node:crypto";import{ConnectionManager as q}from"../core/aibot/index.js";import{AUDIT_LOCAL_ACTION_TYPES as N}from"../core/aibot/types.js";import{ClaudeAdapter as L}from"../adapter/claude/index.js";import{CodexAdapter as D}from"../adapter/codex/index.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"../adapter/deepseek-harness/session-history.js";import{PiAdapter as W}from"../adapter/pi/index.js";import{AcpAdapter as S}from"../adapter/acp/index.js";import{OpenHumanAdapter as G}from"../adapter/openhuman/index.js";import{CursorAdapter as j}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as K}from"../adapter/codewhale/index.js";import{OpenCodeAdapter as k}from"../adapter/opencode/index.js";import{AgyAdapter as H}from"../adapter/agy/index.js";import{DshJsonRpcAdapter as z}from"../adapter/deepseek-harness/index.js";import{LOCAL_ACTION_TYPES as f,SESSION_CONTROL_ERROR_CODES as $,SESSION_CONTROL_VERBS as E,SESSION_MODE_IDS as J}from"../adapter/claude/protocol-contract.js";import{isAuditLocalActionType as Y}from"../audit/query/audit-local-actions.js";import{shouldEnableRawApiCapture as Q}from"../audit/raw-capture/types.js";import{buildWireSkills as X}from"../core/skill-sync/sync-state.js";import{executeEventTool as V}from"../core/mcp/event-tool-executor.js";import{fetchAvailableModels as Z}from"../adapter/claude/model-list.js";import{applyProxyEnv as ee,getProxyManager as te}from"../core/proxy/index.js";import{getKiroRelaySpawnEnv as ne}from"../core/proxy/kiro-relay.js";import{supportsKiroCwRelay as ie}from"../core/config/provider-env.js";import{buildProviderEnv as se}from"../core/config/provider-env.js";import{isClaudeDirectEnv as oe,stripGrixRelayEnv as re}from"../core/config/claude-direct-env.js";import{sweepNativeProviderResidue as ae}from"./native-provider-sweep.js";import{scanCodexSessions as de}from"../adapter/codex/session-scanner.js";import{scanClaudeSessions as le}from"../adapter/claude/session-scanner.js";import{resolveAcpAgentTypes as ce,scanAcpSessions as he,scanReasonixSessionTitles as ue}from"../adapter/acp/session-scanner.js";import{scanPiSessions as pe}from"../adapter/pi/session-scanner.js";import{scanCodeWhaleSessions as ge}from"../adapter/codewhale/session-scanner.js";import{scanCursorSessions as fe}from"../adapter/cursor/session-scanner.js";import{scanOpenCodeSessions as me}from"../adapter/opencode/session-scanner.js";import{scanDshSessions as ve}from"../adapter/deepseek-harness/session-scanner.js";import{SessionScanCache as v,resolveCodexLeafDirs as _e,resolveClaudeLeafDirs as Se,resolveAcpLeafDirs as Ce,resolvePiLeafDirs as be,resolveCodeWhaleLeafDirs as Ae,resolveCursorLeafDirs as Ee,resolveOpenCodeLeafDirs as we,resolveDshLeafDirs as ye,resolveReasonixLeafDirs as Re}from"./session-scan-cache.js";import{log as h,ConversationLog as ke,AgentApiPacketLog as Te,BridgeEventLog as Pe,GRIX_PATHS as w}from"../core/log/index.js";import{routeSessionControlCommand as xe,routeSessionControlLocalAction as Me}from"./session-control-router.js";import{maybeOfferCliInstall as Le,handleCliInstallQuestionReply as De,handleCliInstallInteractionReply as He,runConfirmedCliInstall as $e}from"./cli-install-flow.js";import{handleEventCancel as Qe,waitForEventDone as Ie,handleAibotStop as Oe,killAndResumeStopSlot as Be,handleAibotRevoke as Fe}from"./event-stop.js";import{handleConfigureGatewayProvider as Ue,getAuditLocalActionHandler as qe,handleAuditLocalAction as Ne,handleConnectorRollback as We,getRelayStateSyncer as Ge,relayStateSyncOnConnect as je,reportRelayStateLocalChange as Ke,handleApplyRelayState as ze,fetchRelayCredential as Je,isSharedInstance as Ye}from"./connector-ops.js";import{unbindSession as Xe,handleUnbindTextCommand as Ve,handleUnbindLocalAction as Ze,handleListSessionsTextCommand as et,handleListSessionsLocalAction as tt,handleSyncHistoryLocalAction as nt}from"./session-list.js";import{handleCodexSessionControlOpen as it,handleSessionControlForPool as st,handleSessionControlLocalActionForPool as ot,handleCodexSessionControlLocalActionOpen as rt,handleCursorSessionControlLocalActionOpen as at,handlePiSessionControlOpen as dt,handlePiSessionControlRestart as lt,handlePiSessionControlRestartLocalAction as ct,syncOpenCodeBinding as ht,isWorkspaceFreeClient as ut,ensureDefaultBindingForWorkspaceFreeClient as pt,bindSessionForPool as gt,deferredCallbacks as ft,handleOpenHumanSessionControlOpen as mt,handleCodeWhaleSessionControlOpen as vt,handleCodeWhaleSessionControlLocalActionOpen as _t,handleDeepSeekSessionControlLocalActionOpen as St}from"./session-control-open.js";import{handleGetSessionUsage as Ct,handleThreadCompact as bt}from"./session-usage.js";import{handleSkillDeleteLocalAction as At,handleSkillUploadLocalAction as Et,handleSkillEnableLocalAction as wt,handleSkillRefreshLocalAction as yt,handleSkillDisableLocalAction as Rt,computeSkillReport as kt,reportSessionSkills as Tt,skillsSyncGroupKey as Pt,forceRefreshSkills as xt,adoptSkillsWireHashFromDisk as Mt,buildLibrarySkillsReport as Lt,skillLookupEnv as Dt}from"./skill-actions.js";import{normalizeClaudeModeId as Ht,handleExecCommandOptions as $t,resolveSessionModelId as Qt,resolveSessionModeId as It,resolveCursorSessionModeId as Ot,resolveClaudeSessionEffort as Bt,resolveClaudeSessionModeId as Ft,currentClaudeModeId as Ut,resolveCodexSessionModelId as qt,resolveCodexNewSessionGlobalDefault as Nt,pinCodexGlobalDefault as Wt,buildCursorToolbarMeta as Gt,buildAgyToolbarMeta as jt,buildAgyQuotaMeta as Kt,sendAgyBindingCard as zt,refreshAndPushAgyQuota as Jt,handleAgySetModel as Yt,buildClaudeToolbarMeta as Xt}from"./toolbar-meta.js";import{resolveProviderQuotaSource as Vt,maybeQueryProviderQuota as Zt,startProviderQuotaTimer as en,stopProviderQuotaTimer as tn,refreshAndPushProviderQuota as nn,pushProviderQuotaToBindings as sn,enrichProviderQuotaMeta as on,providerQuotaMetaPayload as rn,refreshProviderQuotaForSession as an,refreshQuotaAfterModelSwitch as dn,doRefreshQuotaAfterModelSwitch as ln}from"./provider-quota.js";import{handleGetRateLimits as cn,resolveRateLimitWakeSessionId as hn,wakeRateLimitSlot as un}from"./rate-limits.js";import{RevokeHandler as pn}from"./revoke-handler.js";import{AdapterPool as gn}from"./adapter-pool.js";import{parseSessionControlCommand as fn}from"./session-controller.js";import{isOpenSessionDirectiveMessage as mn,parseExecApprovalResolutionMessage as vn,parseAgentQuestionReplyMessage as _n}from"../core/protocol/interaction-parser.js";import{rejectUnusableAuditOptions as Sn}from"./inbound-audit-gate.js";import{interceptUnboundInboundEvent as Cn}from"./inbound-binding-gate.js";import{dispatchSessionControlTextCommand as bn}from"./text-command-session-control.js";import{dispatchSessionControlLocalAction as An}from"./local-action-session-control.js";import{handleCreateFolderLocalAction as En,handleFileListLocalAction as wn}from"./local-action-files.js";import{handleAcpToolbarLocalAction as yn,persistToolbarSelection as Rn}from"./local-action-toolbar.js";import{buildOpenedBindingResult as kn,ensureImportedAgentSession as Tn,hasDiskScanner as Pn,normalizePathForCompare as xn,providerKeyForAdapter as Mn,resolveAgentSessionId as Ln,resolveOrphanTitle as Dn,setResolvedAgentSessionId as Hn}from"./session-identity.js";import{buildDshOpenedToolbarMeta as $n,dshCatalogDataRoot as Qn}from"./dsh-toolbar.js";import{ensureSlotStarted as In,failSessionOpen as On,getClaudeWorkerStatus as Bn,refreshClaudeWorkerStatusCard as Fn,resolveCwdForBinding as Un}from"./session-open-helpers.js";import{handleAcpSetModel as qn,handleAcpSetMode as Nn,resolveAcpInitialDefaults as Wn}from"./acp-toolbar-persist.js";import{SessionBindingStore as Gn}from"../core/persistence/session-binding-store.js";import{serveLocalFile as jn}from"../core/files/index.js";import{uploadReplyFileToAgentMedia as Kn}from"../core/protocol/agent-api-media.js";import{ActiveEventStore as zn}from"../core/persistence/active-event-store.js";import{PendingEventCoordinator as Jn}from"./pending-event-coordinator.js";import{LifecycleBarrier as Yn}from"./lifecycle-barrier.js";import{QUEUE_COMPOSING_TTL_MS as Xn}from"./event-queue.js";import{DEFAULT_CONNECTOR_RUNTIME_CONFIG as Vn,applyConnectorRuntimeConfigPatch as Zn,extractConnectorRuntimeConfigPatch as ei}from"./runtime-config.js";import{DEFAULT_QUOTE_TRIGGER_BY_ADAPTER as ti,SendController as ni}from"./send-controller.js";import{providerQuotaToRateLimits as ii,providerQuotaToCodexRateLimits as si}from"../core/provider-quota/index.js";import{buildToolUseCard as C,buildToolResultCard as b,buildDshOnlineToolCard as oi,buildLocalGrixCardLink as I}from"./tool-card-utils.js";import{planRawEventDelivery as ri,buildAuxiliaryDetailText as ai}from"./raw-event-delivery.js";import{DeferredEventManager as di}from"./deferred-events.js";import{buildAgentProbeResult as li,PROBE_CACHE_TTL_STATIC_MS as ci,PROBE_CACHE_TTL_FULL_MS as hi}from"./probe-helper.js";import{BridgeAuditController as ui}from"../audit/integration/bridge-audit-controller.js";import{isSettlableAuditProducer as pi,NoopAuditProducer as gi}from"../audit/producer/audit-producer.js";import{buildAuditStatePayload as O,AuditPreparationFailedError as fi,AuditTurnScopeUnsupportedError as mi}from"../audit/core/audit-state.js";import{extractAuditOptions as B,freezeAuditOptions as vi,stripAuditOptions as _i}from"../audit/core/audit-options.js";import{AuditSessionOptionsError as Si}from"../audit/core/audit-session-registry.js";const Ci=600*1e3,F=1800*1e3,bi=60*1e3,Ai=4e3;function Ei(x,e,n){const r=M("sha256").update(x).update("\0").update(e).update("\0").update(n).digest("hex");return y.join(w.data,"audit-source","reasonix",`${r}.jsonl`)}const T=new Set(["claude","acp","agy","cursor","codex","deepseek-harness"]),wi=new Set(["claude","codex","cursor","codewhale","opencode","pi","openhuman","agy","acp","deepseek-harness"]),P=3;class oo{config;name;aibotHandle;aibotConfig;pool;stopped=!1;startupAbortController=new AbortController;stopPromise=null;dropPendingEventsRequested=!1;pendingEventsDropped=!1;revokeHandler=new pn;sessionBindings=new Map;deferredMgr;sendCtrl=new ni(Vn);bindingStore;globalConfigStore;upgradeTrigger=null;daemonShutdownRequester=null;lifecycleBusyChecker=null;lifecycleAdmissionCloser=null;lifecycleAdmissionRestorer=null;installAgentHandler=null;pendingCliInstalls=new Map;agentDeletedHandler=null;shareSetHandler=null;skillSyncHandler=null;providerConfigHandler=null;relayStateApplyPorts=null;relayStateSyncer=null;agentProfile={agentName:"",introduction:""};agentSystemPrompt="";activeEventStore;pendingEvents;pendingStartedEventIds=new Set;lifecycleBarrier=new Yn;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 n=Number(e);return n>0&&Date.now()-n<=bi}resolveProviderQuotaSource(e){return Vt(this,e)}maybeQueryProviderQuota(e=!1,n){return Zt(this,e,n)}startProviderQuotaTimer(){en(this)}stopProviderQuotaTimer(){tn(this)}refreshAndPushProviderQuota(e=!1){return nn(this,e)}pushProviderQuotaToBindings(e,n=!1){sn(this,e,n)}enrichProviderQuotaMeta(e,n="standard",r=this.cachedProviderQuota,i=this.cachedProviderQuotaSampledAtMs){return on(this,e,n,r,i)}providerQuotaMetaPayload(e,n,r){return rn(this,e,n,r)}refreshProviderQuotaForSession(e,n,r){return an(this,e,n,r)}refreshQuotaAfterModelSwitch(e,n,r){dn(this,e,n,r)}doRefreshQuotaAfterModelSwitch(e,n,r){return ln(this,e,n,r)}getFreshClaudeRateLimitState(){const e=this.cachedClaudeRateLimitState;return e&&this.isRateLimitsCacheFresh(e.sampledAt)?e:null}getFreshCodexGlobalRateLimitCache(){const e=this.cachedRateLimits,n=this.cachedCodexContextWindow,r=this.cachedCodexTokenUsage;return{sampledAt:Math.max(this.cachedRateLimitsSampledAtMs??0,this.cachedCodexUsageSampledAtMs??0)||null,rateLimits:e,contextWindow:n,tokenUsage:r,hasData:!!(e||n||r)}}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,wsConnected:this.aibotHandle?.status==="ready",exhausted:this.pool?[...this.pool.getAllSlots()].some(n=>n.respawn.exhausted):!1,adapterType:this.config.adapterType??"acp",clientType:this.config.aibot.clientType,pool:e}}hasPendingWork(){return this.pool?.hasPendingWork()??!1}hasPendingOrBackgroundWork(){return this.lifecycleBarrier.hasActiveAdmissions()||(this.pool?.hasPendingOrBackgroundWork()??!1)}async waitUntilLifecycleIdle(e){const n=()=>this.lifecycleBusyChecker?.()??this.hasPendingOrBackgroundWork();if(n()){const r=Math.round(F/6e4);h.info(this.name,`${e}: active tasks detected, waiting up to ${r}min until idle before restart (admission stays open while waiting)`);const i=Date.now()+F,t=5e3,s=600*1e3;let o=Date.now();for(;n()&&!this.stopped;){if(Date.now()>=i)return h.warn(this.name,`${e}: idle wait exceeded ${r}min; abandoning this restart. Admission was never closed, so agents kept serving. A busy state that never clears usually means an adapter leaked its busy flag \u2014 check for a turn that never completed.`),!1;await new Promise(a=>setTimeout(a,t)),Date.now()-o>=s&&(o=Date.now(),h.info(this.name,`${e}: still waiting for active tasks to finish before restart`))}}return this.stopped?!1:(this.closeLifecycleAdmissionForRestart(),n()?(h.warn(this.name,`${e}: work arrived while closing admission; reopening and abandoning this restart`),this.reopenLifecycleAdmissionAfterAbort(),!1):(h.info(this.name,`${e}: all tasks completed, proceeding with restart`),!0))}reopenLifecycleAdmissionAfterAbort(){if(this.lifecycleAdmissionRestorer){this.lifecycleAdmissionRestorer();return}this.openLifecycleAdmission()}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 n=0,r=!1;for(const i 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 t=!1;await this.pool.removeSlot(i.sessionId).catch(s=>{r=!0,t=!0,h.warn(this.name,`failed to recycle adapter slot ${i.sessionId} after relay change: ${s}`)}),t||(n+=1)}return n>0&&h.info(this.name,`recycled ${n} adapter slot(s) so the new Grix relay env takes effect`),r?(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 n=e.conversation?"full":"static",r=e.conversation?hi:ci;if(!e.fresh){const a=this.probeCache.get(n);if(a&&Date.now()-a.sampledAt<r)return{...a.result,cached:!0}}const i=this.config.adapterType??"acp",t=this.createAdapter(i,"__probe__"),s=e.conversation&&i==="acp"?()=>this.runAcpConversationProbe(t,e.timeoutMs??1e4):void 0;let o;try{o=await li({adapter:t,agentName:this.name,clientType:this.config.aibot.clientType,adapterType:i,providerBaseUrl:this.config.providerBaseUrl??null,opts:e,launchConversationProbe:s})}finally{t.stop().catch(()=>{})}return this.probeCache.set(n,{result:o,sampledAt:o.probed_at}),o}async runAcpConversationProbe(e,n){const r=Date.now(),i="__probe__",t=`probe-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,s=this.config.agent.cwd||U(),o=()=>Date.now()-r;try{await e.start()}catch(u){return{attempted:!0,ok:!1,latency_ms:o(),error:{code:"conversation_failed",message:`start failed: ${u instanceof Error?u.message:String(u)}`}}}if(!e.isAlive())return{attempted:!0,ok:!1,latency_ms:o(),error:{code:"process_not_started",message:"agent process not alive"}};if(e instanceof S)try{await e.bindSession(i,s)}catch{}let a=null;const c=new Promise(u=>{a=g=>{g===t&&u()},e.on("eventDone",a)});e.deliverInboundEvent({event_id:t,session_id:i,content:"ping",msg_id:t}),e.deliverStopEvent(t,i);let d=null;const l=await Promise.race([c.then(()=>!1),new Promise(u=>{d=setTimeout(()=>u(!0),n)})]);return d&&clearTimeout(d),a&&e.removeListener("eventDone",a),l?{attempted:!0,ok:!1,latency_ms:o(),error:{code:"conversation_timeout",message:`no eventDone within ${n}ms`}}:{attempted:!0,ok:!0,latency_ms:o()}}constructor(e,n,r=new gi){this.config=e,this.auditController=new ui(r,{onAuditState:t=>{try{this.aibotHandle.sendAuditState(O(t,Date.now()))}catch{}}}),pi(r)&&r.addJobSettledHandler((t,s)=>{this.auditController.handleJobSettled(t,s)}),this.name=e.name;const i=e.adapterType??"acp";if(this.sendCtrl.setDefaultQuoteTrigger(ti[i]),this.aibotConfig={...e.aibot,...i==="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",...N]}:{}},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 ke(e.logDir):null,this.packetLog=e.logDir?new Te(e.logDir):null,this.bindingStore=new Gn(e.bindingsPath,e.legacyBindingsPath),this.bindingStore.load(),this.globalConfigStore=n??null,this.deferredMgr=new di(this.name),this.activeEventStore=e.activeEventStorePath?new zn(e.activeEventStorePath):null,this.pendingEvents=new Jn(e.pendingEventStorePath),i==="codex")this.sessionScanCache=new v(de,_e);else if(i==="claude")this.sessionScanCache=new v(le,Se);else if(i==="pi"){const t=e.agent.env?.PI_CODING_AGENT_DIR;this.sessionScanCache=new v(()=>pe(void 0,t),()=>be(void 0,t))}else if(i==="codewhale")this.sessionScanCache=new v(ge,Ae);else if(i==="cursor")this.sessionScanCache=new v(fe,Ee);else if(i==="opencode")this.sessionScanCache=new v(me,we);else if(i==="deepseek-harness"){const t=typeof e.adapterOptions?.dshHome=="string"?e.adapterOptions.dshHome:e.agent.env?.DSH_HOME;this.sessionScanCache=new v(()=>ve(t),()=>ye(t))}else if(i==="agy")this.sessionScanCache=new v(()=>[],()=>[]);else{e.aibot.clientType?.trim().toLowerCase()==="reasonix"&&(this.reasonixTitleScan=new v(ue,Re));const t=ce(e.aibot.clientType);this.sessionScanCache=t?new v(()=>he(void 0,t),()=>Ce(void 0,t)):new v(()=>[],()=>[])}}async start(){if(this.stopped)throw new Error("agent start aborted");if(await ae({agentName:this.name,adapterType:this.config.adapterType??"acp",command:this.config.agent.command,piConfigDir:this.config.agent.env?.PI_CODING_AGENT_DIR,dshHome:typeof this.config.adapterOptions?.dshHome=="string"?this.config.adapterOptions.dshHome:this.config.agent.env?.DSH_HOME,hasProvider:!!this.config.agent.provider,boundCwds:[...this.bindingStore.entries()].map(([,t])=>String(t.cwd??""))}).then(t=>{t.length>0&&h.info(this.name,`restored native provider config after relay disable: ${t.join(", ")}`)}).catch(t=>{h.warn(this.name,`native provider residue sweep failed: ${t instanceof Error?t.message:String(t)}`)}),this.stopped)throw new Error("agent start aborted");if((this.config.adapterType??"acp")==="claude"){if(await Z().catch(()=>{}),this.stopped)throw new Error("agent start aborted");this.maybeQueryProviderQuota().catch(()=>{})}if(this.stopped)throw new Error("agent start aborted");const e=!!(this.config.providerBaseUrl&&this.config.providerApiKey||this.config.agent.provider?.baseUrl&&this.config.agent.provider?.apiKey),n=(this.config.adapterType??"acp")==="pi",r=(this.config.adapterType??"acp")==="opencode";if(this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi"||e?(this.maybeQueryProviderQuota().catch(()=>{}),this.startProviderQuotaTimer()):(n||r)&&this.startProviderQuotaTimer(),(this.config.adapterType??"acp")==="codex"&&this.maybeQueryProviderQuota().catch(()=>{}),(this.config.adapterType??"acp")==="opencode"&&this.maybeQueryProviderQuota().catch(()=>{}),this.stopped)throw new Error("agent start aborted");if(await this.connectAibot(),this.stopped)throw this.aibotHandle?.disconnect(),new Error("agent start aborted");this.sendCtrl.bind(this.aibotHandle);const i=this.config.adapterType??"acp";if(this.pool=new gn({maxPoolSize:this.config.poolMaxSize??20,idleTimeoutMs:this.config.poolIdleTimeoutMs??18e5,eventQueue:this.config.eventQueue},t=>{const s=this.createAdapter(i,t);return s instanceof S&&s.on("acpSessionReady",o=>{this.bindingStore.setAcpSessionId(t,o),this.sessionScanCache.invalidate()}),s},(t,s)=>{this.aibotHandle.sendEventAck({event_id:t,session_id:s,received_at:Date.now()})}),this.pool.setEventStateHandler((t,s,o,a)=>{if(h.info(this.name,`[queue-debug] send event_state session=${s} event=${t} state=${o} queue_pos=${a?.queue_position??""} queue_total=${a?.queue_total??""}`),this.aibotHandle.sendEventState({event_id:t,session_id:s,state:o,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(s),o==="running"&&(this.pendingStartedEventIds.add(t),this.pendingEvents.remove(t).catch(c=>{h.warn(this.name,`Failed to remove running event from pending store event=${t}: ${c instanceof Error?c.message:String(c)}`)})),o==="canceled"||o==="failed"){const c=o==="canceled"?"canceled":"failed";this.aibotHandle.sendEventResult({event_id:t,status:c,msg:a?.reason,updated_at:Date.now()}),this.auditController.closeWithoutAdapter(t,c,a?.reason,{queueTerminalState:o}),this.discardEventTrackingState(t),this.pendingEvents.remove(t).catch(d=>{h.warn(this.name,`Failed to remove queued terminal event from pending store event=${t}: ${d instanceof Error?d.message:String(d)}`)})}}),this.pool.setQueueComposingHandler((t,s,o)=>{this.aibotHandle.sendSessionActivitySet({session_id:t,kind:"composing",active:s,...s?{ttl_ms:Xn,ref_event_id:o}:{}})}),this.pool.setInternalErrorHandler(t=>{this.handleSessionInternalError(t).catch(s=>{h.error(this.name,`[recovery] handleSessionInternalError failed event=${t.eventId} session=${t.sessionId}: ${s instanceof Error?s.message:String(s)}`)})}),this.pool.setEventStartedHandler((t,s)=>{if(this.reportSessionSkills(s),this.config.adapterType!=="claude")return;this.claudeWorkerStatus.set(s,"busy");const o=this.bindingStore.get(s);o?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"busy",cwd:o.cwd,meta:this.buildClaudeToolbarMeta(s)})}),this.pool.setEventDoneHandler((t,s)=>{this.markAuditAdapterClosed(t,s);const o=this.config.adapterType??"acp";if(o==="claude"){this.claudeWorkerStatus.set(s,"ready");const a=this.bindingStore.get(s);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:"ready",cwd:a.cwd,meta:this.buildClaudeToolbarMeta(s)})}else if(o==="agy"){const a=this.bindingStore.get(s);if(a?.cwd){const c=this.buildAgyToolbarMeta(s),d=c?.available_models??[];h.info(this.name,`[agy-toolbar-diag] eventDone push binding card session=${s} model_id=${String(c?.model_id??"")} available_models=${d.length} meta_keys=${c?Object.keys(c).join(","):"<none>"}`),this.sendAgyBindingCard(s,a.cwd,c),this.refreshAndPushAgyQuota(s)}else h.info(this.name,`[agy-toolbar-diag] eventDone skip binding card: no binding cwd session=${s}`)}}),this.pool.setSessionActivityHandler((t,s,o)=>{const a=this.selfDrivenSessions.has(t),c=this.selfDrivenLabels.get(t);s?(this.selfDrivenSessions.add(t),o&&this.selfDrivenLabels.set(t,o),this.aibotHandle.sendSessionActivitySet({session_id:t,kind:"composing",active:!0,ttl_ms:9e4})):(this.selfDrivenSessions.delete(t),this.selfDrivenLabels.delete(t),a&&this.aibotHandle.sendSessionActivitySet({session_id:t,kind:"composing",active:!1})),(a!==s||s&&o!==void 0&&o!==c)&&this.pushQueueSnapshotForSession(t)}),await this.replayPendingEventsOnStartup(),this.stopped)throw new Error("agent start aborted");this.pool.startIdleSweep(),h.info(this.name,`Ready (adapter: ${i}, poolMax: ${this.config.poolMaxSize??20})`)}requestStop(){this.stopped=!0,this.lifecycleBarrier.close(),this.startupAbortController.abort(),this.pool?.stopIdleSweep(),this.stopProviderQuotaTimer(),this.pool?.pauseAllQueues("shutdown")}async stop(e){if(e?.dropPendingEvents&&(this.dropPendingEventsRequested=!0),this.requestStop(),!this.stopPromise){const n=this.stopOnce();this.stopPromise=n,n.catch(()=>{this.stopPromise===n&&(this.stopPromise=null)})}await this.stopPromise,this.dropPendingEventsRequested&&!this.pendingEventsDropped&&await this.dropPendingEventsBestEffort()}async stopOnce(){this.lifecycleBarrier.close(),this.pool?.stopIdleSweep(),this.stopProviderQuotaTimer(),this.pool?.pauseAllQueues("shutdown");const e=this.pool?.collectActiveEventIds()??[],n=new Map(e.map(o=>[o,this.eventSessionIndex.get(o)]));e.length>0&&this.activeEventStore&&await this.activeEventStore.save(e);for(const o of e)h.info(this.name,`Canceling active event on shutdown: ${o}`),this.sendEventResultWithCleanup(o,"canceled","process shutting down");e.length>0&&await new Promise(o=>setTimeout(o,100)),this.pool?.clearActiveEventsForShutdown();for(const o of e){const a=n.get(o),c=a?this.pool?.getSlot(a):void 0;this.auditController.markAdapterClosed(o,c?.adapter.takeAuditBoundary?.(o)??{processTerminated:!0})}const r=this.deferredMgr.getAllDeferredEntries(),i=this.pool?.drainAllQueuedEvents()??[],t=this.pendingEvents.dedupe([...this.pendingEvents.replaySnapshot(),...r.map(o=>({kind:"deferred",channel:o.channel,sessionId:o.sessionId,event:o.event})),...i.map(o=>({kind:"queued",event:o}))]);let s=!1;if(this.dropPendingEventsRequested)try{await this.pendingEvents.clear(),this.pendingEventsDropped=!0}catch(o){h.warn(this.name,`Failed to clear pending event store on removal: ${o instanceof Error?o.message:String(o)}`)}else try{s=await this.pendingEvents.mergeForShutdown(t)}catch(o){h.error(this.name,`Failed to persist pending events on shutdown: ${o instanceof Error?o.message:String(o)}`)}if(!s)for(const o of t){const a=o.event;h.info(this.name,`Failing pending event on shutdown: ${a.event_id}`),this.sendEventResultWithCleanup(a.event_id,"failed","process shutting down"),this.auditController.markAdapterClosed(a.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()}async dropPendingEventsBestEffort(){try{await this.pendingEvents.clear(),this.pendingEventsDropped=!0}catch(e){h.warn(this.name,`Failed to clear pending event store on removal: ${e instanceof Error?e.message:String(e)}`)}}resolveSpawnEnv(){const e=this.providerResolver?this.providerResolver():this.config.agent.provider,n=se(this.config.agent.clientType,e),r=this.config.agent.env;let i=Object.keys(n).length>0?{...n,...r}:r;if(oe(n)){const t=te()?.getRuntimeInfo(),s={...r??{},...n},o=re(s,{proxyUrl:t?.proxyUrl,caCertPath:t?.caCertPath,caBundlePath:t?.caBundlePath});return delete o.ANTHROPIC_API_KEY,delete o.CLAUDE_CODE_OAUTH_TOKEN,o}if(ie(this.config.agent.clientType)){const t=ne(this.name);t&&(i={...i??{},...t})}return ee(i,this.name,this.config.agent.clientType)}createAdapter(e,n){switch(e){case"claude":return this.createClaudeAdapter(n);case"codex":return this.createCodexAdapter(n);case"pi":return this.createPiAdapter(n);case"openhuman":return this.createOpenHumanAdapter(n);case"codewhale":return this.createCodeWhaleAdapter(n);case"cursor":return this.createCursorAdapter(n);case"opencode":return this.createOpenCodeAdapter(n);case"agy":return this.createAgyAdapter(n);case"deepseek-harness":return this.createDshAdapter(n);default:return this.createAcpAdapter(n)}}createDshAdapter(e){const n={sendStreamChunk:(t,s,o,a,c,d,l)=>{this.sendStreamChunkByRuntimeConfig(t,s,o,a,c,d,l)},sendFinalStreamChunkReliable:this.reliableFinalWiring("deepseek-harness",Ai),sendThinking:(t,s,o)=>this.sendThinkingByRuntimeConfig(t,s,o),sendEventResult:(t,s,o,a)=>{this.sendEventResultWithCleanup(t,s,o,void 0,a)},sendRawEventEnvelope:(t,s,o,a)=>{const c=oi(o);if(c){this.sendToolExecutionCard(t,s,c);return}this.deliverRawEventEnvelope(t,s,o,"deepseek",a)},sendLocalActionResult:(t,s,o,a,c)=>{this.aibotHandle.sendLocalActionResult({action_id:t,status:s,...o!==void 0?{result:o}:{},...a?{error_code:a}:{},...c?{error_msg:c}:{}},e)},sendPermissionCard:t=>{this.sendGrixApprovalCard(t,"deepseek")},sendUpdateBindingCard:(t,s,o,a)=>{this.aibotHandle.sendUpdateBindingCard({session_id:t,worker_status:s,cwd:o,meta:a})},getAgentProfile:()=>({...this.agentProfile,systemPrompt:this.agentSystemPrompt}),getAgentId:()=>this.config.aibot.agentId,queryProviderQuota:t=>this.maybeQueryProviderQuota(t===!0,{providerId:"deepseek"}),agentInvoke:async(t,s,o)=>this.platformInvoke(t,s,o),eventToolInvoke:async(t,s)=>this.invokeDshEventTool(t,s)},r=M("sha256").update(this.config.aibot.agentId).digest("hex").slice(0,24),i=this.config.adapterOptions??{};return new z({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:i},n,{aibotSessionId:e,bindingStore:this.bindingStore,globalConfigStore:this.globalConfigStore,agentName:this.name,dataRoot:y.join(w.data,"deepseek-harness",r),...typeof i.cordisPath=="string"?{cordisPath:i.cordisPath}:{},...typeof i.defaultModel=="string"?{defaultModel:i.defaultModel}:{},...typeof i.maxTokens=="number"?{maxTokens:i.maxTokens}:{},...typeof i.maxLineBytes=="number"?{maxLineBytes:i.maxLineBytes}:{},...i.integrationMode==="embedded_jsonrpc"||i.integrationMode==="profile_bridge"?{integrationMode:i.integrationMode}:{},...typeof i.dshHome=="string"?{dshHome:i.dshHome}:{},...typeof i.dshProfile=="string"?{dshProfile:i.dshProfile}:{},...typeof i.autoInstallBridge=="boolean"?{autoInstallBridge:i.autoInstallBridge}:{},...typeof i.autoStartProfile=="boolean"?{autoStartProfile:i.autoStartProfile}:{},...this.config.agent.provider?{provider:this.config.agent.provider}:{},promptTimeoutMs:this.config.promptTimeoutMs})}createCursorAdapter(e){const n={...this.config.adapterOptions??{}};n.bindingStore=this.bindingStore,n.aibotSessionId=e;const r=this.bindingStore.get(e),i=this.resolveSessionModelId(e);i&&(n.model=i);const t=this.resolveCursorSessionModeId(e),s=t??"full_auto";t||this.bindingStore.setCursorModeId(e,s),n.mode=s,r?.cwd&&(n.workspace=r.cwd);const o={sendStreamChunk:(a,c,d,l,u,g,p)=>{this.sendStreamChunkByRuntimeConfig(a,c,d,l,u,g,p)},sendEventResult:(a,c,d)=>{this.sendEventResultWithCleanup(a,c,d)},sendEventAck:(a,c)=>{this.aibotHandle.sendEventAck({event_id:a,session_id:c,received_at:Date.now()})},sendRawEventEnvelope:(a,c,d)=>{this.deliverRawEventEnvelope(a,c,d,"cursor",this.buildCursorRawEventFallbackText(d))},sendAgentQuestionCard:(a,c,d)=>{const l=d.questions.map(g=>g.header).join(", "),u=I(`[Agent Question] ${d.request_id}`,"agent_question",d);this.aibotHandle.sendText({event_id:a,session_id:c,content:u,msg_type:1,extra:{card_type:"agent_question",summary_text:l}})},agentInvoke:async(a,c,d)=>this.platformInvoke(a,c,d),sendLocalActionResult:(a,c,d,l,u)=>{this.aibotHandle.sendLocalActionResult({action_id:a,status:c,...d!==void 0?{result:d}:{},...l?{error_code:l}:{},...u?{error_msg:u}:{}},e)},sendUpdateBindingCard:(a,c,d,l)=>{this.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:c,cwd:d,...l?{meta:l}:{}})},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId};return new j({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:n},o)}createClaudeAdapter(e){const n={sendReply:(t,s,o,a,c)=>{this.sendReplyByRuntimeConfig(t,s,o,a,c)},sendStreamChunk:(t,s,o,a,c,d,l)=>{this.sendStreamChunkByRuntimeConfig(t,s,o,a,c,d,l)},sendMedia:(t,s,o,a,c,d,l)=>{this.aibotHandle.sendMedia({event_id:t,session_id:s,content:o,msg_type:2,quoted_message_id:c||void 0,client_msg_id:d||void 0,extra:l?{media_caption:a,...l}:{media_caption:a}})},sendEventResult:(t,s,o,a)=>{this.sendEventResultWithCleanup(t,s,o,a)},sendEventAck:(t,s)=>{this.aibotHandle.sendEventAck({event_id:t,session_id:s,received_at:Date.now()})},agentInvoke:async(t,s,o)=>this.platformInvoke(t,s,o),sendLocalActionResult:(t,s,o,a,c)=>{this.aibotHandle.sendLocalActionResult({action_id:t,status:s,...o!==void 0?{result:o}:{},...a?{error_code:a}:{},...c?{error_msg:c}:{}},e)},sendToolUse:(t,s,o,a)=>{this.sendToolExecutionCard(t,s,C(o,a))},sendToolResult:(t,s,o,a)=>{this.sendToolExecutionCard(t,s,b(o,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:(t,s,o)=>{this.sendGrixAgentQuestionCard(t,s,o)},sendPermissionCard:t=>{this.sendGrixApprovalCard(t,"claude")},sendDirectMessage:t=>{this.aibotHandle.sendMsg({session_id:t.sessionId,msg_type:1,content:t.content,...t.clientMsgId?{client_msg_id:t.clientMsgId}:{},...t.quotedMessageId?{quoted_message_id:t.quotedMessageId}:{}})},onStatusLineUpdated:t=>{(t.rateLimits?.fiveHour||t.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=t);const s=this.bindingStore.get(e);s?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:this.claudeWorkerStatus.get(e)??"ready",cwd:s.cwd,meta:this.buildClaudeToolbarMeta(e)})},sendMcpFrame:t=>{this.aibotHandle.sendMcpFrame(e,t)}},r=this.config.adapterOptions??{},i={...r,sessionRuntimeResolver:()=>{const t=this.bindingStore.get(e),s=this.auditController.getSession(e);return{cwd:t?.cwd,modeId:this.resolveClaudeSessionModeId(e)??J.fullAuto,modelId:this.resolveSessionModelId(e),effort:this.resolveClaudeSessionEffort(e),pluginDir:r.pluginDir,claudeSessionId:t?.claudeSessionId,...s?{audit:{enabled:!0,profile:s.options.profile,capture:s.options.capture}}:{},onSessionIdAssigned:o=>{this.bindingStore.setClaudeSessionId(e,o),this.sessionScanCache.invalidate()}}}};return new L({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:i},n)}createCodexAdapter(e){let n=null;const r={sendEventResult:(o,a,c)=>{if(a!=="responded"){this.sendEventResultWithCleanup(o,a,c);return}this.sendCtrl.sendFinalStreamChunkReliable(o,e,`codex_terminal_fence_${o}`,5e3,!0,!0).then(()=>this.sendEventResultWithCleanup(o,a,c),d=>{const l=`codex output acceptance fence failed: ${d instanceof Error?d.message:String(d)}`;this.sendEventResultWithCleanup(o,a==="responded"?"failed":a,a==="responded"?l:c)})},sendEventAck:(o,a)=>this.aibotHandle.sendEventAck({event_id:o,session_id:a,received_at:Date.now()}),sendCodexEvent:o=>{this.shouldDropCodexDisplayEvent(o.event_id,o.codex_method)||(this.captureCodexAuditOutput(o),this.aibotHandle.sendCodexEvent(this.stampCodexEventQuote(o)),this.logCodexEventToConversation(o))},sendThinking:(o,a,c)=>{this.sendThinkingByRuntimeConfig(o,a,c)},sendRunError:(o,a,c)=>{this.sendRunErrorAsChunk(o,a,c)},sendUpdateBindingCard:(o,a,c,d)=>{const l={...d??{}};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:o,worker_status:a,cwd:c,...Object.keys(l).length>0?{meta:l}:{}})},agentInvoke:async(o,a,c)=>this.platformInvoke(o,a,c),sendLocalActionResult:(o,a,c,d,l)=>this.aibotHandle.sendLocalActionResult({action_id:o,status:a,...c!==void 0?{result:c}:{},...d?{error_code:d}:{},...l?{error_msg:l}:{}},e),sendSessionActivitySet:(o,a,c,d)=>{this.aibotHandle.sendSessionActivitySet({session_id:o,kind:a,active:c,...d??{}})},getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId,onRateLimitsUpdated:o=>{this.cachedRateLimits=o,this.cachedRateLimitsSampledAtMs=Date.now(),this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const a=this.bindingStore.get(e);if(a?.cwd){const c=this.cachedRateLimitsSampledAtMs,d={rate_limits:{...o.primary.windowMinutes>0?{primary:o.primary}:{},...o.secondary.windowMinutes>0?{secondary:o.secondary}:{},sampledAt:c},rate_limit_primary_percent:o.primary.usedPercent,rate_limit_secondary_percent:o.secondary.usedPercent,rate_limit_primary_window_min:o.primary.windowMinutes,rate_limit_secondary_window_min:o.secondary.windowMinutes,credits:o.credits,...o.extras&&o.extras.length>0?{extra_limits:o.extras}:{},...n?.getEffortMeta()};this.cachedProviderQuota?.success&&(d.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:d})}},onContextWindowUpdated:o=>{if(!o)return;this.cachedCodexContextWindow=o,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:o,...n?.getEffortMeta()}})},onTokenUsageUpdated:o=>{o&&(this.cachedCodexTokenUsage=o,this.cachedCodexUsageSampledAtMs=Date.now())}},i=this.config.adapterOptions??{},t=this.globalConfigStore?.get(this.name),s=this.auditController.getAdapterPreparation(e);return n=new D({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...i,model:this.resolveCodexSessionModelId(e)??i.model,collaborationMode:this.bindingStore.getCodexModeId(e)??this.resolveCodexNewSessionGlobalDefault(e,t?.codexModeId,o=>this.bindingStore.setCodexModeId(e,o))??i.collaborationMode,reasoningEffort:this.bindingStore.getCodexReasoningEffort(e)??this.pinCodexGlobalDefault(t?.codexReasoningEffort,o=>this.bindingStore.setCodexReasoningEffort(e,o))??i.reasoningEffort,serviceTier:this.bindingStore.getCodexServiceTier(e)??this.resolveCodexNewSessionGlobalDefault(e,t?.codexServiceTier,o=>this.bindingStore.setCodexServiceTier(e,o))??i.serviceTier,sandboxMode:this.bindingStore.getCodexSandboxMode(e)??this.pinCodexGlobalDefault(t?.codexSandboxMode,o=>this.bindingStore.setCodexSandboxMode(e,o))??i.sandboxMode,aibotSessionId:e,bindingStore:this.bindingStore,...Q(s?.options)?{rawApiCapture:{auditId:s.auditId,sessionId:e,spoolRootDir:y.join(w.data,"audit-replay","raw-spool")}}:{}}},r),n}createCodeWhaleAdapter(e){const n={sendEventResult:(i,t,s)=>{this.sendEventResultWithCleanup(i,t,s)},sendEventAck:(i,t)=>this.aibotHandle.sendEventAck({event_id:i,session_id:t,received_at:Date.now()}),sendStreamChunk:(i,t,s,o,a,c)=>{this.sendStreamChunkByRuntimeConfig(i,t,s,o,a,c)},sendUpdateBindingCard:(i,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,i,s)}),sendLocalActionResult:(i,t,s,o,a)=>this.aibotHandle.sendLocalActionResult({action_id:i,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e),sendSessionActivitySet:(i,t,s,o)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:t,active:s,...o??{}})},sendToolUse:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,C(s,o))},sendToolResult:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,b(s,o))},agentInvoke:async(i,t,s)=>this.platformInvoke(i,t,s),getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=this.config.adapterOptions??{};return new K({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...r,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,model:this.resolveSessionModelId(e)??r.model,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},n)}createPiAdapter(e){const n={sendEventResult:(i,t,s)=>{this.sendEventResultWithCleanup(i,t,s),h.info("bridge",`[pi] sendEventResult event=${i} status=${t}`)},sendEventAck:(i,t)=>this.aibotHandle.sendEventAck({event_id:i,session_id:t,received_at:Date.now()}),sendUpdateBindingCard:(i,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,i,s)}),agentInvoke:async(i,t,s)=>this.platformInvoke(i,t,s),sendLocalActionResult:(i,t,s,o,a)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e)},sendSessionActivitySet:(i,t,s,o)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:t,active:s,...o??{}})},sendToolUse:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,C(s,o))},sendToolResult:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,b(s,o))},sendStreamChunk:(i,t,s,o,a,c)=>{this.sendStreamChunkByRuntimeConfig(i,t,s,o,a,c),a&&h.info("bridge",`[pi] sendFinalStreamChunk event=${i} seq=${o}`)},sendFinalStreamChunkReliable:this.reliableFinalWiring("pi"),sendThinking:(i,t,s)=>{this.sendThinkingByRuntimeConfig(i,t,s)},sendRunError:(i,t,s,o,a)=>{this.sendStreamChunkByRuntimeConfig(i,t,`
2
2
 
3
- Error: ${s}`,o,!1,a)},getAgentProfile:()=>this.agentProfile},r=this.config.adapterOptions??{};return new W({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...r,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},i)}createOpenHumanAdapter(e){const i={sendStreamChunk:(n,t,s,o,a,l)=>{this.sendStreamChunkByRuntimeConfig(n,t,s,o,a,l)},sendFinalStreamChunkReliable:async(n,t,s,o)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(n,t,o)}catch(a){throw h.error("bridge",`[openhuman] sendFinalStreamChunkReliable ACK failed event=${n}: ${a}`),a}},sendEventResult:(n,t,s)=>{this.sendEventResultWithCleanup(n,t,s),h.info("bridge",`[openhuman] sendEventResult event=${n} status=${t}`)},sendEventAck:(n,t)=>this.aibotHandle.sendEventAck({event_id:n,session_id:t,received_at:Date.now()}),sendToolUse:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,C(s,o))},sendToolResult:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,b(s,o))},sendThinking:(n,t,s)=>{this.sendThinkingByRuntimeConfig(n,t,s)},sendRunError:(n,t,s)=>{this.sendStreamChunkByRuntimeConfig(n,t,`
3
+ Error: ${s}`,o,!1,a)},getAgentProfile:()=>this.agentProfile},r=this.config.adapterOptions??{};return new W({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...r,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},n)}createOpenHumanAdapter(e){const n={sendStreamChunk:(i,t,s,o,a,c)=>{this.sendStreamChunkByRuntimeConfig(i,t,s,o,a,c)},sendFinalStreamChunkReliable:async(i,t,s,o)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(i,t,o)}catch(a){throw h.error("bridge",`[openhuman] sendFinalStreamChunkReliable ACK failed event=${i}: ${a}`),a}},sendEventResult:(i,t,s)=>{this.sendEventResultWithCleanup(i,t,s),h.info("bridge",`[openhuman] sendEventResult event=${i} status=${t}`)},sendEventAck:(i,t)=>this.aibotHandle.sendEventAck({event_id:i,session_id:t,received_at:Date.now()}),sendToolUse:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,C(s,o))},sendToolResult:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,b(s,o))},sendThinking:(i,t,s)=>{this.sendThinkingByRuntimeConfig(i,t,s)},sendRunError:(i,t,s)=>{this.sendStreamChunkByRuntimeConfig(i,t,`
4
4
 
5
- Error: ${s}`,0,!1)},sendUpdateBindingCard:(n,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,n,s)}),agentInvoke:async(n,t,s)=>this.platformInvoke(n,t,s),sendLocalActionResult:(n,t,s,o,a)=>{this.aibotHandle.sendLocalActionResult({action_id:n,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=this.config.adapterOptions??{};return new G({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:r},i,{port:r.port,host:r.host,workspaceDir:r.workspace_dir,sessionToken:r.session_token,enableSessionBinding:!0,aibotSessionId:e})}createOpenCodeAdapter(e){const i={sendStreamChunk:(n,t,s,o,a,l)=>{this.sendStreamChunkByRuntimeConfig(n,t,s,o,a,l)},sendFinalStreamChunkReliable:this.reliableFinalWiring("opencode"),sendEventResult:(n,t,s)=>{this.sendEventResultWithCleanup(n,t,s),h.info("bridge",`[opencode] sendEventResult event=${n} status=${t}`)},sendEventAck:(n,t)=>this.aibotHandle.sendEventAck({event_id:n,session_id:t,received_at:Date.now()}),sendToolUse:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,C(s,o))},sendToolResult:(n,t,s,o)=>{this.sendToolExecutionCard(n,t,b(s,o))},sendThinking:(n,t,s)=>{this.sendThinkingByRuntimeConfig(n,t,s)},sendRunError:(n,t,s)=>{this.sendRunErrorAsChunk(n,t,s)},sendUpdateBindingCard:(n,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,n,s)}),agentInvoke:async(n,t,s)=>this.platformInvoke(n,t,s),sendLocalActionResult:(n,t,s,o,a)=>{this.aibotHandle.sendLocalActionResult({action_id:n,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e)},sendPermissionCard:n=>{this.sendGrixApprovalCard(n,"opencode")},sendAgentQuestionCard:(n,t,s)=>{this.sendGrixAgentQuestionCard(n,t,s)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=this.config.adapterOptions??{};return new k({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:r},i,{port:r.port,hostname:r.hostname,model:r.model??this.resolveSessionModelId(e),agent:r.agent,permissionPolicy:r.permission_policy,enableSessionBinding:!0,aibotSessionId:e,bindingStore:this.bindingStore,...this.config.agent.provider?{provider:this.config.agent.provider}:{}})}createAgyAdapter(e){const i={sendStreamChunk:(n,t,s,o,a,l)=>{this.sendStreamChunkByRuntimeConfig(n,t,s,o,a,l)},sendEventResult:(n,t,s)=>{this.sendEventResultWithCleanup(n,t,s)},sendEventAck:(n,t)=>{this.aibotHandle.sendEventAck({event_id:n,session_id:t,received_at:Date.now()})},agentInvoke:async(n,t,s)=>this.platformInvoke(n,t,s),forceCompleteInternalEvent:(n,t)=>{this.pool.eventComplete(n,t),this.pushQueueSnapshotForSession(t)},persistConversationId:(n,t)=>{this.bindingStore.setAgyConversationId(n,t)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=n=>{const t=this.bindingStore.get(n);return{cwd:t?.cwd,modelId:this.resolveSessionModelId(n),conversationId:t?.agyConversationId}};return new H({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:this.config.adapterOptions??{}},i,r)}createAcpAdapter(e){const i=this.isAcpRawTransportEnabled(),r={sendStreamChunk:(d,c,u,g,p,_,A)=>{this.sendStreamChunkByRuntimeConfig(d,c,u,g,p,_,A)},sendFinalStreamChunkReliable:this.reliableFinalWiring("acp",4e3),sendEventResult:(d,c,u)=>{this.sendEventResultWithCleanup(d,c,u)},sendEventAck:(d,c)=>{this.aibotHandle.sendEventAck({event_id:d,session_id:c,received_at:Date.now()})},agentInvoke:async(d,c,u)=>this.platformInvoke(d,c,u),sendLocalActionResult:(d,c,u,g,p)=>{this.aibotHandle.sendLocalActionResult({action_id:d,status:c,...u!==void 0?{result:u}:{},...g?{error_code:g}:{},...p?{error_msg:p}:{}},e)},sendRawEventEnvelope:(d,c,u)=>{this.sendAcpRawEventEnvelope(d,c,u)},sendToolUse:(d,c,u,g)=>{if(i){this.sendAcpRawEventEnvelope(d,c,{type:"tool_use",payload:{tool_name:u,tool_input:g??""}});return}this.sendToolExecutionCard(d,c,C(u,g))},sendToolResult:(d,c,u,g)=>{this.sendToolExecutionCard(d,c,b(u,g))},sendThinking:(d,c,u)=>{this.sendThinkingByRuntimeConfig(d,c,u)},sendRunError:(d,c,u)=>{this.sendStreamChunkByRuntimeConfig(d,c,`
5
+ Error: ${s}`,0,!1)},sendUpdateBindingCard:(i,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,i,s)}),agentInvoke:async(i,t,s)=>this.platformInvoke(i,t,s),sendLocalActionResult:(i,t,s,o,a)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=this.config.adapterOptions??{};return new G({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:r},n,{port:r.port,host:r.host,workspaceDir:r.workspace_dir,sessionToken:r.session_token,enableSessionBinding:!0,aibotSessionId:e})}createOpenCodeAdapter(e){const n={sendStreamChunk:(i,t,s,o,a,c)=>{this.sendStreamChunkByRuntimeConfig(i,t,s,o,a,c)},sendFinalStreamChunkReliable:this.reliableFinalWiring("opencode"),sendEventResult:(i,t,s)=>{this.sendEventResultWithCleanup(i,t,s),h.info("bridge",`[opencode] sendEventResult event=${i} status=${t}`)},sendEventAck:(i,t)=>this.aibotHandle.sendEventAck({event_id:i,session_id:t,received_at:Date.now()}),sendToolUse:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,C(s,o))},sendToolResult:(i,t,s,o)=>{this.sendToolExecutionCard(i,t,b(s,o))},sendThinking:(i,t,s)=>{this.sendThinkingByRuntimeConfig(i,t,s)},sendRunError:(i,t,s)=>{this.sendRunErrorAsChunk(i,t,s)},sendUpdateBindingCard:(i,t,s,o)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:t,cwd:s,...this.providerQuotaMetaPayload(o,i,s)}),agentInvoke:async(i,t,s)=>this.platformInvoke(i,t,s),sendLocalActionResult:(i,t,s,o,a)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:t,...s!==void 0?{result:s}:{},...o?{error_code:o}:{},...a?{error_msg:a}:{}},e)},sendPermissionCard:i=>{this.sendGrixApprovalCard(i,"opencode")},sendAgentQuestionCard:(i,t,s)=>{this.sendGrixAgentQuestionCard(i,t,s)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=this.config.adapterOptions??{};return new k({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:r},n,{port:r.port,hostname:r.hostname,model:r.model??this.resolveSessionModelId(e),agent:r.agent,permissionPolicy:r.permission_policy,enableSessionBinding:!0,aibotSessionId:e,bindingStore:this.bindingStore,...this.config.agent.provider?{provider:this.config.agent.provider}:{}})}createAgyAdapter(e){const n={sendStreamChunk:(i,t,s,o,a,c)=>{this.sendStreamChunkByRuntimeConfig(i,t,s,o,a,c)},sendEventResult:(i,t,s)=>{this.sendEventResultWithCleanup(i,t,s)},sendEventAck:(i,t)=>{this.aibotHandle.sendEventAck({event_id:i,session_id:t,received_at:Date.now()})},agentInvoke:async(i,t,s)=>this.platformInvoke(i,t,s),forceCompleteInternalEvent:(i,t)=>{this.pool.eventComplete(i,t),this.pushQueueSnapshotForSession(t)},persistConversationId:(i,t)=>{this.bindingStore.setAgyConversationId(i,t)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},r=i=>{const t=this.bindingStore.get(i);return{cwd:t?.cwd,modelId:this.resolveSessionModelId(i),conversationId:t?.agyConversationId}};return new H({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:this.config.adapterOptions??{}},n,r)}createAcpAdapter(e){const n=this.isAcpRawTransportEnabled(),r={sendStreamChunk:(d,l,u,g,p,_,A)=>{this.sendStreamChunkByRuntimeConfig(d,l,u,g,p,_,A)},sendFinalStreamChunkReliable:this.reliableFinalWiring("acp",4e3),sendEventResult:(d,l,u)=>{this.sendEventResultWithCleanup(d,l,u)},sendEventAck:(d,l)=>{this.aibotHandle.sendEventAck({event_id:d,session_id:l,received_at:Date.now()})},agentInvoke:async(d,l,u)=>this.platformInvoke(d,l,u),sendLocalActionResult:(d,l,u,g,p)=>{this.aibotHandle.sendLocalActionResult({action_id:d,status:l,...u!==void 0?{result:u}:{},...g?{error_code:g}:{},...p?{error_msg:p}:{}},e)},sendRawEventEnvelope:(d,l,u)=>{this.sendAcpRawEventEnvelope(d,l,u)},sendToolUse:(d,l,u,g)=>{if(n){this.sendAcpRawEventEnvelope(d,l,{type:"tool_use",payload:{tool_name:u,tool_input:g??""}});return}this.sendToolExecutionCard(d,l,C(u,g))},sendToolResult:(d,l,u,g)=>{this.sendToolExecutionCard(d,l,b(u,g))},sendThinking:(d,l,u)=>{this.sendThinkingByRuntimeConfig(d,l,u)},sendRunError:(d,l,u)=>{this.sendStreamChunkByRuntimeConfig(d,l,`
6
6
 
7
- Error: ${u}`,1,!1)},sendAgentQuestionCard:(d,c,u)=>{this.sendGrixAgentQuestionCard(d,c,u)},sendPermissionCard:d=>{h.info("bridge","sendPermissionCard callback entered",{rawTransport:i,eventId:d.eventId,sessionId:d.sessionId,toolCallId:d.toolCallId,toolName:d.toolName,toolTitle:d.toolTitle});const c=d.toolInput&&d.toolTitle&&d.toolInput!==d.toolTitle?`${d.toolTitle}: ${d.toolInput}`:d.toolTitle||d.toolInput||d.toolName;if(i){this.sendAcpRawEventEnvelope(d.eventId,d.sessionId,{type:"permission_request",payload:{tool_call_id:d.toolCallId,tool_name:d.toolName,tool_title:d.toolTitle,...d.toolInput?{tool_input:d.toolInput}:{},options:d.options}}),h.info("bridge","sendPermissionCard: sent via rawEventEnvelope",{eventId:d.eventId,toolCallId:d.toolCallId});return}const u=`perm_${R()}`,g={event_id:d.eventId,session_id:d.sessionId,client_msg_id:u,msg_type:1,content:d.toolTitle?`Permission required: ${d.toolTitle}`:"Permission request",extra:{channel_data:{execApproval:{approvalId:d.toolCallId,approvalSlug:d.toolName},grix:{execApproval:{approval_command_id:d.toolCallId,approval_type:"permission",command:c,host:"acp"}}},agent_api_origin:!0}};h.info("bridge","sendPermissionCard: about to invoke aibotHandle.sendMsg",{eventId:d.eventId,sessionId:d.sessionId,clientMsgId:u,toolCallId:d.toolCallId,contentLength:g.content.length});try{this.aibotHandle.sendMsg(g),h.info("bridge","sendPermissionCard: aibotHandle.sendMsg returned",{eventId:d.eventId,clientMsgId:u})}catch(p){h.error("bridge","sendPermissionCard: aibotHandle.sendMsg threw",{eventId:d.eventId,clientMsgId:u,error:p instanceof Error?p.message:String(p)})}},sendAuthNotification:(d,c)=>{d&&this.aibotHandle.sendMsg({session_id:d,msg_type:1,content:c,extra:{biz_card:{version:1,type:"agent_error",payload:{error:{name:"AuthRequired",message:c}}}}})},sendAgentMessage:(d,c)=>{d&&c&&this.aibotHandle.sendMsg({session_id:d,msg_type:1,content:c})},sendUpdateBindingCard:(d,c,u,g)=>{const p={...g??{}};if(!p.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const _=this.providerQuotaToRateLimits(this.cachedProviderQuota);_&&(p.rate_limits=_)}!p.provider_quota&&this.cachedProviderQuota?.success&&(p.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:c,cwd:u,...Object.keys(p).length>0?{meta:p}:{}})},onSkillsUpdate:(d,c)=>{try{this.aibotHandle.sendSkillsUpdate({skills:X(d,w.skills),library_skills:this.buildLibrarySkillsReport(c)})}catch(u){}},onContextWindowUpdated:d=>{this.cachedAcpContextWindow=d,this.cachedAcpContextWindowSampledAtMs=Date.now();const c="usedPercentage"in d?d.usedPercentage.toFixed(1):(d.used/d.size*100).toFixed(1);h.info(this.name,`[acp] context_window updated: ${c}%`);const u=this.bindingStore.get(e);if(u?.cwd){const g="usedPercentage"in d?d.usedPercentage:Math.min(100,d.used/d.size*100),p={context_window:{..."usedPercentage"in d?{}:d,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(()=>{}),p.provider_quota=this.cachedProviderQuota;const _=this.providerQuotaToRateLimits(this.cachedProviderQuota);_&&(p.rate_limits=_)}this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:u.cwd,meta:p})}},sendMcpFrame:d=>{this.aibotHandle.sendMcpFrame(e,d)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},n=e?this.bindingStore.get(e):void 0,t=e?this.auditController.getSession(e):void 0,s=this.config.aibot.clientType==="reasonix"&&t?Ei(this.name,e,t.auditId):void 0,o=this.globalConfigStore?.get(this.name),{initialModel:a,initialMode:l}=Wn({sessionBinding:n,globalDefaults:o,configInitialMode:this.config.acpInitialMode});return e&&a&&!n?.acpModelId&&this.bindingStore.setAcpModelId(e,a),e&&l&&!n?.acpModeId&&this.bindingStore.setAcpModeId(e,l),(a||l)&&h.info(this.name,`[toolbar] hydrate from binding: session=${e} model=${a??"<none>"} mode=${l??"<none>"}`),new S({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv()},r,{acpAuthMethod:this.config.acpAuthMethod,acpInitialMode:l,acpInitialModel:a,acpMcpTools:this.config.acpMcpTools,rawTransport:i,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 Pe(this.config.logDir,`${this.name}-${e}`):null,reasonixAuditTranscriptPath:s,agentType:this.config.aibot.clientType})}async connectAibot(){const i=await new q().connect(this.aibotConfig,{aborted:()=>this.stopped,signal:this.startupAbortController.signal,label:this.name,packetLog:this.packetLog,maxRetries:this.config.connectMaxRetries});if(this.stopped)throw i.disconnect(),new Error("connection aborted");this.aibotHandle=i;const r=this.aibotHandle.authAck;if(this.applyAgentProfile(r?.agent_name,r?.introduction,{source:"auth_ack",respawnOnChange:!1},r?.system_prompt),this.aibotHandle.onEvent(n=>{this.handleAibotEvent(n).catch(t=>{h.error(this.name,`handleAibotEvent failed: ${t}`),this.aibotHandle.sendEventAck({event_id:n.event_id,session_id:n.session_id,received_at:Date.now()});const s=t instanceof Error?t.message:String(t);if(/CWD must be|Bound directory does not exist|Bound path is not a directory/i.test(s)&&n.session_id){this.bindingStore.delete(n.session_id),this.sessionBindings.delete(n.session_id),this.sessionProviderHints.delete(n.session_id),this.sessionProviderQuotas.delete(n.session_id),this.sessionProviderMeta.delete(n.session_id);const a=this.pool.getSlot(n.session_id);a?.adapter instanceof S&&a.adapter.getSessionBindings().delete(n.session_id);const l=this.config.adapterType??"acp",d=this.resolveBindingChannelKey(l);this.aibotHandle.sendMsg({event_id:n.event_id,session_id:n.session_id,msg_type:1,content:s,extra:{channel_data:{[d]:{sessionBinding:{status:"missing",reason:"binding_stale",error_code:$.invalidCwd}}}},quoted_message_id:n.msg_id});return}this.aibotHandle.sendEventResult({event_id:n.event_id,status:"failed",msg:s,updated_at:Date.now()})})}),this.aibotHandle.onStop(n=>{try{this.handleAibotStop(n)}catch(t){h.error(this.name,`handleAibotStop failed: ${t}`)}}),this.aibotHandle.onAgentDeleted(n=>{h.warn(this.name,`agent deleted on platform (source=${n?.source??"unknown"}${n?.reason?` reason=${n.reason}`:""}), notifying manager to clean up`);try{this.agentDeletedHandler?.()}catch(t){h.error(this.name,`agentDeletedHandler failed: ${t}`)}}),this.aibotHandle.onShareSet(n=>{try{this.shareSetHandler?.(Array.isArray(n?.shared_to)?n.shared_to:[])}catch(t){h.error(this.name,`onShareSet failed: ${t}`)}}),this.aibotHandle.onProfilePush(n=>{try{this.applyAgentProfile(n?.agent_name,n?.introduction,{source:"profile_push",respawnOnChange:!0},n?.system_prompt)}catch(t){h.error(this.name,`onProfilePush failed: ${t}`)}}),this.aibotHandle.onSkillSync(n=>{if(!this.stopped)try{h.info(this.name,`skill_sync received owner=${n?.owner_id??""} name=${n?.name??""}`),this.skillSyncHandler?.()}catch(t){h.error(this.name,`onSkillSync failed: ${t}`)}}),this.aibotHandle.onRevoke(n=>{this.handleAibotRevoke(n).catch(t=>{h.error(this.name,`handleAibotRevoke failed: ${t}`)})}),this.aibotHandle.onLocalAction(n=>{this.handleAibotLocalAction(n).catch(t=>{h.error(this.name,`handleAibotLocalAction failed: ${t}`)})}),this.aibotHandle.onEventCancel(n=>{h.info(this.name,`recv event_cancel event_id=${n.event_id} session_id=${n.session_id}`),this.handleEventCancel(n).catch(t=>{h.error(this.name,`handleEventCancel failed: ${t}`)})}),this.aibotHandle.onMcpFrame((n,t)=>{const s=this.pool.getSlot(n)?.adapter;s?.deliverMcpFrameToAgent?s.deliverMcpFrameToAgent(t):h.warn(this.name,`mcp_frame: no adapter for session=${n}`)}),this.aibotHandle.onQueueClear(n=>{const t=this.pool.clearQueue(n.session_id);this.aibotHandle.sendQueueClearResult({session_id:n.session_id,canceled_event_ids:t}),this.pushQueueSnapshotForSession(n.session_id)}),typeof this.aibotHandle.onQueueReorder=="function"&&this.aibotHandle.onQueueReorder(n=>{const t=Array.isArray(n.ordered_event_ids)?n.ordered_event_ids.filter(o=>typeof o=="string"&&o.length>0):[],s=this.pool.reorderQueue(n.session_id,t);this.aibotHandle.sendQueueReorderResult({session_id:n.session_id,applied_event_ids:s}),this.pushQueueSnapshotForSession(n.session_id)}),typeof this.aibotHandle.onEventHold=="function"&&this.aibotHandle.onEventHold(n=>{const t=typeof n.session_id=="string"?n.session_id:"",s=typeof n.event_id=="string"?n.event_id:"",o=n.hold!==!1;if(h.info(this.name,`recv event_hold event_id=${s} session_id=${t} hold=${o} reason=${n.reason??""}`),!t||!s){this.aibotHandle.sendEventHoldResult({session_id:t,event_id:s,ok:!1,held:!1,error:"bad_request"});return}const a=typeof n.reason=="string"?n.reason:"",l=typeof n.ttl_ms=="number"?n.ttl_ms:void 0,d=this.pool.holdEvent(t,s,o,a,l),c=d==="ok";this.aibotHandle.sendEventHoldResult({session_id:t,event_id:s,ok:c,held:c?o:!1,...c?{}:{error:d}}),c&&this.pushQueueSnapshotForSession(t)}),typeof this.aibotHandle.onQueueEdit=="function"&&this.aibotHandle.onQueueEdit(n=>{const t=typeof n.session_id=="string"?n.session_id:"",s=typeof n.event_id=="string"?n.event_id:"";if(h.info(this.name,`recv queue_edit event_id=${s} session_id=${t}`),!t||!s){this.aibotHandle.sendQueueEditResult({session_id:t,event_id:s,ok:!1,error:"bad_request"});return}const o=typeof n.content=="string"?n.content:"",a=this.pool.editQueuedEvent(t,s,o),l=a==="ok";this.aibotHandle.sendQueueEditResult({session_id:t,event_id:s,ok:l,...l?{}:{error:a}}),l&&this.pushQueueSnapshotForSession(t)}),typeof this.aibotHandle.onQueueSnapshotQuery=="function"&&this.aibotHandle.onQueueSnapshotQuery(n=>{this.replyQueueSnapshotForSession(n.session_id)}),h.info(this.name,"Connected to aibot"),this.activeEventStore){const n=await this.activeEventStore.drain();if(n.length>0){h.warn(this.name,`Recovering ${n.length} stale event(s) from previous run`);for(const t of n)h.info(this.name,`Failing stale event on startup: ${t}`),this.aibotHandle.sendEventResult({event_id:t,status:"failed",msg:"process restarted, event lost",updated_at:Date.now()})}}this.pushQueueSnapshots(),this.relayStateSyncOnConnect(),this.aibotHandle.onReconnected(()=>{if(this.stopped)return;this.pushQueueSnapshots();const n=this.aibotHandle.authAck;this.applyAgentProfile(n?.agent_name,n?.introduction,{source:"reconnect",respawnOnChange:!0},n?.system_prompt),this.forceRefreshSkills(void 0,{force:!0}),this.skillSyncHandler?.(),this.relayStateSyncOnConnect()}),this.aibotHandle.onStreamRejected((n,t)=>{this.sendCtrl.markEventRejected(n)})}applyAgentProfile(e,i,r,n){const t=String(e??"").trim(),s=String(i??"").trim(),o=n===void 0?this.agentSystemPrompt:String(n),a=t!==this.agentProfile.agentName||s!==this.agentProfile.introduction||o!==this.agentSystemPrompt;this.agentProfile={agentName:t,introduction:s},this.agentSystemPrompt=o,t||s?h.info(this.name,`agent profile (${r.source}): GOT name="${t}" intro_len=${s.length} system_prompt_len=${o.length} changed=${a}`):h.warn(this.name,`agent profile (${r.source}): EMPTY \u2014 \u670D\u52A1\u7AEF\u672A\u4E0B\u53D1 agent_name/introduction\uFF08auth_ack \u5B57\u6BB5\u7F3A\u5931\u6216\u503C\u4E3A\u7A7A\uFF09`),a&&r.respawnOnChange&&this.applyProfileChangeToAdapters("agent_profile_changed")}applyProfileChangeToAdapters(e){if(!this.pool)return;const i=this.pool.getAllSlots();let r=0;for(const o of i)if(o.adapter.onAgentProfileChanged)try{o.adapter.onAgentProfileChanged(),r++}catch(a){h.warn(this.name,`onAgentProfileChanged failed for session=${o.sessionId}: ${a}`)}const n=i.filter(o=>o.adapter instanceof L),t=n.filter(o=>{if(o.state!=="ready")return!1;const a=o.adapter.getStatus();return!a.busy&&!a.backgroundBusy}),s=n.length-t.length;h.info(this.name,`${e}: notified ${r} adapter(s) via hook; respawning ${t.length} idle Claude slot(s), skipping ${s} busy`);for(const o of t)this.pool.removeSlot(o.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 i=this.pool?.getQueueSnapshot(e)??null,r=i?[...i.running]:[],n=i?i.running_items.map(s=>({event_id:s.event_id,...s.content_preview?{content_preview:s.content_preview}:{},...s.title?{title:s.title}:{},...s.summary?{summary:s.summary}:{},actions:[{type:"stop"}]})):[],t=i?i.queued.map(s=>({event_id:s.event_id,position:s.position,...s.content_preview?{content_preview:s.content_preview}:{},...typeof s.content=="string"?{content:s.content}:{},...s.title?{title:s.title}:{},...s.summary?{summary:s.summary}:{},held:s.held===!0,held_reason:s.held_reason??"",actions:[{type:"cancel"}]})):[];if(r.length===0&&this.selfDrivenSessions.has(e)&&this.pool?.getSlot(e)){const s=`selfdrive_${e}`,o=this.selfDrivenLabels.get(e)??"Background task in progress";r.push(s),n.push({event_id:s,content_preview:o,title:o,summary:o,actions:[]})}return{session_id:e,running:r,running_items:n,queued:t}}pushQueueSnapshotForSession(e){if(!this.config.eventQueue||!this.pool)return;const i=this.buildQueueSnapshotPayload(e);h.info(this.name,`[queue-debug] push snapshot session=${e} running=${i.running.length} queued=${i.queued.length} running_ids=[${i.running.join(",")}]`),this.aibotHandle.sendQueueSnapshot(i)}replyQueueSnapshotForSession(e){!this.config.eventQueue||!this.pool||this.aibotHandle.sendQueueSnapshot(this.buildQueueSnapshotPayload(e))}async platformInvoke(e,i,r){return e==="file_link"?jn(i):e==="file_upload"?this.uploadFileAndSendMedia(i):this.aibotHandle.agentInvoke(e,i,r)}invokeDshEventTool(e,i){const r=V(this.aibotHandle,e,i),n=r.content[0]?.text??"";if(r.isError)throw new Error(n||`grix event tool "${e}" failed`);try{return JSON.parse(n)}catch{return n}}async uploadFileAndSendMedia(e){const i=String(e.file_path??"").trim(),r=String(e.session_id??"").trim(),n=String(e.caption??"").trim(),t=String(e.reply_to_message_id??"").trim();if(!i)throw new Error("file_path is required");if(!r)throw new Error("session_id is required");const s=await Kn({wsURL:this.config.aibot.url,apiKey:this.config.aibot.apiKey,sessionID:r,filePath:i}),o=await this.aibotHandle.sendMedia({session_id:r,msg_type:2,content:n||`[${s.attachment_type}]`,client_msg_id:`file_upload_${R()}`,...t?{quoted_message_id:t}:{},extra:s.extra});if(o.cmd!=="send_ack"){const l=o.payload??{},d=String(l.msg??o.cmd);throw new Error(`media message send failed: ${d}`)}const a=o.payload??{};return{ok:!0,file_name:s.file_name,attachment_type:s.attachment_type,access_url:s.access_url,message_id:a.msg_id!=null?String(a.msg_id):null}}sendReplyByRuntimeConfig(e,i,r,n,t){const s=this.indexEventSession(e,i)??i;this.auditController.captureReply(e,r),this.sendCtrl.sendReply(e,s,r,n,t),r&&this.conversationLog?.logOutbound?.(s,e,"reply",r)}stampCodexEventQuote(e){if(e.quoted_message_id!=null){if(e.quoted_message_id)return e;const{quoted_message_id:s,...o}=e;return o}const i=e;if(i.codex_method!=="item/agentMessage/delta")return e;const n=i.codex_payload?.params?.phase;if(typeof n=="string"&&n.trim()&&n.trim().toLowerCase()!=="final_answer")return e;const t=this.sendCtrl.getDefaultQuotedMessageId(e.event_id);return t?{...e,quoted_message_id:t}:e}captureCodexAuditOutput(e){if(e.codex_method!=="item/agentMessage/delta")return;const i=e.codex_payload?.params,r=typeof i?.phase=="string"?i.phase.trim().toLowerCase():"";if(r&&r!=="final_answer")return;const n=i?.delta;typeof n!="string"||!n||this.auditController.captureUnsequencedStreamChunk(e.event_id,n)}discardEventTrackingState(e){this.inflightEvents.delete(e),this.restartCount.delete(e),this.eventSessionIndex.delete(e),this.pendingStartedEventIds.delete(e),this.sendCtrl.discardEventState(e)}reliableFinalWiring(e,i){return async(r,n,t)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(r,n,t,i)}catch(s){throw h.error("bridge",`[${e}] sendFinalStreamChunkReliable ACK failed event=${r}: ${s}`),s}h.info("bridge",`[${e}] sendFinalStreamChunkReliable done event=${r}`)}}sendStreamChunkByRuntimeConfig(e,i,r,n,t,s,o){const a=this.indexEventSession(e,i)??i;this.auditController.captureStreamChunk(e,n,r),this.sendCtrl.sendStreamChunk(e,a,r,n,t,s,o),(r||t)&&this.conversationLog?.logOutbound?.(a,e,t?"stream_chunk_finish":"stream_chunk",r)}surfacedRunErrorEvents=new Set;sendRunErrorAsChunk(e,i,r){this.surfacedRunErrorEvents.has(e)||(this.surfacedRunErrorEvents.add(e),this.sendStreamChunkByRuntimeConfig(e,i,`
7
+ Error: ${u}`,1,!1)},sendAgentQuestionCard:(d,l,u)=>{this.sendGrixAgentQuestionCard(d,l,u)},sendPermissionCard:d=>{h.info("bridge","sendPermissionCard callback entered",{rawTransport:n,eventId:d.eventId,sessionId:d.sessionId,toolCallId:d.toolCallId,toolName:d.toolName,toolTitle:d.toolTitle});const l=d.toolInput&&d.toolTitle&&d.toolInput!==d.toolTitle?`${d.toolTitle}: ${d.toolInput}`:d.toolTitle||d.toolInput||d.toolName;if(n){this.sendAcpRawEventEnvelope(d.eventId,d.sessionId,{type:"permission_request",payload:{tool_call_id:d.toolCallId,tool_name:d.toolName,tool_title:d.toolTitle,...d.toolInput?{tool_input:d.toolInput}:{},options:d.options}}),h.info("bridge","sendPermissionCard: sent via rawEventEnvelope",{eventId:d.eventId,toolCallId:d.toolCallId});return}const u=`perm_${R()}`,g={event_id:d.eventId,session_id:d.sessionId,client_msg_id:u,msg_type:1,content:d.toolTitle?`Permission required: ${d.toolTitle}`:"Permission request",extra:{channel_data:{execApproval:{approvalId:d.toolCallId,approvalSlug:d.toolName},grix:{execApproval:{approval_command_id:d.toolCallId,approval_type:"permission",command:l,host:"acp"}}},agent_api_origin:!0}};h.info("bridge","sendPermissionCard: about to invoke aibotHandle.sendMsg",{eventId:d.eventId,sessionId:d.sessionId,clientMsgId:u,toolCallId:d.toolCallId,contentLength:g.content.length});try{this.aibotHandle.sendMsg(g),h.info("bridge","sendPermissionCard: aibotHandle.sendMsg returned",{eventId:d.eventId,clientMsgId:u})}catch(p){h.error("bridge","sendPermissionCard: aibotHandle.sendMsg threw",{eventId:d.eventId,clientMsgId:u,error:p instanceof Error?p.message:String(p)})}},sendAuthNotification:(d,l)=>{d&&this.aibotHandle.sendMsg({session_id:d,msg_type:1,content:l,extra:{biz_card:{version:1,type:"agent_error",payload:{error:{name:"AuthRequired",message:l}}}}})},sendAgentMessage:(d,l)=>{d&&l&&this.aibotHandle.sendMsg({session_id:d,msg_type:1,content:l})},sendUpdateBindingCard:(d,l,u,g)=>{const p={...g??{}};if(!p.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const _=this.providerQuotaToRateLimits(this.cachedProviderQuota);_&&(p.rate_limits=_)}!p.provider_quota&&this.cachedProviderQuota?.success&&(p.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:l,cwd:u,...Object.keys(p).length>0?{meta:p}:{}})},onSkillsUpdate:(d,l)=>{try{this.aibotHandle.sendSkillsUpdate({skills:X(d,w.skills),library_skills:this.buildLibrarySkillsReport(l)})}catch(u){}},onContextWindowUpdated:d=>{this.cachedAcpContextWindow=d,this.cachedAcpContextWindowSampledAtMs=Date.now();const l="usedPercentage"in d?d.usedPercentage.toFixed(1):(d.used/d.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 d?d.usedPercentage:Math.min(100,d.used/d.size*100),p={context_window:{..."usedPercentage"in d?{}:d,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(()=>{}),p.provider_quota=this.cachedProviderQuota;const _=this.providerQuotaToRateLimits(this.cachedProviderQuota);_&&(p.rate_limits=_)}this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:u.cwd,meta:p})}},sendMcpFrame:d=>{this.aibotHandle.sendMcpFrame(e,d)},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},i=e?this.bindingStore.get(e):void 0,t=e?this.auditController.getSession(e):void 0,s=this.config.aibot.clientType==="reasonix"&&t?Ei(this.name,e,t.auditId):void 0,o=this.globalConfigStore?.get(this.name),{initialModel:a,initialMode:c}=Wn({sessionBinding:i,globalDefaults:o,configInitialMode:this.config.acpInitialMode});return e&&a&&!i?.acpModelId&&this.bindingStore.setAcpModelId(e,a),e&&c&&!i?.acpModeId&&this.bindingStore.setAcpModeId(e,c),(a||c)&&h.info(this.name,`[toolbar] hydrate from binding: session=${e} model=${a??"<none>"} mode=${c??"<none>"}`),new S({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv()},r,{acpAuthMethod:this.config.acpAuthMethod,acpInitialMode:c,acpInitialModel:a,acpMcpTools:this.config.acpMcpTools,rawTransport:n,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 Pe(this.config.logDir,`${this.name}-${e}`):null,reasonixAuditTranscriptPath:s,agentType:this.config.aibot.clientType})}async connectAibot(){const n=await new q().connect(this.aibotConfig,{aborted:()=>this.stopped,signal:this.startupAbortController.signal,label:this.name,packetLog:this.packetLog,maxRetries:this.config.connectMaxRetries});if(this.stopped)throw n.disconnect(),new Error("connection aborted");this.aibotHandle=n;const r=this.aibotHandle.authAck;if(this.applyAgentProfile(r?.agent_name,r?.introduction,{source:"auth_ack",respawnOnChange:!1},r?.system_prompt),this.aibotHandle.onEvent(i=>{this.handleAibotEvent(i).catch(t=>{h.error(this.name,`handleAibotEvent failed: ${t}`),this.aibotHandle.sendEventAck({event_id:i.event_id,session_id:i.session_id,received_at:Date.now()});const s=t instanceof Error?t.message:String(t);this.handleStaleCwdError(i,s)||this.aibotHandle.sendEventResult({event_id:i.event_id,status:"failed",msg:s,updated_at:Date.now()})})}),this.aibotHandle.onStop(i=>{try{this.handleAibotStop(i)}catch(t){h.error(this.name,`handleAibotStop failed: ${t}`)}}),this.aibotHandle.onAgentDeleted(i=>{h.warn(this.name,`agent deleted on platform (source=${i?.source??"unknown"}${i?.reason?` reason=${i.reason}`:""}), notifying manager to clean up`);try{this.agentDeletedHandler?.()}catch(t){h.error(this.name,`agentDeletedHandler failed: ${t}`)}}),this.aibotHandle.onShareSet(i=>{try{this.shareSetHandler?.(Array.isArray(i?.shared_to)?i.shared_to:[])}catch(t){h.error(this.name,`onShareSet failed: ${t}`)}}),this.aibotHandle.onProfilePush(i=>{try{this.applyAgentProfile(i?.agent_name,i?.introduction,{source:"profile_push",respawnOnChange:!0},i?.system_prompt)}catch(t){h.error(this.name,`onProfilePush failed: ${t}`)}}),this.aibotHandle.onSkillSync(i=>{if(!this.stopped)try{h.info(this.name,`skill_sync received owner=${i?.owner_id??""} name=${i?.name??""}`),this.skillSyncHandler?.()}catch(t){h.error(this.name,`onSkillSync failed: ${t}`)}}),this.aibotHandle.onRevoke(i=>{this.handleAibotRevoke(i).catch(t=>{h.error(this.name,`handleAibotRevoke failed: ${t}`)})}),this.aibotHandle.onLocalAction(i=>{this.handleAibotLocalAction(i).catch(t=>{h.error(this.name,`handleAibotLocalAction failed: ${t}`)})}),this.aibotHandle.onEventCancel(i=>{h.info(this.name,`recv event_cancel event_id=${i.event_id} session_id=${i.session_id}`),this.handleEventCancel(i).catch(t=>{h.error(this.name,`handleEventCancel failed: ${t}`)})}),this.aibotHandle.onMcpFrame((i,t)=>{const s=this.pool.getSlot(i)?.adapter;s?.deliverMcpFrameToAgent?s.deliverMcpFrameToAgent(t):h.warn(this.name,`mcp_frame: no adapter for session=${i}`)}),this.aibotHandle.onQueueClear(i=>{const t=this.pool.clearQueue(i.session_id);this.aibotHandle.sendQueueClearResult({session_id:i.session_id,canceled_event_ids:t}),this.pushQueueSnapshotForSession(i.session_id)}),typeof this.aibotHandle.onQueueReorder=="function"&&this.aibotHandle.onQueueReorder(i=>{const t=Array.isArray(i.ordered_event_ids)?i.ordered_event_ids.filter(o=>typeof o=="string"&&o.length>0):[],s=this.pool.reorderQueue(i.session_id,t);this.aibotHandle.sendQueueReorderResult({session_id:i.session_id,applied_event_ids:s}),this.pushQueueSnapshotForSession(i.session_id)}),typeof this.aibotHandle.onEventHold=="function"&&this.aibotHandle.onEventHold(i=>{const t=typeof i.session_id=="string"?i.session_id:"",s=typeof i.event_id=="string"?i.event_id:"",o=i.hold!==!1;if(h.info(this.name,`recv event_hold event_id=${s} session_id=${t} hold=${o} reason=${i.reason??""}`),!t||!s){this.aibotHandle.sendEventHoldResult({session_id:t,event_id:s,ok:!1,held:!1,error:"bad_request"});return}const a=typeof i.reason=="string"?i.reason:"",c=typeof i.ttl_ms=="number"?i.ttl_ms:void 0,d=this.pool.holdEvent(t,s,o,a,c),l=d==="ok";this.aibotHandle.sendEventHoldResult({session_id:t,event_id:s,ok:l,held:l?o:!1,...l?{}:{error:d}}),l&&this.pushQueueSnapshotForSession(t)}),typeof this.aibotHandle.onQueueEdit=="function"&&this.aibotHandle.onQueueEdit(i=>{const t=typeof i.session_id=="string"?i.session_id:"",s=typeof i.event_id=="string"?i.event_id:"";if(h.info(this.name,`recv queue_edit event_id=${s} session_id=${t}`),!t||!s){this.aibotHandle.sendQueueEditResult({session_id:t,event_id:s,ok:!1,error:"bad_request"});return}const o=typeof i.content=="string"?i.content:"",a=this.pool.editQueuedEvent(t,s,o),c=a==="ok";this.aibotHandle.sendQueueEditResult({session_id:t,event_id:s,ok:c,...c?{}:{error:a}}),c&&this.pushQueueSnapshotForSession(t)}),typeof this.aibotHandle.onQueueSnapshotQuery=="function"&&this.aibotHandle.onQueueSnapshotQuery(i=>{this.replyQueueSnapshotForSession(i.session_id)}),h.info(this.name,"Connected to aibot"),this.activeEventStore){const i=await this.activeEventStore.drain();if(i.length>0){h.warn(this.name,`Recovering ${i.length} stale event(s) from previous run`);for(const t of i)h.info(this.name,`Failing stale event on startup: ${t}`),this.aibotHandle.sendEventResult({event_id:t,status:"failed",msg:"process restarted, event lost",updated_at:Date.now()})}}this.pushQueueSnapshots(),this.relayStateSyncOnConnect(),this.aibotHandle.onReconnected(()=>{if(this.stopped)return;this.pushQueueSnapshots();const i=this.aibotHandle.authAck;this.applyAgentProfile(i?.agent_name,i?.introduction,{source:"reconnect",respawnOnChange:!0},i?.system_prompt),this.forceRefreshSkills(void 0,{force:!0}),this.skillSyncHandler?.(),this.relayStateSyncOnConnect()}),this.aibotHandle.onStreamRejected((i,t)=>{this.sendCtrl.markEventRejected(i)})}applyAgentProfile(e,n,r,i){const t=String(e??"").trim(),s=String(n??"").trim(),o=i===void 0?this.agentSystemPrompt:String(i),a=t!==this.agentProfile.agentName||s!==this.agentProfile.introduction||o!==this.agentSystemPrompt;this.agentProfile={agentName:t,introduction:s},this.agentSystemPrompt=o,t||s?h.info(this.name,`agent profile (${r.source}): GOT name="${t}" intro_len=${s.length} system_prompt_len=${o.length} changed=${a}`):h.warn(this.name,`agent profile (${r.source}): EMPTY \u2014 \u670D\u52A1\u7AEF\u672A\u4E0B\u53D1 agent_name/introduction\uFF08auth_ack \u5B57\u6BB5\u7F3A\u5931\u6216\u503C\u4E3A\u7A7A\uFF09`),a&&r.respawnOnChange&&this.applyProfileChangeToAdapters("agent_profile_changed")}applyProfileChangeToAdapters(e){if(!this.pool)return;const n=this.pool.getAllSlots();let r=0;for(const o of n)if(o.adapter.onAgentProfileChanged)try{o.adapter.onAgentProfileChanged(),r++}catch(a){h.warn(this.name,`onAgentProfileChanged failed for session=${o.sessionId}: ${a}`)}const i=n.filter(o=>o.adapter instanceof L),t=i.filter(o=>{if(o.state!=="ready")return!1;const a=o.adapter.getStatus();return!a.busy&&!a.backgroundBusy}),s=i.length-t.length;h.info(this.name,`${e}: notified ${r} adapter(s) via hook; respawning ${t.length} idle Claude slot(s), skipping ${s} busy`);for(const o of t)this.pool.removeSlot(o.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 n=this.pool?.getQueueSnapshot(e)??null,r=n?[...n.running]:[],i=n?n.running_items.map(s=>({event_id:s.event_id,...s.content_preview?{content_preview:s.content_preview}:{},...s.title?{title:s.title}:{},...s.summary?{summary:s.summary}:{},actions:[{type:"stop"}]})):[],t=n?n.queued.map(s=>({event_id:s.event_id,position:s.position,...s.content_preview?{content_preview:s.content_preview}:{},...typeof s.content=="string"?{content:s.content}:{},...s.title?{title:s.title}:{},...s.summary?{summary:s.summary}:{},held:s.held===!0,held_reason:s.held_reason??"",actions:[{type:"cancel"}]})):[];if(r.length===0&&this.selfDrivenSessions.has(e)&&this.pool?.getSlot(e)){const s=`selfdrive_${e}`,o=this.selfDrivenLabels.get(e)??"Background task in progress";r.push(s),i.push({event_id:s,content_preview:o,title:o,summary:o,actions:[]})}return{session_id:e,running:r,running_items:i,queued:t}}pushQueueSnapshotForSession(e){if(!this.config.eventQueue||!this.pool)return;const n=this.buildQueueSnapshotPayload(e);h.info(this.name,`[queue-debug] push snapshot session=${e} running=${n.running.length} queued=${n.queued.length} running_ids=[${n.running.join(",")}]`),this.aibotHandle.sendQueueSnapshot(n)}replyQueueSnapshotForSession(e){!this.config.eventQueue||!this.pool||this.aibotHandle.sendQueueSnapshot(this.buildQueueSnapshotPayload(e))}async platformInvoke(e,n,r){return e==="file_link"?jn(n):e==="file_upload"?this.uploadFileAndSendMedia(n):this.aibotHandle.agentInvoke(e,n,r)}invokeDshEventTool(e,n){const r=V(this.aibotHandle,e,n),i=r.content[0]?.text??"";if(r.isError)throw new Error(i||`grix event tool "${e}" failed`);try{return JSON.parse(i)}catch{return i}}async uploadFileAndSendMedia(e){const n=String(e.file_path??"").trim(),r=String(e.session_id??"").trim(),i=String(e.caption??"").trim(),t=String(e.reply_to_message_id??"").trim();if(!n)throw new Error("file_path is required");if(!r)throw new Error("session_id is required");const s=await Kn({wsURL:this.config.aibot.url,apiKey:this.config.aibot.apiKey,sessionID:r,filePath:n}),o=await this.aibotHandle.sendMedia({session_id:r,msg_type:2,content:i||`[${s.attachment_type}]`,client_msg_id:`file_upload_${R()}`,...t?{quoted_message_id:t}:{},extra:s.extra});if(o.cmd!=="send_ack"){const c=o.payload??{},d=String(c.msg??o.cmd);throw new Error(`media message send failed: ${d}`)}const a=o.payload??{};return{ok:!0,file_name:s.file_name,attachment_type:s.attachment_type,access_url:s.access_url,message_id:a.msg_id!=null?String(a.msg_id):null}}sendReplyByRuntimeConfig(e,n,r,i,t){const s=this.indexEventSession(e,n)??n;this.auditController.captureReply(e,r),this.sendCtrl.sendReply(e,s,r,i,t),r&&this.conversationLog?.logOutbound?.(s,e,"reply",r)}stampCodexEventQuote(e){if(e.quoted_message_id!=null){if(e.quoted_message_id)return e;const{quoted_message_id:s,...o}=e;return o}const n=e;if(n.codex_method!=="item/agentMessage/delta")return e;const i=n.codex_payload?.params?.phase;if(typeof i=="string"&&i.trim()&&i.trim().toLowerCase()!=="final_answer")return e;const t=this.sendCtrl.getDefaultQuotedMessageId(e.event_id);return t?{...e,quoted_message_id:t}:e}captureCodexAuditOutput(e){if(e.codex_method!=="item/agentMessage/delta")return;const n=e.codex_payload?.params,r=typeof n?.phase=="string"?n.phase.trim().toLowerCase():"";if(r&&r!=="final_answer")return;const i=n?.delta;typeof i!="string"||!i||this.auditController.captureUnsequencedStreamChunk(e.event_id,i)}discardEventTrackingState(e){this.inflightEvents.delete(e),this.restartCount.delete(e),this.eventSessionIndex.delete(e),this.pendingStartedEventIds.delete(e),this.sendCtrl.discardEventState(e)}reliableFinalWiring(e,n){return async(r,i,t)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(r,i,t,n)}catch(s){throw h.error("bridge",`[${e}] sendFinalStreamChunkReliable ACK failed event=${r}: ${s}`),s}h.info("bridge",`[${e}] sendFinalStreamChunkReliable done event=${r}`)}}sendStreamChunkByRuntimeConfig(e,n,r,i,t,s,o){const a=this.indexEventSession(e,n)??n;this.auditController.captureStreamChunk(e,i,r),this.sendCtrl.sendStreamChunk(e,a,r,i,t,s,o),(r||t)&&this.conversationLog?.logOutbound?.(a,e,t?"stream_chunk_finish":"stream_chunk",r)}surfacedRunErrorEvents=new Set;sendRunErrorAsChunk(e,n,r){this.surfacedRunErrorEvents.has(e)||(this.surfacedRunErrorEvents.add(e),this.sendStreamChunkByRuntimeConfig(e,n,`
8
8
 
9
- Error: ${r}`,1,!1))}sendEventResultWithCleanup(e,i,r,n,t=!1){const s=this.eventSessionIndex.get(e);t&&this.surfacedRunErrorEvents.add(e),i==="failed"&&s&&r?.trim()&&this.sendRunErrorAsChunk(e,s,r),this.auditController.markResponded(e,i,r),this.sendCtrl.sendEventResult(e,i,r,n),s&&(this.pool.eventComplete(e,s)===!1&&h.error(this.name,`Event terminal result could not release queue slot event=${e} session=${s} status=${i}`),this.pushQueueSnapshotForSession(s),this.conversationLog?.logResult?.(s,e,i,r),this.eventSessionIndex.delete(e)),this.inflightEvents.delete(e),this.restartCount.delete(e),this.surfacedRunErrorEvents.delete(e),this.pendingStartedEventIds.delete(e),this.pendingEvents.remove(e).catch(o=>{h.warn(this.name,`Failed to remove terminal event from pending store event=${e}: ${o instanceof Error?o.message:String(o)}`)}),i==="responded"&&(this.config.adapterType??"acp")!=="agy"&&(this.cachedProviderQuotaSampledAtMs=null,this.refreshAndPushProviderQuota(!0).catch(()=>{}))}async handleSessionInternalError(e){const{eventId:i,sessionId:r,errorMsg:n}=e;if(this.stopped)return;const t=this.inflightEvents.get(i);if(!t){h.warn(this.name,`[recovery] no inflight event for internalError event=${i} session=${r}; surface failure directly`),this.sendRunErrorAsChunk(i,r,n),this.sendEventResultWithCleanup(i,"failed",n,"agent_stop_failure");return}const s=(this.restartCount.get(i)??0)+1;this.restartCount.set(i,s);const o=this.config.adapterType??"acp";if(s>P){h.error(this.name,`[recovery] adapter=${o} session=${r} event=${i} restart=${s}/${P} outcome=give-up err=${n}`),this.sendRunErrorAsChunk(i,r,n),this.sendEventResultWithCleanup(i,"failed",n,"agent_stop_failure");return}h.info(this.name,`[recovery] adapter=${o} session=${r} event=${i} restart=${s}/${P} outcome=restarting err=${n}`);const a=this.pool.drainQueuedForSession(r);a.length>0&&h.info(this.name,`[recovery] session=${r} preserved ${a.length} queued sibling event(s) across restart`);try{await this.pool.removeSlot(r)}catch(c){h.warn(this.name,`[recovery] removeSlot failed session=${r}: ${c instanceof Error?c.message:String(c)}`)}if(this.stopped)return;const l=e.replayOriginalContent?t.content:this.resolveRecoveryPrompt(o,t),d={...t,content:l};try{await this.pool.deliverInboundEvent(d)}catch(c){h.error(this.name,`[recovery] redeliver failed event=${i} session=${r}: ${c instanceof Error?c.message:String(c)}`),this.sendEventResultWithCleanup(i,"failed",c instanceof Error?c.message:String(c));return}for(const c of a){if(this.stopped)break;try{await this.pool.deliverInboundEvent(c)}catch(u){h.error(this.name,`[recovery] sibling redeliver failed event=${c.event_id} session=${r}: ${u instanceof Error?u.message:String(u)}`),this.sendEventResultWithCleanup(c.event_id,"failed",u instanceof Error?u.message:String(u))}}}resolveRecoveryPrompt(e,i){return e==="acp"?"continue":i.content}sendThinkingByRuntimeConfig(e,i,r){this.sendCtrl.sendThinking(e,i,r)}bufferStreamChunk(e,i,r,n,t){this.auditController.captureUnsequencedStreamChunk(e,r),this.sendCtrl.bufferOnly(e,i,r,n,t)}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)}async replayPendingEventsOnStartup(){const e=await this.pendingEvents.loadForReplay();if(e.length===0)return;const i=new Set(e.map(n=>n.event.event_id).filter(Boolean)),r=[];h.warn(this.name,`Replaying ${e.length} pending event(s) from previous run`);for(const n of e){if(this.stopped)break;const t=n.event;this.pendingEvents.startReplay(n);try{if(n.kind==="deferred"){const s=this.bindingStore.get(n.sessionId);s?.cwd?(await this.prepareBoundDeferredReplay(n,s.cwd),await this.deliverPendingReplayEvent(t),this.pendingStartedEventIds.has(t.event_id)||r.push(n)):(this.restorePendingReplayAuditTurn(t),this.deferredMgr.defer(n.channel,n.sessionId,t),r.push(n))}else await this.deliverPendingReplayEvent(t),this.pendingStartedEventIds.has(t.event_id)||r.push(n)}catch(s){const o=s instanceof Error?s.message:String(s);h.error(this.name,`Pending event replay failed event=${t.event_id}: ${o}`),this.sendEventResultWithCleanup(t.event_id,"failed",o),this.pendingEvents.markCanceled(t.event_id),await this.pendingEvents.remove(t.event_id).catch(()=>{})}finally{this.pendingEvents.finishReplay(n),await this.pendingEvents.checkpointReplay(i,[...r,...this.pendingEvents.replaySnapshot()])}if(this.stopped)break}this.stopped||(this.pendingEvents.finishAllReplay(),await this.pendingEvents.checkpointReplay(i,r))}failEventIfLifecycleDraining(e,i="connector is draining for restart; control command was not executed"){return this.lifecycleBarrier.isClosed()?(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_lifecycle_draining",msg:i,updated_at:Date.now()}),!0):!1}sendCanceledPendingEventResult(e,i){this.restorePendingReplayAuditTurn(e),this.captureEventRuntimeConfig(e),this.sendEventResultWithCleanup(e.event_id,"canceled",i),this.auditController.markAdapterClosed(e.event_id,{adapterNotStarted:!0})}async deliverPendingReplayEvent(e){this.restorePendingReplayAuditTurn(e),this.captureEventRuntimeConfig(e),await this.pool.deliverInboundEvent(e)}async prepareBoundDeferredReplay(e,i){this.sessionBindings.set(e.sessionId,i),e.channel==="acp"?await this.bindSessionForPool(e.sessionId,i):e.channel==="opencode"&&await this.syncOpenCodeBinding(e.sessionId,i)}restorePendingReplayAuditTurn(e){const i=e.audit;if(!i?.enabled||!i.auditId||!i.capture||!i.profile||!i.scope)return;const r=vi({enabled:!0,scope:i.scope,profile:i.profile,capture:i.capture,...i.retentionDays===void 0?{}:{retentionDays:i.retentionDays}});if(!r.enabled)return;const n=Object.freeze({auditId:i.auditId,businessSessionId:e.session_id,provider:this.resolveAuditProvider(),options:r,createdAt:new Date().toISOString()}),t=this.auditController.startTurn({session:n,eventId:e.event_id,userInput:e.content??"",...e.msg_id===void 0?{}:{originMsgId:e.msg_id},...Number.isFinite(Number(e.created_at))&&Number(e.created_at)>0?{startedAt:new Date(Number(e.created_at)).toISOString()}:{},boundary:{adapterType:this.config.adapterType??"acp"}});t&&(e.audit={...i,auditId:t.auditId,turnId:t.turnId,profile:n.options.profile,capture:{...n.options.capture},rawProviderBody:n.options.capture.rawProviderBody})}indexEventSession(e,i){if(!e||!i)return;const r=this.eventSessionIndex.get(e);return r?(r!==i&&h.warn(this.name,`Ignoring event session mismatch event=${e} indexed=${r} supplied=${i}`),r):(this.eventSessionIndex.set(e,i),i)}shouldDropToolDisplayEvent(e){return this.sendCtrl.shouldDropToolDisplayEvent(e)}shouldDropThinkingDisplayEvent(e){return this.sendCtrl.shouldDropThinkingDisplayEvent(e)}shouldDropCodexDisplayEvent(e,i){return this.sendCtrl.shouldDropCodexDisplayEvent(e,i)}logCodexEventToConversation(e){if(!this.conversationLog||e.codex_method!=="item/agentMessage/delta")return;const r=e.codex_payload?.params?.delta;if(!r)return;const n=this.eventSessionIndex.get(e.event_id)??e.session_id;this.conversationLog.append(n,{ts:Date.now(),dir:"outbound",event_id:e.event_id,kind:"codex_delta",text_len:r.length,content:r})}isAcpRawTransportEnabled(){return(this.config.adapterOptions??{}).raw_transport===!0}shouldDropAcpRawDisplayEvent(e,i){return this.sendCtrl.shouldDropAcpRawDisplayEvent(e,i)}sendAcpRawEventEnvelope(e,i,r){this.shouldDropAcpRawDisplayEvent(e,r.type)||this.deliverRawEventEnvelope(e,i,r,"acp",this.buildAcpRawEventFallbackText(r))}buildAcpRawEventFallbackText(e){const i=String(e.type??"").trim();if(!i)return"[acp] event";switch(i){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] ${i}`}}rawDetailSeq=0;deliverRawEventEnvelope(e,i,r,n,t){const s=ri({envelope:r,fallbackText:t,channelKey:n,allocateRefId:()=>`${e}_rawd_${++this.rawDetailSeq}`}),o=()=>{this.aibotHandle.sendMsg({event_id:e,session_id:i,msg_type:1,content:s.fallbackText,extra:{channel_data:{[n]:{raw_event:s.envelope}},agent_api_origin:!0}})};if(!s.sharded){o();return}h.info("bridge",`${n} raw_event oversized, sharded delivery: event=${e} fields=${s.oversizedFields.map(a=>a.field).join(",")}`),(async()=>{for(const a of s.oversizedFields)await this.sendCtrl.deliverAuxiliaryLargeText(e,i,ai({envelopeType:r.type,field:a.field,fullText:a.fullText}),a.refClientMsgId);o()})().catch(a=>{h.warn("bridge",`${n} raw_event sharded delivery failed event=${e}: ${a}`)})}buildCursorRawEventFallbackText(e){const i=String(e?.type??"").trim(),r=e?.payload&&typeof e.payload=="object"?e.payload:{};switch(i){case"permission_request":return`Permission required: ${String(r.tool_title??r.tool_name??"permission request")}`;case"tool_use":case"tool_call":case"tool_execution_start":return`[tool] ${String(r.tool_name??r.toolName??"tool")}`;case"tool_result":case"tool_execution_end":case"tool_execution_update":return"[tool result]";case"error":return`[error] ${String(r.message??"agent error")}`;default:return i?`[cursor] ${i}`:"[cursor] event"}}sendToolExecutionCard(e,i,r,n){this.sendCtrl.sendToolExecutionCard(e,i,r,n)}sendGrixApprovalCard(e,i){this.aibotHandle.sendMsg({event_id:e.eventId,session_id:e.sessionId,client_msg_id:`perm_${R()}`,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:i}}},agent_api_origin:!0}})}sendGrixAgentQuestionCard(e,i,r){const n=r.questions.map(s=>s.header).join(", "),t=I(`[Agent Question] ${r.request_id}`,"agent_question",r);this.aibotHandle.sendText({event_id:e,session_id:i,content:t,msg_type:1,extra:{card_type:"agent_question",summary_text:n}})}async handleAgentQuestionReplyEvent(e){const i=_n(String(e.content??""));if(!i)return!1;this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const n=this.pool.getSlot(e.session_id)?.adapter,t=n instanceof S?"acp":n instanceof k?"opencode":this.config.adapterType??"unknown",s=n instanceof k?n.handleQuestionReplyEvent(i):n instanceof S?await n.handleQuestionReplyEvent(i):{delivered:!1,errorCode:"interaction_request_not_pending",errorMsg:"The question is no longer pending; the reply was not delivered."};return s.delivered?(h.info(this.name,`[${t}] question reply delivered event=${e.event_id} session=${e.session_id} request=${i.request_id}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()})):(h.warn(this.name,`[${t}] question reply rejected event=${e.event_id} session=${e.session_id} request=${i.request_id} code=${s.errorCode??"interaction_reply_failed"}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:s.errorCode??"interaction_reply_failed",msg:s.errorMsg??"The question reply was not delivered.",updated_at:Date.now()})),!0}async handleExecApprovalResolutionEvent(e){const i=vn(String(e.content??""));if(!i)return!1;this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const n=this.pool.getSlot(e.session_id)?.adapter,t=i.params,s=String(t.tool_call_id??t.approval_command_id??t.approval_id??t.exec_context_id??""),o=n?.handleExecApprovalEvent?await n.handleExecApprovalEvent({...t,event_id:e.event_id,session_id:e.session_id}):{delivered:!1,errorCode:"approval_not_supported",errorMsg:"The current adapter does not support exec approval resolution events."};return o.delivered?(h.info(this.name,`[${this.config.adapterType??"unknown"}] exec approval resolution delivered event=${e.event_id} session=${e.session_id} approval=${s||"-"}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()})):(h.warn(this.name,`[${this.config.adapterType??"unknown"}] exec approval resolution rejected event=${e.event_id} session=${e.session_id} approval=${s||"-"} code=${o.errorCode}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:o.errorCode,msg:o.errorMsg,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 i=this.config.adapterType??"acp",r=fn(e);let n;if(r&&(n=this.lifecycleBarrier.tryEnter()??void 0,!n)){this.failEventIfLifecycleDraining(e);return}try{if(await this.handleCliInstallQuestionReply(e)||(i==="opencode"||i==="acp")&&await this.handleAgentQuestionReplyEvent(e)||await this.handleExecApprovalResolutionEvent(e))return;const t=ei(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 s=t.patch,o=B(e.extra);if(Sn(this,e,i,o))return;if(r){await bn(this,r,e,i,o);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 a;try{a=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(await Cn(this,e,i,wi.has(i),s,a))return;if((this.config.adapterType??"acp")==="acp"){const u=String(e.content??"").trim().match(/^\/(\S+)\s*(.*)/);if(u){const[,g,p]=u,A=this.pool.getSlot(e.session_id)?.adapter;if(A?.execCommand&&(A.getSupportedCommands?.()??[]).some(m=>m.name===g||m.name===`/${g}`)){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});try{const m=await A.execCommand(g,p.trim(),e.session_id);m.status==="options"&&m.data&&this.handleExecCommandOptions(e.session_id,g,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(i==="codex"&&Q(a?.options)){const c=this.pool.getSlot(e.session_id);if(c?.adapter instanceof D&&!c.adapter.hasRawApiCaptureRelay()){const u=c.eventQueue.snapshot(e.session_id);u.running.length===0&&u.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=${u.running.length} queued=${u.queued.length}`)}}const d=this.prepareAuditedInboundEvent(e,s,a);try{const c=await this.pendingEvents.append({kind:"queued",event:d});if(this.pendingEvents.isCanceled(e.event_id)){await this.pendingEvents.remove(e.event_id),this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.sendCanceledPendingEventResult(d,"canceled");return}if(this.lifecycleBarrier.isClosed()){if(!c)throw new Error("pending event store unavailable during lifecycle drain");this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),h.info(this.name,`Persisted inbound event during lifecycle drain: ${e.event_id}`);return}this.captureEventRuntimeConfig(d),await this.pool.deliverInboundEvent(d)}catch(c){await this.pendingEvents.remove(e.event_id).catch(u=>{h.warn(this.name,`Failed to remove undelivered pending event=${e.event_id}: ${u instanceof Error?u.message:String(u)}`)}),this.failUndeliveredInboundEvent(e,c)}}finally{n?.()}}failUndeliveredInboundEvent(e,i){const r=i instanceof Error?i.message:String(i);this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.auditController.closeWithoutAdapter(e.event_id,"failed",r,{deliveryFailed:!0}),this.discardEventTrackingState(e.event_id),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:r,updated_at:Date.now()})}handleCodexSessionControlOpen(e,i){return it(this,e,i)}handleSessionControlForPool(e,i){return st(this,e,i)}handleSessionControlLocalActionForPool(e){return ot(this,e)}handleCodexSessionControlLocalActionOpen(e){return rt(this,e)}handleCursorSessionControlLocalActionOpen(e){return at(this,e)}handlePiSessionControlOpen(e,i){return dt(this,e,i)}handlePiSessionControlRestart(e){return lt(this,e)}handlePiSessionControlRestartLocalAction(e){return ct(this,e)}syncOpenCodeBinding(e,i){return ht(this,e,i)}isWorkspaceFreeClient(){return ut(this)}ensureDefaultBindingForWorkspaceFreeClient(e,i){return pt(this,e,i)}bindSessionForPool(e,i){return gt(this,e,i)}deferredCallbacks(){return ft(this)}handleOpenHumanSessionControlOpen(e,i){return mt(this,e,i)}handleCodeWhaleSessionControlOpen(e,i){return vt(this,e,i)}handleCodeWhaleSessionControlLocalActionOpen(e){return _t(this,e)}handleDeepSeekSessionControlLocalActionOpen(e){return St(this,e)}normalizeClaudeModeId(e){return Ht(this,e)}handleExecCommandOptions(e,i,r){$t(this,e,i,r)}resolveSessionModelId(e){return Qt(this,e)}resolveSessionModeId(e){return It(this,e)}resolveCursorSessionModeId(e){return Ot(this,e)}resolveClaudeSessionEffort(e){return Bt(this,e)}resolveClaudeSessionModeId(e){return Ft(this,e)}currentClaudeModeId(e){return Ut(this,e)}resolveCodexSessionModelId(e){return qt(this,e)}resolveCodexNewSessionGlobalDefault(e,i,r){return Nt(this,e,i,r)}pinCodexGlobalDefault(e,i){return Wt(this,e,i)}buildCursorToolbarMeta(e){return Gt(this,e)}buildAgyToolbarMeta(e,i){return jt(this,e,i)}buildAgyQuotaMeta(e){return Kt(this,e)}sendAgyBindingCard(e,i,r){return zt(this,e,i,r)}refreshAndPushAgyQuota(e,i=!1){return Jt(this,e,i)}handleAgySetModel(e,i){return Yt(this,e,i)}buildClaudeToolbarMeta(e){return Xt(this,e)}providerQuotaToCodexRateLimits(e){return si(e,this.cachedProviderQuotaSampledAtMs??Date.now())}providerQuotaToRateLimits(e){return ii(e,this.cachedProviderQuotaSampledAtMs??Date.now())}async resolveCwdForBinding(e){return Un(e)}failSessionOpen(e,i){return On(this,e,i)}getClaudeWorkerStatus(e){return Bn(this,e)}refreshClaudeWorkerStatusCard(e,i){return Fn(this,e,i)}async ensureSlotStarted(e,i=6e4){return In(this,e,i)}maybeOfferCliInstall(e){Le(this,e)}handleCliInstallQuestionReply(e){return De(this,e)}handleCliInstallInteractionReply(e){return He(this,e)}runConfirmedCliInstall(e,i){return $e(this,e,i)}handleSkillDeleteLocalAction(e){return At(this,e)}handleSkillUploadLocalAction(e){return Et(this,e)}handleSkillEnableLocalAction(e){return wt(this,e)}handleSkillRefreshLocalAction(e){yt(this,e)}handleSkillDisableLocalAction(e){return Rt(this,e)}computeSkillReport(e){return kt(this,e)}reportSessionSkills(e){Tt(this,e)}skillsSyncGroupKey(){return Pt(this)}forceRefreshSkills(e,i){return xt(this,e,i)}adoptSkillsWireHashFromDisk(){Mt(this)}buildLibrarySkillsReport(e){return Lt(this,e)}skillLookupEnv(){return Dt(this)}resolveOrphanTitle(e){return Dn(this,e)}resolveAgentSessionId(e){return Ln(this,e)}providerKeyForAdapter(){return Mn(this)}setResolvedAgentSessionId(e,i){Hn(this,e,i)}normalizePathForCompare(e){return xn(e)}ensureImportedAgentSession(e,i){Tn(this,e,i)}buildOpenedBindingResult(e,i,r="ready"){return kn(this,e,i,r)}buildDshOpenedToolbarMeta(e){return $n(this,e)}dshCatalogDataRoot(){return Qn(this)}hasDiskScanner(){return Pn(this)}unbindSession(e){return Xe(this,e)}handleUnbindTextCommand(e){return Ve(this,e)}handleUnbindLocalAction(e){return Ze(this,e)}handleListSessionsTextCommand(e){return et(this,e)}handleListSessionsLocalAction(e){return tt(this,e)}handleSyncHistoryLocalAction(e){return nt(this,e)}handleSessionControlCommand(e,i){return xe(this,e,i)}handleSessionControlLocalAction(e){return Me(this,e)}handleEventCancel(e){return Qe(this,e)}waitForEventDone(e,i,r){return Ie(this,e,i,r)}handleAibotStop(e){Oe(this,e)}killAndResumeStopSlot(e,i){return Be(this,e,i)}handleAibotRevoke(e){return Fe(this,e)}handleConfigureGatewayProvider(e){return Ue(this,e)}getAuditLocalActionHandler(){return qe(this)}handleAuditLocalAction(e){return Ne(this,e)}handleConnectorRollback(e){return We(this,e)}getRelayStateSyncer(){return Ge(this)}relayStateSyncOnConnect(){je(this)}reportRelayStateLocalChange(){Ke(this)}handleApplyRelayState(e){return ze(this,e)}fetchRelayCredential(e){return Je(this,e)}isSharedInstance(){return Ye(this)}async handleAibotLocalAction(e){if(this.stopped){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"connector_lifecycle_draining",error_msg:"connector is shutting down; local action was not executed"});return}const i=e.action_type??"",r=String((e.params??{}).session_id??""),n=String((e.params??{}).verb??"").trim().toLowerCase();h.debug(this.name,`local_action received action_type=${i} verb=${n||"-"} action_id=${e.action_id} session_id=${r}`);let t;if(i===f.sessionControl&&(t=this.lifecycleBarrier.tryEnter()??void 0,!t)){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"connector_lifecycle_draining",error_msg:"connector is draining for restart; session control was not executed"});return}try{if(i===f.interactionReply&&await this.handleCliInstallInteractionReply(e))return;if(Y(i)){await this.handleAuditLocalAction(e);return}const s=(this.config.adapterType??"acp")==="claude";if(i===f.sessionControl&&n===E.exec&&await this.handleSessionControlLocalAction(e))return;if(i===f.sessionControl&&n===E.listSessions){await this.handleListSessionsLocalAction(e);return}if(i===f.sessionControl&&n===E.syncHistory){await this.handleSyncHistoryLocalAction(e);return}if(i===f.sessionControl&&n===E.unbind){await this.handleUnbindLocalAction(e);return}if(i==="skill_upload"){await this.handleSkillUploadLocalAction(e);return}if(i==="skill_delete"){await this.handleSkillDeleteLocalAction(e);return}if(i==="skill_enable"){await this.handleSkillEnableLocalAction(e);return}if(i==="skill_disable"){await this.handleSkillDisableLocalAction(e);return}if(i==="skill_refresh"){this.handleSkillRefreshLocalAction(e);return}const o=(this.config.adapterType??"acp")==="opencode";if((s&&(i===f.interactionReply||i==="exec_approve"||i==="exec_reject")||o&&i===f.interactionReply)&&(await this.pool.deliverLocalAction(e)).handled||s&&await this.handleSessionControlLocalAction(e))return;if(i===f.sessionControl){await An(this,e,r);return}if(i==="file_list"){await wn(this,e,r);return}if(i==="create_folder"){await En(this,e,r);return}if(i===f.setModel&&(this.config.adapterType??"acp")==="agy"){await this.handleAgySetModel(e,r);return}if(i===f.getSessionUsage){if((this.config.adapterType??"acp")==="deepseek-harness"&&(await this.pool.deliverLocalAction(e,{autoCreateSlot:!!r&&!!this.bindingStore.get(r)?.cwd})).handled)return;await this.handleGetSessionUsage(e,r);return}if(i===f.getRateLimits){if((this.config.adapterType??"acp")==="deepseek-harness"&&(await this.pool.deliverLocalAction(e,{autoCreateSlot:!!r&&!!this.bindingStore.get(r)?.cwd})).handled)return;await this.handleGetRateLimits(e,r);return}const a=(this.config.adapterType??"acp")==="acp",l=(this.config.adapterType??"acp")==="cursor";if((s||a||l)&&i===f.threadCompact){await this.handleThreadCompact(e,r);return}if(i==="connector_rollback"){await this.handleConnectorRollback(e);return}if(i==="connector_upgrade_push"){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{accepted:!0}}),this.upgradeTrigger?.();return}if(i===f.getAgentGlobalConfig){const p=this.globalConfigStore?.get(this.name);this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{agentName:this.name,...p?{config:p}:{config:null}}});return}if(i==="configure_gateway_provider"){await this.handleConfigureGatewayProvider(e);return}if(i==="apply_relay_state"){await this.handleApplyRelayState(e);return}const d=this.config.adapterType??"acp",c=(d==="codex"||d==="cursor"||d==="pi"||d==="openhuman"||d==="opencode"||d==="deepseek-harness"||d==="acp")&&!!r&&!!this.bindingStore.get(r)?.cwd,u=await this.pool.deliverLocalAction(e,{autoCreateSlot:c});if(u.handled){Rn(this,e,r,d,u,p=>T.has(p));return}if((d==="codex"||d==="cursor"||d==="pi"||d==="openhuman"||d==="opencode"||d==="deepseek-harness")&&r&&!this.bindingStore.get(r)?.cwd){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:$.bindingMissing,error_msg:"Session binding missing. Open a workspace first."});return}if(d==="acp"&&(i==="set_mode"||i==="set_model")){await yn(this,e,r,i);return}const g=!!r&&!!this.pool.getSlot(r);this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"unsupported_local_action",error_msg:g?`Action type "${i}" is not supported by the current agent process.`:`No active agent process for this session. The reply to action "${i}" could not be delivered \u2014 please resend it as a new message.`})}finally{t?.()}}handleGetSessionUsage(e,i){return Ct(this,e,i)}handleThreadCompact(e,i){return bt(this,e,i)}handleGetRateLimits(e,i){return cn(this,e,i)}resolveRateLimitWakeSessionId(e,i){return hn(this,e,i)}wakeRateLimitSlot(e,i){return un(this,e,i)}sessionControlCtx(e){const i=this.pool.getSlot(e),r=i?.adapter instanceof S?i.adapter:null,n=(this.config.adapterType??"acp")==="acp",t={bindingStore:this.bindingStore,acpAdapter:r,globalConfigStore:this.globalConfigStore,agentName:this.name,log:h};return{getCwd:()=>this.bindingStore.get(e)?.cwd??this.config.agent.cwd??process.cwd(),getSessionBindings:()=>{if(r)return r.getSessionBindings();const s=this.sessionBindings;if(e&&!s.has(e)){const o=this.bindingStore.get(e);o?.cwd&&s.set(e,o.cwd)}return s},getStatus:()=>this.getStatus(),isAcpAlive:!!r?.isAlive(),getAcpSessionOptions:()=>r?.acpSessionOptions??null,setMode:s=>r?r.setMode(s):Promise.resolve(!1),setModel:s=>r?r.setModel(s):Promise.resolve(!1),acpSetMode:n?(s,o)=>Nn(t,s,o):void 0,acpSetModel:n?(s,o)=>qn(t,s,o):void 0,getPendingApproval:s=>{const o=r?.pendingApprovalEntries.get(s);return o?{requestId:o}:void 0},deletePendingApproval:s=>r?.pendingApprovalEntries.delete(s)??!1,respondPermission:(s,o)=>(r&&r.respondToPermission(s,o),Promise.resolve()),onSessionBound:(s,o)=>{this.bindingStore.set(s,o)},onSessionUnbound:s=>{this.unbindSession(s).catch(o=>{h.warn(this.name,`session unbind cleanup failed: ${o instanceof Error?o.message:String(o)}`)})},cancelActiveRun:()=>(this.config.adapterType??"acp")==="agy"&&i?.adapter instanceof H?(i.adapter.cancelCurrentRun(),Promise.resolve()):i?.adapter?.cancel("")??Promise.resolve(),onModeSet:s=>{const o=this.config.adapterType??"acp";o==="codex"?this.globalConfigStore?.set(this.name,{codexModeId:s}):o==="opencode"?this.bindingStore.setModeId(e,s):T.has(o)||this.globalConfigStore?.set(this.name,{acpInitialMode:s})},onModelSet:s=>{const o=this.config.adapterType??"acp";o==="codex"?this.globalConfigStore?.set(this.name,{codexModelId:s}):o==="opencode"?this.bindingStore.setModelId(e,s):T.has(o)||this.globalConfigStore?.set(this.name,{modelId:s}),this.refreshQuotaAfterModelSwitch(e,s)}}}sessionControlSenders(e){return{sendEventAck:(i,r)=>this.aibotHandle.sendEventAck({event_id:i,session_id:r,received_at:Date.now()}),sendEventResult:(i,r,n)=>this.aibotHandle.sendEventResult({event_id:i,status:r,...n?.msg?{msg:n.msg}:{},...n?.code?{code:n.code}:{},updated_at:Date.now()}),sendLocalActionResult:(i,r,n,t,s)=>this.aibotHandle.sendLocalActionResult({action_id:i,status:r,...n?{result:n}:{},...t?{error_code:t}:{},...s?{error_msg:s}:{}},e)}}resolveBindingChannelKey(e){switch(e){case"claude":return"grix-claude";case"codex":return"codex";case"cursor":return"cursor";case"pi":return"pi";case"openhuman":return"openhuman";case"codewhale":return"codewhale";case"opencode":return"opencode";case"agy":return"acp";case"deepseek-harness":return"deepseek";case"acp":return this.config.aibot.clientType==="qwen"?"qwen":"acp";default:return e}}finalizeThinking(e,i){this.sendCtrl.finalizeThinking(e,i)}logInboundConversation(e){const i=String(e.session_id??"").trim();i&&this.conversationLog?.logInbound(i,{event_id:e.event_id,msg_id:e.msg_id,sender_id:e.sender_id,msg_type:e.msg_type,content:e.content??""})}resolveAuditProvider(){const e=this.config.adapterType??"acp";return e==="claude"||e==="codex"||e==="cursor"||e==="opencode"||e==="pi"||e==="codewhale"||e==="deepseek-harness"||e==="agy"?e:"acp"}sendAuditConfigurationError(e,i){const r=i instanceof Error?i.message:String(i),n=(()=>{const a=B(e.extra);return a.options?.enabled===!0&&a.options.scope==="turn"})(),t=i instanceof mi||i instanceof fi,s=i instanceof Si&&n,o=s?"audit_config_invalid":t?i.code:"audit_config_conflict";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:o,msg:r,updated_at:Date.now()}),t||s)try{this.aibotHandle.sendAuditState(O({state:"failed",eventId:e.event_id,sessionId:e.session_id,...e.msg_id===void 0?{}:{msgId:e.msg_id},errorCode:o,errorMessage:r},Date.now()))}catch{}}markAuditAdapterClosed(e,i){const n=this.pool.getSlot(i)?.adapter.takeAuditBoundary?.(e);this.auditController.markAdapterClosed(e,n)}prepareAuditedInboundEvent(e,i,r){const n=this.buildInboundEvent(e,i),t=this.bindingStore.get(e.session_id),s=t?this.resolveAgentSessionId(t):void 0,o=Number(e.created_at),a=Number.isFinite(o)&&o>0?new Date(o).toISOString():void 0,l=this.auditController.startTurn({session:r,eventId:e.event_id,userInput:e.content??"",...e.msg_id===void 0?{}:{originMsgId:e.msg_id},...a===void 0?{}:{startedAt:a},boundary:{adapterType:this.config.adapterType??"acp",...s?{providerSessionId:s}:{}}});return l&&(n.audit={enabled:!0,auditId:l.auditId,turnId:l.turnId,...r?{scope:r.options.scope,profile:r.options.profile,...r.options.retentionDays===void 0?{}:{retentionDays:r.options.retentionDays},capture:{...r.options.capture}}:{},rawProviderBody:r?.options.capture.rawProviderBody===!0}),n}buildInboundEvent(e,i){const r=Zn(this.sendCtrl.getGlobalRuntimeConfig(),i),n=_i(e.extra);return{event_id:e.event_id,session_id:e.session_id,thread_id:e.thread_id,sender_id:e.sender_id,msg_id:e.msg_id,msg_type:e.msg_type,content:e.content??"",quoted_message_id:e.quoted_message_id,context_messages_json:this.buildContextMessagesJson(e.context_messages),extra_json:n===void 0?void 0:JSON.stringify(n),connector_runtime_config:{response_delivery:r.responseDelivery,tool_events:r.toolEvents,thinking_events:r.thinkingEvents},session_type:e.session_type,created_at:e.created_at}}buildContextMessagesJson(e){if(!e)return;const i=e.filter(r=>!mn(String(r?.content??"")));if(i.length!==0)return JSON.stringify(i)}isStaleEvent(e){const i=Number(e.created_at);return!Number.isFinite(i)||i<=0?!1:Date.now()-i>Ci}setUpgradeTrigger(e){this.upgradeTrigger=e}setDaemonShutdownRequester(e){this.daemonShutdownRequester=e}setLifecycleBusyChecker(e){this.lifecycleBusyChecker=e}setLifecycleAdmissionCloser(e){this.lifecycleAdmissionCloser=e}setLifecycleAdmissionRestorer(e){this.lifecycleAdmissionRestorer=e}closeLifecycleAdmission(){this.lifecycleBarrier.setAutoOpenHandler(e=>{h.warn(this.name,`Lifecycle admission auto-reopened after ${Math.round(e/1e3)}s: a restart was expected but never happened. Admission is open again and events flow; the pending restart or upgrade did not complete.`)}),this.lifecycleBarrier.close()}openLifecycleAdmission(){this.lifecycleBarrier.open()}closeLifecycleAdmissionForRestart(){this.lifecycleAdmissionCloser?this.lifecycleAdmissionCloser():this.closeLifecycleAdmission()}setInstallAgentHandler(e){this.installAgentHandler=e}setAgentDeletedHandler(e){this.agentDeletedHandler=e}setSkillSyncHandler(e){this.skillSyncHandler=e}setShareSetHandler(e){this.shareSetHandler=e}setProviderConfigHandler(e){this.providerConfigHandler=e}setRelayStateApplyPorts(e){this.relayStateApplyPorts=e}}export{oo as AgentInstance,T as PER_SESSION_ADAPTERS};
9
+ Error: ${r}`,1,!1))}sendEventResultWithCleanup(e,n,r,i,t=!1){const s=this.eventSessionIndex.get(e);t&&this.surfacedRunErrorEvents.add(e),n==="failed"&&s&&r?.trim()&&this.sendRunErrorAsChunk(e,s,r),this.auditController.markResponded(e,n,r),this.sendCtrl.sendEventResult(e,n,r,i),s&&(this.pool.eventComplete(e,s)===!1&&h.error(this.name,`Event terminal result could not release queue slot event=${e} session=${s} status=${n}`),this.pushQueueSnapshotForSession(s),this.conversationLog?.logResult?.(s,e,n,r),this.eventSessionIndex.delete(e)),this.inflightEvents.delete(e),this.restartCount.delete(e),this.surfacedRunErrorEvents.delete(e),this.pendingStartedEventIds.delete(e),this.pendingEvents.remove(e).catch(o=>{h.warn(this.name,`Failed to remove terminal event from pending store event=${e}: ${o instanceof Error?o.message:String(o)}`)}),n==="responded"&&(this.config.adapterType??"acp")!=="agy"&&(this.cachedProviderQuotaSampledAtMs=null,this.refreshAndPushProviderQuota(!0).catch(()=>{}))}async handleSessionInternalError(e){const{eventId:n,sessionId:r,errorMsg:i}=e;if(this.stopped)return;const t=this.inflightEvents.get(n);if(!t){h.warn(this.name,`[recovery] no inflight event for internalError event=${n} session=${r}; surface failure directly`),this.sendRunErrorAsChunk(n,r,i),this.sendEventResultWithCleanup(n,"failed",i,"agent_stop_failure");return}const s=(this.restartCount.get(n)??0)+1;this.restartCount.set(n,s);const o=this.config.adapterType??"acp";if(s>P){h.error(this.name,`[recovery] adapter=${o} session=${r} event=${n} restart=${s}/${P} outcome=give-up err=${i}`),this.sendRunErrorAsChunk(n,r,i),this.sendEventResultWithCleanup(n,"failed",i,"agent_stop_failure");return}h.info(this.name,`[recovery] adapter=${o} session=${r} event=${n} restart=${s}/${P} outcome=restarting err=${i}`);const a=this.pool.drainQueuedForSession(r);a.length>0&&h.info(this.name,`[recovery] session=${r} preserved ${a.length} queued sibling event(s) across restart`);try{await this.pool.removeSlot(r)}catch(l){h.warn(this.name,`[recovery] removeSlot failed session=${r}: ${l instanceof Error?l.message:String(l)}`)}if(this.stopped)return;const c=e.replayOriginalContent?t.content:this.resolveRecoveryPrompt(o,t),d={...t,content:c};try{await this.pool.deliverInboundEvent(d)}catch(l){h.error(this.name,`[recovery] redeliver failed event=${n} session=${r}: ${l instanceof Error?l.message:String(l)}`),this.sendEventResultWithCleanup(n,"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=${r}: ${u instanceof Error?u.message:String(u)}`),this.sendEventResultWithCleanup(l.event_id,"failed",u instanceof Error?u.message:String(u))}}}resolveRecoveryPrompt(e,n){return e==="acp"?"continue":n.content}sendThinkingByRuntimeConfig(e,n,r){this.sendCtrl.sendThinking(e,n,r)}bufferStreamChunk(e,n,r,i,t){this.auditController.captureUnsequencedStreamChunk(e,r),this.sendCtrl.bufferOnly(e,n,r,i,t)}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)}async replayPendingEventsOnStartup(){const e=await this.pendingEvents.loadForReplay();if(e.length===0)return;const n=new Set(e.map(i=>i.event.event_id).filter(Boolean)),r=[];h.warn(this.name,`Replaying ${e.length} pending event(s) from previous run`);for(const i of e){if(this.stopped)break;const t=i.event;this.pendingEvents.startReplay(i);try{if(i.kind==="deferred"){const s=this.bindingStore.get(i.sessionId);s?.cwd?(await this.prepareBoundDeferredReplay(i,s.cwd),await this.deliverPendingReplayEvent(t),this.pendingStartedEventIds.has(t.event_id)||r.push(i)):(this.restorePendingReplayAuditTurn(t),this.deferredMgr.defer(i.channel,i.sessionId,t),r.push(i))}else await this.deliverPendingReplayEvent(t),this.pendingStartedEventIds.has(t.event_id)||r.push(i)}catch(s){const o=s instanceof Error?s.message:String(s);h.error(this.name,`Pending event replay failed event=${t.event_id}: ${o}`),this.sendEventResultWithCleanup(t.event_id,"failed",o),this.pendingEvents.markCanceled(t.event_id),await this.pendingEvents.remove(t.event_id).catch(()=>{})}finally{this.pendingEvents.finishReplay(i),await this.pendingEvents.checkpointReplay(n,[...r,...this.pendingEvents.replaySnapshot()])}if(this.stopped)break}this.stopped||(this.pendingEvents.finishAllReplay(),await this.pendingEvents.checkpointReplay(n,r))}failEventIfLifecycleDraining(e,n="connector is draining for restart; control command was not executed"){return this.lifecycleBarrier.isClosed()?(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_lifecycle_draining",msg:n,updated_at:Date.now()}),!0):!1}sendCanceledPendingEventResult(e,n){this.restorePendingReplayAuditTurn(e),this.captureEventRuntimeConfig(e),this.sendEventResultWithCleanup(e.event_id,"canceled",n),this.auditController.markAdapterClosed(e.event_id,{adapterNotStarted:!0})}async deliverPendingReplayEvent(e){this.restorePendingReplayAuditTurn(e),this.captureEventRuntimeConfig(e),await this.pool.deliverInboundEvent(e)}async prepareBoundDeferredReplay(e,n){this.sessionBindings.set(e.sessionId,n),e.channel==="acp"?await this.bindSessionForPool(e.sessionId,n):e.channel==="opencode"&&await this.syncOpenCodeBinding(e.sessionId,n)}restorePendingReplayAuditTurn(e){const n=e.audit;if(!n?.enabled||!n.auditId||!n.capture||!n.profile||!n.scope)return;const r=vi({enabled:!0,scope:n.scope,profile:n.profile,capture:n.capture,...n.retentionDays===void 0?{}:{retentionDays:n.retentionDays}});if(!r.enabled)return;const i=Object.freeze({auditId:n.auditId,businessSessionId:e.session_id,provider:this.resolveAuditProvider(),options:r,createdAt:new Date().toISOString()}),t=this.auditController.startTurn({session:i,eventId:e.event_id,userInput:e.content??"",...e.msg_id===void 0?{}:{originMsgId:e.msg_id},...Number.isFinite(Number(e.created_at))&&Number(e.created_at)>0?{startedAt:new Date(Number(e.created_at)).toISOString()}:{},boundary:{adapterType:this.config.adapterType??"acp"}});t&&(e.audit={...n,auditId:t.auditId,turnId:t.turnId,profile:i.options.profile,capture:{...i.options.capture},rawProviderBody:i.options.capture.rawProviderBody})}indexEventSession(e,n){if(!e||!n)return;const r=this.eventSessionIndex.get(e);return r?(r!==n&&h.warn(this.name,`Ignoring event session mismatch event=${e} indexed=${r} supplied=${n}`),r):(this.eventSessionIndex.set(e,n),n)}shouldDropToolDisplayEvent(e){return this.sendCtrl.shouldDropToolDisplayEvent(e)}shouldDropThinkingDisplayEvent(e){return this.sendCtrl.shouldDropThinkingDisplayEvent(e)}shouldDropCodexDisplayEvent(e,n){return this.sendCtrl.shouldDropCodexDisplayEvent(e,n)}logCodexEventToConversation(e){if(!this.conversationLog||e.codex_method!=="item/agentMessage/delta")return;const r=e.codex_payload?.params?.delta;if(!r)return;const i=this.eventSessionIndex.get(e.event_id)??e.session_id;this.conversationLog.append(i,{ts:Date.now(),dir:"outbound",event_id:e.event_id,kind:"codex_delta",text_len:r.length,content:r})}isAcpRawTransportEnabled(){return(this.config.adapterOptions??{}).raw_transport===!0}shouldDropAcpRawDisplayEvent(e,n){return this.sendCtrl.shouldDropAcpRawDisplayEvent(e,n)}sendAcpRawEventEnvelope(e,n,r){this.shouldDropAcpRawDisplayEvent(e,r.type)||this.deliverRawEventEnvelope(e,n,r,"acp",this.buildAcpRawEventFallbackText(r))}buildAcpRawEventFallbackText(e){const n=String(e.type??"").trim();if(!n)return"[acp] event";switch(n){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] ${n}`}}rawDetailSeq=0;deliverRawEventEnvelope(e,n,r,i,t){const s=ri({envelope:r,fallbackText:t,channelKey:i,allocateRefId:()=>`${e}_rawd_${++this.rawDetailSeq}`}),o=()=>{this.aibotHandle.sendMsg({event_id:e,session_id:n,msg_type:1,content:s.fallbackText,extra:{channel_data:{[i]:{raw_event:s.envelope}},agent_api_origin:!0}})};if(!s.sharded){o();return}h.info("bridge",`${i} raw_event oversized, sharded delivery: event=${e} fields=${s.oversizedFields.map(a=>a.field).join(",")}`),(async()=>{for(const a of s.oversizedFields)await this.sendCtrl.deliverAuxiliaryLargeText(e,n,ai({envelopeType:r.type,field:a.field,fullText:a.fullText}),a.refClientMsgId);o()})().catch(a=>{h.warn("bridge",`${i} raw_event sharded delivery failed event=${e}: ${a}`)})}buildCursorRawEventFallbackText(e){const n=String(e?.type??"").trim(),r=e?.payload&&typeof e.payload=="object"?e.payload:{};switch(n){case"permission_request":return`Permission required: ${String(r.tool_title??r.tool_name??"permission request")}`;case"tool_use":case"tool_call":case"tool_execution_start":return`[tool] ${String(r.tool_name??r.toolName??"tool")}`;case"tool_result":case"tool_execution_end":case"tool_execution_update":return"[tool result]";case"error":return`[error] ${String(r.message??"agent error")}`;default:return n?`[cursor] ${n}`:"[cursor] event"}}sendToolExecutionCard(e,n,r,i){this.sendCtrl.sendToolExecutionCard(e,n,r,i)}sendGrixApprovalCard(e,n){this.aibotHandle.sendMsg({event_id:e.eventId,session_id:e.sessionId,client_msg_id:`perm_${R()}`,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:n}}},agent_api_origin:!0}})}sendGrixAgentQuestionCard(e,n,r){const i=r.questions.map(s=>s.header).join(", "),t=I(`[Agent Question] ${r.request_id}`,"agent_question",r);this.aibotHandle.sendText({event_id:e,session_id:n,content:t,msg_type:1,extra:{card_type:"agent_question",summary_text:i}})}async handleAgentQuestionReplyEvent(e){const n=_n(String(e.content??""));if(!n)return!1;this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const i=this.pool.getSlot(e.session_id)?.adapter,t=i instanceof S?"acp":i instanceof k?"opencode":this.config.adapterType??"unknown",s=i instanceof k?i.handleQuestionReplyEvent(n):i instanceof S?await i.handleQuestionReplyEvent(n):{delivered:!1,errorCode:"interaction_request_not_pending",errorMsg:"The question is no longer pending; the reply was not delivered."};return s.delivered?(h.info(this.name,`[${t}] question reply delivered event=${e.event_id} session=${e.session_id} request=${n.request_id}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()})):(h.warn(this.name,`[${t}] question reply rejected event=${e.event_id} session=${e.session_id} request=${n.request_id} code=${s.errorCode??"interaction_reply_failed"}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:s.errorCode??"interaction_reply_failed",msg:s.errorMsg??"The question reply was not delivered.",updated_at:Date.now()})),!0}async handleExecApprovalResolutionEvent(e){const n=vn(String(e.content??""));if(!n)return!1;this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});const i=this.pool.getSlot(e.session_id)?.adapter,t=n.params,s=String(t.tool_call_id??t.approval_command_id??t.approval_id??t.exec_context_id??""),o=i?.handleExecApprovalEvent?await i.handleExecApprovalEvent({...t,event_id:e.event_id,session_id:e.session_id}):{delivered:!1,errorCode:"approval_not_supported",errorMsg:"The current adapter does not support exec approval resolution events."};return o.delivered?(h.info(this.name,`[${this.config.adapterType??"unknown"}] exec approval resolution delivered event=${e.event_id} session=${e.session_id} approval=${s||"-"}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"responded",updated_at:Date.now()})):(h.warn(this.name,`[${this.config.adapterType??"unknown"}] exec approval resolution rejected event=${e.event_id} session=${e.session_id} approval=${s||"-"} code=${o.errorCode}`),this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",code:o.errorCode,msg:o.errorMsg,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 n=this.config.adapterType??"acp",r=fn(e);let i;if(r&&(i=this.lifecycleBarrier.tryEnter()??void 0,!i)){this.failEventIfLifecycleDraining(e);return}try{if(await this.handleCliInstallQuestionReply(e)||(n==="opencode"||n==="acp")&&await this.handleAgentQuestionReplyEvent(e)||await this.handleExecApprovalResolutionEvent(e))return;const t=ei(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 s=t.patch,o=B(e.extra);if(Sn(this,e,n,o))return;if(r){await bn(this,r,e,n,o);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 a;try{a=this.auditController.resolveSession({sessionId:e.session_id,provider:this.resolveAuditProvider(),extra:e.extra,eventId:e.event_id}).session}catch(l){this.sendAuditConfigurationError(e,l);return}if(await Cn(this,e,n,wi.has(n),s,a))return;if((this.config.adapterType??"acp")==="acp"){const u=String(e.content??"").trim().match(/^\/(\S+)\s*(.*)/);if(u){const[,g,p]=u,A=this.pool.getSlot(e.session_id)?.adapter;if(A?.execCommand&&(A.getSupportedCommands?.()??[]).some(m=>m.name===g||m.name===`/${g}`)){this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()});try{const m=await A.execCommand(g,p.trim(),e.session_id);m.status==="options"&&m.data&&this.handleExecCommandOptions(e.session_id,g,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(n==="codex"&&Q(a?.options)){const l=this.pool.getSlot(e.session_id);if(l?.adapter instanceof D&&!l.adapter.hasRawApiCaptureRelay()){const u=l.eventQueue.snapshot(e.session_id);u.running.length===0&&u.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=${u.running.length} queued=${u.queued.length}`)}}const d=this.prepareAuditedInboundEvent(e,s,a);try{const l=await this.pendingEvents.append({kind:"queued",event:d});if(this.pendingEvents.isCanceled(e.event_id)){await this.pendingEvents.remove(e.event_id),this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.sendCanceledPendingEventResult(d,"canceled");return}if(this.lifecycleBarrier.isClosed()){if(!l)throw new Error("pending event store unavailable during lifecycle drain");this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),h.info(this.name,`Persisted inbound event during lifecycle drain: ${e.event_id}`);return}this.captureEventRuntimeConfig(d),await this.pool.deliverInboundEvent(d)}catch(l){await this.pendingEvents.remove(e.event_id).catch(u=>{h.warn(this.name,`Failed to remove undelivered pending event=${e.event_id}: ${u instanceof Error?u.message:String(u)}`)}),this.failUndeliveredInboundEvent(e,l)}}finally{i?.()}}handleStaleCwdError(e,n){if(!/CWD must be|Bound directory does not exist|Bound path is not a directory/i.test(n)||!e.session_id)return!1;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 i=this.pool.getSlot(e.session_id);i?.adapter instanceof S&&i.adapter.getSessionBindings().delete(e.session_id);const t=this.config.adapterType??"acp",s=this.resolveBindingChannelKey(t);return this.aibotHandle.sendMsg({event_id:e.event_id,session_id:e.session_id,msg_type:1,content:n,extra:{channel_data:{[s]:{sessionBinding:{status:"missing",reason:"binding_stale",error_code:$.invalidCwd}}}},quoted_message_id:e.msg_id}),!0}failUndeliveredInboundEvent(e,n){const r=n instanceof Error?n.message:String(n);h.warn(this.name,`Inbound event undelivered event=${e.event_id} session=${e.session_id}: ${r}`),this.aibotHandle.sendEventAck({event_id:e.event_id,session_id:e.session_id,received_at:Date.now()}),this.auditController.closeWithoutAdapter(e.event_id,"failed",r,{deliveryFailed:!0}),this.discardEventTrackingState(e.event_id),!this.handleStaleCwdError(e,r)&&this.aibotHandle.sendEventResult({event_id:e.event_id,status:"failed",msg:r,updated_at:Date.now()})}handleCodexSessionControlOpen(e,n){return it(this,e,n)}handleSessionControlForPool(e,n){return st(this,e,n)}handleSessionControlLocalActionForPool(e){return ot(this,e)}handleCodexSessionControlLocalActionOpen(e){return rt(this,e)}handleCursorSessionControlLocalActionOpen(e){return at(this,e)}handlePiSessionControlOpen(e,n){return dt(this,e,n)}handlePiSessionControlRestart(e){return lt(this,e)}handlePiSessionControlRestartLocalAction(e){return ct(this,e)}syncOpenCodeBinding(e,n){return ht(this,e,n)}isWorkspaceFreeClient(){return ut(this)}ensureDefaultBindingForWorkspaceFreeClient(e,n){return pt(this,e,n)}bindSessionForPool(e,n){return gt(this,e,n)}deferredCallbacks(){return ft(this)}handleOpenHumanSessionControlOpen(e,n){return mt(this,e,n)}handleCodeWhaleSessionControlOpen(e,n){return vt(this,e,n)}handleCodeWhaleSessionControlLocalActionOpen(e){return _t(this,e)}handleDeepSeekSessionControlLocalActionOpen(e){return St(this,e)}normalizeClaudeModeId(e){return Ht(this,e)}handleExecCommandOptions(e,n,r){$t(this,e,n,r)}resolveSessionModelId(e){return Qt(this,e)}resolveSessionModeId(e){return It(this,e)}resolveCursorSessionModeId(e){return Ot(this,e)}resolveClaudeSessionEffort(e){return Bt(this,e)}resolveClaudeSessionModeId(e){return Ft(this,e)}currentClaudeModeId(e){return Ut(this,e)}resolveCodexSessionModelId(e){return qt(this,e)}resolveCodexNewSessionGlobalDefault(e,n,r){return Nt(this,e,n,r)}pinCodexGlobalDefault(e,n){return Wt(this,e,n)}buildCursorToolbarMeta(e){return Gt(this,e)}buildAgyToolbarMeta(e,n){return jt(this,e,n)}buildAgyQuotaMeta(e){return Kt(this,e)}sendAgyBindingCard(e,n,r){return zt(this,e,n,r)}refreshAndPushAgyQuota(e,n=!1){return Jt(this,e,n)}handleAgySetModel(e,n){return Yt(this,e,n)}buildClaudeToolbarMeta(e){return Xt(this,e)}providerQuotaToCodexRateLimits(e){return si(e,this.cachedProviderQuotaSampledAtMs??Date.now())}providerQuotaToRateLimits(e){return ii(e,this.cachedProviderQuotaSampledAtMs??Date.now())}async resolveCwdForBinding(e){return Un(e)}failSessionOpen(e,n){return On(this,e,n)}getClaudeWorkerStatus(e){return Bn(this,e)}refreshClaudeWorkerStatusCard(e,n){return Fn(this,e,n)}async ensureSlotStarted(e,n=6e4){return In(this,e,n)}maybeOfferCliInstall(e){Le(this,e)}handleCliInstallQuestionReply(e){return De(this,e)}handleCliInstallInteractionReply(e){return He(this,e)}runConfirmedCliInstall(e,n){return $e(this,e,n)}handleSkillDeleteLocalAction(e){return At(this,e)}handleSkillUploadLocalAction(e){return Et(this,e)}handleSkillEnableLocalAction(e){return wt(this,e)}handleSkillRefreshLocalAction(e){yt(this,e)}handleSkillDisableLocalAction(e){return Rt(this,e)}computeSkillReport(e){return kt(this,e)}reportSessionSkills(e){Tt(this,e)}skillsSyncGroupKey(){return Pt(this)}forceRefreshSkills(e,n){return xt(this,e,n)}adoptSkillsWireHashFromDisk(){Mt(this)}buildLibrarySkillsReport(e){return Lt(this,e)}skillLookupEnv(){return Dt(this)}resolveOrphanTitle(e){return Dn(this,e)}resolveAgentSessionId(e){return Ln(this,e)}providerKeyForAdapter(){return Mn(this)}setResolvedAgentSessionId(e,n){Hn(this,e,n)}normalizePathForCompare(e){return xn(e)}ensureImportedAgentSession(e,n){Tn(this,e,n)}buildOpenedBindingResult(e,n,r="ready"){return kn(this,e,n,r)}buildDshOpenedToolbarMeta(e){return $n(this,e)}dshCatalogDataRoot(){return Qn(this)}hasDiskScanner(){return Pn(this)}unbindSession(e){return Xe(this,e)}handleUnbindTextCommand(e){return Ve(this,e)}handleUnbindLocalAction(e){return Ze(this,e)}handleListSessionsTextCommand(e){return et(this,e)}handleListSessionsLocalAction(e){return tt(this,e)}handleSyncHistoryLocalAction(e){return nt(this,e)}handleSessionControlCommand(e,n){return xe(this,e,n)}handleSessionControlLocalAction(e){return Me(this,e)}handleEventCancel(e){return Qe(this,e)}waitForEventDone(e,n,r){return Ie(this,e,n,r)}handleAibotStop(e){Oe(this,e)}killAndResumeStopSlot(e,n){return Be(this,e,n)}handleAibotRevoke(e){return Fe(this,e)}handleConfigureGatewayProvider(e){return Ue(this,e)}getAuditLocalActionHandler(){return qe(this)}handleAuditLocalAction(e){return Ne(this,e)}handleConnectorRollback(e){return We(this,e)}getRelayStateSyncer(){return Ge(this)}relayStateSyncOnConnect(){je(this)}reportRelayStateLocalChange(){Ke(this)}handleApplyRelayState(e){return ze(this,e)}fetchRelayCredential(e){return Je(this,e)}isSharedInstance(){return Ye(this)}async handleAibotLocalAction(e){if(this.stopped){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"connector_lifecycle_draining",error_msg:"connector is shutting down; local action was not executed"});return}const n=e.action_type??"",r=String((e.params??{}).session_id??""),i=String((e.params??{}).verb??"").trim().toLowerCase();h.debug(this.name,`local_action received action_type=${n} verb=${i||"-"} action_id=${e.action_id} session_id=${r}`);let t;if(n===f.sessionControl&&(t=this.lifecycleBarrier.tryEnter()??void 0,!t)){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"connector_lifecycle_draining",error_msg:"connector is draining for restart; session control was not executed"});return}try{if(n===f.interactionReply&&await this.handleCliInstallInteractionReply(e))return;if(Y(n)){await this.handleAuditLocalAction(e);return}const s=(this.config.adapterType??"acp")==="claude";if(n===f.sessionControl&&i===E.exec&&await this.handleSessionControlLocalAction(e))return;if(n===f.sessionControl&&i===E.listSessions){await this.handleListSessionsLocalAction(e);return}if(n===f.sessionControl&&i===E.syncHistory){await this.handleSyncHistoryLocalAction(e);return}if(n===f.sessionControl&&i===E.unbind){await this.handleUnbindLocalAction(e);return}if(n==="skill_upload"){await this.handleSkillUploadLocalAction(e);return}if(n==="skill_delete"){await this.handleSkillDeleteLocalAction(e);return}if(n==="skill_enable"){await this.handleSkillEnableLocalAction(e);return}if(n==="skill_disable"){await this.handleSkillDisableLocalAction(e);return}if(n==="skill_refresh"){this.handleSkillRefreshLocalAction(e);return}const o=(this.config.adapterType??"acp")==="opencode";if((s&&(n===f.interactionReply||n==="exec_approve"||n==="exec_reject")||o&&n===f.interactionReply)&&(await this.pool.deliverLocalAction(e)).handled||s&&await this.handleSessionControlLocalAction(e))return;if(n===f.sessionControl){await An(this,e,r);return}if(n==="file_list"){await wn(this,e,r);return}if(n==="create_folder"){await En(this,e,r);return}if(n===f.setModel&&(this.config.adapterType??"acp")==="agy"){await this.handleAgySetModel(e,r);return}if(n===f.getSessionUsage){if((this.config.adapterType??"acp")==="deepseek-harness"&&(await this.pool.deliverLocalAction(e,{autoCreateSlot:!!r&&!!this.bindingStore.get(r)?.cwd})).handled)return;await this.handleGetSessionUsage(e,r);return}if(n===f.getRateLimits){if((this.config.adapterType??"acp")==="deepseek-harness"&&(await this.pool.deliverLocalAction(e,{autoCreateSlot:!!r&&!!this.bindingStore.get(r)?.cwd})).handled)return;await this.handleGetRateLimits(e,r);return}const a=(this.config.adapterType??"acp")==="acp",c=(this.config.adapterType??"acp")==="cursor";if((s||a||c)&&n===f.threadCompact){await this.handleThreadCompact(e,r);return}if(n==="connector_rollback"){await this.handleConnectorRollback(e);return}if(n==="connector_upgrade_push"){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{accepted:!0}}),this.upgradeTrigger?.();return}if(n===f.getAgentGlobalConfig){const p=this.globalConfigStore?.get(this.name);this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"ok",result:{agentName:this.name,...p?{config:p}:{config:null}}});return}if(n==="configure_gateway_provider"){await this.handleConfigureGatewayProvider(e);return}if(n==="apply_relay_state"){await this.handleApplyRelayState(e);return}const d=this.config.adapterType??"acp",l=(d==="codex"||d==="cursor"||d==="pi"||d==="openhuman"||d==="opencode"||d==="deepseek-harness"||d==="acp")&&!!r&&!!this.bindingStore.get(r)?.cwd,u=await this.pool.deliverLocalAction(e,{autoCreateSlot:l});if(u.handled){Rn(this,e,r,d,u,p=>T.has(p));return}if((d==="codex"||d==="cursor"||d==="pi"||d==="openhuman"||d==="opencode"||d==="deepseek-harness")&&r&&!this.bindingStore.get(r)?.cwd){this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:$.bindingMissing,error_msg:"Session binding missing. Open a workspace first."});return}if(d==="acp"&&(n==="set_mode"||n==="set_model")){await yn(this,e,r,n);return}const g=!!r&&!!this.pool.getSlot(r);this.aibotHandle.sendLocalActionResult({action_id:e.action_id,status:"failed",error_code:"unsupported_local_action",error_msg:g?`Action type "${n}" is not supported by the current agent process.`:`No active agent process for this session. The reply to action "${n}" could not be delivered \u2014 please resend it as a new message.`})}finally{t?.()}}handleGetSessionUsage(e,n){return Ct(this,e,n)}handleThreadCompact(e,n){return bt(this,e,n)}handleGetRateLimits(e,n){return cn(this,e,n)}resolveRateLimitWakeSessionId(e,n){return hn(this,e,n)}wakeRateLimitSlot(e,n){return un(this,e,n)}sessionControlCtx(e){const n=this.pool.getSlot(e),r=n?.adapter instanceof S?n.adapter:null,i=(this.config.adapterType??"acp")==="acp",t={bindingStore:this.bindingStore,acpAdapter:r,globalConfigStore:this.globalConfigStore,agentName:this.name,log:h};return{getCwd:()=>this.bindingStore.get(e)?.cwd??this.config.agent.cwd??process.cwd(),getSessionBindings:()=>{if(r)return r.getSessionBindings();const s=this.sessionBindings;if(e&&!s.has(e)){const o=this.bindingStore.get(e);o?.cwd&&s.set(e,o.cwd)}return s},getStatus:()=>this.getStatus(),isAcpAlive:!!r?.isAlive(),getAcpSessionOptions:()=>r?.acpSessionOptions??null,setMode:s=>r?r.setMode(s):Promise.resolve(!1),setModel:s=>r?r.setModel(s):Promise.resolve(!1),acpSetMode:i?(s,o)=>Nn(t,s,o):void 0,acpSetModel:i?(s,o)=>qn(t,s,o):void 0,getPendingApproval:s=>{const o=r?.pendingApprovalEntries.get(s);return o?{requestId:o}:void 0},deletePendingApproval:s=>r?.pendingApprovalEntries.delete(s)??!1,respondPermission:(s,o)=>(r&&r.respondToPermission(s,o),Promise.resolve()),onSessionBound:(s,o)=>{this.bindingStore.set(s,o)},onSessionUnbound:s=>{this.unbindSession(s).catch(o=>{h.warn(this.name,`session unbind cleanup failed: ${o instanceof Error?o.message:String(o)}`)})},cancelActiveRun:()=>(this.config.adapterType??"acp")==="agy"&&n?.adapter instanceof H?(n.adapter.cancelCurrentRun(),Promise.resolve()):n?.adapter?.cancel("")??Promise.resolve(),onModeSet:s=>{const o=this.config.adapterType??"acp";o==="codex"?this.globalConfigStore?.set(this.name,{codexModeId:s}):o==="opencode"?this.bindingStore.setModeId(e,s):T.has(o)||this.globalConfigStore?.set(this.name,{acpInitialMode:s})},onModelSet:s=>{const o=this.config.adapterType??"acp";o==="codex"?this.globalConfigStore?.set(this.name,{codexModelId:s}):o==="opencode"?this.bindingStore.setModelId(e,s):T.has(o)||this.globalConfigStore?.set(this.name,{modelId:s}),this.refreshQuotaAfterModelSwitch(e,s)}}}sessionControlSenders(e){return{sendEventAck:(n,r)=>this.aibotHandle.sendEventAck({event_id:n,session_id:r,received_at:Date.now()}),sendEventResult:(n,r,i)=>this.aibotHandle.sendEventResult({event_id:n,status:r,...i?.msg?{msg:i.msg}:{},...i?.code?{code:i.code}:{},updated_at:Date.now()}),sendLocalActionResult:(n,r,i,t,s)=>this.aibotHandle.sendLocalActionResult({action_id:n,status:r,...i?{result:i}:{},...t?{error_code:t}:{},...s?{error_msg:s}:{}},e)}}resolveBindingChannelKey(e){switch(e){case"claude":return"grix-claude";case"codex":return"codex";case"cursor":return"cursor";case"pi":return"pi";case"openhuman":return"openhuman";case"codewhale":return"codewhale";case"opencode":return"opencode";case"agy":return"acp";case"deepseek-harness":return"deepseek";case"acp":return this.config.aibot.clientType==="qwen"?"qwen":"acp";default:return e}}finalizeThinking(e,n){this.sendCtrl.finalizeThinking(e,n)}logInboundConversation(e){const n=String(e.session_id??"").trim();n&&this.conversationLog?.logInbound(n,{event_id:e.event_id,msg_id:e.msg_id,sender_id:e.sender_id,msg_type:e.msg_type,content:e.content??""})}resolveAuditProvider(){const e=this.config.adapterType??"acp";return e==="claude"||e==="codex"||e==="cursor"||e==="opencode"||e==="pi"||e==="codewhale"||e==="deepseek-harness"||e==="agy"?e:"acp"}sendAuditConfigurationError(e,n){const r=n instanceof Error?n.message:String(n),i=(()=>{const a=B(e.extra);return a.options?.enabled===!0&&a.options.scope==="turn"})(),t=n instanceof mi||n instanceof fi,s=n instanceof Si&&i,o=s?"audit_config_invalid":t?n.code:"audit_config_conflict";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:o,msg:r,updated_at:Date.now()}),t||s)try{this.aibotHandle.sendAuditState(O({state:"failed",eventId:e.event_id,sessionId:e.session_id,...e.msg_id===void 0?{}:{msgId:e.msg_id},errorCode:o,errorMessage:r},Date.now()))}catch{}}markAuditAdapterClosed(e,n){const i=this.pool.getSlot(n)?.adapter.takeAuditBoundary?.(e);this.auditController.markAdapterClosed(e,i)}prepareAuditedInboundEvent(e,n,r){const i=this.buildInboundEvent(e,n),t=this.bindingStore.get(e.session_id),s=t?this.resolveAgentSessionId(t):void 0,o=Number(e.created_at),a=Number.isFinite(o)&&o>0?new Date(o).toISOString():void 0,c=this.auditController.startTurn({session:r,eventId:e.event_id,userInput:e.content??"",...e.msg_id===void 0?{}:{originMsgId:e.msg_id},...a===void 0?{}:{startedAt:a},boundary:{adapterType:this.config.adapterType??"acp",...s?{providerSessionId:s}:{}}});return c&&(i.audit={enabled:!0,auditId:c.auditId,turnId:c.turnId,...r?{scope:r.options.scope,profile:r.options.profile,...r.options.retentionDays===void 0?{}:{retentionDays:r.options.retentionDays},capture:{...r.options.capture}}:{},rawProviderBody:r?.options.capture.rawProviderBody===!0}),i}buildInboundEvent(e,n){const r=Zn(this.sendCtrl.getGlobalRuntimeConfig(),n),i=_i(e.extra);return{event_id:e.event_id,session_id:e.session_id,thread_id:e.thread_id,sender_id:e.sender_id,msg_id:e.msg_id,msg_type:e.msg_type,content:e.content??"",quoted_message_id:e.quoted_message_id,context_messages_json:this.buildContextMessagesJson(e.context_messages),extra_json:i===void 0?void 0:JSON.stringify(i),connector_runtime_config:{response_delivery:r.responseDelivery,tool_events:r.toolEvents,thinking_events:r.thinkingEvents},session_type:e.session_type,created_at:e.created_at}}buildContextMessagesJson(e){if(!e)return;const n=e.filter(r=>!mn(String(r?.content??"")));if(n.length!==0)return JSON.stringify(n)}isStaleEvent(e){const n=Number(e.created_at);return!Number.isFinite(n)||n<=0?!1:Date.now()-n>Ci}setUpgradeTrigger(e){this.upgradeTrigger=e}setDaemonShutdownRequester(e){this.daemonShutdownRequester=e}setLifecycleBusyChecker(e){this.lifecycleBusyChecker=e}setLifecycleAdmissionCloser(e){this.lifecycleAdmissionCloser=e}setLifecycleAdmissionRestorer(e){this.lifecycleAdmissionRestorer=e}closeLifecycleAdmission(){this.lifecycleBarrier.setAutoOpenHandler(e=>{h.warn(this.name,`Lifecycle admission auto-reopened after ${Math.round(e/1e3)}s: a restart was expected but never happened. Admission is open again and events flow; the pending restart or upgrade did not complete.`)}),this.lifecycleBarrier.close()}openLifecycleAdmission(){this.lifecycleBarrier.open()}closeLifecycleAdmissionForRestart(){this.lifecycleAdmissionCloser?this.lifecycleAdmissionCloser():this.closeLifecycleAdmission()}setInstallAgentHandler(e){this.installAgentHandler=e}setAgentDeletedHandler(e){this.agentDeletedHandler=e}setSkillSyncHandler(e){this.skillSyncHandler=e}setShareSetHandler(e){this.shareSetHandler=e}setProviderConfigHandler(e){this.providerConfigHandler=e}setRelayStateApplyPorts(e){this.relayStateApplyPorts=e}}export{oo as AgentInstance,T as PER_SESSION_ADAPTERS};
@@ -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};
@@ -1 +1 @@
1
- const r=[{name:"grix_query",description:"Search contacts, sessions, message history, messages, or favorited sessions in the Grix/AIBot platform. message_history defaults to the newest one clean text/approval-card message and excludes process/tool cards.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"],description:"Query action type. search_favorite_sessions returns the owner's favorited sessions (supports keyword filter)."},id:{type:"string",description:"Contact ID (contact_search) or Session ID (session_search)."},keyword:{type:"string",description:"Search keyword."},sessionType:{type:"integer",enum:[1,2],description:"Filter by session type (session_search only): 1=private chat, 2=group chat. Omit to return all."},limit:{type:"integer",description:"Max results. message_history defaults to 1 when omitted."},offset:{type:"integer",description:"Result offset."},sessionId:{type:"string",description:"Session ID (message_history, message_search)."},beforeId:{type:"string",description:"Pagination cursor (message_history, message_search)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"]},id:{type:"string"},keyword:{type:"string",maxLength:200},sessionType:{type:"integer",enum:[1,2]},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}}},{name:"grix_audit_data",description:"Read connector-backed conversation audit replay data from Grix/AIBot: manifest, span pages, and content chunks.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get_manifest","list_spans","get_content_chunk"],description:"Audit read action. Start with get_manifest, then call list_spans and/or get_content_chunk based on the manifest."},auditId:{type:"string",description:"Audit ID returned by the audited turn metadata."},revision:{type:"integer",description:"Optional manifest revision to read. Usually use the revision returned by get_manifest."},cursor:{type:"string",description:"Opaque pagination cursor returned by list_spans or get_content_chunk."},limit:{type:"integer",description:"Max span items for list_spans."},contentId:{type:"string",description:"Content reference ID from manifest.content_refs (get_content_chunk only)."},maxBytes:{type:"integer",description:"Max UTF-8 bytes to return for get_content_chunk."}},required:["action","auditId"]},validation:{required:["action","auditId"],properties:{action:{type:"string",enum:["get_manifest","list_spans","get_content_chunk"]},auditId:{type:"string"},revision:{type:"integer",minimum:1},cursor:{type:"string",maxLength:4096},limit:{type:"integer",minimum:1,maximum:200},contentId:{type:"string"},maxBytes:{type:"integer",minimum:1,maximum:131072}}}},{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"],description:"Group action type."},sessionId:{type:"string",description:"Group session ID."},name:{type:"string",description:"Group name (create)."},memberIds:{type:"array",items:{type:"string"},description:"Member IDs to add/remove."},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]},description:"Member types (1=user, 2=agent)."},memberId:{type:"string",description:"Target member ID."},role:{type:"integer",enum:[1,2],description:"New role (1=admin, 2=member)."},memberType:{type:"integer",description:"Member type."},allMembersMuted:{type:"boolean",description:"Whether to mute all members."},isSpeakMuted:{type:"boolean",description:"Whether member is muted."},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted."}},required:["action"]},validation:{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"}}}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform. Do NOT use this to answer the inbound event you are currently handling \u2014 answer in plain text (or the reply tool where available) instead, otherwise the user receives duplicate messages.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Target session ID"},content:{type:"string",description:"Message content"},msgType:{type:"integer",description:"Message type (1=text, default 1)"},quotedMessageId:{type:"string",description:"Message ID to reply to"},threadId:{type:"string",description:"Thread ID for threaded reply"}},required:["sessionId","content"]},validation:{required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Session ID"},msgId:{type:"string",description:"Message ID to unsend"}},required:["sessionId","msgId"]},validation:{required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}}},{name:"grix_file_link",description:"Create a direct, tailnet-only download link for a local file on this host. Use this whenever the user asks you to send, share, give, or deliver a file that exists on the machine where you run (a report, log, build artifact, export, or any local path). It returns a ready-to-use Markdown link in the `markdown` field \u2014 include that exact Markdown link in your reply so the user can click and download the file directly over the shared Tailscale network. The link is reachable only inside the tailnet, so just send it as-is \u2014 no need to worry about or mention any link lifetime. The download link is HTTPS, served by a built-in self-signed CA. The result also returns `ca_install_url`: the first time you share a link with a user (or whenever their browser warns the cert is untrusted), also give them this CA install link so they can install and trust it once \u2014 after that all download links work without warnings. Requires this host to be on a tailnet (Tailscale running).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file on this host to share with the user."},ttl_ms:{type:"integer",description:"Optional link lifetime in milliseconds. Leave unset to use the long default; set only if you deliberately want a short-lived link."}},required:["file_path"]},validation:{required:["file_path"],properties:{file_path:{type:"string",maxLength:4096},ttl_ms:{type:"integer",minimum:1e4,maximum:864e5}}}},{name:"grix_file_upload",description:"Upload a local file to the Grix platform and send it as a media message in the target session. Supports images (jpg/png/webp/gif/bmp/heic/heif), videos (mp4/mov/m4v/webm/mkv/avi), documents (pdf/doc/docx/xls/xlsx/ppt/pptx/txt/md/csv/json/xml), and archives (zip/rar/7z/tar/gz). Max 50 MB. Use this instead of grix_file_link when the file should appear as a native attachment in the chat (visible inline for images/videos), rather than a tailnet download link.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file to upload."},session_id:{type:"string",description:"Target session ID to send the file to."},caption:{type:"string",description:"Optional text caption for the media message."},reply_to_message_id:{type:"string",description:"Optional message ID to quote/reply to."}},required:["file_path","session_id"]},validation:{required:["file_path","session_id"],properties:{file_path:{type:"string",maxLength:4096},session_id:{type:"string"},caption:{type:"string",maxLength:2e3},reply_to_message_id:{type:"string"}}}},{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"],description:"Admin action type."},agentName:{type:"string",description:"Agent name (create_agent)."},introduction:{type:"string",description:"Professional behavioral introduction describing the Agent purpose, responsibilities, operating expectations, and boundaries (create_agent)."},isMain:{type:"boolean",description:"Set as main agent (create_agent)."},agentId:{type:"string",description:"Agent ID (assign_category, rotate_api_key)."},categoryId:{type:"string",description:"Category ID (create_agent, update_category, assign_category)."},name:{type:"string",description:"Category name (create_category, update_category)."},parentId:{type:"string",description:"Parent category ID (create_category, update_category)."},sortOrder:{type:"integer",description:"Sort order (create_category, update_category)."}},required:["action"]},validation:{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"}}}},{name:"grix_call_owner",description:"Call your owner into this session to talk by voice. Use this when, during your work, you need to reach your owner \u2014 to discuss something or to get an approval/review. It sends the owner an offline notification; when they tap it they land directly in this conversation and a voice-brain call is started automatically. Requires the owner to have configured a voice brain. Rate-limited per session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID to call the owner into."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_agent_update",description:"Update the display name and/or text introduction of one of your owner's agents, identified by its numeric agent ID. Provide agent_name, introduction, or both \u2014 at least one is required.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},agent_name:{type:"string",description:"New display name (max 100 characters, must be unique among the owner's agents)."},introduction:{type:"string",description:"New text introduction (max 300 characters)."}},required:["agent_id"]},validation:{required:["agent_id"],properties:{agent_id:{type:"string"},agent_name:{type:"string",maxLength:100},introduction:{type:"string",maxLength:300}}}},{name:"grix_dispatch_agent",description:`Dispatch one of your owner's agents to do work in a given working directory. Provide the target agent numeric ID, the working directory, and a text description of the task. The backend creates a NEW private session between the owner and that agent for each dispatch (it does not reuse past sessions), binds the working directory when the agent type requires it (claude/codex/etc.), and sends the task into the session AS THE OWNER so the agent starts working. Because the task is delivered as the owner, write it in the owner's first-person voice and tone \u2014 phrase it the way the owner would speak directly to the agent (e.g. "\u5E2E\u6211\u2026", "\u4F60\u53BB\u2026"), NOT as a third-person relay or as yourself narrating on the owner's behalf. Provide a short title summarizing the core of the task \u2014 it becomes the new session's title; if omitted the backend derives one from the task text.`,inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},cwd:{type:"string",description:"Absolute working directory where the agent should do the work."},task:{type:"string",description:"Text description of the task to perform, written in the owner's first-person voice and tone \u2014 it is delivered into the session as the owner, so phrase it as the owner speaking directly to the agent, not as a third-person relay."},title:{type:"string",description:"Optional short title (a few words) summarizing the core of the task; used as the new session's title. If omitted, the backend derives a title from the task text."}},required:["agent_id","cwd","task"]},validation:{required:["agent_id","cwd","task"],properties:{agent_id:{type:"string"},cwd:{type:"string",maxLength:4096},task:{type:"string",maxLength:1e4},title:{type:"string",maxLength:255}}}},{name:"grix_session_send",description:"Send a message into a session AS THE OWNER \u2014 it appears as if the owner sent it, NOT as you (the agent). Dispatch callbacks (report_dispatch_result) MUST use this tool, even when you are a member of the callback session: a message sent as yourself cannot quote-wake the dispatcher agent, and your membership is not checked. NEVER use this for your own ordinary replies in a conversation \u2014 that would make your words show up as the owner's message; reply normally (or use grix_message_send to send as yourself) for those. The owner must be a member of the target session. Requires the Send as Owner permission scope \u2014 if rejected for missing permission, surface the error as-is so the owner can grant it; do not fall back to grix_message_send. Optional quoted_message_id quotes a message in the same session (used by dispatch callbacks to wake the dispatcher agent).",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Target session ID."},content:{type:"string",description:"Message content to send as the owner."},quoted_message_id:{type:"string",description:"Optional message ID in the target session to quote/reply to.",pattern:"^[1-9]\\d*$"}},required:["session_id","content"]},validation:{required:["session_id","content"],properties:{session_id:{type:"string"},content:{type:"string",maxLength:1e4},quoted_message_id:{type:"string",pattern:"^[1-9]\\d*$"}}}},{name:"grix_chat_state_query",description:"Query the chat-level task states across all of your owner's sessions (including direct and group chats). Returns one entry per session with a single mutually-exclusive state: running (working), waiting_approval (blocked on your owner to approve/deny), waiting_question (asked the owner a question, awaiting their reply), completed, failed, or idle (no task / stopped). When session_id identifies one completed session, the entry also includes exactly one clean final_result; non-completed and list queries never include message content. Also returns the session title (task_title) for easy identification. Supports pagination (page/page_size) and optional state filtering. Use this to see at a glance which chats are done, still running, or waiting on the owner.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"(Optional) Query a single session by its ID. Omit to return all sessions."},page:{type:"number",description:"(Optional) Page number, starting from 1. Defaults to 1 if omitted."},page_size:{type:"number",description:"(Optional) Number of items per page, max 100. Defaults to 10 if omitted."},state:{type:"string",description:"(Optional) Filter by a specific state: running, waiting_approval, waiting_question, completed, failed, or idle. Omit to return all states."}}},validation:{required:[],properties:{}}},{name:"grix_chat_state_update",description:"Manually update the task state of a specific chat session. Use this to mark a chat as completed, failed, idle, or any other state when you need to override it manually. The reason is written to stop_reason and is optional.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID whose state to update."},state:{type:"string",enum:["running","waiting_approval","waiting_question","completed","failed","idle"],description:"The new state to set. Must be one of: running, waiting_approval, waiting_question, completed, failed, idle."},reason:{type:"string",description:"(Optional) Reason for the state change, written to stop_reason."}}},validation:{required:["session_id","state"],properties:{}}},{name:"grix_access_control",description:"Manage sender access control: pair approval, allow/remove senders, set policy.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"Access control action type."},code:{type:"string",description:"Pairing code (required for pair_approve/pair_deny)."},sender_id:{type:"string",description:"Sender ID (required for allow_sender/remove_sender)."},policy:{type:"string",enum:["allowlist","open","disabled"],description:"Access policy (required for set_policy)."}},required:["action"]},validation:{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"]}}}},{name:"grix_widget_visitor_ban",description:"Ban a widget visitor session: blocks the session and adds its most recent init IP to the owner's global IP ban list (7-day expiry).",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Widget visitor session ID (required)."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_egg_search",description:"Search the Grix egg market (published skill/persona packages the owner can hatch into a new agent or install into an existing one). Keyword matching is per-term AND over name + description + category, so search short keywords (one concept per call) rather than a whole sentence; omit keyword to browse a category. Results include id, name, description, category, install_count, can_create_agent, and existing_agent_client_types.",inputSchema:{type:"object",properties:{keyword:{type:"string",description:"Short search keyword(s); terms are ANDed. Omit to list by category."},categoryId:{type:"string",description:"Optional egg category ID to restrict results."},locale:{type:"string",description:"Optional locale such as zh-CN or en; defaults to the owner's locale."},page:{type:"integer",description:"Page number, starting from 1."},pageSize:{type:"integer",description:"Items per page (1-50), default 20."}}},validation:{required:[],properties:{keyword:{type:"string",maxLength:200},categoryId:{type:"string"},locale:{type:"string",maxLength:16},page:{type:"integer",minimum:1},pageSize:{type:"integer",minimum:1,maximum:50}}}},{name:"grix_egg_get",description:"Get one Grix egg by id \u2014 full description, current version, and whether it can create a new agent or install into existing agents. Use after grix_egg_search to show details before the owner decides to hatch.",inputSchema:{type:"object",properties:{id:{type:"string",description:"Egg ID from grix_egg_search."},locale:{type:"string",description:"Optional locale."},version:{type:"integer",description:"Optional specific version; defaults to the current one."}},required:["id"]},validation:{required:["id"],properties:{id:{type:"string"},locale:{type:"string",maxLength:16},version:{type:"integer",minimum:1}}}},{name:"grix_skill_set",description:"Create, update, or delete one of your owner's custom skills in the platform skill library. The skill library auto-syncs to every machine the owner runs an agent on (a per-machine `grix/skills` directory), so defining a skill here makes it available on all of them. A skill is a plain SKILL.md package (frontmatter + body), same standard as other Grix skills. Provide `name` and the full `content` (the SKILL.md text) to create or overwrite by name. To delete a skill, pass its `name` with an empty `content` string. How and when any agent actually loads/uses a synced skill is arranged by the owner (in a system prompt or in conversation); this tool only manages the library.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name (max 100 characters); unique within the owner. Used as the identifier and the synced directory name."},content:{type:"string",description:"Full SKILL.md text. Pass an empty string to delete the skill by name."}},required:["name","content"]},validation:{required:["name","content"],properties:{name:{type:"string",maxLength:100},content:{type:"string",maxLength:262144}}}},{name:"grix_skill_get",description:"Read one of your owner's custom skills by name (returns its full SKILL.md content), or list the owner's skill library when no name is given. Use this before editing to fetch current content, then call grix_skill_set with the revised text.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name to fetch. Omit to list all skills (names + versions) instead."}}},validation:{required:[],properties:{name:{type:"string",maxLength:100}}}}],a=[{name:"grix_reply",description:"Send your final reply \u2014 the conclusion the user is waiting for \u2014 to the specified session. This is the message the user treats as your answer; deliver your final result here, and use plain text only for brief progress notes while you work. Supports streaming in chunks; the frontend automatically aggregates them into one complete message. The connector quotes the message being answered automatically, so quoted_message_id is optional (set it only to quote a different earlier message).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"Associated event ID from the inbound event."},session_id:{type:"string",description:"Target session ID."},text:{type:"string",description:"Reply text content."},quoted_message_id:{type:"string",description:"Quoted message ID (optional)."},is_final:{type:"boolean",description:"Whether this is a stage-final reply. Advisory only \u2014 does not trigger event completion; completion is handled by the complete tool or Stop hook."}},required:["session_id","text"]},validation:{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"}}}},{name:"grix_complete",description:"Mark event processing as complete, notifying the backend that no more replies are expected.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to complete."},status:{type:"string",enum:["responded","canceled","failed"],description:"Completion status."},msg:{type:"string",description:"Additional note (optional)."}},required:["event_id","status"]},validation:{required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}}},{name:"grix_event_ack",description:"Acknowledge event receipt (usually done automatically by the Dispatcher; agents typically do not need to call this manually).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to acknowledge."},session_id:{type:"string",description:"Session ID."}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'Set the "typing" indicator status for a session.',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Session ID."},active:{type:"boolean",description:"true = typing, false = stopped."},event_id:{type:"string",description:"Associated event ID (optional)."}},required:["session_id","active"]},validation:{required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}}},{name:"grix_status",description:"Query the Grix connection status of the current MCP session.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],b={grix_dispatch_agent:"grix-agent-dispatch",grix_agent_update:"grix-agent-dispatch",grix_query:"grix-query",grix_audit_data:"grix-audit-data",grix_group:"grix-group",grix_message_send:"message-send",grix_message_unsend:"message-unsend",grix_admin:"grix-admin",grix_call_owner:"grix-owner-relay",grix_session_send:"grix-owner-relay",grix_chat_state_query:"grix-chat-state",grix_chat_state_update:"grix-chat-state",grix_status:"grix-chat-state",grix_access_control:"grix-access-control",grix_widget_visitor_ban:"grix-widget-visitor-ban",grix_file_link:"tailnet-file-share"};function w(e){return` Before calling this tool, follow the \`${e}\` skill's procedure first; do not invoke this tool directly without going through that skill's guidance.`}for(const e of[...r,...a]){const t=b[e.name];t&&(e.description+=w(t))}const p=[{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."},final:{type:"boolean",description:"Advisory flag only. It does not complete the event; completion is handled by complete tool or Stop hook."}},required:["chat_id","event_id","text"]}},{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"]},msg:{type:"string"},code:{type:"string"}},required:["event_id","status"]}}],c=new Set(p.map(e=>e.name)),x=new Set(r.map(e=>e.name)),k=new Set(a.map(e=>e.name)),I=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,S=/[A-Za-z0-9._-]+/;function Z(e){return!!(x.has(e)||k.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const q=[...r,...a],A=[...q,...p],V=new Map(A.map(e=>[e.name,e]));function X(e,t){return e==="reply"?{name:"grix_reply",args:_("grix_reply",{event_id:t.event_id,session_id:t.chat_id,text:t.text,quoted_message_id:t.reply_to,is_final:t.final})}:e==="complete"?{name:"grix_complete",args:_("grix_complete",{event_id:t.event_id,status:t.status,msg:t.msg,code:t.code})}:{name:e,args:t}}function l(e){const t=String(e??"").trim();return t?t.match(I)?.[1]:void 0}function u(e){const t=String(e??"").trim();if(!t)return;const n=l(t);if(n)return m(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const o=t.match(/[A-Za-z0-9._-]+/g)??[];for(const s of o)if(!(s==="event_id"||s==="chat_id"||s==="session_id")&&s.length>0)return s;return t.match(S)?.[0]}function m(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return u(t)}function _(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=l(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const o=m(i),d=String(n.session_id??""),s=u(n.session_id),v=/\bevent_id\b|["'<>\s]/.test(d);s&&!(v&&o)?n.session_id=s:o&&(n.session_id=o)}return n}function Y(e){return c.has(e)}function J(e,t){switch(e){case"grix_query":return T(t);case"grix_audit_data":return D(t);case"grix_group":return L(t);case"grix_message_send":return E(t);case"grix_message_unsend":return j(t);case"grix_file_link":return N(t);case"grix_file_upload":return z(t);case"grix_admin":return H(t);case"grix_call_owner":return P(t);case"grix_agent_update":return C(t);case"grix_dispatch_agent":return U(t);case"grix_session_send":return G(t);case"grix_chat_state_query":return R(t);case"grix_chat_state_update":return F(t);case"grix_access_control":return B(t);case"grix_widget_visitor_ban":return W(t);case"grix_egg_search":return O(t);case"grix_egg_get":return M(t);case"grix_skill_set":return $(t);case"grix_skill_get":return Q(t);default:throw new Error(`Unknown tool: ${e}`)}}const g={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search",search_favorite_sessions:"search_favorite_sessions"};function T(e){const t=String(e.action??""),n=g[t];if(!n)throw new Error(`Unknown grix_query action: ${t}`);const i={};return e.id!=null&&(i.id=e.id),e.keyword!=null&&(i.keyword=e.keyword),e.sessionType!=null&&(i.session_type=e.sessionType),e.limit!=null?i.limit=e.limit:t==="message_history"&&(i.limit=1),e.offset!=null&&(i.offset=e.offset),e.sessionId!=null&&(i.session_id=e.sessionId),e.beforeId!=null&&(i.before_id=e.beforeId),{action:n,params:i}}function O(e){const t={};return e.keyword!=null&&(t.keyword=e.keyword),e.categoryId!=null&&(t.category_id=e.categoryId),e.locale!=null&&(t.locale=e.locale),e.page!=null&&(t.page=e.page),e.pageSize!=null&&(t.page_size=e.pageSize),{action:"egg_search",params:t}}function M(e){const t={id:e.id};return e.locale!=null&&(t.locale=e.locale),e.version!=null&&(t.version=e.version),{action:"egg_get",params:t}}const y={get_manifest:"audit_get_manifest",list_spans:"audit_list_spans",get_content_chunk:"audit_get_content_chunk"};function D(e){const t=String(e.action??""),n=y[t];if(!n)throw new Error(`Unknown grix_audit_data action: ${t}`);const i={audit_id:e.auditId};return e.revision!=null&&(i.revision=e.revision),e.cursor!=null&&(i.cursor=e.cursor),e.limit!=null&&(i.limit=e.limit),e.contentId!=null&&(i.content_id=e.contentId),e.maxBytes!=null&&(i.max_bytes=e.maxBytes),{action:n,params:i}}const h={create:"group_create",detail:"group_detail_read",leave:"group_leave_self",add_members:"group_member_add",remove_members:"group_member_remove",update_member_role:"group_member_role_update",update_all_members_muted:"group_all_members_muted_update",update_member_speaking:"group_member_speaking_update",dissolve:"group_dissolve"};function L(e){const t=String(e.action??""),n=h[t];if(!n)throw new Error(`Unknown grix_group action: ${t}`);const i={};return e.sessionId!=null&&(i.session_id=e.sessionId),e.name!=null&&(i.name=e.name),e.memberIds!=null&&(i.member_ids=e.memberIds),e.memberTypes!=null&&(i.member_types=e.memberTypes),e.memberId!=null&&(i.member_id=e.memberId),e.role!=null&&(i.role=e.role),e.memberType!=null&&(i.member_type=e.memberType),e.allMembersMuted!=null&&(i.all_members_muted=e.allMembersMuted),e.isSpeakMuted!=null&&(i.is_speak_muted=e.isSpeakMuted),e.canSpeakWhenAllMuted!=null&&(i.can_speak_when_all_muted=e.canSpeakWhenAllMuted),{action:n,params:i}}function E(e){const t={session_id:e.sessionId,msg_type:e.msgType??1,content:e.content};return e.quotedMessageId!=null&&(t.quoted_message_id=e.quotedMessageId),e.threadId!=null&&(t.thread_id=e.threadId),{action:"send_msg",params:t}}function j(e){return{action:"delete_msg",params:{session_id:e.sessionId,msg_id:e.msgId}}}function N(e){const t={file_path:e.file_path};return e.ttl_ms!=null&&(t.ttl_ms=e.ttl_ms),{action:"file_link",params:t}}function z(e){const t={file_path:e.file_path,session_id:e.session_id};return e.caption!=null&&(t.caption=e.caption),e.reply_to_message_id!=null&&(t.reply_to_message_id=e.reply_to_message_id),{action:"file_upload",params:t,timeoutMs:6e4}}const f={create_agent:"agent_api_create",list_categories:"agent_category_list",create_category:"agent_category_create",update_category:"agent_category_update",assign_category:"agent_category_assign",rotate_api_key:"agent_api_key_rotate"};function P(e){return{action:"call_owner",params:{session_id:e.session_id}}}function C(e){if(e.agent_name==null&&e.introduction==null)throw new Error("grix_agent_update requires agent_name or introduction");const t={agent_id:e.agent_id};return e.agent_name!=null&&(t.agent_name=e.agent_name),e.introduction!=null&&(t.introduction=e.introduction),{action:"agent_introduction_update",params:t}}function U(e){return{action:"dispatch_agent",params:{agent_id:e.agent_id,cwd:e.cwd,task:e.task,title:e.title},timeoutMs:75e3}}function G(e){const t={session_id:e.session_id,content:e.content};return e.quoted_message_id!=null&&String(e.quoted_message_id).trim()!==""&&(t.quoted_message_id=e.quoted_message_id),{action:"session_send",params:t}}function R(e){const t={};return e.session_id!=null&&(t.session_id=e.session_id),e.page!=null&&(t.page=e.page),e.page_size!=null&&(t.page_size=e.page_size),e.state!=null&&(t.state=e.state),{action:"chat_state_query",params:t}}function B(e){const t=String(e.action??""),n=K[t];if(!n)throw new Error(`Unknown grix_access_control action: ${t}`);const i={};return e.code!=null&&(i.code=e.code),e.sender_id!=null&&(i.sender_id=e.sender_id),e.policy!=null&&(i.policy=e.policy),{action:"claude_access_control",params:{verb:n,payload:i},timeoutMs:3e4}}function W(e){return{action:"widget_visitor_ban",params:{session_id:e.session_id}}}function F(e){const t={session_id:e.session_id,state:e.state};return e.reason!=null&&(t.reason=e.reason),{action:"chat_state_update",params:t}}function $(e){return{action:"skill_set",params:{name:e.name,content:e.content},timeoutMs:3e4}}function Q(e){const t={};return e.name!=null&&(t.name=e.name),{action:"skill_get",params:t}}function H(e){const t=String(e.action??""),n=f[t];if(!n)throw new Error(`Unknown grix_admin action: ${t}`);const i={};return e.agentName!=null&&(i.agent_name=e.agentName),e.introduction!=null&&(i.introduction=e.introduction),e.isMain!=null&&(i.is_main=e.isMain),e.agentId!=null&&(i.agent_id=e.agentId),e.categoryId!=null&&(i.category_id=e.categoryId),e.name!=null&&(i.name=e.name),e.parentId!=null&&(i.parent_id=e.parentId),e.sortOrder!=null&&(i.sort_order=e.sortOrder),{action:n,params:i}}const ee=new Set([...Object.values(g),...Object.values(y),...Object.values(h),...Object.values(f),"send_msg","delete_msg","file_link","file_upload","call_owner","agent_introduction_update","dispatch_agent","session_send","chat_state_query","chat_state_update","claude_access_control","widget_visitor_ban","skill_set","skill_get"]),K={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{K as ACCESS_CONTROL_ACTION_MAP,q as ALL_TOOLS,a as EVENT_TOOLS,A as EXPOSED_TOOLS,ee as PHASE1_INVOKE_ACTIONS,x as PHASE1_TOOL_NAMES,k as PHASE2_TOOL_NAMES,r as TOOLS,p as TOOL_ALIASES,V as TOOL_MAP,Y as isAlias,Z as isGrixInternalToolName,X as mapToolAlias,_ as normalizeEventToolArgs,J as toolCallToInvoke};
1
+ const r=[{name:"grix_query",description:"Search contacts, sessions, message history, messages, or favorited sessions in the Grix/AIBot platform. message_history defaults to the newest one clean text/approval-card message and excludes process/tool cards.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"],description:"Query action type. search_favorite_sessions returns the owner's favorited sessions (supports keyword filter)."},id:{type:"string",description:"Contact ID (contact_search) or Session ID (session_search)."},peerId:{type:"string",pattern:"^[1-9]\\d{0,19}$",description:"Peer user ID (session_search only): locate the private chat between the current user and this account exactly, independent of title/nickname/remark. Takes precedence over id/keyword. Use this when you know the target user's ID (e.g. the agent owner). Returns error 4004 when no such private chat exists."},keyword:{type:"string",description:"Search keyword."},sessionType:{type:"integer",enum:[1,2],description:"Filter by session type (session_search only): 1=private chat, 2=group chat. Omit to return all."},limit:{type:"integer",description:"Max results. message_history defaults to 1 when omitted."},offset:{type:"integer",description:"Result offset."},sessionId:{type:"string",description:"Session ID (message_history, message_search)."},beforeId:{type:"string",description:"Pagination cursor (message_history, message_search)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"]},id:{type:"string"},peerId:{type:"string",pattern:"^[1-9]\\d{0,19}$"},keyword:{type:"string",maxLength:200},sessionType:{type:"integer",enum:[1,2]},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}}},{name:"grix_audit_data",description:"Read connector-backed conversation audit replay data from Grix/AIBot: manifest, span pages, and content chunks.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get_manifest","list_spans","get_content_chunk"],description:"Audit read action. Start with get_manifest, then call list_spans and/or get_content_chunk based on the manifest."},auditId:{type:"string",description:"Audit ID returned by the audited turn metadata."},revision:{type:"integer",description:"Optional manifest revision to read. Usually use the revision returned by get_manifest."},cursor:{type:"string",description:"Opaque pagination cursor returned by list_spans or get_content_chunk."},limit:{type:"integer",description:"Max span items for list_spans."},contentId:{type:"string",description:"Content reference ID from manifest.content_refs (get_content_chunk only)."},maxBytes:{type:"integer",description:"Max UTF-8 bytes to return for get_content_chunk."}},required:["action","auditId"]},validation:{required:["action","auditId"],properties:{action:{type:"string",enum:["get_manifest","list_spans","get_content_chunk"]},auditId:{type:"string"},revision:{type:"integer",minimum:1},cursor:{type:"string",maxLength:4096},limit:{type:"integer",minimum:1,maximum:200},contentId:{type:"string"},maxBytes:{type:"integer",minimum:1,maximum:131072}}}},{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"],description:"Group action type."},sessionId:{type:"string",description:"Group session ID."},name:{type:"string",description:"Group name (create)."},memberIds:{type:"array",items:{type:"string"},description:"Member IDs to add/remove."},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]},description:"Member types (1=user, 2=agent)."},memberId:{type:"string",description:"Target member ID."},role:{type:"integer",enum:[1,2],description:"New role (1=admin, 2=member)."},memberType:{type:"integer",description:"Member type."},allMembersMuted:{type:"boolean",description:"Whether to mute all members."},isSpeakMuted:{type:"boolean",description:"Whether member is muted."},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted."}},required:["action"]},validation:{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"}}}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform. Do NOT use this to answer the inbound event you are currently handling \u2014 answer in plain text (or the reply tool where available) instead, otherwise the user receives duplicate messages.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Target session ID"},content:{type:"string",description:"Message content"},msgType:{type:"integer",description:"Message type (1=text, default 1)"},quotedMessageId:{type:"string",description:"Message ID to reply to"},threadId:{type:"string",description:"Thread ID for threaded reply"}},required:["sessionId","content"]},validation:{required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Session ID"},msgId:{type:"string",description:"Message ID to unsend"}},required:["sessionId","msgId"]},validation:{required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}}},{name:"grix_file_link",description:"Create a direct, tailnet-only download link for a local file on this host. Use this whenever the user asks you to send, share, give, or deliver a file that exists on the machine where you run (a report, log, build artifact, export, or any local path). It returns a ready-to-use Markdown link in the `markdown` field \u2014 include that exact Markdown link in your reply so the user can click and download the file directly over the shared Tailscale network. The link is reachable only inside the tailnet, so just send it as-is \u2014 no need to worry about or mention any link lifetime. The download link is HTTPS, served by a built-in self-signed CA. The result also returns `ca_install_url`: the first time you share a link with a user (or whenever their browser warns the cert is untrusted), also give them this CA install link so they can install and trust it once \u2014 after that all download links work without warnings. Requires this host to be on a tailnet (Tailscale running).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file on this host to share with the user."},ttl_ms:{type:"integer",description:"Optional link lifetime in milliseconds. Leave unset to use the long default; set only if you deliberately want a short-lived link."}},required:["file_path"]},validation:{required:["file_path"],properties:{file_path:{type:"string",maxLength:4096},ttl_ms:{type:"integer",minimum:1e4,maximum:864e5}}}},{name:"grix_file_upload",description:"Upload a local file to the Grix platform and send it as a media message in the target session. Supports images (jpg/png/webp/gif/bmp/heic/heif), videos (mp4/mov/m4v/webm/mkv/avi), documents (pdf/doc/docx/xls/xlsx/ppt/pptx/txt/md/csv/json/xml), and archives (zip/rar/7z/tar/gz). Max 50 MB. Use this instead of grix_file_link when the file should appear as a native attachment in the chat (visible inline for images/videos), rather than a tailnet download link.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file to upload."},session_id:{type:"string",description:"Target session ID to send the file to."},caption:{type:"string",description:"Optional text caption for the media message."},reply_to_message_id:{type:"string",description:"Optional message ID to quote/reply to."}},required:["file_path","session_id"]},validation:{required:["file_path","session_id"],properties:{file_path:{type:"string",maxLength:4096},session_id:{type:"string"},caption:{type:"string",maxLength:2e3},reply_to_message_id:{type:"string"}}}},{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"],description:"Admin action type."},agentName:{type:"string",description:"Agent name (create_agent)."},introduction:{type:"string",description:"Professional behavioral introduction describing the Agent purpose, responsibilities, operating expectations, and boundaries (create_agent)."},isMain:{type:"boolean",description:"Set as main agent (create_agent)."},agentId:{type:"string",description:"Agent ID (assign_category, rotate_api_key)."},categoryId:{type:"string",description:"Category ID (create_agent, update_category, assign_category)."},name:{type:"string",description:"Category name (create_category, update_category)."},parentId:{type:"string",description:"Parent category ID (create_category, update_category)."},sortOrder:{type:"integer",description:"Sort order (create_category, update_category)."}},required:["action"]},validation:{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"}}}},{name:"grix_call_owner",description:"Call your owner into this session to talk by voice. Use this when, during your work, you need to reach your owner \u2014 to discuss something or to get an approval/review. It sends the owner an offline notification; when they tap it they land directly in this conversation and a voice-brain call is started automatically. Requires the owner to have configured a voice brain. Rate-limited per session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID to call the owner into."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_agent_update",description:"Update the display name and/or text introduction of one of your owner's agents, identified by its numeric agent ID. Provide agent_name, introduction, or both \u2014 at least one is required.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},agent_name:{type:"string",description:"New display name (max 100 characters, must be unique among the owner's agents)."},introduction:{type:"string",description:"New text introduction (max 300 characters)."}},required:["agent_id"]},validation:{required:["agent_id"],properties:{agent_id:{type:"string"},agent_name:{type:"string",maxLength:100},introduction:{type:"string",maxLength:300}}}},{name:"grix_dispatch_agent",description:`Dispatch one of your owner's agents to do work in a given working directory. Provide the target agent numeric ID, the working directory, and a text description of the task. The backend creates a NEW private session between the owner and that agent for each dispatch (it does not reuse past sessions), binds the working directory when the agent type requires it (claude/codex/etc.), and sends the task into the session AS THE OWNER so the agent starts working. Because the task is delivered as the owner, write it in the owner's first-person voice and tone \u2014 phrase it the way the owner would speak directly to the agent (e.g. "\u5E2E\u6211\u2026", "\u4F60\u53BB\u2026"), NOT as a third-person relay or as yourself narrating on the owner's behalf. Provide a short title summarizing the core of the task \u2014 it becomes the new session's title; if omitted the backend derives one from the task text.`,inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},cwd:{type:"string",description:"Absolute working directory where the agent should do the work."},task:{type:"string",description:"Text description of the task to perform, written in the owner's first-person voice and tone \u2014 it is delivered into the session as the owner, so phrase it as the owner speaking directly to the agent, not as a third-person relay."},title:{type:"string",description:"Optional short title (a few words) summarizing the core of the task; used as the new session's title. If omitted, the backend derives a title from the task text."}},required:["agent_id","cwd","task"]},validation:{required:["agent_id","cwd","task"],properties:{agent_id:{type:"string"},cwd:{type:"string",maxLength:4096},task:{type:"string",maxLength:1e4},title:{type:"string",maxLength:255}}}},{name:"grix_session_send",description:"Send a message into a session AS THE OWNER \u2014 it appears as if the owner sent it, NOT as you (the agent). Dispatch callbacks (report_dispatch_result) MUST use this tool, even when you are a member of the callback session: a message sent as yourself cannot quote-wake the dispatcher agent, and your membership is not checked. NEVER use this for your own ordinary replies in a conversation \u2014 that would make your words show up as the owner's message; reply normally (or use grix_message_send to send as yourself) for those. The owner must be a member of the target session. Requires the Send as Owner permission scope \u2014 if rejected for missing permission, surface the error as-is so the owner can grant it; do not fall back to grix_message_send. Optional quoted_message_id quotes a message in the same session (used by dispatch callbacks to wake the dispatcher agent).",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Target session ID."},content:{type:"string",description:"Message content to send as the owner."},quoted_message_id:{type:"string",description:"Optional message ID in the target session to quote/reply to.",pattern:"^[1-9]\\d*$"}},required:["session_id","content"]},validation:{required:["session_id","content"],properties:{session_id:{type:"string"},content:{type:"string",maxLength:1e4},quoted_message_id:{type:"string",pattern:"^[1-9]\\d*$"}}}},{name:"grix_chat_state_query",description:"Query the chat-level task states across all of your owner's sessions (including direct and group chats). Returns one entry per session with a single mutually-exclusive state: running (working), waiting_approval (blocked on your owner to approve/deny), waiting_question (asked the owner a question, awaiting their reply), completed, failed, or idle (no task / stopped). When session_id identifies one completed session, the entry also includes exactly one clean final_result; non-completed and list queries never include message content. Also returns the session title (task_title) for easy identification. Supports pagination (page/page_size) and optional state filtering. Use this to see at a glance which chats are done, still running, or waiting on the owner.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"(Optional) Query a single session by its ID. Omit to return all sessions."},page:{type:"number",description:"(Optional) Page number, starting from 1. Defaults to 1 if omitted."},page_size:{type:"number",description:"(Optional) Number of items per page, max 100. Defaults to 10 if omitted."},state:{type:"string",description:"(Optional) Filter by a specific state: running, waiting_approval, waiting_question, completed, failed, or idle. Omit to return all states."}}},validation:{required:[],properties:{}}},{name:"grix_chat_state_update",description:"Manually update the task state of a specific chat session. Use this to mark a chat as completed, failed, idle, or any other state when you need to override it manually. The reason is written to stop_reason and is optional.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID whose state to update."},state:{type:"string",enum:["running","waiting_approval","waiting_question","completed","failed","idle"],description:"The new state to set. Must be one of: running, waiting_approval, waiting_question, completed, failed, idle."},reason:{type:"string",description:"(Optional) Reason for the state change, written to stop_reason."}}},validation:{required:["session_id","state"],properties:{}}},{name:"grix_access_control",description:"Manage sender access control: pair approval, allow/remove senders, set policy.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"Access control action type."},code:{type:"string",description:"Pairing code (required for pair_approve/pair_deny)."},sender_id:{type:"string",description:"Sender ID (required for allow_sender/remove_sender)."},policy:{type:"string",enum:["allowlist","open","disabled"],description:"Access policy (required for set_policy)."}},required:["action"]},validation:{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"]}}}},{name:"grix_widget_visitor_ban",description:"Ban a widget visitor session: blocks the session and adds its most recent init IP to the owner's global IP ban list (7-day expiry).",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Widget visitor session ID (required)."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_egg_search",description:"Search the Grix egg market (published skill/persona packages the owner can hatch into a new agent or install into an existing one). Keyword matching is per-term AND over name + description + category, so search short keywords (one concept per call) rather than a whole sentence; omit keyword to browse a category. Results include id, name, description, category, install_count, can_create_agent, and existing_agent_client_types.",inputSchema:{type:"object",properties:{keyword:{type:"string",description:"Short search keyword(s); terms are ANDed. Omit to list by category."},categoryId:{type:"string",description:"Optional egg category ID to restrict results."},locale:{type:"string",description:"Optional locale such as zh-CN or en; defaults to the owner's locale."},page:{type:"integer",description:"Page number, starting from 1."},pageSize:{type:"integer",description:"Items per page (1-50), default 20."}}},validation:{required:[],properties:{keyword:{type:"string",maxLength:200},categoryId:{type:"string"},locale:{type:"string",maxLength:16},page:{type:"integer",minimum:1},pageSize:{type:"integer",minimum:1,maximum:50}}}},{name:"grix_egg_get",description:"Get one Grix egg by id \u2014 full description, current version, and whether it can create a new agent or install into existing agents. Use after grix_egg_search to show details before the owner decides to hatch.",inputSchema:{type:"object",properties:{id:{type:"string",description:"Egg ID from grix_egg_search."},locale:{type:"string",description:"Optional locale."},version:{type:"integer",description:"Optional specific version; defaults to the current one."}},required:["id"]},validation:{required:["id"],properties:{id:{type:"string"},locale:{type:"string",maxLength:16},version:{type:"integer",minimum:1}}}},{name:"grix_skill_set",description:"Create, update, or delete one of your owner's custom skills in the platform skill library. The skill library auto-syncs to every machine the owner runs an agent on (a per-machine `grix/skills` directory), so defining a skill here makes it available on all of them. A skill is a plain SKILL.md package (frontmatter + body), same standard as other Grix skills. Provide `name` and the full `content` (the SKILL.md text) to create or overwrite by name. To delete a skill, pass its `name` with an empty `content` string. How and when any agent actually loads/uses a synced skill is arranged by the owner (in a system prompt or in conversation); this tool only manages the library.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name (max 100 characters); unique within the owner. Used as the identifier and the synced directory name."},content:{type:"string",description:"Full SKILL.md text. Pass an empty string to delete the skill by name."}},required:["name","content"]},validation:{required:["name","content"],properties:{name:{type:"string",maxLength:100},content:{type:"string",maxLength:262144}}}},{name:"grix_skill_get",description:"Read one of your owner's custom skills by name (returns its full SKILL.md content), or list the owner's skill library when no name is given. Use this before editing to fetch current content, then call grix_skill_set with the revised text.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name to fetch. Omit to list all skills (names + versions) instead."}}},validation:{required:[],properties:{name:{type:"string",maxLength:100}}}}],a=[{name:"grix_reply",description:"Send your final reply \u2014 the conclusion the user is waiting for \u2014 to the specified session. This is the message the user treats as your answer; deliver your final result here, and use plain text only for brief progress notes while you work. Supports streaming in chunks; the frontend automatically aggregates them into one complete message. The connector quotes the message being answered automatically, so quoted_message_id is optional (set it only to quote a different earlier message).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"Associated event ID from the inbound event."},session_id:{type:"string",description:"Target session ID."},text:{type:"string",description:"Reply text content."},quoted_message_id:{type:"string",description:"Quoted message ID (optional)."},is_final:{type:"boolean",description:"Whether this is a stage-final reply. Advisory only \u2014 does not trigger event completion; completion is handled by the complete tool or Stop hook."}},required:["session_id","text"]},validation:{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"}}}},{name:"grix_complete",description:"Mark event processing as complete, notifying the backend that no more replies are expected.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to complete."},status:{type:"string",enum:["responded","canceled","failed"],description:"Completion status."},msg:{type:"string",description:"Additional note (optional)."}},required:["event_id","status"]},validation:{required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}}},{name:"grix_event_ack",description:"Acknowledge event receipt (usually done automatically by the Dispatcher; agents typically do not need to call this manually).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to acknowledge."},session_id:{type:"string",description:"Session ID."}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'Set the "typing" indicator status for a session.',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Session ID."},active:{type:"boolean",description:"true = typing, false = stopped."},event_id:{type:"string",description:"Associated event ID (optional)."}},required:["session_id","active"]},validation:{required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}}},{name:"grix_status",description:"Query the Grix connection status of the current MCP session.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],b={grix_dispatch_agent:"grix-agent-dispatch",grix_agent_update:"grix-agent-dispatch",grix_query:"grix-query",grix_audit_data:"grix-audit-data",grix_group:"grix-group",grix_message_send:"message-send",grix_message_unsend:"message-unsend",grix_admin:"grix-admin",grix_call_owner:"grix-owner-relay",grix_session_send:"grix-owner-relay",grix_chat_state_query:"grix-chat-state",grix_chat_state_update:"grix-chat-state",grix_status:"grix-chat-state",grix_access_control:"grix-access-control",grix_widget_visitor_ban:"grix-widget-visitor-ban",grix_file_link:"tailnet-file-share"};function w(e){return` Before calling this tool, follow the \`${e}\` skill's procedure first; do not invoke this tool directly without going through that skill's guidance.`}for(const e of[...r,...a]){const t=b[e.name];t&&(e.description+=w(t))}const p=[{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."},final:{type:"boolean",description:"Advisory flag only. It does not complete the event; completion is handled by complete tool or Stop hook."}},required:["chat_id","event_id","text"]}},{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"]},msg:{type:"string"},code:{type:"string"}},required:["event_id","status"]}}],c=new Set(p.map(e=>e.name)),x=new Set(r.map(e=>e.name)),k=new Set(a.map(e=>e.name)),I=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,S=/[A-Za-z0-9._-]+/;function Z(e){return!!(x.has(e)||k.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const q=[...r,...a],A=[...q,...p],V=new Map(A.map(e=>[e.name,e]));function X(e,t){return e==="reply"?{name:"grix_reply",args:_("grix_reply",{event_id:t.event_id,session_id:t.chat_id,text:t.text,quoted_message_id:t.reply_to,is_final:t.final})}:e==="complete"?{name:"grix_complete",args:_("grix_complete",{event_id:t.event_id,status:t.status,msg:t.msg,code:t.code})}:{name:e,args:t}}function l(e){const t=String(e??"").trim();return t?t.match(I)?.[1]:void 0}function u(e){const t=String(e??"").trim();if(!t)return;const n=l(t);if(n)return m(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const o=t.match(/[A-Za-z0-9._-]+/g)??[];for(const s of o)if(!(s==="event_id"||s==="chat_id"||s==="session_id")&&s.length>0)return s;return t.match(S)?.[0]}function m(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return u(t)}function _(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=l(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const o=m(i),d=String(n.session_id??""),s=u(n.session_id),v=/\bevent_id\b|["'<>\s]/.test(d);s&&!(v&&o)?n.session_id=s:o&&(n.session_id=o)}return n}function Y(e){return c.has(e)}function J(e,t){switch(e){case"grix_query":return T(t);case"grix_audit_data":return D(t);case"grix_group":return L(t);case"grix_message_send":return E(t);case"grix_message_unsend":return j(t);case"grix_file_link":return N(t);case"grix_file_upload":return z(t);case"grix_admin":return H(t);case"grix_call_owner":return P(t);case"grix_agent_update":return U(t);case"grix_dispatch_agent":return C(t);case"grix_session_send":return G(t);case"grix_chat_state_query":return R(t);case"grix_chat_state_update":return $(t);case"grix_access_control":return B(t);case"grix_widget_visitor_ban":return W(t);case"grix_egg_search":return O(t);case"grix_egg_get":return M(t);case"grix_skill_set":return F(t);case"grix_skill_get":return Q(t);default:throw new Error(`Unknown tool: ${e}`)}}const g={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search",search_favorite_sessions:"search_favorite_sessions"};function T(e){const t=String(e.action??""),n=g[t];if(!n)throw new Error(`Unknown grix_query action: ${t}`);const i={};return e.id!=null&&(i.id=e.id),e.peerId!=null&&(i.peer_id=e.peerId),e.keyword!=null&&(i.keyword=e.keyword),e.sessionType!=null&&(i.session_type=e.sessionType),e.limit!=null?i.limit=e.limit:t==="message_history"&&(i.limit=1),e.offset!=null&&(i.offset=e.offset),e.sessionId!=null&&(i.session_id=e.sessionId),e.beforeId!=null&&(i.before_id=e.beforeId),{action:n,params:i}}function O(e){const t={};return e.keyword!=null&&(t.keyword=e.keyword),e.categoryId!=null&&(t.category_id=e.categoryId),e.locale!=null&&(t.locale=e.locale),e.page!=null&&(t.page=e.page),e.pageSize!=null&&(t.page_size=e.pageSize),{action:"egg_search",params:t}}function M(e){const t={id:e.id};return e.locale!=null&&(t.locale=e.locale),e.version!=null&&(t.version=e.version),{action:"egg_get",params:t}}const y={get_manifest:"audit_get_manifest",list_spans:"audit_list_spans",get_content_chunk:"audit_get_content_chunk"};function D(e){const t=String(e.action??""),n=y[t];if(!n)throw new Error(`Unknown grix_audit_data action: ${t}`);const i={audit_id:e.auditId};return e.revision!=null&&(i.revision=e.revision),e.cursor!=null&&(i.cursor=e.cursor),e.limit!=null&&(i.limit=e.limit),e.contentId!=null&&(i.content_id=e.contentId),e.maxBytes!=null&&(i.max_bytes=e.maxBytes),{action:n,params:i}}const h={create:"group_create",detail:"group_detail_read",leave:"group_leave_self",add_members:"group_member_add",remove_members:"group_member_remove",update_member_role:"group_member_role_update",update_all_members_muted:"group_all_members_muted_update",update_member_speaking:"group_member_speaking_update",dissolve:"group_dissolve"};function L(e){const t=String(e.action??""),n=h[t];if(!n)throw new Error(`Unknown grix_group action: ${t}`);const i={};return e.sessionId!=null&&(i.session_id=e.sessionId),e.name!=null&&(i.name=e.name),e.memberIds!=null&&(i.member_ids=e.memberIds),e.memberTypes!=null&&(i.member_types=e.memberTypes),e.memberId!=null&&(i.member_id=e.memberId),e.role!=null&&(i.role=e.role),e.memberType!=null&&(i.member_type=e.memberType),e.allMembersMuted!=null&&(i.all_members_muted=e.allMembersMuted),e.isSpeakMuted!=null&&(i.is_speak_muted=e.isSpeakMuted),e.canSpeakWhenAllMuted!=null&&(i.can_speak_when_all_muted=e.canSpeakWhenAllMuted),{action:n,params:i}}function E(e){const t={session_id:e.sessionId,msg_type:e.msgType??1,content:e.content};return e.quotedMessageId!=null&&(t.quoted_message_id=e.quotedMessageId),e.threadId!=null&&(t.thread_id=e.threadId),{action:"send_msg",params:t}}function j(e){return{action:"delete_msg",params:{session_id:e.sessionId,msg_id:e.msgId}}}function N(e){const t={file_path:e.file_path};return e.ttl_ms!=null&&(t.ttl_ms=e.ttl_ms),{action:"file_link",params:t}}function z(e){const t={file_path:e.file_path,session_id:e.session_id};return e.caption!=null&&(t.caption=e.caption),e.reply_to_message_id!=null&&(t.reply_to_message_id=e.reply_to_message_id),{action:"file_upload",params:t,timeoutMs:6e4}}const f={create_agent:"agent_api_create",list_categories:"agent_category_list",create_category:"agent_category_create",update_category:"agent_category_update",assign_category:"agent_category_assign",rotate_api_key:"agent_api_key_rotate"};function P(e){return{action:"call_owner",params:{session_id:e.session_id}}}function U(e){if(e.agent_name==null&&e.introduction==null)throw new Error("grix_agent_update requires agent_name or introduction");const t={agent_id:e.agent_id};return e.agent_name!=null&&(t.agent_name=e.agent_name),e.introduction!=null&&(t.introduction=e.introduction),{action:"agent_introduction_update",params:t}}function C(e){return{action:"dispatch_agent",params:{agent_id:e.agent_id,cwd:e.cwd,task:e.task,title:e.title},timeoutMs:75e3}}function G(e){const t={session_id:e.session_id,content:e.content};return e.quoted_message_id!=null&&String(e.quoted_message_id).trim()!==""&&(t.quoted_message_id=e.quoted_message_id),{action:"session_send",params:t}}function R(e){const t={};return e.session_id!=null&&(t.session_id=e.session_id),e.page!=null&&(t.page=e.page),e.page_size!=null&&(t.page_size=e.page_size),e.state!=null&&(t.state=e.state),{action:"chat_state_query",params:t}}function B(e){const t=String(e.action??""),n=K[t];if(!n)throw new Error(`Unknown grix_access_control action: ${t}`);const i={};return e.code!=null&&(i.code=e.code),e.sender_id!=null&&(i.sender_id=e.sender_id),e.policy!=null&&(i.policy=e.policy),{action:"claude_access_control",params:{verb:n,payload:i},timeoutMs:3e4}}function W(e){return{action:"widget_visitor_ban",params:{session_id:e.session_id}}}function $(e){const t={session_id:e.session_id,state:e.state};return e.reason!=null&&(t.reason=e.reason),{action:"chat_state_update",params:t}}function F(e){return{action:"skill_set",params:{name:e.name,content:e.content},timeoutMs:3e4}}function Q(e){const t={};return e.name!=null&&(t.name=e.name),{action:"skill_get",params:t}}function H(e){const t=String(e.action??""),n=f[t];if(!n)throw new Error(`Unknown grix_admin action: ${t}`);const i={};return e.agentName!=null&&(i.agent_name=e.agentName),e.introduction!=null&&(i.introduction=e.introduction),e.isMain!=null&&(i.is_main=e.isMain),e.agentId!=null&&(i.agent_id=e.agentId),e.categoryId!=null&&(i.category_id=e.categoryId),e.name!=null&&(i.name=e.name),e.parentId!=null&&(i.parent_id=e.parentId),e.sortOrder!=null&&(i.sort_order=e.sortOrder),{action:n,params:i}}const ee=new Set([...Object.values(g),...Object.values(y),...Object.values(h),...Object.values(f),"send_msg","delete_msg","file_link","file_upload","call_owner","agent_introduction_update","dispatch_agent","session_send","chat_state_query","chat_state_update","claude_access_control","widget_visitor_ban","skill_set","skill_get"]),K={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{K as ACCESS_CONTROL_ACTION_MAP,q as ALL_TOOLS,a as EVENT_TOOLS,A as EXPOSED_TOOLS,ee as PHASE1_INVOKE_ACTIONS,x as PHASE1_TOOL_NAMES,k as PHASE2_TOOL_NAMES,r as TOOLS,p as TOOL_ALIASES,V as TOOL_MAP,Y as isAlias,Z as isGrixInternalToolName,X as mapToolAlias,_ as normalizeEventToolArgs,J as toolCallToInvoke};
@@ -19,7 +19,10 @@ Always call the `grix_query` tool with one `action`:
19
19
  - `session_search` — find sessions. Same three modes as `contact_search`. Each result includes
20
20
  `session_type` (1 = private chat, 2 = group chat). To filter by type pass `sessionType`: `1`
21
21
  for private chats only, `2` for group chats only. **Omitting `sessionType` returns all sessions
22
- regardless of type.**
22
+ regardless of type.** A fourth mode: `peerId` (a user ID) returns the private chat between the
23
+ current user and that account exactly, via the pair key rather than the title — use it whenever
24
+ you know the target user's ID (e.g. "contact the agent owner, user 123"). It takes precedence
25
+ over `id`/`keyword`; error `4004` means no private chat exists with that user yet.
23
26
  - `search_favorite_sessions` — list the owner's favorited sessions; optional
24
27
  `keyword` filter.
25
28
  - `message_history` — read recent clean messages in a session. Requires
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(t){const o=new Set([`http://127.0.0.1:${t.serverPort}`,`http://localhost:${t.serverPort}`,...t.allowedOrigins]),e=new Set([`127.0.0.1:${t.serverPort}`,`localhost:${t.serverPort}`,...t.allowedHosts]);return{validateRequest(s){const r=i(s,o);if(!r.ok)return r;const n=l(s,e);return n.ok?{ok:!0}:n}}}function i(t,o){const e=t.headers.origin;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${e}`}:{ok:!0}}function l(t,o){const e=t.headers.host;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${e}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
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 +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};
@@ -10479,6 +10479,7 @@ var TOOLS = [
10479
10479
  description: "Query action type. search_favorite_sessions returns the owner's favorited sessions (supports keyword filter)."
10480
10480
  },
10481
10481
  id: { type: "string", description: "Contact ID (contact_search) or Session ID (session_search)." },
10482
+ peerId: { type: "string", pattern: "^[1-9]\\d{0,19}$", description: "Peer user ID (session_search only): locate the private chat between the current user and this account exactly, independent of title/nickname/remark. Takes precedence over id/keyword. Use this when you know the target user's ID (e.g. the agent owner). Returns error 4004 when no such private chat exists." },
10482
10483
  keyword: { type: "string", description: "Search keyword." },
10483
10484
  sessionType: { type: "integer", enum: [1, 2], description: "Filter by session type (session_search only): 1=private chat, 2=group chat. Omit to return all." },
10484
10485
  limit: { type: "integer", description: "Max results. message_history defaults to 1 when omitted." },
@@ -10493,6 +10494,7 @@ var TOOLS = [
10493
10494
  properties: {
10494
10495
  action: { type: "string", enum: ["contact_search", "session_search", "message_history", "message_search", "search_favorite_sessions"] },
10495
10496
  id: { type: "string" },
10497
+ peerId: { type: "string", pattern: "^[1-9]\\d{0,19}$" },
10496
10498
  keyword: { type: "string", maxLength: 200 },
10497
10499
  sessionType: { type: "integer", enum: [1, 2] },
10498
10500
  limit: { type: "integer", minimum: 1, maximum: 100 },
@@ -11174,6 +11176,7 @@ function buildQueryInvoke(args) {
11174
11176
  if (!invokeAction) throw new Error(`Unknown grix_query action: ${action}`);
11175
11177
  const params = {};
11176
11178
  if (args.id != null) params.id = args.id;
11179
+ if (args.peerId != null) params.peer_id = args.peerId;
11177
11180
  if (args.keyword != null) params.keyword = args.keyword;
11178
11181
  if (args.sessionType != null) params.session_type = args.sessionType;
11179
11182
  if (args.limit != null) params.limit = args.limit;
@@ -22,6 +22,11 @@ Call `grix_query` with one `action`:
22
22
  (ordered by pinned status and `last_active_at`). Each result carries
23
23
  `session_type` (`1` private, `2` group); pass `sessionType` to filter by
24
24
  type, omit to get both.
25
+ Fourth mode: `peerId` (a user ID) — returns the private chat between the
26
+ current user and that account exactly, via the pair key rather than the
27
+ title. Prefer it whenever the target user's ID is known (e.g. the agent
28
+ owner). Takes precedence over `id`/`keyword`; error `4004` means no private
29
+ chat exists with that user yet.
25
30
  - `message_history` — recent clean messages of one session. Requires
26
31
  `sessionId`; `limit` defaults to 1; page backwards with `beforeId` = the
27
32
  oldest message ID from the previous page. History contains plain text and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "4.3.5",
3
+ "version": "4.3.6",
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",