grix-connector 3.16.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/acp/acp-adapter.js +14 -14
- package/dist/adapter/claude/claude-adapter.js +20 -19
- package/dist/adapter/claude/protocol-contract.js +1 -1
- package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
- package/dist/adapter/codex/codex-bridge.js +10 -10
- package/dist/adapter/codex/session-activity.js +3 -1
- package/dist/adapter/cursor/cursor-adapter.js +5 -5
- package/dist/adapter/opencode/opencode-adapter.js +3 -3
- package/dist/adapter/openhuman/openhuman-adapter.js +3 -3
- package/dist/adapter/pi/pi-adapter.js +5 -5
- package/dist/audit/adapters/acp/acp-audit-adapter.js +1 -0
- package/dist/audit/adapters/acp/generic-acp-audit-adapter.js +2 -0
- package/dist/audit/adapters/acp/kimi-audit-adapter.js +2 -0
- package/dist/audit/adapters/acp/reasonix-audit-adapter.js +1 -0
- package/dist/audit/adapters/acp/reasonix-transcript-source.js +1 -0
- package/dist/audit/adapters/claude/claude-audit-adapter.js +1 -0
- package/dist/audit/adapters/claude/claude-otel-source.js +2 -0
- package/dist/audit/adapters/claude/claude-transcript-source.js +1 -0
- package/dist/audit/adapters/claude/claude-usage-merger.js +1 -0
- package/dist/audit/adapters/codewhale/codewhale-audit-adapter.js +1 -0
- package/dist/audit/adapters/codex/codex-audit-adapter.js +1 -0
- package/dist/audit/adapters/cursor/cursor-audit-adapter.js +1 -0
- package/dist/audit/adapters/opencode/opencode-audit-adapter.js +1 -0
- package/dist/audit/adapters/pi/pi-audit-adapter.js +1 -0
- package/dist/audit/adapters/pi/pi-transcript-source.js +1 -0
- package/dist/audit/core/audit-options.js +1 -0
- package/dist/audit/core/audit-session-registry.js +3 -0
- package/dist/audit/core/audit-state.js +1 -0
- package/dist/audit/core/audit-turn-lifecycle.js +1 -0
- package/dist/audit/core/content-reference.js +1 -0
- package/dist/audit/core/replay-finalizer.js +1 -0
- package/dist/audit/core/types.js +1 -0
- package/dist/audit/core/usage.js +1 -0
- package/dist/audit/integration/bridge-audit-controller.js +1 -0
- package/dist/audit/producer/audit-producer.js +1 -0
- package/dist/audit/producer/ipc-audit-producer.js +1 -0
- package/dist/audit/query/audit-local-actions.js +1 -0
- package/dist/audit/query/audit-replay-query-service.js +1 -0
- package/dist/audit/runtime/default-audit-recorder.js +1 -0
- package/dist/audit/storage/file-audit-replay-store.js +2 -0
- package/dist/audit/worker/audit-recorder-ipc-protocol.js +1 -0
- package/dist/audit/worker/audit-recorder-worker-entry.js +1 -0
- package/dist/audit/worker/audit-recorder-worker.js +1 -0
- package/dist/bridge/bridge.js +10 -10
- package/dist/core/aibot/client.js +2 -2
- package/dist/core/aibot/connection-handle.js +1 -1
- package/dist/core/aibot/types.js +1 -0
- package/dist/core/config/provider-env.js +1 -1
- package/dist/core/mcp/internal-api-server.js +1 -1
- package/dist/core/observability/sentry.js +1 -1
- package/dist/core/proxy/compat/kiro-cw/eventstream.js +1 -0
- package/dist/core/proxy/compat/kiro-cw/index.js +1 -0
- package/dist/core/proxy/compat/kiro-cw/request-builder.js +3 -0
- package/dist/core/proxy/compat/kiro-cw/server.js +7 -0
- package/dist/core/proxy/compat/kiro-cw/stream-converter.js +5 -0
- package/dist/core/proxy/index.js +1 -1
- package/dist/core/proxy/kiro-relay.js +2 -0
- package/dist/core/proxy/relay-credential.js +1 -1
- package/dist/grix.js +1 -1
- package/dist/manager.js +2 -2
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/service/platform-adapter.js +4 -1
- package/package.json +8 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{execFileSync as I}from"node:child_process";import{stat as
|
|
1
|
+
import{execFileSync as I}from"node:child_process";import{stat as A}from"node:fs/promises";import{resolveCommandPath as w,spawnCommand as C,killProcessGroup as y}from"../../core/runtime/spawn.js";import{createInterface as _}from"node:readline";import{EventEmitter as k}from"node:events";import{join as M,resolve as E}from"node:path";import{homedir as P}from"node:os";import{fileURLToPath as x}from"node:url";import{InternalApiServer as T}from"../../core/mcp/internal-api-server.js";import{IdentityInjector as $}from"../shared/identity-injector.js";import{syncDefaultSkillsToDir as N}from"../../default-skills/index.js";import{buildSimpleProbeReport as R}from"../shared/probe-util.js";import{getCachedCodeWhaleModels as B,primeCodeWhaleModels as D}from"./model-list.js";import{writeCodeWhaleGrixConfig as L}from"./codewhale-provider-config.js";import{log as o}from"../../core/log/index.js";import{SessionBindingStore as U}from"../../core/persistence/session-binding-store.js";const O=120*1e3,f=1800*1e3,j=5*1e3;function G(g){try{return process.kill(g,0),!0}catch(e){return e.code==="EPERM"}}class oe extends k{type="codewhale";config;callbacks;alive=!1;stopped=!1;internalApi=null;deepSeekSessionId=null;activeEventId=null;activeSessionId=null;chunkSeq=0;activeClientMsgId=null;idleTimer=null;lastProgressAt=0;activeProcess=null;identity;bindingStore=null;aibotSessionId="";cwd;provider;agentName="";grixConfigPath="";lastUsage=null;currentModel=null;toolNamesById=new Map;auditCaptures=new Map;completedAuditBoundaries=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t,this.identity=new $("codewhale-adapter",t.getAgentProfile);const i=e.options??{};if(this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof U?i.bindingStore:null,this.provider=i.provider,this.agentName=String(i.agentName??"").trim(),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const n=this.bindingStore.getCodeWhaleThreadId(this.aibotSessionId);n&&(this.deepSeekSessionId=n)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){this.alive=!0,await this.applyGrixProviderConfig(),await this.startInternalApiAndRegisterMcp(),D(this.config.command||"codewhale"),this.notifyBindingReady(),o.info("codewhale-adapter","Ready (exec mode)")}async applyGrixProviderConfig(){if(!this.provider){this.grixConfigPath="";return}try{this.grixConfigPath=await L(this.agentName,this.provider)??"",this.grixConfigPath?o.info("codewhale-adapter",`Grix provider config written to ${this.grixConfigPath}`):o.warn("codewhale-adapter","provider config incomplete (baseUrl/model required); Grix provider not applied")}catch(e){this.grixConfigPath="",o.warn("codewhale-adapter",`Failed to write Grix provider config: ${e instanceof Error?e.message:String(e)}`)}}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.killActiveProcess(),this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null)}isAlive(){return this.alive}async createSession(e){const t=this.deepSeekSessionId??`ds-${Date.now()}`;return this.notifyBindingReady(),t}async resumeSession(e,t){}onAgentProfileChanged(){this.identity.onProfileChanged()}async destroySession(e){this.identity.forgetSession(e),this.deepSeekSessionId=null,this.persistSessionId(void 0)}sendPrompt(e){const t=new b(e.adapterSessionId);return this.runMessage(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){this.killActiveProcess()}setPermissionHandler(e){}async ping(e){if(this.stopped||!this.alive)return!1;const t=this.activeProcess;return!(t?.pid&&!G(t.pid))}getStatus(){return{alive:this.alive,busy:this.activeEventId!==null,sessions:this.deepSeekSessionId?1:0}}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}clearActiveEventForShutdown(){this.clearIdleTimer(),this.killActiveProcess(),this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.activeEventId=null}takeAuditBoundary(e){const t=this.completedAuditBoundaries.get(e);return t&&this.completedAuditBoundaries.delete(e),t}getMcpConfig(){if(!this.internalApi)return null;const e=E(x(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:"grix-connector-tools",command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async probe(e){const t=this.getStatus();return R(this.config.command||"codewhale",{alive:t.alive,busy:t.busy,started:this.alive},e)}getUsageSnapshot(){return this.lastUsage}async startInternalApiAndRegisterMcp(){try{this.internalApi=new T,this.internalApi.setInvokeHandler(async(a,p,h,c)=>this.callbacks.agentInvoke(a,p,c)),await this.internalApi.start(0),o.info("codewhale-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t={...process.env,...this.config.env},i=typeof t.PATH=="string"?t.PATH:void 0,n=w(this.config.command||"codewhale",i);try{I(n,["mcp","remove",e.name],{env:t,timeout:1e4,stdio:"ignore"})}catch{}const s=["mcp","add",e.name,"--command",e.command];for(const a of e.args)s.push("--arg",a);I(n,s,{env:t,timeout:1e4,stdio:"ignore"}),o.info("codewhale-adapter",`Registered MCP server: ${e.name}`);const d=M(P(),".codewhale","skills"),r=N(d);r.length>0&&o.info("codewhale-adapter",`Synced connector skills to ${d}: [${r.join(", ")}]`)}catch(e){o.warn("codewhale-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}getSupportedCommands(){return[{name:"status",description:"Show session and working directory status"}]}async execCommand(e,t,i){return e==="status"?{status:"ok",message:`Session: ${this.deepSeekSessionId??"none"}, CWD: ${this.cwd}`,data:{sessionId:this.deepSeekSessionId,cwd:this.cwd,alive:this.alive}}:{status:"unsupported",message:`Unknown command: ${e}`}}async handleLocalAction(e){const t=e.action_type??"",i=e.params??{};switch(t){case"get_context":return this.callbacks.sendLocalActionResult(e.action_id,"ok",{sessionId:this.deepSeekSessionId,cwd:this.cwd,model:this.currentModel,model_id:this.currentModel,available_models:this.availableModelsMeta()}),{handled:!0,kind:"get_context"};case"set_model":{const n=String(i.model_id??"").trim();return n?(this.currentModel=n,this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"model_set",modelId:n,model_id:n,available_models:this.availableModelsMeta()}),o.info("codewhale-adapter",`Model set to: ${n}`),{handled:!0,kind:"set_model"}):(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","model_id is required"),{handled:!0,kind:"set_model"})}default:return{handled:!1,kind:""}}}availableModelsMeta(){return B(this.config.command||"codewhale").map(e=>({id:e.id,displayName:e.displayName}))}deliverInboundEvent(e){const t=e.content;if(this.activeEventId){o.info("codewhale-adapter",`Event ${e.event_id}: rejected, busy with ${this.activeEventId}`),this.callbacks.sendEventResult(e.event_id,"failed","agent busy");return}this.startNewMessage(e,t)}deliverStopEvent(e,t){this.activeEventId===e&&(this.killActiveProcess(),this.callbacks.sendEventResult(e,"canceled","stopped by user"),this.clearActive())}startNewMessage(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,this.chunkSeq=0,this.activeClientMsgId=`ds-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.beginAuditCapture(e),this.startComposing();const i={adapterSessionId:this.deepSeekSessionId??"",text:t,contextMessages:e.context_messages_json?JSON.parse(e.context_messages_json).map(s=>({senderId:s.sender_id??"unknown",content:s.content})):void 0},n=new b(this.deepSeekSessionId??"");this.runMessage(i,n,e.event_id,e.session_id).catch(s=>{o.error("codewhale-adapter",`Message failed: ${s}`),this.callbacks.sendEventResult(e.event_id,"failed",s instanceof Error?s.message:String(s)),this.clearActive()}),this.resetIdleTimer(e.event_id)}buildExecArgs(e){const t=[];if(this.grixConfigPath){t.push("--config",this.grixConfigPath);const n=this.provider?.baseUrl?.trim();n&&t.push("--base-url",n)}const i=[...this.config.args??[]];return t.push("exec"),i.includes("--output-format")||t.push("--output-format","stream-json"),t.push(...i),this.currentModel&&t.push("--model",this.currentModel),this.deepSeekSessionId&&t.push("--resume",this.deepSeekSessionId),t.push("--",e),t}async runMessage(e,t,i,n){let s=e.text;e.contextMessages&&e.contextMessages.length>0&&(s=`Conversation context:
|
|
2
2
|
${e.contextMessages.map(l=>`[${l.senderId??"unknown"}]: ${l.content}`).join(`
|
|
3
3
|
`)}
|
|
4
4
|
|
|
5
5
|
Latest user message:
|
|
6
|
-
${s}`),s=this.identity.injectOnce(
|
|
6
|
+
${s}`),s=this.identity.injectOnce(n??e.adapterSessionId,s);const d=this.config.command||"codewhale",r=this.buildExecArgs(s),a={...process.env,...this.config.env},p=w(d,typeof a.PATH=="string"?a.PATH:void 0);o.info("codewhale-adapter",`Spawning: ${p} ${r.slice(0,5).join(" ")}...`);try{if(!(await A(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(c){throw String(c?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):c}const h=C(p,r,{cwd:this.cwd,env:a}).process;return this.activeProcess=h,h.stderr?.on("data",c=>{const l=c.toString().trim();l&&o.info("codewhale-adapter",`[codewhale stderr] ${l}`)}),new Promise((c,l)=>{let m=!1,v="";const S=()=>{this.activeProcess=null};h.on("error",u=>{m||(m=!0,S(),l(u))}),h.on("exit",u=>{if(v.trim()&&this.handleOutputLine(v.trim(),i),v="",m){S();return}if(m=!0,S(),u!==0&&i&&this.activeEventId===i){l(new Error(`codewhale exec exited with code ${u}`));return}t.emitDone({status:"completed"}),c()}),_({input:h.stdout}).on("line",u=>{u.trim()&&this.handleOutputLine(u.trim(),i)}),h.stdin?.end()})}handleOutputLine(e,t){let i;try{i=JSON.parse(e)}catch{o.error("codewhale-adapter",`Invalid JSON: ${e.slice(0,200)}`);return}switch(t&&this.captureAuditEvent(t,e,i),i.type){case"content":{const s=i.content;s&&t&&this.activeEventId===t&&this.activeSessionId&&(this.chunkSeq++,this.callbacks.sendStreamChunk(t,this.activeSessionId,s,this.chunkSeq,!1,this.activeClientMsgId??void 0),this.startComposing(),this.resetIdleTimer(t));break}case"session_capture":{const s=i.content;s&&(this.deepSeekSessionId=s,this.persistSessionId(s),o.info("codewhale-adapter",`Session captured: ${s}`));break}case"metadata":{const s=i.meta;if(s){o.info("codewhale-adapter",`Metadata: model=${s.model}, tokens_in=${s.input_tokens}, tokens_out=${s.output_tokens}`);const d=Number(s.input_tokens??0),r=Number(s.output_tokens??0);if(d>0||r>0){const a=this.lastUsage;this.lastUsage={sampledAt:new Date().toISOString(),turns:(a?.turns??0)+1,total:{input:(a?.total.input??0)+d,output:(a?.total.output??0)+r}}}}break}case"tool_use":{const s=typeof i.name=="string"?i.name.trim():"",d=typeof i.id=="string"?i.id.trim():"",r=typeof i.input=="string"?i.input:JSON.stringify(i.input??{});s&&t&&this.activeEventId===t&&this.activeSessionId&&(d&&this.toolNamesById.set(d,s),o.info("codewhale-adapter",`Tool use: ${s}`),this.callbacks.sendToolUse(t,this.activeSessionId,s,r),this.resetIdleTimer(t));break}case"tool_result":{const s=typeof i.id=="string"?i.id.trim():"",r=(typeof i.name=="string"?i.name.trim():"")||(s?this.toolNamesById.get(s):void 0)||"tool";s&&this.toolNamesById.delete(s);const a=typeof i.output=="string"?i.output:"";t&&this.activeEventId===t&&this.activeSessionId&&(this.callbacks.sendToolResult(t,this.activeSessionId,r,a),this.resetIdleTimer(t));break}case"done":{this.handleMessageCompleted(t);break}default:break}}handleMessageCompleted(e){if(this.stopComposing(),e&&this.activeEventId===e){const t=this.activeSessionId??"",i=this.activeClientMsgId??void 0;t&&(this.chunkSeq++,this.callbacks.sendStreamChunk(e,t,"",this.chunkSeq,!0,i)),this.callbacks.sendEventResult(e,"responded"),this.clearActive()}}killActiveProcess(){const e=this.activeProcess;this.activeProcess=null,e?.pid&&(y(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{y(e,"SIGKILL")}catch{}},5e3).unref())}notifyBindingReady(){if(!this.aibotSessionId||!this.cwd)return;const e=this.availableModelsMeta(),t=this.currentModel??e[0]?.id??"";this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,{model_id:t,available_models:e})}persistSessionId(e){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodeWhaleThreadId(this.aibotSessionId,e)}startComposing(){}stopComposing(){}resetIdleTimer(e){this.lastProgressAt=Date.now(),this.armIdleTimer(e)}armIdleTimer(e){this.clearIdleTimer();const t=this.lastProgressAt+f-Date.now(),i=Math.max(0,Math.min(O,t));this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e)},i)}async onIdleTimeout(e){if(this.activeEventId!==e)return;if(Date.now()-this.lastProgressAt>=f){this.failIdleRun(e,`liveness budget exhausted after ${f/6e4}min`);return}let i=!1;try{i=await this.ping(j)}catch{i=!1}if(this.activeEventId===e){if(i){o.info("codewhale-adapter",`Idle timer: process alive, extending until liveness cap (${f/6e4}min): ${e}`),this.armIdleTimer(e);return}this.failIdleRun(e,"process not alive")}}failIdleRun(e,t){this.activeEventId===e&&(o.error("codewhale-adapter",`Idle timeout (${t}): ${e}`),this.killActiveProcess(),this.callbacks.sendEventResult(e,"failed",`idle timeout: ${t}`),this.clearActive(),this.emit("stuck"))}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}clearActive(){const e=this.activeEventId;e&&this.snapshotAuditBoundary(e),this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.chunkSeq=0,this.activeClientMsgId=null,this.toolNamesById.clear(),this.lastProgressAt=0,this.clearIdleTimer(),e&&this.emit("eventDone",e)}beginAuditCapture(e){!e.audit?.enabled||this.auditCaptures.has(e.event_id)||this.auditCaptures.set(e.event_id,{events:[]})}captureAuditEvent(e,t,i){const n=this.auditCaptures.get(e);n&&n.events.push({sequence:n.events.length,observedAt:new Date().toISOString(),rawLine:t,event:structuredClone(i)})}snapshotAuditBoundary(e){const t=this.auditCaptures.get(e);t&&(this.completedAuditBoundaries.set(e,{adapterType:"codewhale",providerSessionId:this.deepSeekSessionId??void 0,codeWhaleEvidence:{events:t.events}}),this.auditCaptures.delete(e))}}class b extends k{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){o.warn("codewhale-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}export{oe as CodeWhaleAdapter};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import{execFileSync as O}from"node:child_process";import{createInterface as G}from"node:readline";import{EventEmitter as L}from"node:events";import{stat as N}from"node:fs/promises";import{join as C,resolve as X}from"node:path";import{fileURLToPath as Y}from"node:url";import{homedir as K}from"node:os";import{syncDefaultSkillsToDir as Z}from"../../default-skills/index.js";import{resolveCommandPath as Q,spawnCommand as ee,killProcessGroup as D,hasChildProcesses as te}from"../../core/runtime/spawn.js";import{InternalApiServer as ie}from"../../core/mcp/internal-api-server.js";import{log as o}from"../../core/log/index.js";import{resolveClientVersion as se}from"../../core/util/client-version.js";import{isUserVisibleAgentMessagePhase as ne}from"../../core/util/codex-output-policy.js";import{SessionBindingStore as re}from"../../core/persistence/session-binding-store.js";import{ensureCodexProjectTrusted as oe,isCodexCommand as ae,readCodexProviderSettings as k}from"./codex-trust.js";import{checkCodexSessionActivity as de}from"./session-activity.js";import{findRolloutFile as ce}from"./rollout-locator.js";import{checkCodexLock as j}from"./lock-monitor.js";import{resolveCliPath as le,getCliVersion as he}from"../../core/util/cli-probe.js";import{scanSkills as ue}from"../claude/skill-scanner.js";const pe=60*1e3,fe=600*1e3,me=5*1e3,F=2,ge=20,ve=8e3,H=32*1024,q=80,xe=120*1e3,Ie=[{id:"gpt-5.3-codex",displayName:"GPT-5.3 Codex",defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!0}],U=[{id:"default",displayName:"Default"},{id:"plan",displayName:"Plan"}];function z(a,e){const t=String(a??"").trim()||"codex",s=Q(t,e);if(s!==t)return s;const i=process.platform==="win32"?[]:["/opt/homebrew/bin/codex","/usr/local/bin/codex","/usr/bin/codex"],n=process.platform!=="win32"?[]:[C(process.env.LOCALAPPDATA??"","npm","codex.cmd"),C(process.env.APPDATA??"","npm","codex.cmd"),C(process.env.LOCALAPPDATA??"","Programs","codex","codex.exe")],r=[...i,...n];for(const d of r)try{return require("node:fs").accessSync(d,require("node:fs").constants.X_OK),d}catch{continue}return o.warn("codex-adapter",`resolveCodexCommandPath: failed to resolve "${t}". envPath=${e?"provided":"missing (using process.env.PATH)"}. fallbacks tried: [${r.join(", ")}]`),t}class M extends L{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;idleNoProgressCount=0;inFlightToolOps=0;pendingApprovals=new Map;needsHistoryInjection=!1;lastInjectedSessionId=null;identityInjectedThreadId=null;bindingStore=null;aibotSessionId="";threadResumePending=!1;autoTrustProject="auto";codexHome;codexModelOptions=[];codexModelOptionsCachedAt=0;static MODEL_CACHE_TTL_MS=3600*1e3;rateLimitSnapshot=null;currentThreadTokenUsage=null;currentModelContextWindow=null;constructor(e,t){super(),this.config=e,this.callbacks=t;const s=e.options??{};if(this.approvalPolicy=s.approvalPolicy??"never",this.sandboxMode=typeof s.sandboxMode=="string"&&s.sandboxMode.trim()&&s.sandboxMode.trim()!=="default"?s.sandboxMode.trim():void 0,this.aibotSessionId=String(s.aibotSessionId??"").trim(),this.bindingStore=s.bindingStore instanceof re?s.bindingStore:null,this.model=s.model,this.collaborationMode=s.collaborationMode,this.reasoningEffort=s.reasoningEffort,this.serviceTier=s.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 s.autoTrustProject=="boolean"?s.autoTrustProject:"auto",this.codexHome=typeof s.codexHome=="string"&&s.codexHome.trim()?s.codexHome.trim():void 0,this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const i=this.bindingStore.getCodexThreadId(this.aibotSessionId);i&&(this.threadId=i,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.ensureProjectTrusted(),await this.startInternalApiAndRegisterMcp(),await this.spawnCodex(),await this.initializeHandshake(),await this.notifyBindingReadyWithContext(),o.info("codex-adapter",`Ready (pid=${this.process?.pid})`)}async ensureProjectTrusted(){if(this.shouldAutoTrustProject())try{const e=await oe(this.cwd,{codexHome:this.codexHome});e.changed&&o.info("codex-adapter",`Trusted Codex project ${this.cwd} in ${e.configPath}`)}catch(e){const t=e instanceof Error?e.message:String(e);throw o.error("codex-adapter",`Failed to trust Codex project ${this.cwd}: ${t}`),e}}async startInternalApiAndRegisterMcp(){try{this.internalApi=new ie,this.internalApi.setInvokeHandler(async(d,h,m,g)=>this.callbacks.agentInvoke(d,h,g)),await this.internalApi.start(0),o.info("codex-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t={...process.env,...this.config.env},s=typeof t.PATH=="string"?t.PATH:void 0,i=z(this.config.command||"codex",s);try{O(i,["mcp","remove",e.name],{env:t,timeout:1e4,stdio:"ignore"})}catch{}O(i,["mcp","add",e.name,"--",e.command,...e.args],{env:t,timeout:1e4,stdio:"ignore"}),o.info("codex-adapter",`Registered MCP server: ${e.name}`);const n=C(K(),".codex","skills"),r=Z(n);r.length>0&&o.info("codex-adapter",`Synced connector skills to ${n}: [${r.join(", ")}]`)}catch(e){o.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:ae(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){o.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<M.EXTERNAL_PROVIDER_CACHE_TTL_MS)return this.externalProviderCached;const t=k(this.codexHome);return this.externalProviderCached=!!(t.baseUrl&&W(t.baseUrl)),this.externalProviderCheckedAt=e,this.externalProviderCached}effectiveServiceTier(){if(!this.serviceTier||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),s={},i=t?.supportedReasoningEfforts??[];i.length>0&&(s.available_efforts=i,s.reasoning_effort=this.reasoningEffort??t?.defaultReasoningEffort??null);const n=t?.serviceTiers??[];return n.length>0&&(s.available_service_tiers=n,s.service_tier=this.effectiveServiceTier()??t?.defaultServiceTier??null),s}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.callbacks.sendEventResult(t.event_id,"failed","adapter stopped");for(const t of this.steerDeferred.splice(0))this.callbacks.sendEventResult(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")D(e,"SIGTERM"),await Promise.race([new Promise(s=>{e.once("exit",()=>s(!0))}),new Promise(s=>{setTimeout(()=>s(!1),5e3)})])||D(e,"SIGKILL");else if(e)try{e.kill("SIGTERM")}catch{}}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)}sendPrompt(e){const t=new R(e.adapterSessionId);return this.runTurn(e,t).catch(s=>{t.emitError(s instanceof Error?s:new Error(String(s)))}),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),s=!!(this.process.stdout&&!this.process.stdout.destroyed);return t&&s}if(!this.process.stdin||this.process.stdin.destroyed)return!!(this.process.stdout&&!this.process.stdout.destroyed);try{const t=++this.requestId,s={jsonrpc:"2.0",id:t,method:"ping",params:{}};return await new Promise(i=>{const n=setTimeout(()=>{this.pendingRequests.delete(String(t)),i(!1)},e);this.pendingRequests.set(String(t),{resolve:()=>i(!0),reject:()=>i(!1),timer:n}),this.process.stdin.write(`${JSON.stringify(s)}
|
|
2
|
-
`)})}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.activeEventId=null}setModel(e){this.model=e,this.persistCodexContext(),o.info("codex-adapter",`Model set to: ${e}`)}setMode(e){const t=
|
|
3
|
-
`):"No skills found",data:i}}default:return{status:"unsupported",message:`Unknown command: ${e}`}}}catch(i){return{status:"failed",message:i instanceof Error?i.message:String(i)}}}async handleLocalAction(e){const t=e.action_type??"",s=e.params??{};switch(o.info("codex-adapter",`handleLocalAction action_type=${t} action_id=${e.action_id} session_id=${s.session_id??""}`),t){case"set_model":{const i=x(l(s.model_id),l(s.modelId),l(s.value));return i&&this.setModel(i),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("model_set")),{handled:!0,kind:"set_model"}}case"set_mode":{const i=s.mode_id;return i&&this.setMode(i),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("mode_set")),{handled:!0,kind:"set_mode"}}case"set_reasoning_effort":{const i=x(l(s.reasoning_effort),l(s.reasoning_eff),l(s.effort));return i&&this.setReasoningEffort(i),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("effort_set",!1)),{handled:!0,kind:"set_reasoning_effort"}}case"set_service_tier":{const i=x(l(s.service_tier),l(s.serviceTier),l(s.value));return i&&this.setServiceTier(i),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 i=x(l(s.sandbox_mode),l(s.sandboxMode),l(s.value));return i&&this.setSandboxMode(i),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("sandbox_mode_set",!1)),{handled:!0,kind:"set_sandbox_mode"}}case"thread_compact":{o.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.callbacks.sendEventResult(this.activeEventId,"canceled","compacting"),this.clearActive());try{if(await this.ensureThreadResumed(),this.needsHistoryInjection)return o.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 i=new Promise(n=>{this.compactionDoneResolver=n});await this.threadCompact(),this.armCompactionFallback(),await i,o.info("codex-adapter",`thread_compact done action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(i){this.finishCompaction("compact-error");const n=i instanceof Error?i.message:String(i);/thread.*(not found|not exist|unknown|invalid)/i.test(n)||/not found.*thread/i.test(n)?(o.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.")):(o.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 i=this.resolvePendingApproval(e);if(!i)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=s.decision||"allow-once",r=be[n]??"accept";return this.sendApprovalDecision(i.requestId,r),this.pendingApprovals.delete(i.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:i.approvalId,approval_command_id:i.approvalCommandId,decision:n}),this.resumeAfterApproval(e,s,i),{handled:!0,kind:t}}case"exec_reject":case"file_reject":{const i=this.resolvePendingApproval(e);return i?(this.sendApprovalDecision(i.requestId,"deny"),this.pendingApprovals.delete(i.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:i.approvalId,approval_command_id:i.approvalCommandId,decision:"deny"}),this.resumeAfterApproval(e,s,i),{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 i=this.resolvePendingApproval(e);return!i||i.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(i.requestId,"accept"),this.pendingApprovals.delete(i.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:i.approvalId,decision:"approve"}),this.resumeAfterApproval(e,s,i),{handled:!0,kind:t})}case"permission_reject":{const i=this.resolvePendingApproval(e);return!i||i.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(i.requestId,"deny"),this.pendingApprovals.delete(i.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:i.approvalId,decision:"deny"}),this.resumeAfterApproval(e,s,i),{handled:!0,kind:t})}case"turn_interrupt":{try{await this.cancel(this.threadId??""),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(i){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,i instanceof Error?i.message:String(i))}return{handled:!0,kind:"turn_interrupt"}}case"thread_rollback":{const i=Number(s.numTurns??s.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.callbacks.sendEventResult(this.activeEventId,"canceled","rolled back"),this.clearActive());try{await this.threadRollback(i),this.callbacks.sendLocalActionResult(e.action_id,"ok",{numTurns:i})}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 i=this.rateLimitSnapshot,n=this.buildContextWindowSnapshot(),r=Date.now(),d=this.currentThreadTokenUsage;return i?o.info("codex-adapter",`[rate-limits] responding: primary=${i.primary.usedPercent.toFixed(1)}% window=${i.primary.windowMinutes}min resetsAt=${i.primary.resetsAt} secondary=${i.secondary.usedPercent.toFixed(1)}% window=${i.secondary.windowMinutes}min resetsAt=${i.secondary.resetsAt}`):o.info("codex-adapter","[rate-limits] responding: no rateLimitSnapshot available"),o.debug("codex-adapter",`[cp-diagnose] get_rate_limits: threadId=${this.threadId??"-"} contextWindow=${JSON.stringify(n)} tokenUsage=${JSON.stringify(d)}`),this.callbacks.sendLocalActionResult(e.action_id,"ok",{adapterType:"codex",available:i!==null,cached:!1,sampledAt:r,rateLimits:i,contextWindow:n,tokenUsage:d}),{handled:!0,kind:"get_rate_limits"}}default:return{handled:!1,kind:""}}}async buildToolbarContextResult(e,t=!0){t&&await this.refreshCodexModelOptions();const s=_(this.collaborationMode)??"default",i=this.currentModelId(),n=this.getModelOption(i),r=this.getModelOptions(),d=U,h=this.reasoningEffort??n?.defaultReasoningEffort??null,m=n?.supportedReasoningEfforts??[],g=this.effectiveServiceTier()??n?.defaultServiceTier??null,p=n?.serviceTiers??[],u=this.isExternalProvider(),v=u?[]:m,I=u?null:h,y=u?[]:p,w=u?null:g,c={outcome:e,session_context:{modelId:i,modeId:s,reasoningEffort:I,serviceTier:w,approvalPolicy:this.approvalPolicy,sandboxMode:this.sandboxMode??null},model_id:i,mode_id:s,currentModelId:i,currentModeId:s,available_models:r,available_modes:d,available_efforts:v,availableModels:r,availableModes:d,reasoning_effort:I,available_service_tiers:y,service_tier:w,sandbox_mode:this.sandboxMode??null,models:r.map(f=>({modelId:f.id,name:f.displayName})),modes:d.map(f=>({id:f.id,name:f.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(s=>s.isDefault)?.id??t[0]?.id??""}getModelOption(e){const t=e.trim().toLowerCase();return this.getModelOptions().find(s=>s.id.trim().toLowerCase()===t)}getModelOptions(){const e=this.config.options??{},t=e.available_models??e.availableModels??e.models,s=Se(t),i=this.codexModelOptions,n=[],r=String(this.model??"").trim(),d=r&&!i.some(p=>p.id.trim().toLowerCase()===r.toLowerCase()),h=i.length>0?i:d?[]:Ie;if(r){const p=[...i,...s].find(u=>u.id.trim().toLowerCase()===r.toLowerCase());n.push({id:r,displayName:p?.displayName??T(r),defaultReasoningEffort:p?.defaultReasoningEffort??null,supportedReasoningEfforts:p?.supportedReasoningEfforts??[],defaultServiceTier:p?.defaultServiceTier??null,serviceTiers:p?.serviceTiers??[],isDefault:p?.isDefault??!1})}n.push(...s),n.push(...h);const m=[],g=new Set;for(const p of n){const u=p.id.trim(),v=u.toLowerCase();!u||g.has(v)||(g.add(v),m.push({id:u,displayName:p.displayName.trim()||u,defaultReasoningEffort:p.defaultReasoningEffort,supportedReasoningEfforts:[...p.supportedReasoningEfforts],defaultServiceTier:p.defaultServiceTier,serviceTiers:[...p.serviceTiers],isDefault:p.isDefault}))}return m}async refreshCodexModelOptions(){if(!this.initialized||!this.alive||!this.process?.stdin||Date.now()-this.codexModelOptionsCachedAt<M.MODEL_CACHE_TTL_MS)return;const e=k(this.codexHome);if(e.baseUrl&&W(e.baseUrl)){try{const t=await Ce(e.baseUrl,e.apiKey);if(t.length>0){this.codexModelOptions=B(t),this.codexModelOptionsCachedAt=Date.now(),o.info("codex-adapter",`Loaded ${t.length} models from external provider ${e.baseUrl}`);return}}catch(t){o.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 s;do{const i=await this.sendRequest("model/list",{cursor:s??null,includeHidden:!1,limit:100},15e3),n=Ee(i);t.push(...n.models),s=n.nextCursor}while(s);t.length>0&&(this.codexModelOptions=B(t),this.codexModelOptionsCachedAt=Date.now())}catch(t){o.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;codexSequence=0;turnError=null;turnErrorIsRetryableOnly=!0;turnHasVisibleOutput=!1;deliverInboundEvent(e){if(this.compacting){o.info("codex-adapter",`Event ${e.event_id} deferred: compaction in progress`),this.compactionDeferred.push(e);return}const t=e.content;if(this.currentTurnId&&t.trim()){o.info("codex-adapter",`Event ${e.event_id}: steering active turn ${this.currentTurnId}`),this.steerTurn(t).catch(s=>{const i=s instanceof Error?s.message:String(s);if(o.info("codex-adapter",`Steer failed, falling through: ${i}`),!this.currentTurnId){this.startNewTurn(e,t);return}if(Re(i)){o.info("codex-adapter","Unsteerable turn detected, clearing active state and starting new turn"),this.clearActive(),this.startNewTurn(e,t);return}o.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){o.info("codex-adapter",`Event ${e.event_id} rejected: busy and empty content`),this.callbacks.sendEventResult(e.event_id,"failed","agent busy");return}this.startNewTurn(e,t)}startNewTurn(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.codexSequence=0,this.startComposing();const s=this.threadId??"",i=new R(s),n={adapterSessionId:s,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,i,e.event_id,e.session_id).catch(r=>{o.error("codex-adapter",`Turn failed: ${r}`),this.callbacks.sendEventResult(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.callbacks.sendEventResult(e,"canceled","stopped by user"),this.clearActive())}async spawnCodex(){const e={...process.env,...this.config.env},t=typeof e.PATH=="string"?e.PATH:void 0;t||o.warn("codex-adapter",`spawnCodex: env.PATH is missing! process.env.PATH=${process.env.PATH?"set":"missing"}, config.env=${JSON.stringify(this.config.env)}`);const s=z(this.config.command||"codex",t),i=we(this.config.args);this.sandboxMode&&i.push("-c",`sandbox_mode="${this.sandboxMode}"`),o.info("codex-adapter",`Spawning: ${s} ${i.join(" ")}`);try{if(!(await N(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(r){throw String(r?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):r}const n=j({codexHome:this.codexHome});if(n.locked&&!n.stale)throw new Error(`Codex session appears locked by another process: ${n.path}`);n.stale&&o.warn("codex-adapter",`Ignoring stale Codex lock: ${n.path}`);try{this.process=ee(s,i,{env:e,cwd:this.cwd}).process}catch(r){throw o.error("codex-adapter",`Codex spawn threw: ${r}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",r}this.process.on("error",r=>{o.error("codex-adapter",`Codex process spawn error: ${r}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("spawn failed: "+(r instanceof Error?r.message:String(r))),this.stopComposing(),this.activeEventId&&(this.callbacks.sendEventResult(this.activeEventId,"failed","Codex process spawn failed"),this.activeEventId=null),this.emit("exit",1)}),this.process.on("exit",r=>{o.info("codex-adapter",`Codex process exited (code=${r})`),this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("process exited"),this.stopComposing(),this.emit("exit",r)}),this.process.stderr?.on("data",r=>{const d=r.toString().trim();d&&o.info("codex-adapter",`[codex stderr] ${d}`)}),this.bindStdout(),this.alive=!0}bindStdout(){if(!this.process?.stdout)return;this.process.stdout.setEncoding("utf8"),G({input:this.process.stdout}).on("line",t=>{if(!t.trim())return;let s;try{s=JSON.parse(t)}catch{o.error("codex-adapter",`Invalid JSON from Codex: ${t.slice(0,200)}`);return}if(this.bridgeStatus==="starting"&&(this.bridgeStatus="ready"),s.id!=null){const i=String(s.id),n=this.pendingRequests.get(i);if(n){clearTimeout(n.timer),this.pendingRequests.delete(i),n.resolve(s);return}}this.handleNotification(s)})}handleNotification(e){const t=e.method,s=e.params??{};switch(this.captureContextWindowFromPayload(t,s),this.activeEventId&&this.resetIdleTimer(this.activeEventId),this.activeEventId&&t&&t.startsWith("item/")&&!t.endsWith("/requestApproval")&&this.startComposing(),t){case"item/started":{const i=s.item,n=i?.id,r=i?.type,d=i?.phase;this.isLongRunningToolItemType(r)&&(this.inFlightToolOps+=1),r==="agentMessage"&&n&&(typeof d=="string"&&d.trim()?this.agentMessagePhases.set(n,d.trim().toLowerCase()):this.agentMessagePhases.delete(n),ne(d)?(this.visibleAgentMessageIds.add(n),this.hiddenAgentMessageIds.delete(n)):(this.hiddenAgentMessageIds.add(n),this.visibleAgentMessageIds.delete(n)));break}case"item/agentMessage/delta":{const i=s.delta,n=s.itemId;i&&this.activeEventId&&(!n||!this.hiddenAgentMessageIds.has(n))&&!this.shouldSuppressAgentMessageDeltaDuringToolRun(n)&&(this.turnHasVisibleOutput=!0,this.emitCodexEvent("item/agentMessage/delta",e));break}case"item/completed":{const i=s.item,n=i?.id,r=i?.type;this.isLongRunningToolItemType(r)&&(this.inFlightToolOps=Math.max(0,this.inFlightToolOps-1)),this.activeEventId&&r!=="agentMessage"&&(this.turnHasVisibleOutput=!0,this.emitCodexEvent("item/completed",e)),r==="agentMessage"&&n&&(this.visibleAgentMessageIds.delete(n),this.hiddenAgentMessageIds.delete(n),this.agentMessagePhases.delete(n));break}case"turn/started":{const n=s.turn?.id;n&&(this.currentTurnId=n,this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,o.info("codex-adapter",`Turn started: ${n}`),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.activeEventId&&this.emitCodexEvent("item/permissions/requestApproval",e),this.handleApprovalRequest(e,"permission");break}case"turn/completed":{this.handleTurnCompleted(s);break}case"error":{const i=s.message??JSON.stringify(s);o.error("codex-adapter",`Codex error: ${i}`);const n=s.willRetry===!0;i&&(this.turnError=i,n||(this.turnErrorIsRetryableOnly=!1)),this.activeEventId&&!n&&this.callbacks.sendRunError(this.activeEventId,this.activeSessionId??"",i);break}case"account/rateLimits/updated":{this.rateLimitSnapshot=this.parseRateLimitSnapshot(s),this.rateLimitSnapshot&&(o.info("codex-adapter",`Rate limits updated: primary=${this.rateLimitSnapshot.primary.usedPercent.toFixed(1)}% secondary=${this.rateLimitSnapshot.secondary.usedPercent.toFixed(1)}%`),this.callbacks.onRateLimitsUpdated?.(this.rateLimitSnapshot));break}case"thread/tokenUsage/updated":{const i=s.threadId,n=s.tokenUsage,r=n?.last;(!i||!n||!r)&&o.info("codex-adapter",`[cp-diagnose] token_usage payload_incomplete: method=thread/tokenUsage/updated hasThreadId=${String(!!i)} hasTokenUsage=${String(!!n)} hasLast=${String(!!r)} params=${JSON.stringify(s)}`),i&&n&&r&&(this.currentThreadTokenUsage={inputTokens:r.inputTokens??0,outputTokens:r.outputTokens??0,cacheReadInputTokens:r.cachedInputTokens??0,cacheCreationInputTokens:0},o.info("codex-adapter",`[cp-diagnose] token_usage raw thread=${i}: ${JSON.stringify(n)}`),o.info("codex-adapter",`[cp-diagnose] token_usage parsed thread=${i}: ${JSON.stringify(this.currentThreadTokenUsage)}`),this.callbacks.onTokenUsageUpdated?.(this.currentThreadTokenUsage),this.publishContextWindowSnapshot());break}default:break}}captureContextWindowFromPayload(e,t){const s=["model_context_window","modelContextWindow","context_window_size","contextWindowSize"],i=this.findNumericField(t,s);if(i==null||i<=0){const n=this.probeContextWindowFields(t,s);n.foundAnyCandidateField&&o.info("codex-adapter",`[cp-diagnose] context_window missing_or_invalid: method=${e??"-"} matchedFields=${n.matchedFields.join(",")||"-"} raw=${n.rawValues.join(",")||"-"} extracted=${String(i)}`);return}this.currentModelContextWindow!==i&&(this.currentModelContextWindow=i,o.info("codex-adapter",`[cp-diagnose] context_window updated: method=${e??"-"} size=${i}`),this.publishContextWindowSnapshot())}probeContextWindowFields(e,t){const s=[],i=[],n=r=>{if(!r||typeof r!="object")return;if(Array.isArray(r)){for(const h of r)n(h);return}const d=r;for(const h of t)Object.prototype.hasOwnProperty.call(d,h)&&(s.push(h),i.push(String(d[h])));for(const h of Object.values(d))n(h)};return n(e),{foundAnyCandidateField:s.length>0,matchedFields:s,rawValues:i}}findNumericField(e,t){if(!e||typeof e!="object")return null;const s=e;for(const i of t){const n=s[i];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 i of Object.values(s)){if(Array.isArray(i)){for(const r of i){const d=this.findNumericField(r,t);if(d!=null)return d}continue}const n=this.findNumericField(i,t);if(n!=null)return n}return null}buildContextWindowSnapshot(){const e=this.currentModelContextWindow;if(!e||e<=0)return o.debug("codex-adapter",`[cp-diagnose] context_window snapshot skipped: invalid size=${String(e)}`),null;const t=this.currentThreadTokenUsage,s=t?t.inputTokens+t.outputTokens:null,i=s==null?null:Math.max(0,e-s),n=s==null?null:Math.min(100,s/e*100),r=s==null?null:Math.max(0,100-(n??0));return o.info("codex-adapter",`[cp-diagnose] context_window computed: threadId=${this.threadId??"-"} size=${e} usedTokens=${String(s)} usedPercentage=${String(n)}`),{sizeTokens:e,usedTokens:s,remainingTokens:i,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<q||this.pendingAutoCompact||this.compacting||(this.pendingAutoCompact=!0,o.info("codex-adapter",`[auto-compact] context_window usedPercentage=${t.toFixed(1)}% >= ${q}%, 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=>{o.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=>{o.warn("codex-adapter",`[auto-compact] compact error: ${e instanceof Error?e.message:e}`)})))}parseRateLimitSnapshot(e){try{const s=e.rateLimitsByLimitId?.codex??e.rateLimits??e,i=s.primary,n=s.secondary,r=s.credits,d=c=>{if(typeof c=="number"&&Number.isFinite(c))return c;if(typeof c=="string"){const f=Number(c);if(Number.isFinite(f))return f}return 0},h=c=>typeof c=="boolean"?c:typeof c=="string"?c.toLowerCase()==="true":!1,m=c=>{if(c==null)return null;if(typeof c=="string"){const f=c.trim();if(!f)return null;const b=Number(f);return Number.isFinite(b)&&b>1e9?new Date(b*1e3).toISOString():f}if(typeof c=="number"&&Number.isFinite(c)&&c>0){const f=c>1e12?c/1e3:c;return new Date(f*1e3).toISOString()}return null},g=c=>{const f=c.resets_in_seconds??c.resetsInSeconds,b=typeof f=="number"||typeof f=="string"?Number(f):NaN;return!Number.isFinite(b)||b<=0?null:new Date(Date.now()+b*1e3).toISOString()},p=c=>({usedPercent:d(c.used_percent??c.usedPercent),windowMinutes:d(c.window_minutes??c.windowDurationMins??c.windowMinutes),resetsAt:m(c.resets_at??c.resetsAt)??g(c)}),u=()=>({usedPercent:0,windowMinutes:0,resetsAt:null}),v=()=>{const c=[];if(i&&c.push(i),n&&c.push(n),Array.isArray(s.windows))for(const f of s.windows)f&&typeof f=="object"&&c.push(f);return c.map(p).filter(f=>f.windowMinutes>0)},I=(c,f,b)=>{const P=c.filter(S=>b(S.windowMinutes));return P.length===0?null:P.reduce((S,$)=>Math.abs($.windowMinutes-f)<Math.abs(S.windowMinutes-f)?$:S)},y=v(),w=y.length>0?{primary:I(y,300,c=>c<1440)??u(),secondary:I(y,10080,c=>c>=1440)??u()}:i||n?{primary:i?p(i):u(),secondary:n?p(n):u()}:null;return w?{primary:w.primary,secondary:w.secondary,credits:r?{hasCredits:h(r.has_credits??r.hasCredits),unlimited:h(r.unlimited),balance:r.balance==null?null:d(r.balance)}:{hasCredits:!1,unlimited:!1,balance:null}}:null}catch{return null}}handleApprovalRequest(e,t){const s=e.id;if(s==null)return;const i=e.method,n=`${s}`.trim(),r=`codex_${J(this.activeSessionId??"")}_${J(n)}`;if(this.approvalPolicy==="never"){this.sendApprovalDecision(s,"accept");return}this.activeEventId&&this.emitCodexEvent(i,e),this.pendingApprovals.set(r,{approvalId:r,approvalCommandId:n,sourceEventId:this.activeEventId??"",requestId:s,kind:t}),o.info("codex-adapter",`Pending approval stored: ${r} (kind=${t})`),this.clearIdleTimer(),this.stopComposing()}resolvePendingApproval(e){const t=e.params??{},s=x(t.approval_id,t.approvalId);if(s)return this.pendingApprovals.get(s)??null;const i=x(t.approval_command_id,t.approvalCommandId);if(i){for(const[,n]of this.pendingApprovals)if(n.approvalCommandId===i)return n}return null}sendApprovalDecision(e,t){if(e==null||!this.process?.stdin)return;const s={jsonrpc:"2.0",id:e,result:{decision:t}};this.process.stdin.write(`${JSON.stringify(s)}
|
|
4
|
-
`)}armCompactionFallback(){this.compacting&&(this.compactingTimer&&clearTimeout(this.compactingTimer),this.compactingTimer=setTimeout(()=>{o.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")},
|
|
5
|
-
`)})}sendNotification(e,t){if(!this.process?.stdin)return;const
|
|
6
|
-
`)}async initializeHandshake(){if(this.initialized)return;const e=
|
|
7
|
-
`),text_elements:[]}),this.identityInjectedThreadId=this.threadId,o.info("codex-adapter",`Injected agent identity for thread=${this.threadId} name="${
|
|
1
|
+
import{execFileSync as N}from"node:child_process";import{createInterface as Y}from"node:readline";import{EventEmitter as L}from"node:events";import{stat as F}from"node:fs/promises";import{join as S,resolve as Q}from"node:path";import{fileURLToPath as K}from"node:url";import{homedir as Z}from"node:os";import{syncDefaultSkillsToDir as ee}from"../../default-skills/index.js";import{resolveCommandPath as te,spawnCommand as ie,killProcessGroup as j,hasChildProcesses as se}from"../../core/runtime/spawn.js";import{InternalApiServer as ne}from"../../core/mcp/internal-api-server.js";import{log as o}from"../../core/log/index.js";import{resolveClientVersion as re}from"../../core/util/client-version.js";import{isUserVisibleAgentMessagePhase as A}from"../../core/util/codex-output-policy.js";import{SessionBindingStore as oe}from"../../core/persistence/session-binding-store.js";import{ensureCodexProjectTrusted as ae,isCodexCommand as de,readCodexProviderSettings as E}from"./codex-trust.js";import{checkCodexSessionActivity as ce,inspectCodexTurnProgress as le}from"./session-activity.js";import{findRolloutFile as ue}from"./rollout-locator.js";import{checkCodexLock as H}from"./lock-monitor.js";import{resolveCliPath as he,getCliVersion as pe}from"../../core/util/cli-probe.js";import{scanSkills as fe}from"../claude/skill-scanner.js";const me=60*1e3,ge=600*1e3,ve=5*1e3,Ie=5*1e3;function xe(d,e){const t=Number(process.env[d]);return Number.isFinite(t)&&t>0?t:e}function be(d){const e=Number(process.env[d]);return Number.isFinite(e)&&e>0?e:null}const k=xe("GRIX_CODEX_PREFLIGHT_STALL_TIMEOUT_MS",120*1e3),ye=20,we=8e3,q=32*1024,U=80,Te=120*1e3,_e=[{id:"gpt-5.3-codex",displayName:"GPT-5.3 Codex",defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!0}],z=[{id:"default",displayName:"Default"},{id:"plan",displayName:"Plan"}],Ce=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 G(d,e){const t=String(d??"").trim()||"codex",i=te(t,e);if(i!==t)return i;const s=process.platform==="win32"?[]:["/opt/homebrew/bin/codex","/usr/local/bin/codex","/usr/bin/codex"],n=process.platform!=="win32"?[]:[S(process.env.LOCALAPPDATA??"","npm","codex.cmd"),S(process.env.APPDATA??"","npm","codex.cmd"),S(process.env.LOCALAPPDATA??"","Programs","codex","codex.exe")],r=[...s,...n];for(const a of r)try{return require("node:fs").accessSync(a,require("node:fs").constants.X_OK),a}catch{continue}return o.warn("codex-adapter",`resolveCodexCommandPath: failed to resolve "${t}". envPath=${e?"provided":"missing (using process.env.PATH)"}. fallbacks tried: [${r.join(", ")}]`),t}class $ extends L{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=be("GRIX_CODEX_TURN_INACTIVITY_TIMEOUT_MS");pendingApprovals=new Map;needsHistoryInjection=!1;lastInjectedSessionId=null;identityInjectedThreadId=null;bindingStore=null;aibotSessionId="";threadResumePending=!1;autoTrustProject="auto";codexHome;codexModelOptions=[];codexModelOptionsCachedAt=0;static MODEL_CACHE_TTL_MS=3600*1e3;rateLimitSnapshot=null;currentThreadTokenUsage=null;currentModelContextWindow=null;auditCaptureByEventId=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const i=e.options??{};if(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 oe?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,this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const s=this.bindingStore.getCodexThreadId(this.aibotSessionId);s&&(this.threadId=s,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.ensureProjectTrusted(),await this.startInternalApiAndRegisterMcp(),await this.spawnCodex(),await this.initializeHandshake(),await this.notifyBindingReadyWithContext(),o.info("codex-adapter",`Ready (pid=${this.process?.pid})`)}async ensureProjectTrusted(){if(this.shouldAutoTrustProject())try{const e=await ae(this.cwd,{codexHome:this.codexHome});e.changed&&o.info("codex-adapter",`Trusted Codex project ${this.cwd} in ${e.configPath}`)}catch(e){const t=e instanceof Error?e.message:String(e);throw o.error("codex-adapter",`Failed to trust Codex project ${this.cwd}: ${t}`),e}}async startInternalApiAndRegisterMcp(){try{this.internalApi=new ne,this.internalApi.setInvokeHandler(async(a,c,f,m)=>this.callbacks.agentInvoke(a,c,m)),await this.internalApi.start(0),o.info("codex-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t={...process.env,...this.config.env},i=typeof t.PATH=="string"?t.PATH:void 0,s=G(this.config.command||"codex",i);try{N(s,["mcp","remove",e.name],{env:t,timeout:1e4,stdio:"ignore"})}catch{}N(s,["mcp","add",e.name,"--",e.command,...e.args],{env:t,timeout:1e4,stdio:"ignore"}),o.info("codex-adapter",`Registered MCP server: ${e.name}`);const n=S(Z(),".codex","skills"),r=ee(n);r.length>0&&o.info("codex-adapter",`Synced connector skills to ${n}: [${r.join(", ")}]`)}catch(e){o.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:de(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){o.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<$.EXTERNAL_PROVIDER_CACHE_TTL_MS)return this.externalProviderCached;const t=E(this.codexHome);return this.externalProviderCached=!!(t.baseUrl&&W(t.baseUrl)),this.externalProviderCheckedAt=e,this.externalProviderCached}effectiveServiceTier(){if(!this.serviceTier||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.callbacks.sendEventResult(t.event_id,"failed","adapter stopped");for(const t of this.steerDeferred.splice(0))this.callbacks.sendEventResult(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")j(e,"SIGTERM"),await Promise.race([new Promise(i=>{e.once("exit",()=>i(!0))}),new Promise(i=>{setTimeout(()=>i(!1),5e3)})])||j(e,"SIGKILL");else if(e)try{e.kill("SIGTERM")}catch{}}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)}sendPrompt(e){const t=new P(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)}
|
|
2
|
+
`)})}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.activeEventId=null}setModel(e){this.model=e,this.persistCodexContext(),o.info("codex-adapter",`Model set to: ${e}`)}setMode(e){const t=T(e);if(!t){o.info("codex-adapter",`Ignoring unsupported mode: ${e}`);return}this.collaborationMode=t,this.persistCodexContext(),o.info("codex-adapter",`Mode set to: ${t}`)}setReasoningEffort(e){this.reasoningEffort=e,this.persistCodexContext(),o.info("codex-adapter",`Reasoning effort set to: ${e}`)}setServiceTier(e){const t=e.trim();this.serviceTier=t.toLowerCase()==="default"?void 0:t,this.persistCodexContext(),o.info("codex-adapter",`Service tier set to: ${this.serviceTier??"default"}`)}setSandboxMode(e){this.sandboxMode=e,this.persistCodexContext(),o.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}enableAuditCapture(e){const t=e.trim();!t||this.auditCaptureByEventId.has(t)||this.auditCaptureByEventId.set(t,{threadId:this.threadId??void 0,modelId:this.currentModelId()??void 0,sequence:0,events:[]})}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}:{}}}}getMcpConfig(){if(!this.internalApi)return null;const e=Q(K(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:"grix-connector-tools",command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async hasBackgroundWork(){const e=this.process?.pid;return e?se(e,[e]):!1}onAgentProfileChanged(){this.identityInjectedThreadId!==null&&(o.info("codex-adapter",`agent profile changed; clearing identity-injected thread record (was ${this.identityInjectedThreadId})`),this.identityInjectedThreadId=null)}async probe(e){const t=this.config.command||"codex",i=await he(t),s=i!==null;let n=null,r;if(s){const x=await pe(t);n=x.version,x.error&&(r=x.error)}else r={code:"cli_not_found",message:`command not found: ${t}`};const c=E().baseUrl??null,f=this.currentModelId()||null,m=this.getStatus(),p=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},h=await this.probeSessionRecord(),I=H({codexHome:this.codexHome});return{cli:{command:t,installed:s,path:i,version:n,...r?{error:r}:{}},conversation:p,config:{model:f,base_url:c,source:{model:f?"runtime":"unknown",base_url:c?"file":"unknown"}},process:{started:!!this.process,alive:m.alive,busy:m.busy},session:h,lock:{present:I.present,locked:I.locked,stale:I.stale,path:I.path}}}async probeSessionRecord(){const e=this.threadId?ue(this.threadId,this.codexHome):null;if(!e)return{recordPath:null,lastActivityMs:null,freshMs:null};try{const t=await F(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.callbacks.sendEventResult(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=T(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:z}}}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.callbacks.sendEventResult(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.callbacks.sendEventResult(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=fe({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(`
|
|
3
|
+
`):"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(o.info("codex-adapter",`handleLocalAction action_type=${t} action_id=${e.action_id} session_id=${i.session_id??""}`),t){case"set_model":{const s=v(l(i.model_id),l(i.modelId),l(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=v(l(i.reasoning_effort),l(i.reasoning_eff),l(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=v(l(i.service_tier),l(i.serviceTier),l(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=v(l(i.sandbox_mode),l(i.sandboxMode),l(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":{o.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.callbacks.sendEventResult(this.activeEventId,"canceled","compacting"),this.clearActive());try{if(await this.ensureThreadResumed(),this.needsHistoryInjection)return o.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,o.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)?(o.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.")):(o.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=Se[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.callbacks.sendEventResult(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(),a=this.currentThreadTokenUsage;return s?o.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}`):o.info("codex-adapter","[rate-limits] responding: no rateLimitSnapshot available"),o.debug("codex-adapter",`[cp-diagnose] get_rate_limits: threadId=${this.threadId??"-"} contextWindow=${JSON.stringify(n)} tokenUsage=${JSON.stringify(a)}`),this.callbacks.sendLocalActionResult(e.action_id,"ok",{adapterType:"codex",available:s!==null,cached:!1,sampledAt:r,rateLimits:s,contextWindow:n,tokenUsage:a}),{handled:!0,kind:"get_rate_limits"}}default:return{handled:!1,kind:""}}}async buildToolbarContextResult(e,t=!0){t&&await this.refreshCodexModelOptions();const i=T(this.collaborationMode)??"default",s=this.currentModelId(),n=this.getModelOption(s),r=this.getModelOptions(),a=z,c=this.reasoningEffort??n?.defaultReasoningEffort??null,f=n?.supportedReasoningEfforts??[],m=this.effectiveServiceTier()??n?.defaultServiceTier??null,p=n?.serviceTiers??[],h=this.isExternalProvider(),I=h?[]:f,x=h?null:c,w=h?[]:p,y=h?null:m,u={outcome:e,session_context:{modelId:s,modeId:i,reasoningEffort:x,serviceTier:y,approvalPolicy:this.approvalPolicy,sandboxMode:this.sandboxMode??null},model_id:s,mode_id:i,currentModelId:s,currentModeId:i,available_models:r,available_modes:a,available_efforts:I,availableModels:r,availableModes:a,reasoning_effort:x,available_service_tiers:w,service_tier:y,sandbox_mode:this.sandboxMode??null,models:r.map(g=>({modelId:g.id,name:g.displayName})),modes:a.map(g=>({id:g.id,name:g.displayName}))};return this.rateLimitSnapshot&&(u.rate_limit_primary_percent=this.rateLimitSnapshot.primary.usedPercent,u.rate_limit_secondary_percent=this.rateLimitSnapshot.secondary.usedPercent,u.rate_limit_primary_window_min=this.rateLimitSnapshot.primary.windowMinutes,u.rate_limit_secondary_window_min=this.rateLimitSnapshot.secondary.windowMinutes),u}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=Re(t),s=this.codexModelOptions,n=[],r=String(this.model??"").trim(),a=r&&!s.some(p=>p.id.trim().toLowerCase()===r.toLowerCase()),c=s.length>0?s:a?[]:_e;if(r){const p=[...s,...i].find(h=>h.id.trim().toLowerCase()===r.toLowerCase());n.push({id:r,displayName:p?.displayName??_(r),defaultReasoningEffort:p?.defaultReasoningEffort??null,supportedReasoningEfforts:p?.supportedReasoningEfforts??[],defaultServiceTier:p?.defaultServiceTier??null,serviceTiers:p?.serviceTiers??[],isDefault:p?.isDefault??!1})}n.push(...i),n.push(...c);const f=[],m=new Set;for(const p of n){const h=p.id.trim(),I=h.toLowerCase();!h||m.has(I)||(m.add(I),f.push({id:h,displayName:p.displayName.trim()||h,defaultReasoningEffort:p.defaultReasoningEffort,supportedReasoningEfforts:[...p.supportedReasoningEfforts],defaultServiceTier:p.defaultServiceTier,serviceTiers:[...p.serviceTiers],isDefault:p.isDefault}))}return f}async refreshCodexModelOptions(){if(!this.initialized||!this.alive||!this.process?.stdin||Date.now()-this.codexModelOptionsCachedAt<$.MODEL_CACHE_TTL_MS)return;const e=E(this.codexHome);if(e.baseUrl&&W(e.baseUrl)){try{const t=await Pe(e.baseUrl,e.apiKey);if(t.length>0){this.codexModelOptions=V(t),this.codexModelOptionsCachedAt=Date.now(),o.info("codex-adapter",`Loaded ${t.length} models from external provider ${e.baseUrl}`);return}}catch(t){o.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=De(s);t.push(...n.models),i=n.nextCursor}while(i);t.length>0&&(this.codexModelOptions=V(t),this.codexModelOptionsCachedAt=Date.now())}catch(t){o.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;queuedFinalAnswerMessageIds=new Set;turnHasQueuedFinalAnswer=!1;reliableCodexDeliveryChain=Promise.resolve();reliableCodexDeliveryError=null;reliableCodexDeliveryGeneration=0;turnCompletionInProgress=!1;codexSequence=0;turnError=null;turnErrorIsRetryableOnly=!0;turnHasVisibleOutput=!1;turnSawVisibleFinalAnswer=!1;turnHasDeliveredFinalAnswer=!1;deliverInboundEvent(e){if(this.compacting){o.info("codex-adapter",`Event ${e.event_id} deferred: compaction in progress`),this.compactionDeferred.push(e);return}const t=e.content;if(this.currentTurnId&&t.trim()){o.info("codex-adapter",`Event ${e.event_id}: steering active turn ${this.currentTurnId}`),this.steerTurn(t).catch(i=>{const s=i instanceof Error?i.message:String(i);if(o.info("codex-adapter",`Steer failed, falling through: ${s}`),!this.currentTurnId){this.startNewTurn(e,t);return}if(Ne(s)){o.info("codex-adapter","Unsteerable turn detected, clearing active state and starting new turn"),this.clearActive(),this.startNewTurn(e,t);return}o.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){o.info("codex-adapter",`Event ${e.event_id} rejected: busy and empty content`),this.callbacks.sendEventResult(e.event_id,"failed","agent busy");return}this.startNewTurn(e,t)}startNewTurn(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,e.audit?.enabled===!0&&this.enableAuditCapture(e.event_id),this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.resetReliableCodexDeliveryState(),this.codexSequence=0,this.startComposing();const i=this.threadId??"",s=new P(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=>{o.error("codex-adapter",`Turn failed: ${r}`),this.callbacks.sendEventResult(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.callbacks.sendEventResult(e,"canceled","stopped by user"),this.clearActive())}async spawnCodex(){const e={...process.env,...this.config.env},t=typeof e.PATH=="string"?e.PATH:void 0;t||o.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=G(this.config.command||"codex",t),s=Ae(this.config.args);this.sandboxMode&&s.push("-c",`sandbox_mode="${this.sandboxMode}"`),o.info("codex-adapter",`Spawning: ${i} ${s.join(" ")}`);try{if(!(await F(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(r){throw String(r?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):r}const n=H({codexHome:this.codexHome});if(n.locked&&!n.stale)throw new Error(`Codex session appears locked by another process: ${n.path}`);n.stale&&o.warn("codex-adapter",`Ignoring stale Codex lock: ${n.path}`);try{this.process=ie(i,s,{env:e,cwd:this.cwd}).process}catch(r){throw o.error("codex-adapter",`Codex spawn threw: ${r}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",r}this.process.on("error",r=>{o.error("codex-adapter",`Codex process spawn error: ${r}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("spawn failed: "+(r instanceof Error?r.message:String(r))),this.stopComposing(),this.activeEventId&&(this.callbacks.sendEventResult(this.activeEventId,"failed","Codex process spawn failed"),this.activeEventId=null),this.emit("exit",1)}),this.process.on("exit",r=>{o.info("codex-adapter",`Codex process exited (code=${r})`),this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("process exited"),this.stopComposing(),this.emit("exit",r)}),this.process.stderr?.on("data",r=>{const a=r.toString().trim();a&&o.info("codex-adapter",`[codex stderr] ${a}`)}),this.bindStdout(),this.alive=!0}bindStdout(){if(!this.process?.stdout)return;this.process.stdout.setEncoding("utf8"),Y({input:this.process.stdout}).on("line",t=>{if(!t.trim())return;let i;try{i=JSON.parse(t)}catch{o.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,a=n?.type,c=this.normalizeAgentMessagePhase(n?.phase);this.isLongRunningToolItemType(a)&&(this.inFlightToolOps+=1),a==="agentMessage"&&r&&(c?this.agentMessagePhases.set(r,c):this.agentMessagePhases.delete(r),A(c)?(this.visibleAgentMessageIds.add(r),this.hiddenAgentMessageIds.delete(r)):(this.hiddenAgentMessageIds.add(r),this.visibleAgentMessageIds.delete(r)),c==="final_answer"&&A(c)&&(this.turnSawVisibleFinalAnswer=!0));break}case"item/agentMessage/delta":{const n=i.delta,r=i.itemId,a=this.resolveAgentMessagePhase(r,i.phase),c=(!r||!this.hiddenAgentMessageIds.has(r))&&A(a);if(a==="final_answer"&&c&&(this.turnSawVisibleFinalAnswer=!0),n&&this.activeEventId&&c&&!this.shouldSuppressAgentMessageDeltaDuringToolRun(r,a)){const f=a?{...e,params:{...i,phase:a}}:e;a==="final_answer"?this.queueReliableFinalAnswerDelta(r,f):(this.recordDeliveredAgentMessage(r,a),this.emitCodexEvent("item/agentMessage/delta",f))}break}case"item/completed":{const n=i.item,r=n?.id,a=n?.type;if(this.isLongRunningToolItemType(a)&&(this.inFlightToolOps=Math.max(0,this.inFlightToolOps-1)),this.activeEventId&&a!=="agentMessage"&&(this.turnHasVisibleOutput=!0,this.emitCodexEvent("item/completed",e)),a==="agentMessage"){const c=this.resolveAgentMessagePhase(r,n?.phase),f=(!r||!this.hiddenAgentMessageIds.has(r))&&A(c);if(c==="final_answer"&&f){this.turnSawVisibleFinalAnswer=!0;const m=this.extractAgentMessageText(n),p=r?this.deliveredAgentMessageIds.has(r):!1,h=r?this.queuedFinalAnswerMessageIds.has(r):this.turnHasQueuedFinalAnswer;this.activeEventId&&m&&!p&&!h&&(o.warn("codex-adapter",`Recovering final_answer from item/completed item_id=${r??"unknown"}`),this.queueReliableFinalAnswerDelta(r,{method:"item/agentMessage/delta",params:{...r?{itemId:r}:{},delta:m,phase:c}}))}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.resetReliableCodexDeliveryState(),this.currentTurnStartedAt=Date.now(),this.preflightCheckComplete=!1,o.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.activeEventId&&this.emitCodexEvent("item/permissions/requestApproval",e),this.handleApprovalRequest(e,"permission");break}case"turn/completed":{this.handleTurnCompleted(i);break}case"error":{const n=i.message??JSON.stringify(i);o.error("codex-adapter",`Codex error: ${n}`);const r=i.willRetry===!0;n&&(this.turnError=n,r||(this.turnErrorIsRetryableOnly=!1)),this.activeEventId&&!r&&this.callbacks.sendRunError(this.activeEventId,this.activeSessionId??"",n);break}case"account/rateLimits/updated":{this.rateLimitSnapshot=this.parseRateLimitSnapshot(i),this.rateLimitSnapshot&&(o.info("codex-adapter",`Rate limits updated: primary=${this.rateLimitSnapshot.primary.usedPercent.toFixed(1)}% secondary=${this.rateLimitSnapshot.secondary.usedPercent.toFixed(1)}%`),this.callbacks.onRateLimitsUpdated?.(this.rateLimitSnapshot));break}case"thread/tokenUsage/updated":{const n=i.threadId,r=i.tokenUsage,a=r?.last;(!n||!r||!a)&&o.info("codex-adapter",`[cp-diagnose] token_usage payload_incomplete: method=thread/tokenUsage/updated hasThreadId=${String(!!n)} hasTokenUsage=${String(!!r)} hasLast=${String(!!a)} params=${JSON.stringify(i)}`),n&&r&&a&&(this.currentThreadTokenUsage={inputTokens:a.inputTokens??0,outputTokens:a.outputTokens??0,cacheReadInputTokens:a.cachedInputTokens??0,cacheCreationInputTokens:0},o.info("codex-adapter",`[cp-diagnose] token_usage raw thread=${n}: ${JSON.stringify(r)}`),o.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&&t!=="turn/completed"&&(!s||this.pendingApprovals.size===0)&&this.resetIdleTimer(this.activeEventId)}shouldIgnoreOutOfScopeNotification(e,t,i){if(!t||e.id!=null)return!1;const s=v(l(i.threadId),l(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 v(l(e.turnId),l(e.turnID),l(t?.id))}logIgnoredNotificationScope(e,t,i){e!=="error"&&!e.startsWith("turn/")||o.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 a=typeof t.threadId=="string"&&t.threadId?t.threadId:typeof t.thread_id=="string"&&t.thread_id?t.thread_id:this.threadId;if(a&&(s.threadId=a),!!Ce.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 f=c instanceof Error?c.message:String(c);o.warn("codex-adapter",`Audit evidence capture skipped event=${i} method=${e}: ${f}`)}}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&&o.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,o.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 a=r;for(const c of t)Object.prototype.hasOwnProperty.call(a,c)&&(i.push(c),s.push(String(a[c])));for(const c of Object.values(a))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 a=this.findNumericField(r,t);if(a!=null)return a}continue}const n=this.findNumericField(s,t);if(n!=null)return n}return null}buildContextWindowSnapshot(){const e=this.currentModelContextWindow;if(!e||e<=0)return o.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 o.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<U||this.pendingAutoCompact||this.compacting||(this.pendingAutoCompact=!0,o.info("codex-adapter",`[auto-compact] context_window usedPercentage=${t.toFixed(1)}% >= ${U}%, 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=>{o.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=>{o.warn("codex-adapter",`[auto-compact] compact error: ${e instanceof Error?e.message:e}`)})))}parseRateLimitSnapshot(e){try{const i=e.rateLimitsByLimitId?.codex??e.rateLimits??e,s=i.primary,n=i.secondary,r=i.credits,a=u=>{if(typeof u=="number"&&Number.isFinite(u))return u;if(typeof u=="string"){const g=Number(u);if(Number.isFinite(g))return g}return 0},c=u=>typeof u=="boolean"?u:typeof u=="string"?u.toLowerCase()==="true":!1,f=u=>{if(u==null)return null;if(typeof u=="string"){const g=u.trim();if(!g)return null;const b=Number(g);return Number.isFinite(b)&&b>1e9?new Date(b*1e3).toISOString():g}if(typeof u=="number"&&Number.isFinite(u)&&u>0){const g=u>1e12?u/1e3:u;return new Date(g*1e3).toISOString()}return null},m=u=>{const g=u.resets_in_seconds??u.resetsInSeconds,b=typeof g=="number"||typeof g=="string"?Number(g):NaN;return!Number.isFinite(b)||b<=0?null:new Date(Date.now()+b*1e3).toISOString()},p=u=>({usedPercent:a(u.used_percent??u.usedPercent),windowMinutes:a(u.window_minutes??u.windowDurationMins??u.windowMinutes),resetsAt:f(u.resets_at??u.resetsAt)??m(u)}),h=()=>({usedPercent:0,windowMinutes:0,resetsAt:null}),I=()=>{const u=[];if(s&&u.push(s),n&&u.push(n),Array.isArray(i.windows))for(const g of i.windows)g&&typeof g=="object"&&u.push(g);return u.map(p).filter(g=>g.windowMinutes>0)},x=(u,g,b)=>{const D=u.filter(C=>b(C.windowMinutes));return D.length===0?null:D.reduce((C,O)=>Math.abs(O.windowMinutes-g)<Math.abs(C.windowMinutes-g)?O:C)},w=I(),y=w.length>0?{primary:x(w,300,u=>u<1440)??h(),secondary:x(w,10080,u=>u>=1440)??h()}:s||n?{primary:s?p(s):h(),secondary:n?p(n):h()}:null;return y?{primary:y.primary,secondary:y.secondary,credits:r?{hasCredits:c(r.has_credits??r.hasCredits),unlimited:c(r.unlimited),balance:r.balance==null?null:a(r.balance)}:{hasCredits:!1,unlimited:!1,balance:null}}:null}catch{return null}}handleApprovalRequest(e,t){const i=e.id;if(i==null)return;const s=e.method,n=`${i}`.trim(),r=`codex_${J(this.activeSessionId??"")}_${J(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}),o.info("codex-adapter",`Pending approval stored: ${r} (kind=${t})`),this.clearIdleTimer(),this.stopComposing()}resolvePendingApproval(e){const t=e.params??{},i=v(t.approval_id,t.approvalId);if(i)return this.pendingApprovals.get(i)??null;const s=v(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)}
|
|
4
|
+
`)}armCompactionFallback(){this.compacting&&(this.compactingTimer&&clearTimeout(this.compactingTimer),this.compactingTimer=setTimeout(()=>{o.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")},Te),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);o.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.clearIdleTimer(),this.activeEventId){if(this.turnCompletionInProgress)return;this.turnCompletionInProgress=!0;const t=this.activeEventId,i=this.reliableCodexDeliveryGeneration,s={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,codex_payload:X("turn/completed",e),codex_at:new Date().toISOString()};this.finishTurnCompleted(t,i,s)}this.compacting&&this.finishCompaction("turn-completed")}async finishTurnCompleted(e,t,i){if(await this.reliableCodexDeliveryChain,this.activeEventId!==e||this.reliableCodexDeliveryGeneration!==t)return;const s=this.turnError,n=this.turnErrorIsRetryableOnly,r=this.turnHasVisibleOutput,a=this.turnSawVisibleFinalAnswer&&!this.turnHasDeliveredFinalAnswer,c=s&&!(n&&r)?s:null,f=this.reliableCodexDeliveryError??(a?"Codex final answer was observed but not delivered":null);let m=null;if(this.callbacks.sendCodexEventReliable)try{await this.callbacks.sendCodexEventReliable(i)}catch(h){m=`Codex reliable delivery failed for turn/completed: ${B(h)}`,o.error("codex-adapter",m)}else this.callbacks.sendCodexEvent(i),m="Codex reliable delivery unavailable for turn/completed",o.error("codex-adapter",m);if(this.activeEventId!==e||this.reliableCodexDeliveryGeneration!==t)return;const p=m??c??f;this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.clearActive({runPendingAutoCompact:!1}),this.callbacks.sendEventResult(e,p?"failed":"responded",p??void 0),this.tryRunPendingAutoCompact()}emitCodexEvent(e,t){const i=this.createCodexEventPayload(e,t);i&&this.callbacks.sendCodexEvent(i)}createCodexEventPayload(e,t){return this.activeEventId?{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,codex_payload:X(e,t),codex_at:new Date().toISOString()}:null}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,a={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:m=>{m.error?n(new Error(`JSON-RPC error: ${m.error.message}`)):s(m.result)},reject:n,timer:c});const f=JSON.stringify(a);this.process.stdin.write(`${f}
|
|
5
|
+
`)})}sendNotification(e,t){if(!this.process?.stdin)return;const i={jsonrpc:"2.0",method:e,params:t??{}};this.process.stdin.write(`${JSON.stringify(i)}
|
|
6
|
+
`)}async initializeHandshake(){if(this.initialized)return;const e=re(),t=await this.sendRequest("initialize",{clientInfo:{name:"grix-connector",title:"Grix Connector",version:e},capabilities:{experimentalApi:!0}},15e3);o.info("codex-adapter",`Initialized: ${JSON.stringify(t)}`),this.sendNotification("initialized"),this.initialized=!0,await this.refreshCodexModelOptions(),this.fetchRateLimits()}fetchRateLimits(){Promise.resolve(this.sendRequest("account/rateLimits/read",void 0,1e4)).then(e=>{const t=this.parseRateLimitSnapshot(e);t&&(this.rateLimitSnapshot=t,o.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=>{o.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=[],r=this.callbacks.getAgentProfile?.(),a=r?.agentName?.trim()??"",c=r?.introduction?.trim()??"";if((a||c)&&this.identityInjectedThreadId!==this.threadId){const h=["[system-identity]"];a&&h.push(`Your name is "${a}".`),c&&h.push(`Your self-introduction: ${c}`),h.push("Treat this as an out-of-band instruction; do not echo or repeat it in your replies."),h.push("[/system-identity]"),n.push({type:"text",text:h.join(`
|
|
7
|
+
`),text_elements:[]}),this.identityInjectedThreadId=this.threadId,o.info("codex-adapter",`Injected agent identity for thread=${this.threadId} name="${a}"`)}if(this.needsHistoryInjection&&s){this.needsHistoryInjection=!1;const h=await this.loadHistoryForInjection(s);for(const I of h)n.push(I);h.length>0&&o.info("codex-adapter",`Injected ${h.length} history items`)}if(e.contextMessages&&e.contextMessages.length>0){const h=e.contextMessages.map(I=>`[${I.senderId??"unknown"}]: ${I.content}`).join(`
|
|
8
8
|
`);n.push({type:"text",text:`Conversation context:
|
|
9
|
-
${
|
|
9
|
+
${h}
|
|
10
10
|
|
|
11
|
-
Latest user message:`,text_elements:[]})}n.push({type:"text",text:e.text,text_elements:[]});const m={threadId:this.threadId,approvalPolicy:this.approvalPolicy,input:n,model:this.model},g=Te(this.collaborationMode,this.model);g&&(m.collaborationMode=g),this.reasoningEffort&&(m.effort=this.reasoningEffort);const p=this.effectiveServiceTier();p&&(m.serviceTier=p),await this.sendRequest("turn/start",m),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(){try{const e=await this.sendRequest("thread/start",{approvalPolicy:this.approvalPolicy,model:this.model,cwd:this.cwd,experimentalRawEvents:!1,persistExtendedHistory:!1,...this.reasoningEffort?{effort:this.reasoningEffort}:{},...this.effectiveServiceTier()?{serviceTier:this.effectiveServiceTier()}:{}}),t=ye(e);if(!t)throw new Error("Codex thread id is missing in thread/start result");this.threadId=t,this.updateModelFromThreadResult(e),this.threadResumePending=!1,this.persistThreadId(t)}catch{throw new Error("Failed to start Codex thread")}}updateModelFromThreadResult(e){if(this.model)return;const t=_e(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:_(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 s=await t.readHistory(e,ge),i=[];for(const n of s){const r=(n.content??"").slice(0,ve);n.direction==="inbound"?i.push({type:"text",text:r,text_elements:[]}):n.direction==="outbound"&&i.push({type:"assistant",text:r,text_elements:[]})}return i}catch(s){return o.error("codex-adapter",`Failed to load history: ${s}`),[]}}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,s){if(!this.threadId)return;const i=e.event_id?.trim()||`local_action_${e.action_id.trim()}`,n=x(t.session_id,t.sessionId)??this.activeSessionId??"";if(!n)return;const r=this.threadId,d=new R(r),h={adapterSessionId:r,text:""};this.activeEventId=i,this.activeSessionId=n,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.codexSequence=0,this.runTurn(h,d,i,n).catch(m=>{o.error("codex-adapter",`Post-approval turn failed: ${m}`),this.callbacks.sendEventResult(i,"failed",m instanceof Error?m.message:String(m)),this.clearActive()}),this.resetIdleTimer(i)}clearActive(e){const t=this.activeEventId;this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.currentTurnId=null,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.inFlightToolOps=0,this.clearIdleTimer(),this.pendingApprovals.clear(),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);o.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.idleNoProgressCount=0,this.armIdleTimer(e)}armIdleTimer(e){this.clearIdleTimer();const t=this.inFlightToolOps>0?fe:pe;this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e,t)},t)}async onIdleTimeout(e,t){if(this.activeEventId!==e)return;let s=!1;try{s=await this.ping(me)}catch{s=!1}if(this.activeEventId!==e)return;if(!s){o.error("codex-adapter",`Agent idle ${t/1e3}s and ping failed, declaring stuck: ${e}`),this.declareStuck(e,`agent idle ${t/1e3}s, ping failed`);return}const i=this.lastIdleCheckAt,n=this.lastProgressAt>i,r=n?!1:await this.checkSessionActivitySince(i);if(this.activeEventId===e){if(this.lastIdleCheckAt=Date.now(),n||r){r&&o.info("codex-adapter",`Idle timer: no stream output but rollout still being written, continuing: ${e}`),this.idleNoProgressCount=0,this.armIdleTimer(e);return}this.idleNoProgressCount++,this.idleNoProgressCount>=F?(o.error("codex-adapter",`Agent alive but no progress for ${this.idleNoProgressCount} idle cycles, declaring stuck: ${e}`),this.declareStuck(e,`agent alive but no progress for ${this.idleNoProgressCount} idle cycles`)):(o.warn("codex-adapter",`Idle timer fired, ping ok, no progress (${this.idleNoProgressCount}/${F}): ${e}`),this.armIdleTimer(e))}}declareStuck(e,t){this.callbacks.sendEventResult(e,"failed",t),this.clearActive(),this.emit("stuck")}async checkSessionActivitySince(e){if(!this.threadId)return!1;try{return await de(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"}shouldSuppressAgentMessageDeltaDuringToolRun(e){return this.inFlightToolOps<=0?!1:(o.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 be={allow:"accept","allow-once":"accept","allow-always":"acceptForSession",deny:"deny"};function we(a){return a&&a.length>0?[...a]:["app-server"]}function l(a){if(typeof a!="string")return;const e=a.trim();return e||void 0}function ye(a){if(!a||typeof a!="object")return null;const e=a,t=e.thread&&typeof e.thread=="object"?e.thread:void 0;return x(l(e.threadId),l(e.threadID),l(t?.id))??null}function _e(a){return!a||typeof a!="object"?null:l(a.model)??null}function _(a){const e=a?.trim().toLowerCase();return e==="default"||e==="plan"?e:null}function Te(a,e){const t=_(a),s=l(e);if(!(!t||!s))return{mode:t,settings:{model:s}}}function Se(a){if(!Array.isArray(a))return[];const e=[];for(const t of a){if(typeof t=="string"){const r=t.trim();r&&e.push(Ae(r,T(r)));continue}if(!t||typeof t!="object")continue;const s=t,i=x(l(s.id),l(s.model_id),l(s.modelId),l(s.value));if(!i)continue;const n=x(l(s.displayName),l(s.display_name),l(s.name),l(s.label))??T(i);e.push({id:i,displayName:n,defaultReasoningEffort:l(s.defaultReasoningEffort)??null,supportedReasoningEfforts:E(s.supportedReasoningEfforts),defaultServiceTier:l(s.defaultServiceTier)??null,serviceTiers:A(s.serviceTiers),isDefault:s.isDefault===!0})}return e}function W(a){const e=a.toLowerCase().replace(/\/+$/,"");return!(e==="https://api.openai.com"||e==="https://api.openai.com/v1"||e.endsWith(".openai.com"))}async function Ce(a,e){const s=`${a.replace(/\/+$/,"")}/models`,i={Accept:"application/json"};e&&(i.Authorization=`Bearer ${e}`);const n=new AbortController,r=setTimeout(()=>n.abort(),1e4);try{const d=await fetch(s,{headers:i,signal:n.signal});if(!d.ok)return[];const h=await d.json();return ke(h)}finally{clearTimeout(r)}}function ke(a){if(!a||typeof a!="object")return[];const e=a,t=Array.isArray(e.data)?e.data:[],s=[];for(const i of t){if(!i||typeof i!="object")continue;const n=i,r=x(l(n.id),l(n.model));if(!r)continue;const d=x(l(n.displayName),l(n.display_name),l(n.name))??T(r);s.push({id:r,displayName:d,defaultReasoningEffort:l(n.defaultReasoningEffort)??null,supportedReasoningEfforts:E(n.supportedReasoningEfforts),defaultServiceTier:l(n.defaultServiceTier)??null,serviceTiers:A(n.serviceTiers),isDefault:n.isDefault===!0})}return s}function Ee(a){if(!a||typeof a!="object")return{models:[],nextCursor:null};const e=a,t=Array.isArray(e.data)?e.data:[],s=[];for(const i of t){if(!i||typeof i!="object")continue;const n=i;if(n.hidden===!0)continue;const r=x(l(n.id),l(n.model));if(!r)continue;const d=x(l(n.displayName),l(n.display_name),l(n.name))??T(r);s.push({id:r,displayName:d,defaultReasoningEffort:l(n.defaultReasoningEffort)??null,supportedReasoningEfforts:E(n.supportedReasoningEfforts),defaultServiceTier:l(n.defaultServiceTier)??null,serviceTiers:A(n.serviceTiers),isDefault:n.isDefault===!0})}return{models:s,nextCursor:l(e.nextCursor)??null}}function B(a){const e=[],t=new Set;for(const s of a){const i=s.id.trim(),n=i.toLowerCase();!i||t.has(n)||(t.add(n),e.push({id:i,displayName:s.displayName.trim()||i,defaultReasoningEffort:s.defaultReasoningEffort,supportedReasoningEfforts:[...s.supportedReasoningEfforts],defaultServiceTier:s.defaultServiceTier,serviceTiers:[...s.serviceTiers],isDefault:s.isDefault}))}return e}function Ae(a,e){return{id:a,displayName:e,defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!1}}function E(a){if(!Array.isArray(a))return[];const e=[];for(const t of a){if(typeof t=="string"){const i=t.trim();i&&e.push(i);continue}if(!t||typeof t!="object")continue;const s=l(t.reasoningEffort);s&&e.push(s)}return e}function A(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 s=t,i=l(s.id);i&&e.push({id:i,displayName:x(l(s.name),l(s.displayName),l(s.display_name))??i,description:l(s.description)??null})}return e}function T(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 x(...a){for(const e of a)if(e!=null){if(typeof e=="string"&&!e.trim())continue;return e}}function J(a){return a.trim().replace(/[^a-zA-Z0-9._:-]+/g,"_")}function V(a,e){switch(a){case"turn/completed":return;case"item/agentMessage/delta":return{params:{delta:(e?.params??{}).delta}};case"item/completed":{const s=(e?.params??{}).item;if(!s||typeof s!="object")return e;let i=s.aggregatedOutput;return typeof i=="string"&&i.length>H&&(i=i.slice(0,H)+`
|
|
12
|
-
\u2026(truncated)`),{params:{item:{type:
|
|
11
|
+
Latest user message:`,text_elements:[]})}n.push({type:"text",text:e.text,text_elements:[]});const f={threadId:this.threadId,approvalPolicy:this.approvalPolicy,input:n,model:this.model},m=Me(this.collaborationMode,this.model);m&&(f.collaborationMode=m),this.reasoningEffort&&(f.effort=this.reasoningEffort);const p=this.effectiveServiceTier();p&&(f.serviceTier=p),await this.sendRequest("turn/start",f),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(){try{const e=await this.sendRequest("thread/start",{approvalPolicy:this.approvalPolicy,model:this.model,cwd:this.cwd,experimentalRawEvents:!1,persistExtendedHistory:!1,...this.reasoningEffort?{effort:this.reasoningEffort}:{},...this.effectiveServiceTier()?{serviceTier:this.effectiveServiceTier()}:{}}),t=Ee(e);if(!t)throw new Error("Codex thread id is missing in thread/start result");this.threadId=t,this.updateModelFromThreadResult(e),this.threadResumePending=!1,this.persistThreadId(t)}catch{throw new Error("Failed to start Codex thread")}}updateModelFromThreadResult(e){if(this.model)return;const t=ke(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:T(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,we);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 o.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=v(t.session_id,t.sessionId)??this.activeSessionId??"";if(!n)return;const r=this.threadId,a=new P(r),c={adapterSessionId:r,text:""};this.activeEventId=s,this.activeSessionId=n,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.resetReliableCodexDeliveryState(),this.codexSequence=0,this.runTurn(c,a,s,n).catch(f=>{o.error("codex-adapter",`Post-approval turn failed: ${f}`),this.callbacks.sendEventResult(s,"failed",f instanceof Error?f.message:String(f)),this.clearActive()}),this.resetIdleTimer(s)}clearActive(e){const t=this.activeEventId;this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.currentTurnId=null,this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.resetReliableCodexDeliveryState(),this.inFlightToolOps=0,this.consecutivePingFailures=0,this.currentTurnStartedAt=0,this.preflightCheckComplete=!1,this.clearIdleTimer(),this.pendingApprovals.clear(),t&&e?.emitEventDone!==!1&&this.emit("eventDone",t),this.replaySteerDeferred(),e?.runPendingAutoCompact!==!1&&this.tryRunPendingAutoCompact()}replaySteerDeferred(){if(this.steerDeferred.length===0)return;const e=this.steerDeferred.splice(0);o.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?ge:me,n=this.turnInactivityTimeoutMs===null?Number.POSITIVE_INFINITY:this.lastProgressAt+this.turnInactivityTimeoutMs-i,r=this.currentTurnStartedAt>0&&!this.preflightCheckComplete?this.currentTurnStartedAt+k-i:Number.POSITIVE_INFINITY,a=Math.max(0,Math.min(s,n,r,t));this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e,a)},a)}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),[a,c]=await Promise.all([n,r]);if(this.activeEventId!==e)return;const f=this.activityGeneration>s;if(this.lastIdleCheckAt=Date.now(),this.lastIdleCheckGeneration=this.activityGeneration,!this.preflightCheckComplete&&this.currentTurnStartedAt>0&&Date.now()-this.currentTurnStartedAt>=k){const p=this.activityGeneration,h=await this.inspectCurrentTurnProgress();if(this.activeEventId!==e)return;if(this.activityGeneration>p)this.preflightCheckComplete=!0;else if(h==="task_started_only"){this.declareRecoverablePreflightStuck(e,`Codex preflight stalled for ${Math.round(k/1e3)}s before model execution`);return}else h==="unknown"?this.currentTurnStartedAt=Date.now():this.preflightCheckComplete=!0}if(f||c){c&&(o.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 m=Date.now()-this.lastProgressAt;if(this.turnInactivityTimeoutMs!==null&&m>=this.turnInactivityTimeoutMs){o.error("codex-adapter",`Turn inactive ${Math.round(m/1e3)}s \u2265 cap ${Math.round(this.turnInactivityTimeoutMs/1e3)}s, declaring stuck: ${e}`),this.declareStuck(e,`turn inactivity timeout after ${Math.round(m/1e3)}s with no Codex activity`);return}if(!a){if(this.consecutivePingFailures+=1,this.consecutivePingFailures<2){o.warn("codex-adapter",`Agent idle ${t/1e3}s and ping failed once; retrying liveness probe: ${e}`),this.armIdleTimer(e,Ie);return}o.error("codex-adapter",`Agent idle ${t/1e3}s and ping failed twice, declaring stuck: ${e}`),this.declareStuck(e,`agent idle ${t/1e3}s, ping failed twice`);return}this.consecutivePingFailures=0,this.idleNoProgressCount++,o.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.callbacks.sendEventResult(e,"failed",t),this.clearActive(),this.emit("stuck")}declareRecoverablePreflightStuck(e,t){const i=this.activeSessionId??"";o.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 le(this.threadId,this.currentTurnId,this.codexHome)}catch{return"unknown"}}async checkSessionActivitySince(e){if(!this.threadId)return!1;try{return await ce(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)}queueReliableFinalAnswerDelta(e,t){const i=this.createCodexEventPayload("item/agentMessage/delta",t);if(!i)return;const s=i.event_id,n=this.reliableCodexDeliveryGeneration;if(this.turnHasQueuedFinalAnswer=!0,e&&this.queuedFinalAnswerMessageIds.add(e),!this.callbacks.sendCodexEventReliable){this.callbacks.sendCodexEvent(i),this.recordReliableCodexDeliveryError(n,"Codex reliable delivery unavailable for final_answer");return}const r=this.callbacks.sendCodexEventReliable,a=this.reliableCodexDeliveryChain.then(async()=>{await r(i),this.activeEventId===s&&this.reliableCodexDeliveryGeneration===n&&this.recordDeliveredAgentMessage(e,"final_answer")});this.reliableCodexDeliveryChain=a.catch(c=>{this.recordReliableCodexDeliveryError(n,`Codex reliable delivery failed for final_answer: ${B(c)}`)})}recordReliableCodexDeliveryError(e,t){this.reliableCodexDeliveryGeneration===e&&(this.reliableCodexDeliveryError||(this.reliableCodexDeliveryError=t),o.error("codex-adapter",t))}resetReliableCodexDeliveryState(){this.reliableCodexDeliveryGeneration+=1,this.reliableCodexDeliveryChain=Promise.resolve(),this.reliableCodexDeliveryError=null,this.queuedFinalAnswerMessageIds.clear(),this.turnHasQueuedFinalAnswer=!1,this.turnCompletionInProgress=!1}shouldSuppressAgentMessageDeltaDuringToolRun(e,t){return t==="final_answer"||this.inFlightToolOps<=0?!1:(o.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 Se={allow:"accept","allow-once":"accept","allow-always":"acceptForSession",deny:"deny"};function Ae(d){return d&&d.length>0?[...d]:["app-server"]}function l(d){if(typeof d!="string")return;const e=d.trim();return e||void 0}function Ee(d){if(!d||typeof d!="object")return null;const e=d,t=e.thread&&typeof e.thread=="object"?e.thread:void 0;return v(l(e.threadId),l(e.threadID),l(t?.id))??null}function ke(d){return!d||typeof d!="object"?null:l(d.model)??null}function T(d){const e=d?.trim().toLowerCase();return e==="default"||e==="plan"?e:null}function Me(d,e){const t=T(d),i=l(e);if(!(!t||!i))return{mode:t,settings:{model:i}}}function Re(d){if(!Array.isArray(d))return[];const e=[];for(const t of d){if(typeof t=="string"){const r=t.trim();r&&e.push(Oe(r,_(r)));continue}if(!t||typeof t!="object")continue;const i=t,s=v(l(i.id),l(i.model_id),l(i.modelId),l(i.value));if(!s)continue;const n=v(l(i.displayName),l(i.display_name),l(i.name),l(i.label))??_(s);e.push({id:s,displayName:n,defaultReasoningEffort:l(i.defaultReasoningEffort)??null,supportedReasoningEfforts:M(i.supportedReasoningEfforts),defaultServiceTier:l(i.defaultServiceTier)??null,serviceTiers:R(i.serviceTiers),isDefault:i.isDefault===!0})}return e}function W(d){const e=d.toLowerCase().replace(/\/+$/,"");return!(e==="https://api.openai.com"||e==="https://api.openai.com/v1"||e.endsWith(".openai.com"))}async function Pe(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 a=await fetch(i,{headers:s,signal:n.signal});if(!a.ok)return[];const c=await a.json();return $e(c)}finally{clearTimeout(r)}}function $e(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=v(l(n.id),l(n.model));if(!r)continue;const a=v(l(n.displayName),l(n.display_name),l(n.name))??_(r);i.push({id:r,displayName:a,defaultReasoningEffort:l(n.defaultReasoningEffort)??null,supportedReasoningEfforts:M(n.supportedReasoningEfforts),defaultServiceTier:l(n.defaultServiceTier)??null,serviceTiers:R(n.serviceTiers),isDefault:n.isDefault===!0})}return i}function De(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=v(l(n.id),l(n.model));if(!r)continue;const a=v(l(n.displayName),l(n.display_name),l(n.name))??_(r);i.push({id:r,displayName:a,defaultReasoningEffort:l(n.defaultReasoningEffort)??null,supportedReasoningEfforts:M(n.supportedReasoningEfforts),defaultServiceTier:l(n.defaultServiceTier)??null,serviceTiers:R(n.serviceTiers),isDefault:n.isDefault===!0})}return{models:i,nextCursor:l(e.nextCursor)??null}}function V(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 Oe(d,e){return{id:d,displayName:e,defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!1}}function M(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=l(t.reasoningEffort);i&&e.push(i)}return e}function R(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=l(i.id);s&&e.push({id:s,displayName:v(l(i.name),l(i.displayName),l(i.display_name))??s,description:l(i.description)??null})}return e}function _(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 v(...d){for(const e of d)if(e!=null){if(typeof e=="string"&&!e.trim())continue;return e}}function B(d){return d instanceof Error?d.message:String(d)}function J(d){return d.trim().replace(/[^a-zA-Z0-9._:-]+/g,"_")}function X(d,e){switch(d){case"turn/completed":return;case"item/agentMessage/delta":{const t=e?.params??{};return{params:{delta:t.delta,...t.itemId!==void 0?{itemId:t.itemId}:{},...t.phase!==void 0?{phase:t.phase}:{}}}}case"item/completed":{const i=(e?.params??{}).item;if(!i||typeof i!="object")return e;let s=i.aggregatedOutput;return typeof s=="string"&&s.length>q&&(s=s.slice(0,q)+`
|
|
12
|
+
\u2026(truncated)`),{params:{item:{type:i.type,command:i.command,aggregatedOutput:s,exitCode:i.exitCode,durationMs:i.durationMs}}}}default:return e}}class P extends L{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){o.warn("codex-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}function Ne(d){return["cannot steer a compact turn","turn not found","turn already completed","no active turn"].some(t=>d.includes(t))}export{$ as CodexAdapter,X as trimCodexPayloadForWire};
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
import{stat as
|
|
1
|
+
import{open as _,stat as A}from"node:fs/promises";import{resolveCodexHome as k}from"./codex-trust.js";import{findRolloutFile as d}from"./rollout-locator.js";const u=new Map,b=512*1024;async function g(t){try{return(await A(t)).mtimeMs}catch{return null}}function $(t,r){const i=k(r),s=`${i}\0${t}`,n=u.get(s);if(n)return n;const e=d(t,i);return e&&u.set(s,e),e}async function M(t,r,i){if(!t)return!1;const s=k(i),n=`${s}\0${t}`,e=u.get(n);if(e){const l=await g(e);if(l!==null)return l>r;u.delete(n)}const c=d(t,s);if(!c)return!1;u.set(n,c);const f=await g(c);return f!==null&&f>r}async function O(t,r,i){if(!t||!r)return"unknown";const s=$(t,i);if(!s)return"unknown";let n;try{n=await _(s,"r");const e=await n.stat();if(e.size<=0)return"unknown";const c=Math.max(0,e.size-b),f=e.size-c,l=Buffer.alloc(f),{bytesRead:x}=await n.read(l,0,f,c);let y=l.subarray(0,x).toString("utf8");if(c>0){const o=y.indexOf(`
|
|
2
|
+
`);if(o<0)return"unknown";y=y.slice(o+1)}const p=[];for(const o of y.split(`
|
|
3
|
+
`))if(o.trim())try{const a=JSON.parse(o);if(!a||typeof a!="object"||Array.isArray(a))return"unknown";p.push(a)}catch{return"unknown"}let w=-1;for(let o=p.length-1;o>=0;o--){const a=p[o];if(a.type!=="event_msg")continue;const m=a.payload;if(!m||typeof m!="object"||Array.isArray(m))continue;const h=m;if(h.type==="task_started"&&h.turn_id===r){w=o;break}}return w<0?"unknown":w===p.length-1?"task_started_only":"progressed"}catch{return u.delete(`${k(i)}\0${t}`),"unknown"}finally{await n?.close().catch(()=>{})}}export{M as checkCodexSessionActivity,O as inspectCodexTurnProgress};
|