grix-connector 3.30.0 → 3.31.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.
Files changed (33) hide show
  1. package/dist/adapter/claude/claude-bridge-server.js +1 -1
  2. package/dist/adapter/claude/claude-tools.js +1 -1
  3. package/dist/adapter/claude/claude-worker-client.js +1 -1
  4. package/dist/adapter/claude/mcp-http-launcher.js +2 -2
  5. package/dist/adapter/claude/result-timeout.js +1 -1
  6. package/dist/adapter/codex/codex-bridge.js +9 -9
  7. package/dist/adapter/deepseek-harness/bridge-installer.js +6 -6
  8. package/dist/adapter/deepseek-harness/bridge-session-reliability.js +1 -1
  9. package/dist/adapter/deepseek-harness/grix-jsonrpc.cordis.yml +6 -1
  10. package/dist/adapter/deepseek-harness/index.js +1 -1
  11. package/dist/adapter/deepseek-harness/jsonrpc-adapter.js +2 -2
  12. package/dist/adapter/deepseek-harness/process-runtime.js +1 -1
  13. package/dist/adapter/deepseek-harness/profile-runtime.js +2 -2
  14. package/dist/adapter/deepseek-harness/profile-supervisor.js +2 -2
  15. package/dist/adapter/deepseek-harness/skill-manager.js +1 -0
  16. package/dist/adapter/deepseek-harness/toolbar-state.js +1 -1
  17. package/dist/assets/dsh-bridge/grix-dsh-bridge-3.31.0.tgz +0 -0
  18. package/dist/assets/dsh-bridge/manifest.json +6 -6
  19. package/dist/bridge/bridge.js +5 -5
  20. package/dist/core/access/allowlist-store.js +1 -1
  21. package/dist/core/config/codex-direct.js +1 -1
  22. package/dist/core/file-ops/list-files.js +1 -1
  23. package/dist/core/persistence/session-binding-store.js +2 -2
  24. package/dist/log.js +2 -2
  25. package/dist/manager.js +1 -1
  26. package/dist/mcp/stream-http/config.js +1 -1
  27. package/dist/mcp/stream-http/connection-binding.js +1 -1
  28. package/dist/mcp/stream-http/security.js +1 -1
  29. package/dist/mcp/stream-http/tool-executor.js +1 -1
  30. package/dist/mcp/stream-http/tool-registry.js +1 -1
  31. package/dist/mcp/stream-http/tool-schemas.js +1 -1
  32. package/package.json +1 -1
  33. package/dist/assets/dsh-bridge/grix-dsh-bridge-3.30.0.tgz +0 -0
