grix-connector 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/claude/claude-bridge-server.js +1 -1
- package/dist/adapter/claude/claude-tools.js +1 -1
- package/dist/adapter/claude/claude-worker-client.js +1 -1
- package/dist/adapter/claude/mcp-http-launcher.js +2 -2
- package/dist/adapter/claude/result-timeout.js +1 -1
- package/dist/assets/dsh-bridge/{grix-dsh-bridge-4.1.0.tgz → grix-dsh-bridge-4.2.0.tgz} +0 -0
- package/dist/assets/dsh-bridge/manifest.json +4 -4
- package/dist/bridge/bridge.js +1 -1
- package/dist/core/access/allowlist-store.js +1 -1
- package/dist/core/file-ops/list-files.js +1 -1
- package/dist/core/installer/npm-registry.js +4 -4
- package/dist/core/runtime/health.js +1 -1
- package/dist/core/upgrade/npm-upgrader.js +2 -2
- package/dist/core/upgrade/upgrade-checker.js +1 -1
- package/dist/grix.js +6 -6
- package/dist/log.js +2 -2
- package/dist/mcp/stream-http/config.js +1 -1
- package/dist/mcp/stream-http/connection-binding.js +1 -1
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/mcp/stream-http/tool-executor.js +1 -1
- package/dist/mcp/stream-http/tool-registry.js +1 -1
- package/dist/mcp/stream-http/tool-schemas.js +1 -1
- package/dist/service/service-manager.js +3 -3
- package/package.json +1 -1
- package/scripts/upgrade-guardian.mjs +78 -3
- package/scripts/upgrade-guardian.sh +100 -75
|
@@ -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
|
|
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 +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(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
|
+
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 +1 @@
|
|
|
1
|
-
import{log as l}from"../../core/log/index.js";class c{controlURL="";token="";isConfigured(){return!!(this.controlURL&&this.token)}configure(
|
|
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,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
|
|
2
|
-
`),"utf8"),{expectPath:a,pidPath:i}}function h(
|
|
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 +1 @@
|
|
|
1
|
-
class m{defaultTimeoutMs;onTimeout;timers=new Map;constructor(
|
|
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};
|
|
Binary file
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bridgeVersion": "4.
|
|
4
|
-
"tarball": "grix-dsh-bridge-4.
|
|
3
|
+
"bridgeVersion": "4.2.0",
|
|
4
|
+
"tarball": "grix-dsh-bridge-4.2.0.tgz",
|
|
5
5
|
"size": 21976,
|
|
6
6
|
"unpackedSize": 87631,
|
|
7
|
-
"shasum": "
|
|
8
|
-
"integrity": "sha512-
|
|
7
|
+
"shasum": "d8627080719752e462c8de2325c8060845d2379f",
|
|
8
|
+
"integrity": "sha512-rQYngfwCRMb+Ib7rlGKzxJ7uhpeJ1iZTf9Q/VJXzX6M+ze75suSrbjkjkfU7Rd6tkFcDHF9DhONBJ15q1Uz/NA=="
|
|
9
9
|
}
|
package/dist/bridge/bridge.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import $ from"node:path";import{existsSync as ce}from"node:fs";import{realpath as He,stat as j}from"node:fs/promises";import{tmpdir as xe,homedir as z}from"node:os";import{createHash as V,randomUUID as U}from"node:crypto";import{ConnectionManager as Me}from"../core/aibot/index.js";import{AUDIT_LOCAL_ACTION_TYPES as De}from"../core/aibot/types.js";import{ClaudeAdapter as Q}from"../adapter/claude/index.js";import{CodexAdapter as le}from"../adapter/codex/index.js";import{PiAdapter as Qe}from"../adapter/pi/index.js";import{AcpAdapter as R}from"../adapter/acp/index.js";import{OpenHumanAdapter as Be}from"../adapter/openhuman/index.js";import{CursorAdapter as F,CURSOR_MODE_OPTIONS as Oe,fetchCursorAccountUsage as qe}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as ue}from"../adapter/codewhale/index.js";import{OpenCodeAdapter as N}from"../adapter/opencode/index.js";import{AgyAdapter as he}from"../adapter/agy/index.js";import{DshJsonRpcAdapter as Y,buildDshBindingToolbarMeta as Ue,DEFAULT_DSH_PRESETS as Fe,listDshPlugins as Ne,listDshSkills as We,listDshProfiles as Ke,normalizeDshReasoningEffort as Ge,normalizeDshThinking as je,readDshCredentials as ze,resolveDshAgentPreset as Ve,resolveDshCatalogForToolbar as Ye,resolveDshHome as Je,resolveDshModeId as ge,resolveDshSelectedProfileName as Xe}from"../adapter/deepseek-harness/index.js";import{getCachedAgyModels as pe,resolveAgyToolbarModelId as fe}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as J,refreshAgyQuotaInfo as X}from"../adapter/agy/quota.js";import{LOCAL_ACTION_ERROR_CODES as L,LOCAL_ACTION_TYPES as E,SESSION_CONTROL_ERROR_CODES as f,SESSION_CONTROL_VERBS as v,SESSION_MODE_IDS as y}from"../adapter/claude/protocol-contract.js";import{AuditLocalActionHandler as Ze,isAuditLocalActionType as et}from"../audit/query/audit-local-actions.js";import{AuditReplayQueryService as tt}from"../audit/query/audit-replay-query-service.js";import{resolveDefaultAuditStorageRootDir as it}from"../audit/runtime/default-audit-recorder.js";import{FileAuditReplayStore as nt}from"../audit/storage/file-audit-replay-store.js";import{shouldEnableRawApiCapture as me}from"../audit/raw-capture/types.js";import{parseClaudeSessionUsage as st}from"../adapter/claude/usage-parser.js";import"../adapter/claude/session-history.js";import"../adapter/codex/session-history.js";import"../adapter/pi/session-history.js";import"../adapter/opencode/session-history.js";import"../adapter/codewhale/session-history.js";import"../adapter/deepseek-harness/session-history.js";import{SESSION_HISTORY_ERROR_CODES as W,SessionHistoryError as ot,getSessionHistoryReader as rt}from"../adapter/shared/session-history.js";import{resolveSkillScanMode as H}from"../adapter/claude/skill-scanner.js";import{resolveHermesHomeDir as at}from"../adapter/shared/native-provider-config.js";import{buildReportedSkills as dt,syncDefaultSkillsToDir as ct}from"../default-skills/index.js";import{buildWireSkills as _e}from"../core/skill-sync/sync-state.js";import{executeEventTool as lt}from"../core/mcp/event-tool-executor.js";import{uploadSkill as ut}from"../core/skill-sync/skill-upload.js";import{deleteLocalSkill as ht}from"../core/skill-sync/skill-delete.js";import{buildLibrarySkills as gt}from"../core/skill-sync/library-skills.js";import{enableSkill as pt,disableSkill as ft,SkillEnableError as ve}from"../core/skill-sync/skill-enable.js";import{fetchAvailableModels as Z,getCachedModels as ee,readSettingsEnv as mt}from"../adapter/claude/model-list.js";import{parseAcpSessionUsage as _t}from"../adapter/acp/usage-parser.js";import{applyProxyEnv as vt,getProxyManager as Se,relayHostsForClientType as St,buildGatewayRoute as bt}from"../core/proxy/index.js";import{getKiroRelaySpawnEnv as wt}from"../core/proxy/kiro-relay.js";import{supportsKiroCwRelay as be}from"../core/config/provider-env.js";import{RelayFetchError as Ct,deriveGatewayBaseUrls as te,fetchRelayCredentialWithRetry as At}from"../core/proxy/relay-credential-fetch.js";import{RelayStateSyncer as Et}from"../core/proxy/relay-state-sync.js";import{isDirectRelayExplicitlyUnsupported as kt}from"../core/proxy/relay-credential.js";import{buildProviderEnv as we}from"../core/config/provider-env.js";import{CLAUDE_EFFORT_LEVELS as B,isClaudeDirectEnv as Rt,normalizeClaudeEffort as ie,stripGrixRelayEnv as yt}from"../core/config/claude-direct-env.js";import{sweepNativeProviderResidue as $t}from"./native-provider-sweep.js";import{parseCodexSessionUsage as Pt}from"../adapter/codex/usage-parser.js";import{readCodexProviderSettings as It}from"../adapter/codex/codex-trust.js";import{resolveKimiProviderSettings as Tt}from"../core/provider-quota/index.js";import{scanCodexSessions as Lt}from"../adapter/codex/session-scanner.js";import{scanClaudeSessions as Ht}from"../adapter/claude/session-scanner.js";import{reasonixStampFromSessionId as xt,resolveAcpAgentTypes as Mt,scanAcpSessions as Dt,scanReasonixSessionTitles as Qt}from"../adapter/acp/session-scanner.js";import{scanPiSessions as Bt}from"../adapter/pi/session-scanner.js";import{scanCodeWhaleSessions as Ot}from"../adapter/codewhale/session-scanner.js";import{scanCursorSessions as qt}from"../adapter/cursor/session-scanner.js";import{scanOpenCodeSessions as Ut}from"../adapter/opencode/session-scanner.js";import{scanDshSessions as Ft}from"../adapter/deepseek-harness/session-scanner.js";import{parsePiSessionUsage as Nt}from"../adapter/pi/usage-parser.js";import{SessionScanCache as P,resolveCodexLeafDirs as Wt,resolveClaudeLeafDirs as Kt,resolveAcpLeafDirs as Gt,resolvePiLeafDirs as jt,resolveCodeWhaleLeafDirs as zt,resolveCursorLeafDirs as Vt,resolveOpenCodeLeafDirs as Yt,resolveDshLeafDirs as Jt,resolveReasonixLeafDirs as Xt}from"./session-scan-cache.js";import{log as h,ConversationLog as Zt,AgentApiPacketLog as ei,BridgeEventLog as ti,GRIX_PATHS as I}from"../core/log/index.js";import{RevokeHandler as ii}from"./revoke-handler.js";import{AdapterPool as ni}from"./adapter-pool.js";import{parseSessionControlCommand as si,handleSessionControlCommand as Ce,handleSessionControlLocalAction as oi}from"./session-controller.js";import{isOpenSessionDirectiveMessage as ri,parseExecApprovalResolutionMessage as ai,parseAgentQuestionReplyMessage as Ae}from"../core/protocol/interaction-parser.js";import{resolveCliPath as di}from"../core/util/cli-probe.js";import{buildCliInstallQuestion as ci,CLI_INSTALL_OPTION_YES as li,CLI_INSTALL_REQUEST_PREFIX as ui,cliDisplayName as hi,isCliMissingError as ne,isInstallConfirmReply as gi,resolveInstallAgentType as pi,sessionControlOpenFailure as fi}from"./cli-install-offer.js";import{handleAcpSetModel as Ee,handleAcpSetMode as ke,resolveAcpInitialDefaults as mi}from"./acp-toolbar-persist.js";import{SessionBindingStore as _i}from"../core/persistence/session-binding-store.js";import{handleFileListAction as vi,handleCreateFolderAction as Si,serveLocalFile as bi,realHomeDir as Re}from"../core/files/index.js";import{getMachineName as wi}from"../core/util/index.js";import{uploadReplyFileToAgentMedia as Ci}from"../core/protocol/agent-api-media.js";import{ActiveEventStore as Ai}from"../core/persistence/active-event-store.js";import{PendingEventCoordinator as Ei}from"./pending-event-coordinator.js";import{LifecycleBarrier as ki}from"./lifecycle-barrier.js";import{DEFAULT_CONNECTOR_RUNTIME_CONFIG as Ri,applyConnectorRuntimeConfigPatch as yi,extractConnectorRuntimeConfigPatch as $i}from"./runtime-config.js";import{DEFAULT_QUOTE_TRIGGER_BY_ADAPTER as Pi,SendController as Ii}from"./send-controller.js";import{sharedProviderQuotaService as se,detectProviderFromModel as O,normalizeProviderId as oe,readPiProviderSettings as Ti,readOpenCodeProviderSettings as Li,providerQuotaToRateLimits as ye,providerQuotaToCodexRateLimits as $e,isOpenaiCodexProviderName as Hi,queryOpenaiCodexQuota as Pe,openaiCodexQuotaCacheKey as xi}from"../core/provider-quota/index.js";import{queryKiroQuota as re}from"../core/provider-quota/kiro.js";import{buildToolUseCard as x,buildToolResultCard as M,buildDshOnlineToolCard as Mi,buildLocalGrixCardLink as Ie}from"./tool-card-utils.js";import{planRawEventDelivery as Di,buildAuxiliaryDetailText as Qi}from"./raw-event-delivery.js";import{DeferredEventManager as Bi}from"./deferred-events.js";import{buildAgentProbeResult as Oi,PROBE_CACHE_TTL_STATIC_MS as qi,PROBE_CACHE_TTL_FULL_MS as Ui}from"./probe-helper.js";import{BridgeAuditController as Fi}from"../audit/integration/bridge-audit-controller.js";import{isSettlableAuditProducer as Ni,NoopAuditProducer as Wi}from"../audit/producer/audit-producer.js";import{buildAuditStatePayload as K,AuditPreparationFailedError as Ki,AuditTurnScopeUnsupportedError as Gi}from"../audit/core/audit-state.js";import{extractAuditOptions as Te,freezeAuditOptions as ji,stripAuditOptions as zi}from"../audit/core/audit-options.js";import{AuditSessionOptionsError as Vi}from"../audit/core/audit-session-registry.js";const Yi=600*1e3,Ji=60*1e3,Le=30*1e3,Xi=10*1e3,Zi=10*1e3,en=4e3;function ae(q,e){return JSON.stringify({skills:q,library_skills:e})}function tn(q,e,n){const t=V("sha256").update(q).update("\0").update(e).update("\0").update(n).digest("hex");return $.join(I.data,"audit-source","reasonix",`${t}.jsonl`)}const G=new Set(["claude","acp","agy","cursor","codex","deepseek-harness"]),nn=new Set(["claude","codex","cursor","codewhale","opencode","pi","openhuman","agy","acp","deepseek-harness"]),de=3;class Ws{config;name;aibotHandle;aibotConfig;pool;stopped=!1;startupAbortController=new AbortController;stopPromise=null;dropPendingEventsRequested=!1;pendingEventsDropped=!1;revokeHandler=new ii;sessionBindings=new Map;deferredMgr;sendCtrl=new Ii(Ri);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 ki;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<=Ji}async resolveProviderQuotaSource(e){if(e?.disabled||e?.providerId==="openai_codex")return null;let n=this.config.providerBaseUrl??this.config.agent.provider?.baseUrl,t=this.config.providerApiKey??this.config.agent.provider?.apiKey;if((this.config.adapterType??"acp")==="deepseek-harness"){if(t??=this.config.agent.env?.DEEPSEEK_API_KEY,n??=this.config.agent.env?.DEEPSEEK_BASE_URL,!t){const s=Je(typeof this.config.adapterOptions?.dshHome=="string"?this.config.adapterOptions.dshHome:void 0,this.config.agent.env);try{const o=await ze(s),r=typeof o.DEEPSEEK_API_KEY=="string"?o.DEEPSEEK_API_KEY.trim():"";r&&(t=r,n??=typeof o.DEEPSEEK_BASE_URL=="string"&&o.DEEPSEEK_BASE_URL.trim()?o.DEEPSEEK_BASE_URL.trim():"https://api.deepseek.com",h.debug(this.name,"[provider-quota] deepseek-harness: resolved official DeepSeek API key from DSH credential store ($DSH_HOME)"))}catch(o){h.warn(this.name,`[provider-quota] deepseek-harness: could not read DSH credential store: ${o instanceof Error?o.message:String(o)}`)}}n??=t?"https://api.deepseek.com":void 0}if((!n||!t)&&(this.config.adapterType??"acp")==="claude"){const s=mt();n||(n=(s.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(s.ANTHROPIC_API_KEY??"").trim()||(s.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!n||!t)&&(this.config.adapterType??"acp")==="codex"){const s=It();!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if((!n||!t)&&(this.config.adapterType??"acp")==="acp"&&this.config.aibot.clientType==="kimi"){const s=await Tt();!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if((!n||!t)&&(this.config.adapterType??"acp")==="pi"){const s=Ti(e);!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if((!n||!t)&&(this.config.adapterType??"acp")==="opencode"){const s=Li(e);!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if(!n||!t)return null;const i=oe(e?.providerId)??O(e?.model)?.id??oe(this.config.agent.provider?.providerId)??O(this.config.agent.provider?.model)?.id;return{baseUrl:n,...this.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:this.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...i?{providerId:i}:{}}}async maybeQueryProviderQuota(e=!1,n){if(this.config.aibot.clientType==="kiro"){if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota)return this.cachedProviderQuota;try{const s=await re();return this.cachedProviderQuota=s,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro",h.info(this.name,`[provider-quota] kiro queried: success=${s.success}`+(s.balance?` balance=${s.balance.remaining} ${s.balance.unit}`:"")+(s.planName?` plan=${s.planName}`:"")+(s.error?` error=${s.error}`:"")),s}catch(s){return h.warn(this.name,`[provider-quota] kiro query failed: ${s instanceof Error?s.message:String(s)}`),null}}if(n?.providerId==="openai_codex")try{const s=await Pe();return s.quota.success?s.quota:null}catch(s){return h.warn(this.name,`[provider-quota] openai_codex query failed: ${s instanceof Error?s.message:String(s)}`),null}const t=await this.resolveProviderQuotaSource(n);if(!t)return null;const i=se.cacheKey(t);if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota&&this.cachedProviderQuotaKey===i)return this.cachedProviderQuota;try{const s=await se.query(t,{fresh:e}),o=s.quota;return this.cachedProviderQuota=o,this.cachedProviderQuotaSampledAtMs=s.sampledAt,this.cachedProviderQuotaKey=s.cacheKey,h.info(this.name,`[provider-quota] queried: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(r=>`${r.name}=${r.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")),o}catch(s){return h.warn(this.name,`[provider-quota] query failed: ${s instanceof Error?s.message:String(s)}`),null}}startProviderQuotaTimer(){this.stopped||this.providerQuotaTimer||(this.providerQuotaTimer=setInterval(()=>{if(this.stopped){this.stopProviderQuotaTimer();return}this.refreshAndPushProviderQuota().catch(()=>{})},Le),h.info(this.name,`[provider-quota-timer] started (interval=${Le}ms)`))}stopProviderQuotaTimer(){this.providerQuotaTimer&&(clearInterval(this.providerQuotaTimer),this.providerQuotaTimer=null,h.info(this.name,"[provider-quota-timer] stopped"))}async refreshAndPushProviderQuota(e=!1){try{let n;if(this.config.aibot.clientType==="kiro")n=await re(),this.cachedProviderQuota=n,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro";else{const t=[...this.sessionBindings.entries()].filter(([i,s])=>!!s&&this.sessionProviderHints.has(i));if(t.length>0&&await Promise.all(t.map(([i,s])=>this.refreshProviderQuotaForSession(i,s,e))),t.length===this.sessionBindings.size&&t.length>0)return;n=await this.maybeQueryProviderQuota(e)}n?.success&&this.pushProviderQuotaToBindings(n,this.sessionProviderHints.size>0)}catch{}}pushProviderQuotaToBindings(e,n=!1){const t=this.providerQuotaToRateLimits(e);for(const[i,s]of this.sessionBindings.entries()){if(!s||n&&this.sessionProviderHints.has(i))continue;if((this.config.adapterType??"acp")==="deepseek-harness"){const a=this.pool.getSlot(i)?.adapter;if(a instanceof Y){a.updateProviderQuotaSnapshot(e);continue}}const o={provider_quota:e};t&&(o.rate_limits=t);const r=this.cachedAcpContextWindow;r&&("usedPercentage"in r?o.context_window={usedPercentage:r.usedPercentage,remainingPercentage:100-r.usedPercentage}:o.context_window=r),this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:s,meta:o})}}enrichProviderQuotaMeta(e,n="standard",t=this.cachedProviderQuota,i=this.cachedProviderQuotaSampledAtMs){const s={...e??{}};if(!t?.success||(s.provider_quota||(s.provider_quota=t),s.rate_limits))return s;if(n==="codex"){const r=$e(t,i??Date.now());return r&&(s.rate_limits=r.rateLimits,s.rate_limit_primary_percent=r.primaryPercent,s.rate_limit_secondary_percent=r.secondaryPercent,s.rate_limit_primary_window_min=r.primaryWindowMin,s.rate_limit_secondary_window_min=r.secondaryWindowMin),s}const o=ye(t,i??Date.now());return o&&(s.rate_limits=o),s}providerQuotaMetaPayload(e,n,t){let i=this.cachedProviderQuota,s=this.cachedProviderQuotaSampledAtMs,o=!1;if(n){const a=typeof e?.model_provider=="string"?e.model_provider:void 0,d=typeof e?.model_id=="string"?e.model_id:void 0,c=oe(a)??O(a)?.id??O(d)?.id??(Hi(a)?"openai_codex":null);if(c||d){const u=a?.trim().toLowerCase()??"",g=u==="grix"||u.startsWith("grix-"),p={...c?{providerId:c}:{},...d?{model:d}:{},...!!a&&!g&&!c?{disabled:!0}:{}},_=this.sessionProviderHints.get(n),b=_?.providerId!==p.providerId||_?.model!==p.model||_?.disabled!==p.disabled;this.sessionProviderHints.set(n,p),this.sessionProviderMeta.set(n,{...e??{}}),b&&this.sessionProviderQuotas.delete(n),(b||!this.sessionProviderQuotas.has(n))&&t&&this.refreshProviderQuotaForSession(n,t,!1)}const l=this.sessionProviderQuotas.get(n);o=this.sessionProviderHints.has(n),o&&(i=null,s=null),l&&(i=l.quota,s=l.sampledAt)}const r=this.enrichProviderQuotaMeta(e,"standard",i,s);return o&&(r.provider_quota||(r.provider_quota=null),r.rate_limits||(r.rate_limits=null)),Object.keys(r).length>0?{meta:r}:{}}async refreshProviderQuotaForSession(e,n,t){const i=this.sessionProviderHints.get(e);if(!i)return;if(i.disabled){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=hint_disabled providerId=${i.providerId??""} model=${i.model??""}`);return}const s=`${i.providerId??""}|${i.model??""}|false`;try{let o,r,a;if(i.providerId==="openai_codex"){const u=this.sessionProviderQuotas.get(e);if(!t&&u&&u.quota.success&&u.cacheKey.startsWith("openai_codex|")&&this.isRateLimitsCacheFresh(u.sampledAt))o=u.quota,r=u.sampledAt,a=u.cacheKey;else{const g=await Pe();o=g.quota,r=Date.now(),a=xi(g.accountKey)}}else{const u=await this.resolveProviderQuotaSource(i);if(!u){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=no_source providerId=${i.providerId??""} model=${i.model??""}`);return}const g=await se.query(u,{fresh:t});o=g.quota,r=g.sampledAt,a=g.cacheKey}const d=this.sessionProviderHints.get(e);if(`${d?.providerId??""}|${d?.model??""}|${d?.disabled===!0}`!==s)return;if(h.info(this.name,`[provider-quota] queried: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(u=>`${u.name}=${u.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")+` session=${e}`),!o.success){const u=this.sessionProviderQuotas.get(e);(!u?.quota.success||u.cacheKey!==a)&&this.sessionProviderQuotas.delete(e);return}this.sessionProviderQuotas.set(e,{quota:o,sampledAt:r,cacheKey:a});const l=this.enrichProviderQuotaMeta(this.sessionProviderMeta.get(e),"standard",o,r);this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:n,meta:l})}catch(o){h.warn(this.name,`[provider-quota] session query failed: session=${e} ${o instanceof Error?o.message:String(o)}`)}}refreshQuotaAfterModelSwitch(e,n,t){const i=n.trim();if(!e||!i)return;const s=t?.trim()||void 0,o=`${e}|${s??""}|${i}`,r=Date.now();this.lastModelSwitchQuotaRefresh&&this.lastModelSwitchQuotaRefresh.key===o&&r-this.lastModelSwitchQuotaRefresh.at<Xi||(this.lastModelSwitchQuotaRefresh={key:o,at:r},this.doRefreshQuotaAfterModelSwitch(e,i,s).catch(a=>{h.warn(this.name,`[provider-quota] model-switch refresh failed: session=${e} model=${i} ${a instanceof Error?a.message:String(a)}`)}))}async doRefreshQuotaAfterModelSwitch(e,n,t){const i=this.sessionProviderHints.get(e);if(i||t){const o=t??O(n)?.id??i?.providerId,r={...o?{providerId:o}:{},model:n,...i?.disabled?{disabled:!0}:{}},a=i?.providerId!==r.providerId||i?.model!==r.model||i?.disabled!==r.disabled;this.sessionProviderHints.set(e,r),a&&this.sessionProviderQuotas.delete(e);const d=this.sessionBindings.get(e)??this.bindingStore.get(e)?.cwd??"";(a||!this.sessionProviderQuotas.has(e))&&d&&await this.refreshProviderQuotaForSession(e,d,!0);return}const s=await this.maybeQueryProviderQuota(!0,{model:n});s?.success&&this.pushProviderQuotaToBindings(s,this.sessionProviderHints.size>0)}getFreshClaudeRateLimitState(){const e=this.cachedClaudeRateLimitState;return e&&this.isRateLimitsCacheFresh(e.sampledAt)?e:null}getFreshCodexGlobalRateLimitCache(){const e=this.cachedRateLimits,n=this.cachedCodexContextWindow,t=this.cachedCodexTokenUsage;return{sampledAt:Math.max(this.cachedRateLimitsSampledAtMs??0,this.cachedCodexUsageSampledAtMs??0)||null,rateLimits:e,contextWindow:n,tokenUsage:t,hasData:!!(e||n||t)}}getStatus(){const e=this.pool?.getStatus()??{total:0,ready:0,busy:0};return{name:this.name,agentId:this.config.aibot.agentId,alive:!this.stopped,busy:e.busy>0,exhausted:this.pool?[...this.pool.getAllSlots()].some(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){this.closeLifecycleAdmissionForRestart();const n=()=>this.lifecycleBusyChecker?.()??this.hasPendingOrBackgroundWork();if(!n())return!this.stopped;h.info(this.name,`${e}: active tasks detected, waiting until idle before restart`);const t=5e3,i=600*1e3;let s=Date.now();for(;n()&&!this.stopped;)await new Promise(o=>setTimeout(o,t)),Date.now()-s>=i&&(s=Date.now(),h.info(this.name,`${e}: still waiting for active tasks to finish before restart`));return this.stopped?!1:(h.info(this.name,`${e}: all tasks completed, proceeding with restart`),!0)}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,t=!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 s=!1;await this.pool.removeSlot(i.sessionId).catch(o=>{t=!0,s=!0,h.warn(this.name,`failed to recycle adapter slot ${i.sessionId} after relay change: ${o}`)}),s||(n+=1)}return n>0&&h.info(this.name,`recycled ${n} adapter slot(s) so the new Grix relay env takes effect`),t?(this.relayEnvStale=!0,!1):(this.relayEnvStale=!1,this.relayEnvSettledHandler?.(),!0)}setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}providerResolver;setProviderResolver(e){this.providerResolver=e}hasStaleRelayEnv(){return this.relayEnvStale}markRelayEnvStale(){this.relayEnvStale=!0}async probe(e={}){const n=e.conversation?"full":"static",t=e.conversation?Ui:qi;if(!e.fresh){const a=this.probeCache.get(n);if(a&&Date.now()-a.sampledAt<t)return{...a.result,cached:!0}}const i=this.config.adapterType??"acp",s=this.createAdapter(i,"__probe__"),o=e.conversation&&i==="acp"?()=>this.runAcpConversationProbe(s,e.timeoutMs??1e4):void 0;let r;try{r=await Oi({adapter:s,agentName:this.name,clientType:this.config.aibot.clientType,adapterType:i,providerBaseUrl:this.config.providerBaseUrl??null,opts:e,launchConversationProbe:o})}finally{s.stop().catch(()=>{})}return this.probeCache.set(n,{result:r,sampledAt:r.probed_at}),r}async runAcpConversationProbe(e,n){const t=Date.now(),i="__probe__",s=`probe-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,o=this.config.agent.cwd||xe(),r=()=>Date.now()-t;try{await e.start()}catch(u){return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_failed",message:`start failed: ${u instanceof Error?u.message:String(u)}`}}}if(!e.isAlive())return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"process_not_started",message:"agent process not alive"}};if(e instanceof R)try{await e.bindSession(i,o)}catch{}let a=null;const d=new Promise(u=>{a=g=>{g===s&&u()},e.on("eventDone",a)});e.deliverInboundEvent({event_id:s,session_id:i,content:"ping",msg_id:s}),e.deliverStopEvent(s,i);let c=null;const l=await Promise.race([d.then(()=>!1),new Promise(u=>{c=setTimeout(()=>u(!0),n)})]);return c&&clearTimeout(c),a&&e.removeListener("eventDone",a),l?{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_timeout",message:`no eventDone within ${n}ms`}}:{attempted:!0,ok:!0,latency_ms:r()}}constructor(e,n,t=new Wi){this.config=e,this.auditController=new Fi(t,{onAuditState:s=>{try{this.aibotHandle.sendAuditState(K(s,Date.now()))}catch{}}}),Ni(t)&&t.addJobSettledHandler((s,o)=>{this.auditController.handleJobSettled(s,o)}),this.name=e.name;const i=e.adapterType??"acp";if(this.sendCtrl.setDefaultQuoteTrigger(Pi[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",...De]}:{}},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 Zt(e.logDir):null,this.packetLog=e.logDir?new ei(e.logDir):null,this.bindingStore=new _i(e.bindingsPath,e.legacyBindingsPath),this.bindingStore.load(),this.globalConfigStore=n??null,this.deferredMgr=new Bi(this.name),this.activeEventStore=e.activeEventStorePath?new Ai(e.activeEventStorePath):null,this.pendingEvents=new Ei(e.pendingEventStorePath),i==="codex")this.sessionScanCache=new P(Lt,Wt);else if(i==="claude")this.sessionScanCache=new P(Ht,Kt);else if(i==="pi"){const s=e.agent.env?.PI_CODING_AGENT_DIR;this.sessionScanCache=new P(()=>Bt(void 0,s),()=>jt(void 0,s))}else if(i==="codewhale")this.sessionScanCache=new P(Ot,zt);else if(i==="cursor")this.sessionScanCache=new P(qt,Vt);else if(i==="opencode")this.sessionScanCache=new P(Ut,Yt);else if(i==="deepseek-harness"){const s=typeof e.adapterOptions?.dshHome=="string"?e.adapterOptions.dshHome:e.agent.env?.DSH_HOME;this.sessionScanCache=new P(()=>Ft(s),()=>Jt(s))}else if(i==="agy")this.sessionScanCache=new P(()=>[],()=>[]);else{e.aibot.clientType?.trim().toLowerCase()==="reasonix"&&(this.reasonixTitleScan=new P(Qt,Xt));const s=Mt(e.aibot.clientType);this.sessionScanCache=s?new P(()=>Dt(void 0,s),()=>Gt(void 0,s)):new P(()=>[],()=>[])}}async start(){if(this.stopped)throw new Error("agent start aborted");if(await $t({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(([,s])=>String(s.cwd??""))}).then(s=>{s.length>0&&h.info(this.name,`restored native provider config after relay disable: ${s.join(", ")}`)}).catch(s=>{h.warn(this.name,`native provider residue sweep failed: ${s instanceof Error?s.message:String(s)}`)}),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",t=(this.config.adapterType??"acp")==="opencode";if(this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi"||e?(this.maybeQueryProviderQuota().catch(()=>{}),this.startProviderQuotaTimer()):(n||t)&&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 ni({maxPoolSize:this.config.poolMaxSize??20,idleTimeoutMs:this.config.poolIdleTimeoutMs??18e5,eventQueue:this.config.eventQueue},s=>{const o=this.createAdapter(i,s);return o instanceof R&&o.on("acpSessionReady",r=>{this.bindingStore.setAcpSessionId(s,r),this.sessionScanCache.invalidate()}),o},(s,o)=>{this.aibotHandle.sendEventAck({event_id:s,session_id:o,received_at:Date.now()})}),this.pool.setEventStateHandler((s,o,r,a)=>{if(h.info(this.name,`[queue-debug] send event_state session=${o} event=${s} state=${r} queue_pos=${a?.queue_position??""} queue_total=${a?.queue_total??""}`),this.aibotHandle.sendEventState({event_id:s,session_id:o,state:r,content_preview:a?.content_preview,content:a?.content,queue_position:a?.queue_position,queue_total:a?.queue_total,actions:a?.actions,reason:a?.reason,held:a?.held,held_reason:a?.held_reason,updated_at:Date.now()}),this.pushQueueSnapshotForSession(o),r==="running"&&(this.pendingStartedEventIds.add(s),this.pendingEvents.remove(s).catch(d=>{h.warn(this.name,`Failed to remove running event from pending store event=${s}: ${d instanceof Error?d.message:String(d)}`)})),r==="canceled"||r==="failed"){const d=r==="canceled"?"canceled":"failed";this.aibotHandle.sendEventResult({event_id:s,status:d,msg:a?.reason,updated_at:Date.now()}),this.auditController.closeWithoutAdapter(s,d,a?.reason,{queueTerminalState:r}),this.discardEventTrackingState(s),this.pendingEvents.remove(s).catch(c=>{h.warn(this.name,`Failed to remove queued terminal event from pending store event=${s}: ${c instanceof Error?c.message:String(c)}`)})}}),this.pool.setQueueComposingHandler((s,o,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:o,...o?{ttl_ms:3e4,ref_event_id:r}:{}})}),this.pool.setInternalErrorHandler(s=>{this.handleSessionInternalError(s).catch(o=>{h.error(this.name,`[recovery] handleSessionInternalError failed event=${s.eventId} session=${s.sessionId}: ${o instanceof Error?o.message:String(o)}`)})}),this.pool.setEventStartedHandler((s,o)=>{if(this.reportSessionSkills(o),this.config.adapterType!=="claude")return;this.claudeWorkerStatus.set(o,"busy");const r=this.bindingStore.get(o);r?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"busy",cwd:r.cwd,meta:this.buildClaudeToolbarMeta(o)})}),this.pool.setEventDoneHandler((s,o)=>{this.markAuditAdapterClosed(s,o);const r=this.config.adapterType??"acp";if(r==="claude"){this.claudeWorkerStatus.set(o,"ready");const a=this.bindingStore.get(o);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"ready",cwd:a.cwd,meta:this.buildClaudeToolbarMeta(o)})}else if(r==="agy"){const a=this.bindingStore.get(o);if(a?.cwd){const d=this.buildAgyToolbarMeta(o),c=d?.available_models??[];h.info(this.name,`[agy-toolbar-diag] eventDone push binding card session=${o} model_id=${String(d?.model_id??"")} available_models=${c.length} meta_keys=${d?Object.keys(d).join(","):"<none>"}`),this.sendAgyBindingCard(o,a.cwd,d),this.refreshAndPushAgyQuota(o)}else h.info(this.name,`[agy-toolbar-diag] eventDone skip binding card: no binding cwd session=${o}`)}}),this.pool.setSessionActivityHandler((s,o,r)=>{const a=this.selfDrivenSessions.has(s),d=this.selfDrivenLabels.get(s);o?(this.selfDrivenSessions.add(s),r&&this.selfDrivenLabels.set(s,r),this.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:!0,ttl_ms:9e4})):(this.selfDrivenSessions.delete(s),this.selfDrivenLabels.delete(s),a&&this.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:!1})),(a!==o||o&&r!==void 0&&r!==d)&&this.pushQueueSnapshotForSession(s)}),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(r=>[r,this.eventSessionIndex.get(r)]));e.length>0&&this.activeEventStore&&await this.activeEventStore.save(e);for(const r of e)h.info(this.name,`Canceling active event on shutdown: ${r}`),this.sendEventResultWithCleanup(r,"canceled","process shutting down");e.length>0&&await new Promise(r=>setTimeout(r,100)),this.pool?.clearActiveEventsForShutdown();for(const r of e){const a=n.get(r),d=a?this.pool?.getSlot(a):void 0;this.auditController.markAdapterClosed(r,d?.adapter.takeAuditBoundary?.(r)??{processTerminated:!0})}const t=this.deferredMgr.getAllDeferredEntries(),i=this.pool?.drainAllQueuedEvents()??[],s=this.pendingEvents.dedupe([...this.pendingEvents.replaySnapshot(),...t.map(r=>({kind:"deferred",channel:r.channel,sessionId:r.sessionId,event:r.event})),...i.map(r=>({kind:"queued",event:r}))]);let o=!1;if(this.dropPendingEventsRequested)try{await this.pendingEvents.clear(),this.pendingEventsDropped=!0}catch(r){h.warn(this.name,`Failed to clear pending event store on removal: ${r instanceof Error?r.message:String(r)}`)}else try{o=await this.pendingEvents.mergeForShutdown(s)}catch(r){h.error(this.name,`Failed to persist pending events on shutdown: ${r instanceof Error?r.message:String(r)}`)}if(!o)for(const r of s){const a=r.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=we(this.config.agent.clientType,e),t=this.config.agent.env;let i=Object.keys(n).length>0?{...n,...t}:t;if(Rt(n)){const s=Se()?.getRuntimeInfo(),o={...t??{},...n},r=yt(o,{proxyUrl:s?.proxyUrl,caCertPath:s?.caCertPath,caBundlePath:s?.caBundlePath});return delete r.ANTHROPIC_API_KEY,delete r.CLAUDE_CODE_OAUTH_TOKEN,r}if(be(this.config.agent.clientType)){const s=wt(this.name);s&&(i={...i??{},...s})}return vt(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:(s,o,r,a,d,c,l)=>{this.sendStreamChunkByRuntimeConfig(s,o,r,a,d,c,l)},sendFinalStreamChunkReliable:this.reliableFinalWiring("deepseek-harness",en),sendThinking:(s,o,r)=>this.sendThinkingByRuntimeConfig(s,o,r),sendEventResult:(s,o,r,a)=>{this.sendEventResultWithCleanup(s,o,r,void 0,a)},sendRawEventEnvelope:(s,o,r,a)=>{const d=Mi(r);if(d){this.sendToolExecutionCard(s,o,d);return}this.deliverRawEventEnvelope(s,o,r,"deepseek",a)},sendLocalActionResult:(s,o,r,a,d)=>{this.aibotHandle.sendLocalActionResult({action_id:s,status:o,...r!==void 0?{result:r}:{},...a?{error_code:a}:{},...d?{error_msg:d}:{}},e)},sendPermissionCard:s=>{this.sendGrixApprovalCard(s,"deepseek")},sendUpdateBindingCard:(s,o,r,a)=>{this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:o,cwd:r,meta:a})},getAgentProfile:()=>({...this.agentProfile,systemPrompt:this.agentSystemPrompt}),getAgentId:()=>this.config.aibot.agentId,queryProviderQuota:s=>this.maybeQueryProviderQuota(s===!0,{providerId:"deepseek"}),agentInvoke:async(s,o,r)=>this.platformInvoke(s,o,r),eventToolInvoke:async(s,o)=>this.invokeDshEventTool(s,o)},t=V("sha256").update(this.config.aibot.agentId).digest("hex").slice(0,24),i=this.config.adapterOptions??{};return new Y({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:$.join(I.data,"deepseek-harness",t),...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 t=this.bindingStore.get(e),i=this.resolveSessionModelId(e);i&&(n.model=i);const s=this.bindingStore.getCursorModeId(e),o=s??"full_auto";s||this.bindingStore.setCursorModeId(e,o),n.mode=o,t?.cwd&&(n.workspace=t.cwd);const r={sendStreamChunk:(a,d,c,l,u,g,m)=>{this.sendStreamChunkByRuntimeConfig(a,d,c,l,u,g,m)},sendEventResult:(a,d,c)=>{this.sendEventResultWithCleanup(a,d,c)},sendEventAck:(a,d)=>{this.aibotHandle.sendEventAck({event_id:a,session_id:d,received_at:Date.now()})},sendRawEventEnvelope:(a,d,c)=>{this.deliverRawEventEnvelope(a,d,c,"cursor",this.buildCursorRawEventFallbackText(c))},sendAgentQuestionCard:(a,d,c)=>{const l=c.questions.map(g=>g.header).join(", "),u=Ie(`[Agent Question] ${c.request_id}`,"agent_question",c);this.aibotHandle.sendText({event_id:a,session_id:d,content:u,msg_type:1,extra:{card_type:"agent_question",summary_text:l}})},agentInvoke:async(a,d,c)=>this.platformInvoke(a,d,c),sendLocalActionResult:(a,d,c,l,u)=>{this.aibotHandle.sendLocalActionResult({action_id:a,status:d,...c!==void 0?{result:c}:{},...l?{error_code:l}:{},...u?{error_msg:u}:{}},e)},sendUpdateBindingCard:(a,d,c,l)=>{this.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:d,cwd:c,...l?{meta:l}:{}})},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId};return new F({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:n},r)}createClaudeAdapter(e){const n={sendReply:(s,o,r,a,d)=>{this.sendReplyByRuntimeConfig(s,o,r,a,d)},sendStreamChunk:(s,o,r,a,d,c,l)=>{this.sendStreamChunkByRuntimeConfig(s,o,r,a,d,c,l)},sendMedia:(s,o,r,a,d,c,l)=>{this.aibotHandle.sendMedia({event_id:s,session_id:o,content:r,msg_type:2,quoted_message_id:d||void 0,client_msg_id:c||void 0,extra:l?{media_caption:a,...l}:{media_caption:a}})},sendEventResult:(s,o,r,a)=>{this.sendEventResultWithCleanup(s,o,r,a)},sendEventAck:(s,o)=>{this.aibotHandle.sendEventAck({event_id:s,session_id:o,received_at:Date.now()})},agentInvoke:async(s,o,r)=>this.platformInvoke(s,o,r),sendLocalActionResult:(s,o,r,a,d)=>{this.aibotHandle.sendLocalActionResult({action_id:s,status:o,...r!==void 0?{result:r}:{},...a?{error_code:a}:{},...d?{error_msg:d}:{}},e)},sendToolUse:(s,o,r,a)=>{this.sendToolExecutionCard(s,o,x(r,a))},sendToolResult:(s,o,r,a)=>{this.sendToolExecutionCard(s,o,M(r,a))},getWsUrl:()=>this.config.aibot.url,getAgentId:()=>this.config.aibot.agentId,getAgentProfile:()=>this.agentProfile,getApiKey:()=>this.config.aibot.apiKey,getActiveEventCount:()=>0,getPendingPermissionCount:()=>0,getPendingElicitationCount:()=>0,sendAgentQuestionCard:(s,o,r)=>{this.sendGrixAgentQuestionCard(s,o,r)},sendPermissionCard:s=>{this.sendGrixApprovalCard(s,"claude")},sendDirectMessage:s=>{this.aibotHandle.sendMsg({session_id:s.sessionId,msg_type:1,content:s.content,...s.clientMsgId?{client_msg_id:s.clientMsgId}:{},...s.quotedMessageId?{quoted_message_id:s.quotedMessageId}:{}})},onStatusLineUpdated:s=>{(s.rateLimits?.fiveHour||s.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=s);const o=this.bindingStore.get(e);o?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:this.claudeWorkerStatus.get(e)??"ready",cwd:o.cwd,meta:this.buildClaudeToolbarMeta(e)})},sendMcpFrame:s=>{this.aibotHandle.sendMcpFrame(e,s)}},t=this.config.adapterOptions??{},i={...t,sessionRuntimeResolver:()=>{const s=this.bindingStore.get(e),o=this.auditController.getSession(e);return{cwd:s?.cwd,modeId:s?.modeId??y.fullAuto,modelId:this.resolveSessionModelId(e),effort:this.resolveClaudeSessionEffort(e),pluginDir:t.pluginDir,claudeSessionId:s?.claudeSessionId,...o?{audit:{enabled:!0,profile:o.options.profile,capture:o.options.capture}}:{},onSessionIdAssigned:r=>{this.bindingStore.setClaudeSessionId(e,r),this.sessionScanCache.invalidate()}}}};return new Q({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:i},n)}createCodexAdapter(e){let n=null;const t={sendEventResult:(r,a,d)=>{if(a!=="responded"){this.sendEventResultWithCleanup(r,a,d);return}this.sendCtrl.sendFinalStreamChunkReliable(r,e,`codex_terminal_fence_${r}`,5e3,!0,!0).then(()=>this.sendEventResultWithCleanup(r,a,d),c=>{const l=`codex output acceptance fence failed: ${c instanceof Error?c.message:String(c)}`;this.sendEventResultWithCleanup(r,a==="responded"?"failed":a,a==="responded"?l:d)})},sendEventAck:(r,a)=>this.aibotHandle.sendEventAck({event_id:r,session_id:a,received_at:Date.now()}),sendCodexEvent:r=>{this.shouldDropCodexDisplayEvent(r.event_id,r.codex_method)||(this.captureCodexAuditOutput(r),this.aibotHandle.sendCodexEvent(this.stampCodexEventQuote(r)),this.logCodexEventToConversation(r))},sendThinking:(r,a,d)=>{this.sendThinkingByRuntimeConfig(r,a,d)},sendRunError:(r,a,d)=>{this.sendRunErrorAsChunk(r,a,d)},sendUpdateBindingCard:(r,a,d,c)=>{const l={...c??{}};if(!l.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const u=this.providerQuotaToCodexRateLimits(this.cachedProviderQuota);u&&(l.rate_limits=u.rateLimits,l.rate_limit_primary_percent=u.primaryPercent,l.rate_limit_secondary_percent=u.secondaryPercent,l.rate_limit_primary_window_min=u.primaryWindowMin,l.rate_limit_secondary_window_min=u.secondaryWindowMin)}!l.provider_quota&&this.cachedProviderQuota?.success&&(l.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:r,worker_status:a,cwd:d,...Object.keys(l).length>0?{meta:l}:{}})},agentInvoke:async(r,a,d)=>this.platformInvoke(r,a,d),sendLocalActionResult:(r,a,d,c,l)=>this.aibotHandle.sendLocalActionResult({action_id:r,status:a,...d!==void 0?{result:d}:{},...c?{error_code:c}:{},...l?{error_msg:l}:{}},e),sendSessionActivitySet:(r,a,d,c)=>{this.aibotHandle.sendSessionActivitySet({session_id:r,kind:a,active:d,...c??{}})},getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId,onRateLimitsUpdated:r=>{this.cachedRateLimits=r,this.cachedRateLimitsSampledAtMs=Date.now(),this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const a=this.bindingStore.get(e);if(a?.cwd){const d=this.cachedRateLimitsSampledAtMs,c={rate_limits:{...r.primary.windowMinutes>0?{primary:r.primary}:{},...r.secondary.windowMinutes>0?{secondary:r.secondary}:{},sampledAt:d},rate_limit_primary_percent:r.primary.usedPercent,rate_limit_secondary_percent:r.secondary.usedPercent,rate_limit_primary_window_min:r.primary.windowMinutes,rate_limit_secondary_window_min:r.secondary.windowMinutes,credits:r.credits,...r.extras&&r.extras.length>0?{extra_limits:r.extras}:{},...n?.getEffortMeta()};this.cachedProviderQuota?.success&&(c.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:c})}},onContextWindowUpdated:r=>{if(!r)return;this.cachedCodexContextWindow=r,this.cachedCodexUsageSampledAtMs=Date.now();const a=this.bindingStore.get(e);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:{context_window:r,...n?.getEffortMeta()}})},onTokenUsageUpdated:r=>{r&&(this.cachedCodexTokenUsage=r,this.cachedCodexUsageSampledAtMs=Date.now())}},i=this.config.adapterOptions??{},s=this.globalConfigStore?.get(this.name),o=this.auditController.getAdapterPreparation(e);return n=new le({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,s?.codexModeId,r=>this.bindingStore.setCodexModeId(e,r))??i.collaborationMode,reasoningEffort:s?.codexReasoningEffort??i.reasoningEffort,serviceTier:this.bindingStore.getCodexServiceTier(e)??this.resolveCodexNewSessionGlobalDefault(e,s?.codexServiceTier,r=>this.bindingStore.setCodexServiceTier(e,r))??i.serviceTier,sandboxMode:s?.codexSandboxMode??i.sandboxMode,aibotSessionId:e,bindingStore:this.bindingStore,...me(o?.options)?{rawApiCapture:{auditId:o.auditId,sessionId:e,spoolRootDir:$.join(I.data,"audit-replay","raw-spool")}}:{}}},t),n}createCodeWhaleAdapter(e){const n={sendEventResult:(i,s,o)=>{this.sendEventResultWithCleanup(i,s,o)},sendEventAck:(i,s)=>this.aibotHandle.sendEventAck({event_id:i,session_id:s,received_at:Date.now()}),sendStreamChunk:(i,s,o,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(i,s,o,r,a,d)},sendUpdateBindingCard:(i,s,o,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:s,cwd:o,...this.providerQuotaMetaPayload(r,i,o)}),sendLocalActionResult:(i,s,o,r,a)=>this.aibotHandle.sendLocalActionResult({action_id:i,status:s,...o!==void 0?{result:o}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}},e),sendSessionActivitySet:(i,s,o,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:s,active:o,...r??{}})},sendToolUse:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,x(o,r))},sendToolResult:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,M(o,r))},agentInvoke:async(i,s,o)=>this.platformInvoke(i,s,o),getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},t=this.config.adapterOptions??{};return new ue({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},n)}createPiAdapter(e){const n={sendEventResult:(i,s,o)=>{this.sendEventResultWithCleanup(i,s,o),h.info("bridge",`[pi] sendEventResult event=${i} status=${s}`)},sendEventAck:(i,s)=>this.aibotHandle.sendEventAck({event_id:i,session_id:s,received_at:Date.now()}),sendUpdateBindingCard:(i,s,o,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:s,cwd:o,...this.providerQuotaMetaPayload(r,i,o)}),agentInvoke:async(i,s,o)=>this.platformInvoke(i,s,o),sendLocalActionResult:(i,s,o,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:s,...o!==void 0?{result:o}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}},e)},sendSessionActivitySet:(i,s,o,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:s,active:o,...r??{}})},sendToolUse:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,x(o,r))},sendToolResult:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,M(o,r))},sendStreamChunk:(i,s,o,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(i,s,o,r,a,d),a&&h.info("bridge",`[pi] sendFinalStreamChunk event=${i} seq=${r}`)},sendFinalStreamChunkReliable:this.reliableFinalWiring("pi"),sendThinking:(i,s,o)=>{this.sendThinkingByRuntimeConfig(i,s,o)},sendRunError:(i,s,o,r,a)=>{this.sendStreamChunkByRuntimeConfig(i,s,`
|
|
1
|
+
import $ from"node:path";import{existsSync as ce}from"node:fs";import{realpath as He,stat as j}from"node:fs/promises";import{tmpdir as xe,homedir as z}from"node:os";import{createHash as V,randomUUID as U}from"node:crypto";import{ConnectionManager as Me}from"../core/aibot/index.js";import{AUDIT_LOCAL_ACTION_TYPES as De}from"../core/aibot/types.js";import{ClaudeAdapter as Q}from"../adapter/claude/index.js";import{CodexAdapter as le}from"../adapter/codex/index.js";import{PiAdapter as Qe}from"../adapter/pi/index.js";import{AcpAdapter as R}from"../adapter/acp/index.js";import{OpenHumanAdapter as Be}from"../adapter/openhuman/index.js";import{CursorAdapter as F,CURSOR_MODE_OPTIONS as Oe,fetchCursorAccountUsage as qe}from"../adapter/cursor/index.js";import{CodeWhaleAdapter as ue}from"../adapter/codewhale/index.js";import{OpenCodeAdapter as N}from"../adapter/opencode/index.js";import{AgyAdapter as he}from"../adapter/agy/index.js";import{DshJsonRpcAdapter as Y,buildDshBindingToolbarMeta as Ue,DEFAULT_DSH_PRESETS as Fe,listDshPlugins as Ne,listDshSkills as We,listDshProfiles as Ke,normalizeDshReasoningEffort as Ge,normalizeDshThinking as je,readDshCredentials as ze,resolveDshAgentPreset as Ve,resolveDshCatalogForToolbar as Ye,resolveDshHome as Je,resolveDshModeId as ge,resolveDshSelectedProfileName as Xe}from"../adapter/deepseek-harness/index.js";import{getCachedAgyModels as pe,resolveAgyToolbarModelId as fe}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as J,refreshAgyQuotaInfo as X}from"../adapter/agy/quota.js";import{LOCAL_ACTION_ERROR_CODES as L,LOCAL_ACTION_TYPES as E,SESSION_CONTROL_ERROR_CODES as f,SESSION_CONTROL_VERBS as v,SESSION_MODE_IDS as y}from"../adapter/claude/protocol-contract.js";import{AuditLocalActionHandler as Ze,isAuditLocalActionType as et}from"../audit/query/audit-local-actions.js";import{AuditReplayQueryService as tt}from"../audit/query/audit-replay-query-service.js";import{resolveDefaultAuditStorageRootDir as it}from"../audit/runtime/default-audit-recorder.js";import{FileAuditReplayStore as nt}from"../audit/storage/file-audit-replay-store.js";import{shouldEnableRawApiCapture as me}from"../audit/raw-capture/types.js";import{parseClaudeSessionUsage as st}from"../adapter/claude/usage-parser.js";import"../adapter/claude/session-history.js";import"../adapter/codex/session-history.js";import"../adapter/pi/session-history.js";import"../adapter/opencode/session-history.js";import"../adapter/codewhale/session-history.js";import"../adapter/deepseek-harness/session-history.js";import{SESSION_HISTORY_ERROR_CODES as W,SessionHistoryError as ot,getSessionHistoryReader as rt}from"../adapter/shared/session-history.js";import{resolveSkillScanMode as H}from"../adapter/claude/skill-scanner.js";import{resolveHermesHomeDir as at}from"../adapter/shared/native-provider-config.js";import{buildReportedSkills as dt,syncDefaultSkillsToDir as ct}from"../default-skills/index.js";import{buildWireSkills as _e}from"../core/skill-sync/sync-state.js";import{executeEventTool as lt}from"../core/mcp/event-tool-executor.js";import{uploadSkill as ut}from"../core/skill-sync/skill-upload.js";import{deleteLocalSkill as ht}from"../core/skill-sync/skill-delete.js";import{buildLibrarySkills as gt}from"../core/skill-sync/library-skills.js";import{enableSkill as pt,disableSkill as ft,SkillEnableError as ve}from"../core/skill-sync/skill-enable.js";import{fetchAvailableModels as Z,getCachedModels as ee,readSettingsEnv as mt}from"../adapter/claude/model-list.js";import{parseAcpSessionUsage as _t}from"../adapter/acp/usage-parser.js";import{applyProxyEnv as vt,getProxyManager as Se,relayHostsForClientType as St,buildGatewayRoute as bt}from"../core/proxy/index.js";import{getKiroRelaySpawnEnv as wt}from"../core/proxy/kiro-relay.js";import{supportsKiroCwRelay as be}from"../core/config/provider-env.js";import{RelayFetchError as Ct,deriveGatewayBaseUrls as te,fetchRelayCredentialWithRetry as At}from"../core/proxy/relay-credential-fetch.js";import{RelayStateSyncer as Et}from"../core/proxy/relay-state-sync.js";import{isDirectRelayExplicitlyUnsupported as kt}from"../core/proxy/relay-credential.js";import{buildProviderEnv as we}from"../core/config/provider-env.js";import{CLAUDE_EFFORT_LEVELS as B,isClaudeDirectEnv as Rt,normalizeClaudeEffort as ie,stripGrixRelayEnv as yt}from"../core/config/claude-direct-env.js";import{sweepNativeProviderResidue as $t}from"./native-provider-sweep.js";import{parseCodexSessionUsage as Pt}from"../adapter/codex/usage-parser.js";import{readCodexProviderSettings as It}from"../adapter/codex/codex-trust.js";import{resolveKimiProviderSettings as Tt}from"../core/provider-quota/index.js";import{scanCodexSessions as Lt}from"../adapter/codex/session-scanner.js";import{scanClaudeSessions as Ht}from"../adapter/claude/session-scanner.js";import{reasonixStampFromSessionId as xt,resolveAcpAgentTypes as Mt,scanAcpSessions as Dt,scanReasonixSessionTitles as Qt}from"../adapter/acp/session-scanner.js";import{scanPiSessions as Bt}from"../adapter/pi/session-scanner.js";import{scanCodeWhaleSessions as Ot}from"../adapter/codewhale/session-scanner.js";import{scanCursorSessions as qt}from"../adapter/cursor/session-scanner.js";import{scanOpenCodeSessions as Ut}from"../adapter/opencode/session-scanner.js";import{scanDshSessions as Ft}from"../adapter/deepseek-harness/session-scanner.js";import{parsePiSessionUsage as Nt}from"../adapter/pi/usage-parser.js";import{SessionScanCache as P,resolveCodexLeafDirs as Wt,resolveClaudeLeafDirs as Kt,resolveAcpLeafDirs as Gt,resolvePiLeafDirs as jt,resolveCodeWhaleLeafDirs as zt,resolveCursorLeafDirs as Vt,resolveOpenCodeLeafDirs as Yt,resolveDshLeafDirs as Jt,resolveReasonixLeafDirs as Xt}from"./session-scan-cache.js";import{log as h,ConversationLog as Zt,AgentApiPacketLog as ei,BridgeEventLog as ti,GRIX_PATHS as I}from"../core/log/index.js";import{RevokeHandler as ii}from"./revoke-handler.js";import{AdapterPool as ni}from"./adapter-pool.js";import{parseSessionControlCommand as si,handleSessionControlCommand as Ce,handleSessionControlLocalAction as oi}from"./session-controller.js";import{isOpenSessionDirectiveMessage as ri,parseExecApprovalResolutionMessage as ai,parseAgentQuestionReplyMessage as Ae}from"../core/protocol/interaction-parser.js";import{resolveCliPath as di}from"../core/util/cli-probe.js";import{buildCliInstallQuestion as ci,CLI_INSTALL_OPTION_YES as li,CLI_INSTALL_REQUEST_PREFIX as ui,cliDisplayName as hi,isCliMissingError as ne,isInstallConfirmReply as gi,resolveInstallAgentType as pi,sessionControlOpenFailure as fi}from"./cli-install-offer.js";import{handleAcpSetModel as Ee,handleAcpSetMode as ke,resolveAcpInitialDefaults as mi}from"./acp-toolbar-persist.js";import{SessionBindingStore as _i}from"../core/persistence/session-binding-store.js";import{handleFileListAction as vi,handleCreateFolderAction as Si,serveLocalFile as bi,realHomeDir as Re}from"../core/files/index.js";import{getMachineName as wi}from"../core/util/index.js";import{uploadReplyFileToAgentMedia as Ci}from"../core/protocol/agent-api-media.js";import{ActiveEventStore as Ai}from"../core/persistence/active-event-store.js";import{PendingEventCoordinator as Ei}from"./pending-event-coordinator.js";import{LifecycleBarrier as ki}from"./lifecycle-barrier.js";import{DEFAULT_CONNECTOR_RUNTIME_CONFIG as Ri,applyConnectorRuntimeConfigPatch as yi,extractConnectorRuntimeConfigPatch as $i}from"./runtime-config.js";import{DEFAULT_QUOTE_TRIGGER_BY_ADAPTER as Pi,SendController as Ii}from"./send-controller.js";import{sharedProviderQuotaService as se,detectProviderFromModel as O,normalizeProviderId as oe,readPiProviderSettings as Ti,readOpenCodeProviderSettings as Li,providerQuotaToRateLimits as ye,providerQuotaToCodexRateLimits as $e,isOpenaiCodexProviderName as Hi,queryOpenaiCodexQuota as Pe,openaiCodexQuotaCacheKey as xi}from"../core/provider-quota/index.js";import{queryKiroQuota as re}from"../core/provider-quota/kiro.js";import{buildToolUseCard as x,buildToolResultCard as M,buildDshOnlineToolCard as Mi,buildLocalGrixCardLink as Ie}from"./tool-card-utils.js";import{planRawEventDelivery as Di,buildAuxiliaryDetailText as Qi}from"./raw-event-delivery.js";import{DeferredEventManager as Bi}from"./deferred-events.js";import{buildAgentProbeResult as Oi,PROBE_CACHE_TTL_STATIC_MS as qi,PROBE_CACHE_TTL_FULL_MS as Ui}from"./probe-helper.js";import{BridgeAuditController as Fi}from"../audit/integration/bridge-audit-controller.js";import{isSettlableAuditProducer as Ni,NoopAuditProducer as Wi}from"../audit/producer/audit-producer.js";import{buildAuditStatePayload as K,AuditPreparationFailedError as Ki,AuditTurnScopeUnsupportedError as Gi}from"../audit/core/audit-state.js";import{extractAuditOptions as Te,freezeAuditOptions as ji,stripAuditOptions as zi}from"../audit/core/audit-options.js";import{AuditSessionOptionsError as Vi}from"../audit/core/audit-session-registry.js";const Yi=600*1e3,Ji=60*1e3,Le=30*1e3,Xi=10*1e3,Zi=10*1e3,en=4e3;function ae(q,e){return JSON.stringify({skills:q,library_skills:e})}function tn(q,e,n){const t=V("sha256").update(q).update("\0").update(e).update("\0").update(n).digest("hex");return $.join(I.data,"audit-source","reasonix",`${t}.jsonl`)}const G=new Set(["claude","acp","agy","cursor","codex","deepseek-harness"]),nn=new Set(["claude","codex","cursor","codewhale","opencode","pi","openhuman","agy","acp","deepseek-harness"]),de=3;class Ws{config;name;aibotHandle;aibotConfig;pool;stopped=!1;startupAbortController=new AbortController;stopPromise=null;dropPendingEventsRequested=!1;pendingEventsDropped=!1;revokeHandler=new ii;sessionBindings=new Map;deferredMgr;sendCtrl=new Ii(Ri);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 ki;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<=Ji}async resolveProviderQuotaSource(e){if(e?.disabled||e?.providerId==="openai_codex")return null;let n=this.config.providerBaseUrl??this.config.agent.provider?.baseUrl,t=this.config.providerApiKey??this.config.agent.provider?.apiKey;if((this.config.adapterType??"acp")==="deepseek-harness"){if(t??=this.config.agent.env?.DEEPSEEK_API_KEY,n??=this.config.agent.env?.DEEPSEEK_BASE_URL,!t){const s=Je(typeof this.config.adapterOptions?.dshHome=="string"?this.config.adapterOptions.dshHome:void 0,this.config.agent.env);try{const o=await ze(s),r=typeof o.DEEPSEEK_API_KEY=="string"?o.DEEPSEEK_API_KEY.trim():"";r&&(t=r,n??=typeof o.DEEPSEEK_BASE_URL=="string"&&o.DEEPSEEK_BASE_URL.trim()?o.DEEPSEEK_BASE_URL.trim():"https://api.deepseek.com",h.debug(this.name,"[provider-quota] deepseek-harness: resolved official DeepSeek API key from DSH credential store ($DSH_HOME)"))}catch(o){h.warn(this.name,`[provider-quota] deepseek-harness: could not read DSH credential store: ${o instanceof Error?o.message:String(o)}`)}}n??=t?"https://api.deepseek.com":void 0}if((!n||!t)&&(this.config.adapterType??"acp")==="claude"){const s=mt();n||(n=(s.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(s.ANTHROPIC_API_KEY??"").trim()||(s.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!n||!t)&&(this.config.adapterType??"acp")==="codex"){const s=It();!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if((!n||!t)&&(this.config.adapterType??"acp")==="acp"&&this.config.aibot.clientType==="kimi"){const s=await Tt();!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if((!n||!t)&&(this.config.adapterType??"acp")==="pi"){const s=Ti(e);!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if((!n||!t)&&(this.config.adapterType??"acp")==="opencode"){const s=Li(e);!n&&s.baseUrl&&(n=s.baseUrl),!t&&s.apiKey&&(t=s.apiKey)}if(!n||!t)return null;const i=oe(e?.providerId)??O(e?.model)?.id??oe(this.config.agent.provider?.providerId)??O(this.config.agent.provider?.model)?.id;return{baseUrl:n,...this.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:this.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...i?{providerId:i}:{}}}async maybeQueryProviderQuota(e=!1,n){if(this.config.aibot.clientType==="kiro"){if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota)return this.cachedProviderQuota;try{const s=await re();return this.cachedProviderQuota=s,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro",h.info(this.name,`[provider-quota] kiro queried: success=${s.success}`+(s.balance?` balance=${s.balance.remaining} ${s.balance.unit}`:"")+(s.planName?` plan=${s.planName}`:"")+(s.error?` error=${s.error}`:"")),s}catch(s){return h.warn(this.name,`[provider-quota] kiro query failed: ${s instanceof Error?s.message:String(s)}`),null}}if(n?.providerId==="openai_codex")try{const s=await Pe();return s.quota.success?s.quota:null}catch(s){return h.warn(this.name,`[provider-quota] openai_codex query failed: ${s instanceof Error?s.message:String(s)}`),null}const t=await this.resolveProviderQuotaSource(n);if(!t)return null;const i=se.cacheKey(t);if(!e&&this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)&&this.cachedProviderQuota&&this.cachedProviderQuotaKey===i)return this.cachedProviderQuota;try{const s=await se.query(t,{fresh:e}),o=s.quota;return this.cachedProviderQuota=o,this.cachedProviderQuotaSampledAtMs=s.sampledAt,this.cachedProviderQuotaKey=s.cacheKey,h.info(this.name,`[provider-quota] queried: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(r=>`${r.name}=${r.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")),o}catch(s){return h.warn(this.name,`[provider-quota] query failed: ${s instanceof Error?s.message:String(s)}`),null}}startProviderQuotaTimer(){this.stopped||this.providerQuotaTimer||(this.providerQuotaTimer=setInterval(()=>{if(this.stopped){this.stopProviderQuotaTimer();return}this.refreshAndPushProviderQuota().catch(()=>{})},Le),h.info(this.name,`[provider-quota-timer] started (interval=${Le}ms)`))}stopProviderQuotaTimer(){this.providerQuotaTimer&&(clearInterval(this.providerQuotaTimer),this.providerQuotaTimer=null,h.info(this.name,"[provider-quota-timer] stopped"))}async refreshAndPushProviderQuota(e=!1){try{let n;if(this.config.aibot.clientType==="kiro")n=await re(),this.cachedProviderQuota=n,this.cachedProviderQuotaSampledAtMs=Date.now(),this.cachedProviderQuotaKey="kiro";else{const t=[...this.sessionBindings.entries()].filter(([i,s])=>!!s&&this.sessionProviderHints.has(i));if(t.length>0&&await Promise.all(t.map(([i,s])=>this.refreshProviderQuotaForSession(i,s,e))),t.length===this.sessionBindings.size&&t.length>0)return;n=await this.maybeQueryProviderQuota(e)}n?.success&&this.pushProviderQuotaToBindings(n,this.sessionProviderHints.size>0)}catch{}}pushProviderQuotaToBindings(e,n=!1){const t=this.providerQuotaToRateLimits(e);for(const[i,s]of this.sessionBindings.entries()){if(!s||n&&this.sessionProviderHints.has(i))continue;if((this.config.adapterType??"acp")==="deepseek-harness"){const a=this.pool.getSlot(i)?.adapter;if(a instanceof Y){a.updateProviderQuotaSnapshot(e);continue}}const o={provider_quota:e};t&&(o.rate_limits=t);const r=this.cachedAcpContextWindow;r&&("usedPercentage"in r?o.context_window={usedPercentage:r.usedPercentage,remainingPercentage:100-r.usedPercentage}:o.context_window=r),this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:s,meta:o})}}enrichProviderQuotaMeta(e,n="standard",t=this.cachedProviderQuota,i=this.cachedProviderQuotaSampledAtMs){const s={...e??{}};if(!t?.success||(s.provider_quota||(s.provider_quota=t),s.rate_limits))return s;if(n==="codex"){const r=$e(t,i??Date.now());return r&&(s.rate_limits=r.rateLimits,s.rate_limit_primary_percent=r.primaryPercent,s.rate_limit_secondary_percent=r.secondaryPercent,s.rate_limit_primary_window_min=r.primaryWindowMin,s.rate_limit_secondary_window_min=r.secondaryWindowMin),s}const o=ye(t,i??Date.now());return o&&(s.rate_limits=o),s}providerQuotaMetaPayload(e,n,t){let i=this.cachedProviderQuota,s=this.cachedProviderQuotaSampledAtMs,o=!1;if(n){const a=typeof e?.model_provider=="string"?e.model_provider:void 0,d=typeof e?.model_id=="string"?e.model_id:void 0,c=oe(a)??O(a)?.id??O(d)?.id??(Hi(a)?"openai_codex":null);if(c||d){const u=a?.trim().toLowerCase()??"",g=u==="grix"||u.startsWith("grix-"),p={...c?{providerId:c}:{},...d?{model:d}:{},...!!a&&!g&&!c?{disabled:!0}:{}},_=this.sessionProviderHints.get(n),b=_?.providerId!==p.providerId||_?.model!==p.model||_?.disabled!==p.disabled;this.sessionProviderHints.set(n,p),this.sessionProviderMeta.set(n,{...e??{}}),b&&this.sessionProviderQuotas.delete(n),(b||!this.sessionProviderQuotas.has(n))&&t&&this.refreshProviderQuotaForSession(n,t,!1)}const l=this.sessionProviderQuotas.get(n);o=this.sessionProviderHints.has(n),o&&(i=null,s=null),l&&(i=l.quota,s=l.sampledAt)}const r=this.enrichProviderQuotaMeta(e,"standard",i,s);return o&&(r.provider_quota||(r.provider_quota=null),r.rate_limits||(r.rate_limits=null)),Object.keys(r).length>0?{meta:r}:{}}async refreshProviderQuotaForSession(e,n,t){const i=this.sessionProviderHints.get(e);if(!i)return;if(i.disabled){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=hint_disabled providerId=${i.providerId??""} model=${i.model??""}`);return}const s=`${i.providerId??""}|${i.model??""}|false`;try{let o,r,a;if(i.providerId==="openai_codex"){const u=this.sessionProviderQuotas.get(e);if(!t&&u&&u.quota.success&&u.cacheKey.startsWith("openai_codex|")&&this.isRateLimitsCacheFresh(u.sampledAt))o=u.quota,r=u.sampledAt,a=u.cacheKey;else{const g=await Pe();o=g.quota,r=Date.now(),a=xi(g.accountKey)}}else{const u=await this.resolveProviderQuotaSource(i);if(!u){h.debug(this.name,`[provider-quota] session skip: session=${e} reason=no_source providerId=${i.providerId??""} model=${i.model??""}`);return}const g=await se.query(u,{fresh:t});o=g.quota,r=g.sampledAt,a=g.cacheKey}const d=this.sessionProviderHints.get(e);if(`${d?.providerId??""}|${d?.model??""}|${d?.disabled===!0}`!==s)return;if(h.info(this.name,`[provider-quota] queried: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(u=>`${u.name}=${u.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")+` session=${e}`),!o.success){const u=this.sessionProviderQuotas.get(e);(!u?.quota.success||u.cacheKey!==a)&&this.sessionProviderQuotas.delete(e);return}this.sessionProviderQuotas.set(e,{quota:o,sampledAt:r,cacheKey:a});const l=this.enrichProviderQuotaMeta(this.sessionProviderMeta.get(e),"standard",o,r);this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:n,meta:l})}catch(o){h.warn(this.name,`[provider-quota] session query failed: session=${e} ${o instanceof Error?o.message:String(o)}`)}}refreshQuotaAfterModelSwitch(e,n,t){const i=n.trim();if(!e||!i)return;const s=t?.trim()||void 0,o=`${e}|${s??""}|${i}`,r=Date.now();this.lastModelSwitchQuotaRefresh&&this.lastModelSwitchQuotaRefresh.key===o&&r-this.lastModelSwitchQuotaRefresh.at<Xi||(this.lastModelSwitchQuotaRefresh={key:o,at:r},this.doRefreshQuotaAfterModelSwitch(e,i,s).catch(a=>{h.warn(this.name,`[provider-quota] model-switch refresh failed: session=${e} model=${i} ${a instanceof Error?a.message:String(a)}`)}))}async doRefreshQuotaAfterModelSwitch(e,n,t){const i=this.sessionProviderHints.get(e);if(i||t){const o=t??O(n)?.id??i?.providerId,r={...o?{providerId:o}:{},model:n,...i?.disabled?{disabled:!0}:{}},a=i?.providerId!==r.providerId||i?.model!==r.model||i?.disabled!==r.disabled;this.sessionProviderHints.set(e,r),a&&this.sessionProviderQuotas.delete(e);const d=this.sessionBindings.get(e)??this.bindingStore.get(e)?.cwd??"";(a||!this.sessionProviderQuotas.has(e))&&d&&await this.refreshProviderQuotaForSession(e,d,!0);return}const s=await this.maybeQueryProviderQuota(!0,{model:n});s?.success&&this.pushProviderQuotaToBindings(s,this.sessionProviderHints.size>0)}getFreshClaudeRateLimitState(){const e=this.cachedClaudeRateLimitState;return e&&this.isRateLimitsCacheFresh(e.sampledAt)?e:null}getFreshCodexGlobalRateLimitCache(){const e=this.cachedRateLimits,n=this.cachedCodexContextWindow,t=this.cachedCodexTokenUsage;return{sampledAt:Math.max(this.cachedRateLimitsSampledAtMs??0,this.cachedCodexUsageSampledAtMs??0)||null,rateLimits:e,contextWindow:n,tokenUsage:t,hasData:!!(e||n||t)}}getStatus(){const e=this.pool?.getStatus()??{total:0,ready:0,busy:0};return{name:this.name,agentId:this.config.aibot.agentId,alive:!this.stopped,busy:e.busy>0,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){this.closeLifecycleAdmissionForRestart();const n=()=>this.lifecycleBusyChecker?.()??this.hasPendingOrBackgroundWork();if(!n())return!this.stopped;h.info(this.name,`${e}: active tasks detected, waiting until idle before restart`);const t=5e3,i=600*1e3;let s=Date.now();for(;n()&&!this.stopped;)await new Promise(o=>setTimeout(o,t)),Date.now()-s>=i&&(s=Date.now(),h.info(this.name,`${e}: still waiting for active tasks to finish before restart`));return this.stopped?!1:(h.info(this.name,`${e}: all tasks completed, proceeding with restart`),!0)}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,t=!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 s=!1;await this.pool.removeSlot(i.sessionId).catch(o=>{t=!0,s=!0,h.warn(this.name,`failed to recycle adapter slot ${i.sessionId} after relay change: ${o}`)}),s||(n+=1)}return n>0&&h.info(this.name,`recycled ${n} adapter slot(s) so the new Grix relay env takes effect`),t?(this.relayEnvStale=!0,!1):(this.relayEnvStale=!1,this.relayEnvSettledHandler?.(),!0)}setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}providerResolver;setProviderResolver(e){this.providerResolver=e}hasStaleRelayEnv(){return this.relayEnvStale}markRelayEnvStale(){this.relayEnvStale=!0}async probe(e={}){const n=e.conversation?"full":"static",t=e.conversation?Ui:qi;if(!e.fresh){const a=this.probeCache.get(n);if(a&&Date.now()-a.sampledAt<t)return{...a.result,cached:!0}}const i=this.config.adapterType??"acp",s=this.createAdapter(i,"__probe__"),o=e.conversation&&i==="acp"?()=>this.runAcpConversationProbe(s,e.timeoutMs??1e4):void 0;let r;try{r=await Oi({adapter:s,agentName:this.name,clientType:this.config.aibot.clientType,adapterType:i,providerBaseUrl:this.config.providerBaseUrl??null,opts:e,launchConversationProbe:o})}finally{s.stop().catch(()=>{})}return this.probeCache.set(n,{result:r,sampledAt:r.probed_at}),r}async runAcpConversationProbe(e,n){const t=Date.now(),i="__probe__",s=`probe-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,o=this.config.agent.cwd||xe(),r=()=>Date.now()-t;try{await e.start()}catch(u){return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_failed",message:`start failed: ${u instanceof Error?u.message:String(u)}`}}}if(!e.isAlive())return{attempted:!0,ok:!1,latency_ms:r(),error:{code:"process_not_started",message:"agent process not alive"}};if(e instanceof R)try{await e.bindSession(i,o)}catch{}let a=null;const d=new Promise(u=>{a=g=>{g===s&&u()},e.on("eventDone",a)});e.deliverInboundEvent({event_id:s,session_id:i,content:"ping",msg_id:s}),e.deliverStopEvent(s,i);let c=null;const l=await Promise.race([d.then(()=>!1),new Promise(u=>{c=setTimeout(()=>u(!0),n)})]);return c&&clearTimeout(c),a&&e.removeListener("eventDone",a),l?{attempted:!0,ok:!1,latency_ms:r(),error:{code:"conversation_timeout",message:`no eventDone within ${n}ms`}}:{attempted:!0,ok:!0,latency_ms:r()}}constructor(e,n,t=new Wi){this.config=e,this.auditController=new Fi(t,{onAuditState:s=>{try{this.aibotHandle.sendAuditState(K(s,Date.now()))}catch{}}}),Ni(t)&&t.addJobSettledHandler((s,o)=>{this.auditController.handleJobSettled(s,o)}),this.name=e.name;const i=e.adapterType??"acp";if(this.sendCtrl.setDefaultQuoteTrigger(Pi[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",...De]}:{}},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 Zt(e.logDir):null,this.packetLog=e.logDir?new ei(e.logDir):null,this.bindingStore=new _i(e.bindingsPath,e.legacyBindingsPath),this.bindingStore.load(),this.globalConfigStore=n??null,this.deferredMgr=new Bi(this.name),this.activeEventStore=e.activeEventStorePath?new Ai(e.activeEventStorePath):null,this.pendingEvents=new Ei(e.pendingEventStorePath),i==="codex")this.sessionScanCache=new P(Lt,Wt);else if(i==="claude")this.sessionScanCache=new P(Ht,Kt);else if(i==="pi"){const s=e.agent.env?.PI_CODING_AGENT_DIR;this.sessionScanCache=new P(()=>Bt(void 0,s),()=>jt(void 0,s))}else if(i==="codewhale")this.sessionScanCache=new P(Ot,zt);else if(i==="cursor")this.sessionScanCache=new P(qt,Vt);else if(i==="opencode")this.sessionScanCache=new P(Ut,Yt);else if(i==="deepseek-harness"){const s=typeof e.adapterOptions?.dshHome=="string"?e.adapterOptions.dshHome:e.agent.env?.DSH_HOME;this.sessionScanCache=new P(()=>Ft(s),()=>Jt(s))}else if(i==="agy")this.sessionScanCache=new P(()=>[],()=>[]);else{e.aibot.clientType?.trim().toLowerCase()==="reasonix"&&(this.reasonixTitleScan=new P(Qt,Xt));const s=Mt(e.aibot.clientType);this.sessionScanCache=s?new P(()=>Dt(void 0,s),()=>Gt(void 0,s)):new P(()=>[],()=>[])}}async start(){if(this.stopped)throw new Error("agent start aborted");if(await $t({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(([,s])=>String(s.cwd??""))}).then(s=>{s.length>0&&h.info(this.name,`restored native provider config after relay disable: ${s.join(", ")}`)}).catch(s=>{h.warn(this.name,`native provider residue sweep failed: ${s instanceof Error?s.message:String(s)}`)}),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",t=(this.config.adapterType??"acp")==="opencode";if(this.config.aibot.clientType==="kiro"||this.config.aibot.clientType==="kimi"||e?(this.maybeQueryProviderQuota().catch(()=>{}),this.startProviderQuotaTimer()):(n||t)&&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 ni({maxPoolSize:this.config.poolMaxSize??20,idleTimeoutMs:this.config.poolIdleTimeoutMs??18e5,eventQueue:this.config.eventQueue},s=>{const o=this.createAdapter(i,s);return o instanceof R&&o.on("acpSessionReady",r=>{this.bindingStore.setAcpSessionId(s,r),this.sessionScanCache.invalidate()}),o},(s,o)=>{this.aibotHandle.sendEventAck({event_id:s,session_id:o,received_at:Date.now()})}),this.pool.setEventStateHandler((s,o,r,a)=>{if(h.info(this.name,`[queue-debug] send event_state session=${o} event=${s} state=${r} queue_pos=${a?.queue_position??""} queue_total=${a?.queue_total??""}`),this.aibotHandle.sendEventState({event_id:s,session_id:o,state:r,content_preview:a?.content_preview,content:a?.content,queue_position:a?.queue_position,queue_total:a?.queue_total,actions:a?.actions,reason:a?.reason,held:a?.held,held_reason:a?.held_reason,updated_at:Date.now()}),this.pushQueueSnapshotForSession(o),r==="running"&&(this.pendingStartedEventIds.add(s),this.pendingEvents.remove(s).catch(d=>{h.warn(this.name,`Failed to remove running event from pending store event=${s}: ${d instanceof Error?d.message:String(d)}`)})),r==="canceled"||r==="failed"){const d=r==="canceled"?"canceled":"failed";this.aibotHandle.sendEventResult({event_id:s,status:d,msg:a?.reason,updated_at:Date.now()}),this.auditController.closeWithoutAdapter(s,d,a?.reason,{queueTerminalState:r}),this.discardEventTrackingState(s),this.pendingEvents.remove(s).catch(c=>{h.warn(this.name,`Failed to remove queued terminal event from pending store event=${s}: ${c instanceof Error?c.message:String(c)}`)})}}),this.pool.setQueueComposingHandler((s,o,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:o,...o?{ttl_ms:3e4,ref_event_id:r}:{}})}),this.pool.setInternalErrorHandler(s=>{this.handleSessionInternalError(s).catch(o=>{h.error(this.name,`[recovery] handleSessionInternalError failed event=${s.eventId} session=${s.sessionId}: ${o instanceof Error?o.message:String(o)}`)})}),this.pool.setEventStartedHandler((s,o)=>{if(this.reportSessionSkills(o),this.config.adapterType!=="claude")return;this.claudeWorkerStatus.set(o,"busy");const r=this.bindingStore.get(o);r?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"busy",cwd:r.cwd,meta:this.buildClaudeToolbarMeta(o)})}),this.pool.setEventDoneHandler((s,o)=>{this.markAuditAdapterClosed(s,o);const r=this.config.adapterType??"acp";if(r==="claude"){this.claudeWorkerStatus.set(o,"ready");const a=this.bindingStore.get(o);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"ready",cwd:a.cwd,meta:this.buildClaudeToolbarMeta(o)})}else if(r==="agy"){const a=this.bindingStore.get(o);if(a?.cwd){const d=this.buildAgyToolbarMeta(o),c=d?.available_models??[];h.info(this.name,`[agy-toolbar-diag] eventDone push binding card session=${o} model_id=${String(d?.model_id??"")} available_models=${c.length} meta_keys=${d?Object.keys(d).join(","):"<none>"}`),this.sendAgyBindingCard(o,a.cwd,d),this.refreshAndPushAgyQuota(o)}else h.info(this.name,`[agy-toolbar-diag] eventDone skip binding card: no binding cwd session=${o}`)}}),this.pool.setSessionActivityHandler((s,o,r)=>{const a=this.selfDrivenSessions.has(s),d=this.selfDrivenLabels.get(s);o?(this.selfDrivenSessions.add(s),r&&this.selfDrivenLabels.set(s,r),this.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:!0,ttl_ms:9e4})):(this.selfDrivenSessions.delete(s),this.selfDrivenLabels.delete(s),a&&this.aibotHandle.sendSessionActivitySet({session_id:s,kind:"composing",active:!1})),(a!==o||o&&r!==void 0&&r!==d)&&this.pushQueueSnapshotForSession(s)}),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(r=>[r,this.eventSessionIndex.get(r)]));e.length>0&&this.activeEventStore&&await this.activeEventStore.save(e);for(const r of e)h.info(this.name,`Canceling active event on shutdown: ${r}`),this.sendEventResultWithCleanup(r,"canceled","process shutting down");e.length>0&&await new Promise(r=>setTimeout(r,100)),this.pool?.clearActiveEventsForShutdown();for(const r of e){const a=n.get(r),d=a?this.pool?.getSlot(a):void 0;this.auditController.markAdapterClosed(r,d?.adapter.takeAuditBoundary?.(r)??{processTerminated:!0})}const t=this.deferredMgr.getAllDeferredEntries(),i=this.pool?.drainAllQueuedEvents()??[],s=this.pendingEvents.dedupe([...this.pendingEvents.replaySnapshot(),...t.map(r=>({kind:"deferred",channel:r.channel,sessionId:r.sessionId,event:r.event})),...i.map(r=>({kind:"queued",event:r}))]);let o=!1;if(this.dropPendingEventsRequested)try{await this.pendingEvents.clear(),this.pendingEventsDropped=!0}catch(r){h.warn(this.name,`Failed to clear pending event store on removal: ${r instanceof Error?r.message:String(r)}`)}else try{o=await this.pendingEvents.mergeForShutdown(s)}catch(r){h.error(this.name,`Failed to persist pending events on shutdown: ${r instanceof Error?r.message:String(r)}`)}if(!o)for(const r of s){const a=r.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=we(this.config.agent.clientType,e),t=this.config.agent.env;let i=Object.keys(n).length>0?{...n,...t}:t;if(Rt(n)){const s=Se()?.getRuntimeInfo(),o={...t??{},...n},r=yt(o,{proxyUrl:s?.proxyUrl,caCertPath:s?.caCertPath,caBundlePath:s?.caBundlePath});return delete r.ANTHROPIC_API_KEY,delete r.CLAUDE_CODE_OAUTH_TOKEN,r}if(be(this.config.agent.clientType)){const s=wt(this.name);s&&(i={...i??{},...s})}return vt(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:(s,o,r,a,d,c,l)=>{this.sendStreamChunkByRuntimeConfig(s,o,r,a,d,c,l)},sendFinalStreamChunkReliable:this.reliableFinalWiring("deepseek-harness",en),sendThinking:(s,o,r)=>this.sendThinkingByRuntimeConfig(s,o,r),sendEventResult:(s,o,r,a)=>{this.sendEventResultWithCleanup(s,o,r,void 0,a)},sendRawEventEnvelope:(s,o,r,a)=>{const d=Mi(r);if(d){this.sendToolExecutionCard(s,o,d);return}this.deliverRawEventEnvelope(s,o,r,"deepseek",a)},sendLocalActionResult:(s,o,r,a,d)=>{this.aibotHandle.sendLocalActionResult({action_id:s,status:o,...r!==void 0?{result:r}:{},...a?{error_code:a}:{},...d?{error_msg:d}:{}},e)},sendPermissionCard:s=>{this.sendGrixApprovalCard(s,"deepseek")},sendUpdateBindingCard:(s,o,r,a)=>{this.aibotHandle.sendUpdateBindingCard({session_id:s,worker_status:o,cwd:r,meta:a})},getAgentProfile:()=>({...this.agentProfile,systemPrompt:this.agentSystemPrompt}),getAgentId:()=>this.config.aibot.agentId,queryProviderQuota:s=>this.maybeQueryProviderQuota(s===!0,{providerId:"deepseek"}),agentInvoke:async(s,o,r)=>this.platformInvoke(s,o,r),eventToolInvoke:async(s,o)=>this.invokeDshEventTool(s,o)},t=V("sha256").update(this.config.aibot.agentId).digest("hex").slice(0,24),i=this.config.adapterOptions??{};return new Y({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:$.join(I.data,"deepseek-harness",t),...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 t=this.bindingStore.get(e),i=this.resolveSessionModelId(e);i&&(n.model=i);const s=this.bindingStore.getCursorModeId(e),o=s??"full_auto";s||this.bindingStore.setCursorModeId(e,o),n.mode=o,t?.cwd&&(n.workspace=t.cwd);const r={sendStreamChunk:(a,d,c,l,u,g,m)=>{this.sendStreamChunkByRuntimeConfig(a,d,c,l,u,g,m)},sendEventResult:(a,d,c)=>{this.sendEventResultWithCleanup(a,d,c)},sendEventAck:(a,d)=>{this.aibotHandle.sendEventAck({event_id:a,session_id:d,received_at:Date.now()})},sendRawEventEnvelope:(a,d,c)=>{this.deliverRawEventEnvelope(a,d,c,"cursor",this.buildCursorRawEventFallbackText(c))},sendAgentQuestionCard:(a,d,c)=>{const l=c.questions.map(g=>g.header).join(", "),u=Ie(`[Agent Question] ${c.request_id}`,"agent_question",c);this.aibotHandle.sendText({event_id:a,session_id:d,content:u,msg_type:1,extra:{card_type:"agent_question",summary_text:l}})},agentInvoke:async(a,d,c)=>this.platformInvoke(a,d,c),sendLocalActionResult:(a,d,c,l,u)=>{this.aibotHandle.sendLocalActionResult({action_id:a,status:d,...c!==void 0?{result:c}:{},...l?{error_code:l}:{},...u?{error_msg:u}:{}},e)},sendUpdateBindingCard:(a,d,c,l)=>{this.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:d,cwd:c,...l?{meta:l}:{}})},getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId};return new F({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:n},r)}createClaudeAdapter(e){const n={sendReply:(s,o,r,a,d)=>{this.sendReplyByRuntimeConfig(s,o,r,a,d)},sendStreamChunk:(s,o,r,a,d,c,l)=>{this.sendStreamChunkByRuntimeConfig(s,o,r,a,d,c,l)},sendMedia:(s,o,r,a,d,c,l)=>{this.aibotHandle.sendMedia({event_id:s,session_id:o,content:r,msg_type:2,quoted_message_id:d||void 0,client_msg_id:c||void 0,extra:l?{media_caption:a,...l}:{media_caption:a}})},sendEventResult:(s,o,r,a)=>{this.sendEventResultWithCleanup(s,o,r,a)},sendEventAck:(s,o)=>{this.aibotHandle.sendEventAck({event_id:s,session_id:o,received_at:Date.now()})},agentInvoke:async(s,o,r)=>this.platformInvoke(s,o,r),sendLocalActionResult:(s,o,r,a,d)=>{this.aibotHandle.sendLocalActionResult({action_id:s,status:o,...r!==void 0?{result:r}:{},...a?{error_code:a}:{},...d?{error_msg:d}:{}},e)},sendToolUse:(s,o,r,a)=>{this.sendToolExecutionCard(s,o,x(r,a))},sendToolResult:(s,o,r,a)=>{this.sendToolExecutionCard(s,o,M(r,a))},getWsUrl:()=>this.config.aibot.url,getAgentId:()=>this.config.aibot.agentId,getAgentProfile:()=>this.agentProfile,getApiKey:()=>this.config.aibot.apiKey,getActiveEventCount:()=>0,getPendingPermissionCount:()=>0,getPendingElicitationCount:()=>0,sendAgentQuestionCard:(s,o,r)=>{this.sendGrixAgentQuestionCard(s,o,r)},sendPermissionCard:s=>{this.sendGrixApprovalCard(s,"claude")},sendDirectMessage:s=>{this.aibotHandle.sendMsg({session_id:s.sessionId,msg_type:1,content:s.content,...s.clientMsgId?{client_msg_id:s.clientMsgId}:{},...s.quotedMessageId?{quoted_message_id:s.quotedMessageId}:{}})},onStatusLineUpdated:s=>{(s.rateLimits?.fiveHour||s.rateLimits?.sevenDay)&&(this.cachedClaudeRateLimitState=s);const o=this.bindingStore.get(e);o?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:this.claudeWorkerStatus.get(e)??"ready",cwd:o.cwd,meta:this.buildClaudeToolbarMeta(e)})},sendMcpFrame:s=>{this.aibotHandle.sendMcpFrame(e,s)}},t=this.config.adapterOptions??{},i={...t,sessionRuntimeResolver:()=>{const s=this.bindingStore.get(e),o=this.auditController.getSession(e);return{cwd:s?.cwd,modeId:s?.modeId??y.fullAuto,modelId:this.resolveSessionModelId(e),effort:this.resolveClaudeSessionEffort(e),pluginDir:t.pluginDir,claudeSessionId:s?.claudeSessionId,...o?{audit:{enabled:!0,profile:o.options.profile,capture:o.options.capture}}:{},onSessionIdAssigned:r=>{this.bindingStore.setClaudeSessionId(e,r),this.sessionScanCache.invalidate()}}}};return new Q({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:i},n)}createCodexAdapter(e){let n=null;const t={sendEventResult:(r,a,d)=>{if(a!=="responded"){this.sendEventResultWithCleanup(r,a,d);return}this.sendCtrl.sendFinalStreamChunkReliable(r,e,`codex_terminal_fence_${r}`,5e3,!0,!0).then(()=>this.sendEventResultWithCleanup(r,a,d),c=>{const l=`codex output acceptance fence failed: ${c instanceof Error?c.message:String(c)}`;this.sendEventResultWithCleanup(r,a==="responded"?"failed":a,a==="responded"?l:d)})},sendEventAck:(r,a)=>this.aibotHandle.sendEventAck({event_id:r,session_id:a,received_at:Date.now()}),sendCodexEvent:r=>{this.shouldDropCodexDisplayEvent(r.event_id,r.codex_method)||(this.captureCodexAuditOutput(r),this.aibotHandle.sendCodexEvent(this.stampCodexEventQuote(r)),this.logCodexEventToConversation(r))},sendThinking:(r,a,d)=>{this.sendThinkingByRuntimeConfig(r,a,d)},sendRunError:(r,a,d)=>{this.sendRunErrorAsChunk(r,a,d)},sendUpdateBindingCard:(r,a,d,c)=>{const l={...c??{}};if(!l.rate_limits&&this.cachedProviderQuota?.success){this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const u=this.providerQuotaToCodexRateLimits(this.cachedProviderQuota);u&&(l.rate_limits=u.rateLimits,l.rate_limit_primary_percent=u.primaryPercent,l.rate_limit_secondary_percent=u.secondaryPercent,l.rate_limit_primary_window_min=u.primaryWindowMin,l.rate_limit_secondary_window_min=u.secondaryWindowMin)}!l.provider_quota&&this.cachedProviderQuota?.success&&(l.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:r,worker_status:a,cwd:d,...Object.keys(l).length>0?{meta:l}:{}})},agentInvoke:async(r,a,d)=>this.platformInvoke(r,a,d),sendLocalActionResult:(r,a,d,c,l)=>this.aibotHandle.sendLocalActionResult({action_id:r,status:a,...d!==void 0?{result:d}:{},...c?{error_code:c}:{},...l?{error_msg:l}:{}},e),sendSessionActivitySet:(r,a,d,c)=>{this.aibotHandle.sendSessionActivitySet({session_id:r,kind:a,active:d,...c??{}})},getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId,onRateLimitsUpdated:r=>{this.cachedRateLimits=r,this.cachedRateLimitsSampledAtMs=Date.now(),this.isRateLimitsCacheFresh(this.cachedProviderQuotaSampledAtMs)||this.maybeQueryProviderQuota().catch(()=>{});const a=this.bindingStore.get(e);if(a?.cwd){const d=this.cachedRateLimitsSampledAtMs,c={rate_limits:{...r.primary.windowMinutes>0?{primary:r.primary}:{},...r.secondary.windowMinutes>0?{secondary:r.secondary}:{},sampledAt:d},rate_limit_primary_percent:r.primary.usedPercent,rate_limit_secondary_percent:r.secondary.usedPercent,rate_limit_primary_window_min:r.primary.windowMinutes,rate_limit_secondary_window_min:r.secondary.windowMinutes,credits:r.credits,...r.extras&&r.extras.length>0?{extra_limits:r.extras}:{},...n?.getEffortMeta()};this.cachedProviderQuota?.success&&(c.provider_quota=this.cachedProviderQuota),this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:c})}},onContextWindowUpdated:r=>{if(!r)return;this.cachedCodexContextWindow=r,this.cachedCodexUsageSampledAtMs=Date.now();const a=this.bindingStore.get(e);a?.cwd&&this.aibotHandle.sendUpdateBindingCard({session_id:e,worker_status:"ready",cwd:a.cwd,meta:{context_window:r,...n?.getEffortMeta()}})},onTokenUsageUpdated:r=>{r&&(this.cachedCodexTokenUsage=r,this.cachedCodexUsageSampledAtMs=Date.now())}},i=this.config.adapterOptions??{},s=this.globalConfigStore?.get(this.name),o=this.auditController.getAdapterPreparation(e);return n=new le({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,s?.codexModeId,r=>this.bindingStore.setCodexModeId(e,r))??i.collaborationMode,reasoningEffort:s?.codexReasoningEffort??i.reasoningEffort,serviceTier:this.bindingStore.getCodexServiceTier(e)??this.resolveCodexNewSessionGlobalDefault(e,s?.codexServiceTier,r=>this.bindingStore.setCodexServiceTier(e,r))??i.serviceTier,sandboxMode:s?.codexSandboxMode??i.sandboxMode,aibotSessionId:e,bindingStore:this.bindingStore,...me(o?.options)?{rawApiCapture:{auditId:o.auditId,sessionId:e,spoolRootDir:$.join(I.data,"audit-replay","raw-spool")}}:{}}},t),n}createCodeWhaleAdapter(e){const n={sendEventResult:(i,s,o)=>{this.sendEventResultWithCleanup(i,s,o)},sendEventAck:(i,s)=>this.aibotHandle.sendEventAck({event_id:i,session_id:s,received_at:Date.now()}),sendStreamChunk:(i,s,o,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(i,s,o,r,a,d)},sendUpdateBindingCard:(i,s,o,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:s,cwd:o,...this.providerQuotaMetaPayload(r,i,o)}),sendLocalActionResult:(i,s,o,r,a)=>this.aibotHandle.sendLocalActionResult({action_id:i,status:s,...o!==void 0?{result:o}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}},e),sendSessionActivitySet:(i,s,o,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:s,active:o,...r??{}})},sendToolUse:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,x(o,r))},sendToolResult:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,M(o,r))},agentInvoke:async(i,s,o)=>this.platformInvoke(i,s,o),getConversationLog:()=>this.conversationLog,getAgentProfile:()=>this.agentProfile,getAgentId:()=>this.config.aibot.agentId},t=this.config.adapterOptions??{};return new ue({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},n)}createPiAdapter(e){const n={sendEventResult:(i,s,o)=>{this.sendEventResultWithCleanup(i,s,o),h.info("bridge",`[pi] sendEventResult event=${i} status=${s}`)},sendEventAck:(i,s)=>this.aibotHandle.sendEventAck({event_id:i,session_id:s,received_at:Date.now()}),sendUpdateBindingCard:(i,s,o,r)=>this.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:s,cwd:o,...this.providerQuotaMetaPayload(r,i,o)}),agentInvoke:async(i,s,o)=>this.platformInvoke(i,s,o),sendLocalActionResult:(i,s,o,r,a)=>{this.aibotHandle.sendLocalActionResult({action_id:i,status:s,...o!==void 0?{result:o}:{},...r?{error_code:r}:{},...a?{error_msg:a}:{}},e)},sendSessionActivitySet:(i,s,o,r)=>{this.aibotHandle.sendSessionActivitySet({session_id:i,kind:s,active:o,...r??{}})},sendToolUse:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,x(o,r))},sendToolResult:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,M(o,r))},sendStreamChunk:(i,s,o,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(i,s,o,r,a,d),a&&h.info("bridge",`[pi] sendFinalStreamChunk event=${i} seq=${r}`)},sendFinalStreamChunkReliable:this.reliableFinalWiring("pi"),sendThinking:(i,s,o)=>{this.sendThinkingByRuntimeConfig(i,s,o)},sendRunError:(i,s,o,r,a)=>{this.sendStreamChunkByRuntimeConfig(i,s,`
|
|
2
2
|
|
|
3
3
|
Error: ${o}`,r,!1,a)},getAgentProfile:()=>this.agentProfile},t=this.config.adapterOptions??{};return new Qe({command:this.config.agent.command,args:this.config.agent.args,env:this.resolveSpawnEnv(),options:{...t,aibotSessionId:e,bindingStore:this.bindingStore,agentName:this.name,...this.config.agent.provider?{provider:this.config.agent.provider}:{}}},n)}createOpenHumanAdapter(e){const n={sendStreamChunk:(i,s,o,r,a,d)=>{this.sendStreamChunkByRuntimeConfig(i,s,o,r,a,d)},sendFinalStreamChunkReliable:async(i,s,o,r)=>{try{await this.sendCtrl.sendFinalStreamChunkReliable(i,s,r)}catch(a){throw h.error("bridge",`[openhuman] sendFinalStreamChunkReliable ACK failed event=${i}: ${a}`),a}},sendEventResult:(i,s,o)=>{this.sendEventResultWithCleanup(i,s,o),h.info("bridge",`[openhuman] sendEventResult event=${i} status=${s}`)},sendEventAck:(i,s)=>this.aibotHandle.sendEventAck({event_id:i,session_id:s,received_at:Date.now()}),sendToolUse:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,x(o,r))},sendToolResult:(i,s,o,r)=>{this.sendToolExecutionCard(i,s,M(o,r))},sendThinking:(i,s,o)=>{this.sendThinkingByRuntimeConfig(i,s,o)},sendRunError:(i,s,o)=>{this.sendStreamChunkByRuntimeConfig(i,s,`
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readJSONFile as o,writeJSONFileAtomic as
|
|
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 +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
|
|
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,4 +1,4 @@
|
|
|
1
|
-
import{execFile as w,execFileSync as $}from"node:child_process";import{existsSync as O}from"node:fs";import{dirname as T,join as y}from"node:path";import{promisify as k}from"node:util";import{log as I}from"../log/logger.js";import{probeUrls as v}from"./speed-test.js";const C=k(w),A=1e4,x=2,M=3e3;function R(t,e={}){if((e.platform??process.platform)!=="win32")return{command:"npm",args:t};const i=e.env??process.env,
|
|
2
|
-
[${
|
|
3
|
-
${d}`.trim(),r),I.info("installer",`${
|
|
4
|
-
${N??""}`.trim();if(p){const h=E||p.message,S=c||p.killed===!0?`ETIMEDOUT: npm install exceeded ${r}ms (registry likely unreachable): ${h}`:h;s(new b(S,E||h));return}
|
|
1
|
+
import{execFile as w,execFileSync as $}from"node:child_process";import{existsSync as O}from"node:fs";import{dirname as T,join as y}from"node:path";import{promisify as k}from"node:util";import{log as I}from"../log/logger.js";import{probeUrls as v}from"./speed-test.js";const C=k(w),A=1e4,x=2,M=3e3;function R(t,e={}){if((e.platform??process.platform)!=="win32")return{command:"npm",args:t};const i=e.env??process.env,o=e.nodePath??process.execPath,u=[typeof i.npm_execpath=="string"?i.npm_execpath:"",y(T(o),"node_modules","npm","bin","npm-cli.js")];try{const n=$("where.exe",["npm.cmd"],{encoding:"utf-8",timeout:3e3,windowsHide:!0}).split(/\r?\n/).map(l=>l.trim()).filter(Boolean);for(const l of n)u.push(y(T(l),"node_modules","npm","bin","npm-cli.js"))}catch{}const s=u.find(n=>n&&O(n));if(!s)throw new Error("Unable to locate npm-cli.js for safe Windows execution");return{command:o,args:[s,...t]}}class b extends Error{output;constructor(e,r){super(e),this.name="NpmInstallError",this.output=r}}const f=[{id:"official",label:"npm \u5B98\u65B9",url:"https://registry.npmjs.org"},{id:"npmmirror",label:"npmmirror (\u6DD8\u5B9D\u955C\u50CF)",url:"https://registry.npmmirror.com"}];async function P(){const t=await v(f.map(r=>({url:r.url,label:r.label})),5e3),e=[];for(const r of t)if(r.reachable){const i=f.find(o=>o.url===r.url);i&&e.push(i)}for(const r of t)if(!r.reachable){const i=f.find(o=>o.url===r.url);i&&!e.includes(i)&&e.push(i)}for(const r of f)e.includes(r)||e.push(r);return e}async function B(){try{const t=R(["config","get","registry"]),{stdout:e}=await C(t.command,t.args,{timeout:A,encoding:"utf-8"});return e.trim()}catch{return"https://registry.npmjs.org"}}async function J(t,e,r,i){const o=await P();if(o.length===0)throw new Error("All npm registries are unreachable. Check your network connection.");let u="",s="";for(const n of o)for(let l=0;l<=x;l++)try{return I.info("installer",`npm install ${t} using ${n.label} (${n.url})`),{output:await D(t,n.url,e,r,i),registry:n.label,registryUrl:n.url}}catch(a){const c=a instanceof Error?a.message:String(a),d=L(a);if(u=c,s=F(`${s}
|
|
2
|
+
[${n.label}] ${c}
|
|
3
|
+
${d}`.trim(),r),I.info("installer",`${n.label} failed: ${c.slice(0,200)}`),j(c)&&l<x){await new Promise(m=>setTimeout(m,M));continue}if(!U(c))throw new b(c,s);break}throw new b(`npm install failed on all registries. Last error: ${u}`,s)}function U(t){return/ECONNRESET|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ERR_SOCKET_TIMEOUT|getaddrinfo|socket hang up|network|fetch failed|timed out|tunneling socket|self.signed|404|ETARGET|No matching version|notarget/i.test(t)}function j(t){return/\bEBUSY\b|resource busy or locked|EPERM[^\n]*\brename\b|\bELOCKED\b/i.test(t)}function D(t,e,r,i,o){return new Promise((u,s)=>{const n=["install","-g",t,"--registry",e,"--prefer-online","--no-audit","--no-fund"];o?.prefix&&n.push("--prefix",o.prefix);const l=process.platform==="win32",a=R(n,{env:o?.env});let c=!1,d=Promise.resolve(),m;const g=w(a.command,a.args,{maxBuffer:i,windowsHide:!0,env:o?.env},async(p,_,N)=>{clearTimeout(m),await d;const E=`${_??""}
|
|
4
|
+
${N??""}`.trim();if(p){const h=E||p.message,S=c||p.killed===!0?`ETIMEDOUT: npm install exceeded ${r}ms (registry likely unreachable): ${h}`:h;s(new b(S,E||h));return}u(E)});m=setTimeout(()=>{c=!0,l&&g.pid?d=new Promise(p=>{w("taskkill",["/PID",String(g.pid),"/T","/F"],{windowsHide:!0,timeout:1e4},()=>{g.kill("SIGTERM"),p()})}):g.kill("SIGTERM")},r),m.unref?.()})}function L(t){if(t&&typeof t=="object"&&"output"in t){const e=t.output;return typeof e=="string"?e:""}return""}function F(t,e){return t.length<=e?t:t.slice(-e)}function Q(t){return f.map(e=>({label:e.label,command:`npm install -g ${t} --registry ${e.url}`}))}export{f as NPM_REGISTRIES,b as NpmInstallError,B as getCurrentRegistry,Q as getMirrorInstallCommands,U as isRetriableRegistryError,j as isTransientInstallError,J as npmInstallWithMirror,P as probeRegistries,R as resolveNpmInvocation};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createServer as
|
|
1
|
+
import{createServer as h}from"node:http";import{log as s}from"../log/logger.js";import{resolveClientVersion as v}from"../util/client-version.js";class f{server=null;startTime=Date.now();alive=!0;statusProvider=null;metaProvider=null;version=v();setStatusProvider(e){this.statusProvider=e}setMetaProvider(e){this.metaProvider=e}async start(e){return new Promise((o,n)=>{this.server=h((a,t)=>{if(a.url==="/healthz")if(this.alive){const r=this.statusProvider?.();let i;try{i=this.metaProvider?.()}catch(l){s.warn("health",`meta provider failed: ${l}`)}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({status:"ok",version:this.version,uptime:Math.floor((Date.now()-this.startTime)/1e3),pid:process.pid,...r?{agents:r}:{},...i??{}}))}else t.writeHead(503,{"Content-Type":"application/json"}),t.end(JSON.stringify({status:"shutting_down"}));else t.writeHead(404),t.end()}),this.server.listen(e,"127.0.0.1",()=>{s.info("health",`Listening on 127.0.0.1:${e}`),o()}),this.server.on("error",n)})}markShuttingDown(){this.alive=!1}async stop(){if(this.server)return new Promise(e=>{this.server.close(()=>e())})}}export{f as HealthServer};
|