@@ -1 +1 @@
1
- import c from"node:http";import{randomUUID as d}from"node:crypto";import{log as o}from"../../core/log/index.js";function l(t){t.writeHead(401,{"content-type":"application/json"}),t.end(JSON.stringify({error:"unauthorized"}))}function u(t){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not_found"}))}function h(t,e){t.writeHead(400,{"content-type":"application/json"}),t.end(JSON.stringify({error:e}))}function p(t,e={ok:!0}){t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify(e))}async function v(t){const e=[];for await(const r of t)e.push(r);const n=Buffer.concat(e).toString("utf8").trim();return n?JSON.parse(n):{}}function k(t){const e=(t.headers.authorization??"").trim();return e.toLowerCase().startsWith("bearer ")?e.slice(7).trim():""}class w{host="127.0.0.1";port=0;token;callbacks;server=null;address=null;constructor(e){this.token=d(),this.callbacks=e}getToken(){return this.token}getURL(){return this.address?`http://${this.address.address}:${this.address.port}`:""}async start(){this.server||(this.server=c.createServer(async(e,n)=>{try{await this.handleRequest(e,n)}catch(r){h(n,r instanceof Error?r.message:String(r))}}),await new Promise((e,n)=>{this.server.once("error",n),this.server.listen(this.port,this.host,()=>{this.server.off("error",n),e()})}),this.address=this.server.address(),o.info("claude-bridge",`Bridge server listening on ${this.getURL()}`))}async stop(){if(!this.server)return;const e=this.server;this.server=null,this.address=null,e.closeIdleConnections?.(),e.closeAllConnections?.(),await new Promise((n,r)=>{e.close(s=>s?r(s):n())})}async handleRequest(e,n){if(k(e)!==this.token){l(n);return}if(e.method!=="POST"){n.writeHead(405,{"content-type":"application/json"}),n.end(JSON.stringify({error:"method_not_allowed"}));return}const r=new URL(e.url,"http://localhost").pathname,s=await v(e),i=f.get(r);if(!i){u(n);return}const a=await i(this.callbacks,s);p(n,a??{ok:!0})}}const f=new Map([["/v1/worker/register",async(t,e)=>(o.info("claude-bridge",`Worker registered: ${e.worker_id} (pid=${e.pid})`),t.onRegisterWorker(e))],["/v1/worker/status",async(t,e)=>(o.info("claude-bridge",`Worker status: ${e.status}`),t.onStatusUpdate(e))],["/v1/worker/send-text",async(t,e)=>t.onSendText(e)],["/v1/worker/send-stream-chunk",async(t,e)=>t.onSendStreamChunk(e)],["/v1/worker/send-media",async(t,e)=>t.onSendMedia(e)],["/v1/worker/delete-message",async(t,e)=>t.onDeleteMessage(e)],["/v1/worker/ack-event",async(t,e)=>t.onAckEvent(e)],["/v1/worker/event-result",async(t,e)=>t.onSendEventResult(e)],["/v1/worker/event-stop-ack",async(t,e)=>t.onSendEventStopAck(e)],["/v1/worker/event-stop-result",async(t,e)=>t.onSendEventStopResult(e)],["/v1/worker/session-composing",async(t,e)=>t.onSetSessionComposing(e)],["/v1/worker/agent-invoke",async(t,e)=>t.onAgentInvoke(e)],["/v1/worker/local-action-result",async(t,e)=>t.onLocalActionResult(e)]]);export{w as ClaudeBridgeServer};
1
+ import c from"node:http";import{randomUUID as d}from"node:crypto";import{log as o}from"../../core/log/index.js";function l(t){t.writeHead(401,{"content-type":"application/json"}),t.end(JSON.stringify({error:"unauthorized"}))}function u(t){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not_found"}))}function h(t,e){t.writeHead(400,{"content-type":"application/json"}),t.end(JSON.stringify({error:e}))}function p(t,e={ok:!0}){t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify(e))}async function v(t){const e=[];for await(const n of t)e.push(n);const r=Buffer.concat(e).toString("utf8").trim();return r?JSON.parse(r):{}}function k(t){const e=(t.headers.authorization??"").trim();return e.toLowerCase().startsWith("bearer ")?e.slice(7).trim():""}class w{host="127.0.0.1";port=0;token;callbacks;server=null;address=null;constructor(e){this.token=d(),this.callbacks=e}getToken(){return this.token}getURL(){return this.address?`http://${this.address.address}:${this.address.port}`:""}async start(){this.server||(this.server=c.createServer(async(e,r)=>{try{await this.handleRequest(e,r)}catch(n){h(r,n instanceof Error?n.message:String(n))}}),await new Promise((e,r)=>{this.server.once("error",r),this.server.listen(this.port,this.host,()=>{this.server.off("error",r),e()})}),this.address=this.server.address(),o.info("claude-bridge",`Bridge server listening on ${this.getURL()}`))}async stop(){if(!this.server)return;const e=this.server;this.server=null,this.address=null,e.closeIdleConnections?.(),e.closeAllConnections?.(),await new Promise((r,n)=>{e.close(s=>s?n(s):r())})}async handleRequest(e,r){if(k(e)!==this.token){l(r);return}if(e.method!=="POST"){r.writeHead(405,{"content-type":"application/json"}),r.end(JSON.stringify({error:"method_not_allowed"}));return}const n=new URL(e.url,"http://localhost").pathname,s=await v(e),i=f.get(n);if(!i){u(r);return}const a=await i(this.callbacks,s);p(r,a??{ok:!0})}}const f=new Map([["/v1/worker/register",async(t,e)=>(o.info("claude-bridge",`Worker registered: ${e.worker_id} (pid=${e.pid})`),t.onRegisterWorker(e))],["/v1/worker/status",async(t,e)=>(o.info("claude-bridge",`Worker status: ${e.status}`),t.onStatusUpdate(e))],["/v1/worker/send-text",async(t,e)=>t.onSendText(e)],["/v1/worker/send-stream-chunk",async(t,e)=>t.onSendStreamChunk(e)],["/v1/worker/send-media",async(t,e)=>t.onSendMedia(e)],["/v1/worker/delete-message",async(t,e)=>t.onDeleteMessage(e)],["/v1/worker/ack-event",async(t,e)=>t.onAckEvent(e)],["/v1/worker/event-result",async(t,e)=>t.onSendEventResult(e)],["/v1/worker/event-stop-ack",async(t,e)=>t.onSendEventStopAck(e)],["/v1/worker/event-stop-result",async(t,e)=>t.onSendEventStopResult(e)],["/v1/worker/session-composing",async(t,e)=>t.onSetSessionComposing(e)],["/v1/worker/agent-invoke",async(t,e)=>t.onAgentInvoke(e)],["/v1/worker/local-action-result",async(t,e)=>t.onLocalActionResult(e)]]);export{w as ClaudeBridgeServer};
@@ -1 +1 @@
1
- import{randomUUID as x}from"node:crypto";import{CallToolRequestSchema as S,ListToolsRequestSchema as w}from"@modelcontextprotocol/sdk/types.js";import{log as f}from"../../core/log/index.js";import{toolCallToInvoke as k}from"../../core/mcp/tools.js";const E=new Set(["contact_search","session_search","message_history","message_search","group_create","group_detail_read","group_leave_self","group_member_add","group_member_remove","group_member_role_update","group_all_members_muted_update","group_member_speaking_update","group_dissolve","send_msg","delete_msg","agent_api_create","agent_category_list","agent_category_create","agent_category_update","agent_category_assign","agent_api_key_rotate"]),y=3e4,I=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},files:{type:"array",items:{type:"string"},description:"Optional absolute local file paths. Each file is uploaded through Agent API OSS presign before sending."},final:{type:"boolean",description:"Whether this is the final reply for the event. Defaults to false \u2014 the event stays open while Claude continues working, and auto-completes after inactivity. Set true only when this is definitively the last message for the event."}},required:["chat_id","event_id"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},code:{type:"string"},msg:{type:"string"}},required:["event_id","status"]}},{name:"delete_message",description:"Delete a previously sent message in the same grix-claude chat.",inputSchema:{type:"object",properties:{chat_id:{type:"string"},message_id:{type:"string"}},required:["chat_id","message_id"]}},{name:"status",description:"Show grix-claude runtime status, upstream access state, bridge health, and startup hints.",inputSchema:{type:"object",properties:{}}},{name:"send",description:"Send a message to a chat session proactively, without requiring an inbound event. Use for notifications or scheduled reports.",inputSchema:{type:"object",properties:{chat_id:{type:"string",description:"The target chat/session id."},text:{type:"string",description:"The message text to send."}},required:["chat_id","text"]}},{name:"access_pair",description:"Forward a sender pairing approval code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"access_deny",description:"Forward a sender pairing denial code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"allow_sender",description:"Ask upstream access control to allow a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"remove_sender",description:"Ask upstream access control to remove a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"access_policy",description:"Ask upstream access control to update the sender access policy.",inputSchema:{type:"object",properties:{policy:{type:"string",enum:["allowlist","open","disabled"]}},required:["policy"]}},{name:"grix_query",description:"Search contacts, sessions, message history, or messages by keyword in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},keyword:{type:"string"},id:{type:"string"},sessionId:{type:"string"},limit:{type:"number"},offset:{type:"number"},beforeId:{type:"string"}},required:["action"]}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string"},memberIds:{type:"array",items:{type:"string"}},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer",description:"Member type (for update_member_role / update_member_speaking)."},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted (for update_member_speaking)."}},required:["action"]}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},content:{type:"string"},msgType:{type:"number"},quotedMessageId:{type:"string"},threadId:{type:"string"}},required:["sessionId","content"]}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},msgId:{type:"string"}},required:["sessionId","msgId"]}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentId:{type:"string"},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"number"}},required:["action"]}}];function q(r,e){r.setRequestHandler(w,async()=>({tools:I})),r.setRequestHandler(S,async i=>{const{name:n,arguments:t}=i.params,s=t??{};try{switch(n){case"reply":return await A(s,e);case"complete":return await $(s,e);case"delete_message":return await T(s,e);case"status":return j(e);case"send":return await M(s,e);case"access_pair":case"access_deny":case"allow_sender":case"remove_sender":case"access_policy":return await R(n,s,e);case"grix_query":case"grix_group":case"grix_message_send":case"grix_message_unsend":case"grix_admin":return await O(n,s,e);default:return{content:[{type:"text",text:`Unknown tool: ${n}`}],isError:!0}}}catch(a){return f.error("claude-tools",`Tool ${n} error: ${a}`),{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],isError:!0}}})}async function A(r,e){const i=e.getActiveEvent();if(!i)return{content:[{type:"text",text:"No active event to reply to"}],isError:!0};const n=String(r.text??""),t=String(r.chat_id??""),s=String(r.event_id??i.eventId),a=r.reply_to,d=r.files,_=r.final===!0;if(!t||!s)return{content:[{type:"text",text:"reply requires chat_id and event_id"}],isError:!0};if(!n.trim()&&(!d||d.length===0))return{content:[{type:"text",text:"reply requires at least one of text or files"}],isError:!0};const{text:g,quotedMessageId:v}=e.resolveQuotedMessageId(a,n),b=[];let m=0;const h=`reply_${s}_${Date.now()}`;try{if(g){const p=e.splitText(g);for(let o=0;o<p.length;o++){if(!e.isEventActive(s))return c("ignored: event no longer active");m++,e.bridge.sendStreamChunk(s,t,p[o],++i.chunkSeq,!1,h)}}if(d&&d.length>0)for(const p of d){if(!e.isEventActive(s))return c("ignored: event no longer active");m++;const o=await e.uploadFile(p,t),l=`${x()}_${m}`;e.bridge.sendMedia(s,t,o.access_url,o.file_name,v,l,o.extra),f.info("claude-tools",`File sent: ${o.file_name}`)}e.bridge.sendStreamChunk(s,t,"",++i.chunkSeq,!0,h)}catch(p){if(g&&b.length===0)try{const o=`fallback_${s}_${Date.now()}`,l=e.splitText(g);for(let u=0;u<l.length;u++)e.bridge.sendStreamChunk("",t,l[u],u+1,!1,o);return e.bridge.sendStreamChunk("",t,"",l.length+1,!0,o),e.markReplySent(s),_&&e.finalizeEvent(s,"responded"),c("sent via fallback")}catch{}if(!e.isEventActive(s))return c("ignored: event no longer active");throw e.bridge.sendEventResult(s,"failed",String(p),"send_msg_failed"),p}return e.markReplySent(s),_?e.finalizeEvent(s,"responded"):(i.responded=!0,e.clearActiveEvent("completed")),c("Reply sent")}async function $(r,e){const i=e.getActiveEvent(),n=String(r.event_id??""),t=r.status??"",s=r.code,a=r.msg;if(!n||!t)return{content:[{type:"text",text:"complete requires event_id and status"}],isError:!0};const d=["responded","canceled","failed"];return d.includes(t)?e.isEventActive(n)?(e.bridge.sendEventResult(n,t,a,s),e.clearActiveEvent(t),c("Event completed")):c("ignored: event no longer active"):{content:[{type:"text",text:`status must be one of: ${d.join(", ")}`}],isError:!0}}async function T(r,e){const i=String(r.chat_id??""),n=String(r.message_id??"");if(!i||!n)return{content:[{type:"text",text:"chat_id and message_id are required"}],isError:!0};try{return await e.bridge.agentInvoke("grix_message_unsend",{sessionId:i,msgId:n},y),c(`deleted (${n})`)}catch(t){return{content:[{type:"text",text:`Delete failed: ${t}`}],isError:!0}}}function j(r){const e=r.getStatusInfo();return{content:[{type:"text",text:JSON.stringify({alive:e.alive,active_event:e.activeEvent,pending_approvals:e.pendingPermissions,pending_questions:e.pendingElicitations})}]}}async function M(r,e){const i=String(r.chat_id??""),n=String(r.text??"");if(!i||!n)return{content:[{type:"text",text:"chat_id and text are required"}],isError:!0};try{const t=e.splitText(n),s=`send_${i}_${Date.now()}`;for(let a=0;a<t.length;a++)e.bridge.sendStreamChunk("",i,t[a],a+1,!1,s);return e.bridge.sendStreamChunk("",i,"",t.length+1,!0,s),c("sent")}catch(t){return{content:[{type:"text",text:`Send failed: ${t}`}],isError:!0}}}const C={access_pair:{verb:"pair_approve",payloadKey:"code"},access_deny:{verb:"pair_deny",payloadKey:"code"},allow_sender:{verb:"sender_allow",payloadKey:"sender_id"},remove_sender:{verb:"sender_remove",payloadKey:"sender_id"},access_policy:{verb:"policy_set",payloadKey:"policy"}};async function R(r,e,i){try{const n=C[r];if(!n)throw new Error(`Unknown access control tool: ${r}`);const t={};e.code!=null&&(t.code=e.code),e.sender_id!=null&&(t.sender_id=e.sender_id),e.policy!=null&&(t.policy=e.policy);const s=await i.bridge.agentInvoke("claude_access_control",{verb:n.verb,payload:t},y);return{content:[{type:"text",text:typeof s=="string"?s:JSON.stringify(s)}]}}catch(n){return{content:[{type:"text",text:`${r} failed: ${n}`}],isError:!0}}}async function O(r,e,i){try{const n=k(r,e);if(!E.has(n.action))throw new Error(`Action not allowed: ${n.action}`);const t=await i.bridge.agentInvoke(n.action,n.params,y);if(t&&Number(t.code??0)!==0)throw new Error(String(t.msg??"invoke failed"));return{content:[{type:"text",text:t?.data!=null?typeof t.data=="string"?t.data:JSON.stringify(t.data):JSON.stringify(t)}]}}catch(n){return{content:[{type:"text",text:`${r} failed: ${n}`}],isError:!0}}}function c(r){return{content:[{type:"text",text:r}]}}export{q as registerClaudeTools};
1
+ import{randomUUID as x}from"node:crypto";import{CallToolRequestSchema as S,ListToolsRequestSchema as w}from"@modelcontextprotocol/sdk/types.js";import{log as f}from"../../core/log/index.js";import{toolCallToInvoke as k}from"../../core/mcp/tools.js";const E=new Set(["contact_search","session_search","message_history","message_search","group_create","group_detail_read","group_leave_self","group_member_add","group_member_remove","group_member_role_update","group_all_members_muted_update","group_member_speaking_update","group_dissolve","send_msg","delete_msg","agent_api_create","agent_category_list","agent_category_create","agent_category_update","agent_category_assign","agent_api_key_rotate"]),y=3e4,I=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},files:{type:"array",items:{type:"string"},description:"Optional absolute local file paths. Each file is uploaded through Agent API OSS presign before sending."},final:{type:"boolean",description:"Whether this is the final reply for the event. Defaults to false \u2014 the event stays open while Claude continues working, and auto-completes after inactivity. Set true only when this is definitively the last message for the event."}},required:["chat_id","event_id"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},code:{type:"string"},msg:{type:"string"}},required:["event_id","status"]}},{name:"delete_message",description:"Delete a previously sent message in the same grix-claude chat.",inputSchema:{type:"object",properties:{chat_id:{type:"string"},message_id:{type:"string"}},required:["chat_id","message_id"]}},{name:"status",description:"Show grix-claude runtime status, upstream access state, bridge health, and startup hints.",inputSchema:{type:"object",properties:{}}},{name:"send",description:"Send a message to a chat session proactively, without requiring an inbound event. Use for notifications or scheduled reports.",inputSchema:{type:"object",properties:{chat_id:{type:"string",description:"The target chat/session id."},text:{type:"string",description:"The message text to send."}},required:["chat_id","text"]}},{name:"access_pair",description:"Forward a sender pairing approval code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"access_deny",description:"Forward a sender pairing denial code to upstream access control.",inputSchema:{type:"object",properties:{code:{type:"string"}},required:["code"]}},{name:"allow_sender",description:"Ask upstream access control to allow a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"remove_sender",description:"Ask upstream access control to remove a sender_id.",inputSchema:{type:"object",properties:{sender_id:{type:"string"}},required:["sender_id"]}},{name:"access_policy",description:"Ask upstream access control to update the sender access policy.",inputSchema:{type:"object",properties:{policy:{type:"string",enum:["allowlist","open","disabled"]}},required:["policy"]}},{name:"grix_query",description:"Search contacts, sessions, message history, or messages by keyword in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},keyword:{type:"string"},id:{type:"string"},sessionId:{type:"string"},limit:{type:"number"},offset:{type:"number"},beforeId:{type:"string"}},required:["action"]}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string"},memberIds:{type:"array",items:{type:"string"}},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer",description:"Member type (for update_member_role / update_member_speaking)."},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted (for update_member_speaking)."}},required:["action"]}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},content:{type:"string"},msgType:{type:"number"},quotedMessageId:{type:"string"},threadId:{type:"string"}},required:["sessionId","content"]}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string"},msgId:{type:"string"}},required:["sessionId","msgId"]}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentId:{type:"string"},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"number"}},required:["action"]}}];function q(n,e){n.setRequestHandler(w,async()=>({tools:I})),n.setRequestHandler(S,async i=>{const{name:r,arguments:t}=i.params,s=t??{};try{switch(r){case"reply":return await A(s,e);case"complete":return await $(s,e);case"delete_message":return await T(s,e);case"status":return j(e);case"send":return await M(s,e);case"access_pair":case"access_deny":case"allow_sender":case"remove_sender":case"access_policy":return await R(r,s,e);case"grix_query":case"grix_group":case"grix_message_send":case"grix_message_unsend":case"grix_admin":return await O(r,s,e);default:return{content:[{type:"text",text:`Unknown tool: ${r}`}],isError:!0}}}catch(a){return f.error("claude-tools",`Tool ${r} error: ${a}`),{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],isError:!0}}})}async function A(n,e){const i=e.getActiveEvent();if(!i)return{content:[{type:"text",text:"No active event to reply to"}],isError:!0};const r=String(n.text??""),t=String(n.chat_id??""),s=String(n.event_id??i.eventId),a=n.reply_to,d=n.files,_=n.final===!0;if(!t||!s)return{content:[{type:"text",text:"reply requires chat_id and event_id"}],isError:!0};if(!r.trim()&&(!d||d.length===0))return{content:[{type:"text",text:"reply requires at least one of text or files"}],isError:!0};const{text:g,quotedMessageId:v}=e.resolveQuotedMessageId(a,r),b=[];let m=0;const h=`reply_${s}_${Date.now()}`;try{if(g){const p=e.splitText(g);for(let o=0;o<p.length;o++){if(!e.isEventActive(s))return c("ignored: event no longer active");m++,e.bridge.sendStreamChunk(s,t,p[o],++i.chunkSeq,!1,h)}}if(d&&d.length>0)for(const p of d){if(!e.isEventActive(s))return c("ignored: event no longer active");m++;const o=await e.uploadFile(p,t),l=`${x()}_${m}`;e.bridge.sendMedia(s,t,o.access_url,o.file_name,v,l,o.extra),f.info("claude-tools",`File sent: ${o.file_name}`)}e.bridge.sendStreamChunk(s,t,"",++i.chunkSeq,!0,h)}catch(p){if(g&&b.length===0)try{const o=`fallback_${s}_${Date.now()}`,l=e.splitText(g);for(let u=0;u<l.length;u++)e.bridge.sendStreamChunk("",t,l[u],u+1,!1,o);return e.bridge.sendStreamChunk("",t,"",l.length+1,!0,o),e.markReplySent(s),_&&e.finalizeEvent(s,"responded"),c("sent via fallback")}catch{}if(!e.isEventActive(s))return c("ignored: event no longer active");throw e.bridge.sendEventResult(s,"failed",String(p),"send_msg_failed"),p}return e.markReplySent(s),_?e.finalizeEvent(s,"responded"):(i.responded=!0,e.clearActiveEvent("completed")),c("Reply sent")}async function $(n,e){const i=e.getActiveEvent(),r=String(n.event_id??""),t=n.status??"",s=n.code,a=n.msg;if(!r||!t)return{content:[{type:"text",text:"complete requires event_id and status"}],isError:!0};const d=["responded","canceled","failed"];return d.includes(t)?e.isEventActive(r)?(e.bridge.sendEventResult(r,t,a,s),e.clearActiveEvent(t),c("Event completed")):c("ignored: event no longer active"):{content:[{type:"text",text:`status must be one of: ${d.join(", ")}`}],isError:!0}}async function T(n,e){const i=String(n.chat_id??""),r=String(n.message_id??"");if(!i||!r)return{content:[{type:"text",text:"chat_id and message_id are required"}],isError:!0};try{return await e.bridge.agentInvoke("grix_message_unsend",{sessionId:i,msgId:r},y),c(`deleted (${r})`)}catch(t){return{content:[{type:"text",text:`Delete failed: ${t}`}],isError:!0}}}function j(n){const e=n.getStatusInfo();return{content:[{type:"text",text:JSON.stringify({alive:e.alive,active_event:e.activeEvent,pending_approvals:e.pendingPermissions,pending_questions:e.pendingElicitations})}]}}async function M(n,e){const i=String(n.chat_id??""),r=String(n.text??"");if(!i||!r)return{content:[{type:"text",text:"chat_id and text are required"}],isError:!0};try{const t=e.splitText(r),s=`send_${i}_${Date.now()}`;for(let a=0;a<t.length;a++)e.bridge.sendStreamChunk("",i,t[a],a+1,!1,s);return e.bridge.sendStreamChunk("",i,"",t.length+1,!0,s),c("sent")}catch(t){return{content:[{type:"text",text:`Send failed: ${t}`}],isError:!0}}}const C={access_pair:{verb:"pair_approve",payloadKey:"code"},access_deny:{verb:"pair_deny",payloadKey:"code"},allow_sender:{verb:"sender_allow",payloadKey:"sender_id"},remove_sender:{verb:"sender_remove",payloadKey:"sender_id"},access_policy:{verb:"policy_set",payloadKey:"policy"}};async function R(n,e,i){try{const r=C[n];if(!r)throw new Error(`Unknown access control tool: ${n}`);const t={};e.code!=null&&(t.code=e.code),e.sender_id!=null&&(t.sender_id=e.sender_id),e.policy!=null&&(t.policy=e.policy);const s=await i.bridge.agentInvoke("claude_access_control",{verb:r.verb,payload:t},y);return{content:[{type:"text",text:typeof s=="string"?s:JSON.stringify(s)}]}}catch(r){return{content:[{type:"text",text:`${n} failed: ${r}`}],isError:!0}}}async function O(n,e,i){try{const r=k(n,e);if(!E.has(r.action))throw new Error(`Action not allowed: ${r.action}`);const t=await i.bridge.agentInvoke(r.action,r.params,y);if(t&&Number(t.code??0)!==0)throw new Error(String(t.msg??"invoke failed"));return{content:[{type:"text",text:t?.data!=null?typeof t.data=="string"?t.data:JSON.stringify(t.data):JSON.stringify(t)}]}}catch(r){return{content:[{type:"text",text:`${n} failed: ${r}`}],isError:!0}}}function c(n){return{content:[{type:"text",text:n}]}}export{q as registerClaudeTools};
@@ -1 +1 @@
1
- import{log as l}from"../../core/log/index.js";class c{controlURL="";token="";isConfigured(){return!!(this.controlURL&&this.token)}configure(r,e){this.controlURL=r.replace(/\/+$/,""),this.token=e.trim(),l.info("claude-worker-client",`Configured with control URL: ${this.controlURL}`)}async post(r,e,s){if(!this.isConfigured())throw new Error("worker control not configured");const i=new AbortController,o=setTimeout(()=>i.abort(),s);try{const t=await fetch(`${this.controlURL}${r}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${this.token}`},body:JSON.stringify(e),signal:i.signal}),n=await t.text(),a=n.trim()?JSON.parse(n):{};if(!t.ok)throw new Error(a.error||`worker control failed ${t.status}`);return a}finally{clearTimeout(o)}}isRetryableError(r){const e=r instanceof Error?r.message:String(r);return/fetch failed|network|ECONNRESET|ETIMEDOUT|EAI_AGAIN|socket hang up|aborted/i.test(e)}async postWithRetry(r,e,s,i=1){let o;for(let t=0;t<=i;t++)try{return t>0&&l.info("claude-worker-client",`Retrying ${r} attempt=${t+1}`),await this.post(r,e,s)}catch(n){if(o=n,t>=i||!this.isRetryableError(n))break;await new Promise(a=>setTimeout(a,150))}throw o instanceof Error?o:new Error(String(o))}async deliverEvent(r){return this.postWithRetry("/v1/worker/deliver-event",{payload:r},1e4,1)}async deliverStop(r){return this.postWithRetry("/v1/worker/deliver-stop",{payload:r},1e4,1)}async deliverLocalAction(r){return this.postWithRetry("/v1/worker/deliver-local-action",{payload:r},1e4,1)}async ping(){try{return await this.postWithRetry("/v1/worker/ping",{},5e3,1),!0}catch{return!1}}}export{c as ClaudeWorkerClient};
1
+ import{log as l}from"../../core/log/index.js";class c{controlURL="";token="";isConfigured(){return!!(this.controlURL&&this.token)}configure(t,e){this.controlURL=t.replace(/\/+$/,""),this.token=e.trim(),l.info("claude-worker-client",`Configured with control URL: ${this.controlURL}`)}async post(t,e,s){if(!this.isConfigured())throw new Error("worker control not configured");const i=new AbortController,o=setTimeout(()=>i.abort(),s);try{const r=await fetch(`${this.controlURL}${t}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${this.token}`},body:JSON.stringify(e),signal:i.signal}),n=await r.text(),a=n.trim()?JSON.parse(n):{};if(!r.ok)throw new Error(a.error||`worker control failed ${r.status}`);return a}finally{clearTimeout(o)}}isRetryableError(t){const e=t instanceof Error?t.message:String(t);return/fetch failed|network|ECONNRESET|ETIMEDOUT|EAI_AGAIN|socket hang up|aborted/i.test(e)}async postWithRetry(t,e,s,i=1){let o;for(let r=0;r<=i;r++)try{return r>0&&l.info("claude-worker-client",`Retrying ${t} attempt=${r+1}`),await this.post(t,e,s)}catch(n){if(o=n,r>=i||!this.isRetryableError(n))break;await new Promise(a=>setTimeout(a,150))}throw o instanceof Error?o:new Error(String(o))}async deliverEvent(t){return this.postWithRetry("/v1/worker/deliver-event",{payload:t},1e4,1)}async deliverStop(t){return this.postWithRetry("/v1/worker/deliver-stop",{payload:t},1e4,1)}async deliverLocalAction(t){return this.postWithRetry("/v1/worker/deliver-local-action",{payload:t},1e4,1)}async ping(){try{return await this.postWithRetry("/v1/worker/ping",{},5e3,1),!0}catch{return!1}}}export{c as ClaudeWorkerClient};
@@ -1,2 +1,2 @@
1
- import{spawn as x,execSync as y}from"node:child_process";import{randomUUID as v}from"node:crypto";import{mkdir as S}from"node:fs/promises";import{readFileSync as C}from"node:fs";import{join as d}from"node:path";import{homedir as T,tmpdir as I}from"node:os";import{log as o}from"../../core/log/index.js";import{MCP_HTTP_CHANNEL_NAME as m}from"./protocol-contract.js";function P(t){let e=null,r=0,n=!1,i=!1;const a=v(),s=t.gatewayUrl??"http://127.0.0.1:19580/mcp";return{async start(){await F(t.command,s,t.env);const c=E(t.grix),u=[...t.args??[],"--name",`grix-mcp-${t.name}`,"--session-id",a];t.fullAuto&&u.push("--dangerously-skip-permissions"),u.push("--dangerously-load-development-channels",`server:${m}`,"--append-system-prompt",c);const f=d(I(),`grix-mcp-claude-${t.name}`);await S(f,{recursive:!0});const{expectPath:$,pidPath:g}=await M(f,t.command,u),_={...process.env,...t.env??{}};e=x("/usr/bin/expect",[$],{cwd:t.cwd,env:_,stdio:["ignore","pipe","pipe"],detached:!0}),o.info("mcp-http-launcher",`\u542F\u52A8 Claude: name=${t.name} cwd=${t.cwd} pid=${e.pid}`),r=await k(g),n=!0,o.info("mcp-http-launcher",`Claude \u5B50\u8FDB\u7A0B PID: ${r}`),e.on("exit",(l,p)=>{o.info("mcp-http-launcher",`Claude \u9000\u51FA: code=${l} signal=${p}`),n=!1,e=null,r=0,i||(o.info("mcp-http-launcher","3 \u79D2\u540E\u81EA\u52A8\u91CD\u542F..."),setTimeout(()=>{i||this.start().catch(w=>{o.error("mcp-http-launcher",`\u91CD\u542F\u5931\u8D25: ${w}`)})},3e3))}),e.stdout?.on("data",l=>{const p=l.toString().trim();p&&o.info("mcp-http-launcher",`[stdout] ${p.slice(0,300)}`)}),e.stderr?.on("data",l=>{const p=l.toString().trim();p&&o.info("mcp-http-launcher",`[stderr] ${p.slice(0,300)}`)})},async stop(){if(i=!0,n=!1,r>0)try{process.kill(r,"SIGTERM")}catch{}if(e?.pid){try{process.kill(-e.pid,"SIGTERM")}catch{}await new Promise(c=>{const u=setTimeout(()=>{if(r>0)try{process.kill(r,"SIGKILL")}catch{}if(e?.pid)try{process.kill(-e.pid,"SIGKILL")}catch{}c()},5e3);e?.once("exit",()=>{clearTimeout(u),c()})})}e=null,r=0},getStatus(){return{name:t.name,alive:n,pid:r}}}}function E(t){return["You are connected to a chat via the grix MCP server.",`On startup, immediately call grix_authorize with: agentId="${t.agentId}", apiKey="${t.apiKey}", wsUrl="${t.wsUrl}", clientType="${t.clientType}".`,"When you receive a <channel> message, you MUST respond by calling the grix_reply tool (or the grix_complete tool if no response is needed).","Never write your reply as plain text \u2014 it will NOT reach the user. Only the grix_reply tool delivers your response to the chat.","The <channel> message contains event_id and session_id \u2014 pass them to grix_reply."].join(" ")}async function F(t,e,r){const n=d(T(),".claude.json");let i=null;try{const s=C(n,"utf8");i=JSON.parse(s)?.mcpServers?.[m]??null}catch{}if(i&&String(i.type??"").trim()==="http"&&String(i.url??"").trim()===e)return;o.info("mcp-http-launcher",`\u6CE8\u518C MCP Server: ${m} -> ${e}`);const a={...process.env,...r??{}};try{y(`${t} mcp remove -s user ${m}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}catch{}y(`${t} mcp add --scope user --transport http ${m} ${e}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}async function M(t,e,r){const{writeFile:n}=await import("node:fs/promises"),i=d(t,"claude.pid"),a=d(t,"claude.expect"),s=["log_user 1","set timeout -1","set startup_prompt_armed 1",`set claude_command [list {${h(e)}}${r.map(c=>` {${h(c)}}`).join("")}]`,"spawn -noecho {*}$claude_command",`set pid_file [open {${h(i)}} w]`,"puts $pid_file [exp_pid -i $spawn_id]","close $pid_file","expect {"," -re {(?i)(Quick.*safety.*check|trust.*folder)} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)I am using this for local development} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)(Enter.*confirm|Press.*Enter|Hit.*Enter)} {",' if {$startup_prompt_armed} { send -- "\\r"; after 300 }; exp_continue'," }"," -re {Listening for channel} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," -re {bypass permissions} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," eof {}","}","expect eof",""];return await n(i,"","utf8"),await n(a,s.join(`
2
- `),"utf8"),{expectPath:a,pidPath:i}}function h(t){return t.replace(/[\\{}$\[\]"]/g,"\\$&")}async function k(t,e=1e4){const{readFile:r}=await import("node:fs/promises"),n=Math.ceil(e/100);for(let i=0;i<n;i++){try{const a=await r(t,"utf8"),s=parseInt(String(a).trim(),10);if(Number.isFinite(s)&&s>0)return s}catch{}await new Promise(a=>setTimeout(a,100))}return 0}export{P as createMcpHttpLauncher};
1
+ import{spawn as x,execSync as y}from"node:child_process";import{randomUUID as v}from"node:crypto";import{mkdir as S}from"node:fs/promises";import{readFileSync as C}from"node:fs";import{join as d}from"node:path";import{homedir as T,tmpdir as I}from"node:os";import{log as o}from"../../core/log/index.js";import{MCP_HTTP_CHANNEL_NAME as l}from"./protocol-contract.js";function P(e){let t=null,r=0,n=!1,i=!1;const a=v(),s=e.gatewayUrl??"http://127.0.0.1:19580/mcp";return{async start(){await F(e.command,s,e.env);const c=E(e.grix),u=[...e.args??[],"--name",`grix-mcp-${e.name}`,"--session-id",a];e.fullAuto&&u.push("--dangerously-skip-permissions"),u.push("--dangerously-load-development-channels",`server:${l}`,"--append-system-prompt",c);const f=d(I(),`grix-mcp-claude-${e.name}`);await S(f,{recursive:!0});const{expectPath:$,pidPath:g}=await M(f,e.command,u),_={...process.env,...e.env??{}};t=x("/usr/bin/expect",[$],{cwd:e.cwd,env:_,stdio:["ignore","pipe","pipe"],detached:!0}),o.info("mcp-http-launcher",`\u542F\u52A8 Claude: name=${e.name} cwd=${e.cwd} pid=${t.pid}`),r=await k(g),n=!0,o.info("mcp-http-launcher",`Claude \u5B50\u8FDB\u7A0B PID: ${r}`),t.on("exit",(m,p)=>{o.info("mcp-http-launcher",`Claude \u9000\u51FA: code=${m} signal=${p}`),n=!1,t=null,r=0,i||(o.info("mcp-http-launcher","3 \u79D2\u540E\u81EA\u52A8\u91CD\u542F..."),setTimeout(()=>{i||this.start().catch(w=>{o.error("mcp-http-launcher",`\u91CD\u542F\u5931\u8D25: ${w}`)})},3e3))}),t.stdout?.on("data",m=>{const p=m.toString().trim();p&&o.info("mcp-http-launcher",`[stdout] ${p.slice(0,300)}`)}),t.stderr?.on("data",m=>{const p=m.toString().trim();p&&o.info("mcp-http-launcher",`[stderr] ${p.slice(0,300)}`)})},async stop(){if(i=!0,n=!1,r>0)try{process.kill(r,"SIGTERM")}catch{}if(t?.pid){try{process.kill(-t.pid,"SIGTERM")}catch{}await new Promise(c=>{const u=setTimeout(()=>{if(r>0)try{process.kill(r,"SIGKILL")}catch{}if(t?.pid)try{process.kill(-t.pid,"SIGKILL")}catch{}c()},5e3);t?.once("exit",()=>{clearTimeout(u),c()})})}t=null,r=0},getStatus(){return{name:e.name,alive:n,pid:r}}}}function E(e){return["You are connected to a chat via the grix MCP server.",`On startup, immediately call grix_authorize with: agentId="${e.agentId}", apiKey="${e.apiKey}", wsUrl="${e.wsUrl}", clientType="${e.clientType}".`,"When you receive a <channel> message, you MUST respond by calling the grix_reply tool (or the grix_complete tool if no response is needed).","Never write your reply as plain text \u2014 it will NOT reach the user. Only the grix_reply tool delivers your response to the chat.","The <channel> message contains event_id and session_id \u2014 pass them to grix_reply."].join(" ")}async function F(e,t,r){const n=d(T(),".claude.json");let i=null;try{const s=C(n,"utf8");i=JSON.parse(s)?.mcpServers?.[l]??null}catch{}if(i&&String(i.type??"").trim()==="http"&&String(i.url??"").trim()===t)return;o.info("mcp-http-launcher",`\u6CE8\u518C MCP Server: ${l} -> ${t}`);const a={...process.env,...r??{}};try{y(`${e} mcp remove -s user ${l}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}catch{}y(`${e} mcp add --scope user --transport http ${l} ${t}`,{encoding:"utf8",timeout:1e4,env:a,stdio:"pipe"})}async function M(e,t,r){const{writeFile:n}=await import("node:fs/promises"),i=d(e,"claude.pid"),a=d(e,"claude.expect"),s=["log_user 1","set timeout -1","set startup_prompt_armed 1",`set claude_command [list {${h(t)}}${r.map(c=>` {${h(c)}}`).join("")}]`,"spawn -noecho {*}$claude_command",`set pid_file [open {${h(i)}} w]`,"puts $pid_file [exp_pid -i $spawn_id]","close $pid_file","expect {"," -re {(?i)(Quick.*safety.*check|trust.*folder)} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)I am using this for local development} {",' if {$startup_prompt_armed} { send -- "1\\r"; after 300 }; exp_continue'," }"," -re {(?i)(Enter.*confirm|Press.*Enter|Hit.*Enter)} {",' if {$startup_prompt_armed} { send -- "\\r"; after 300 }; exp_continue'," }"," -re {Listening for channel} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," -re {bypass permissions} {"," set startup_prompt_armed 0"," after 1000",' send -- "Call grix_authorize now as instructed in your system prompt.\\r"'," }"," eof {}","}","expect eof",""];return await n(i,"","utf8"),await n(a,s.join(`
2
+ `),"utf8"),{expectPath:a,pidPath:i}}function h(e){return e.replace(/[\\{}$\[\]"]/g,"\\$&")}async function k(e,t=1e4){const{readFile:r}=await import("node:fs/promises"),n=Math.ceil(t/100);for(let i=0;i<n;i++){try{const a=await r(e,"utf8"),s=parseInt(String(a).trim(),10);if(Number.isFinite(s)&&s>0)return s}catch{}await new Promise(a=>setTimeout(a,100))}return 0}export{P as createMcpHttpLauncher};
@@ -1 +1 @@
1
- class m{defaultTimeoutMs;onTimeout;timers=new Map;constructor(e){this.defaultTimeoutMs=e.defaultTimeoutMs??9e4,this.onTimeout=e.onTimeout}arm(e,t){this.cancel(e);const s=t?.timeoutMs??this.defaultTimeoutMs,i=Date.now()+s,o=setTimeout(()=>{this.timers.delete(e),this.onTimeout(e).catch(()=>{})},s);return this.timers.set(e,o),i}cancel(e){const t=this.timers.get(e);t&&(clearTimeout(t),this.timers.delete(e))}has(e){return this.timers.has(e)}close(){for(const e of this.timers.values())clearTimeout(e);this.timers.clear()}}export{m as ResultTimeoutManager};
1
+ class m{defaultTimeoutMs;onTimeout;timers=new Map;constructor(t){this.defaultTimeoutMs=t.defaultTimeoutMs??9e4,this.onTimeout=t.onTimeout}arm(t,e){this.cancel(t);const s=e?.timeoutMs??this.defaultTimeoutMs,i=Date.now()+s,o=setTimeout(()=>{this.timers.delete(t),this.onTimeout(t).catch(()=>{})},s);return this.timers.set(t,o),i}cancel(t){const e=this.timers.get(t);e&&(clearTimeout(e),this.timers.delete(t))}has(t){return this.timers.has(t)}close(){for(const t of this.timers.values())clearTimeout(t);this.timers.clear()}}export{m as ResultTimeoutManager};
@@ -1,12 +1,12 @@
1
- import{execFileSync as Y}from"node:child_process";import{createInterface as pe}from"node:readline";import{EventEmitter as K}from"node:events";import{stat as Z}from"node:fs/promises";import{join as P,resolve as fe}from"node:path";import{fileURLToPath as me}from"node:url";import{syncDefaultSkillsToDir as ge}from"../../default-skills/index.js";import{resolveCommandPath as ve,spawnCommand as Ie,killProcessGroup as Q,hasChildProcesses as xe}from"../../core/runtime/spawn.js";import{InternalApiServer as ye}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as we,LEGACY_MCP_SERVER_NAMES as _e}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as Te}from"../shared/inbound-message-id-injector.js";import{log as d}from"../../core/log/index.js";import{resolveClientVersion as Ce}from"../../core/util/client-version.js";import{isThinkingAgentMessagePhase as L,isUserVisibleAgentMessagePhase as N}from"../../core/util/codex-output-policy.js";import{SessionBindingStore as be}from"../../core/persistence/session-binding-store.js";import{ensureCodexProjectTrusted as Ae,isCodexCommand as Ee,readCodexProviderSettings as F,resolveCodexHome as Se}from"./codex-trust.js";import{prepareCodexDirectHome as Re}from"./direct-home.js";import{checkCodexSessionActivity as Me,inspectCodexTurnProgress as ke}from"./session-activity.js";import{findRolloutFile as Pe}from"./rollout-locator.js";import{checkCodexLock as ee}from"./lock-monitor.js";import{resolveCliPath as De,getCliVersion as $e}from"../../core/util/cli-probe.js";import{scanSkills as Oe}from"../claude/skill-scanner.js";import{normalizeCodexConfigOverrides as te}from"./config-overrides.js";import{buildCodexOpenAiCompatibleProviderOverrides as Le,CODEX_RELAY_OPENAI_PROVIDER_ID as Ne,prepareCodexRawCapture as Fe,resolveCodexProviderName as je,resolveCodexRawCaptureTarget as He,resolveCodexProviderSupportsWebsocketsConfigKey as Ue}from"./raw-capture-hook.js";import{unavailableRawApiCaptureBoundary as qe}from"../../audit/raw-capture/capture-relay.js";const Be=60*1e3,ze=600*1e3,We="GRIX_RELAY_PROXY",Ve=5*1e3,Ge=15*1e3,ie=3;function j(a,e){const t=Number(process.env[a]);return Number.isFinite(t)&&t>0?t:e}function Xe(a){const e=Number(process.env[a]);return Number.isFinite(e)&&e>0?e:null}function Je(a){if(!a||typeof a!="object"||Array.isArray(a))return;const e=a,t=typeof e.auditId=="string"?e.auditId.trim():"",i=typeof e.sessionId=="string"?e.sessionId.trim():"",s=typeof e.spoolRootDir=="string"?e.spoolRootDir.trim():"";return t&&i&&s?{auditId:t,sessionId:i,spoolRootDir:s}:void 0}const H=j("GRIX_CODEX_PREFLIGHT_STALL_TIMEOUT_MS",120*1e3),Ye=20,Ke=8e3,se=2*1024,ne=`
2
- \u2026(truncated)`,re=80,Ze=120*1e3,Qe=j("GRIX_CODEX_DELTA_COALESCE_MS",1e3),et=j("GRIX_CODEX_DELTA_COALESCE_CHARS",4096),tt=[{id:"gpt-5.3-codex",displayName:"GPT-5.3 Codex",defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!0}],oe=[{id:"default",displayName:"Default"},{id:"plan",displayName:"Plan"}],it=new Set(["rawResponse/completed","codex/rawResponse/completed","rawResponseItem/completed","codex/rawResponseItem/completed","thread/tokenUsage/updated","codex/thread/tokenUsage/updated","thread/compacted","codex/thread/compacted","turn/started","codex/turn/started","turn/completed","codex/turn/completed","item/started","codex/item/started","item/completed","codex/item/completed","error","codex/error"]);function ae(a,e){const t=String(a??"").trim()||"codex",i=ve(t,e);if(i!==t)return i;if(t!=="codex")return t;const s=process.platform==="win32"?[]:["/opt/homebrew/bin/codex","/usr/local/bin/codex","/usr/bin/codex"],n=process.platform!=="win32"?[]:[P(process.env.LOCALAPPDATA??"","npm","codex.cmd"),P(process.env.APPDATA??"","npm","codex.cmd"),P(process.env.LOCALAPPDATA??"","Programs","codex","codex.exe")],r=[...s,...n];for(const o of r)try{return require("node:fs").accessSync(o,require("node:fs").constants.X_OK),o}catch{continue}return d.warn("codex-adapter",`resolveCodexCommandPath: failed to resolve "${t}". envPath=${e?"provided":"missing (using process.env.PATH)"}. fallbacks tried: [${r.join(", ")}]`),t}class D extends K{type="codex";config;callbacks;process=null;alive=!1;stopped=!1;internalApi=null;bridgeStatus="starting";pendingRequests=new Map;requestId=0;threadId=null;initialized=!1;cwd;approvalPolicy;sandboxMode;model;collaborationMode;reasoningEffort;serviceTier;idleTimer=null;lastProgressAt=0;lastIdleCheckAt=0;activityGeneration=0;lastIdleCheckGeneration=0;idleNoProgressCount=0;inFlightToolOps=0;consecutivePingFailures=0;currentTurnStartedAt=0;preflightCheckComplete=!1;turnInactivityTimeoutMs=Xe("GRIX_CODEX_TURN_INACTIVITY_TIMEOUT_MS");pendingApprovals=new Map;needsHistoryInjection=!1;lastInjectedSessionId=null;identityInputInjectedThreadId=null;inboundMessageIds=new Te;legacyDeveloperInstructionsUnsupported=!1;profileIdentityRefreshPending=!1;bindingStore=null;aibotSessionId="";threadResumePending=!1;autoTrustProject="auto";codexHome;codexDirect=null;directEnv={};configOverrideArgs=[];rawCaptureOptions;rawCaptureRelay;rawCaptureConfigOverrides=[];rawCaptureUnavailableReason;codexModelOptions=[];codexModelOptionsCachedAt=0;static MODEL_CACHE_TTL_MS=3600*1e3;rateLimitSnapshot=null;lastNonDefaultLimitRefreshAt=0;static NON_DEFAULT_LIMIT_REFRESH_INTERVAL_MS=6e4;currentThreadTokenUsage=null;currentModelContextWindow=null;auditCaptureByEventId=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const i=e.options??{};this.approvalPolicy=i.approvalPolicy??"never",this.sandboxMode=typeof i.sandboxMode=="string"&&i.sandboxMode.trim()&&i.sandboxMode.trim()!=="default"?i.sandboxMode.trim():void 0,this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof be?i.bindingStore:null,this.model=i.model,this.collaborationMode=i.collaborationMode,this.reasoningEffort=i.reasoningEffort,this.serviceTier=i.serviceTier,this.bindingStore&&this.aibotSessionId&&(this.model=this.model??this.bindingStore.getCodexModelId(this.aibotSessionId),this.collaborationMode=this.collaborationMode??this.bindingStore.getCodexModeId(this.aibotSessionId),this.reasoningEffort=this.reasoningEffort??this.bindingStore.getCodexReasoningEffort(this.aibotSessionId),this.serviceTier=this.serviceTier??this.bindingStore.getCodexServiceTier(this.aibotSessionId),this.sandboxMode=this.sandboxMode??this.bindingStore.getCodexSandboxMode(this.aibotSessionId)),this.autoTrustProject=typeof i.autoTrustProject=="boolean"?i.autoTrustProject:"auto",this.codexHome=typeof i.codexHome=="string"&&i.codexHome.trim()?i.codexHome.trim():void 0;const s=i.codexDirect;if(this.codexDirect=s&&typeof s=="object"&&!Array.isArray(s)?s:null,this.configOverrideArgs=te(i.codexConfigOverrides,"codexConfigOverrides"),this.rawCaptureOptions=Je(i.rawApiCapture),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const n=this.bindingStore.getCodexThreadId(this.aibotSessionId);n&&(this.threadId=n,this.threadResumePending=!0)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){await this.prepareDirectHome(),await this.ensureProjectTrusted(),await this.prepareRawApiCapture();try{await this.startInternalApiAndRegisterMcp(),await this.spawnCodex(),await this.initializeHandshake(),await this.notifyBindingReadyWithContext(),d.info("codex-adapter",`Ready (pid=${this.process?.pid})`)}catch(e){throw await this.stopRawApiCapture(),e}}async prepareRawApiCapture(){if(this.rawCaptureOptions)try{const e=await Fe(this.rawCaptureOptions,{adapterType:"codex",sessionId:this.rawCaptureOptions.sessionId,cwd:this.cwd,env:this.resolveChildEnv(),configOverrides:this.configOverrideArgs,codexHome:this.codexHome});this.rawCaptureRelay=e.relay,this.rawCaptureConfigOverrides=e.overlay.configOverrides??[],this.rawCaptureUnavailableReason=void 0,d.info("codex-adapter","Raw API audit capture relay is ready")}catch(e){this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],this.rawCaptureUnavailableReason=e instanceof Error?e.message:String(e),d.warn("codex-adapter",`Raw API audit capture unavailable: ${this.rawCaptureUnavailableReason}`)}}async stopRawApiCapture(){const e=this.rawCaptureRelay;this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],e&&await e.stop()}async prepareDirectHome(){if(!this.codexDirect)return;const e=await Re(this.codexDirect);this.codexHome=e.codexHome,this.directEnv=e.env;const t=te(e.configOverrides,"codexDirect.configOverrides");this.configOverrideArgs=[...this.configOverrideArgs,...t],d.info("codex-adapter",`Codex direct home ready: ${e.codexHome} (catalog=${e.catalogVersion??"none"}, token=${e.tokenDigest?`present sha256:${e.tokenDigest}`:"absent"})`)}resolveChildEnv(){const e={...process.env,...this.config.env};return this.codexHome&&(e.CODEX_HOME=this.codexHome),e}async ensureProjectTrusted(){if(this.shouldAutoTrustProject())try{const e=await Ae(this.cwd,{codexHome:this.codexHome});e.changed&&d.info("codex-adapter",`Trusted Codex project ${this.cwd} in ${e.configPath}`)}catch(e){const t=e instanceof Error?e.message:String(e);throw d.error("codex-adapter",`Failed to trust Codex project ${this.cwd}: ${t}`),e}}async startInternalApiAndRegisterMcp(){try{this.internalApi=new ye,this.internalApi.setInvokeHandler(async(o,c,p,h)=>this.callbacks.agentInvoke(o,c,h)),await this.internalApi.start(0),d.info("codex-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t=this.resolveChildEnv(),i=typeof t.PATH=="string"?t.PATH:void 0,s=ae(this.config.command||"codex",i);for(const o of[..._e,e.name])try{Y(s,["mcp","remove",o],{env:t,timeout:1e4,stdio:"ignore"})}catch{}Y(s,["mcp","add",e.name,"--",e.command,...e.args],{env:t,timeout:1e4,stdio:"ignore"}),d.info("codex-adapter",`Registered MCP server: ${e.name}`);const n=P(Se(this.codexHome),"skills"),r=ge(n);r.length>0&&d.info("codex-adapter",`Synced connector skills to ${n}: [${r.join(", ")}]`)}catch(e){d.warn("codex-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}shouldAutoTrustProject(){return this.autoTrustProject===!1?!1:this.autoTrustProject===!0?!0:Ee(this.config.command)}notifyBindingReady(){!this.aibotSessionId||!this.cwd||this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd)}async notifyBindingReadyWithContext(){if(!(!this.aibotSessionId||!this.cwd))try{this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,await this.buildToolbarContextResult("binding_ready"))}catch(e){d.warn("codex-adapter",`Failed to attach toolbar context to binding update: ${e instanceof Error?e.message:String(e)}`),this.notifyBindingReady()}}externalProviderCheckedAt=0;externalProviderCached=!1;static EXTERNAL_PROVIDER_CACHE_TTL_MS=60*1e3;isExternalProvider(){const e=Date.now();if(e-this.externalProviderCheckedAt<D.EXTERNAL_PROVIDER_CACHE_TTL_MS)return this.externalProviderCached;const t=F(this.codexHome);return this.externalProviderCached=!!(t.baseUrl&&ce(t.baseUrl)),this.externalProviderCheckedAt=e,this.externalProviderCached}effectiveServiceTier(){if(!this.serviceTier||this.serviceTier.trim().toLowerCase()==="default"||this.isExternalProvider())return;const e=this.getModelOption(this.currentModelId());if(!(e&&!e.serviceTiers.some(t=>t.id===this.serviceTier)))return this.serviceTier}getEffortMeta(){if(this.isExternalProvider())return{};const e=this.currentModelId(),t=this.getModelOption(e),i={},s=t?.supportedReasoningEfforts??[];s.length>0&&(i.available_efforts=s,i.reasoning_effort=this.reasoningEffort??t?.defaultReasoningEffort??null);const n=t?.serviceTiers??[];return n.length>0&&(i.available_service_tiers=n,i.service_tier=this.effectiveServiceTier()??t?.defaultServiceTier??null),i}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.rejectAllPending("adapter stopped"),this.pendingAutoCompact=!1,this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);for(const t of this.compactionDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");for(const t of this.steerDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");this.internalApi&&(await this.internalApi.stop(),this.internalApi=null);const e=this.process;if(this.process=null,e?.pid&&typeof e.once=="function")Q(e,"SIGTERM"),await Promise.race([new Promise(i=>{e.once("exit",()=>i(!0))}),new Promise(i=>{setTimeout(()=>i(!1),5e3)})])||Q(e,"SIGKILL");else if(e)try{e.kill("SIGTERM")}catch{}await this.stopRawApiCapture()}isAlive(){return this.alive}async createSession(e){if(this.initialized||await this.initializeHandshake(),this.threadId||await this.startNewThread(),!this.threadId)throw new Error("Failed to create session: thread ID is missing");return await this.notifyBindingReadyWithContext(),this.threadId}async resumeSession(e,t){await this.ensureThreadResumed()}async destroySession(e){this.threadId=null,this.threadResumePending=!1,this.persistThreadId(void 0),this.inboundMessageIds.reset()}sendPrompt(e){const t=new z(e.adapterSessionId);return this.runTurn(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){if(this.threadId)try{await this.sendRequest("turn/interrupt",{threadId:this.threadId,turnId:this.currentTurnId??""},5e3)}catch{}}setPermissionHandler(e){this.permissionHandler=e}permissionHandler=null;async ping(e){if(!this.alive||!this.process)return!1;if(!this.process.pid){const t=!!(this.process.stdin&&!this.process.stdin.destroyed),i=!!(this.process.stdout&&!this.process.stdout.destroyed);return t&&i}if(!this.process.stdin||this.process.stdin.destroyed)return!!(this.process.stdout&&!this.process.stdout.destroyed);try{const t=++this.requestId,i={jsonrpc:"2.0",id:t,method:"ping",params:{}};return await new Promise(s=>{const n=setTimeout(()=>{this.pendingRequests.delete(String(t)),s(!1)},e);this.pendingRequests.set(String(t),{resolve:()=>s(!0),reject:()=>s(!1),timer:n}),this.process.stdin.write(`${JSON.stringify(i)}
3
- `)})}catch{return!1}}getStatus(){return{alive:this.alive,busy:this.currentTurnId!==null||this.compacting,sessions:this.threadId?1:0}}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}clearActiveEventForShutdown(){this.clearIdleTimer(),this.clearCodexDeltaBuffer(),this.activeEventId=null}setModel(e){this.model=e,this.persistCodexContext(),d.info("codex-adapter",`Model set to: ${e}`)}setMode(e){const t=M(e);if(!t){d.info("codex-adapter",`Ignoring unsupported mode: ${e}`);return}this.collaborationMode=t,this.persistCodexContext(),d.info("codex-adapter",`Mode set to: ${t}`)}setReasoningEffort(e){this.reasoningEffort=e,this.persistCodexContext(),d.info("codex-adapter",`Reasoning effort set to: ${e}`)}setServiceTier(e){const t=e.trim();this.serviceTier=t.toLowerCase()==="default"?"default":t,this.persistCodexContext(),d.info("codex-adapter",`Service tier set to: ${this.serviceTier}`)}setSandboxMode(e){this.sandboxMode=e,this.persistCodexContext(),d.info("codex-adapter",`Sandbox mode set to: ${e} (applied on next restart)`)}async threadCompact(){if(!this.threadId)throw new Error("No active thread");return this.sendRequest("thread/compact/start",{threadId:this.threadId},12e4)}async threadRollback(e){if(!this.threadId)throw new Error("No active thread");return this.sendRequest("thread/rollback",{threadId:this.threadId,numTurns:e},1e4)}getThreadId(){return this.threadId}hasRawApiCaptureRelay(){return!!this.rawCaptureRelay}enableAuditCapture(e,t={}){const i=e.trim();if(!i||this.auditCaptureByEventId.has(i))return;const s=t.rawProviderBody??!!this.rawCaptureOptions;this.auditCaptureByEventId.set(i,{threadId:this.threadId??void 0,modelId:this.currentModelId()??void 0,rawProviderBody:s,sequence:0,events:[]}),s&&this.rawCaptureRelay?.beginEvent(i,t.auditId)}takeAuditBoundary(e){const t=this.auditCaptureByEventId.get(e);if(t)return this.auditCaptureByEventId.delete(e),{adapterType:this.type,providerTurnId:t.providerTurnId,threadId:t.threadId??this.threadId??void 0,codexEvidence:{events:t.events,...t.modelId?{modelId:t.modelId}:{},...t.rawProviderBody?{rawApiCapture:this.rawCaptureRelay?this.rawCaptureRelay.takeEvent(e):qe(this.rawCaptureUnavailableReason??"raw_capture_relay_not_prepared_before_adapter_start")}:{}}}}getMcpConfig(){if(!this.internalApi)return null;const e=fe(me(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:we(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async hasBackgroundWork(){const e=this.process?.pid;return e?xe(e,[e]):!1}onAgentProfileChanged(){this.threadId&&(this.profileIdentityRefreshPending=!0,this.identityInputInjectedThreadId=null,d.info("codex-adapter",`agent profile changed; scheduling identity refresh for thread=${this.threadId}`))}async probe(e){const t=this.config.command||"codex",i=await De(t),s=i!==null;let n=null,r;if(s){const y=await $e(t);n=y.version,y.error&&(r=y.error)}else r={code:"cli_not_found",message:`command not found: ${t}`};const c=F(this.codexHome).baseUrl??null,p=this.currentModelId()||null,h=this.getStatus(),f=e?.conversation?{attempted:!0,ok:!1,latency_ms:null,error:{code:"unsupported",message:"codex does not support minimal prompt probe"}}:{attempted:!1,ok:!1,latency_ms:null},v=await this.probeSessionRecord(),x=ee({codexHome:this.codexHome});return{cli:{command:t,installed:s,path:i,version:n,...r?{error:r}:{}},conversation:f,config:{model:p,base_url:c,source:{model:p?"runtime":"unknown",base_url:c?"file":"unknown"}},process:{started:!!this.process,alive:h.alive,busy:h.busy},session:v,lock:{present:x.present,locked:x.locked,stale:x.stale,path:x.path}}}async probeSessionRecord(){const e=this.threadId?Pe(this.threadId,this.codexHome):null;if(!e)return{recordPath:null,lastActivityMs:null,freshMs:null};try{const t=await Z(e);return{recordPath:e,lastActivityMs:t.mtimeMs,freshMs:Date.now()-t.mtimeMs}}catch{return{recordPath:e,lastActivityMs:null,freshMs:null}}}getSupportedCommands(){return[{name:"compact",description:"Compact thread to reduce context size"},{name:"model",description:"List or set model",args:"[model_id]"},{name:"mode",description:"List or set collaboration mode",args:"[default|plan]"},{name:"rollback",description:"Roll back thread turns",args:"[num_turns]"},{name:"interrupt",description:"Interrupt current turn"},{name:"rate_limits",description:"Show current rate limits"},{name:"status",description:"Show thread and session status"},{name:"skills",description:"List available skills"}]}async execCommand(e,t,i){try{switch(e){case"compact":{if(!this.threadId)return{status:"failed",message:"No active thread"};if(this.compacting)return{status:"failed",message:"Compaction already in progress"};if(this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","compacting"),this.clearActive()),await this.ensureThreadResumed(),this.currentTurnId)return{status:"failed",message:"agent busy"};if(this.needsHistoryInjection)return{status:"failed",message:"The session has expired and there is no history to compact. Please send a new message and try again."};this.compacting=!0;const s=new Promise(n=>{this.compactionDoneResolver=n});try{return await this.threadCompact(),this.armCompactionFallback(),await s,{status:"ok",message:"Thread compacted"}}catch(n){this.finishCompaction("compact-error");const r=n instanceof Error?n.message:String(n);if(/thread.*(not found|not exist|unknown|invalid)/i.test(r)||/not found.*thread/i.test(r))return this.threadId=null,this.persistThreadId(void 0),{status:"failed",message:"The session has expired and there is no history to compact. Please send a new message and try again."};throw n}}case"model":{const s=t.trim();return s?this.getModelOptions().some(r=>r.id===s)?(this.setModel(s),{status:"ok",message:`Model set to ${s}`}):{status:"failed",message:`Unknown model: ${s}`}:{status:"ok",message:`Current: ${this.currentModelId()}`,data:{models:this.getModelOptions()}}}case"mode":{const s=t.trim();if(s){const n=M(s);return n?(this.setMode(n),{status:"ok",message:`Mode set to ${n}`}):{status:"failed",message:`Unknown mode: ${s}. Supported: default, plan`}}return{status:"ok",message:`Current: ${this.collaborationMode??"default"}`,data:{modes:oe}}}case"rollback":{if(!this.threadId)return{status:"failed",message:"No active thread"};const s=Math.max(1,parseInt(t.trim(),10)||1);return this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","rolled back"),this.clearActive()),await this.threadRollback(s),{status:"ok",message:`Rolled back ${s} turn(s)`}}case"interrupt":return this.threadId?(await this.cancel(this.threadId),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","interrupted"),this.clearActive(),{status:"ok",message:"Turn interrupted"}):{status:"failed",message:"No active thread"};case"rate_limits":return{status:"ok",message:this.rateLimitSnapshot?`Primary: ${this.rateLimitSnapshot.primary.usedPercent.toFixed(1)}%, Secondary: ${this.rateLimitSnapshot.secondary.usedPercent.toFixed(1)}%`:"Rate limits not available",data:{rateLimits:this.rateLimitSnapshot}};case"status":return{status:"ok",message:`Thread: ${this.threadId??"none"}, Model: ${this.currentModelId()}, Mode: ${this.collaborationMode??"default"}`,data:{threadId:this.threadId,model:this.currentModelId(),mode:this.collaborationMode??"default",cwd:this.cwd,alive:this.alive}};case"skills":{const s=Oe({mode:"codex",projectDir:this.cwd}),n=s.map(r=>`- ${r.name}${r.trigger?` (${r.trigger})`:""}: ${r.description}`);return{status:"ok",message:n.length>0?n.join(`
4
- `):"No skills found",data:s}}default:return{status:"unsupported",message:`Unknown command: ${e}`}}}catch(s){return{status:"failed",message:s instanceof Error?s.message:String(s)}}}async handleLocalAction(e){const t=e.action_type??"",i=e.params??{};switch(d.info("codex-adapter",`handleLocalAction action_type=${t} action_id=${e.action_id} session_id=${i.session_id??""}`),t){case"set_model":{const s=I(u(i.model_id),u(i.modelId),u(i.value));return s&&this.setModel(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("model_set")),{handled:!0,kind:"set_model"}}case"set_mode":{const s=i.mode_id;return s&&this.setMode(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("mode_set")),{handled:!0,kind:"set_mode"}}case"set_reasoning_effort":{const s=I(u(i.reasoning_effort),u(i.reasoning_eff),u(i.effort));return s&&this.setReasoningEffort(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("effort_set",!1)),{handled:!0,kind:"set_reasoning_effort"}}case"set_service_tier":{const s=I(u(i.service_tier),u(i.serviceTier),u(i.value));return s&&this.setServiceTier(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("service_tier_set",!1)),{handled:!0,kind:"set_service_tier"}}case"set_sandbox_mode":{const s=I(u(i.sandbox_mode),u(i.sandboxMode),u(i.value));return s&&this.setSandboxMode(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("sandbox_mode_set",!1)),{handled:!0,kind:"set_sandbox_mode"}}case"thread_compact":{d.info("codex-adapter",`thread_compact start action_id=${e.action_id} threadId=${this.threadId}`),this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","compacting"),this.clearActive());try{if(await this.ensureThreadResumed(),this.needsHistoryInjection)return d.info("codex-adapter",`thread_compact aborted: thread expired, new thread created action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"thread_expired","The session has expired and there is no history to compact. Please send a new message and try again."),{handled:!0,kind:"thread_compact"};this.compacting=!0;const s=new Promise(n=>{this.compactionDoneResolver=n});await this.threadCompact(),this.armCompactionFallback(),await s,d.info("codex-adapter",`thread_compact done action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(s){this.finishCompaction("compact-error");const n=s instanceof Error?s.message:String(s);/thread.*(not found|not exist|unknown|invalid)/i.test(n)||/not found.*thread/i.test(n)?(d.warn("codex-adapter",`thread_compact thread expired, resetting threadId action_id=${e.action_id} err=${n}`),this.threadId=null,this.persistThreadId(void 0),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"thread_expired","The session has expired and there is no history to compact. Please send a new message and try again.")):(d.info("codex-adapter",`thread_compact failed action_id=${e.action_id} err=${n}`),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,n))}return{handled:!0,kind:"thread_compact"}}case"get_context":return this.callbacks.sendLocalActionResult(e.action_id,"ok",{threadId:this.threadId,model:this.model,mode:this.collaborationMode,approvalPolicy:this.approvalPolicy,cwd:this.cwd,...await this.buildToolbarContextResult("context")}),{handled:!0,kind:"get_context"};case"exec_approve":case"file_approve":{const s=this.resolvePendingApproval(e);if(!s)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:t};const n=i.decision||"allow-once",r=st[n]??"accept";return this.sendApprovalDecision(s.requestId,r),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,approval_command_id:s.approvalCommandId,decision:n}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t}}case"exec_reject":case"file_reject":{const s=this.resolvePendingApproval(e);return s?(this.sendApprovalDecision(s.requestId,"deny"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,approval_command_id:s.approvalCommandId,decision:"deny"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t}):(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:t})}case"permission_approve":{const s=this.resolvePendingApproval(e);return!s||s.kind!=="permission"?(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That permission approval request is no longer pending."),{handled:!0,kind:t}):(this.sendApprovalDecision(s.requestId,"accept"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,decision:"approve"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t})}case"permission_reject":{const s=this.resolvePendingApproval(e);return!s||s.kind!=="permission"?(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That permission approval request is no longer pending."),{handled:!0,kind:t}):(this.sendApprovalDecision(s.requestId,"deny"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,decision:"deny"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t})}case"turn_interrupt":{try{await this.cancel(this.threadId??""),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(s){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,s instanceof Error?s.message:String(s))}return{handled:!0,kind:"turn_interrupt"}}case"thread_rollback":{const s=Number(i.numTurns??i.num_turns??1);if(!this.threadId)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"no_thread","No active thread"),{handled:!0,kind:"thread_rollback"};this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","rolled back"),this.clearActive());try{await this.threadRollback(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",{numTurns:s})}catch(n){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,n instanceof Error?n.message:String(n))}return{handled:!0,kind:"thread_rollback"}}case"get_rate_limits":{const s=this.rateLimitSnapshot,n=this.buildContextWindowSnapshot(),r=Date.now(),o=this.currentThreadTokenUsage;return s?d.info("codex-adapter",`[rate-limits] responding: primary=${s.primary.usedPercent.toFixed(1)}% window=${s.primary.windowMinutes}min resetsAt=${s.primary.resetsAt} secondary=${s.secondary.usedPercent.toFixed(1)}% window=${s.secondary.windowMinutes}min resetsAt=${s.secondary.resetsAt}`):d.info("codex-adapter","[rate-limits] responding: no rateLimitSnapshot available"),d.debug("codex-adapter",`[cp-diagnose] get_rate_limits: threadId=${this.threadId??"-"} contextWindow=${JSON.stringify(n)} tokenUsage=${JSON.stringify(o)}`),this.callbacks.sendLocalActionResult(e.action_id,"ok",{adapterType:"codex",available:s!==null,cached:!1,sampledAt:r,rateLimits:s,contextWindow:n,tokenUsage:o}),{handled:!0,kind:"get_rate_limits"}}default:return{handled:!1,kind:""}}}async buildToolbarContextResult(e,t=!0){t&&await this.refreshCodexModelOptions();const i=M(this.collaborationMode)??"default",s=this.currentModelId(),n=this.getModelOption(s),r=this.getModelOptions(),o=oe,c=this.reasoningEffort??n?.defaultReasoningEffort??null,p=n?.supportedReasoningEfforts??[],h=this.effectiveServiceTier()??n?.defaultServiceTier??null,f=n?.serviceTiers??[],v=this.isExternalProvider(),x=v?[]:p,y=v?null:c,E=v?[]:f,S=v?null:h,T={outcome:e,session_context:{modelId:s,modeId:i,reasoningEffort:y,serviceTier:S,approvalPolicy:this.approvalPolicy,sandboxMode:this.sandboxMode??null},model_id:s,mode_id:i,currentModelId:s,currentModeId:i,available_models:r,available_modes:o,available_efforts:x,availableModels:r,availableModes:o,reasoning_effort:y,available_service_tiers:E,service_tier:S,sandbox_mode:this.sandboxMode??null,models:r.map(w=>({modelId:w.id,name:w.displayName})),modes:o.map(w=>({id:w.id,name:w.displayName}))};return this.rateLimitSnapshot&&(T.rate_limit_primary_percent=this.rateLimitSnapshot.primary.usedPercent,T.rate_limit_secondary_percent=this.rateLimitSnapshot.secondary.usedPercent,T.rate_limit_primary_window_min=this.rateLimitSnapshot.primary.windowMinutes,T.rate_limit_secondary_window_min=this.rateLimitSnapshot.secondary.windowMinutes),T}currentModelId(){const e=String(this.model??"").trim();if(e)return e;const t=this.getModelOptions();return t.find(i=>i.isDefault)?.id??t[0]?.id??""}getModelOption(e){const t=e.trim().toLowerCase();return this.getModelOptions().find(i=>i.id.trim().toLowerCase()===t)}getModelOptions(){const e=this.config.options??{},t=e.available_models??e.availableModels??e.models,i=ct(t),s=this.codexModelOptions,n=[],r=String(this.model??"").trim(),o=r&&!s.some(f=>f.id.trim().toLowerCase()===r.toLowerCase()),c=s.length>0?s:o?[]:tt;if(r){const f=[...s,...i].find(v=>v.id.trim().toLowerCase()===r.toLowerCase());n.push({id:r,displayName:f?.displayName??k(r),defaultReasoningEffort:f?.defaultReasoningEffort??null,supportedReasoningEfforts:f?.supportedReasoningEfforts??[],defaultServiceTier:f?.defaultServiceTier??null,serviceTiers:f?.serviceTiers??[],isDefault:f?.isDefault??!1})}n.push(...i),n.push(...c);const p=[],h=new Set;for(const f of n){const v=f.id.trim(),x=v.toLowerCase();!v||h.has(x)||(h.add(x),p.push({id:v,displayName:f.displayName.trim()||v,defaultReasoningEffort:f.defaultReasoningEffort,supportedReasoningEfforts:[...f.supportedReasoningEfforts],defaultServiceTier:f.defaultServiceTier,serviceTiers:[...f.serviceTiers],isDefault:f.isDefault}))}return p}async refreshCodexModelOptions(){if(!this.initialized||!this.alive||!this.process?.stdin||Date.now()-this.codexModelOptionsCachedAt<D.MODEL_CACHE_TTL_MS)return;const e=F(this.codexHome);if(e.baseUrl&&ce(e.baseUrl)){try{const t=await lt(e.baseUrl,e.apiKey);if(t.length>0){this.codexModelOptions=le(t),this.codexModelOptionsCachedAt=Date.now(),d.info("codex-adapter",`Loaded ${t.length} models from external provider ${e.baseUrl}`);return}}catch(t){d.warn("codex-adapter",`External provider /v1/models failed (${t instanceof Error?t.message:String(t)}), falling back`)}this.codexModelOptions=[],this.codexModelOptionsCachedAt=Date.now();return}try{const t=[];let i;do{const s=await this.sendRequest("model/list",{cursor:i??null,includeHidden:!1,limit:100},15e3),n=ht(s);t.push(...n.models),i=n.nextCursor}while(i);t.length>0&&(this.codexModelOptions=le(t),this.codexModelOptionsCachedAt=Date.now())}catch(t){d.warn("codex-adapter",`Failed to load Codex model list: ${t instanceof Error?t.message:String(t)}`)}}currentTurnId=null;compacting=!1;pendingAutoCompact=!1;compactionDeferred=[];steerDeferred=[];compactingTimer=null;compactionDoneResolver=null;activeEventId=null;activeSessionId=null;visibleAgentMessageIds=new Set;hiddenAgentMessageIds=new Set;agentMessagePhases=new Map;deliveredAgentMessageIds=new Set;deliveredThinkingAgentMessageIds=new Set;codexSequence=0;pendingCodexDeltaFlush=null;turnError=null;turnErrorIsRetryableOnly=!0;turnHasVisibleOutput=!1;turnSawVisibleFinalAnswer=!1;turnHasDeliveredFinalAnswer=!1;deliverInboundEvent(e){if(this.compacting){d.info("codex-adapter",`Event ${e.event_id} deferred: compaction in progress`),this.compactionDeferred.push(e);return}const t=this.inboundMessageIds.prepare(e.session_id,e.content,e.msg_id),i=t.text,s=()=>{t.instructionPending&&this.inboundMessageIds.commitInstruction(e.session_id)},n=()=>{const r=this.inboundMessageIds.prepare(e.session_id,e.content,e.msg_id);r.instructionPending&&this.inboundMessageIds.commitInstruction(e.session_id),this.startNewTurn(e,r.text)};if(this.currentTurnId&&i.trim()){d.info("codex-adapter",`Event ${e.event_id}: steering active turn ${this.currentTurnId}`),this.steerTurn(i).then(()=>{s()}).catch(r=>{const o=r instanceof Error?r.message:String(r);if(d.info("codex-adapter",`Steer failed, falling through: ${o}`),!this.currentTurnId){n();return}if(mt(o)){d.info("codex-adapter","Unsteerable turn detected, clearing active state and starting new turn"),this.clearActive(),n();return}d.info("codex-adapter",`Steer failed but turn still active; deferring event ${e.event_id} for replay after turn ends`),this.steerDeferred.push(e)});return}if(this.currentTurnId){d.info("codex-adapter",`Event ${e.event_id} rejected: busy and empty content`),this.sendEventResultAfterFlushing(e.event_id,"failed","agent busy");return}s(),this.startNewTurn(e,i)}startNewTurn(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,e.audit?.enabled===!0&&this.enableAuditCapture(e.event_id,{auditId:e.audit.auditId,rawProviderBody:e.audit.rawProviderBody}),this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.codexSequence=0,this.startComposing();const i=this.threadId??"",s=new z(i),n={adapterSessionId:i,text:t,contextMessages:e.context_messages_json?JSON.parse(e.context_messages_json).map(r=>({senderId:r.sender_id??"unknown",content:r.content})):void 0};this.runTurn(n,s,e.event_id,e.session_id).catch(r=>{d.error("codex-adapter",`Turn failed: ${r}`),this.sendEventResultAfterFlushing(e.event_id,"failed",r instanceof Error?r.message:String(r)),this.clearActive()}),this.resetIdleTimer(e.event_id)}deliverStopEvent(e,t){this.activeEventId===e&&(this.cancel(this.threadId??"").catch(()=>{}),this.sendEventResultAfterFlushing(e,"canceled","stopped by user"),this.clearActive())}async spawnCodex(){const e={...this.resolveChildEnv(),...this.directEnv},t=typeof e.PATH=="string"?e.PATH:void 0;t||d.warn("codex-adapter",`spawnCodex: env.PATH is missing! process.env.PATH=${process.env.PATH?"set":"missing"}, config.env=${JSON.stringify(this.config.env)}`);const i=ae(this.config.command||"codex",t),s=rt(this.config.args);for(const o of this.configOverrideArgs)s.push("-c",o);for(const o of this.resolveRelayTransportConfigOverrides())s.push("-c",o);for(const o of this.rawCaptureConfigOverrides)s.push("-c",o);this.sandboxMode&&s.push("-c",`sandbox_mode="${this.sandboxMode}"`);const n=s.map(o=>this.rawCaptureConfigOverrides.includes(o)?"<raw-api-capture-overlay>":o);d.info("codex-adapter",`Spawning: ${i} ${n.join(" ")}`);try{if(!(await Z(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(o){throw String(o?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):o}const r=ee({codexHome:this.codexHome});if(r.locked&&!r.stale)throw new Error(`Codex session appears locked by another process: ${r.path}`);r.stale&&d.warn("codex-adapter",`Ignoring stale Codex lock: ${r.path}`);try{this.process=Ie(i,s,{env:e,cwd:this.cwd}).process}catch(o){throw d.error("codex-adapter",`Codex spawn threw: ${o}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",o}this.process.on("error",o=>{d.error("codex-adapter",`Codex process spawn error: ${o}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("spawn failed: "+(o instanceof Error?o.message:String(o))),this.stopComposing(),this.activeEventId?(this.flushCodexDeltaBuffer(),this.sendEventResultAfterFlushing(this.activeEventId,"failed","Codex process spawn failed"),this.activeEventId=null):this.clearCodexDeltaBuffer(),this.emit("exit",1)}),this.process.on("exit",o=>{d.info("codex-adapter",`Codex process exited (code=${o})`),this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("process exited"),this.stopComposing(),this.activeEventId?this.flushCodexDeltaBuffer():this.clearCodexDeltaBuffer(),this.emit("exit",o)}),this.process.stderr?.on("data",o=>{const c=o.toString().trim();c&&d.info("codex-adapter",`[codex stderr] ${c}`)}),this.bindStdout(),this.alive=!0}resolveRelayTransportConfigOverrides(){if(this.config.env?.[We]!=="1")return[];const e=je(this.codexHome,this.configOverrideArgs);if(e==="openai"){const i=He(this.codexHome,this.configOverrideArgs);return Le(Ne,"Grix OpenAI Relay",i.targetBaseUrl)}const t=Ue(e);return t?[`${t}=false`]:[]}bindStdout(){if(!this.process?.stdout)return;this.process.stdout.setEncoding("utf8"),pe({input:this.process.stdout}).on("line",t=>{if(!t.trim())return;let i;try{i=JSON.parse(t)}catch{d.error("codex-adapter",`Invalid JSON from Codex: ${t.slice(0,200)}`);return}if(this.bridgeStatus==="starting"&&(this.bridgeStatus="ready"),i.id!=null){const s=String(i.id),n=this.pendingRequests.get(s);if(n){clearTimeout(n.timer),this.pendingRequests.delete(s),n.resolve(i);return}}this.handleNotification(i)})}handleNotification(e){const t=e.method,i=e.params??{};if(this.shouldIgnoreOutOfScopeNotification(e,t,i)){this.activeEventId&&this.resetIdleTimer(this.activeEventId);return}switch(this.captureAuditNotification(t,i),this.captureContextWindowFromPayload(t,i),this.activeEventId&&t&&t.startsWith("item/")&&!t.endsWith("/requestApproval")&&this.startComposing(),t){case"item/started":{const n=i.item,r=n?.id,o=n?.type,c=this.normalizeAgentMessagePhase(n?.phase);if(this.isLongRunningToolItemType(o)&&(this.inFlightToolOps+=1),o==="agentMessage"&&r){c?this.agentMessagePhases.set(r,c):this.agentMessagePhases.delete(r);const p=N(c),h=L(c);p?(this.visibleAgentMessageIds.add(r),this.hiddenAgentMessageIds.delete(r)):h?(this.visibleAgentMessageIds.delete(r),this.hiddenAgentMessageIds.delete(r)):(this.hiddenAgentMessageIds.add(r),this.visibleAgentMessageIds.delete(r)),c==="final_answer"&&p&&(this.turnSawVisibleFinalAnswer=!0)}break}case"item/agentMessage/delta":{const n=i.delta,r=i.itemId,o=this.resolveAgentMessagePhase(r,i.phase),c=(!r||!this.hiddenAgentMessageIds.has(r))&&N(o),p=(!r||!this.hiddenAgentMessageIds.has(r))&&L(o);if(o==="final_answer"&&c&&(this.turnSawVisibleFinalAnswer=!0),n&&this.activeEventId&&p){this.recordDeliveredThinkingAgentMessage(r),this.callbacks.sendThinking?.(this.activeEventId,this.activeSessionId??"",n);break}n&&this.activeEventId&&c&&!this.shouldSuppressAgentMessageDeltaDuringToolRun(r,o)&&(this.recordDeliveredAgentMessage(r,o),this.queueCodexDeltaEvent({...e,params:{...i,...o?{phase:o}:{}}}));break}case"item/completed":{const n=i.item,r=n?.id,o=n?.type;if(this.isLongRunningToolItemType(o)&&(this.inFlightToolOps=Math.max(0,this.inFlightToolOps-1)),this.activeEventId&&o==="commandExecution"&&(this.turnHasVisibleOutput=!0,this.emitCodexEvent("item/completed",e)),o==="agentMessage"){const c=this.resolveAgentMessagePhase(r,n?.phase),p=(!r||!this.hiddenAgentMessageIds.has(r))&&N(c);if(c==="final_answer"&&p){this.turnSawVisibleFinalAnswer=!0;const h=this.extractAgentMessageText(n),f=r?this.deliveredAgentMessageIds.has(r):!1;this.activeEventId&&h&&!f&&(d.warn("codex-adapter",`Recovering final_answer from item/completed item_id=${r??"unknown"}`),this.recordDeliveredAgentMessage(r,c),this.queueCodexDeltaEvent({method:"item/agentMessage/delta",params:{...r?{itemId:r}:{},delta:h,phase:c}}))}else if(L(c)){const h=this.extractAgentMessageText(n),f=r?this.deliveredThinkingAgentMessageIds.has(r):!1;this.activeEventId&&h&&!f&&(this.recordDeliveredThinkingAgentMessage(r),this.callbacks.sendThinking?.(this.activeEventId,this.activeSessionId??"",h))}r&&(this.visibleAgentMessageIds.delete(r),this.hiddenAgentMessageIds.delete(r),this.agentMessagePhases.delete(r))}break}case"turn/started":{const r=i.turn?.id;r&&(this.currentTurnId=r,this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.currentTurnStartedAt=Date.now(),this.preflightCheckComplete=!1,d.info("codex-adapter",`Turn started: ${r}`),this.startComposing());break}case"item/fileChange/requestApproval":{this.handleApprovalRequest(e,"file");break}case"item/commandExecution/requestApproval":{this.handleApprovalRequest(e,"exec");break}case"item/permissions/requestApproval":{this.handleApprovalRequest(e,"permission");break}case"turn/completed":{this.handleTurnCompleted(i);break}case"error":{const n=i.message??JSON.stringify(i);d.error("codex-adapter",`Codex error: ${n}`);const r=i.willRetry===!0;n&&(this.turnError=n,r||(this.turnErrorIsRetryableOnly=!1)),this.activeEventId&&!r&&(this.flushCodexDeltaBuffer(),this.callbacks.sendRunError(this.activeEventId,this.activeSessionId??"",n));break}case"account/rateLimits/updated":{const n=this.extractRateLimitPushLimitId(i),r=this.parseRateLimitSnapshot(i,this.rateLimitSnapshot);r&&(this.rateLimitSnapshot=r,d.info("codex-adapter",`Rate limits updated: primary=${r.primary.usedPercent.toFixed(1)}% secondary=${r.secondary.usedPercent.toFixed(1)}% extras=${r.extras?.length??0}`),this.callbacks.onRateLimitsUpdated?.(r)),n&&n!=="codex"&&this.refreshMainRateLimitsThrottled();break}case"thread/tokenUsage/updated":{const n=i.threadId,r=i.tokenUsage,o=r?.last;(!n||!r||!o)&&d.info("codex-adapter",`[cp-diagnose] token_usage payload_incomplete: method=thread/tokenUsage/updated hasThreadId=${String(!!n)} hasTokenUsage=${String(!!r)} hasLast=${String(!!o)} params=${JSON.stringify(i)}`),n&&r&&o&&(this.currentThreadTokenUsage={inputTokens:o.inputTokens??0,outputTokens:o.outputTokens??0,cacheReadInputTokens:o.cachedInputTokens??0,cacheCreationInputTokens:0},d.info("codex-adapter",`[cp-diagnose] token_usage raw thread=${n}: ${JSON.stringify(r)}`),d.info("codex-adapter",`[cp-diagnose] token_usage parsed thread=${n}: ${JSON.stringify(this.currentThreadTokenUsage)}`),this.callbacks.onTokenUsageUpdated?.(this.currentThreadTokenUsage),this.publishContextWindowSnapshot());break}default:break}const s=t?.endsWith("/requestApproval")===!0;t&&t!=="turn/started"&&(t.startsWith("item/")||t==="error"||t==="turn/completed")&&(this.preflightCheckComplete=!0),this.activeEventId&&(!s||this.pendingApprovals.size===0)&&this.resetIdleTimer(this.activeEventId)}shouldIgnoreOutOfScopeNotification(e,t,i){if(!t||e.id!=null)return!1;const s=I(u(i.threadId),u(i.threadID));if(s&&this.threadId&&s!==this.threadId)return this.logIgnoredNotificationScope(t,s,this.readNotificationTurnId(i)),!0;const n=this.readNotificationTurnId(i);return n&&this.currentTurnId&&n!==this.currentTurnId?(this.logIgnoredNotificationScope(t,s,n),!0):!1}readNotificationTurnId(e){const t=e.turn&&typeof e.turn=="object"?e.turn:void 0;return I(u(e.turnId),u(e.turnID),u(t?.id))}logIgnoredNotificationScope(e,t,i){e!=="error"&&!e.startsWith("turn/")||d.info("codex-adapter",`[scope] ignored ${e} thread=${t??"<none>"} turn=${i??"<none>"} active_thread=${this.threadId??"<none>"} active_turn=${this.currentTurnId??"<none>"}`)}captureAuditNotification(e,t){const i=this.activeEventId;if(!e||!i)return;const s=this.auditCaptureByEventId.get(i);if(!s)return;const n=t.turn,r=typeof t.turnId=="string"&&t.turnId?t.turnId:typeof t.turn_id=="string"&&t.turn_id?t.turn_id:typeof n?.id=="string"&&n.id?n.id:this.currentTurnId;r&&(s.providerTurnId=r);const o=typeof t.threadId=="string"&&t.threadId?t.threadId:typeof t.thread_id=="string"&&t.thread_id?t.thread_id:this.threadId;if(o&&(s.threadId=o),!!it.has(e))try{const c=JSON.parse(JSON.stringify(t));s.events.push({sequence:++s.sequence,method:e,params:c,observedAt:new Date().toISOString()})}catch(c){const p=c instanceof Error?c.message:String(c);d.warn("codex-adapter",`Audit evidence capture skipped event=${i} method=${e}: ${p}`)}}captureContextWindowFromPayload(e,t){const i=["model_context_window","modelContextWindow","context_window_size","contextWindowSize"],s=this.findNumericField(t,i);if(s==null||s<=0){const n=this.probeContextWindowFields(t,i);n.foundAnyCandidateField&&d.info("codex-adapter",`[cp-diagnose] context_window missing_or_invalid: method=${e??"-"} matchedFields=${n.matchedFields.join(",")||"-"} raw=${n.rawValues.join(",")||"-"} extracted=${String(s)}`);return}this.currentModelContextWindow!==s&&(this.currentModelContextWindow=s,d.info("codex-adapter",`[cp-diagnose] context_window updated: method=${e??"-"} size=${s}`),this.publishContextWindowSnapshot())}probeContextWindowFields(e,t){const i=[],s=[],n=r=>{if(!r||typeof r!="object")return;if(Array.isArray(r)){for(const c of r)n(c);return}const o=r;for(const c of t)Object.prototype.hasOwnProperty.call(o,c)&&(i.push(c),s.push(String(o[c])));for(const c of Object.values(o))n(c)};return n(e),{foundAnyCandidateField:i.length>0,matchedFields:i,rawValues:s}}findNumericField(e,t){if(!e||typeof e!="object")return null;const i=e;for(const s of t){const n=i[s];if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n=="string"){const r=Number(n);if(Number.isFinite(r))return r}}for(const s of Object.values(i)){if(Array.isArray(s)){for(const r of s){const o=this.findNumericField(r,t);if(o!=null)return o}continue}const n=this.findNumericField(s,t);if(n!=null)return n}return null}buildContextWindowSnapshot(){const e=this.currentModelContextWindow;if(!e||e<=0)return d.debug("codex-adapter",`[cp-diagnose] context_window snapshot skipped: invalid size=${String(e)}`),null;const t=this.currentThreadTokenUsage,i=t?t.inputTokens+t.outputTokens:null,s=i==null?null:Math.max(0,e-i),n=i==null?null:Math.min(100,i/e*100),r=i==null?null:Math.max(0,100-(n??0));return d.info("codex-adapter",`[cp-diagnose] context_window computed: threadId=${this.threadId??"-"} size=${e} usedTokens=${String(i)} usedPercentage=${String(n)}`),{sizeTokens:e,usedTokens:i,remainingTokens:s,usedPercentage:n,remainingPercentage:r,source:"codex:model_context_window"}}publishContextWindowSnapshot(){const e=this.buildContextWindowSnapshot();this.callbacks.onContextWindowUpdated?.(e),this.maybeScheduleAutoCompact(e)}maybeScheduleAutoCompact(e){const t=e?.usedPercentage;typeof t!="number"||t<re||this.pendingAutoCompact||this.compacting||(this.pendingAutoCompact=!0,d.info("codex-adapter",`[auto-compact] context_window usedPercentage=${t.toFixed(1)}% >= ${re}%, scheduling compact`),this.tryRunPendingAutoCompact())}tryRunPendingAutoCompact(){this.pendingAutoCompact&&(this.stopped||!this.alive||this.currentTurnId||this.compacting||(this.pendingAutoCompact=!1,this.execCommand("compact","",this.activeSessionId??"").then(e=>{d.info("codex-adapter",`[auto-compact] compact done status=${e.status} msg=${e.message??""}`),e.status==="failed"&&/agent busy/i.test(e.message??"")&&(this.pendingAutoCompact=!0)}).catch(e=>{d.warn("codex-adapter",`[auto-compact] compact error: ${e instanceof Error?e.message:e}`)})))}parseRateLimitSnapshot(e,t=null){try{const i=e.rateLimitsByLimitId,s=this.extractRateLimitPushLimitId(e),n=!i?.codex&&!!s&&s!=="codex",r=i?.codex??(n?{}:e.rateLimits??e),o=r.primary,c=r.secondary,p=r.credits,h=l=>{if(typeof l=="number"&&Number.isFinite(l))return l;if(typeof l=="string"){const m=Number(l);if(Number.isFinite(m))return m}return 0},f=l=>typeof l=="boolean"?l:typeof l=="string"?l.toLowerCase()==="true":!1,v=l=>{if(l==null)return null;if(typeof l=="string"){const m=l.trim();if(!m)return null;const g=Number(m);return Number.isFinite(g)&&g>1e9?new Date(g*1e3).toISOString():m}if(typeof l=="number"&&Number.isFinite(l)&&l>0){const m=l>1e12?l/1e3:l;return new Date(m*1e3).toISOString()}return null},x=l=>{const m=l.resets_in_seconds??l.resetsInSeconds,g=typeof m=="number"||typeof m=="string"?Number(m):NaN;return!Number.isFinite(g)||g<=0?null:new Date(Date.now()+g*1e3).toISOString()},y=l=>({usedPercent:h(l.used_percent??l.usedPercent),windowMinutes:h(l.window_minutes??l.windowDurationMins??l.windowMinutes),resetsAt:v(l.resets_at??l.resetsAt)??x(l)}),E=()=>({usedPercent:0,windowMinutes:0,resetsAt:null}),S=(l,m)=>l??m??E(),T=()=>{const l=[];if(o&&l.push(o),c&&l.push(c),Array.isArray(r.windows))for(const m of r.windows)m&&typeof m=="object"&&l.push(m);return l.map(y).filter(m=>m.windowMinutes>0)},w=(l,m,g)=>{const C=l.filter(b=>g(b.windowMinutes));return C.length===0?null:C.reduce((b,A)=>Math.abs(A.windowMinutes-m)<Math.abs(b.windowMinutes-m)?A:b)},$=T(),O=n?t?{primary:t.primary,secondary:t.secondary}:null:$.length>0?{primary:S(w($,300,l=>l<1440),t?.primary),secondary:S(w($,10080,l=>l>=1440),t?.secondary)}:o||c?{primary:o?y(o):t?.primary??E(),secondary:c?y(c):t?.secondary??E()}:null;if(!O)return null;const W=(l,m)=>{if(!m||typeof m!="object"||Array.isArray(m))return null;const g=m,C=g.limitName??g.limit_name,b=typeof C=="string"&&C.trim()?C.trim():l,A=[],V=g.primary,G=g.secondary;V&&A.push(V),G&&A.push(G);const X=A.map(y).filter(R=>R.windowMinutes>0),J=w(X,10080,R=>R>=1440)??w(X,300,R=>R<1440);return J?{id:l,label:b,...J}:null};let _;if(i&&typeof i=="object"){_=[];for(const[l,m]of Object.entries(i)){if(l==="codex")continue;const g=W(l,m);g&&_.push(g)}}else if(_=t?.extras?[...t.extras]:[],n&&s){const l=W(s,e.rateLimits??e);if(l){const m=_.findIndex(g=>g.id===l.id);m>=0?_[m]=l:_.push(l)}}return{primary:O.primary,secondary:O.secondary,credits:p?{hasCredits:f(p.has_credits??p.hasCredits),unlimited:f(p.unlimited),balance:p.balance==null?null:h(p.balance)}:t?.credits??{hasCredits:!1,unlimited:!1,balance:null},..._.length>0?{extras:_}:{}}}catch{return null}}handleApprovalRequest(e,t){const i=e.id;if(i==null)return;const s=e.method,n=`${i}`.trim(),r=`codex_${ue(this.activeSessionId??"")}_${ue(n)}`;if(this.approvalPolicy==="never"){this.sendApprovalDecision(i,"accept");return}this.activeEventId&&this.emitCodexEvent(s,e),this.pendingApprovals.set(r,{approvalId:r,approvalCommandId:n,sourceEventId:this.activeEventId??"",requestId:i,kind:t}),d.info("codex-adapter",`Pending approval stored: ${r} (kind=${t})`),this.clearIdleTimer(),this.stopComposing()}resolvePendingApproval(e){const t=e.params??{},i=I(t.approval_id,t.approvalId);if(i)return this.pendingApprovals.get(i)??null;const s=I(t.approval_command_id,t.approvalCommandId);if(s){for(const[,n]of this.pendingApprovals)if(n.approvalCommandId===s)return n}return null}sendApprovalDecision(e,t){if(e==null||!this.process?.stdin)return;const i={jsonrpc:"2.0",id:e,result:{decision:t}};this.process.stdin.write(`${JSON.stringify(i)}
5
- `)}armCompactionFallback(){this.compacting&&(this.compactingTimer&&clearTimeout(this.compactingTimer),this.compactingTimer=setTimeout(()=>{d.warn("codex-adapter","Compaction fallback fired: turn/completed not received within timeout, treating as stuck and releasing deferred events"),this.currentTurnId=null,this.finishCompaction("fallback-timeout")},Ze),this.compactingTimer.unref?.())}finishCompaction(e){if(!this.compacting)return;this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);const t=this.compactionDeferred.splice(0);d.info("codex-adapter",`Compaction finished (${e}); replaying ${t.length} deferred events`);for(const s of t)this.deliverInboundEvent(s);const i=this.compactionDoneResolver;this.compactionDoneResolver=null,i?.()}handleTurnCompleted(e){if(this.currentTurnId=null,this.stopComposing(),this.activeEventId){this.flushCodexDeltaBuffer();const t=this.activeEventId,i={event_id:t,session_id:this.activeSessionId??"",thread_id:this.threadId??void 0,codex_event_type:"codex",codex_method:"turn/completed",codex_sequence:++this.codexSequence},s=this.turnError,n=this.turnErrorIsRetryableOnly,r=this.turnHasVisibleOutput,o=this.turnSawVisibleFinalAnswer&&!this.turnHasDeliveredFinalAnswer;this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1;const p=(s&&!(n&&r)?s:null)??(o?"Codex final answer was observed but not delivered":null)??(r?null:"Codex completed without producing any visible output"),h=p!==null;this.callbacks.sendCodexEvent(i),this.sendEventResultAfterFlushing(t,h?"failed":"responded",p??void 0),this.clearActive()}this.compacting&&this.finishCompaction("turn-completed")}emitCodexEvent(e,t){if(!this.activeEventId)return;this.flushCodexDeltaBuffer();const i=he(e,t);if(i===void 0&&e==="item/completed")return;const s={event_id:this.activeEventId,session_id:this.activeSessionId??"",thread_id:this.threadId??void 0,codex_event_type:"codex",codex_method:e,codex_sequence:++this.codexSequence};i!==void 0&&(s.codex_payload=i),this.callbacks.sendCodexEvent(s)}queueCodexDeltaEvent(e){if(!this.activeEventId)return;const t=he("item/agentMessage/delta",e),i=t?.params?.delta;if(typeof i!="string"||i.length===0)return;const s=typeof t?.params?.phase=="string"?t.params.phase:void 0,n=this.activeEventId,r=this.activeSessionId??"",o=this.threadId??void 0,c=this.pendingCodexDeltaFlush;if(c&&(c.eventId!==n||c.sessionId!==r||c.threadId!==o||c.phase!==s)&&this.flushCodexDeltaBuffer(),this.pendingCodexDeltaFlush||(this.pendingCodexDeltaFlush={eventId:n,sessionId:r,threadId:o,delta:"",phase:s,timer:null}),this.pendingCodexDeltaFlush.delta+=i,this.pendingCodexDeltaFlush.delta.length>=et){this.flushCodexDeltaBuffer();return}this.pendingCodexDeltaFlush.timer||(this.pendingCodexDeltaFlush.timer=setTimeout(()=>{if(this.activeEventId!==n){this.clearCodexDeltaBuffer();return}this.flushCodexDeltaBuffer()},Qe))}flushCodexDeltaBuffer(){const e=this.pendingCodexDeltaFlush;if(!e||(this.pendingCodexDeltaFlush=null,e.timer&&clearTimeout(e.timer),!e.delta))return;const t={event_id:e.eventId,session_id:e.sessionId,thread_id:e.threadId,codex_event_type:"codex",codex_method:"item/agentMessage/delta",codex_sequence:++this.codexSequence,codex_payload:{params:{delta:e.delta,...e.phase?{phase:e.phase}:{}}}};this.callbacks.sendCodexEvent(t)}clearCodexDeltaBuffer(){const e=this.pendingCodexDeltaFlush;this.pendingCodexDeltaFlush=null,e?.timer&&clearTimeout(e.timer)}sendEventResultAfterFlushing(e,t,i){this.pendingCodexDeltaFlush?.eventId===e&&this.flushCodexDeltaBuffer(),this.callbacks.sendEventResult(e,t,i)}startComposing(){}stopComposing(){}async sendRequest(e,t,i=3e4){return new Promise((s,n)=>{if(!this.process?.stdin){n(new Error("Codex process not available"));return}const r=++this.requestId,o={jsonrpc:"2.0",id:r,method:e,params:t??{}},c=setTimeout(()=>{this.pendingRequests.delete(String(r)),n(new Error(`Request timeout: ${e}`))},i);this.pendingRequests.set(String(r),{resolve:h=>{h.error?n(new Error(`JSON-RPC error: ${h.error.message}`)):s(h.result)},reject:n,timer:c});const p=JSON.stringify(o);this.process.stdin.write(`${p}
1
+ import{execFileSync as Y}from"node:child_process";import{createInterface as fe}from"node:readline";import{EventEmitter as K}from"node:events";import{stat as Z}from"node:fs/promises";import{join as P,resolve as pe}from"node:path";import{fileURLToPath as me}from"node:url";import{syncDefaultSkillsToDir as ge}from"../../default-skills/index.js";import{resolveCommandPath as ve,spawnCommand as Ie,killProcessGroup as Q,hasChildProcesses as xe}from"../../core/runtime/spawn.js";import{InternalApiServer as ye}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as we,LEGACY_MCP_SERVER_NAMES as _e}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as Ce}from"../shared/inbound-message-id-injector.js";import{log as a}from"../../core/log/index.js";import{resolveClientVersion as Te}from"../../core/util/client-version.js";import{isThinkingAgentMessagePhase as L,isUserVisibleAgentMessagePhase as N}from"../../core/util/codex-output-policy.js";import{SessionBindingStore as be}from"../../core/persistence/session-binding-store.js";import{ensureCodexProjectTrusted as Ae,isCodexCommand as Ee,readCodexProviderSettings as F,resolveCodexHome as Se}from"./codex-trust.js";import{prepareCodexDirectHome as Re}from"./direct-home.js";import{checkCodexSessionActivity as Me,inspectCodexTurnProgress as ke}from"./session-activity.js";import{findRolloutFile as Pe}from"./rollout-locator.js";import{checkCodexLock as ee}from"./lock-monitor.js";import{resolveCliPath as De,getCliVersion as $e}from"../../core/util/cli-probe.js";import{scanSkills as Oe}from"../claude/skill-scanner.js";import{normalizeCodexConfigOverrides as te}from"./config-overrides.js";import{buildCodexOpenAiCompatibleProviderOverrides as Le,CODEX_RELAY_OPENAI_PROVIDER_ID as Ne,prepareCodexRawCapture as Fe,resolveCodexProviderName as je,resolveCodexRawCaptureTarget as He,resolveCodexProviderSupportsWebsocketsConfigKey as qe}from"./raw-capture-hook.js";import{unavailableRawApiCaptureBoundary as Ue}from"../../audit/raw-capture/capture-relay.js";const Be=60*1e3,ze=600*1e3,We="GRIX_RELAY_PROXY",Ve=5*1e3,Ge=15*1e3,ie=3;function j(d,e){const t=Number(process.env[d]);return Number.isFinite(t)&&t>0?t:e}function Xe(d){const e=Number(process.env[d]);return Number.isFinite(e)&&e>0?e:null}function Je(d){if(!d||typeof d!="object"||Array.isArray(d))return;const e=d,t=typeof e.auditId=="string"?e.auditId.trim():"",i=typeof e.sessionId=="string"?e.sessionId.trim():"",s=typeof e.spoolRootDir=="string"?e.spoolRootDir.trim():"";return t&&i&&s?{auditId:t,sessionId:i,spoolRootDir:s}:void 0}const H=j("GRIX_CODEX_PREFLIGHT_STALL_TIMEOUT_MS",120*1e3),Ye=20,Ke=8e3,se=2*1024,ne=`
2
+ \u2026(truncated)`,re=80,Ze=120*1e3,Qe=j("GRIX_CODEX_DELTA_COALESCE_MS",1e3),et=j("GRIX_CODEX_DELTA_COALESCE_CHARS",4096),tt=[{id:"gpt-5.3-codex",displayName:"GPT-5.3 Codex",defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!0}],oe=[{id:"default",displayName:"Default"},{id:"plan",displayName:"Plan"}],it=new Set(["rawResponse/completed","codex/rawResponse/completed","rawResponseItem/completed","codex/rawResponseItem/completed","thread/tokenUsage/updated","codex/thread/tokenUsage/updated","thread/compacted","codex/thread/compacted","turn/started","codex/turn/started","turn/completed","codex/turn/completed","item/started","codex/item/started","item/completed","codex/item/completed","error","codex/error"]);function ae(d,e){const t=String(d??"").trim()||"codex",i=ve(t,e);if(i!==t)return i;if(t!=="codex")return t;const s=process.platform==="win32"?[]:["/opt/homebrew/bin/codex","/usr/local/bin/codex","/usr/bin/codex"],n=process.platform!=="win32"?[]:[P(process.env.LOCALAPPDATA??"","npm","codex.cmd"),P(process.env.APPDATA??"","npm","codex.cmd"),P(process.env.LOCALAPPDATA??"","Programs","codex","codex.exe")],r=[...s,...n];for(const o of r)try{return require("node:fs").accessSync(o,require("node:fs").constants.X_OK),o}catch{continue}return a.warn("codex-adapter",`resolveCodexCommandPath: failed to resolve "${t}". envPath=${e?"provided":"missing (using process.env.PATH)"}. fallbacks tried: [${r.join(", ")}]`),t}class D extends K{type="codex";config;callbacks;process=null;alive=!1;stopped=!1;internalApi=null;bridgeStatus="starting";pendingRequests=new Map;requestId=0;threadId=null;initialized=!1;cwd;approvalPolicy;sandboxMode;model;collaborationMode;reasoningEffort;serviceTier;idleTimer=null;lastProgressAt=0;lastIdleCheckAt=0;activityGeneration=0;lastIdleCheckGeneration=0;idleNoProgressCount=0;inFlightToolOps=0;consecutivePingFailures=0;currentTurnStartedAt=0;preflightCheckComplete=!1;turnInactivityTimeoutMs=Xe("GRIX_CODEX_TURN_INACTIVITY_TIMEOUT_MS");pendingApprovals=new Map;needsHistoryInjection=!1;lastInjectedSessionId=null;identityInputInjectedThreadId=null;inboundMessageIds=new Ce;legacyDeveloperInstructionsUnsupported=!1;profileIdentityRefreshPending=!1;bindingStore=null;aibotSessionId="";threadResumePending=!1;autoTrustProject="auto";codexHome;codexDirect=null;directEnv={};configOverrideArgs=[];rawCaptureOptions;rawCaptureRelay;rawCaptureConfigOverrides=[];rawCaptureUnavailableReason;codexModelOptions=[];codexModelOptionsCachedAt=0;static MODEL_CACHE_TTL_MS=3600*1e3;rateLimitSnapshot=null;lastNonDefaultLimitRefreshAt=0;static NON_DEFAULT_LIMIT_REFRESH_INTERVAL_MS=6e4;currentThreadTokenUsage=null;currentModelContextWindow=null;auditCaptureByEventId=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const i=e.options??{};this.approvalPolicy=i.approvalPolicy??"never",this.sandboxMode=typeof i.sandboxMode=="string"&&i.sandboxMode.trim()&&i.sandboxMode.trim()!=="default"?i.sandboxMode.trim():void 0,this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof be?i.bindingStore:null,this.model=i.model,this.collaborationMode=i.collaborationMode,this.reasoningEffort=i.reasoningEffort,this.serviceTier=i.serviceTier,this.bindingStore&&this.aibotSessionId&&(this.model=this.model??this.bindingStore.getCodexModelId(this.aibotSessionId),this.collaborationMode=this.collaborationMode??this.bindingStore.getCodexModeId(this.aibotSessionId),this.reasoningEffort=this.reasoningEffort??this.bindingStore.getCodexReasoningEffort(this.aibotSessionId),this.serviceTier=this.serviceTier??this.bindingStore.getCodexServiceTier(this.aibotSessionId),this.sandboxMode=this.sandboxMode??this.bindingStore.getCodexSandboxMode(this.aibotSessionId)),this.autoTrustProject=typeof i.autoTrustProject=="boolean"?i.autoTrustProject:"auto",this.codexHome=typeof i.codexHome=="string"&&i.codexHome.trim()?i.codexHome.trim():void 0;const s=i.codexDirect;if(this.codexDirect=s&&typeof s=="object"&&!Array.isArray(s)?s:null,this.configOverrideArgs=te(i.codexConfigOverrides,"codexConfigOverrides"),this.rawCaptureOptions=Je(i.rawApiCapture),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const n=this.bindingStore.getCodexThreadId(this.aibotSessionId);n&&(this.threadId=n,this.threadResumePending=!0)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){await this.prepareDirectHome(),await this.ensureProjectTrusted(),await this.prepareRawApiCapture();try{await this.startInternalApiAndRegisterMcp(),await this.spawnCodex(),await this.initializeHandshake(),await this.notifyBindingReadyWithContext(),a.info("codex-adapter",`Ready (pid=${this.process?.pid})`)}catch(e){throw await this.stopRawApiCapture(),e}}async prepareRawApiCapture(){if(this.rawCaptureOptions)try{const e=await Fe(this.rawCaptureOptions,{adapterType:"codex",sessionId:this.rawCaptureOptions.sessionId,cwd:this.cwd,env:this.resolveChildEnv(),configOverrides:this.configOverrideArgs,codexHome:this.codexHome});this.rawCaptureRelay=e.relay,this.rawCaptureConfigOverrides=e.overlay.configOverrides??[],this.rawCaptureUnavailableReason=void 0,a.info("codex-adapter","Raw API audit capture relay is ready")}catch(e){this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],this.rawCaptureUnavailableReason=e instanceof Error?e.message:String(e),a.warn("codex-adapter",`Raw API audit capture unavailable: ${this.rawCaptureUnavailableReason}`)}}async stopRawApiCapture(){const e=this.rawCaptureRelay;this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],e&&await e.stop()}async prepareDirectHome(){if(!this.codexDirect)return;const e=await Re(this.codexDirect);this.codexHome=e.codexHome,this.directEnv=e.env;const t=te(e.configOverrides,"codexDirect.configOverrides");this.configOverrideArgs=[...this.configOverrideArgs,...t],a.info("codex-adapter",`Codex direct home ready: ${e.codexHome} (catalog=${e.catalogVersion??"none"}, token=${e.tokenDigest?`present sha256:${e.tokenDigest}`:"absent"})`)}resolveChildEnv(){const e={...process.env,...this.config.env};return this.codexHome&&(e.CODEX_HOME=this.codexHome),e}async ensureProjectTrusted(){if(this.shouldAutoTrustProject())try{const e=await Ae(this.cwd,{codexHome:this.codexHome});e.changed&&a.info("codex-adapter",`Trusted Codex project ${this.cwd} in ${e.configPath}`)}catch(e){const t=e instanceof Error?e.message:String(e);throw a.error("codex-adapter",`Failed to trust Codex project ${this.cwd}: ${t}`),e}}async startInternalApiAndRegisterMcp(){try{this.internalApi=new ye,this.internalApi.setInvokeHandler(async(o,c,h,p)=>this.callbacks.agentInvoke(o,c,p)),await this.internalApi.start(0),a.info("codex-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t=this.resolveChildEnv(),i=typeof t.PATH=="string"?t.PATH:void 0,s=ae(this.config.command||"codex",i);for(const o of[..._e,e.name])try{Y(s,["mcp","remove",o],{env:t,timeout:1e4,stdio:"ignore"})}catch{}Y(s,["mcp","add",e.name,"--",e.command,...e.args],{env:t,timeout:1e4,stdio:"ignore"}),a.info("codex-adapter",`Registered MCP server: ${e.name}`);const n=P(Se(this.codexHome),"skills"),r=ge(n);r.length>0&&a.info("codex-adapter",`Synced connector skills to ${n}: [${r.join(", ")}]`)}catch(e){a.warn("codex-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}shouldAutoTrustProject(){return this.autoTrustProject===!1?!1:this.autoTrustProject===!0?!0:Ee(this.config.command)}notifyBindingReady(){!this.aibotSessionId||!this.cwd||this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd)}async notifyBindingReadyWithContext(){if(!(!this.aibotSessionId||!this.cwd))try{this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,await this.buildToolbarContextResult("binding_ready"))}catch(e){a.warn("codex-adapter",`Failed to attach toolbar context to binding update: ${e instanceof Error?e.message:String(e)}`),this.notifyBindingReady()}}externalProviderCheckedAt=0;externalProviderCached=!1;static EXTERNAL_PROVIDER_CACHE_TTL_MS=60*1e3;isExternalProvider(){const e=Date.now();if(e-this.externalProviderCheckedAt<D.EXTERNAL_PROVIDER_CACHE_TTL_MS)return this.externalProviderCached;const t=F(this.codexHome);return this.externalProviderCached=!!(t.baseUrl&&ce(t.baseUrl)),this.externalProviderCheckedAt=e,this.externalProviderCached}effectiveServiceTier(){if(!this.serviceTier||this.serviceTier.trim().toLowerCase()==="default"||this.isExternalProvider())return;const e=this.getModelOption(this.currentModelId());if(!(e&&!e.serviceTiers.some(t=>t.id===this.serviceTier)))return this.serviceTier}resolveReasoningEffortForModel(e,t,i={}){const s=String(e??"").trim();if(!s||this.isExternalProvider())return;const n=this.getModelOption(t),r=n?.supportedReasoningEfforts??[];if(r.length===0)return;const o=r.find(c=>c.trim().toLowerCase()===s.toLowerCase());if(o)return o;if(!i.strict&&["max","ultra"].includes(s.toLowerCase())){const c=r.find(h=>h.trim().toLowerCase()==="xhigh");if(c)return c}return i.strict?void 0:n?.defaultReasoningEffort??void 0}effectiveReasoningEffort(){return this.resolveReasoningEffortForModel(this.reasoningEffort,this.currentModelId())}getEffortMeta(){if(this.isExternalProvider())return{};const e=this.currentModelId(),t=this.getModelOption(e),i={},s=t?.supportedReasoningEfforts??[];s.length>0&&(i.available_efforts=s,i.reasoning_effort=this.effectiveReasoningEffort()??t?.defaultReasoningEffort??null);const n=t?.serviceTiers??[];return n.length>0&&(i.available_service_tiers=n,i.service_tier=this.effectiveServiceTier()??t?.defaultServiceTier??null),i}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.rejectAllPending("adapter stopped"),this.pendingAutoCompact=!1,this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);for(const t of this.compactionDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");for(const t of this.steerDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");this.internalApi&&(await this.internalApi.stop(),this.internalApi=null);const e=this.process;if(this.process=null,e?.pid&&typeof e.once=="function")Q(e,"SIGTERM"),await Promise.race([new Promise(i=>{e.once("exit",()=>i(!0))}),new Promise(i=>{setTimeout(()=>i(!1),5e3)})])||Q(e,"SIGKILL");else if(e)try{e.kill("SIGTERM")}catch{}await this.stopRawApiCapture()}isAlive(){return this.alive}async createSession(e){if(this.initialized||await this.initializeHandshake(),this.threadId||await this.startNewThread(),!this.threadId)throw new Error("Failed to create session: thread ID is missing");return await this.notifyBindingReadyWithContext(),this.threadId}async resumeSession(e,t){await this.ensureThreadResumed()}async destroySession(e){this.threadId=null,this.threadResumePending=!1,this.persistThreadId(void 0),this.inboundMessageIds.reset()}sendPrompt(e){const t=new z(e.adapterSessionId);return this.runTurn(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){if(this.threadId)try{await this.sendRequest("turn/interrupt",{threadId:this.threadId,turnId:this.currentTurnId??""},5e3)}catch{}}setPermissionHandler(e){this.permissionHandler=e}permissionHandler=null;async ping(e){if(!this.alive||!this.process)return!1;if(!this.process.pid){const t=!!(this.process.stdin&&!this.process.stdin.destroyed),i=!!(this.process.stdout&&!this.process.stdout.destroyed);return t&&i}if(!this.process.stdin||this.process.stdin.destroyed)return!!(this.process.stdout&&!this.process.stdout.destroyed);try{const t=++this.requestId,i={jsonrpc:"2.0",id:t,method:"ping",params:{}};return await new Promise(s=>{const n=setTimeout(()=>{this.pendingRequests.delete(String(t)),s(!1)},e);this.pendingRequests.set(String(t),{resolve:()=>s(!0),reject:()=>s(!1),timer:n}),this.process.stdin.write(`${JSON.stringify(i)}
3
+ `)})}catch{return!1}}getStatus(){return{alive:this.alive,busy:this.currentTurnId!==null||this.compacting,sessions:this.threadId?1:0}}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}clearActiveEventForShutdown(){this.clearIdleTimer(),this.clearCodexDeltaBuffer(),this.activeEventId=null}setModel(e){this.model=e,this.reasoningEffort=this.resolveReasoningEffortForModel(this.reasoningEffort,this.currentModelId()),this.persistCodexContext(),a.info("codex-adapter",`Model set to: ${e}`)}setMode(e){const t=M(e);if(!t){a.info("codex-adapter",`Ignoring unsupported mode: ${e}`);return}this.collaborationMode=t,this.persistCodexContext(),a.info("codex-adapter",`Mode set to: ${t}`)}setReasoningEffort(e){const t=this.resolveReasoningEffortForModel(e,this.currentModelId(),{strict:!0});if(!t){a.info("codex-adapter",`Ignoring unsupported reasoning effort for ${this.currentModelId()}: ${e}`);return}this.reasoningEffort=t,this.persistCodexContext(),a.info("codex-adapter",`Reasoning effort set to: ${t}`)}setServiceTier(e){const t=e.trim();this.serviceTier=t.toLowerCase()==="default"?"default":t,this.persistCodexContext(),a.info("codex-adapter",`Service tier set to: ${this.serviceTier}`)}setSandboxMode(e){this.sandboxMode=e,this.persistCodexContext(),a.info("codex-adapter",`Sandbox mode set to: ${e} (applied on next restart)`)}async threadCompact(){if(!this.threadId)throw new Error("No active thread");return this.sendRequest("thread/compact/start",{threadId:this.threadId},12e4)}async threadRollback(e){if(!this.threadId)throw new Error("No active thread");return this.sendRequest("thread/rollback",{threadId:this.threadId,numTurns:e},1e4)}getThreadId(){return this.threadId}hasRawApiCaptureRelay(){return!!this.rawCaptureRelay}enableAuditCapture(e,t={}){const i=e.trim();if(!i||this.auditCaptureByEventId.has(i))return;const s=t.rawProviderBody??!!this.rawCaptureOptions;this.auditCaptureByEventId.set(i,{threadId:this.threadId??void 0,modelId:this.currentModelId()??void 0,rawProviderBody:s,sequence:0,events:[]}),s&&this.rawCaptureRelay?.beginEvent(i,t.auditId)}takeAuditBoundary(e){const t=this.auditCaptureByEventId.get(e);if(t)return this.auditCaptureByEventId.delete(e),{adapterType:this.type,providerTurnId:t.providerTurnId,threadId:t.threadId??this.threadId??void 0,codexEvidence:{events:t.events,...t.modelId?{modelId:t.modelId}:{},...t.rawProviderBody?{rawApiCapture:this.rawCaptureRelay?this.rawCaptureRelay.takeEvent(e):Ue(this.rawCaptureUnavailableReason??"raw_capture_relay_not_prepared_before_adapter_start")}:{}}}}getMcpConfig(){if(!this.internalApi)return null;const e=pe(me(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:we(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async hasBackgroundWork(){const e=this.process?.pid;return e?xe(e,[e]):!1}onAgentProfileChanged(){this.threadId&&(this.profileIdentityRefreshPending=!0,this.identityInputInjectedThreadId=null,a.info("codex-adapter",`agent profile changed; scheduling identity refresh for thread=${this.threadId}`))}async probe(e){const t=this.config.command||"codex",i=await De(t),s=i!==null;let n=null,r;if(s){const y=await $e(t);n=y.version,y.error&&(r=y.error)}else r={code:"cli_not_found",message:`command not found: ${t}`};const c=F(this.codexHome).baseUrl??null,h=this.currentModelId()||null,p=this.getStatus(),f=e?.conversation?{attempted:!0,ok:!1,latency_ms:null,error:{code:"unsupported",message:"codex does not support minimal prompt probe"}}:{attempted:!1,ok:!1,latency_ms:null},g=await this.probeSessionRecord(),x=ee({codexHome:this.codexHome});return{cli:{command:t,installed:s,path:i,version:n,...r?{error:r}:{}},conversation:f,config:{model:h,base_url:c,source:{model:h?"runtime":"unknown",base_url:c?"file":"unknown"}},process:{started:!!this.process,alive:p.alive,busy:p.busy},session:g,lock:{present:x.present,locked:x.locked,stale:x.stale,path:x.path}}}async probeSessionRecord(){const e=this.threadId?Pe(this.threadId,this.codexHome):null;if(!e)return{recordPath:null,lastActivityMs:null,freshMs:null};try{const t=await Z(e);return{recordPath:e,lastActivityMs:t.mtimeMs,freshMs:Date.now()-t.mtimeMs}}catch{return{recordPath:e,lastActivityMs:null,freshMs:null}}}getSupportedCommands(){return[{name:"compact",description:"Compact thread to reduce context size"},{name:"model",description:"List or set model",args:"[model_id]"},{name:"mode",description:"List or set collaboration mode",args:"[default|plan]"},{name:"rollback",description:"Roll back thread turns",args:"[num_turns]"},{name:"interrupt",description:"Interrupt current turn"},{name:"rate_limits",description:"Show current rate limits"},{name:"status",description:"Show thread and session status"},{name:"skills",description:"List available skills"}]}async execCommand(e,t,i){try{switch(e){case"compact":{if(!this.threadId)return{status:"failed",message:"No active thread"};if(this.compacting)return{status:"failed",message:"Compaction already in progress"};if(this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","compacting"),this.clearActive()),await this.ensureThreadResumed(),this.currentTurnId)return{status:"failed",message:"agent busy"};if(this.needsHistoryInjection)return{status:"failed",message:"The session has expired and there is no history to compact. Please send a new message and try again."};this.compacting=!0;const s=new Promise(n=>{this.compactionDoneResolver=n});try{return await this.threadCompact(),this.armCompactionFallback(),await s,{status:"ok",message:"Thread compacted"}}catch(n){this.finishCompaction("compact-error");const r=n instanceof Error?n.message:String(n);if(/thread.*(not found|not exist|unknown|invalid)/i.test(r)||/not found.*thread/i.test(r))return this.threadId=null,this.persistThreadId(void 0),{status:"failed",message:"The session has expired and there is no history to compact. Please send a new message and try again."};throw n}}case"model":{const s=t.trim();return s?this.getModelOptions().some(r=>r.id===s)?(this.setModel(s),{status:"ok",message:`Model set to ${s}`}):{status:"failed",message:`Unknown model: ${s}`}:{status:"ok",message:`Current: ${this.currentModelId()}`,data:{models:this.getModelOptions()}}}case"mode":{const s=t.trim();if(s){const n=M(s);return n?(this.setMode(n),{status:"ok",message:`Mode set to ${n}`}):{status:"failed",message:`Unknown mode: ${s}. Supported: default, plan`}}return{status:"ok",message:`Current: ${this.collaborationMode??"default"}`,data:{modes:oe}}}case"rollback":{if(!this.threadId)return{status:"failed",message:"No active thread"};const s=Math.max(1,parseInt(t.trim(),10)||1);return this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","rolled back"),this.clearActive()),await this.threadRollback(s),{status:"ok",message:`Rolled back ${s} turn(s)`}}case"interrupt":return this.threadId?(await this.cancel(this.threadId),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","interrupted"),this.clearActive(),{status:"ok",message:"Turn interrupted"}):{status:"failed",message:"No active thread"};case"rate_limits":return{status:"ok",message:this.rateLimitSnapshot?`Primary: ${this.rateLimitSnapshot.primary.usedPercent.toFixed(1)}%, Secondary: ${this.rateLimitSnapshot.secondary.usedPercent.toFixed(1)}%`:"Rate limits not available",data:{rateLimits:this.rateLimitSnapshot}};case"status":return{status:"ok",message:`Thread: ${this.threadId??"none"}, Model: ${this.currentModelId()}, Mode: ${this.collaborationMode??"default"}`,data:{threadId:this.threadId,model:this.currentModelId(),mode:this.collaborationMode??"default",cwd:this.cwd,alive:this.alive}};case"skills":{const s=Oe({mode:"codex",projectDir:this.cwd}),n=s.map(r=>`- ${r.name}${r.trigger?` (${r.trigger})`:""}: ${r.description}`);return{status:"ok",message:n.length>0?n.join(`
4
+ `):"No skills found",data:s}}default:return{status:"unsupported",message:`Unknown command: ${e}`}}}catch(s){return{status:"failed",message:s instanceof Error?s.message:String(s)}}}async handleLocalAction(e){const t=e.action_type??"",i=e.params??{};switch(a.info("codex-adapter",`handleLocalAction action_type=${t} action_id=${e.action_id} session_id=${i.session_id??""}`),t){case"set_model":{const s=I(u(i.model_id),u(i.modelId),u(i.value));return s&&this.setModel(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("model_set")),{handled:!0,kind:"set_model"}}case"set_mode":{const s=i.mode_id;return s&&this.setMode(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("mode_set")),{handled:!0,kind:"set_mode"}}case"set_reasoning_effort":{const s=I(u(i.reasoning_effort),u(i.reasoning_eff),u(i.effort)),n=this.resolveReasoningEffortForModel(s,this.currentModelId(),{strict:!0});if(!n){const r=this.getModelOption(this.currentModelId())?.supportedReasoningEfforts??[];return this.callbacks.sendLocalActionResult(e.action_id,"failed",{outcome:"effort_rejected",model_id:this.currentModelId(),available_efforts:r},"unsupported_reasoning_effort",r.length>0?`reasoning_effort must be one of: ${r.join(", ")}`:`reasoning_effort is not supported by model ${this.currentModelId()}`),{handled:!0,kind:"set_reasoning_effort_rejected"}}return this.setReasoningEffort(n),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("effort_set",!1)),{handled:!0,kind:"set_reasoning_effort"}}case"set_service_tier":{const s=I(u(i.service_tier),u(i.serviceTier),u(i.value));return s&&this.setServiceTier(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("service_tier_set",!1)),{handled:!0,kind:"set_service_tier"}}case"set_sandbox_mode":{const s=I(u(i.sandbox_mode),u(i.sandboxMode),u(i.value));return s&&this.setSandboxMode(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("sandbox_mode_set",!1)),{handled:!0,kind:"set_sandbox_mode"}}case"thread_compact":{a.info("codex-adapter",`thread_compact start action_id=${e.action_id} threadId=${this.threadId}`),this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","compacting"),this.clearActive());try{if(await this.ensureThreadResumed(),this.needsHistoryInjection)return a.info("codex-adapter",`thread_compact aborted: thread expired, new thread created action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"thread_expired","The session has expired and there is no history to compact. Please send a new message and try again."),{handled:!0,kind:"thread_compact"};this.compacting=!0;const s=new Promise(n=>{this.compactionDoneResolver=n});await this.threadCompact(),this.armCompactionFallback(),await s,a.info("codex-adapter",`thread_compact done action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(s){this.finishCompaction("compact-error");const n=s instanceof Error?s.message:String(s);/thread.*(not found|not exist|unknown|invalid)/i.test(n)||/not found.*thread/i.test(n)?(a.warn("codex-adapter",`thread_compact thread expired, resetting threadId action_id=${e.action_id} err=${n}`),this.threadId=null,this.persistThreadId(void 0),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"thread_expired","The session has expired and there is no history to compact. Please send a new message and try again.")):(a.info("codex-adapter",`thread_compact failed action_id=${e.action_id} err=${n}`),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,n))}return{handled:!0,kind:"thread_compact"}}case"get_context":return this.callbacks.sendLocalActionResult(e.action_id,"ok",{threadId:this.threadId,model:this.model,mode:this.collaborationMode,approvalPolicy:this.approvalPolicy,cwd:this.cwd,...await this.buildToolbarContextResult("context")}),{handled:!0,kind:"get_context"};case"exec_approve":case"file_approve":{const s=this.resolvePendingApproval(e);if(!s)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:t};const n=i.decision||"allow-once",r=st[n]??"accept";return this.sendApprovalDecision(s.requestId,r),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,approval_command_id:s.approvalCommandId,decision:n}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t}}case"exec_reject":case"file_reject":{const s=this.resolvePendingApproval(e);return s?(this.sendApprovalDecision(s.requestId,"deny"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,approval_command_id:s.approvalCommandId,decision:"deny"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t}):(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:t})}case"permission_approve":{const s=this.resolvePendingApproval(e);return!s||s.kind!=="permission"?(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That permission approval request is no longer pending."),{handled:!0,kind:t}):(this.sendApprovalDecision(s.requestId,"accept"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,decision:"approve"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t})}case"permission_reject":{const s=this.resolvePendingApproval(e);return!s||s.kind!=="permission"?(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That permission approval request is no longer pending."),{handled:!0,kind:t}):(this.sendApprovalDecision(s.requestId,"deny"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,decision:"deny"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t})}case"turn_interrupt":{try{await this.cancel(this.threadId??""),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(s){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,s instanceof Error?s.message:String(s))}return{handled:!0,kind:"turn_interrupt"}}case"thread_rollback":{const s=Number(i.numTurns??i.num_turns??1);if(!this.threadId)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"no_thread","No active thread"),{handled:!0,kind:"thread_rollback"};this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","rolled back"),this.clearActive());try{await this.threadRollback(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",{numTurns:s})}catch(n){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,n instanceof Error?n.message:String(n))}return{handled:!0,kind:"thread_rollback"}}case"get_rate_limits":{const s=this.rateLimitSnapshot,n=this.buildContextWindowSnapshot(),r=Date.now(),o=this.currentThreadTokenUsage;return s?a.info("codex-adapter",`[rate-limits] responding: primary=${s.primary.usedPercent.toFixed(1)}% window=${s.primary.windowMinutes}min resetsAt=${s.primary.resetsAt} secondary=${s.secondary.usedPercent.toFixed(1)}% window=${s.secondary.windowMinutes}min resetsAt=${s.secondary.resetsAt}`):a.info("codex-adapter","[rate-limits] responding: no rateLimitSnapshot available"),a.debug("codex-adapter",`[cp-diagnose] get_rate_limits: threadId=${this.threadId??"-"} contextWindow=${JSON.stringify(n)} tokenUsage=${JSON.stringify(o)}`),this.callbacks.sendLocalActionResult(e.action_id,"ok",{adapterType:"codex",available:s!==null,cached:!1,sampledAt:r,rateLimits:s,contextWindow:n,tokenUsage:o}),{handled:!0,kind:"get_rate_limits"}}default:return{handled:!1,kind:""}}}async buildToolbarContextResult(e,t=!0){t&&await this.refreshCodexModelOptions();const i=M(this.collaborationMode)??"default",s=this.currentModelId(),n=this.getModelOption(s),r=this.getModelOptions(),o=oe,c=this.effectiveReasoningEffort()??n?.defaultReasoningEffort??null,h=n?.supportedReasoningEfforts??[],p=this.effectiveServiceTier()??n?.defaultServiceTier??null,f=n?.serviceTiers??[],g=this.isExternalProvider(),x=g?[]:h,y=g?null:c,E=g?[]:f,S=g?null:p,C={outcome:e,session_context:{modelId:s,modeId:i,reasoningEffort:y,serviceTier:S,approvalPolicy:this.approvalPolicy,sandboxMode:this.sandboxMode??null},model_id:s,mode_id:i,currentModelId:s,currentModeId:i,available_models:r,available_modes:o,available_efforts:x,availableModels:r,availableModes:o,reasoning_effort:y,available_service_tiers:E,service_tier:S,sandbox_mode:this.sandboxMode??null,models:r.map(w=>({modelId:w.id,name:w.displayName})),modes:o.map(w=>({id:w.id,name:w.displayName}))};return this.rateLimitSnapshot&&(C.rate_limit_primary_percent=this.rateLimitSnapshot.primary.usedPercent,C.rate_limit_secondary_percent=this.rateLimitSnapshot.secondary.usedPercent,C.rate_limit_primary_window_min=this.rateLimitSnapshot.primary.windowMinutes,C.rate_limit_secondary_window_min=this.rateLimitSnapshot.secondary.windowMinutes),C}currentModelId(){const e=String(this.model??"").trim();if(e)return e;const t=this.getModelOptions();return t.find(i=>i.isDefault)?.id??t[0]?.id??""}getModelOption(e){const t=e.trim().toLowerCase();return this.getModelOptions().find(i=>i.id.trim().toLowerCase()===t)}getModelOptions(){const e=this.config.options??{},t=e.available_models??e.availableModels??e.models,i=ct(t),s=this.codexModelOptions,n=[],r=String(this.model??"").trim(),o=r&&!s.some(f=>f.id.trim().toLowerCase()===r.toLowerCase()),c=s.length>0?s:o?[]:tt;if(r){const f=[...s,...i].find(g=>g.id.trim().toLowerCase()===r.toLowerCase());n.push({id:r,displayName:f?.displayName??k(r),defaultReasoningEffort:f?.defaultReasoningEffort??null,supportedReasoningEfforts:f?.supportedReasoningEfforts??[],defaultServiceTier:f?.defaultServiceTier??null,serviceTiers:f?.serviceTiers??[],isDefault:f?.isDefault??!1})}n.push(...i),n.push(...c);const h=[],p=new Set;for(const f of n){const g=f.id.trim(),x=g.toLowerCase();!g||p.has(x)||(p.add(x),h.push({id:g,displayName:f.displayName.trim()||g,defaultReasoningEffort:f.defaultReasoningEffort,supportedReasoningEfforts:[...f.supportedReasoningEfforts],defaultServiceTier:f.defaultServiceTier,serviceTiers:[...f.serviceTiers],isDefault:f.isDefault}))}return h}async refreshCodexModelOptions(){if(!this.initialized||!this.alive||!this.process?.stdin||Date.now()-this.codexModelOptionsCachedAt<D.MODEL_CACHE_TTL_MS)return;const e=F(this.codexHome);if(e.baseUrl&&ce(e.baseUrl)){try{const t=await lt(e.baseUrl,e.apiKey);if(t.length>0){this.codexModelOptions=le(t),this.codexModelOptionsCachedAt=Date.now(),a.info("codex-adapter",`Loaded ${t.length} models from external provider ${e.baseUrl}`);return}}catch(t){a.warn("codex-adapter",`External provider /v1/models failed (${t instanceof Error?t.message:String(t)}), falling back`)}this.codexModelOptions=[],this.codexModelOptionsCachedAt=Date.now();return}try{const t=[];let i;do{const s=await this.sendRequest("model/list",{cursor:i??null,includeHidden:!1,limit:100},15e3),n=ht(s);t.push(...n.models),i=n.nextCursor}while(i);t.length>0&&(this.codexModelOptions=le(t),this.codexModelOptionsCachedAt=Date.now())}catch(t){a.warn("codex-adapter",`Failed to load Codex model list: ${t instanceof Error?t.message:String(t)}`)}}currentTurnId=null;compacting=!1;pendingAutoCompact=!1;compactionDeferred=[];steerDeferred=[];compactingTimer=null;compactionDoneResolver=null;activeEventId=null;activeSessionId=null;visibleAgentMessageIds=new Set;hiddenAgentMessageIds=new Set;agentMessagePhases=new Map;deliveredAgentMessageIds=new Set;deliveredThinkingAgentMessageIds=new Set;codexSequence=0;pendingCodexDeltaFlush=null;turnError=null;turnErrorIsRetryableOnly=!0;turnHasVisibleOutput=!1;turnSawVisibleFinalAnswer=!1;turnHasDeliveredFinalAnswer=!1;deliverInboundEvent(e){if(this.compacting){a.info("codex-adapter",`Event ${e.event_id} deferred: compaction in progress`),this.compactionDeferred.push(e);return}const t=this.inboundMessageIds.prepare(e.session_id,e.content,e.msg_id),i=t.text,s=()=>{t.instructionPending&&this.inboundMessageIds.commitInstruction(e.session_id)},n=()=>{const r=this.inboundMessageIds.prepare(e.session_id,e.content,e.msg_id);r.instructionPending&&this.inboundMessageIds.commitInstruction(e.session_id),this.startNewTurn(e,r.text)};if(this.currentTurnId&&i.trim()){a.info("codex-adapter",`Event ${e.event_id}: steering active turn ${this.currentTurnId}`),this.steerTurn(i).then(()=>{s()}).catch(r=>{const o=r instanceof Error?r.message:String(r);if(a.info("codex-adapter",`Steer failed, falling through: ${o}`),!this.currentTurnId){n();return}if(mt(o)){a.info("codex-adapter","Unsteerable turn detected, clearing active state and starting new turn"),this.clearActive(),n();return}a.info("codex-adapter",`Steer failed but turn still active; deferring event ${e.event_id} for replay after turn ends`),this.steerDeferred.push(e)});return}if(this.currentTurnId){a.info("codex-adapter",`Event ${e.event_id} rejected: busy and empty content`),this.sendEventResultAfterFlushing(e.event_id,"failed","agent busy");return}s(),this.startNewTurn(e,i)}startNewTurn(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,e.audit?.enabled===!0&&this.enableAuditCapture(e.event_id,{auditId:e.audit.auditId,rawProviderBody:e.audit.rawProviderBody}),this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.codexSequence=0,this.startComposing();const i=this.threadId??"",s=new z(i),n={adapterSessionId:i,text:t,contextMessages:e.context_messages_json?JSON.parse(e.context_messages_json).map(r=>({senderId:r.sender_id??"unknown",content:r.content})):void 0};this.runTurn(n,s,e.event_id,e.session_id).catch(r=>{a.error("codex-adapter",`Turn failed: ${r}`),this.sendEventResultAfterFlushing(e.event_id,"failed",r instanceof Error?r.message:String(r)),this.clearActive()}),this.resetIdleTimer(e.event_id)}deliverStopEvent(e,t){this.activeEventId===e&&(this.cancel(this.threadId??"").catch(()=>{}),this.sendEventResultAfterFlushing(e,"canceled","stopped by user"),this.clearActive())}async spawnCodex(){const e={...this.resolveChildEnv(),...this.directEnv},t=typeof e.PATH=="string"?e.PATH:void 0;t||a.warn("codex-adapter",`spawnCodex: env.PATH is missing! process.env.PATH=${process.env.PATH?"set":"missing"}, config.env=${JSON.stringify(this.config.env)}`);const i=ae(this.config.command||"codex",t),s=rt(this.config.args);for(const o of this.configOverrideArgs)s.push("-c",o);for(const o of this.resolveRelayTransportConfigOverrides())s.push("-c",o);for(const o of this.rawCaptureConfigOverrides)s.push("-c",o);this.sandboxMode&&s.push("-c",`sandbox_mode="${this.sandboxMode}"`);const n=s.map(o=>this.rawCaptureConfigOverrides.includes(o)?"<raw-api-capture-overlay>":o);a.info("codex-adapter",`Spawning: ${i} ${n.join(" ")}`);try{if(!(await Z(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(o){throw String(o?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):o}const r=ee({codexHome:this.codexHome});if(r.locked&&!r.stale)throw new Error(`Codex session appears locked by another process: ${r.path}`);r.stale&&a.warn("codex-adapter",`Ignoring stale Codex lock: ${r.path}`);try{this.process=Ie(i,s,{env:e,cwd:this.cwd}).process}catch(o){throw a.error("codex-adapter",`Codex spawn threw: ${o}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",o}this.process.on("error",o=>{a.error("codex-adapter",`Codex process spawn error: ${o}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("spawn failed: "+(o instanceof Error?o.message:String(o))),this.stopComposing(),this.activeEventId?(this.flushCodexDeltaBuffer(),this.sendEventResultAfterFlushing(this.activeEventId,"failed","Codex process spawn failed"),this.activeEventId=null):this.clearCodexDeltaBuffer(),this.emit("exit",1)}),this.process.on("exit",o=>{a.info("codex-adapter",`Codex process exited (code=${o})`),this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("process exited"),this.stopComposing(),this.activeEventId?this.flushCodexDeltaBuffer():this.clearCodexDeltaBuffer(),this.emit("exit",o)}),this.process.stderr?.on("data",o=>{const c=o.toString().trim();c&&a.info("codex-adapter",`[codex stderr] ${c}`)}),this.bindStdout(),this.alive=!0}resolveRelayTransportConfigOverrides(){if(this.config.env?.[We]!=="1")return[];const e=je(this.codexHome,this.configOverrideArgs);if(e==="openai"){const i=He(this.codexHome,this.configOverrideArgs);return Le(Ne,"Grix OpenAI Relay",i.targetBaseUrl)}const t=qe(e);return t?[`${t}=false`]:[]}bindStdout(){if(!this.process?.stdout)return;this.process.stdout.setEncoding("utf8"),fe({input:this.process.stdout}).on("line",t=>{if(!t.trim())return;let i;try{i=JSON.parse(t)}catch{a.error("codex-adapter",`Invalid JSON from Codex: ${t.slice(0,200)}`);return}if(this.bridgeStatus==="starting"&&(this.bridgeStatus="ready"),i.id!=null){const s=String(i.id),n=this.pendingRequests.get(s);if(n){clearTimeout(n.timer),this.pendingRequests.delete(s),n.resolve(i);return}}this.handleNotification(i)})}handleNotification(e){const t=e.method,i=e.params??{};if(this.shouldIgnoreOutOfScopeNotification(e,t,i)){this.activeEventId&&this.resetIdleTimer(this.activeEventId);return}switch(this.captureAuditNotification(t,i),this.captureContextWindowFromPayload(t,i),this.activeEventId&&t&&t.startsWith("item/")&&!t.endsWith("/requestApproval")&&this.startComposing(),t){case"item/started":{const n=i.item,r=n?.id,o=n?.type,c=this.normalizeAgentMessagePhase(n?.phase);if(this.isLongRunningToolItemType(o)&&(this.inFlightToolOps+=1),o==="agentMessage"&&r){c?this.agentMessagePhases.set(r,c):this.agentMessagePhases.delete(r);const h=N(c),p=L(c);h?(this.visibleAgentMessageIds.add(r),this.hiddenAgentMessageIds.delete(r)):p?(this.visibleAgentMessageIds.delete(r),this.hiddenAgentMessageIds.delete(r)):(this.hiddenAgentMessageIds.add(r),this.visibleAgentMessageIds.delete(r)),c==="final_answer"&&h&&(this.turnSawVisibleFinalAnswer=!0)}break}case"item/agentMessage/delta":{const n=i.delta,r=i.itemId,o=this.resolveAgentMessagePhase(r,i.phase),c=(!r||!this.hiddenAgentMessageIds.has(r))&&N(o),h=(!r||!this.hiddenAgentMessageIds.has(r))&&L(o);if(o==="final_answer"&&c&&(this.turnSawVisibleFinalAnswer=!0),n&&this.activeEventId&&h){this.recordDeliveredThinkingAgentMessage(r),this.callbacks.sendThinking?.(this.activeEventId,this.activeSessionId??"",n);break}n&&this.activeEventId&&c&&!this.shouldSuppressAgentMessageDeltaDuringToolRun(r,o)&&(this.recordDeliveredAgentMessage(r,o),this.queueCodexDeltaEvent({...e,params:{...i,...o?{phase:o}:{}}}));break}case"item/completed":{const n=i.item,r=n?.id,o=n?.type;if(this.isLongRunningToolItemType(o)&&(this.inFlightToolOps=Math.max(0,this.inFlightToolOps-1)),this.activeEventId&&o==="commandExecution"&&(this.turnHasVisibleOutput=!0,this.emitCodexEvent("item/completed",e)),o==="agentMessage"){const c=this.resolveAgentMessagePhase(r,n?.phase),h=(!r||!this.hiddenAgentMessageIds.has(r))&&N(c);if(c==="final_answer"&&h){this.turnSawVisibleFinalAnswer=!0;const p=this.extractAgentMessageText(n),f=r?this.deliveredAgentMessageIds.has(r):!1;this.activeEventId&&p&&!f&&(a.warn("codex-adapter",`Recovering final_answer from item/completed item_id=${r??"unknown"}`),this.recordDeliveredAgentMessage(r,c),this.queueCodexDeltaEvent({method:"item/agentMessage/delta",params:{...r?{itemId:r}:{},delta:p,phase:c}}))}else if(L(c)){const p=this.extractAgentMessageText(n),f=r?this.deliveredThinkingAgentMessageIds.has(r):!1;this.activeEventId&&p&&!f&&(this.recordDeliveredThinkingAgentMessage(r),this.callbacks.sendThinking?.(this.activeEventId,this.activeSessionId??"",p))}r&&(this.visibleAgentMessageIds.delete(r),this.hiddenAgentMessageIds.delete(r),this.agentMessagePhases.delete(r))}break}case"turn/started":{const r=i.turn?.id;r&&(this.currentTurnId=r,this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.currentTurnStartedAt=Date.now(),this.preflightCheckComplete=!1,a.info("codex-adapter",`Turn started: ${r}`),this.startComposing());break}case"item/fileChange/requestApproval":{this.handleApprovalRequest(e,"file");break}case"item/commandExecution/requestApproval":{this.handleApprovalRequest(e,"exec");break}case"item/permissions/requestApproval":{this.handleApprovalRequest(e,"permission");break}case"turn/completed":{this.handleTurnCompleted(i);break}case"error":{const n=i.message??JSON.stringify(i);a.error("codex-adapter",`Codex error: ${n}`);const r=i.willRetry===!0;n&&(this.turnError=n,r||(this.turnErrorIsRetryableOnly=!1)),this.activeEventId&&!r&&(this.flushCodexDeltaBuffer(),this.callbacks.sendRunError(this.activeEventId,this.activeSessionId??"",n));break}case"account/rateLimits/updated":{const n=this.extractRateLimitPushLimitId(i),r=this.parseRateLimitSnapshot(i,this.rateLimitSnapshot);r&&(this.rateLimitSnapshot=r,a.info("codex-adapter",`Rate limits updated: primary=${r.primary.usedPercent.toFixed(1)}% secondary=${r.secondary.usedPercent.toFixed(1)}% extras=${r.extras?.length??0}`),this.callbacks.onRateLimitsUpdated?.(r)),n&&n!=="codex"&&this.refreshMainRateLimitsThrottled();break}case"thread/tokenUsage/updated":{const n=i.threadId,r=i.tokenUsage,o=r?.last;(!n||!r||!o)&&a.info("codex-adapter",`[cp-diagnose] token_usage payload_incomplete: method=thread/tokenUsage/updated hasThreadId=${String(!!n)} hasTokenUsage=${String(!!r)} hasLast=${String(!!o)} params=${JSON.stringify(i)}`),n&&r&&o&&(this.currentThreadTokenUsage={inputTokens:o.inputTokens??0,outputTokens:o.outputTokens??0,cacheReadInputTokens:o.cachedInputTokens??0,cacheCreationInputTokens:0},a.info("codex-adapter",`[cp-diagnose] token_usage raw thread=${n}: ${JSON.stringify(r)}`),a.info("codex-adapter",`[cp-diagnose] token_usage parsed thread=${n}: ${JSON.stringify(this.currentThreadTokenUsage)}`),this.callbacks.onTokenUsageUpdated?.(this.currentThreadTokenUsage),this.publishContextWindowSnapshot());break}default:break}const s=t?.endsWith("/requestApproval")===!0;t&&t!=="turn/started"&&(t.startsWith("item/")||t==="error"||t==="turn/completed")&&(this.preflightCheckComplete=!0),this.activeEventId&&(!s||this.pendingApprovals.size===0)&&this.resetIdleTimer(this.activeEventId)}shouldIgnoreOutOfScopeNotification(e,t,i){if(!t||e.id!=null)return!1;const s=I(u(i.threadId),u(i.threadID));if(s&&this.threadId&&s!==this.threadId)return this.logIgnoredNotificationScope(t,s,this.readNotificationTurnId(i)),!0;const n=this.readNotificationTurnId(i);return n&&this.currentTurnId&&n!==this.currentTurnId?(this.logIgnoredNotificationScope(t,s,n),!0):!1}readNotificationTurnId(e){const t=e.turn&&typeof e.turn=="object"?e.turn:void 0;return I(u(e.turnId),u(e.turnID),u(t?.id))}logIgnoredNotificationScope(e,t,i){e!=="error"&&!e.startsWith("turn/")||a.info("codex-adapter",`[scope] ignored ${e} thread=${t??"<none>"} turn=${i??"<none>"} active_thread=${this.threadId??"<none>"} active_turn=${this.currentTurnId??"<none>"}`)}captureAuditNotification(e,t){const i=this.activeEventId;if(!e||!i)return;const s=this.auditCaptureByEventId.get(i);if(!s)return;const n=t.turn,r=typeof t.turnId=="string"&&t.turnId?t.turnId:typeof t.turn_id=="string"&&t.turn_id?t.turn_id:typeof n?.id=="string"&&n.id?n.id:this.currentTurnId;r&&(s.providerTurnId=r);const o=typeof t.threadId=="string"&&t.threadId?t.threadId:typeof t.thread_id=="string"&&t.thread_id?t.thread_id:this.threadId;if(o&&(s.threadId=o),!!it.has(e))try{const c=JSON.parse(JSON.stringify(t));s.events.push({sequence:++s.sequence,method:e,params:c,observedAt:new Date().toISOString()})}catch(c){const h=c instanceof Error?c.message:String(c);a.warn("codex-adapter",`Audit evidence capture skipped event=${i} method=${e}: ${h}`)}}captureContextWindowFromPayload(e,t){const i=["model_context_window","modelContextWindow","context_window_size","contextWindowSize"],s=this.findNumericField(t,i);if(s==null||s<=0){const n=this.probeContextWindowFields(t,i);n.foundAnyCandidateField&&a.info("codex-adapter",`[cp-diagnose] context_window missing_or_invalid: method=${e??"-"} matchedFields=${n.matchedFields.join(",")||"-"} raw=${n.rawValues.join(",")||"-"} extracted=${String(s)}`);return}this.currentModelContextWindow!==s&&(this.currentModelContextWindow=s,a.info("codex-adapter",`[cp-diagnose] context_window updated: method=${e??"-"} size=${s}`),this.publishContextWindowSnapshot())}probeContextWindowFields(e,t){const i=[],s=[],n=r=>{if(!r||typeof r!="object")return;if(Array.isArray(r)){for(const c of r)n(c);return}const o=r;for(const c of t)Object.prototype.hasOwnProperty.call(o,c)&&(i.push(c),s.push(String(o[c])));for(const c of Object.values(o))n(c)};return n(e),{foundAnyCandidateField:i.length>0,matchedFields:i,rawValues:s}}findNumericField(e,t){if(!e||typeof e!="object")return null;const i=e;for(const s of t){const n=i[s];if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n=="string"){const r=Number(n);if(Number.isFinite(r))return r}}for(const s of Object.values(i)){if(Array.isArray(s)){for(const r of s){const o=this.findNumericField(r,t);if(o!=null)return o}continue}const n=this.findNumericField(s,t);if(n!=null)return n}return null}buildContextWindowSnapshot(){const e=this.currentModelContextWindow;if(!e||e<=0)return a.debug("codex-adapter",`[cp-diagnose] context_window snapshot skipped: invalid size=${String(e)}`),null;const t=this.currentThreadTokenUsage,i=t?t.inputTokens+t.outputTokens:null,s=i==null?null:Math.max(0,e-i),n=i==null?null:Math.min(100,i/e*100),r=i==null?null:Math.max(0,100-(n??0));return a.info("codex-adapter",`[cp-diagnose] context_window computed: threadId=${this.threadId??"-"} size=${e} usedTokens=${String(i)} usedPercentage=${String(n)}`),{sizeTokens:e,usedTokens:i,remainingTokens:s,usedPercentage:n,remainingPercentage:r,source:"codex:model_context_window"}}publishContextWindowSnapshot(){const e=this.buildContextWindowSnapshot();this.callbacks.onContextWindowUpdated?.(e),this.maybeScheduleAutoCompact(e)}maybeScheduleAutoCompact(e){const t=e?.usedPercentage;typeof t!="number"||t<re||this.pendingAutoCompact||this.compacting||(this.pendingAutoCompact=!0,a.info("codex-adapter",`[auto-compact] context_window usedPercentage=${t.toFixed(1)}% >= ${re}%, scheduling compact`),this.tryRunPendingAutoCompact())}tryRunPendingAutoCompact(){this.pendingAutoCompact&&(this.stopped||!this.alive||this.currentTurnId||this.compacting||(this.pendingAutoCompact=!1,this.execCommand("compact","",this.activeSessionId??"").then(e=>{a.info("codex-adapter",`[auto-compact] compact done status=${e.status} msg=${e.message??""}`),e.status==="failed"&&/agent busy/i.test(e.message??"")&&(this.pendingAutoCompact=!0)}).catch(e=>{a.warn("codex-adapter",`[auto-compact] compact error: ${e instanceof Error?e.message:e}`)})))}parseRateLimitSnapshot(e,t=null){try{const i=e.rateLimitsByLimitId,s=this.extractRateLimitPushLimitId(e),n=!i?.codex&&!!s&&s!=="codex",r=i?.codex??(n?{}:e.rateLimits??e),o=r.primary,c=r.secondary,h=r.credits,p=l=>{if(typeof l=="number"&&Number.isFinite(l))return l;if(typeof l=="string"){const m=Number(l);if(Number.isFinite(m))return m}return 0},f=l=>typeof l=="boolean"?l:typeof l=="string"?l.toLowerCase()==="true":!1,g=l=>{if(l==null)return null;if(typeof l=="string"){const m=l.trim();if(!m)return null;const v=Number(m);return Number.isFinite(v)&&v>1e9?new Date(v*1e3).toISOString():m}if(typeof l=="number"&&Number.isFinite(l)&&l>0){const m=l>1e12?l/1e3:l;return new Date(m*1e3).toISOString()}return null},x=l=>{const m=l.resets_in_seconds??l.resetsInSeconds,v=typeof m=="number"||typeof m=="string"?Number(m):NaN;return!Number.isFinite(v)||v<=0?null:new Date(Date.now()+v*1e3).toISOString()},y=l=>({usedPercent:p(l.used_percent??l.usedPercent),windowMinutes:p(l.window_minutes??l.windowDurationMins??l.windowMinutes),resetsAt:g(l.resets_at??l.resetsAt)??x(l)}),E=()=>({usedPercent:0,windowMinutes:0,resetsAt:null}),S=(l,m)=>l??m??E(),C=()=>{const l=[];if(o&&l.push(o),c&&l.push(c),Array.isArray(r.windows))for(const m of r.windows)m&&typeof m=="object"&&l.push(m);return l.map(y).filter(m=>m.windowMinutes>0)},w=(l,m,v)=>{const T=l.filter(b=>v(b.windowMinutes));return T.length===0?null:T.reduce((b,A)=>Math.abs(A.windowMinutes-m)<Math.abs(b.windowMinutes-m)?A:b)},$=C(),O=n?t?{primary:t.primary,secondary:t.secondary}:null:$.length>0?{primary:S(w($,300,l=>l<1440),t?.primary),secondary:S(w($,10080,l=>l>=1440),t?.secondary)}:o||c?{primary:o?y(o):t?.primary??E(),secondary:c?y(c):t?.secondary??E()}:null;if(!O)return null;const W=(l,m)=>{if(!m||typeof m!="object"||Array.isArray(m))return null;const v=m,T=v.limitName??v.limit_name,b=typeof T=="string"&&T.trim()?T.trim():l,A=[],V=v.primary,G=v.secondary;V&&A.push(V),G&&A.push(G);const X=A.map(y).filter(R=>R.windowMinutes>0),J=w(X,10080,R=>R>=1440)??w(X,300,R=>R<1440);return J?{id:l,label:b,...J}:null};let _;if(i&&typeof i=="object"){_=[];for(const[l,m]of Object.entries(i)){if(l==="codex")continue;const v=W(l,m);v&&_.push(v)}}else if(_=t?.extras?[...t.extras]:[],n&&s){const l=W(s,e.rateLimits??e);if(l){const m=_.findIndex(v=>v.id===l.id);m>=0?_[m]=l:_.push(l)}}return{primary:O.primary,secondary:O.secondary,credits:h?{hasCredits:f(h.has_credits??h.hasCredits),unlimited:f(h.unlimited),balance:h.balance==null?null:p(h.balance)}:t?.credits??{hasCredits:!1,unlimited:!1,balance:null},..._.length>0?{extras:_}:{}}}catch{return null}}handleApprovalRequest(e,t){const i=e.id;if(i==null)return;const s=e.method,n=`${i}`.trim(),r=`codex_${ue(this.activeSessionId??"")}_${ue(n)}`;if(this.approvalPolicy==="never"){this.sendApprovalDecision(i,"accept");return}this.activeEventId&&this.emitCodexEvent(s,e),this.pendingApprovals.set(r,{approvalId:r,approvalCommandId:n,sourceEventId:this.activeEventId??"",requestId:i,kind:t}),a.info("codex-adapter",`Pending approval stored: ${r} (kind=${t})`),this.clearIdleTimer(),this.stopComposing()}resolvePendingApproval(e){const t=e.params??{},i=I(t.approval_id,t.approvalId);if(i)return this.pendingApprovals.get(i)??null;const s=I(t.approval_command_id,t.approvalCommandId);if(s){for(const[,n]of this.pendingApprovals)if(n.approvalCommandId===s)return n}return null}sendApprovalDecision(e,t){if(e==null||!this.process?.stdin)return;const i={jsonrpc:"2.0",id:e,result:{decision:t}};this.process.stdin.write(`${JSON.stringify(i)}
5
+ `)}armCompactionFallback(){this.compacting&&(this.compactingTimer&&clearTimeout(this.compactingTimer),this.compactingTimer=setTimeout(()=>{a.warn("codex-adapter","Compaction fallback fired: turn/completed not received within timeout, treating as stuck and releasing deferred events"),this.currentTurnId=null,this.finishCompaction("fallback-timeout")},Ze),this.compactingTimer.unref?.())}finishCompaction(e){if(!this.compacting)return;this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);const t=this.compactionDeferred.splice(0);a.info("codex-adapter",`Compaction finished (${e}); replaying ${t.length} deferred events`);for(const s of t)this.deliverInboundEvent(s);const i=this.compactionDoneResolver;this.compactionDoneResolver=null,i?.()}handleTurnCompleted(e){if(this.currentTurnId=null,this.stopComposing(),this.activeEventId){this.flushCodexDeltaBuffer();const t=this.activeEventId,i={event_id:t,session_id:this.activeSessionId??"",thread_id:this.threadId??void 0,codex_event_type:"codex",codex_method:"turn/completed",codex_sequence:++this.codexSequence},s=this.turnError,n=this.turnErrorIsRetryableOnly,r=this.turnHasVisibleOutput,o=this.turnSawVisibleFinalAnswer&&!this.turnHasDeliveredFinalAnswer;this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1;const h=(s&&!(n&&r)?s:null)??(o?"Codex final answer was observed but not delivered":null)??(r?null:"Codex completed without producing any visible output"),p=h!==null;this.callbacks.sendCodexEvent(i),this.sendEventResultAfterFlushing(t,p?"failed":"responded",h??void 0),this.clearActive()}this.compacting&&this.finishCompaction("turn-completed")}emitCodexEvent(e,t){if(!this.activeEventId)return;this.flushCodexDeltaBuffer();const i=he(e,t);if(i===void 0&&e==="item/completed")return;const s={event_id:this.activeEventId,session_id:this.activeSessionId??"",thread_id:this.threadId??void 0,codex_event_type:"codex",codex_method:e,codex_sequence:++this.codexSequence};i!==void 0&&(s.codex_payload=i),this.callbacks.sendCodexEvent(s)}queueCodexDeltaEvent(e){if(!this.activeEventId)return;const t=he("item/agentMessage/delta",e),i=t?.params?.delta;if(typeof i!="string"||i.length===0)return;const s=typeof t?.params?.phase=="string"?t.params.phase:void 0,n=this.activeEventId,r=this.activeSessionId??"",o=this.threadId??void 0,c=this.pendingCodexDeltaFlush;if(c&&(c.eventId!==n||c.sessionId!==r||c.threadId!==o||c.phase!==s)&&this.flushCodexDeltaBuffer(),this.pendingCodexDeltaFlush||(this.pendingCodexDeltaFlush={eventId:n,sessionId:r,threadId:o,delta:"",phase:s,timer:null}),this.pendingCodexDeltaFlush.delta+=i,this.pendingCodexDeltaFlush.delta.length>=et){this.flushCodexDeltaBuffer();return}this.pendingCodexDeltaFlush.timer||(this.pendingCodexDeltaFlush.timer=setTimeout(()=>{if(this.activeEventId!==n){this.clearCodexDeltaBuffer();return}this.flushCodexDeltaBuffer()},Qe))}flushCodexDeltaBuffer(){const e=this.pendingCodexDeltaFlush;if(!e||(this.pendingCodexDeltaFlush=null,e.timer&&clearTimeout(e.timer),!e.delta))return;const t={event_id:e.eventId,session_id:e.sessionId,thread_id:e.threadId,codex_event_type:"codex",codex_method:"item/agentMessage/delta",codex_sequence:++this.codexSequence,codex_payload:{params:{delta:e.delta,...e.phase?{phase:e.phase}:{}}}};this.callbacks.sendCodexEvent(t)}clearCodexDeltaBuffer(){const e=this.pendingCodexDeltaFlush;this.pendingCodexDeltaFlush=null,e?.timer&&clearTimeout(e.timer)}sendEventResultAfterFlushing(e,t,i){this.pendingCodexDeltaFlush?.eventId===e&&this.flushCodexDeltaBuffer(),this.callbacks.sendEventResult(e,t,i)}startComposing(){}stopComposing(){}async sendRequest(e,t,i=3e4){return new Promise((s,n)=>{if(!this.process?.stdin){n(new Error("Codex process not available"));return}const r=++this.requestId,o={jsonrpc:"2.0",id:r,method:e,params:t??{}},c=setTimeout(()=>{this.pendingRequests.delete(String(r)),n(new Error(`Request timeout: ${e}`))},i);this.pendingRequests.set(String(r),{resolve:p=>{p.error?n(new Error(`JSON-RPC error: ${p.error.message}`)):s(p.result)},reject:n,timer:c});const h=JSON.stringify(o);this.process.stdin.write(`${h}
6
6
  `)})}sendNotification(e,t){if(!this.process?.stdin)return;const i={jsonrpc:"2.0",method:e,params:t??{}};this.process.stdin.write(`${JSON.stringify(i)}
7
- `)}async initializeHandshake(){if(this.initialized)return;const e=Ce(),t=await this.sendRequest("initialize",{clientInfo:{name:"grix-connector",title:"Grix Connector",version:e},capabilities:{experimentalApi:!0}},15e3);d.info("codex-adapter",`Initialized: ${JSON.stringify(t)}`),this.sendNotification("initialized"),this.initialized=!0,await this.refreshCodexModelOptions(),this.fetchRateLimits()}extractRateLimitPushLimitId(e){const t=s=>{if(!s||typeof s!="object"||Array.isArray(s))return null;const n=s.limitId??s.limit_id;return typeof n=="string"&&n.trim()?n.trim():null},i=e.rateLimitsByLimitId;if(i&&typeof i=="object"&&!Array.isArray(i)){const s=i;return s.codex?"codex":t(Object.values(s)[0])}return t(e.rateLimits??e)}refreshMainRateLimitsThrottled(){const e=Date.now();e-this.lastNonDefaultLimitRefreshAt<D.NON_DEFAULT_LIMIT_REFRESH_INTERVAL_MS||(this.lastNonDefaultLimitRefreshAt=e,this.fetchRateLimits())}fetchRateLimits(){Promise.resolve(this.sendRequest("account/rateLimits/read",void 0,1e4)).then(e=>{const t=this.parseRateLimitSnapshot(e);t&&(this.rateLimitSnapshot=t,d.info("codex-adapter",`Initial rate limits: primary=${t.primary.usedPercent.toFixed(1)}% secondary=${t.secondary.usedPercent.toFixed(1)}% credits=${t.credits.balance??"N/A"}`),this.callbacks.onRateLimitsUpdated?.(t))}).catch(e=>{d.warn("codex-adapter",`Failed to fetch rate limits: ${e instanceof Error?e.message:e}`)})}async runTurn(e,t,i,s){this.threadId||await this.createSession({cwd:this.cwd}),await this.ensureThreadResumed();const n=[];if((this.legacyDeveloperInstructionsUnsupported||this.profileIdentityRefreshPending)&&this.identityInputInjectedThreadId!==this.threadId){const h=de(this.callbacks.getAgentProfile?.());h&&(n.push({type:"text",text:h.instructions,text_elements:[]}),d.info("codex-adapter",`Injected agent identity through compatibility input for thread=${this.threadId} name="${h.agentName}"`)),this.identityInputInjectedThreadId=this.threadId,this.profileIdentityRefreshPending=!1}if(this.needsHistoryInjection&&s){this.needsHistoryInjection=!1;const h=await this.loadHistoryForInjection(s);for(const f of h)n.push(f);h.length>0&&d.info("codex-adapter",`Injected ${h.length} history items`)}if(e.contextMessages&&e.contextMessages.length>0){const h=e.contextMessages.map(f=>`[${f.senderId??"unknown"}]: ${f.content}`).join(`
7
+ `)}async initializeHandshake(){if(this.initialized)return;const e=Te(),t=await this.sendRequest("initialize",{clientInfo:{name:"grix-connector",title:"Grix Connector",version:e},capabilities:{experimentalApi:!0}},15e3);a.info("codex-adapter",`Initialized: ${JSON.stringify(t)}`),this.sendNotification("initialized"),this.initialized=!0,await this.refreshCodexModelOptions(),this.fetchRateLimits()}extractRateLimitPushLimitId(e){const t=s=>{if(!s||typeof s!="object"||Array.isArray(s))return null;const n=s.limitId??s.limit_id;return typeof n=="string"&&n.trim()?n.trim():null},i=e.rateLimitsByLimitId;if(i&&typeof i=="object"&&!Array.isArray(i)){const s=i;return s.codex?"codex":t(Object.values(s)[0])}return t(e.rateLimits??e)}refreshMainRateLimitsThrottled(){const e=Date.now();e-this.lastNonDefaultLimitRefreshAt<D.NON_DEFAULT_LIMIT_REFRESH_INTERVAL_MS||(this.lastNonDefaultLimitRefreshAt=e,this.fetchRateLimits())}fetchRateLimits(){Promise.resolve(this.sendRequest("account/rateLimits/read",void 0,1e4)).then(e=>{const t=this.parseRateLimitSnapshot(e);t&&(this.rateLimitSnapshot=t,a.info("codex-adapter",`Initial rate limits: primary=${t.primary.usedPercent.toFixed(1)}% secondary=${t.secondary.usedPercent.toFixed(1)}% credits=${t.credits.balance??"N/A"}`),this.callbacks.onRateLimitsUpdated?.(t))}).catch(e=>{a.warn("codex-adapter",`Failed to fetch rate limits: ${e instanceof Error?e.message:e}`)})}async runTurn(e,t,i,s){this.threadId||await this.createSession({cwd:this.cwd}),await this.ensureThreadResumed();const n=[];if((this.legacyDeveloperInstructionsUnsupported||this.profileIdentityRefreshPending)&&this.identityInputInjectedThreadId!==this.threadId){const f=de(this.callbacks.getAgentProfile?.());f&&(n.push({type:"text",text:f.instructions,text_elements:[]}),a.info("codex-adapter",`Injected agent identity through compatibility input for thread=${this.threadId} name="${f.agentName}"`)),this.identityInputInjectedThreadId=this.threadId,this.profileIdentityRefreshPending=!1}if(this.needsHistoryInjection&&s){this.needsHistoryInjection=!1;const f=await this.loadHistoryForInjection(s);for(const g of f)n.push(g);f.length>0&&a.info("codex-adapter",`Injected ${f.length} history items`)}if(e.contextMessages&&e.contextMessages.length>0){const f=e.contextMessages.map(g=>`[${g.senderId??"unknown"}]: ${g.content}`).join(`
8
8
  `);n.push({type:"text",text:`Conversation context:
9
- ${h}
9
+ ${f}
10
10
 
11
- Latest user message:`,text_elements:[]})}n.push({type:"text",text:e.text,text_elements:[]});const o={threadId:this.threadId,approvalPolicy:this.approvalPolicy,input:n,model:this.model},c=dt(this.collaborationMode,this.model);c&&(o.collaborationMode=c),this.reasoningEffort&&(o.effort=this.reasoningEffort);const p=this.effectiveServiceTier();p&&(o.serviceTier=p),await this.sendRequest("turn/start",o),t.emitDone({status:"completed"})}async ensureThreadResumed(){if(!(!this.threadId||!this.threadResumePending))try{const e=await this.sendRequest("thread/resume",{threadId:this.threadId,approvalPolicy:this.approvalPolicy,model:this.model,excludeTurns:!0,persistExtendedHistory:!1,...this.reasoningEffort?{effort:this.reasoningEffort}:{},...this.effectiveServiceTier()?{serviceTier:this.effectiveServiceTier()}:{}});this.updateModelFromThreadResult(e),this.threadResumePending=!1}catch{this.threadId=null,this.needsHistoryInjection=!0,await this.startNewThread(),this.threadResumePending=!1}}async startNewThread(){const e=de(this.callbacks.getAgentProfile?.()),t={approvalPolicy:this.approvalPolicy,model:this.model,cwd:this.cwd,experimentalRawEvents:!1,persistExtendedHistory:!1,...this.reasoningEffort?{effort:this.reasoningEffort}:{},...this.effectiveServiceTier()?{serviceTier:this.effectiveServiceTier()}:{}};try{let i;if(e&&!this.legacyDeveloperInstructionsUnsupported)try{i=await this.sendRequest("thread/start",{...t,developerInstructions:e.instructions})}catch(n){if(!nt(n))throw n;this.legacyDeveloperInstructionsUnsupported=!0,d.warn("codex-adapter","Codex app-server does not support thread/start.developerInstructions; falling back to first-turn identity input"),i=await this.sendRequest("thread/start",t)}else i=await this.sendRequest("thread/start",t);const s=ot(i);if(!s)throw new Error("Codex thread id is missing in thread/start result");this.threadId=s,this.identityInputInjectedThreadId=null,this.profileIdentityRefreshPending=!1,this.updateModelFromThreadResult(i),this.threadResumePending=!1,this.persistThreadId(s)}catch(i){const s=i instanceof Error?i.message:String(i);throw new Error(`Failed to start Codex thread: ${s}`)}}updateModelFromThreadResult(e){if(this.model)return;const t=at(e);t&&(this.model=t,this.persistCodexContext())}persistThreadId(e){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodexThreadId(this.aibotSessionId,e)}persistCodexContext(){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodexContext(this.aibotSessionId,{modelId:this.model,modeId:M(this.collaborationMode)??void 0,reasoningEffort:this.reasoningEffort,serviceTier:this.serviceTier,sandboxMode:this.sandboxMode})}async loadHistoryForInjection(e){const t=this.callbacks.getConversationLog();if(!t)return[];try{const i=await t.readHistory(e,Ye),s=[];for(const n of i){const r=(n.content??"").slice(0,Ke);n.direction==="inbound"?s.push({type:"text",text:r,text_elements:[]}):n.direction==="outbound"&&s.push({type:"assistant",text:r,text_elements:[]})}return s}catch(i){return d.error("codex-adapter",`Failed to load history: ${i}`),[]}}async steerTurn(e){if(!this.threadId||!this.currentTurnId)throw new Error("No active turn to steer");await this.sendRequest("turn/steer",{threadId:this.threadId,expectedTurnId:this.currentTurnId,input:[{type:"text",text:e,text_elements:[]}]})}resumeAfterApproval(e,t,i){if(!this.threadId)return;const s=e.event_id?.trim()||`local_action_${e.action_id.trim()}`,n=I(t.session_id,t.sessionId)??this.activeSessionId??"";if(!n)return;const r=this.threadId,o=new z(r),c={adapterSessionId:r,text:""};this.activeEventId=s,this.activeSessionId=n,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.codexSequence=0,this.runTurn(c,o,s,n).catch(p=>{d.error("codex-adapter",`Post-approval turn failed: ${p}`),this.sendEventResultAfterFlushing(s,"failed",p instanceof Error?p.message:String(p)),this.clearActive()}),this.resetIdleTimer(s)}clearActive(e){const t=this.activeEventId;if(this.flushCodexDeltaBuffer(),this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.currentTurnId=null,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.inFlightToolOps=0,this.consecutivePingFailures=0,this.currentTurnStartedAt=0,this.preflightCheckComplete=!1,this.clearIdleTimer(),this.pendingApprovals.clear(),t&&e?.emitEventDone!==!1){const i=this.rawCaptureRelay;i?i.completeEvent(t).catch(s=>{d.warn("codex-adapter",`Raw API audit capture did not settle cleanly: ${s instanceof Error?s.message:String(s)}`)}).finally(()=>this.emit("eventDone",t)):this.emit("eventDone",t)}this.replaySteerDeferred(),e?.runPendingAutoCompact!==!1&&this.tryRunPendingAutoCompact()}replaySteerDeferred(){if(this.steerDeferred.length===0)return;const e=this.steerDeferred.splice(0);d.info("codex-adapter",`Replaying ${e.length} steer-deferred event(s) after turn ended`);for(const t of e)this.deliverInboundEvent(t)}resetIdleTimer(e){const t=Date.now();this.lastProgressAt=t,this.lastIdleCheckAt=t,this.activityGeneration+=1,this.lastIdleCheckGeneration=this.activityGeneration,this.idleNoProgressCount=0,this.consecutivePingFailures=0,this.armIdleTimer(e)}armIdleTimer(e,t=Number.POSITIVE_INFINITY){this.clearIdleTimer();const i=Date.now(),s=this.inFlightToolOps>0?ze:Be,n=this.turnInactivityTimeoutMs===null?Number.POSITIVE_INFINITY:this.lastProgressAt+this.turnInactivityTimeoutMs-i,r=this.currentTurnStartedAt>0&&!this.preflightCheckComplete?this.currentTurnStartedAt+H-i:Number.POSITIVE_INFINITY,o=Math.max(0,Math.min(s,n,r,t));this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e,o)},o)}async onIdleTimeout(e,t){if(this.activeEventId!==e)return;const i=this.lastIdleCheckAt,s=this.lastIdleCheckGeneration,n=this.ping(Ve).catch(()=>!1),r=this.checkSessionActivitySince(i),[o,c]=await Promise.all([n,r]);if(this.activeEventId!==e)return;const p=this.activityGeneration>s;if(this.lastIdleCheckAt=Date.now(),this.lastIdleCheckGeneration=this.activityGeneration,!this.preflightCheckComplete&&this.currentTurnStartedAt>0&&Date.now()-this.currentTurnStartedAt>=H){const f=this.activityGeneration,v=await this.inspectCurrentTurnProgress();if(this.activeEventId!==e)return;if(this.activityGeneration>f)this.preflightCheckComplete=!0;else if(v==="task_started_only"){this.declareRecoverablePreflightStuck(e,`Codex preflight stalled for ${Math.round(H/1e3)}s before model execution`);return}else v==="unknown"?this.currentTurnStartedAt=Date.now():this.preflightCheckComplete=!0}if(p||c){c&&(d.info("codex-adapter",`Idle timer: no stream output but rollout still being written, continuing: ${e}`),this.lastProgressAt=Date.now()),this.idleNoProgressCount=0,this.consecutivePingFailures=0,this.armIdleTimer(e);return}const h=Date.now()-this.lastProgressAt;if(this.turnInactivityTimeoutMs!==null&&h>=this.turnInactivityTimeoutMs){d.error("codex-adapter",`Turn inactive ${Math.round(h/1e3)}s \u2265 cap ${Math.round(this.turnInactivityTimeoutMs/1e3)}s, declaring stuck: ${e}`),this.declareStuck(e,`turn inactivity timeout after ${Math.round(h/1e3)}s with no Codex activity`);return}if(!o){if(this.consecutivePingFailures+=1,this.consecutivePingFailures<ie){d.warn("codex-adapter",`Agent idle ${t/1e3}s and ping failed (${this.consecutivePingFailures}/${ie}); retrying liveness probe: ${e}`),this.armIdleTimer(e,Ge);return}d.error("codex-adapter",`Agent idle ${t/1e3}s and ping failed ${this.consecutivePingFailures}x, declaring stuck: ${e}`),this.declareStuck(e,`agent idle ${t/1e3}s, ping failed ${this.consecutivePingFailures}x`);return}this.consecutivePingFailures=0,this.idleNoProgressCount++,d.info("codex-adapter",`Idle timer: ping ok, no stream progress (cycle=${this.idleNoProgressCount}), keeping active turn alive${this.turnInactivityTimeoutMs===null?"":` until inactivity cap (${Math.round(this.turnInactivityTimeoutMs/6e4)}min)`}: ${e}`),this.armIdleTimer(e)}declareStuck(e,t){this.sendEventResultAfterFlushing(e,"failed",t),this.clearActive(),this.emit("stuck")}declareRecoverablePreflightStuck(e,t){const i=this.activeSessionId??"";d.error("codex-adapter",`${t}; restarting adapter and replaying event: ${e}`),this.clearActive({runPendingAutoCompact:!1,emitEventDone:!1}),this.emit("internalError",{eventId:e,sessionId:i,errorMsg:t})}async inspectCurrentTurnProgress(){if(!this.threadId||!this.currentTurnId)return"unknown";try{return await ke(this.threadId,this.currentTurnId,this.codexHome)}catch{return"unknown"}}async checkSessionActivitySince(e){if(!this.threadId)return!1;try{return await Me(this.threadId,e,this.codexHome)}catch{return!1}}isLongRunningToolItemType(e){if(!e)return!1;const t=e.toLowerCase();return t==="commandexecution"||t==="command_execution"||t==="item/commandexecution"||t==="filechange"||t==="file_change"||t==="item/filechange"}normalizeAgentMessagePhase(e){return typeof e!="string"?void 0:e.trim().toLowerCase()||void 0}resolveAgentMessagePhase(e,t){return this.normalizeAgentMessagePhase(t)??(e?this.agentMessagePhases.get(e):void 0)}extractAgentMessageText(e){return e?typeof e.text=="string"&&e.text.length>0?e.text:typeof e.message=="string"&&e.message.length>0?e.message:Array.isArray(e.content)&&e.content.map(i=>{if(typeof i=="string")return i;if(!i||typeof i!="object"||Array.isArray(i))return"";const s=i;return typeof s.text=="string"?s.text:""}).join("")||void 0:void 0}recordDeliveredAgentMessage(e,t){this.turnHasVisibleOutput=!0,e&&this.deliveredAgentMessageIds.add(e),t==="final_answer"&&(this.turnSawVisibleFinalAnswer=!0,this.turnHasDeliveredFinalAnswer=!0)}recordDeliveredThinkingAgentMessage(e){e&&this.deliveredThinkingAgentMessageIds.add(e)}shouldSuppressAgentMessageDeltaDuringToolRun(e,t){return t==="final_answer"||this.inFlightToolOps<=0?!1:(d.info("codex-adapter",`Suppressing agentMessage delta during tool run item_id=${e??"unknown"}`),!0)}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}rejectAllPending(e){for(const[,t]of this.pendingRequests)clearTimeout(t.timer),t.reject(new Error(`Request canceled: ${e}`));this.pendingRequests.clear(),this.pendingApprovals.clear()}}const st={allow:"accept","allow-once":"accept","allow-always":"acceptForSession",deny:"deny"};function de(a){const e=a?.agentName?.trim()??"",t=a?.introduction?.trim()??"";if(!e&&!t)return;const i=["[system-identity]"];return e&&i.push(`Your name is "${e}".`),t&&i.push(`Your self-introduction: ${t}`),i.push("Treat this as an out-of-band instruction; do not echo or repeat it in your replies."),i.push("[/system-identity]"),{agentName:e,instructions:i.join(`
12
- `)}}function nt(a){return a instanceof Error?/unknown\s+(?:field|parameter|property)[^\n]*(?:developerInstructions|developer_instructions)/i.test(a.message):!1}function rt(a){return a&&a.length>0?[...a]:["app-server"]}function u(a){if(typeof a!="string")return;const e=a.trim();return e||void 0}function ot(a){if(!a||typeof a!="object")return null;const e=a,t=e.thread&&typeof e.thread=="object"?e.thread:void 0;return I(u(e.threadId),u(e.threadID),u(t?.id))??null}function at(a){return!a||typeof a!="object"?null:u(a.model)??null}function M(a){const e=a?.trim().toLowerCase();return e==="default"||e==="plan"?e:null}function dt(a,e){const t=M(a),i=u(e);if(!(!t||!i))return{mode:t,settings:{model:i}}}function ct(a){if(!Array.isArray(a))return[];const e=[];for(const t of a){if(typeof t=="string"){const r=t.trim();r&&e.push(pt(r,k(r)));continue}if(!t||typeof t!="object")continue;const i=t,s=I(u(i.id),u(i.model_id),u(i.modelId),u(i.value));if(!s)continue;const n=I(u(i.displayName),u(i.display_name),u(i.name),u(i.label))??k(s);e.push({id:s,displayName:n,defaultReasoningEffort:u(i.defaultReasoningEffort)??null,supportedReasoningEfforts:U(i.supportedReasoningEfforts),defaultServiceTier:u(i.defaultServiceTier)??null,serviceTiers:q(i.serviceTiers),isDefault:i.isDefault===!0})}return e}function ce(a){const e=a.toLowerCase().replace(/\/+$/,"");return!(e==="https://api.openai.com"||e==="https://api.openai.com/v1"||e.endsWith(".openai.com"))}async function lt(a,e){const i=`${a.replace(/\/+$/,"")}/models`,s={Accept:"application/json"};e&&(s.Authorization=`Bearer ${e}`);const n=new AbortController,r=setTimeout(()=>n.abort(),1e4);try{const o=await fetch(i,{headers:s,signal:n.signal});if(!o.ok)return[];const c=await o.json();return ut(c)}finally{clearTimeout(r)}}function ut(a){if(!a||typeof a!="object")return[];const e=a,t=Array.isArray(e.data)?e.data:[],i=[];for(const s of t){if(!s||typeof s!="object")continue;const n=s,r=I(u(n.id),u(n.model));if(!r)continue;const o=I(u(n.displayName),u(n.display_name),u(n.name))??k(r);i.push({id:r,displayName:o,defaultReasoningEffort:u(n.defaultReasoningEffort)??null,supportedReasoningEfforts:U(n.supportedReasoningEfforts),defaultServiceTier:u(n.defaultServiceTier)??null,serviceTiers:q(n.serviceTiers),isDefault:n.isDefault===!0})}return i}function ht(a){if(!a||typeof a!="object")return{models:[],nextCursor:null};const e=a,t=Array.isArray(e.data)?e.data:[],i=[];for(const s of t){if(!s||typeof s!="object")continue;const n=s;if(n.hidden===!0)continue;const r=I(u(n.id),u(n.model));if(!r)continue;const o=I(u(n.displayName),u(n.display_name),u(n.name))??k(r);i.push({id:r,displayName:o,defaultReasoningEffort:u(n.defaultReasoningEffort)??null,supportedReasoningEfforts:U(n.supportedReasoningEfforts),defaultServiceTier:u(n.defaultServiceTier)??null,serviceTiers:q(n.serviceTiers),isDefault:n.isDefault===!0})}return{models:i,nextCursor:u(e.nextCursor)??null}}function le(a){const e=[],t=new Set;for(const i of a){const s=i.id.trim(),n=s.toLowerCase();!s||t.has(n)||(t.add(n),e.push({id:s,displayName:i.displayName.trim()||s,defaultReasoningEffort:i.defaultReasoningEffort,supportedReasoningEfforts:[...i.supportedReasoningEfforts],defaultServiceTier:i.defaultServiceTier,serviceTiers:[...i.serviceTiers],isDefault:i.isDefault}))}return e}function pt(a,e){return{id:a,displayName:e,defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!1}}function U(a){if(!Array.isArray(a))return[];const e=[];for(const t of a){if(typeof t=="string"){const s=t.trim();s&&e.push(s);continue}if(!t||typeof t!="object")continue;const i=u(t.reasoningEffort);i&&e.push(i)}return e}function q(a){if(!Array.isArray(a))return[];const e=[];for(const t of a){if(typeof t=="string"){const n=t.trim();n&&e.push({id:n,displayName:n,description:null});continue}if(!t||typeof t!="object")continue;const i=t,s=u(i.id);s&&e.push({id:s,displayName:I(u(i.name),u(i.displayName),u(i.display_name))??s,description:u(i.description)??null})}return e}function k(a){return a.split(/[-_\s]+/).filter(Boolean).map(e=>/^(gpt|codex|o\d+)$/i.test(e)?e.toUpperCase():e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function I(...a){for(const e of a)if(e!=null){if(typeof e=="string"&&!e.trim())continue;return e}}function ue(a){return a.trim().replace(/[^a-zA-Z0-9._:-]+/g,"_")}function he(a,e){switch(a){case"turn/completed":return;case"item/agentMessage/delta":{const t=e?.params??{};if(typeof t.delta!="string"||t.delta.length===0)return;const i=typeof t.phase=="string"&&t.phase.trim()?t.phase.trim().toLowerCase():void 0;return{params:{delta:t.delta,...i?{phase:i}:{}}}}case"item/completed":{const i=(e?.params??{}).item;if(!i||typeof i!="object"||i.type!=="commandExecution")return;const s=ft(i.command);return{params:{item:{type:"commandExecution",...s!==void 0?{command:s}:{},...i.exitCode!==void 0?{exitCode:i.exitCode}:{},...i.durationMs!==void 0?{durationMs:i.durationMs}:{}}}}}case"item/permissions/requestApproval":return B(e,"permission");case"item/commandExecution/requestApproval":return B(e,"exec");case"item/fileChange/requestApproval":return B(e,"file");default:return}}function B(a,e){if(a==null||typeof a!="object")return;const t=a.params??{};if(t==null||typeof t!="object"||Array.isArray(t))return;const i={},s=(...r)=>{for(const o of r)t[o]!==void 0&&(i[o]=t[o])};e==="permission"?s("threadId","turnId","itemId","reason","permissions"):e==="exec"?s("command","commandLine","command_line","argv","args","availableDecisions","cwd","workingDirectory","working_directory"):s("path","filePath","file_path","targetPath","target_path","paths","files","availableDecisions","cwd","workingDirectory","working_directory");const n={params:i};return a.id!==void 0&&(n.id=a.id),typeof a.method=="string"&&a.method&&(n.method=a.method),n}function ft(a){if(typeof a!="string")return;const e=a.trim();if(e)return e.length<=se?e:e.slice(0,se-ne.length)+ne}class z extends K{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){d.warn("codex-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}function mt(a){return["cannot steer a compact turn","turn not found","turn already completed","no active turn"].some(t=>a.includes(t))}export{D as CodexAdapter,he as trimCodexPayloadForWire};
11
+ Latest user message:`,text_elements:[]})}n.push({type:"text",text:e.text,text_elements:[]});const o={threadId:this.threadId,approvalPolicy:this.approvalPolicy,input:n,model:this.model},c=dt(this.collaborationMode,this.model);c&&(o.collaborationMode=c);const h=this.effectiveReasoningEffort();h&&(o.effort=h);const p=this.effectiveServiceTier();p&&(o.serviceTier=p),await this.sendRequest("turn/start",o),t.emitDone({status:"completed"})}async ensureThreadResumed(){if(!(!this.threadId||!this.threadResumePending))try{const e=this.effectiveReasoningEffort(),t=this.effectiveServiceTier(),i=await this.sendRequest("thread/resume",{threadId:this.threadId,approvalPolicy:this.approvalPolicy,model:this.model,excludeTurns:!0,persistExtendedHistory:!1,...e?{effort:e}:{},...t?{serviceTier:t}:{}});this.updateModelFromThreadResult(i),this.threadResumePending=!1}catch{this.threadId=null,this.needsHistoryInjection=!0,await this.startNewThread(),this.threadResumePending=!1}}async startNewThread(){const e=de(this.callbacks.getAgentProfile?.()),t=this.effectiveReasoningEffort(),i=this.effectiveServiceTier(),s={approvalPolicy:this.approvalPolicy,model:this.model,cwd:this.cwd,experimentalRawEvents:!1,persistExtendedHistory:!1,...t?{effort:t}:{},...i?{serviceTier:i}:{}};try{let n;if(e&&!this.legacyDeveloperInstructionsUnsupported)try{n=await this.sendRequest("thread/start",{...s,developerInstructions:e.instructions})}catch(o){if(!nt(o))throw o;this.legacyDeveloperInstructionsUnsupported=!0,a.warn("codex-adapter","Codex app-server does not support thread/start.developerInstructions; falling back to first-turn identity input"),n=await this.sendRequest("thread/start",s)}else n=await this.sendRequest("thread/start",s);const r=ot(n);if(!r)throw new Error("Codex thread id is missing in thread/start result");this.threadId=r,this.identityInputInjectedThreadId=null,this.profileIdentityRefreshPending=!1,this.updateModelFromThreadResult(n),this.threadResumePending=!1,this.persistThreadId(r)}catch(n){const r=n instanceof Error?n.message:String(n);throw new Error(`Failed to start Codex thread: ${r}`)}}updateModelFromThreadResult(e){if(this.model)return;const t=at(e);t&&(this.model=t,this.persistCodexContext())}persistThreadId(e){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodexThreadId(this.aibotSessionId,e)}persistCodexContext(){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodexContext(this.aibotSessionId,{modelId:this.model,modeId:M(this.collaborationMode)??void 0,reasoningEffort:this.effectiveReasoningEffort(),serviceTier:this.serviceTier,sandboxMode:this.sandboxMode})}async loadHistoryForInjection(e){const t=this.callbacks.getConversationLog();if(!t)return[];try{const i=await t.readHistory(e,Ye),s=[];for(const n of i){const r=(n.content??"").slice(0,Ke);n.direction==="inbound"?s.push({type:"text",text:r,text_elements:[]}):n.direction==="outbound"&&s.push({type:"assistant",text:r,text_elements:[]})}return s}catch(i){return a.error("codex-adapter",`Failed to load history: ${i}`),[]}}async steerTurn(e){if(!this.threadId||!this.currentTurnId)throw new Error("No active turn to steer");await this.sendRequest("turn/steer",{threadId:this.threadId,expectedTurnId:this.currentTurnId,input:[{type:"text",text:e,text_elements:[]}]})}resumeAfterApproval(e,t,i){if(!this.threadId)return;const s=e.event_id?.trim()||`local_action_${e.action_id.trim()}`,n=I(t.session_id,t.sessionId)??this.activeSessionId??"";if(!n)return;const r=this.threadId,o=new z(r),c={adapterSessionId:r,text:""};this.activeEventId=s,this.activeSessionId=n,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.codexSequence=0,this.runTurn(c,o,s,n).catch(h=>{a.error("codex-adapter",`Post-approval turn failed: ${h}`),this.sendEventResultAfterFlushing(s,"failed",h instanceof Error?h.message:String(h)),this.clearActive()}),this.resetIdleTimer(s)}clearActive(e){const t=this.activeEventId;if(this.flushCodexDeltaBuffer(),this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.currentTurnId=null,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.inFlightToolOps=0,this.consecutivePingFailures=0,this.currentTurnStartedAt=0,this.preflightCheckComplete=!1,this.clearIdleTimer(),this.pendingApprovals.clear(),t&&e?.emitEventDone!==!1){const i=this.rawCaptureRelay;i?i.completeEvent(t).catch(s=>{a.warn("codex-adapter",`Raw API audit capture did not settle cleanly: ${s instanceof Error?s.message:String(s)}`)}).finally(()=>this.emit("eventDone",t)):this.emit("eventDone",t)}this.replaySteerDeferred(),e?.runPendingAutoCompact!==!1&&this.tryRunPendingAutoCompact()}replaySteerDeferred(){if(this.steerDeferred.length===0)return;const e=this.steerDeferred.splice(0);a.info("codex-adapter",`Replaying ${e.length} steer-deferred event(s) after turn ended`);for(const t of e)this.deliverInboundEvent(t)}resetIdleTimer(e){const t=Date.now();this.lastProgressAt=t,this.lastIdleCheckAt=t,this.activityGeneration+=1,this.lastIdleCheckGeneration=this.activityGeneration,this.idleNoProgressCount=0,this.consecutivePingFailures=0,this.armIdleTimer(e)}armIdleTimer(e,t=Number.POSITIVE_INFINITY){this.clearIdleTimer();const i=Date.now(),s=this.inFlightToolOps>0?ze:Be,n=this.turnInactivityTimeoutMs===null?Number.POSITIVE_INFINITY:this.lastProgressAt+this.turnInactivityTimeoutMs-i,r=this.currentTurnStartedAt>0&&!this.preflightCheckComplete?this.currentTurnStartedAt+H-i:Number.POSITIVE_INFINITY,o=Math.max(0,Math.min(s,n,r,t));this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e,o)},o)}async onIdleTimeout(e,t){if(this.activeEventId!==e)return;const i=this.lastIdleCheckAt,s=this.lastIdleCheckGeneration,n=this.ping(Ve).catch(()=>!1),r=this.checkSessionActivitySince(i),[o,c]=await Promise.all([n,r]);if(this.activeEventId!==e)return;const h=this.activityGeneration>s;if(this.lastIdleCheckAt=Date.now(),this.lastIdleCheckGeneration=this.activityGeneration,!this.preflightCheckComplete&&this.currentTurnStartedAt>0&&Date.now()-this.currentTurnStartedAt>=H){const f=this.activityGeneration,g=await this.inspectCurrentTurnProgress();if(this.activeEventId!==e)return;if(this.activityGeneration>f)this.preflightCheckComplete=!0;else if(g==="task_started_only"){this.declareRecoverablePreflightStuck(e,`Codex preflight stalled for ${Math.round(H/1e3)}s before model execution`);return}else g==="unknown"?this.currentTurnStartedAt=Date.now():this.preflightCheckComplete=!0}if(h||c){c&&(a.info("codex-adapter",`Idle timer: no stream output but rollout still being written, continuing: ${e}`),this.lastProgressAt=Date.now()),this.idleNoProgressCount=0,this.consecutivePingFailures=0,this.armIdleTimer(e);return}const p=Date.now()-this.lastProgressAt;if(this.turnInactivityTimeoutMs!==null&&p>=this.turnInactivityTimeoutMs){a.error("codex-adapter",`Turn inactive ${Math.round(p/1e3)}s \u2265 cap ${Math.round(this.turnInactivityTimeoutMs/1e3)}s, declaring stuck: ${e}`),this.declareStuck(e,`turn inactivity timeout after ${Math.round(p/1e3)}s with no Codex activity`);return}if(!o){if(this.consecutivePingFailures+=1,this.consecutivePingFailures<ie){a.warn("codex-adapter",`Agent idle ${t/1e3}s and ping failed (${this.consecutivePingFailures}/${ie}); retrying liveness probe: ${e}`),this.armIdleTimer(e,Ge);return}a.error("codex-adapter",`Agent idle ${t/1e3}s and ping failed ${this.consecutivePingFailures}x, declaring stuck: ${e}`),this.declareStuck(e,`agent idle ${t/1e3}s, ping failed ${this.consecutivePingFailures}x`);return}this.consecutivePingFailures=0,this.idleNoProgressCount++,a.info("codex-adapter",`Idle timer: ping ok, no stream progress (cycle=${this.idleNoProgressCount}), keeping active turn alive${this.turnInactivityTimeoutMs===null?"":` until inactivity cap (${Math.round(this.turnInactivityTimeoutMs/6e4)}min)`}: ${e}`),this.armIdleTimer(e)}declareStuck(e,t){this.sendEventResultAfterFlushing(e,"failed",t),this.clearActive(),this.emit("stuck")}declareRecoverablePreflightStuck(e,t){const i=this.activeSessionId??"";a.error("codex-adapter",`${t}; restarting adapter and replaying event: ${e}`),this.clearActive({runPendingAutoCompact:!1,emitEventDone:!1}),this.emit("internalError",{eventId:e,sessionId:i,errorMsg:t})}async inspectCurrentTurnProgress(){if(!this.threadId||!this.currentTurnId)return"unknown";try{return await ke(this.threadId,this.currentTurnId,this.codexHome)}catch{return"unknown"}}async checkSessionActivitySince(e){if(!this.threadId)return!1;try{return await Me(this.threadId,e,this.codexHome)}catch{return!1}}isLongRunningToolItemType(e){if(!e)return!1;const t=e.toLowerCase();return t==="commandexecution"||t==="command_execution"||t==="item/commandexecution"||t==="filechange"||t==="file_change"||t==="item/filechange"}normalizeAgentMessagePhase(e){return typeof e!="string"?void 0:e.trim().toLowerCase()||void 0}resolveAgentMessagePhase(e,t){return this.normalizeAgentMessagePhase(t)??(e?this.agentMessagePhases.get(e):void 0)}extractAgentMessageText(e){return e?typeof e.text=="string"&&e.text.length>0?e.text:typeof e.message=="string"&&e.message.length>0?e.message:Array.isArray(e.content)&&e.content.map(i=>{if(typeof i=="string")return i;if(!i||typeof i!="object"||Array.isArray(i))return"";const s=i;return typeof s.text=="string"?s.text:""}).join("")||void 0:void 0}recordDeliveredAgentMessage(e,t){this.turnHasVisibleOutput=!0,e&&this.deliveredAgentMessageIds.add(e),t==="final_answer"&&(this.turnSawVisibleFinalAnswer=!0,this.turnHasDeliveredFinalAnswer=!0)}recordDeliveredThinkingAgentMessage(e){e&&this.deliveredThinkingAgentMessageIds.add(e)}shouldSuppressAgentMessageDeltaDuringToolRun(e,t){return t==="final_answer"||this.inFlightToolOps<=0?!1:(a.info("codex-adapter",`Suppressing agentMessage delta during tool run item_id=${e??"unknown"}`),!0)}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}rejectAllPending(e){for(const[,t]of this.pendingRequests)clearTimeout(t.timer),t.reject(new Error(`Request canceled: ${e}`));this.pendingRequests.clear(),this.pendingApprovals.clear()}}const st={allow:"accept","allow-once":"accept","allow-always":"acceptForSession",deny:"deny"};function de(d){const e=d?.agentName?.trim()??"",t=d?.introduction?.trim()??"";if(!e&&!t)return;const i=["[system-identity]"];return e&&i.push(`Your name is "${e}".`),t&&i.push(`Your self-introduction: ${t}`),i.push("Treat this as an out-of-band instruction; do not echo or repeat it in your replies."),i.push("[/system-identity]"),{agentName:e,instructions:i.join(`
12
+ `)}}function nt(d){return d instanceof Error?/unknown\s+(?:field|parameter|property)[^\n]*(?:developerInstructions|developer_instructions)/i.test(d.message):!1}function rt(d){return d&&d.length>0?[...d]:["app-server"]}function u(d){if(typeof d!="string")return;const e=d.trim();return e||void 0}function ot(d){if(!d||typeof d!="object")return null;const e=d,t=e.thread&&typeof e.thread=="object"?e.thread:void 0;return I(u(e.threadId),u(e.threadID),u(t?.id))??null}function at(d){return!d||typeof d!="object"?null:u(d.model)??null}function M(d){const e=d?.trim().toLowerCase();return e==="default"||e==="plan"?e:null}function dt(d,e){const t=M(d),i=u(e);if(!(!t||!i))return{mode:t,settings:{model:i}}}function ct(d){if(!Array.isArray(d))return[];const e=[];for(const t of d){if(typeof t=="string"){const r=t.trim();r&&e.push(ft(r,k(r)));continue}if(!t||typeof t!="object")continue;const i=t,s=I(u(i.id),u(i.model_id),u(i.modelId),u(i.value));if(!s)continue;const n=I(u(i.displayName),u(i.display_name),u(i.name),u(i.label))??k(s);e.push({id:s,displayName:n,defaultReasoningEffort:u(i.defaultReasoningEffort)??null,supportedReasoningEfforts:q(i.supportedReasoningEfforts),defaultServiceTier:u(i.defaultServiceTier)??null,serviceTiers:U(i.serviceTiers),isDefault:i.isDefault===!0})}return e}function ce(d){const e=d.toLowerCase().replace(/\/+$/,"");return!(e==="https://api.openai.com"||e==="https://api.openai.com/v1"||e.endsWith(".openai.com"))}async function lt(d,e){const i=`${d.replace(/\/+$/,"")}/models`,s={Accept:"application/json"};e&&(s.Authorization=`Bearer ${e}`);const n=new AbortController,r=setTimeout(()=>n.abort(),1e4);try{const o=await fetch(i,{headers:s,signal:n.signal});if(!o.ok)return[];const c=await o.json();return ut(c)}finally{clearTimeout(r)}}function ut(d){if(!d||typeof d!="object")return[];const e=d,t=Array.isArray(e.data)?e.data:[],i=[];for(const s of t){if(!s||typeof s!="object")continue;const n=s,r=I(u(n.id),u(n.model));if(!r)continue;const o=I(u(n.displayName),u(n.display_name),u(n.name))??k(r);i.push({id:r,displayName:o,defaultReasoningEffort:u(n.defaultReasoningEffort)??null,supportedReasoningEfforts:q(n.supportedReasoningEfforts),defaultServiceTier:u(n.defaultServiceTier)??null,serviceTiers:U(n.serviceTiers),isDefault:n.isDefault===!0})}return i}function ht(d){if(!d||typeof d!="object")return{models:[],nextCursor:null};const e=d,t=Array.isArray(e.data)?e.data:[],i=[];for(const s of t){if(!s||typeof s!="object")continue;const n=s;if(n.hidden===!0)continue;const r=I(u(n.id),u(n.model));if(!r)continue;const o=I(u(n.displayName),u(n.display_name),u(n.name))??k(r);i.push({id:r,displayName:o,defaultReasoningEffort:u(n.defaultReasoningEffort)??null,supportedReasoningEfforts:q(n.supportedReasoningEfforts),defaultServiceTier:u(n.defaultServiceTier)??null,serviceTiers:U(n.serviceTiers),isDefault:n.isDefault===!0})}return{models:i,nextCursor:u(e.nextCursor)??null}}function le(d){const e=[],t=new Set;for(const i of d){const s=i.id.trim(),n=s.toLowerCase();!s||t.has(n)||(t.add(n),e.push({id:s,displayName:i.displayName.trim()||s,defaultReasoningEffort:i.defaultReasoningEffort,supportedReasoningEfforts:[...i.supportedReasoningEfforts],defaultServiceTier:i.defaultServiceTier,serviceTiers:[...i.serviceTiers],isDefault:i.isDefault}))}return e}function ft(d,e){return{id:d,displayName:e,defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!1}}function q(d){if(!Array.isArray(d))return[];const e=[];for(const t of d){if(typeof t=="string"){const s=t.trim();s&&e.push(s);continue}if(!t||typeof t!="object")continue;const i=u(t.reasoningEffort);i&&e.push(i)}return e}function U(d){if(!Array.isArray(d))return[];const e=[];for(const t of d){if(typeof t=="string"){const n=t.trim();n&&e.push({id:n,displayName:n,description:null});continue}if(!t||typeof t!="object")continue;const i=t,s=u(i.id);s&&e.push({id:s,displayName:I(u(i.name),u(i.displayName),u(i.display_name))??s,description:u(i.description)??null})}return e}function k(d){return d.split(/[-_\s]+/).filter(Boolean).map(e=>/^(gpt|codex|o\d+)$/i.test(e)?e.toUpperCase():e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function I(...d){for(const e of d)if(e!=null){if(typeof e=="string"&&!e.trim())continue;return e}}function ue(d){return d.trim().replace(/[^a-zA-Z0-9._:-]+/g,"_")}function he(d,e){switch(d){case"turn/completed":return;case"item/agentMessage/delta":{const t=e?.params??{};if(typeof t.delta!="string"||t.delta.length===0)return;const i=typeof t.phase=="string"&&t.phase.trim()?t.phase.trim().toLowerCase():void 0;return{params:{delta:t.delta,...i?{phase:i}:{}}}}case"item/completed":{const i=(e?.params??{}).item;if(!i||typeof i!="object"||i.type!=="commandExecution")return;const s=pt(i.command);return{params:{item:{type:"commandExecution",...s!==void 0?{command:s}:{},...i.exitCode!==void 0?{exitCode:i.exitCode}:{},...i.durationMs!==void 0?{durationMs:i.durationMs}:{}}}}}case"item/permissions/requestApproval":return B(e,"permission");case"item/commandExecution/requestApproval":return B(e,"exec");case"item/fileChange/requestApproval":return B(e,"file");default:return}}function B(d,e){if(d==null||typeof d!="object")return;const t=d.params??{};if(t==null||typeof t!="object"||Array.isArray(t))return;const i={},s=(...r)=>{for(const o of r)t[o]!==void 0&&(i[o]=t[o])};e==="permission"?s("threadId","turnId","itemId","reason","permissions"):e==="exec"?s("command","commandLine","command_line","argv","args","availableDecisions","cwd","workingDirectory","working_directory"):s("path","filePath","file_path","targetPath","target_path","paths","files","availableDecisions","cwd","workingDirectory","working_directory");const n={params:i};return d.id!==void 0&&(n.id=d.id),typeof d.method=="string"&&d.method&&(n.method=d.method),n}function pt(d){if(typeof d!="string")return;const e=d.trim();if(e)return e.length<=se?e:e.slice(0,se-ne.length)+ne}class z extends K{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){a.warn("codex-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}function mt(d){return["cannot steer a compact turn","turn not found","turn already completed","no active turn"].some(t=>d.includes(t))}export{D as CodexAdapter,he as trimCodexPayloadForWire};