grix-connector 3.33.2 → 3.33.3
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 +2 -2
- package/dist/adapter/agy/agy-adapter.js +5 -5
- package/dist/adapter/agy/model-list.js +2 -2
- package/dist/adapter/claude/claude-adapter.js +5 -5
- package/dist/adapter/claude/model-list.js +1 -1
- package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
- package/dist/adapter/codewhale/model-list.js +2 -2
- package/dist/adapter/codex/codex-bridge.js +1 -1
- package/dist/adapter/cursor/cursor-adapter.js +7 -7
- package/dist/adapter/cursor/fetch-models.js +2 -2
- package/dist/adapter/cursor/resolve-command.js +1 -1
- package/dist/adapter/openhuman/openhuman-adapter.js +3 -3
- package/dist/assets/dsh-bridge/{grix-dsh-bridge-3.33.2.tgz → grix-dsh-bridge-3.33.3.tgz} +0 -0
- package/dist/assets/dsh-bridge/manifest.json +5 -5
- package/dist/audit/adapters/openclaw/openclaw-audit-adapter.js +1 -1
- package/dist/audit/adapters/pi/pi-transcript-source.js +1 -1
- package/dist/audit/core/transcript-fingerprint.js +1 -0
- package/dist/audit/producer/ipc-audit-producer.js +1 -1
- package/dist/bridge/adapter-pool.js +1 -1
- package/dist/bridge/bridge.js +9 -9
- package/dist/bridge/cli-install-offer.js +1 -0
- package/dist/bridge/respawn-manager.js +1 -1
- package/dist/core/files/file-serve.js +1 -1
- package/dist/core/installer/installer.js +6 -6
- package/dist/core/installer/npm-registry.js +3 -3
- package/dist/core/installer/prereq-installer.js +1 -1
- package/dist/core/proxy/hermes-profile-relay.js +1 -1
- package/dist/core/runtime/spawn.js +3 -3
- package/dist/core/upgrade/npm-upgrader.js +2 -2
- package/dist/core/util/cli-probe.js +2 -2
- package/dist/core/util/git-project-root.js +1 -1
- package/dist/default-skills/grix-egg/SKILL.md +2 -2
- package/dist/default-skills/message-send/SKILL.md +1 -1
- package/dist/default-skills/message-unsend/SKILL.md +1 -1
- package/dist/manager.js +1 -1
- package/dist/service/process-control.js +1 -1
- package/openclaw-plugin/audit-recorder-worker.js +170 -44
- package/openclaw-plugin/index.js +88 -14
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
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 b}from"../../core/runtime/spawn.js";import{createInterface as M}from"node:readline";import{EventEmitter as k}from"node:events";import{join as _,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{resolveMcpServerName as $,LEGACY_MCP_SERVER_NAMES as N}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as R}from"../shared/inbound-message-id-injector.js";import{IdentityInjector as B}from"../shared/identity-injector.js";import{compactToolInputForWire as D}from"../shared/tool-wire-payload.js";import{syncDefaultSkillsToDir as L}from"../../default-skills/index.js";import{buildSimpleProbeReport as U}from"../shared/probe-util.js";import{getCachedCodeWhaleModels as j,primeCodeWhaleModels as O}from"./model-list.js";import{writeCodeWhaleGrixConfig as G}from"./codewhale-provider-config.js";import{log as o}from"../../core/log/index.js";import{SessionBindingStore 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 b}from"../../core/runtime/spawn.js";import{createInterface as M}from"node:readline";import{EventEmitter as k}from"node:events";import{join as _,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{resolveMcpServerName as $,LEGACY_MCP_SERVER_NAMES as N}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as R}from"../shared/inbound-message-id-injector.js";import{IdentityInjector as B}from"../shared/identity-injector.js";import{compactToolInputForWire as D}from"../shared/tool-wire-payload.js";import{syncDefaultSkillsToDir as L}from"../../default-skills/index.js";import{buildSimpleProbeReport as U}from"../shared/probe-util.js";import{getCachedCodeWhaleModels as j,primeCodeWhaleModels as O}from"./model-list.js";import{writeCodeWhaleGrixConfig as G}from"./codewhale-provider-config.js";import{log as o}from"../../core/log/index.js";import{SessionBindingStore as H}from"../../core/persistence/session-binding-store.js";const W=120*1e3,f=1800*1e3,q=5*1e3;function F(g){try{return process.kill(g,0),!0}catch(e){return e.code==="EPERM"}}class ue 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;inboundMessageIds=new R;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 B("codewhale-adapter",t.getAgentProfile);const i=e.options??{};if(this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof H?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(),O(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 G(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.inboundMessageIds.forgetSession(e),this.deepSeekSessionId=null,this.persistSessionId(void 0)}sendPrompt(e){const t=new y(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&&!F(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:$(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async probe(e){const t=this.getStatus();return U(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);for(const a of[...N,e.name])try{I(n,["mcp","remove",a],{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0})}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",windowsHide:!0}),o.info("codewhale-adapter",`Registered MCP server: ${e.name}`);const d=_(P(),".codewhale","skills"),r=L(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 j(this.config.command||"codewhale").map(e=>({id:e.id,displayName:e.displayName}))}deliverInboundEvent(e){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}const t=this.inboundMessageIds.inject(e.session_id,e.content,e.msg_id);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 y(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(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()}),M({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=D(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.status=="string"?i.status.trim().toLowerCase():"",p=a==="failed"||a==="failure"||a==="error";t&&this.activeEventId===t&&this.activeSessionId&&(p&&this.callbacks.sendToolResult(t,this.activeSessionId,r,"(failed)"),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&&(b(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{b(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(
|
|
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()}),M({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=D(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.status=="string"?i.status.trim().toLowerCase():"",p=a==="failed"||a==="failure"||a==="error";t&&this.activeEventId===t&&this.activeSessionId&&(p&&this.callbacks.sendToolResult(t,this.activeSessionId,r,"(failed)"),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&&(b(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{b(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(W,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(q)}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 y 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{ue as CodeWhaleAdapter};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{spawn as w}from"node:child_process";import{log as
|
|
2
|
-
`)){const n=o.trim();if(!n)continue;const l=n.match(/^(\S+)\s*\(/),i=(l?l[1]:n).trim();!i||s.has(i)||(s.add(i),e.push({id:i,displayName:i}))}return e}function m(t){return
|
|
1
|
+
import{spawn as w}from"node:child_process";import{log as a}from"../../core/log/index.js";const c="codewhale-model-list",g=3600*1e3,C=1e4,k=[{id:"deepseek-v4-pro",displayName:"deepseek-v4-pro"},{id:"deepseek-v4-flash",displayName:"deepseek-v4-flash"}];let f=null,u=0,d=null;function h(t,e){return new Promise((s,o)=>{const n=w(t,e,{stdio:["ignore","pipe","pipe"],windowsHide:!0});let l="",i="";const p=setTimeout(()=>{n.kill("SIGKILL"),o(new Error(`codewhale ${e.join(" ")} timed out`))},C);n.stdout?.on("data",r=>{l+=r.toString("utf-8")}),n.stderr?.on("data",r=>{i+=r.toString("utf-8")}),n.on("error",r=>{clearTimeout(p),o(r)}),n.on("close",r=>{clearTimeout(p),r===0?s(l):o(new Error(i.trim()||`codewhale ${e.join(" ")} exited with code ${r}`))})})}function v(t){const e=[],s=new Set;for(const o of t.split(`
|
|
2
|
+
`)){const n=o.trim();if(!n)continue;const l=n.match(/^(\S+)\s*\(/),i=(l?l[1]:n).trim();!i||s.has(i)||(s.add(i),e.push({id:i,displayName:i}))}return e}function m(t){return d||(d=(async()=>{try{const e=(await h(t,["config","get","provider"])).trim()||"deepseek",s=await h(t,["model","list","--provider",e]),o=v(s);o.length>0?(f=o,u=Date.now(),a.info(c,`refreshed codewhale models (provider=${e}): ${o.length} entries`)):a.info(c,"codewhale model list returned no parsable entries, keeping fallback")}catch(e){a.info(c,`codewhale model list failed, using fallback: ${e instanceof Error?e.message:e}`)}finally{d=null}})(),d)}function T(t){return(!f||Date.now()-u>=g)&&t&&m(t),f??k}async function L(t){t&&await m(t)}export{T as getCachedCodeWhaleModels,L as primeCodeWhaleModels};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{execFileSync as Y}from"node:child_process";import{createInterface as fe}from"node:readline";import{EventEmitter as K}from"node:events";import{stat as Z}from"node:fs/promises";import{join as P,resolve as pe}from"node:path";import{fileURLToPath as me}from"node:url";import{syncDefaultSkillsToDir as ge}from"../../default-skills/index.js";import{resolveCommandPath as ve,spawnCommand as Ie,killProcessGroup as Q,hasChildProcesses as xe}from"../../core/runtime/spawn.js";import{InternalApiServer as ye}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as we,LEGACY_MCP_SERVER_NAMES as _e}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as Ce}from"../shared/inbound-message-id-injector.js";import{log as d}from"../../core/log/index.js";import{resolveClientVersion as Te}from"../../core/util/client-version.js";import{isThinkingAgentMessagePhase as L,isUserVisibleAgentMessagePhase as N}from"../../core/util/codex-output-policy.js";import{SessionBindingStore as be}from"../../core/persistence/session-binding-store.js";import{ensureCodexProjectTrusted as Ae,isCodexCommand as Ee,readCodexProviderSettings as F,resolveCodexHome as Se}from"./codex-trust.js";import{prepareCodexDirectHome as Re}from"./direct-home.js";import{checkCodexSessionActivity as Me,inspectCodexTurnProgress as ke}from"./session-activity.js";import{findRolloutFile as Pe}from"./rollout-locator.js";import{checkCodexLock as ee}from"./lock-monitor.js";import{resolveCliPath as De,getCliVersion as $e}from"../../core/util/cli-probe.js";import{scanSkills as Oe}from"../claude/skill-scanner.js";import{normalizeCodexConfigOverrides as te}from"./config-overrides.js";import{buildCodexOpenAiCompatibleProviderOverrides as Le,CODEX_RELAY_OPENAI_PROVIDER_ID as Ne,prepareCodexRawCapture as Fe,resolveCodexProviderName as je,resolveCodexRawCaptureTarget as He,resolveCodexProviderSupportsWebsocketsConfigKey as Ue}from"./raw-capture-hook.js";import{unavailableRawApiCaptureBoundary as qe}from"../../audit/raw-capture/capture-relay.js";const Be=60*1e3,ze=600*1e3,We="GRIX_RELAY_PROXY",Ve=5*1e3,Ge=15*1e3,ie=3;function j(a,e){const t=Number(process.env[a]);return Number.isFinite(t)&&t>0?t:e}function Xe(a){const e=Number(process.env[a]);return Number.isFinite(e)&&e>0?e:null}function Je(a){if(!a||typeof a!="object"||Array.isArray(a))return;const e=a,t=typeof e.auditId=="string"?e.auditId.trim():"",i=typeof e.sessionId=="string"?e.sessionId.trim():"",s=typeof e.spoolRootDir=="string"?e.spoolRootDir.trim():"";return t&&i&&s?{auditId:t,sessionId:i,spoolRootDir:s}:void 0}const H=j("GRIX_CODEX_PREFLIGHT_STALL_TIMEOUT_MS",120*1e3),Ye=20,Ke=8e3,se=2*1024,ne=`
|
|
2
|
-
\u2026(truncated)`,re=80,Ze=120*1e3,Qe=j("GRIX_CODEX_DELTA_COALESCE_MS",1e3),et=j("GRIX_CODEX_DELTA_COALESCE_CHARS",4096),tt=[{id:"gpt-5.3-codex",displayName:"GPT-5.3 Codex",defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!0}],oe=[{id:"default",displayName:"Default"},{id:"plan",displayName:"Plan"}],it=new Set(["rawResponse/completed","codex/rawResponse/completed","rawResponseItem/completed","codex/rawResponseItem/completed","thread/tokenUsage/updated","codex/thread/tokenUsage/updated","thread/compacted","codex/thread/compacted","turn/started","codex/turn/started","turn/completed","codex/turn/completed","item/started","codex/item/started","item/completed","codex/item/completed","error","codex/error"]);function ae(a,e){const t=String(a??"").trim()||"codex",i=ve(t,e);if(i!==t)return i;if(t!=="codex")return t;const s=process.platform==="win32"?[]:["/opt/homebrew/bin/codex","/usr/local/bin/codex","/usr/bin/codex"],n=process.platform!=="win32"?[]:[P(process.env.LOCALAPPDATA??"","npm","codex.cmd"),P(process.env.APPDATA??"","npm","codex.cmd"),P(process.env.LOCALAPPDATA??"","Programs","codex","codex.exe")],r=[...s,...n];for(const o of r)try{return require("node:fs").accessSync(o,require("node:fs").constants.X_OK),o}catch{continue}return d.warn("codex-adapter",`resolveCodexCommandPath: failed to resolve "${t}". envPath=${e?"provided":"missing (using process.env.PATH)"}. fallbacks tried: [${r.join(", ")}]`),t}class D extends K{type="codex";config;callbacks;process=null;alive=!1;stopped=!1;internalApi=null;bridgeStatus="starting";pendingRequests=new Map;requestId=0;threadId=null;initialized=!1;cwd;approvalPolicy;sandboxMode;model;collaborationMode;reasoningEffort;serviceTier;idleTimer=null;lastProgressAt=0;lastIdleCheckAt=0;activityGeneration=0;lastIdleCheckGeneration=0;idleNoProgressCount=0;inFlightToolOps=0;consecutivePingFailures=0;currentTurnStartedAt=0;preflightCheckComplete=!1;turnInactivityTimeoutMs=Xe("GRIX_CODEX_TURN_INACTIVITY_TIMEOUT_MS");pendingApprovals=new Map;needsHistoryInjection=!1;lastInjectedSessionId=null;identityInputInjectedThreadId=null;inboundMessageIds=new Ce;legacyDeveloperInstructionsUnsupported=!1;profileIdentityRefreshPending=!1;bindingStore=null;aibotSessionId="";threadResumePending=!1;autoTrustProject="auto";codexHome;codexDirect=null;directEnv={};configOverrideArgs=[];rawCaptureOptions;rawCaptureRelay;rawCaptureConfigOverrides=[];rawCaptureUnavailableReason;codexModelOptions=[];codexModelOptionsCachedAt=0;static MODEL_CACHE_TTL_MS=3600*1e3;rateLimitSnapshot=null;lastNonDefaultLimitRefreshAt=0;static NON_DEFAULT_LIMIT_REFRESH_INTERVAL_MS=6e4;currentThreadTokenUsage=null;currentModelContextWindow=null;auditCaptureByEventId=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const i=e.options??{};this.approvalPolicy=i.approvalPolicy??"never",this.sandboxMode=typeof i.sandboxMode=="string"&&i.sandboxMode.trim()&&i.sandboxMode.trim()!=="default"?i.sandboxMode.trim():void 0,this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof be?i.bindingStore:null,this.model=i.model,this.collaborationMode=i.collaborationMode,this.reasoningEffort=i.reasoningEffort,this.serviceTier=i.serviceTier,this.bindingStore&&this.aibotSessionId&&(this.model=this.model??this.bindingStore.getCodexModelId(this.aibotSessionId),this.collaborationMode=this.collaborationMode??this.bindingStore.getCodexModeId(this.aibotSessionId),this.reasoningEffort=this.reasoningEffort??this.bindingStore.getCodexReasoningEffort(this.aibotSessionId),this.serviceTier=this.serviceTier??this.bindingStore.getCodexServiceTier(this.aibotSessionId),this.sandboxMode=this.sandboxMode??this.bindingStore.getCodexSandboxMode(this.aibotSessionId)),this.autoTrustProject=typeof i.autoTrustProject=="boolean"?i.autoTrustProject:"auto",this.codexHome=typeof i.codexHome=="string"&&i.codexHome.trim()?i.codexHome.trim():void 0;const s=i.codexDirect;if(this.codexDirect=s&&typeof s=="object"&&!Array.isArray(s)?s:null,this.configOverrideArgs=te(i.codexConfigOverrides,"codexConfigOverrides"),this.rawCaptureOptions=Je(i.rawApiCapture),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const n=this.bindingStore.getCodexThreadId(this.aibotSessionId);n&&(this.threadId=n,this.threadResumePending=!0)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){await this.prepareDirectHome(),await this.ensureProjectTrusted(),await this.prepareRawApiCapture();try{await this.startInternalApiAndRegisterMcp(),await this.spawnCodex(),await this.initializeHandshake(),await this.notifyBindingReadyWithContext(),d.info("codex-adapter",`Ready (pid=${this.process?.pid})`)}catch(e){throw await this.stopRawApiCapture(),e}}async prepareRawApiCapture(){if(this.rawCaptureOptions)try{const e=await Fe(this.rawCaptureOptions,{adapterType:"codex",sessionId:this.rawCaptureOptions.sessionId,cwd:this.cwd,env:this.resolveChildEnv(),configOverrides:this.configOverrideArgs,codexHome:this.codexHome});this.rawCaptureRelay=e.relay,this.rawCaptureConfigOverrides=e.overlay.configOverrides??[],this.rawCaptureUnavailableReason=void 0,d.info("codex-adapter","Raw API audit capture relay is ready")}catch(e){this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],this.rawCaptureUnavailableReason=e instanceof Error?e.message:String(e),d.warn("codex-adapter",`Raw API audit capture unavailable: ${this.rawCaptureUnavailableReason}`)}}async stopRawApiCapture(){const e=this.rawCaptureRelay;this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],e&&await e.stop()}async prepareDirectHome(){if(!this.codexDirect)return;const e=await Re(this.codexDirect);this.codexHome=e.codexHome,this.directEnv=e.env;const t=te(e.configOverrides,"codexDirect.configOverrides");this.configOverrideArgs=[...this.configOverrideArgs,...t],d.info("codex-adapter",`Codex direct home ready: ${e.codexHome} (catalog=${e.catalogVersion??"none"}, token=${e.tokenDigest?`present sha256:${e.tokenDigest}`:"absent"})`)}resolveChildEnv(){const e={...process.env,...this.config.env};return this.codexHome&&(e.CODEX_HOME=this.codexHome),e}async ensureProjectTrusted(){if(this.shouldAutoTrustProject())try{const e=await Ae(this.cwd,{codexHome:this.codexHome});e.changed&&d.info("codex-adapter",`Trusted Codex project ${this.cwd} in ${e.configPath}`)}catch(e){const t=e instanceof Error?e.message:String(e);throw d.error("codex-adapter",`Failed to trust Codex project ${this.cwd}: ${t}`),e}}async startInternalApiAndRegisterMcp(){try{this.internalApi=new ye,this.internalApi.setInvokeHandler(async(o,c,h,p)=>this.callbacks.agentInvoke(o,c,p)),await this.internalApi.start(0),d.info("codex-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t=this.resolveChildEnv(),i=typeof t.PATH=="string"?t.PATH:void 0,s=ae(this.config.command||"codex",i);for(const o of[..._e,e.name])try{Y(s,["mcp","remove",o],{env:t,timeout:1e4,stdio:"ignore"})}catch{}Y(s,["mcp","add",e.name,"--",e.command,...e.args],{env:t,timeout:1e4,stdio:"ignore"}),d.info("codex-adapter",`Registered MCP server: ${e.name}`);const n=P(Se(this.codexHome),"skills"),r=ge(n);r.length>0&&d.info("codex-adapter",`Synced connector skills to ${n}: [${r.join(", ")}]`)}catch(e){d.warn("codex-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}shouldAutoTrustProject(){return this.autoTrustProject===!1?!1:this.autoTrustProject===!0?!0:Ee(this.config.command)}notifyBindingReady(){!this.aibotSessionId||!this.cwd||this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd)}async notifyBindingReadyWithContext(){if(!(!this.aibotSessionId||!this.cwd))try{this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,await this.buildToolbarContextResult("binding_ready"))}catch(e){d.warn("codex-adapter",`Failed to attach toolbar context to binding update: ${e instanceof Error?e.message:String(e)}`),this.notifyBindingReady()}}scheduleToolbarContextPush(){this.notifyBindingReadyWithContext()}externalProviderCheckedAt=0;externalProviderCached=!1;static EXTERNAL_PROVIDER_CACHE_TTL_MS=60*1e3;isExternalProvider(){const e=Date.now();if(e-this.externalProviderCheckedAt<D.EXTERNAL_PROVIDER_CACHE_TTL_MS)return this.externalProviderCached;const t=F(this.codexHome);return this.externalProviderCached=!!(t.baseUrl&&ce(t.baseUrl)),this.externalProviderCheckedAt=e,this.externalProviderCached}effectiveServiceTier(){if(!this.serviceTier||this.serviceTier.trim().toLowerCase()==="default"||this.isExternalProvider())return;const e=this.getModelOption(this.currentModelId());if(!(e&&!e.serviceTiers.some(t=>t.id===this.serviceTier)))return this.serviceTier}resolveReasoningEffortForModel(e,t,i={}){const s=String(e??"").trim();if(!s||this.isExternalProvider())return;const n=this.getModelOption(t),r=n?.supportedReasoningEfforts??[];if(r.length===0)return;const o=r.find(c=>c.trim().toLowerCase()===s.toLowerCase());if(o)return o;if(!i.strict&&["max","ultra"].includes(s.toLowerCase())){const c=r.find(h=>h.trim().toLowerCase()==="xhigh");if(c)return c}return i.strict?void 0:n?.defaultReasoningEffort??void 0}effectiveReasoningEffort(){return this.resolveReasoningEffortForModel(this.reasoningEffort,this.currentModelId())}getEffortMeta(){if(this.isExternalProvider())return{};const e=this.currentModelId(),t=this.getModelOption(e),i={},s=t?.supportedReasoningEfforts??[];s.length>0&&(i.available_efforts=s,i.reasoning_effort=this.effectiveReasoningEffort()??t?.defaultReasoningEffort??null);const n=t?.serviceTiers??[];return n.length>0&&(i.available_service_tiers=n,i.service_tier=this.effectiveServiceTier()??t?.defaultServiceTier??null),i}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.rejectAllPending("adapter stopped"),this.pendingAutoCompact=!1,this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);for(const t of this.compactionDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");for(const t of this.steerDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");this.internalApi&&(await this.internalApi.stop(),this.internalApi=null);const e=this.process;if(this.process=null,e?.pid&&typeof e.once=="function")Q(e,"SIGTERM"),await Promise.race([new Promise(i=>{e.once("exit",()=>i(!0))}),new Promise(i=>{setTimeout(()=>i(!1),5e3)})])||Q(e,"SIGKILL");else if(e)try{e.kill("SIGTERM")}catch{}await this.stopRawApiCapture()}isAlive(){return this.alive}async createSession(e){if(this.initialized||await this.initializeHandshake(),this.threadId||await this.startNewThread(),!this.threadId)throw new Error("Failed to create session: thread ID is missing");return await this.notifyBindingReadyWithContext(),this.threadId}async resumeSession(e,t){await this.ensureThreadResumed()}async destroySession(e){this.threadId=null,this.threadResumePending=!1,this.persistThreadId(void 0),this.inboundMessageIds.reset()}sendPrompt(e){const t=new z(e.adapterSessionId);return this.runTurn(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){if(this.threadId)try{await this.sendRequest("turn/interrupt",{threadId:this.threadId,turnId:this.currentTurnId??""},5e3)}catch{}}setPermissionHandler(e){this.permissionHandler=e}permissionHandler=null;async ping(e){if(!this.alive||!this.process)return!1;if(!this.process.pid){const t=!!(this.process.stdin&&!this.process.stdin.destroyed),i=!!(this.process.stdout&&!this.process.stdout.destroyed);return t&&i}if(!this.process.stdin||this.process.stdin.destroyed)return!!(this.process.stdout&&!this.process.stdout.destroyed);try{const t=++this.requestId,i={jsonrpc:"2.0",id:t,method:"ping",params:{}};return await new Promise(s=>{const n=setTimeout(()=>{this.pendingRequests.delete(String(t)),s(!1)},e);this.pendingRequests.set(String(t),{resolve:()=>s(!0),reject:()=>s(!1),timer:n}),this.process.stdin.write(`${JSON.stringify(i)}
|
|
2
|
+
\u2026(truncated)`,re=80,Ze=120*1e3,Qe=j("GRIX_CODEX_DELTA_COALESCE_MS",1e3),et=j("GRIX_CODEX_DELTA_COALESCE_CHARS",4096),tt=[{id:"gpt-5.3-codex",displayName:"GPT-5.3 Codex",defaultReasoningEffort:null,supportedReasoningEfforts:[],defaultServiceTier:null,serviceTiers:[],isDefault:!0}],oe=[{id:"default",displayName:"Default"},{id:"plan",displayName:"Plan"}],it=new Set(["rawResponse/completed","codex/rawResponse/completed","rawResponseItem/completed","codex/rawResponseItem/completed","thread/tokenUsage/updated","codex/thread/tokenUsage/updated","thread/compacted","codex/thread/compacted","turn/started","codex/turn/started","turn/completed","codex/turn/completed","item/started","codex/item/started","item/completed","codex/item/completed","error","codex/error"]);function ae(a,e){const t=String(a??"").trim()||"codex",i=ve(t,e);if(i!==t)return i;if(t!=="codex")return t;const s=process.platform==="win32"?[]:["/opt/homebrew/bin/codex","/usr/local/bin/codex","/usr/bin/codex"],n=process.platform!=="win32"?[]:[P(process.env.LOCALAPPDATA??"","npm","codex.cmd"),P(process.env.APPDATA??"","npm","codex.cmd"),P(process.env.LOCALAPPDATA??"","Programs","codex","codex.exe")],r=[...s,...n];for(const o of r)try{return require("node:fs").accessSync(o,require("node:fs").constants.X_OK),o}catch{continue}return d.warn("codex-adapter",`resolveCodexCommandPath: failed to resolve "${t}". envPath=${e?"provided":"missing (using process.env.PATH)"}. fallbacks tried: [${r.join(", ")}]`),t}class D extends K{type="codex";config;callbacks;process=null;alive=!1;stopped=!1;internalApi=null;bridgeStatus="starting";pendingRequests=new Map;requestId=0;threadId=null;initialized=!1;cwd;approvalPolicy;sandboxMode;model;collaborationMode;reasoningEffort;serviceTier;idleTimer=null;lastProgressAt=0;lastIdleCheckAt=0;activityGeneration=0;lastIdleCheckGeneration=0;idleNoProgressCount=0;inFlightToolOps=0;consecutivePingFailures=0;currentTurnStartedAt=0;preflightCheckComplete=!1;turnInactivityTimeoutMs=Xe("GRIX_CODEX_TURN_INACTIVITY_TIMEOUT_MS");pendingApprovals=new Map;needsHistoryInjection=!1;lastInjectedSessionId=null;identityInputInjectedThreadId=null;inboundMessageIds=new Ce;legacyDeveloperInstructionsUnsupported=!1;profileIdentityRefreshPending=!1;bindingStore=null;aibotSessionId="";threadResumePending=!1;autoTrustProject="auto";codexHome;codexDirect=null;directEnv={};configOverrideArgs=[];rawCaptureOptions;rawCaptureRelay;rawCaptureConfigOverrides=[];rawCaptureUnavailableReason;codexModelOptions=[];codexModelOptionsCachedAt=0;static MODEL_CACHE_TTL_MS=3600*1e3;rateLimitSnapshot=null;lastNonDefaultLimitRefreshAt=0;static NON_DEFAULT_LIMIT_REFRESH_INTERVAL_MS=6e4;currentThreadTokenUsage=null;currentModelContextWindow=null;auditCaptureByEventId=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const i=e.options??{};this.approvalPolicy=i.approvalPolicy??"never",this.sandboxMode=typeof i.sandboxMode=="string"&&i.sandboxMode.trim()&&i.sandboxMode.trim()!=="default"?i.sandboxMode.trim():void 0,this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof be?i.bindingStore:null,this.model=i.model,this.collaborationMode=i.collaborationMode,this.reasoningEffort=i.reasoningEffort,this.serviceTier=i.serviceTier,this.bindingStore&&this.aibotSessionId&&(this.model=this.model??this.bindingStore.getCodexModelId(this.aibotSessionId),this.collaborationMode=this.collaborationMode??this.bindingStore.getCodexModeId(this.aibotSessionId),this.reasoningEffort=this.reasoningEffort??this.bindingStore.getCodexReasoningEffort(this.aibotSessionId),this.serviceTier=this.serviceTier??this.bindingStore.getCodexServiceTier(this.aibotSessionId),this.sandboxMode=this.sandboxMode??this.bindingStore.getCodexSandboxMode(this.aibotSessionId)),this.autoTrustProject=typeof i.autoTrustProject=="boolean"?i.autoTrustProject:"auto",this.codexHome=typeof i.codexHome=="string"&&i.codexHome.trim()?i.codexHome.trim():void 0;const s=i.codexDirect;if(this.codexDirect=s&&typeof s=="object"&&!Array.isArray(s)?s:null,this.configOverrideArgs=te(i.codexConfigOverrides,"codexConfigOverrides"),this.rawCaptureOptions=Je(i.rawApiCapture),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const n=this.bindingStore.getCodexThreadId(this.aibotSessionId);n&&(this.threadId=n,this.threadResumePending=!0)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){await this.prepareDirectHome(),await this.ensureProjectTrusted(),await this.prepareRawApiCapture();try{await this.startInternalApiAndRegisterMcp(),await this.spawnCodex(),await this.initializeHandshake(),await this.notifyBindingReadyWithContext(),d.info("codex-adapter",`Ready (pid=${this.process?.pid})`)}catch(e){throw await this.stopRawApiCapture(),e}}async prepareRawApiCapture(){if(this.rawCaptureOptions)try{const e=await Fe(this.rawCaptureOptions,{adapterType:"codex",sessionId:this.rawCaptureOptions.sessionId,cwd:this.cwd,env:this.resolveChildEnv(),configOverrides:this.configOverrideArgs,codexHome:this.codexHome});this.rawCaptureRelay=e.relay,this.rawCaptureConfigOverrides=e.overlay.configOverrides??[],this.rawCaptureUnavailableReason=void 0,d.info("codex-adapter","Raw API audit capture relay is ready")}catch(e){this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],this.rawCaptureUnavailableReason=e instanceof Error?e.message:String(e),d.warn("codex-adapter",`Raw API audit capture unavailable: ${this.rawCaptureUnavailableReason}`)}}async stopRawApiCapture(){const e=this.rawCaptureRelay;this.rawCaptureRelay=void 0,this.rawCaptureConfigOverrides=[],e&&await e.stop()}async prepareDirectHome(){if(!this.codexDirect)return;const e=await Re(this.codexDirect);this.codexHome=e.codexHome,this.directEnv=e.env;const t=te(e.configOverrides,"codexDirect.configOverrides");this.configOverrideArgs=[...this.configOverrideArgs,...t],d.info("codex-adapter",`Codex direct home ready: ${e.codexHome} (catalog=${e.catalogVersion??"none"}, token=${e.tokenDigest?`present sha256:${e.tokenDigest}`:"absent"})`)}resolveChildEnv(){const e={...process.env,...this.config.env};return this.codexHome&&(e.CODEX_HOME=this.codexHome),e}async ensureProjectTrusted(){if(this.shouldAutoTrustProject())try{const e=await Ae(this.cwd,{codexHome:this.codexHome});e.changed&&d.info("codex-adapter",`Trusted Codex project ${this.cwd} in ${e.configPath}`)}catch(e){const t=e instanceof Error?e.message:String(e);throw d.error("codex-adapter",`Failed to trust Codex project ${this.cwd}: ${t}`),e}}async startInternalApiAndRegisterMcp(){try{this.internalApi=new ye,this.internalApi.setInvokeHandler(async(o,c,h,p)=>this.callbacks.agentInvoke(o,c,p)),await this.internalApi.start(0),d.info("codex-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t=this.resolveChildEnv(),i=typeof t.PATH=="string"?t.PATH:void 0,s=ae(this.config.command||"codex",i);for(const o of[..._e,e.name])try{Y(s,["mcp","remove",o],{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0})}catch{}Y(s,["mcp","add",e.name,"--",e.command,...e.args],{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0}),d.info("codex-adapter",`Registered MCP server: ${e.name}`);const n=P(Se(this.codexHome),"skills"),r=ge(n);r.length>0&&d.info("codex-adapter",`Synced connector skills to ${n}: [${r.join(", ")}]`)}catch(e){d.warn("codex-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}shouldAutoTrustProject(){return this.autoTrustProject===!1?!1:this.autoTrustProject===!0?!0:Ee(this.config.command)}notifyBindingReady(){!this.aibotSessionId||!this.cwd||this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd)}async notifyBindingReadyWithContext(){if(!(!this.aibotSessionId||!this.cwd))try{this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,await this.buildToolbarContextResult("binding_ready"))}catch(e){d.warn("codex-adapter",`Failed to attach toolbar context to binding update: ${e instanceof Error?e.message:String(e)}`),this.notifyBindingReady()}}scheduleToolbarContextPush(){this.notifyBindingReadyWithContext()}externalProviderCheckedAt=0;externalProviderCached=!1;static EXTERNAL_PROVIDER_CACHE_TTL_MS=60*1e3;isExternalProvider(){const e=Date.now();if(e-this.externalProviderCheckedAt<D.EXTERNAL_PROVIDER_CACHE_TTL_MS)return this.externalProviderCached;const t=F(this.codexHome);return this.externalProviderCached=!!(t.baseUrl&&ce(t.baseUrl)),this.externalProviderCheckedAt=e,this.externalProviderCached}effectiveServiceTier(){if(!this.serviceTier||this.serviceTier.trim().toLowerCase()==="default"||this.isExternalProvider())return;const e=this.getModelOption(this.currentModelId());if(!(e&&!e.serviceTiers.some(t=>t.id===this.serviceTier)))return this.serviceTier}resolveReasoningEffortForModel(e,t,i={}){const s=String(e??"").trim();if(!s||this.isExternalProvider())return;const n=this.getModelOption(t),r=n?.supportedReasoningEfforts??[];if(r.length===0)return;const o=r.find(c=>c.trim().toLowerCase()===s.toLowerCase());if(o)return o;if(!i.strict&&["max","ultra"].includes(s.toLowerCase())){const c=r.find(h=>h.trim().toLowerCase()==="xhigh");if(c)return c}return i.strict?void 0:n?.defaultReasoningEffort??void 0}effectiveReasoningEffort(){return this.resolveReasoningEffortForModel(this.reasoningEffort,this.currentModelId())}getEffortMeta(){if(this.isExternalProvider())return{};const e=this.currentModelId(),t=this.getModelOption(e),i={},s=t?.supportedReasoningEfforts??[];s.length>0&&(i.available_efforts=s,i.reasoning_effort=this.effectiveReasoningEffort()??t?.defaultReasoningEffort??null);const n=t?.serviceTiers??[];return n.length>0&&(i.available_service_tiers=n,i.service_tier=this.effectiveServiceTier()??t?.defaultServiceTier??null),i}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.rejectAllPending("adapter stopped"),this.pendingAutoCompact=!1,this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);for(const t of this.compactionDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");for(const t of this.steerDeferred.splice(0))this.sendEventResultAfterFlushing(t.event_id,"failed","adapter stopped");this.internalApi&&(await this.internalApi.stop(),this.internalApi=null);const e=this.process;if(this.process=null,e?.pid&&typeof e.once=="function")Q(e,"SIGTERM"),await Promise.race([new Promise(i=>{e.once("exit",()=>i(!0))}),new Promise(i=>{setTimeout(()=>i(!1),5e3)})])||Q(e,"SIGKILL");else if(e)try{e.kill("SIGTERM")}catch{}await this.stopRawApiCapture()}isAlive(){return this.alive}async createSession(e){if(this.initialized||await this.initializeHandshake(),this.threadId||await this.startNewThread(),!this.threadId)throw new Error("Failed to create session: thread ID is missing");return await this.notifyBindingReadyWithContext(),this.threadId}async resumeSession(e,t){await this.ensureThreadResumed()}async destroySession(e){this.threadId=null,this.threadResumePending=!1,this.persistThreadId(void 0),this.inboundMessageIds.reset()}sendPrompt(e){const t=new z(e.adapterSessionId);return this.runTurn(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){if(this.threadId)try{await this.sendRequest("turn/interrupt",{threadId:this.threadId,turnId:this.currentTurnId??""},5e3)}catch{}}setPermissionHandler(e){this.permissionHandler=e}permissionHandler=null;async ping(e){if(!this.alive||!this.process)return!1;if(!this.process.pid){const t=!!(this.process.stdin&&!this.process.stdin.destroyed),i=!!(this.process.stdout&&!this.process.stdout.destroyed);return t&&i}if(!this.process.stdin||this.process.stdin.destroyed)return!!(this.process.stdout&&!this.process.stdout.destroyed);try{const t=++this.requestId,i={jsonrpc:"2.0",id:t,method:"ping",params:{}};return await new Promise(s=>{const n=setTimeout(()=>{this.pendingRequests.delete(String(t)),s(!1)},e);this.pendingRequests.set(String(t),{resolve:()=>s(!0),reject:()=>s(!1),timer:n}),this.process.stdin.write(`${JSON.stringify(i)}
|
|
3
3
|
`)})}catch{return!1}}getStatus(){return{alive:this.alive,busy:this.currentTurnId!==null||this.compacting,sessions:this.threadId?1:0}}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}clearActiveEventForShutdown(){this.clearIdleTimer(),this.clearCodexDeltaBuffer(),this.activeEventId=null}setModel(e){this.model=e,this.reasoningEffort=this.resolveReasoningEffortForModel(this.reasoningEffort,this.currentModelId()),this.persistCodexContext(),d.info("codex-adapter",`Model set to: ${e}`),this.scheduleToolbarContextPush()}setMode(e){const t=k(e);if(!t){d.info("codex-adapter",`Ignoring unsupported mode: ${e}`);return}this.collaborationMode=t,this.persistCodexContext(),d.info("codex-adapter",`Mode set to: ${t}`),this.scheduleToolbarContextPush()}setReasoningEffort(e){const t=this.resolveReasoningEffortForModel(e,this.currentModelId(),{strict:!0});if(!t){d.info("codex-adapter",`Ignoring unsupported reasoning effort for ${this.currentModelId()}: ${e}`);return}this.reasoningEffort=t,this.persistCodexContext(),d.info("codex-adapter",`Reasoning effort set to: ${t}`)}setServiceTier(e){const t=e.trim();this.serviceTier=t.toLowerCase()==="default"?"default":t,this.persistCodexContext(),d.info("codex-adapter",`Service tier set to: ${this.serviceTier}`)}setSandboxMode(e){this.sandboxMode=e,this.persistCodexContext(),d.info("codex-adapter",`Sandbox mode set to: ${e} (applied on next restart)`)}async threadCompact(){if(!this.threadId)throw new Error("No active thread");return this.sendRequest("thread/compact/start",{threadId:this.threadId},12e4)}async threadRollback(e){if(!this.threadId)throw new Error("No active thread");return this.sendRequest("thread/rollback",{threadId:this.threadId,numTurns:e},1e4)}getThreadId(){return this.threadId}hasRawApiCaptureRelay(){return!!this.rawCaptureRelay}enableAuditCapture(e,t={}){const i=e.trim();if(!i||this.auditCaptureByEventId.has(i))return;const s=t.rawProviderBody??!!this.rawCaptureOptions;this.auditCaptureByEventId.set(i,{threadId:this.threadId??void 0,modelId:this.currentModelId()??void 0,rawProviderBody:s,sequence:0,events:[]}),s&&this.rawCaptureRelay?.beginEvent(i,t.auditId)}takeAuditBoundary(e){const t=this.auditCaptureByEventId.get(e);if(t)return this.auditCaptureByEventId.delete(e),{adapterType:this.type,providerTurnId:t.providerTurnId,threadId:t.threadId??this.threadId??void 0,codexEvidence:{events:t.events,...t.modelId?{modelId:t.modelId}:{},...t.rawProviderBody?{rawApiCapture:this.rawCaptureRelay?this.rawCaptureRelay.takeEvent(e):qe(this.rawCaptureUnavailableReason??"raw_capture_relay_not_prepared_before_adapter_start")}:{}}}}getMcpConfig(){if(!this.internalApi)return null;const e=pe(me(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:we(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async hasBackgroundWork(){const e=this.process?.pid;return e?xe(e,[e]):!1}onAgentProfileChanged(){this.threadId&&(this.profileIdentityRefreshPending=!0,this.identityInputInjectedThreadId=null,d.info("codex-adapter",`agent profile changed; scheduling identity refresh for thread=${this.threadId}`))}async probe(e){const t=this.config.command||"codex",i=await De(t),s=i!==null;let n=null,r;if(s){const y=await $e(t);n=y.version,y.error&&(r=y.error)}else r={code:"cli_not_found",message:`command not found: ${t}`};const c=F(this.codexHome).baseUrl??null,h=this.currentModelId()||null,p=this.getStatus(),f=e?.conversation?{attempted:!0,ok:!1,latency_ms:null,error:{code:"unsupported",message:"codex does not support minimal prompt probe"}}:{attempted:!1,ok:!1,latency_ms:null},g=await this.probeSessionRecord(),x=ee({codexHome:this.codexHome});return{cli:{command:t,installed:s,path:i,version:n,...r?{error:r}:{}},conversation:f,config:{model:h,base_url:c,source:{model:h?"runtime":"unknown",base_url:c?"file":"unknown"}},process:{started:!!this.process,alive:p.alive,busy:p.busy},session:g,lock:{present:x.present,locked:x.locked,stale:x.stale,path:x.path}}}async probeSessionRecord(){const e=this.threadId?Pe(this.threadId,this.codexHome):null;if(!e)return{recordPath:null,lastActivityMs:null,freshMs:null};try{const t=await Z(e);return{recordPath:e,lastActivityMs:t.mtimeMs,freshMs:Date.now()-t.mtimeMs}}catch{return{recordPath:e,lastActivityMs:null,freshMs:null}}}getSupportedCommands(){return[{name:"compact",description:"Compact thread to reduce context size"},{name:"model",description:"List or set model",args:"[model_id]"},{name:"mode",description:"List or set collaboration mode",args:"[default|plan]"},{name:"rollback",description:"Roll back thread turns",args:"[num_turns]"},{name:"interrupt",description:"Interrupt current turn"},{name:"rate_limits",description:"Show current rate limits"},{name:"status",description:"Show thread and session status"},{name:"skills",description:"List available skills"}]}async execCommand(e,t,i){try{switch(e){case"compact":{if(!this.threadId)return{status:"failed",message:"No active thread"};if(this.compacting)return{status:"failed",message:"Compaction already in progress"};if(this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","compacting"),this.clearActive()),await this.ensureThreadResumed(),this.currentTurnId)return{status:"failed",message:"agent busy"};if(this.needsHistoryInjection)return{status:"failed",message:"The session has expired and there is no history to compact. Please send a new message and try again."};this.compacting=!0;const s=new Promise(n=>{this.compactionDoneResolver=n});try{return await this.threadCompact(),this.armCompactionFallback(),await s,{status:"ok",message:"Thread compacted"}}catch(n){this.finishCompaction("compact-error");const r=n instanceof Error?n.message:String(n);if(/thread.*(not found|not exist|unknown|invalid)/i.test(r)||/not found.*thread/i.test(r))return this.threadId=null,this.persistThreadId(void 0),{status:"failed",message:"The session has expired and there is no history to compact. Please send a new message and try again."};throw n}}case"model":{const s=t.trim();return s?this.getModelOptions().some(r=>r.id===s)?(this.setModel(s),{status:"ok",message:`Model set to ${s}`}):{status:"failed",message:`Unknown model: ${s}`}:{status:"ok",message:`Current: ${this.currentModelId()}`,data:{models:this.getModelOptions()}}}case"mode":{const s=t.trim();if(s){const n=k(s);return n?(this.setMode(n),{status:"ok",message:`Mode set to ${n}`}):{status:"failed",message:`Unknown mode: ${s}. Supported: default, plan`}}return{status:"ok",message:`Current: ${this.collaborationMode??"default"}`,data:{modes:oe}}}case"rollback":{if(!this.threadId)return{status:"failed",message:"No active thread"};const s=Math.max(1,parseInt(t.trim(),10)||1);return this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","rolled back"),this.clearActive()),await this.threadRollback(s),{status:"ok",message:`Rolled back ${s} turn(s)`}}case"interrupt":return this.threadId?(await this.cancel(this.threadId),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","interrupted"),this.clearActive(),{status:"ok",message:"Turn interrupted"}):{status:"failed",message:"No active thread"};case"rate_limits":return{status:"ok",message:this.rateLimitSnapshot?`Primary: ${this.rateLimitSnapshot.primary.usedPercent.toFixed(1)}%, Secondary: ${this.rateLimitSnapshot.secondary.usedPercent.toFixed(1)}%`:"Rate limits not available",data:{rateLimits:this.rateLimitSnapshot}};case"status":return{status:"ok",message:`Thread: ${this.threadId??"none"}, Model: ${this.currentModelId()}, Mode: ${this.collaborationMode??"default"}`,data:{threadId:this.threadId,model:this.currentModelId(),mode:this.collaborationMode??"default",cwd:this.cwd,alive:this.alive}};case"skills":{const s=Oe({mode:"codex",projectDir:this.cwd}),n=s.map(r=>`- ${r.name}${r.trigger?` (${r.trigger})`:""}: ${r.description}`);return{status:"ok",message:n.length>0?n.join(`
|
|
4
4
|
`):"No skills found",data:s}}default:return{status:"unsupported",message:`Unknown command: ${e}`}}}catch(s){return{status:"failed",message:s instanceof Error?s.message:String(s)}}}async handleLocalAction(e){const t=e.action_type??"",i=e.params??{};switch(d.info("codex-adapter",`handleLocalAction action_type=${t} action_id=${e.action_id} session_id=${i.session_id??""}`),t){case"set_model":{const s=I(u(i.model_id),u(i.modelId),u(i.value));return s&&this.setModel(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("model_set")),{handled:!0,kind:"set_model"}}case"set_mode":{const s=i.mode_id;return s&&this.setMode(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("mode_set")),{handled:!0,kind:"set_mode"}}case"set_reasoning_effort":{const s=I(u(i.reasoning_effort),u(i.reasoning_eff),u(i.effort)),n=this.resolveReasoningEffortForModel(s,this.currentModelId(),{strict:!0});if(!n){const r=this.getModelOption(this.currentModelId())?.supportedReasoningEfforts??[];return this.callbacks.sendLocalActionResult(e.action_id,"failed",{outcome:"effort_rejected",model_id:this.currentModelId(),available_efforts:r},"unsupported_reasoning_effort",r.length>0?`reasoning_effort must be one of: ${r.join(", ")}`:`reasoning_effort is not supported by model ${this.currentModelId()}`),{handled:!0,kind:"set_reasoning_effort_rejected"}}return this.setReasoningEffort(n),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("effort_set",!1)),{handled:!0,kind:"set_reasoning_effort"}}case"set_service_tier":{const s=I(u(i.service_tier),u(i.serviceTier),u(i.value));return s&&this.setServiceTier(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("service_tier_set",!1)),{handled:!0,kind:"set_service_tier"}}case"set_sandbox_mode":{const s=I(u(i.sandbox_mode),u(i.sandboxMode),u(i.value));return s&&this.setSandboxMode(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",await this.buildToolbarContextResult("sandbox_mode_set",!1)),{handled:!0,kind:"set_sandbox_mode"}}case"thread_compact":{d.info("codex-adapter",`thread_compact start action_id=${e.action_id} threadId=${this.threadId}`),this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","compacting"),this.clearActive());try{if(await this.ensureThreadResumed(),this.needsHistoryInjection)return d.info("codex-adapter",`thread_compact aborted: thread expired, new thread created action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"thread_expired","The session has expired and there is no history to compact. Please send a new message and try again."),{handled:!0,kind:"thread_compact"};this.compacting=!0;const s=new Promise(n=>{this.compactionDoneResolver=n});await this.threadCompact(),this.armCompactionFallback(),await s,d.info("codex-adapter",`thread_compact done action_id=${e.action_id}`),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(s){this.finishCompaction("compact-error");const n=s instanceof Error?s.message:String(s);/thread.*(not found|not exist|unknown|invalid)/i.test(n)||/not found.*thread/i.test(n)?(d.warn("codex-adapter",`thread_compact thread expired, resetting threadId action_id=${e.action_id} err=${n}`),this.threadId=null,this.persistThreadId(void 0),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"thread_expired","The session has expired and there is no history to compact. Please send a new message and try again.")):(d.info("codex-adapter",`thread_compact failed action_id=${e.action_id} err=${n}`),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,n))}return{handled:!0,kind:"thread_compact"}}case"get_context":return this.callbacks.sendLocalActionResult(e.action_id,"ok",{threadId:this.threadId,model:this.model,mode:this.collaborationMode,approvalPolicy:this.approvalPolicy,cwd:this.cwd,...await this.buildToolbarContextResult("context")}),{handled:!0,kind:"get_context"};case"exec_approve":case"file_approve":{const s=this.resolvePendingApproval(e);if(!s)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:t};const n=i.decision||"allow-once",r=st[n]??"accept";return this.sendApprovalDecision(s.requestId,r),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,approval_command_id:s.approvalCommandId,decision:n}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t}}case"exec_reject":case"file_reject":{const s=this.resolvePendingApproval(e);return s?(this.sendApprovalDecision(s.requestId,"deny"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,approval_command_id:s.approvalCommandId,decision:"deny"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t}):(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That approval request is no longer pending."),{handled:!0,kind:t})}case"permission_approve":{const s=this.resolvePendingApproval(e);return!s||s.kind!=="permission"?(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That permission approval request is no longer pending."),{handled:!0,kind:t}):(this.sendApprovalDecision(s.requestId,"accept"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,decision:"approve"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t})}case"permission_reject":{const s=this.resolvePendingApproval(e);return!s||s.kind!=="permission"?(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"unknown_or_expired_approval_id","That permission approval request is no longer pending."),{handled:!0,kind:t}):(this.sendApprovalDecision(s.requestId,"deny"),this.pendingApprovals.delete(s.approvalId),this.callbacks.sendLocalActionResult(e.action_id,"ok",{approval_id:s.approvalId,decision:"deny"}),this.resumeAfterApproval(e,i,s),{handled:!0,kind:t})}case"turn_interrupt":{try{await this.cancel(this.threadId??""),this.callbacks.sendLocalActionResult(e.action_id,"ok")}catch(s){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,s instanceof Error?s.message:String(s))}return{handled:!0,kind:"turn_interrupt"}}case"thread_rollback":{const s=Number(i.numTurns??i.num_turns??1);if(!this.threadId)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"no_thread","No active thread"),{handled:!0,kind:"thread_rollback"};this.currentTurnId&&(await this.cancel(this.threadId).catch(()=>{}),this.activeEventId&&this.sendEventResultAfterFlushing(this.activeEventId,"canceled","rolled back"),this.clearActive());try{await this.threadRollback(s),this.callbacks.sendLocalActionResult(e.action_id,"ok",{numTurns:s})}catch(n){this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,void 0,n instanceof Error?n.message:String(n))}return{handled:!0,kind:"thread_rollback"}}case"get_rate_limits":{const s=this.rateLimitSnapshot,n=this.buildContextWindowSnapshot(),r=Date.now(),o=this.currentThreadTokenUsage;return s?d.info("codex-adapter",`[rate-limits] responding: primary=${s.primary.usedPercent.toFixed(1)}% window=${s.primary.windowMinutes}min resetsAt=${s.primary.resetsAt} secondary=${s.secondary.usedPercent.toFixed(1)}% window=${s.secondary.windowMinutes}min resetsAt=${s.secondary.resetsAt}`):d.info("codex-adapter","[rate-limits] responding: no rateLimitSnapshot available"),d.debug("codex-adapter",`[cp-diagnose] get_rate_limits: threadId=${this.threadId??"-"} contextWindow=${JSON.stringify(n)} tokenUsage=${JSON.stringify(o)}`),this.callbacks.sendLocalActionResult(e.action_id,"ok",{adapterType:"codex",available:s!==null,cached:!1,sampledAt:r,rateLimits:s,contextWindow:n,tokenUsage:o}),{handled:!0,kind:"get_rate_limits"}}default:return{handled:!1,kind:""}}}async buildToolbarContextResult(e,t=!0){t&&await this.refreshCodexModelOptions();const i=k(this.collaborationMode)??"default",s=this.currentModelId(),n=this.getModelOption(s),r=this.getModelOptions(),o=oe,c=this.effectiveReasoningEffort()??n?.defaultReasoningEffort??null,h=n?.supportedReasoningEfforts??[],p=this.effectiveServiceTier()??n?.defaultServiceTier??null,f=n?.serviceTiers??[],g=this.isExternalProvider(),x=g?[]:h,y=g?null:c,S=g?[]:f,R=g?null:p,C={outcome:e,session_context:{modelId:s,modeId:i,reasoningEffort:y,serviceTier:R,approvalPolicy:this.approvalPolicy,sandboxMode:this.sandboxMode??null},model_id:s,mode_id:i,currentModelId:s,currentModeId:i,available_models:r,available_modes:o,available_efforts:x,availableModels:r,availableModes:o,reasoning_effort:y,available_service_tiers:S,service_tier:R,sandbox_mode:this.sandboxMode??null,models:r.map(w=>({modelId:w.id,name:w.displayName})),modes:o.map(w=>({id:w.id,name:w.displayName}))};return this.rateLimitSnapshot&&(C.rate_limit_primary_percent=this.rateLimitSnapshot.primary.usedPercent,C.rate_limit_secondary_percent=this.rateLimitSnapshot.secondary.usedPercent,C.rate_limit_primary_window_min=this.rateLimitSnapshot.primary.windowMinutes,C.rate_limit_secondary_window_min=this.rateLimitSnapshot.secondary.windowMinutes),C}currentModelId(){const e=String(this.model??"").trim();if(e)return e;const t=this.getModelOptions();return t.find(i=>i.isDefault)?.id??t[0]?.id??""}getModelOption(e){const t=e.trim().toLowerCase();return this.getModelOptions().find(i=>i.id.trim().toLowerCase()===t)}getModelOptions(){const e=this.config.options??{},t=e.available_models??e.availableModels??e.models,i=ct(t),s=this.codexModelOptions,n=[],r=String(this.model??"").trim(),o=r&&!s.some(f=>f.id.trim().toLowerCase()===r.toLowerCase()),c=s.length>0?s:o?[]:tt;if(r){const f=[...s,...i].find(g=>g.id.trim().toLowerCase()===r.toLowerCase());n.push({id:r,displayName:f?.displayName??E(r),defaultReasoningEffort:f?.defaultReasoningEffort??null,supportedReasoningEfforts:f?.supportedReasoningEfforts??[],defaultServiceTier:f?.defaultServiceTier??null,serviceTiers:f?.serviceTiers??[],isDefault:f?.isDefault??!1})}n.push(...i),n.push(...c);const h=[],p=new Set;for(const f of n){const g=f.id.trim(),x=g.toLowerCase();!g||p.has(x)||(p.add(x),h.push({id:g,displayName:f.displayName.trim()||g,defaultReasoningEffort:f.defaultReasoningEffort,supportedReasoningEfforts:[...f.supportedReasoningEfforts],defaultServiceTier:f.defaultServiceTier,serviceTiers:[...f.serviceTiers],isDefault:f.isDefault}))}return h}async refreshCodexModelOptions(){if(!this.initialized||!this.alive||!this.process?.stdin||Date.now()-this.codexModelOptionsCachedAt<D.MODEL_CACHE_TTL_MS)return;const e=F(this.codexHome);if(e.baseUrl&&ce(e.baseUrl)){try{const t=await ut(e.baseUrl,e.apiKey);if(t.length>0){this.codexModelOptions=le(t),this.codexModelOptionsCachedAt=Date.now(),d.info("codex-adapter",`Loaded ${t.length} models from external provider ${e.baseUrl}`);return}}catch(t){d.warn("codex-adapter",`External provider /v1/models failed (${t instanceof Error?t.message:String(t)})`)}if(!lt(e.baseUrl)){this.codexModelOptions=[],this.codexModelOptionsCachedAt=Date.now();return}d.info("codex-adapter",`External provider ${e.baseUrl} returned no models; falling back to Codex model/list`)}try{const t=[];let i;do{const s=await this.sendRequest("model/list",{cursor:i??null,includeHidden:!1,limit:100},15e3),n=ft(s);t.push(...n.models),i=n.nextCursor}while(i);t.length>0&&(this.codexModelOptions=le(t),this.codexModelOptionsCachedAt=Date.now())}catch(t){d.warn("codex-adapter",`Failed to load Codex model list: ${t instanceof Error?t.message:String(t)}`)}}currentTurnId=null;compacting=!1;pendingAutoCompact=!1;compactionDeferred=[];steerDeferred=[];compactingTimer=null;compactionDoneResolver=null;activeEventId=null;activeSessionId=null;visibleAgentMessageIds=new Set;hiddenAgentMessageIds=new Set;agentMessagePhases=new Map;deliveredAgentMessageIds=new Set;deliveredThinkingAgentMessageIds=new Set;codexSequence=0;pendingCodexDeltaFlush=null;turnError=null;turnErrorIsRetryableOnly=!0;turnHasVisibleOutput=!1;turnSawVisibleFinalAnswer=!1;turnHasDeliveredFinalAnswer=!1;deliverInboundEvent(e){if(this.compacting){d.info("codex-adapter",`Event ${e.event_id} deferred: compaction in progress`),this.compactionDeferred.push(e);return}const t=this.inboundMessageIds.prepare(e.session_id,e.content,e.msg_id),i=t.text,s=()=>{t.instructionPending&&this.inboundMessageIds.commitInstruction(e.session_id)},n=()=>{const r=this.inboundMessageIds.prepare(e.session_id,e.content,e.msg_id);r.instructionPending&&this.inboundMessageIds.commitInstruction(e.session_id),this.startNewTurn(e,r.text)};if(this.currentTurnId&&i.trim()){d.info("codex-adapter",`Event ${e.event_id}: steering active turn ${this.currentTurnId}`),this.steerTurn(i).then(()=>{s()}).catch(r=>{const o=r instanceof Error?r.message:String(r);if(d.info("codex-adapter",`Steer failed, falling through: ${o}`),!this.currentTurnId){n();return}if(gt(o)){d.info("codex-adapter","Unsteerable turn detected, clearing active state and starting new turn"),this.clearActive(),n();return}d.info("codex-adapter",`Steer failed but turn still active; deferring event ${e.event_id} for replay after turn ends`),this.steerDeferred.push(e)});return}if(this.currentTurnId){d.info("codex-adapter",`Event ${e.event_id} rejected: busy and empty content`),this.sendEventResultAfterFlushing(e.event_id,"failed","agent busy");return}s(),this.startNewTurn(e,i)}startNewTurn(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,e.audit?.enabled===!0&&this.enableAuditCapture(e.event_id,{auditId:e.audit.auditId,rawProviderBody:e.audit.rawProviderBody}),this.visibleAgentMessageIds.clear(),this.hiddenAgentMessageIds.clear(),this.agentMessagePhases.clear(),this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.codexSequence=0,this.startComposing();const i=this.threadId??"",s=new z(i),n={adapterSessionId:i,text:t,contextMessages:e.context_messages_json?JSON.parse(e.context_messages_json).map(r=>({senderId:r.sender_id??"unknown",content:r.content})):void 0};this.runTurn(n,s,e.event_id,e.session_id).catch(r=>{d.error("codex-adapter",`Turn failed: ${r}`),this.sendEventResultAfterFlushing(e.event_id,"failed",r instanceof Error?r.message:String(r)),this.clearActive()}),this.resetIdleTimer(e.event_id)}deliverStopEvent(e,t){this.activeEventId===e&&(this.cancel(this.threadId??"").catch(()=>{}),this.sendEventResultAfterFlushing(e,"canceled","stopped by user"),this.clearActive())}async spawnCodex(){const e={...this.resolveChildEnv(),...this.directEnv},t=typeof e.PATH=="string"?e.PATH:void 0;t||d.warn("codex-adapter",`spawnCodex: env.PATH is missing! process.env.PATH=${process.env.PATH?"set":"missing"}, config.env=${JSON.stringify(this.config.env)}`);const i=ae(this.config.command||"codex",t),s=rt(this.config.args);for(const o of this.configOverrideArgs)s.push("-c",o);for(const o of this.resolveRelayTransportConfigOverrides())s.push("-c",o);for(const o of this.rawCaptureConfigOverrides)s.push("-c",o);this.sandboxMode&&s.push("-c",`sandbox_mode="${this.sandboxMode}"`);const n=s.map(o=>this.rawCaptureConfigOverrides.includes(o)?"<raw-api-capture-overlay>":o);d.info("codex-adapter",`Spawning: ${i} ${n.join(" ")}`);try{if(!(await Z(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(o){throw String(o?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):o}const r=ee({codexHome:this.codexHome});if(r.locked&&!r.stale)throw new Error(`Codex session appears locked by another process: ${r.path}`);r.stale&&d.warn("codex-adapter",`Ignoring stale Codex lock: ${r.path}`);try{this.process=Ie(i,s,{env:e,cwd:this.cwd}).process}catch(o){throw d.error("codex-adapter",`Codex spawn threw: ${o}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",o}this.process.on("error",o=>{d.error("codex-adapter",`Codex process spawn error: ${o}`),this.process=null,this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("spawn failed: "+(o instanceof Error?o.message:String(o))),this.stopComposing(),this.activeEventId?(this.flushCodexDeltaBuffer(),this.sendEventResultAfterFlushing(this.activeEventId,"failed","Codex process spawn failed"),this.activeEventId=null):this.clearCodexDeltaBuffer(),this.emit("exit",1)}),this.process.on("exit",o=>{d.info("codex-adapter",`Codex process exited (code=${o})`),this.alive=!1,this.bridgeStatus="closed",this.clearIdleTimer(),this.rejectAllPending("process exited"),this.stopComposing(),this.activeEventId?this.flushCodexDeltaBuffer():this.clearCodexDeltaBuffer(),this.emit("exit",o)}),this.process.stderr?.on("data",o=>{const c=o.toString().trim();c&&d.info("codex-adapter",`[codex stderr] ${c}`)}),this.bindStdout(),this.alive=!0}resolveRelayTransportConfigOverrides(){if(this.config.env?.[We]!=="1")return[];const e=je(this.codexHome,this.configOverrideArgs);if(e==="openai"){const i=He(this.codexHome,this.configOverrideArgs);return Le(Ne,"Grix OpenAI Relay",i.targetBaseUrl)}const t=Ue(e);return t?[`${t}=false`]:[]}bindStdout(){if(!this.process?.stdout)return;this.process.stdout.setEncoding("utf8"),fe({input:this.process.stdout}).on("line",t=>{if(!t.trim())return;let i;try{i=JSON.parse(t)}catch{d.error("codex-adapter",`Invalid JSON from Codex: ${t.slice(0,200)}`);return}if(this.bridgeStatus==="starting"&&(this.bridgeStatus="ready"),i.id!=null){const s=String(i.id),n=this.pendingRequests.get(s);if(n){clearTimeout(n.timer),this.pendingRequests.delete(s),n.resolve(i);return}}this.handleNotification(i)})}handleNotification(e){const t=e.method,i=e.params??{};if(this.shouldIgnoreOutOfScopeNotification(e,t,i)){this.activeEventId&&this.resetIdleTimer(this.activeEventId);return}switch(this.captureAuditNotification(t,i),this.captureContextWindowFromPayload(t,i),this.activeEventId&&t&&t.startsWith("item/")&&!t.endsWith("/requestApproval")&&this.startComposing(),t){case"item/started":{const n=i.item,r=n?.id,o=n?.type,c=this.normalizeAgentMessagePhase(n?.phase);if(this.isLongRunningToolItemType(o)&&(this.inFlightToolOps+=1),o==="agentMessage"&&r){c?this.agentMessagePhases.set(r,c):this.agentMessagePhases.delete(r);const h=N(c),p=L(c);h?(this.visibleAgentMessageIds.add(r),this.hiddenAgentMessageIds.delete(r)):p?(this.visibleAgentMessageIds.delete(r),this.hiddenAgentMessageIds.delete(r)):(this.hiddenAgentMessageIds.add(r),this.visibleAgentMessageIds.delete(r)),c==="final_answer"&&h&&(this.turnSawVisibleFinalAnswer=!0)}break}case"item/agentMessage/delta":{const n=i.delta,r=i.itemId,o=this.resolveAgentMessagePhase(r,i.phase),c=(!r||!this.hiddenAgentMessageIds.has(r))&&N(o),h=(!r||!this.hiddenAgentMessageIds.has(r))&&L(o);if(o==="final_answer"&&c&&(this.turnSawVisibleFinalAnswer=!0),n&&this.activeEventId&&h){this.recordDeliveredThinkingAgentMessage(r),this.callbacks.sendThinking?.(this.activeEventId,this.activeSessionId??"",n);break}n&&this.activeEventId&&c&&!this.shouldSuppressAgentMessageDeltaDuringToolRun(r,o)&&(this.recordDeliveredAgentMessage(r,o),this.queueCodexDeltaEvent({...e,params:{...i,...o?{phase:o}:{}}}));break}case"item/completed":{const n=i.item,r=n?.id,o=n?.type;if(this.isLongRunningToolItemType(o)&&(this.inFlightToolOps=Math.max(0,this.inFlightToolOps-1)),this.activeEventId&&o==="commandExecution"&&(this.turnHasVisibleOutput=!0,this.emitCodexEvent("item/completed",e)),o==="agentMessage"){const c=this.resolveAgentMessagePhase(r,n?.phase),h=(!r||!this.hiddenAgentMessageIds.has(r))&&N(c);if(c==="final_answer"&&h){this.turnSawVisibleFinalAnswer=!0;const p=this.extractAgentMessageText(n),f=r?this.deliveredAgentMessageIds.has(r):!1;this.activeEventId&&p&&!f&&(d.warn("codex-adapter",`Recovering final_answer from item/completed item_id=${r??"unknown"}`),this.recordDeliveredAgentMessage(r,c),this.queueCodexDeltaEvent({method:"item/agentMessage/delta",params:{...r?{itemId:r}:{},delta:p,phase:c}}))}else if(L(c)){const p=this.extractAgentMessageText(n),f=r?this.deliveredThinkingAgentMessageIds.has(r):!1;this.activeEventId&&p&&!f&&(this.recordDeliveredThinkingAgentMessage(r),this.callbacks.sendThinking?.(this.activeEventId,this.activeSessionId??"",p))}r&&(this.visibleAgentMessageIds.delete(r),this.hiddenAgentMessageIds.delete(r),this.agentMessagePhases.delete(r))}break}case"turn/started":{const r=i.turn?.id;r&&(this.currentTurnId=r,this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1,this.deliveredAgentMessageIds.clear(),this.deliveredThinkingAgentMessageIds.clear(),this.currentTurnStartedAt=Date.now(),this.preflightCheckComplete=!1,d.info("codex-adapter",`Turn started: ${r}`),this.startComposing());break}case"item/fileChange/requestApproval":{this.handleApprovalRequest(e,"file");break}case"item/commandExecution/requestApproval":{this.handleApprovalRequest(e,"exec");break}case"item/permissions/requestApproval":{this.handleApprovalRequest(e,"permission");break}case"turn/completed":{this.handleTurnCompleted(i);break}case"error":{const n=i.message??JSON.stringify(i);d.error("codex-adapter",`Codex error: ${n}`);const r=i.willRetry===!0;n&&(this.turnError=n,r||(this.turnErrorIsRetryableOnly=!1)),this.activeEventId&&!r&&(this.flushCodexDeltaBuffer(),this.callbacks.sendRunError(this.activeEventId,this.activeSessionId??"",n));break}case"account/rateLimits/updated":{const n=this.extractRateLimitPushLimitId(i),r=this.parseRateLimitSnapshot(i,this.rateLimitSnapshot);r&&(this.rateLimitSnapshot=r,d.info("codex-adapter",`Rate limits updated: primary=${r.primary.usedPercent.toFixed(1)}% secondary=${r.secondary.usedPercent.toFixed(1)}% extras=${r.extras?.length??0}`),this.callbacks.onRateLimitsUpdated?.(r)),n&&n!=="codex"&&this.refreshMainRateLimitsThrottled();break}case"thread/tokenUsage/updated":{const n=i.threadId,r=i.tokenUsage,o=r?.last;(!n||!r||!o)&&d.info("codex-adapter",`[cp-diagnose] token_usage payload_incomplete: method=thread/tokenUsage/updated hasThreadId=${String(!!n)} hasTokenUsage=${String(!!r)} hasLast=${String(!!o)} params=${JSON.stringify(i)}`),n&&r&&o&&(this.currentThreadTokenUsage={inputTokens:o.inputTokens??0,outputTokens:o.outputTokens??0,cacheReadInputTokens:o.cachedInputTokens??0,cacheCreationInputTokens:0},d.info("codex-adapter",`[cp-diagnose] token_usage raw thread=${n}: ${JSON.stringify(r)}`),d.info("codex-adapter",`[cp-diagnose] token_usage parsed thread=${n}: ${JSON.stringify(this.currentThreadTokenUsage)}`),this.callbacks.onTokenUsageUpdated?.(this.currentThreadTokenUsage),this.publishContextWindowSnapshot());break}default:break}const s=t?.endsWith("/requestApproval")===!0;t&&t!=="turn/started"&&(t.startsWith("item/")||t==="error"||t==="turn/completed")&&(this.preflightCheckComplete=!0),this.activeEventId&&(!s||this.pendingApprovals.size===0)&&this.resetIdleTimer(this.activeEventId)}shouldIgnoreOutOfScopeNotification(e,t,i){if(!t||e.id!=null)return!1;const s=I(u(i.threadId),u(i.threadID));if(s&&this.threadId&&s!==this.threadId)return this.logIgnoredNotificationScope(t,s,this.readNotificationTurnId(i)),!0;const n=this.readNotificationTurnId(i);return n&&this.currentTurnId&&n!==this.currentTurnId?(this.logIgnoredNotificationScope(t,s,n),!0):!1}readNotificationTurnId(e){const t=e.turn&&typeof e.turn=="object"?e.turn:void 0;return I(u(e.turnId),u(e.turnID),u(t?.id))}logIgnoredNotificationScope(e,t,i){e!=="error"&&!e.startsWith("turn/")||d.info("codex-adapter",`[scope] ignored ${e} thread=${t??"<none>"} turn=${i??"<none>"} active_thread=${this.threadId??"<none>"} active_turn=${this.currentTurnId??"<none>"}`)}captureAuditNotification(e,t){const i=this.activeEventId;if(!e||!i)return;const s=this.auditCaptureByEventId.get(i);if(!s)return;const n=t.turn,r=typeof t.turnId=="string"&&t.turnId?t.turnId:typeof t.turn_id=="string"&&t.turn_id?t.turn_id:typeof n?.id=="string"&&n.id?n.id:this.currentTurnId;r&&(s.providerTurnId=r);const o=typeof t.threadId=="string"&&t.threadId?t.threadId:typeof t.thread_id=="string"&&t.thread_id?t.thread_id:this.threadId;if(o&&(s.threadId=o),!!it.has(e))try{const c=JSON.parse(JSON.stringify(t));s.events.push({sequence:++s.sequence,method:e,params:c,observedAt:new Date().toISOString()})}catch(c){const h=c instanceof Error?c.message:String(c);d.warn("codex-adapter",`Audit evidence capture skipped event=${i} method=${e}: ${h}`)}}captureContextWindowFromPayload(e,t){const i=["model_context_window","modelContextWindow","context_window_size","contextWindowSize"],s=this.findNumericField(t,i);if(s==null||s<=0){const n=this.probeContextWindowFields(t,i);n.foundAnyCandidateField&&d.info("codex-adapter",`[cp-diagnose] context_window missing_or_invalid: method=${e??"-"} matchedFields=${n.matchedFields.join(",")||"-"} raw=${n.rawValues.join(",")||"-"} extracted=${String(s)}`);return}this.currentModelContextWindow!==s&&(this.currentModelContextWindow=s,d.info("codex-adapter",`[cp-diagnose] context_window updated: method=${e??"-"} size=${s}`),this.publishContextWindowSnapshot())}probeContextWindowFields(e,t){const i=[],s=[],n=r=>{if(!r||typeof r!="object")return;if(Array.isArray(r)){for(const c of r)n(c);return}const o=r;for(const c of t)Object.prototype.hasOwnProperty.call(o,c)&&(i.push(c),s.push(String(o[c])));for(const c of Object.values(o))n(c)};return n(e),{foundAnyCandidateField:i.length>0,matchedFields:i,rawValues:s}}findNumericField(e,t){if(!e||typeof e!="object")return null;const i=e;for(const s of t){const n=i[s];if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n=="string"){const r=Number(n);if(Number.isFinite(r))return r}}for(const s of Object.values(i)){if(Array.isArray(s)){for(const r of s){const o=this.findNumericField(r,t);if(o!=null)return o}continue}const n=this.findNumericField(s,t);if(n!=null)return n}return null}buildContextWindowSnapshot(){const e=this.currentModelContextWindow;if(!e||e<=0)return d.debug("codex-adapter",`[cp-diagnose] context_window snapshot skipped: invalid size=${String(e)}`),null;const t=this.currentThreadTokenUsage,i=t?t.inputTokens+t.outputTokens:null,s=i==null?null:Math.max(0,e-i),n=i==null?null:Math.min(100,i/e*100),r=i==null?null:Math.max(0,100-(n??0));return d.info("codex-adapter",`[cp-diagnose] context_window computed: threadId=${this.threadId??"-"} size=${e} usedTokens=${String(i)} usedPercentage=${String(n)}`),{sizeTokens:e,usedTokens:i,remainingTokens:s,usedPercentage:n,remainingPercentage:r,source:"codex:model_context_window"}}publishContextWindowSnapshot(){const e=this.buildContextWindowSnapshot();this.callbacks.onContextWindowUpdated?.(e),this.maybeScheduleAutoCompact(e)}maybeScheduleAutoCompact(e){const t=e?.usedPercentage;typeof t!="number"||t<re||this.pendingAutoCompact||this.compacting||(this.pendingAutoCompact=!0,d.info("codex-adapter",`[auto-compact] context_window usedPercentage=${t.toFixed(1)}% >= ${re}%, scheduling compact`),this.tryRunPendingAutoCompact())}tryRunPendingAutoCompact(){this.pendingAutoCompact&&(this.stopped||!this.alive||this.currentTurnId||this.compacting||(this.pendingAutoCompact=!1,this.execCommand("compact","",this.activeSessionId??"").then(e=>{d.info("codex-adapter",`[auto-compact] compact done status=${e.status} msg=${e.message??""}`),e.status==="failed"&&/agent busy/i.test(e.message??"")&&(this.pendingAutoCompact=!0)}).catch(e=>{d.warn("codex-adapter",`[auto-compact] compact error: ${e instanceof Error?e.message:e}`)})))}parseRateLimitSnapshot(e,t=null){try{const i=e.rateLimitsByLimitId,s=this.extractRateLimitPushLimitId(e),n=!i?.codex&&!!s&&s!=="codex",r=i?.codex??(n?{}:e.rateLimits??e),o=r.primary,c=r.secondary,h=r.credits,p=l=>{if(typeof l=="number"&&Number.isFinite(l))return l;if(typeof l=="string"){const m=Number(l);if(Number.isFinite(m))return m}return 0},f=l=>typeof l=="boolean"?l:typeof l=="string"?l.toLowerCase()==="true":!1,g=l=>{if(l==null)return null;if(typeof l=="string"){const m=l.trim();if(!m)return null;const v=Number(m);return Number.isFinite(v)&&v>1e9?new Date(v*1e3).toISOString():m}if(typeof l=="number"&&Number.isFinite(l)&&l>0){const m=l>1e12?l/1e3:l;return new Date(m*1e3).toISOString()}return null},x=l=>{const m=l.resets_in_seconds??l.resetsInSeconds,v=typeof m=="number"||typeof m=="string"?Number(m):NaN;return!Number.isFinite(v)||v<=0?null:new Date(Date.now()+v*1e3).toISOString()},y=l=>({usedPercent:p(l.used_percent??l.usedPercent),windowMinutes:p(l.window_minutes??l.windowDurationMins??l.windowMinutes),resetsAt:g(l.resets_at??l.resetsAt)??x(l)}),S=()=>({usedPercent:0,windowMinutes:0,resetsAt:null}),R=(l,m)=>l??m??S(),C=()=>{const l=[];if(o&&l.push(o),c&&l.push(c),Array.isArray(r.windows))for(const m of r.windows)m&&typeof m=="object"&&l.push(m);return l.map(y).filter(m=>m.windowMinutes>0)},w=(l,m,v)=>{const T=l.filter(b=>v(b.windowMinutes));return T.length===0?null:T.reduce((b,A)=>Math.abs(A.windowMinutes-m)<Math.abs(b.windowMinutes-m)?A:b)},$=C(),O=n?t?{primary:t.primary,secondary:t.secondary}:null:$.length>0?{primary:R(w($,300,l=>l<1440),t?.primary),secondary:R(w($,10080,l=>l>=1440),t?.secondary)}:o||c?{primary:o?y(o):t?.primary??S(),secondary:c?y(c):t?.secondary??S()}:null;if(!O)return null;const W=(l,m)=>{if(!m||typeof m!="object"||Array.isArray(m))return null;const v=m,T=v.limitName??v.limit_name,b=typeof T=="string"&&T.trim()?T.trim():l,A=[],V=v.primary,G=v.secondary;V&&A.push(V),G&&A.push(G);const X=A.map(y).filter(M=>M.windowMinutes>0),J=w(X,10080,M=>M>=1440)??w(X,300,M=>M<1440);return J?{id:l,label:b,...J}:null};let _;if(i&&typeof i=="object"){_=[];for(const[l,m]of Object.entries(i)){if(l==="codex")continue;const v=W(l,m);v&&_.push(v)}}else if(_=t?.extras?[...t.extras]:[],n&&s){const l=W(s,e.rateLimits??e);if(l){const m=_.findIndex(v=>v.id===l.id);m>=0?_[m]=l:_.push(l)}}return{primary:O.primary,secondary:O.secondary,credits:h?{hasCredits:f(h.has_credits??h.hasCredits),unlimited:f(h.unlimited),balance:h.balance==null?null:p(h.balance)}:t?.credits??{hasCredits:!1,unlimited:!1,balance:null},..._.length>0?{extras:_}:{}}}catch{return null}}handleApprovalRequest(e,t){const i=e.id;if(i==null)return;const s=e.method,n=`${i}`.trim(),r=`codex_${ue(this.activeSessionId??"")}_${ue(n)}`;if(this.approvalPolicy==="never"){this.sendApprovalDecision(i,"accept");return}this.activeEventId&&this.emitCodexEvent(s,e),this.pendingApprovals.set(r,{approvalId:r,approvalCommandId:n,sourceEventId:this.activeEventId??"",requestId:i,kind:t}),d.info("codex-adapter",`Pending approval stored: ${r} (kind=${t})`),this.clearIdleTimer(),this.stopComposing()}resolvePendingApproval(e){const t=e.params??{},i=I(t.approval_id,t.approvalId);if(i)return this.pendingApprovals.get(i)??null;const s=I(t.approval_command_id,t.approvalCommandId);if(s){for(const[,n]of this.pendingApprovals)if(n.approvalCommandId===s)return n}return null}sendApprovalDecision(e,t){if(e==null||!this.process?.stdin)return;const i={jsonrpc:"2.0",id:e,result:{decision:t}};this.process.stdin.write(`${JSON.stringify(i)}
|
|
5
5
|
`)}armCompactionFallback(){this.compacting&&(this.compactingTimer&&clearTimeout(this.compactingTimer),this.compactingTimer=setTimeout(()=>{d.warn("codex-adapter","Compaction fallback fired: turn/completed not received within timeout, treating as stuck and releasing deferred events"),this.currentTurnId=null,this.finishCompaction("fallback-timeout")},Ze),this.compactingTimer.unref?.())}finishCompaction(e){if(!this.compacting)return;this.compacting=!1,this.compactingTimer&&(clearTimeout(this.compactingTimer),this.compactingTimer=null);const t=this.compactionDeferred.splice(0);d.info("codex-adapter",`Compaction finished (${e}); replaying ${t.length} deferred events`);for(const s of t)this.deliverInboundEvent(s);const i=this.compactionDoneResolver;this.compactionDoneResolver=null,i?.()}handleTurnCompleted(e){if(this.currentTurnId=null,this.stopComposing(),this.activeEventId){this.flushCodexDeltaBuffer();const t=this.activeEventId,i={event_id:t,session_id:this.activeSessionId??"",thread_id:this.threadId??void 0,codex_event_type:"codex",codex_method:"turn/completed",codex_sequence:++this.codexSequence},s=this.turnError,n=this.turnErrorIsRetryableOnly,r=this.turnHasVisibleOutput,o=this.turnSawVisibleFinalAnswer&&!this.turnHasDeliveredFinalAnswer;this.turnError=null,this.turnErrorIsRetryableOnly=!0,this.turnHasVisibleOutput=!1,this.turnSawVisibleFinalAnswer=!1,this.turnHasDeliveredFinalAnswer=!1;const h=(s&&!(n&&r)?s:null)??(o?"Codex final answer was observed but not delivered":null)??(r?null:"Codex completed without producing any visible output"),p=h!==null;this.callbacks.sendCodexEvent(i),this.sendEventResultAfterFlushing(t,p?"failed":"responded",h??void 0),this.clearActive()}this.compacting&&this.finishCompaction("turn-completed")}emitCodexEvent(e,t){if(!this.activeEventId)return;this.flushCodexDeltaBuffer();const i=he(e,t);if(i===void 0&&e==="item/completed")return;const s={event_id:this.activeEventId,session_id:this.activeSessionId??"",thread_id:this.threadId??void 0,codex_event_type:"codex",codex_method:e,codex_sequence:++this.codexSequence};i!==void 0&&(s.codex_payload=i),this.callbacks.sendCodexEvent(s)}queueCodexDeltaEvent(e){if(!this.activeEventId)return;const t=he("item/agentMessage/delta",e),i=t?.params?.delta;if(typeof i!="string"||i.length===0)return;const s=typeof t?.params?.phase=="string"?t.params.phase:void 0,n=this.activeEventId,r=this.activeSessionId??"",o=this.threadId??void 0,c=this.pendingCodexDeltaFlush;if(c&&(c.eventId!==n||c.sessionId!==r||c.threadId!==o||c.phase!==s)&&this.flushCodexDeltaBuffer(),this.pendingCodexDeltaFlush||(this.pendingCodexDeltaFlush={eventId:n,sessionId:r,threadId:o,delta:"",phase:s,timer:null}),this.pendingCodexDeltaFlush.delta+=i,this.pendingCodexDeltaFlush.delta.length>=et){this.flushCodexDeltaBuffer();return}this.pendingCodexDeltaFlush.timer||(this.pendingCodexDeltaFlush.timer=setTimeout(()=>{if(this.activeEventId!==n){this.clearCodexDeltaBuffer();return}this.flushCodexDeltaBuffer()},Qe))}flushCodexDeltaBuffer(){const e=this.pendingCodexDeltaFlush;if(!e||(this.pendingCodexDeltaFlush=null,e.timer&&clearTimeout(e.timer),!e.delta))return;const t={event_id:e.eventId,session_id:e.sessionId,thread_id:e.threadId,codex_event_type:"codex",codex_method:"item/agentMessage/delta",codex_sequence:++this.codexSequence,codex_payload:{params:{delta:e.delta,...e.phase?{phase:e.phase}:{}}}};this.callbacks.sendCodexEvent(t)}clearCodexDeltaBuffer(){const e=this.pendingCodexDeltaFlush;this.pendingCodexDeltaFlush=null,e?.timer&&clearTimeout(e.timer)}sendEventResultAfterFlushing(e,t,i){this.pendingCodexDeltaFlush?.eventId===e&&this.flushCodexDeltaBuffer(),this.callbacks.sendEventResult(e,t,i)}startComposing(){}stopComposing(){}async sendRequest(e,t,i=3e4){return new Promise((s,n)=>{if(!this.process?.stdin){n(new Error("Codex process not available"));return}const r=++this.requestId,o={jsonrpc:"2.0",id:r,method:e,params:t??{}},c=setTimeout(()=>{this.pendingRequests.delete(String(r)),n(new Error(`Request timeout: ${e}`))},i);this.pendingRequests.set(String(r),{resolve:p=>{p.error?n(new Error(`JSON-RPC error: ${p.error.message}`)):s(p.result)},reject:n,timer:c});const h=JSON.stringify(o);this.process.stdin.write(`${h}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import{execFileSync as
|
|
1
|
+
import{execFileSync as Y}from"node:child_process";import{createInterface as $}from"node:readline";import{EventEmitter as q}from"node:events";import{randomUUID as Z}from"node:crypto";import{mkdirSync as E,readFileSync as L,writeFileSync as P,readdirSync as ee,statSync as D}from"node:fs";import{join as A,resolve as te}from"node:path";import{fileURLToPath as se}from"node:url";import{homedir as N}from"node:os";import{GRIX_PATHS as ne,log as h}from"../../core/log/index.js";import{IdentityInjector as ie}from"../shared/identity-injector.js";import{buildSimpleProbeReport as re}from"../shared/probe-util.js";import{InternalApiServer as oe}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as ae,pruneLegacyMcpServerEntries as de}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as le}from"../shared/inbound-message-id-injector.js";import{syncDefaultSkillsToDir as ce}from"../../default-skills/index.js";import{spawnCommand as R,killProcessGroup as I}from"../../core/runtime/spawn.js";import{SessionBindingStore as ue}from"../../core/persistence/session-binding-store.js";import{fetchCursorParameterizedModels as he}from"./fetch-models.js";import{resolveCursorSpawn as M}from"./resolve-command.js";import{fetchCursorAccountUsage as me}from"./fetch-usage.js";import{buildCursorContextWindow as fe,buildCursorContextWindowFromUsage as pe,resolveCursorContextWindowSize as ge}from"./context-window.js";const Se=12e4,x=300*1e3,F=90*1e3,j=1800*1e3,ye=8192,Q="Summarize this conversation for handoff to a fresh chat. Include: goals, key decisions, important file paths, current status, and next steps. Be concise but complete. Output ONLY the summary text.",O=12e4,W=new Set(["completed","failed","error","errored","canceled","cancelled","rejected"]);function ve(d){const e=d.replace(/ToolCall$/i,"").trim();return e?e.charAt(0).toUpperCase()+e.slice(1):d||"tool"}function U(d){const e=String(d.call_id??d.callId??"").trim(),t=d.tool_call??d.toolCall;if(t&&typeof t=="object"&&!Array.isArray(t)){const n=Object.keys(t);if(n.length>0){const s=n[0],i=t[s],r=i&&typeof i=="object"&&!Array.isArray(i)?i:null;return{toolName:ve(s),toolInput:r?.args??r?.arguments??{},callId:e}}}return{toolName:String(d.name??d.tool_name??d.toolName??"tool").trim()||"tool",toolInput:d.args??d.tool_input??d.toolInput??{},callId:e}}function H(d){return String(d??"").trim().toLowerCase().replace(/[^a-z0-9]/g,"")}function z(d){const e=H(d);return e==="askquestion"||e==="askuserquestion"}function J(d){const e=H(d);return e==="createplan"||e==="exitplanmode"}function _e(d){if(!Array.isArray(d))return;const e=d.map(t=>{if(typeof t=="string")return t.trim();if(!t||typeof t!="object")return"";const n=t,s=String(n.label??"").trim();if(s)return s;const i=String(n.value??"").trim();if(i)return i;const r=String(n.text??"").trim();return r||""}).filter(t=>t.length>0);return e.length>0?e:void 0}function Ae(d){if(!d||typeof d!="object"||Array.isArray(d))return null;const e=d,t=String(e.title??"").trim(),n=e.questions;if(!Array.isArray(n)||n.length===0)return null;const s=[];for(let i=0;i<n.length;i++){const r=n[i];if(!r||typeof r!="object")continue;const o=r,a=t||`Question ${i+1}`,l=String(o.header??o.id??o.question??a).trim()||a,c=String(o.prompt??o.question??"").trim();if(!c)continue;const u=_e(o.options),p=o.multiSelect===!0||o.multi_select===!0;s.push({header:l,prompt:c,...u?{options:u}:{},...p?{multi_select:!0}:{}})}return s.length>0?s:null}function be(d){if(!d||typeof d!="object"||Array.isArray(d))return null;const e=d,t=String(e.name??e.title??"").trim(),n=String(e.overview??"").trim(),s=String(e.plan??"").trim();if(!s&&!n&&!t)return null;const i=[];return t&&i.push(`# ${t}`),n&&i.push(n),s&&i.push(s),i.join(`
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
3
|
+
`)}function ke(d){if(!d||typeof d!="object"||Array.isArray(d))return null;const e=d,t=String(e.type??"").trim().toLowerCase();if(!t)return null;switch(t){case"tool_call":{const n=String(e.subtype??"").trim().toLowerCase(),s=U(e);return z(s.toolName)||J(s.toolName)?null:n==="started"||n==="start"?{type:"tool_call",payload:{tool_name:s.toolName,...s.callId?{tool_call_id:s.callId}:{}}}:(W.has(n),null)}case"error":return{type:"error",payload:{message:String(e.message??e.error??e.result??"cursor error").trim()||"cursor error"}};case"result":{const n=String(e.subtype??"").trim().toLowerCase();return e.is_error===!0||n==="error"?{type:"error",payload:{message:String(e.result??e.message??"cursor run failed").trim()||"cursor run failed"}}:null}default:return null}}function we(d,e){if(!d||typeof d!="object"||Array.isArray(d))return"";const t=d;if(String(t.type??"")!=="assistant")return"";const n=t.model_call_id??t.modelCallId;if(n!=null&&String(n).trim()!=="")return"";const s=t.message,i=s&&typeof s=="object"&&!Array.isArray(s)?s.content:void 0;if(!Array.isArray(i))return"";const r=i.map(o=>{if(!o||typeof o!="object"||Array.isArray(o))return"";const a=o;return a.type==="text"?String(a.text??""):""}).filter(Boolean).join("");if(!r)return"";if(e){if(r===e||e.startsWith(r)&&r.length<e.length)return"";if(r.startsWith(e))return r.slice(e.length)}return r}const G=[{id:"approval",displayName:"\u4EBA\u5DE5\u786E\u8BA4"},{id:"full_auto",displayName:"\u81EA\u7531\u6A21\u5F0F"},{id:"plan",displayName:"\u8BA1\u5212\u6A21\u5F0F"}];function C(d){const e=String(d??"").trim().toLowerCase();return G.some(t=>t.id===e)?e:null}function B(d){try{return process.kill(d,0),!0}catch(e){return e.code==="EPERM"}}function X(d,e,t){if(t<0)return null;let n;try{n=ee(d,{withFileTypes:!0})}catch{return null}for(const s of n){const i=A(d,s.name);if(s.isDirectory()){const r=X(i,e,t-1);if(r)return r}else if(s.isFile()&&s.name.endsWith(e))return i}return null}function K(d,e){if(!d)return null;const t=e||A(N(),".cursor","projects");return X(t,`${d}.jsonl`,6)}function Ie(d){const e=d.context_messages_json;if(e)try{const t=JSON.parse(e);return!Array.isArray(t)||t.length===0?void 0:t.map(n=>({senderId:String(n.sender_id??"unknown"),content:String(n.content??"")}))}catch{return}}function Ce(d,e){const t=[String(d??"")],n=String(e.quoted_message_id??"").trim();n&&t.push(`[quoted_message_id] ${n}`);const s=String(e.attachments_json??"").trim();return s&&t.push(`[attachments_json]
|
|
4
4
|
${s}`),t.filter(i=>i.length>0).join(`
|
|
5
5
|
|
|
6
|
-
`)}class Z extends q{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){h.warn("cursor-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}class x extends q{type="cursor";static STDERR_MAX_CHARS=8192;config;callbacks;alive=!1;stopped=!1;permissionHandler=null;internalApi=null;bindingStore=null;identity;inboundMessageIds=new ue;inboundQueue=[];pendingBySession=new Map;sessions=new Set;sessionRuntime=new Map;sessionSeq=0;lastUsageBySession=new Map;auditCaptures=new Map;completedAuditBoundaries=new Map;lastContextBySession=new Map;pendingHandoffBySession=new Map;pendingQuestionByRequestId=new Map;pendingQuestionAnswerBySession=new Map;cachedAccountRateLimits=null;rateLimitsInflight=null;_availableModels=[];transcriptPathBySession=new Map;activeBySession=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const n=e.options??{};this.bindingStore=n.bindingStore instanceof me?n.bindingStore:null,this.identity=new oe("cursor-adapter",t.getAgentProfile)}async start(){this.alive=!0,this.stopped=!1,(this.config.options??{}).mcp_tools!==!1&&(this.internalApi=new de,this.internalApi.setInvokeHandler(async(t,n,s,i)=>this.callbacks.agentInvoke(t,n,i)),await this.internalApi.start()),this.notifyBindingReady(),this.refreshModels().then(()=>this.notifyBindingReady()).catch(()=>{}),this.refreshAccountRateLimits().then(()=>this.notifyBindingReady()).catch(()=>{})}get availableModels(){return this._availableModels}get availableModes(){return K.map(e=>({...e}))}async refreshModels(){try{const e={...process.env,...this.config.env??{}},t=await fe({command:this.config.command,env:e,cwd:process.cwd()});t.length>0&&(this._availableModels=t,h.info("cursor-adapter",`Loaded ${t.length} available models`))}catch(e){h.warn("cursor-adapter",`Failed to refresh models: ${e instanceof Error?e.message:String(e)}`)}}async stop(){this.stopped=!0,this.alive=!1;for(const e of this.activeBySession.values())I(e.child,"SIGTERM");this.activeBySession.clear(),this.transcriptPathBySession.clear(),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null)}isAlive(){return this.alive}async createSession(e){const t=`cursor-${Date.now()}-${++this.sessionSeq}`;return this.sessions.add(t),this.sessionRuntime.set(t,{cwd:typeof e.cwd=="string"?e.cwd:void 0,modelId:typeof e.modelId=="string"?e.modelId:void 0,modeId:typeof e.modeId=="string"?e.modeId:void 0}),t}async resumeSession(e,t){this.sessions.add(e);const n=this.sessionRuntime.get(e)??{};this.sessionRuntime.set(e,{...n,cwd:typeof t?.cwd=="string"?t.cwd:n.cwd,modelId:typeof t?.modelId=="string"?t.modelId:n.modelId,modeId:typeof t?.modeId=="string"?t.modeId:n.modeId})}onAgentProfileChanged(){this.identity.onProfileChanged()}async destroySession(e){this.sessions.delete(e),this.sessionRuntime.delete(e),this.transcriptPathBySession.delete(e),this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e),this.pendingQuestionAnswerBySession.delete(e),this.pendingHandoffBySession.delete(e);for(const[t,n]of this.pendingQuestionByRequestId)n.sessionId===e&&this.pendingQuestionByRequestId.delete(t)}sendPrompt(e){const t=new Z(e.adapterSessionId);if(!this.alive||this.stopped)return queueMicrotask(()=>t.emitError(new Error("adapter not running"))),t;const n=this.inboundQueue.shift()??{event_id:`cursor-evt-${Date.now()}`,session_id:e.adapterSessionId,content:e.text},s=e.adapterSessionId,i=this.pendingBySession.get(s)??[];return i.push({event:n,request:e,handle:t}),this.pendingBySession.set(s,i),this.tryStartNext(s),t}tryStartNext(e){if(this.activeBySession.has(e)||!this.alive||this.stopped)return;const t=this.pendingBySession.get(e);if(!t||t.length===0)return;const n=t.shift();t.length===0?this.pendingBySession.delete(e):this.pendingBySession.set(e,t),n&&this.startJob(n,!1,0)}startJob(e,t,n){const{event:s,request:i,handle:r}=e;s.audit?.enabled&&!this.auditCaptures.has(s.event_id)&&this.auditCaptures.set(s.event_id,[]);const o=i.adapterSessionId,a=this.sessionRuntime.get(i.adapterSessionId)??{},l=this.config.options??{},c=[...this.config.args??[]];c.push("-p","--output-format","stream-json"),l.trust!==!1&&c.push("--trust");const u=a.cwd||l.workspace;this.internalApi&&u&&(this.ensureWorkspaceMcpAndSkills(u),c.push("--approve-mcps")),u&&c.push("--workspace",u);const p=a.modelId||l.model;p&&c.push("--model",p);const _=C(a.modeId||l.mode)??"full_auto";_==="full_auto"?c.push("--yolo"):_==="plan"&&c.push("--plan");const v=a.cursorSessionId??this.bindingStore?.getAcpSessionId(i.adapterSessionId),b=!!(v&&l.use_continue!==!1&&!t);b&&c.push("--resume",v),c.push(this.buildPromptText(i));const m={...process.env,...this.config.env??{}},y=F(R(this.config.command,typeof m.PATH=="string"?m.PATH:void 0));h.info("cursor-adapter",`job start: event=${s.event_id} session=${s.session_id} retry=${n}`);let g;try{g=M(y.command,[...y.prefixArgs,...c],{cwd:u||process.cwd(),env:j(m,y),stdio:["ignore","pipe","pipe"]}).process}catch(S){this.finishActive(o,"failed",`spawn failed: ${S instanceof Error?S.message:String(S)}`);return}this.callbacks.sendEventAck(s.event_id,s.session_id),this.emit("eventStarted",s.event_id,s.session_id);const f={event:s,request:i,handle:r,child:g,seq:0,done:!1,stderr:"",timer:null,idleTimer:null,toolCallsInFlight:new Set,toolCallsStarted:0,assistantTextEmitted:"",streamBuffer:"",lastIoAt:Date.now(),sawResult:!1,retryCount:n,usedContinue:b,workspace:u||process.cwd(),args:c};this.activeBySession.set(o,f),this.notifyBindingReady(o),this.armActiveIdleTimer(o);const k=i.timeoutMs&&i.timeoutMs>0?i.timeoutMs:0;k>0&&(f.timer=setTimeout(()=>{f.done||(I(g,"SIGTERM"),this.finishActive(o,"failed",`cursor agent timeout after ${k}ms`))},k)),$({input:g.stdout}).on("line",S=>this.handleStdoutLineForActive(f,S)),g.stderr?.on("data",S=>{if(f.done)return;const w=f.stderr+String(S??"");f.stderr=w.length>x.STDERR_MAX_CHARS?w.slice(-x.STDERR_MAX_CHARS):w,f.lastIoAt=Date.now(),this.armActiveIdleTimer(o)}),g.once("error",S=>{this.finishActive(o,"failed",`spawn failed: ${String(S?.message??S)}`)}),g.once("close",S=>{if(!f.done)if((S??0)===0)this.finishActive(o,"responded");else{if(this.shouldRetryWithoutContinue(f)){f.timer&&clearTimeout(f.timer),f.idleTimer&&clearTimeout(f.idleTimer),this.activeBySession.delete(o),this.startJob(e,!0,f.retryCount+1);return}const w=f.stderr.trim()||`cursor agent exited with code ${S??-1}`;this.finishActive(o,"failed",w)}})}async cancel(e){const t=this.activeBySession.get(e);t&&(I(t.child,"SIGTERM"),this.finishActive(e,"canceled","canceled"))}deliverInboundEvent(e){const t=String(e.session_id??"").trim();if(!t){h.warn("cursor-adapter",`Dropping event ${e.event_id}: missing session_id`),this.callbacks.sendEventResult(e.event_id,"failed","missing session_id");return}if(!this.alive||this.stopped){h.warn("cursor-adapter",`Dropping event ${e.event_id}: adapter not running`),this.callbacks.sendEventAck(e.event_id,t),this.callbacks.sendEventResult(e.event_id,"failed","adapter not running");return}const n={adapterSessionId:t,text:this.inboundMessageIds.inject(t,Me(String(e.content??""),e),e.msg_id),contextMessages:Re(e)},s=new Z(t),i=this.pendingBySession.get(t)??[];i.push({event:e,request:n,handle:s}),this.pendingBySession.set(t,i),h.info("cursor-adapter",`inbound queued: event=${e.event_id} session=${t} depth=${i.length}`),this.tryStartNext(t)}cancelSessionWork(e,t){const n=this.pendingBySession.get(e)??[];this.pendingBySession.delete(e);const s=this.activeBySession.get(e);s&&(this.killChildWithFallback(s.child),this.finishActive(e,"canceled",t));for(const i of n)this.callbacks.sendEventAck(i.event.event_id,i.event.session_id),this.callbacks.sendEventResult(i.event.event_id,"canceled",t),i.handle.emitDone({status:"canceled",error:t})}killChildWithFallback(e){I(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{I(e,"SIGKILL")}catch{}},5e3).unref()}deliverStopEvent(e,t){if(t){const n=this.activeBySession.get(t);if(n?.event.event_id===e){this.killChildWithFallback(n.child),this.finishActive(t,"canceled","stopped");return}const s=this.pendingBySession.get(t)??[],i=s.findIndex(r=>r.event.event_id===e);if(i>=0){const[r]=s.splice(i,1);s.length===0?this.pendingBySession.delete(t):this.pendingBySession.set(t,s),this.callbacks.sendEventAck(r.event.event_id,r.event.session_id),this.callbacks.sendEventResult(r.event.event_id,"canceled","stopped"),r.handle.emitDone({status:"canceled",error:"stopped"})}return}for(const[n,s]of this.activeBySession.entries())if(s.event.event_id===e){this.killChildWithFallback(s.child),this.finishActive(n,"canceled","stopped");return}for(const[n,s]of this.pendingBySession.entries()){const i=s.findIndex(o=>o.event.event_id===e);if(i<0)continue;const[r]=s.splice(i,1);s.length===0?this.pendingBySession.delete(n):this.pendingBySession.set(n,s),this.callbacks.sendEventAck(r.event.event_id,r.event.session_id),this.callbacks.sendEventResult(r.event.event_id,"canceled","stopped"),r.handle.emitDone({status:"canceled",error:"stopped"});return}}async handleLocalAction(e){const t=String(e.action_type??"").trim().toLowerCase(),n=e.params??{},s=String(n.session_id??"").trim(),i=e.action_id;if(t==="claude_interaction_reply")return String(n.kind??"").trim()==="permission"?(this.callbacks.sendLocalActionResult(i,"failed",void 0,"unsupported","Cursor adapter does not support interactive permission approvals"),{handled:!0,kind:"permission_unsupported"}):this.handleQuestionReply(e);switch(t){case"set_model":{const r=String(n.model_id??"").trim();if(!r||!s)return this.callbacks.sendLocalActionResult(i,"failed",void 0,"invalid_params","model_id and session_id are required"),{handled:!0,kind:"set_model"};const o=this.sessionRuntime.get(s)??{};this.sessionRuntime.set(s,{...o,modelId:r}),this.notifyBindingReady(s);const a=this.getToolbarMeta(s);return this.callbacks.sendLocalActionResult(i,"ok",{outcome:"model_set",session_context:{model_id:r,mode_id:a.mode_id,modelId:r,modeId:a.mode_id},model_id:r,mode_id:a.mode_id,available_models:this.availableModels,available_modes:this.availableModes}),{handled:!0,kind:"set_model"}}case"set_mode":{const r=C(n.mode_id);if(!r||!s)return this.callbacks.sendLocalActionResult(i,"failed",void 0,"invalid_params","mode_id must be approval, full_auto, or plan and session_id is required"),{handled:!0,kind:"set_mode"};const o=this.sessionRuntime.get(s)??{};this.sessionRuntime.set(s,{...o,modeId:r}),this.notifyBindingReady(s);const a=this.getToolbarMeta(s);return this.callbacks.sendLocalActionResult(i,"ok",{outcome:"mode_set",session_context:{model_id:a.model_id,mode_id:r,modelId:a.model_id,modeId:r},model_id:a.model_id,mode_id:r,available_models:this.availableModels,available_modes:this.availableModes}),{handled:!0,kind:"set_mode"}}case"get_context":{const r=s?this.sessionRuntime.get(s):void 0,o=this.config.options??{},a=this.getToolbarMeta(s);return this.callbacks.sendLocalActionResult(i,"ok",{session_context:{model_id:a.model_id,mode_id:a.mode_id,cwd:r?.cwd??o.workspace??null},model_id:a.model_id,mode_id:a.mode_id,modelId:a.model_id,modeId:a.mode_id,cwd:r?.cwd??o.workspace??null,available_models:this.availableModels,available_modes:this.availableModes}),{handled:!0,kind:"get_context"}}case"get_rate_limits":{await this.refreshAccountRateLimits({force:!0});const r=this.getRateLimitsSnapshot(s||void 0);return this.callbacks.sendLocalActionResult(i,"ok",r),s&&this.notifyBindingReady(s),{handled:!0,kind:"get_rate_limits"}}case"get_session_usage":{const r=s?this.getUsageSnapshot(s):null;if(r){const o={inputTokens:r.total.input,outputTokens:r.total.output,cacheReadInputTokens:r.total.cacheRead,cacheCreationInputTokens:r.total.cacheWrite};this.callbacks.sendLocalActionResult(i,"ok",{sessionId:s,adapterType:"cursor",sampledAt:r.sampledAt,turns:r.turns,total:o,models:[{model:this.getToolbarMeta(s).model_id??"auto",turns:r.turns,total:o}]})}else this.callbacks.sendLocalActionResult(i,"failed",void 0,"usage_not_found","No usage data found for this session");return{handled:!0,kind:"get_session_usage"}}case"session_control":{const r=String(n.verb??"").trim().toLowerCase();if(r==="restart"&&s)this.cancelSessionWork(s,"restarted"),this.callbacks.sendLocalActionResult(i,"ok",{outcome:"restarted"});else if(r==="status"){const o=this.sessionRuntime.get(s),a=this.config.options??{},l=this.getToolbarMeta(s),c=this.activeBySession.has(s);this.callbacks.sendLocalActionResult(i,"ok",{verb:"status",status:c?"running":"idle",session_context:{model_id:l.model_id,mode_id:l.mode_id,cwd:o?.cwd??a.workspace??null},model_id:l.model_id,mode_id:l.mode_id,modelId:l.model_id,modeId:l.mode_id,cwd:o?.cwd??a.workspace??null,available_models:this.availableModels,available_modes:this.availableModes})}else this.callbacks.sendLocalActionResult(i,"failed",void 0,"invalid_verb",`Unsupported verb: ${r}`);return{handled:!0,kind:"session_control"}}default:return{handled:!1,kind:"unsupported"}}}getSupportedCommands(){return[{name:"compact",description:"\u538B\u7F29\u4E0A\u4E0B\u6587",args:"[instructions]"}]}async execCommand(e,t,n){return e!=="compact"?{status:"unsupported",message:`Unsupported command: ${e}`}:this.runCompactHandoff(n,t)}async runCompactHandoff(e,t=""){if(!e)return{status:"failed",message:"session_id is required"};if(this.activeBySession.has(e))return{status:"failed",message:"Cannot compact while a Cursor turn is active"};const n=this.sessionRuntime.get(e)??{},s=this.config.options??{},i=n.cursorSessionId??this.bindingStore?.getAcpSessionId(e)??null;if(!i)return{status:"failed",message:"No Cursor chat to compact (send a message first)"};const r=String(n.cwd||s.workspace||process.cwd()),o=String(n.modelId||s.model||""),a=C(n.modeId||s.mode)??"full_auto",l=t.trim(),c=l?`${W}
|
|
6
|
+
`)}class V extends q{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){h.warn("cursor-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}class T extends q{type="cursor";static STDERR_MAX_CHARS=8192;config;callbacks;alive=!1;stopped=!1;permissionHandler=null;internalApi=null;bindingStore=null;identity;inboundMessageIds=new le;inboundQueue=[];pendingBySession=new Map;sessions=new Set;sessionRuntime=new Map;sessionSeq=0;lastUsageBySession=new Map;auditCaptures=new Map;completedAuditBoundaries=new Map;lastContextBySession=new Map;pendingHandoffBySession=new Map;pendingQuestionByRequestId=new Map;pendingQuestionAnswerBySession=new Map;cachedAccountRateLimits=null;rateLimitsInflight=null;_availableModels=[];transcriptPathBySession=new Map;activeBySession=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t;const n=e.options??{};this.bindingStore=n.bindingStore instanceof ue?n.bindingStore:null,this.identity=new ie("cursor-adapter",t.getAgentProfile)}async start(){this.alive=!0,this.stopped=!1,(this.config.options??{}).mcp_tools!==!1&&(this.internalApi=new oe,this.internalApi.setInvokeHandler(async(t,n,s,i)=>this.callbacks.agentInvoke(t,n,i)),await this.internalApi.start()),this.notifyBindingReady(),this.refreshModels().then(()=>this.notifyBindingReady()).catch(()=>{}),this.refreshAccountRateLimits().then(()=>this.notifyBindingReady()).catch(()=>{})}get availableModels(){return this._availableModels}get availableModes(){return G.map(e=>({...e}))}async refreshModels(){try{const e={...process.env,...this.config.env??{}},t=await he({command:this.config.command,env:e,cwd:process.cwd()});t.length>0&&(this._availableModels=t,h.info("cursor-adapter",`Loaded ${t.length} available models`))}catch(e){h.warn("cursor-adapter",`Failed to refresh models: ${e instanceof Error?e.message:String(e)}`)}}async stop(){this.stopped=!0,this.alive=!1;for(const e of this.activeBySession.values())I(e.child,"SIGTERM");this.activeBySession.clear(),this.transcriptPathBySession.clear(),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null)}isAlive(){return this.alive}async createSession(e){const t=`cursor-${Date.now()}-${++this.sessionSeq}`;return this.sessions.add(t),this.sessionRuntime.set(t,{cwd:typeof e.cwd=="string"?e.cwd:void 0,modelId:typeof e.modelId=="string"?e.modelId:void 0,modeId:typeof e.modeId=="string"?e.modeId:void 0}),t}async resumeSession(e,t){this.sessions.add(e);const n=this.sessionRuntime.get(e)??{};this.sessionRuntime.set(e,{...n,cwd:typeof t?.cwd=="string"?t.cwd:n.cwd,modelId:typeof t?.modelId=="string"?t.modelId:n.modelId,modeId:typeof t?.modeId=="string"?t.modeId:n.modeId})}onAgentProfileChanged(){this.identity.onProfileChanged()}async destroySession(e){this.sessions.delete(e),this.sessionRuntime.delete(e),this.transcriptPathBySession.delete(e),this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e),this.pendingQuestionAnswerBySession.delete(e),this.pendingHandoffBySession.delete(e);for(const[t,n]of this.pendingQuestionByRequestId)n.sessionId===e&&this.pendingQuestionByRequestId.delete(t)}sendPrompt(e){const t=new V(e.adapterSessionId);if(!this.alive||this.stopped)return queueMicrotask(()=>t.emitError(new Error("adapter not running"))),t;const n=this.inboundQueue.shift()??{event_id:`cursor-evt-${Date.now()}`,session_id:e.adapterSessionId,content:e.text},s=e.adapterSessionId,i=this.pendingBySession.get(s)??[];return i.push({event:n,request:e,handle:t}),this.pendingBySession.set(s,i),this.tryStartNext(s),t}tryStartNext(e){if(this.activeBySession.has(e)||!this.alive||this.stopped)return;const t=this.pendingBySession.get(e);if(!t||t.length===0)return;const n=t.shift();t.length===0?this.pendingBySession.delete(e):this.pendingBySession.set(e,t),n&&this.startJob(n,!1,0)}startJob(e,t,n){const{event:s,request:i,handle:r}=e;s.audit?.enabled&&!this.auditCaptures.has(s.event_id)&&this.auditCaptures.set(s.event_id,[]);const o=i.adapterSessionId,a=this.sessionRuntime.get(i.adapterSessionId)??{},l=this.config.options??{},c=[...this.config.args??[]];c.push("-p","--output-format","stream-json"),l.trust!==!1&&c.push("--trust");const u=a.cwd||l.workspace;this.internalApi&&u&&(this.ensureWorkspaceMcpAndSkills(u),c.push("--approve-mcps")),u&&c.push("--workspace",u);const p=a.modelId||l.model;p&&c.push("--model",p);const _=C(a.modeId||l.mode)??"full_auto";_==="full_auto"?c.push("--yolo"):_==="plan"&&c.push("--plan");const v=a.cursorSessionId??this.bindingStore?.getAcpSessionId(i.adapterSessionId),b=!!(v&&l.use_continue!==!1&&!t);b&&c.push("--resume",v),c.push(this.buildPromptText(i));const f={...process.env,...this.config.env??{}},y=M(this.config.command,f);h.info("cursor-adapter",`job start: event=${s.event_id} session=${s.session_id} retry=${n}`);let g;try{g=R(y.command,[...y.prefixArgs,...c],{cwd:u||process.cwd(),env:y.env,stdio:["ignore","pipe","pipe"]}).process}catch(S){this.finishActive(o,"failed",`spawn failed: ${S instanceof Error?S.message:String(S)}`);return}this.callbacks.sendEventAck(s.event_id,s.session_id),this.emit("eventStarted",s.event_id,s.session_id);const m={event:s,request:i,handle:r,child:g,seq:0,done:!1,stderr:"",timer:null,idleTimer:null,toolCallsInFlight:new Set,toolCallsStarted:0,assistantTextEmitted:"",streamBuffer:"",lastIoAt:Date.now(),sawResult:!1,retryCount:n,usedContinue:b,workspace:u||process.cwd(),args:c};this.activeBySession.set(o,m),this.notifyBindingReady(o),this.armActiveIdleTimer(o);const k=i.timeoutMs&&i.timeoutMs>0?i.timeoutMs:0;k>0&&(m.timer=setTimeout(()=>{m.done||(I(g,"SIGTERM"),this.finishActive(o,"failed",`cursor agent timeout after ${k}ms`))},k)),$({input:g.stdout}).on("line",S=>this.handleStdoutLineForActive(m,S)),g.stderr?.on("data",S=>{if(m.done)return;const w=m.stderr+String(S??"");m.stderr=w.length>T.STDERR_MAX_CHARS?w.slice(-T.STDERR_MAX_CHARS):w,m.lastIoAt=Date.now(),this.armActiveIdleTimer(o)}),g.once("error",S=>{this.finishActive(o,"failed",`spawn failed: ${String(S?.message??S)}`)}),g.once("close",S=>{if(!m.done)if((S??0)===0)this.finishActive(o,"responded");else{if(this.shouldRetryWithoutContinue(m)){m.timer&&clearTimeout(m.timer),m.idleTimer&&clearTimeout(m.idleTimer),this.activeBySession.delete(o),this.startJob(e,!0,m.retryCount+1);return}const w=m.stderr.trim()||`cursor agent exited with code ${S??-1}`;this.finishActive(o,"failed",w)}})}async cancel(e){const t=this.activeBySession.get(e);t&&(I(t.child,"SIGTERM"),this.finishActive(e,"canceled","canceled"))}deliverInboundEvent(e){const t=String(e.session_id??"").trim();if(!t){h.warn("cursor-adapter",`Dropping event ${e.event_id}: missing session_id`),this.callbacks.sendEventResult(e.event_id,"failed","missing session_id");return}if(!this.alive||this.stopped){h.warn("cursor-adapter",`Dropping event ${e.event_id}: adapter not running`),this.callbacks.sendEventAck(e.event_id,t),this.callbacks.sendEventResult(e.event_id,"failed","adapter not running");return}const n={adapterSessionId:t,text:this.inboundMessageIds.inject(t,Ce(String(e.content??""),e),e.msg_id),contextMessages:Ie(e)},s=new V(t),i=this.pendingBySession.get(t)??[];i.push({event:e,request:n,handle:s}),this.pendingBySession.set(t,i),h.info("cursor-adapter",`inbound queued: event=${e.event_id} session=${t} depth=${i.length}`),this.tryStartNext(t)}cancelSessionWork(e,t){const n=this.pendingBySession.get(e)??[];this.pendingBySession.delete(e);const s=this.activeBySession.get(e);s&&(this.killChildWithFallback(s.child),this.finishActive(e,"canceled",t));for(const i of n)this.callbacks.sendEventAck(i.event.event_id,i.event.session_id),this.callbacks.sendEventResult(i.event.event_id,"canceled",t),i.handle.emitDone({status:"canceled",error:t})}killChildWithFallback(e){I(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{I(e,"SIGKILL")}catch{}},5e3).unref()}deliverStopEvent(e,t){if(t){const n=this.activeBySession.get(t);if(n?.event.event_id===e){this.killChildWithFallback(n.child),this.finishActive(t,"canceled","stopped");return}const s=this.pendingBySession.get(t)??[],i=s.findIndex(r=>r.event.event_id===e);if(i>=0){const[r]=s.splice(i,1);s.length===0?this.pendingBySession.delete(t):this.pendingBySession.set(t,s),this.callbacks.sendEventAck(r.event.event_id,r.event.session_id),this.callbacks.sendEventResult(r.event.event_id,"canceled","stopped"),r.handle.emitDone({status:"canceled",error:"stopped"})}return}for(const[n,s]of this.activeBySession.entries())if(s.event.event_id===e){this.killChildWithFallback(s.child),this.finishActive(n,"canceled","stopped");return}for(const[n,s]of this.pendingBySession.entries()){const i=s.findIndex(o=>o.event.event_id===e);if(i<0)continue;const[r]=s.splice(i,1);s.length===0?this.pendingBySession.delete(n):this.pendingBySession.set(n,s),this.callbacks.sendEventAck(r.event.event_id,r.event.session_id),this.callbacks.sendEventResult(r.event.event_id,"canceled","stopped"),r.handle.emitDone({status:"canceled",error:"stopped"});return}}async handleLocalAction(e){const t=String(e.action_type??"").trim().toLowerCase(),n=e.params??{},s=String(n.session_id??"").trim(),i=e.action_id;if(t==="claude_interaction_reply")return String(n.kind??"").trim()==="permission"?(this.callbacks.sendLocalActionResult(i,"failed",void 0,"unsupported","Cursor adapter does not support interactive permission approvals"),{handled:!0,kind:"permission_unsupported"}):this.handleQuestionReply(e);switch(t){case"set_model":{const r=String(n.model_id??"").trim();if(!r||!s)return this.callbacks.sendLocalActionResult(i,"failed",void 0,"invalid_params","model_id and session_id are required"),{handled:!0,kind:"set_model"};const o=this.sessionRuntime.get(s)??{};this.sessionRuntime.set(s,{...o,modelId:r}),this.notifyBindingReady(s);const a=this.getToolbarMeta(s);return this.callbacks.sendLocalActionResult(i,"ok",{outcome:"model_set",session_context:{model_id:r,mode_id:a.mode_id,modelId:r,modeId:a.mode_id},model_id:r,mode_id:a.mode_id,available_models:this.availableModels,available_modes:this.availableModes}),{handled:!0,kind:"set_model"}}case"set_mode":{const r=C(n.mode_id);if(!r||!s)return this.callbacks.sendLocalActionResult(i,"failed",void 0,"invalid_params","mode_id must be approval, full_auto, or plan and session_id is required"),{handled:!0,kind:"set_mode"};const o=this.sessionRuntime.get(s)??{};this.sessionRuntime.set(s,{...o,modeId:r}),this.notifyBindingReady(s);const a=this.getToolbarMeta(s);return this.callbacks.sendLocalActionResult(i,"ok",{outcome:"mode_set",session_context:{model_id:a.model_id,mode_id:r,modelId:a.model_id,modeId:r},model_id:a.model_id,mode_id:r,available_models:this.availableModels,available_modes:this.availableModes}),{handled:!0,kind:"set_mode"}}case"get_context":{const r=s?this.sessionRuntime.get(s):void 0,o=this.config.options??{},a=this.getToolbarMeta(s);return this.callbacks.sendLocalActionResult(i,"ok",{session_context:{model_id:a.model_id,mode_id:a.mode_id,cwd:r?.cwd??o.workspace??null},model_id:a.model_id,mode_id:a.mode_id,modelId:a.model_id,modeId:a.mode_id,cwd:r?.cwd??o.workspace??null,available_models:this.availableModels,available_modes:this.availableModes}),{handled:!0,kind:"get_context"}}case"get_rate_limits":{await this.refreshAccountRateLimits({force:!0});const r=this.getRateLimitsSnapshot(s||void 0);return this.callbacks.sendLocalActionResult(i,"ok",r),s&&this.notifyBindingReady(s),{handled:!0,kind:"get_rate_limits"}}case"get_session_usage":{const r=s?this.getUsageSnapshot(s):null;if(r){const o={inputTokens:r.total.input,outputTokens:r.total.output,cacheReadInputTokens:r.total.cacheRead,cacheCreationInputTokens:r.total.cacheWrite};this.callbacks.sendLocalActionResult(i,"ok",{sessionId:s,adapterType:"cursor",sampledAt:r.sampledAt,turns:r.turns,total:o,models:[{model:this.getToolbarMeta(s).model_id??"auto",turns:r.turns,total:o}]})}else this.callbacks.sendLocalActionResult(i,"failed",void 0,"usage_not_found","No usage data found for this session");return{handled:!0,kind:"get_session_usage"}}case"session_control":{const r=String(n.verb??"").trim().toLowerCase();if(r==="restart"&&s)this.cancelSessionWork(s,"restarted"),this.callbacks.sendLocalActionResult(i,"ok",{outcome:"restarted"});else if(r==="status"){const o=this.sessionRuntime.get(s),a=this.config.options??{},l=this.getToolbarMeta(s),c=this.activeBySession.has(s);this.callbacks.sendLocalActionResult(i,"ok",{verb:"status",status:c?"running":"idle",session_context:{model_id:l.model_id,mode_id:l.mode_id,cwd:o?.cwd??a.workspace??null},model_id:l.model_id,mode_id:l.mode_id,modelId:l.model_id,modeId:l.mode_id,cwd:o?.cwd??a.workspace??null,available_models:this.availableModels,available_modes:this.availableModes})}else this.callbacks.sendLocalActionResult(i,"failed",void 0,"invalid_verb",`Unsupported verb: ${r}`);return{handled:!0,kind:"session_control"}}default:return{handled:!1,kind:"unsupported"}}}getSupportedCommands(){return[{name:"compact",description:"\u538B\u7F29\u4E0A\u4E0B\u6587",args:"[instructions]"}]}async execCommand(e,t,n){return e!=="compact"?{status:"unsupported",message:`Unsupported command: ${e}`}:this.runCompactHandoff(n,t)}async runCompactHandoff(e,t=""){if(!e)return{status:"failed",message:"session_id is required"};if(this.activeBySession.has(e))return{status:"failed",message:"Cannot compact while a Cursor turn is active"};const n=this.sessionRuntime.get(e)??{},s=this.config.options??{},i=n.cursorSessionId??this.bindingStore?.getAcpSessionId(e)??null;if(!i)return{status:"failed",message:"No Cursor chat to compact (send a message first)"};const r=String(n.cwd||s.workspace||process.cwd()),o=String(n.modelId||s.model||""),a=C(n.modeId||s.mode)??"full_auto",l=t.trim(),c=l?`${Q}
|
|
7
7
|
|
|
8
8
|
Additional focus from user:
|
|
9
|
-
${l}`:
|
|
9
|
+
${l}`:Q;this.emit("pauseIntake","compaction"),h.info("cursor-adapter",`[compact] summarize resume=${i} session=${e}`);try{const u=await this.runPrintOnce({prompt:c,resumeChatId:i,cwd:r,modelId:o||void 0,modeId:a,timeoutMs:O});if(!u.ok||!u.text.trim())return{status:"failed",message:u.error??"Summarize failed (empty result)"};const p=await this.createEmptyChat();return p?(this.sessionRuntime.set(e,{...n,cwd:r,modelId:o||n.modelId,modeId:a,cursorSessionId:p}),this.transcriptPathBySession.delete(e),this.bindingStore?.setAcpSessionId(e,p),this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e),this.pendingHandoffBySession.set(e,u.text.trim()),this.lastContextBySession.set(e,fe(0,ge(o))),this.notifyBindingReady(e),h.info("cursor-adapter",`[compact] handoff ready: old=${i} new=${p} summaryChars=${u.text.trim().length}`),{status:"ok",message:"Context compacted via summarize + new chat",data:{previousChatId:i,chatId:p}}):{status:"failed",message:"agent create-chat failed"}}finally{this.emit("resumeIntake","compaction")}}runPrintOnce(e){const t={...process.env,...this.config.env??{}},n=M(this.config.command,t),s=[...n.prefixArgs,...this.config.args??[]];s.push("-p","--output-format","stream-json"),this.config.options?.trust!==!1&&s.push("--trust"),e.cwd&&s.push("--workspace",e.cwd),e.modelId&&s.push("--model",e.modelId);const i=C(e.modeId)??"full_auto";return i==="full_auto"?s.push("--yolo"):i==="plan"&&s.push("--plan"),e.resumeChatId&&s.push("--resume",e.resumeChatId),s.push(e.prompt),new Promise(r=>{let o;try{o=R(n.command,s,{cwd:e.cwd||process.cwd(),env:n.env,stdio:["ignore","pipe","pipe"]}).process}catch(f){r({ok:!1,text:"",error:`spawn failed: ${f instanceof Error?f.message:String(f)}`});return}let a="",l="",c="",u=!1;const p=e.timeoutMs&&e.timeoutMs>0?e.timeoutMs:O,_=setTimeout(()=>{u||(u=!0,this.killChildWithFallback(o),r({ok:!1,text:a,sessionId:l||void 0,error:`compact timeout after ${p}ms`}))},p);_.unref?.();const v=(f,y)=>{u||(u=!0,clearTimeout(_),r({ok:f,text:a,sessionId:l||void 0,error:y}))};$({input:o.stdout}).on("line",f=>{const y=f.trim();if(!y)return;let g;try{g=JSON.parse(y)}catch{return}if(g?.type!=="result")return;const m=typeof g?.result=="string"?g.result:"";m&&(a=m);const k=String(g?.session_id??"").trim();k&&(l=k)}),o.stderr?.on("data",f=>{c+=typeof f=="string"?f:f.toString("utf8")}),o.on("error",f=>v(!1,f.message)),o.on("close",f=>{if(!u){if(a.trim()){v(!0);return}v(!1,c.trim()||`cursor agent exited with code ${f??"unknown"}`)}})})}createEmptyChat(){const e={...process.env,...this.config.env??{}},t=M(this.config.command,e);return new Promise(n=>{let s;try{s=R(t.command,[...t.prefixArgs,"create-chat"],{cwd:process.cwd(),env:t.env,stdio:["ignore","pipe","pipe"]}).process}catch{n(null);return}let i="",r=!1;const o=setTimeout(()=>{r||(r=!0,this.killChildWithFallback(s),n(null))},3e4);o.unref?.(),s.stdout?.on("data",a=>{i+=typeof a=="string"?a:a.toString("utf8")}),s.on("error",()=>{r||(r=!0,clearTimeout(o),n(null))}),s.on("close",a=>{if(r)return;r=!0,clearTimeout(o);const l=i.trim().split(/\s+/)[0]??"";n(a===0&&/^[0-9a-f-]{16,}$/i.test(l)?l:null)})})}setPermissionHandler(e){this.permissionHandler=e}async ping(e){if(!this.alive||this.stopped||(this.config.options??{}).mcp_tools!==!1&&this.internalApi===null)return!1;for(const n of this.activeBySession.values()){const s=n.child?.pid;if(s&&!B(s))return!1}return!0}getStatus(){let e=0;for(const t of this.pendingBySession.values())e+=t.length;return{alive:this.alive,busy:this.activeBySession.size>0,sessions:this.sessions.size,details:{queueDepth:e+this.inboundQueue.length,activeSessions:this.activeBySession.size}}}getActiveEventIds(){const e=[];for(const t of this.activeBySession.values())t.event.event_id&&e.push(t.event.event_id);return e}clearActiveEventForShutdown(){for(const[e,t]of this.activeBySession)this.snapshotAuditBoundary(t.event.event_id,e);this.activeBySession.clear()}takeAuditBoundary(e){const t=this.completedAuditBoundaries.get(e);return t&&this.completedAuditBoundaries.delete(e),t}getMcpConfig(){return null}async probe(e){const t=this.getStatus();return{...await re(this.config.command||"cursor-agent",{alive:t.alive,busy:t.busy,started:this.alive},e),session:this.probeSessionRecord()}}probeSessionRecord(){const e=this.firstKnownCursorSessionId(),t=e?K(e):null;if(!t)return{recordPath:null,lastActivityMs:null,freshMs:null};try{const n=D(t);return{recordPath:t,lastActivityMs:n.mtimeMs,freshMs:Date.now()-n.mtimeMs}}catch{return{recordPath:t,lastActivityMs:null,freshMs:null}}}firstKnownCursorSessionId(){for(const e of this.activeBySession.keys()){const t=this.sessionRuntime.get(e);if(t?.cursorSessionId)return t.cursorSessionId}for(const e of this.sessionRuntime.values())if(e.cursorSessionId)return e.cursorSessionId;return null}getUsageSnapshot(e){return this.lastUsageBySession.get(e)??null}getRateLimitsSnapshot(e){const t=this.cachedAccountRateLimits,n=e?this.lastContextBySession.get(e)??null:null;if(!t)return{adapterType:"cursor",available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:n,tokenUsage:null};const s=Date.parse(t.sampledAt);return{adapterType:"cursor",available:t.available&&!!t.rateLimits,cached:!0,sampledAt:Number.isFinite(s)?s:Date.now(),rateLimits:t.rateLimits,contextWindow:n,tokenUsage:null,...t.displayMessage?{displayMessage:t.displayMessage}:{},...t.error?{error:t.error}:{}}}async refreshAccountRateLimits(e){const t=e?.force===!0,n=this.cachedAccountRateLimits,s=n?Date.now()-Date.parse(n.sampledAt):Number.POSITIVE_INFINITY;if(!t&&n&&Number.isFinite(s)&&s<6e4||this.rateLimitsInflight&&(await this.rateLimitsInflight,!t))return;const i=(async()=>{const r=await me();this.cachedAccountRateLimits={available:r.available,sampledAt:r.sampledAt,rateLimits:r.rateLimits,displayMessage:r.displayMessage,error:r.error},r.available&&r.rateLimits?h.info("cursor-adapter",`[rate-limits] monthly=${r.rateLimits.fiveHour.usedPercentage.toFixed(1)}% api=${r.rateLimits.sevenDay.usedPercentage.toFixed(1)}% resetsAt=${r.rateLimits.fiveHour.resetsAt}`+(r.displayMessage?` msg=${r.displayMessage}`:"")):h.warn("cursor-adapter",`[rate-limits] unavailable: ${r.error??"unknown"}`)})();this.rateLimitsInflight=i.finally(()=>{this.rateLimitsInflight=null}),await this.rateLimitsInflight}getToolbarMeta(e){const t=this.config.options??{},n=e||String(t.aibotSessionId??""),s=n?this.sessionRuntime.get(n):void 0,i=String(s?.modelId||t.model||"auto"),r=C(s?.modeId||t.mode)??"full_auto",o={model_id:i,mode_id:r,currentModelId:i,currentModeId:r,available_models:this.availableModels,available_modes:this.availableModes},a=this.cachedAccountRateLimits?.rateLimits;if(a?.fiveHour||a?.sevenDay){const c=Date.parse(this.cachedAccountRateLimits?.sampledAt??"")||Date.now();o.rate_limits={...a.fiveHour?{fiveHour:a.fiveHour}:{},...a.sevenDay?{sevenDay:a.sevenDay}:{},sampledAt:c}}const l=n?this.lastContextBySession.get(n):void 0;return l&&(o.context_window={usedPercentage:l.usedPercentage,remainingPercentage:l.remainingPercentage,usedTokens:l.usedTokens,sizeTokens:l.sizeTokens}),o}notifyBindingReady(e){if(!this.callbacks.sendUpdateBindingCard)return;const t=this.config.options??{},n=e||String(t.aibotSessionId??"");if(!n)return;const s=this.sessionRuntime.get(n),i=String(s?.cwd||t.workspace||"");i&&this.callbacks.sendUpdateBindingCard(n,this.activeBySession.has(n)?"busy":"ready",i,this.getToolbarMeta(n))}buildPromptText(e){let t;!e.contextMessages||e.contextMessages.length===0?t=e.text:t=`${e.contextMessages.map(r=>`[${r.senderId}] ${r.content}`).join(`
|
|
10
10
|
`)}
|
|
11
11
|
|
|
12
12
|
[Current user message]
|
|
@@ -18,6 +18,6 @@ ${t}`);const s=this.pendingHandoffBySession.get(e.adapterSessionId);return s&&(t
|
|
|
18
18
|
${s}
|
|
19
19
|
|
|
20
20
|
[Current user message]
|
|
21
|
-
${t}`),this.identity.injectOnce(e.adapterSessionId,t)}handleStdoutLineForActive(e,t){if(e.done)return;const n=t.trim();if(!n)return;e.lastIoAt=Date.now();const{event:s}=e;let i;try{i=JSON.parse(n)}catch{this.armActiveIdleTimer(e.request.adapterSessionId);return}const r=this.auditCaptures.get(s.event_id);if(r&&i&&typeof i=="object"&&r.push({sequence:r.length,observedAt:new Date().toISOString(),event:structuredClone(i)}),i?.type==="tool_call"){const l=String(i?.call_id??""),c=String(i?.subtype??"");l&&(c==="started"||c==="start"?(this.flushAssistantStreamBuffer(e),e.toolCallsInFlight.add(l),e.toolCallsStarted+=1,this.handleSpecialToolCallStarted(e,i)):H.has(c)&&e.toolCallsInFlight.delete(l))}this.armActiveIdleTimer(e.request.adapterSessionId);const o=Ie(i);o&&this.callbacks.sendRawEventEnvelope?.(s.event_id,s.session_id,o);const a=Ce(i,e.assistantTextEmitted);if(a&&this.enqueueAssistantStreamDelta(e,a),i?.type==="result"){e.sawResult=!0;const l=typeof i?.result=="string"?i.result.trim():"";l&&(e.assistantTextEmitted?l.startsWith(e.assistantTextEmitted)&&l.length>e.assistantTextEmitted.length&&this.enqueueAssistantStreamDelta(e,l.slice(e.assistantTextEmitted.length)):this.enqueueAssistantStreamDelta(e,l)),this.flushAssistantStreamBuffer(e);const c=String(i?.session_id??"").trim();if(c){const f=this.sessionRuntime.get(e.request.adapterSessionId)??{};f.cursorSessionId!==c&&this.transcriptPathBySession.delete(e.request.adapterSessionId),this.sessionRuntime.set(e.request.adapterSessionId,{...f,cursorSessionId:c}),this.bindingStore?.setAcpSessionId(e.request.adapterSessionId,c)}const u=i?.usage??{},p=this.lastUsageBySession.get(e.request.adapterSessionId);this.lastUsageBySession.set(e.request.adapterSessionId,{sampledAt:new Date().toISOString(),turns:(p?.turns??0)+1,total:{input:(p?.total.input??0)+Number(u.inputTokens??0),output:(p?.total.output??0)+Number(u.outputTokens??0),cacheRead:(p?.total.cacheRead??0)+Number(u.cacheReadTokens??0),cacheWrite:(p?.total.cacheWrite??0)+Number(u.cacheWriteTokens??0)}});const _=String((this.sessionRuntime.get(e.request.adapterSessionId)?.modelId??this.config.options?.model??"")||""),v=Math.max(1,(e.toolCallsStarted??0)+1),b=Number(u.inputTokens??0),m=Number(u.cacheReadTokens??0),y=Number(u.cacheWriteTokens??0),g=Se({inputTokens:b,cacheReadTokens:m,cacheWriteTokens:y},_,{apiRounds:v});g&&(this.lastContextBySession.set(e.request.adapterSessionId,g),h.info("cursor-adapter",`[context_window] used=${g.usedTokens} size=${g.sizeTokens} pct=${g.usedPercentage.toFixed(1)}% model=${_||"auto"} rawIn=${b} rawCache=${m} rawWrite=${y} apiRounds=${v}`))}}handleSpecialToolCallStarted(e,t){const n=z(t);if(X(n.toolName)){const s=we(n.toolInput);s?(e.seq+=1,this.callbacks.sendStreamChunk(e.event.event_id,e.event.session_id,s,e.seq,!1),h.info("cursor-adapter",`CreatePlan forwarded as stream text: event=${e.event.event_id} chars=${s.length}`)):(e.seq+=1,this.callbacks.sendStreamChunk(e.event.event_id,e.event.session_id,"[CreatePlan] \u65B9\u6848\u5185\u5BB9\u89E3\u6790\u5931\u8D25\uFF0C\u672A\u4E0B\u53D1\u6B63\u6587\u3002",e.seq,!1),h.warn("cursor-adapter",`CreatePlan missing plan body: event=${e.event.event_id}`));return}G(n.toolName)&&this.emitAskQuestionCard(e,n.toolInput)}emitAskQuestionCard(e,t){const n=e.event,s=ke(t);if(!s){e.seq+=1,this.callbacks.sendStreamChunk(n.event_id,n.session_id,"[AskQuestion] \u95EE\u9898\u5185\u5BB9\u89E3\u6790\u5931\u8D25\uFF0C\u672A\u4E0B\u53D1\u95EE\u9898\u5361\u3002",e.seq,!1),h.warn("cursor-adapter",`AskQuestion parse failed: event=${n.event_id}`);return}if(!this.callbacks.sendAgentQuestionCard){h.warn("cursor-adapter","AskQuestion skipped: sendAgentQuestionCard callback not wired");return}const i=te(),r=Date.now();this.pendingQuestionByRequestId.set(i,{eventId:n.event_id,sessionId:n.session_id,createdAt:r}),this.callbacks.sendAgentQuestionCard(n.event_id,n.session_id,{request_id:i,mode:"form",questions:s,expires_at:r+T}),h.info("cursor-adapter",`Sent agent_question card: request_id=${i} questions=${s.length} event=${n.event_id}`)}async handleQuestionReply(e){const t=e.params??{},n=String(t.request_id??"").trim();if(!n)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"request_id_required","request_id is required"),{handled:!0,kind:"question_reply_no_id"};const s=this.pendingQuestionByRequestId.get(n),i=s?Date.now()-s.createdAt>T+3e4:!0;if(!s||i)return this.pendingQuestionByRequestId.delete(n),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"interaction_request_not_pending","The question is no longer pending; the reply was not delivered."),{handled:!0,kind:"question_reply_not_pending"};const r=t.resolution??{},o=String(r.type??"");if(o==="action"&&String(r.value??"")==="cancel")return this.pendingQuestionByRequestId.delete(n),this.callbacks.sendLocalActionResult(e.action_id,"ok",{request_id:n,resolution:"cancel"}),{handled:!0,kind:"question_reply_cancel"};let a="";return o==="text"?a=String(r.value??""):o==="map"&&(a=(Array.isArray(r.entries)?r.entries:[]).map(c=>c.value).join(", ")),a?(this.pendingQuestionByRequestId.delete(n),this.pendingQuestionAnswerBySession.set(s.sessionId,a),this.callbacks.sendLocalActionResult(e.action_id,"ok",{request_id:n,resolution:"answer"}),h.info("cursor-adapter",`Question reply cached for next prompt: request_id=${n} session=${s.sessionId}`),{handled:!0,kind:"question_reply"}):(this.pendingQuestionByRequestId.delete(n),this.callbacks.sendLocalActionResult(e.action_id,"ok",{request_id:n,resolution:"cancel"}),{handled:!0,kind:"question_reply_empty"})}enqueueAssistantStreamDelta(e,t){t&&(e.assistantTextEmitted+=t,e.streamBuffer+=t,e.streamBuffer.length>=_e&&this.flushAssistantStreamBuffer(e))}flushAssistantStreamBuffer(e){if(!e.streamBuffer)return;const t=e.streamBuffer;e.streamBuffer="",e.seq+=1,this.callbacks.sendStreamChunk(e.event.event_id,e.event.session_id,t,e.seq,!1,void 0,void 0)}shouldExtendByLiveness(e){const t=this.activeBySession.get(e);if(!t||t.done)return!1;const n=t.child?.pid;if(!n||!B(n)||t.sawResult)return!1;const s=Date.now(),i=s-t.lastIoAt,r=this.transcriptFreshMsForSession(e);if(i<Q||r!==null&&r<Q)return t.livenessExtendStartAt=s,h.info("cursor-adapter",`Liveness check: fresh progress for ${t.event.event_id} (ioAge=${i}ms, transcriptAge=${r??"n/a"}, toolsInFlight=${t.toolCallsInFlight.size}), extending`),!0;const a=t.livenessExtendStartAt??s;return t.livenessExtendStartAt===void 0&&(t.livenessExtendStartAt=a),s-a>O?(h.warn("cursor-adapter",`Liveness extension budget exhausted for ${t.event.event_id} (no progress for ${Math.round((s-a)/6e4)}min), allowing idle kill`),!1):(h.info("cursor-adapter",`Liveness check: turn in progress for ${t.event.event_id} (toolsInFlight=${t.toolCallsInFlight.size}, ioAge=${i}ms), extending`),!0)}transcriptFreshMsForSession(e){const t=this.sessionRuntime.get(e)?.cursorSessionId;if(!t)return null;let n=this.transcriptPathBySession.get(e);if(!n){const s=Y(t);if(!s)return null;this.transcriptPathBySession.set(e,s),n=s}try{return Date.now()-D(n).mtimeMs}catch{return this.transcriptPathBySession.delete(e),null}}hasPendingQuestionForSession(e){const t=Date.now();for(const[n,s]of this.pendingQuestionByRequestId)if(s.sessionId===e){if(t-s.createdAt>T){this.pendingQuestionByRequestId.delete(n);continue}return!0}return!1}armActiveIdleTimer(e){const t=this.activeBySession.get(e);!t||t.done||(t.idleTimer&&clearTimeout(t.idleTimer),t.idleTimer=setTimeout(()=>{if(t.done)return;if(this.hasPendingQuestionForSession(e)){h.info("cursor-adapter",`Idle timeout skipped: awaiting AskQuestion for ${t.event.event_id}, resetting timer`),this.armActiveIdleTimer(e);return}if(this.shouldExtendByLiveness(e)){this.armActiveIdleTimer(e);return}if(t.sawResult){h.warn("cursor-adapter",`Idle after result with no close \u2014 finishing as responded: event=${t.event.event_id} session=${e}`),this.killChildWithFallback(t.child),this.finishActive(e,"responded");return}const n=t.child?.pid,i=!!(n&&B(n))?`liveness budget exhausted after ${O/6e4}min`:"child process dead";h.error("cursor-adapter",`Idle timeout (${i}, toolsInFlight=${t.toolCallsInFlight.size}) \u2014 killing cursor child: event=${t.event.event_id} session=${e}`),this.killChildWithFallback(t.child),this.finishActive(e,"failed",`idle timeout: ${i}`)},ve),t.idleTimer.unref?.())}finishActive(e,t,n){const s=this.activeBySession.get(e);if(!s)return;s.done=!0,s.timer&&clearTimeout(s.timer),s.idleTimer&&clearTimeout(s.idleTimer),this.flushAssistantStreamBuffer(s),s.seq+=1;const i=String(s.event.quoted_message_id??"").trim()||void 0;this.callbacks.sendStreamChunk(s.event.event_id,s.event.session_id,"",s.seq,!0,void 0,i),h.info("cursor-adapter",`job finish: event=${s.event.event_id} session=${s.event.session_id} status=${t}${n?` msg=${n}`:""}`),this.snapshotAuditBoundary(s.event.event_id,e),this.emit("eventDone",s.event.event_id),this.callbacks.sendEventResult(s.event.event_id,t,n),t==="responded"?s.handle.emitDone({status:"completed"}):t==="canceled"?s.handle.emitDone({status:"canceled",error:n}):s.handle.emitDone({status:"failed",error:n}),this.activeBySession.delete(e),this.notifyBindingReady(e),this.tryStartNext(e)}snapshotAuditBoundary(e,t){const n=this.auditCaptures.get(e);if(!n)return;const s=this.sessionRuntime.get(t);this.completedAuditBoundaries.set(e,{adapterType:"cursor",providerSessionId:s?.cursorSessionId,cursorEvidence:{events:n}}),this.auditCaptures.delete(e)}shouldRetryWithoutContinue(e){if(!e.usedContinue||e.retryCount>0)return!1;const t=e.stderr.toLowerCase(),n=t.includes("resume")||t.includes("continue")||t.includes("chat")||t.includes("session"),s=t.includes("not found")||t.includes("no previous session")||t.includes("does not exist")||t.includes("invalid");return n&&s}ensureWorkspaceMcpAndSkills(e){if(!this.internalApi)return;this.ensureCursorMcpConfig(e,this.internalApi.url);const t=A(N(),".cursor","skills"),n=he(t);n.length>0&&h.info("cursor-adapter",`Synced connector skills to ${t}: [${n.join(", ")}]`)}ensureCursorMcpConfig(e,t){const n=le(this.callbacks.getAgentId?.()),s={command:process.execPath,args:[ne(ie(import.meta.url),"../../../mcp/acp-mcp-server.js"),"--api-url",t]},i=[e],r=this.resolveGitRoot(e);r&&r!==e&&i.push(r);let o=null;for(const a of i){const l=this.writeCursorMcpConfig(a,n,s,t);!o&&l&&(o=l)}o&&this.recordCursorMcpRegistry(e,o,s)}resolveGitRoot(e){try{return ee("git",["-C",e,"rev-parse","--show-toplevel"],{timeout:5e3,stdio:["ignore","pipe","ignore"]}).toString("utf8").trim()||null}catch{return null}}writeCursorMcpConfig(e,t,n,s){try{const i=A(e,".cursor"),r=A(i,"mcp.json");E(i,{recursive:!0});let o={};try{o=JSON.parse(L(r,"utf8"))}catch{o={}}(!o.mcpServers||typeof o.mcpServers!="object")&&(o.mcpServers={});const a=ce(o.mcpServers,s);return o.mcpServers[t]=n,P(r,`${JSON.stringify(o,null,2)}
|
|
22
|
-
`,"utf8"),h.info("cursor-adapter",`MCP config synced: dir=${e} file=${r} server=${t}${a.length>0?` pruned=${a.join(",")}`:""}`),r}catch(i){return h.warn("cursor-adapter",`Failed to ensure ${A(e,".cursor","mcp.json")}: ${String(i)}`),null}}recordCursorMcpRegistry(e,t,n){try{const s=A(
|
|
23
|
-
`,"utf8")}catch(s){h.warn("cursor-adapter",`Failed to record MCP registry: ${String(s)}`)}}}export{
|
|
21
|
+
${t}`),this.identity.injectOnce(e.adapterSessionId,t)}handleStdoutLineForActive(e,t){if(e.done)return;const n=t.trim();if(!n)return;e.lastIoAt=Date.now();const{event:s}=e;let i;try{i=JSON.parse(n)}catch{this.armActiveIdleTimer(e.request.adapterSessionId);return}const r=this.auditCaptures.get(s.event_id);if(r&&i&&typeof i=="object"&&r.push({sequence:r.length,observedAt:new Date().toISOString(),event:structuredClone(i)}),i?.type==="tool_call"){const l=String(i?.call_id??""),c=String(i?.subtype??"");l&&(c==="started"||c==="start"?(this.flushAssistantStreamBuffer(e),e.toolCallsInFlight.add(l),e.toolCallsStarted+=1,this.handleSpecialToolCallStarted(e,i)):W.has(c)&&e.toolCallsInFlight.delete(l))}this.armActiveIdleTimer(e.request.adapterSessionId);const o=ke(i);o&&this.callbacks.sendRawEventEnvelope?.(s.event_id,s.session_id,o);const a=we(i,e.assistantTextEmitted);if(a&&this.enqueueAssistantStreamDelta(e,a),i?.type==="result"){e.sawResult=!0;const l=typeof i?.result=="string"?i.result.trim():"";l&&(e.assistantTextEmitted?l.startsWith(e.assistantTextEmitted)&&l.length>e.assistantTextEmitted.length&&this.enqueueAssistantStreamDelta(e,l.slice(e.assistantTextEmitted.length)):this.enqueueAssistantStreamDelta(e,l)),this.flushAssistantStreamBuffer(e);const c=String(i?.session_id??"").trim();if(c){const m=this.sessionRuntime.get(e.request.adapterSessionId)??{};m.cursorSessionId!==c&&this.transcriptPathBySession.delete(e.request.adapterSessionId),this.sessionRuntime.set(e.request.adapterSessionId,{...m,cursorSessionId:c}),this.bindingStore?.setAcpSessionId(e.request.adapterSessionId,c)}const u=i?.usage??{},p=this.lastUsageBySession.get(e.request.adapterSessionId);this.lastUsageBySession.set(e.request.adapterSessionId,{sampledAt:new Date().toISOString(),turns:(p?.turns??0)+1,total:{input:(p?.total.input??0)+Number(u.inputTokens??0),output:(p?.total.output??0)+Number(u.outputTokens??0),cacheRead:(p?.total.cacheRead??0)+Number(u.cacheReadTokens??0),cacheWrite:(p?.total.cacheWrite??0)+Number(u.cacheWriteTokens??0)}});const _=String((this.sessionRuntime.get(e.request.adapterSessionId)?.modelId??this.config.options?.model??"")||""),v=Math.max(1,(e.toolCallsStarted??0)+1),b=Number(u.inputTokens??0),f=Number(u.cacheReadTokens??0),y=Number(u.cacheWriteTokens??0),g=pe({inputTokens:b,cacheReadTokens:f,cacheWriteTokens:y},_,{apiRounds:v});g&&(this.lastContextBySession.set(e.request.adapterSessionId,g),h.info("cursor-adapter",`[context_window] used=${g.usedTokens} size=${g.sizeTokens} pct=${g.usedPercentage.toFixed(1)}% model=${_||"auto"} rawIn=${b} rawCache=${f} rawWrite=${y} apiRounds=${v}`))}}handleSpecialToolCallStarted(e,t){const n=U(t);if(J(n.toolName)){const s=be(n.toolInput);s?(e.seq+=1,this.callbacks.sendStreamChunk(e.event.event_id,e.event.session_id,s,e.seq,!1),h.info("cursor-adapter",`CreatePlan forwarded as stream text: event=${e.event.event_id} chars=${s.length}`)):(e.seq+=1,this.callbacks.sendStreamChunk(e.event.event_id,e.event.session_id,"[CreatePlan] \u65B9\u6848\u5185\u5BB9\u89E3\u6790\u5931\u8D25\uFF0C\u672A\u4E0B\u53D1\u6B63\u6587\u3002",e.seq,!1),h.warn("cursor-adapter",`CreatePlan missing plan body: event=${e.event.event_id}`));return}z(n.toolName)&&this.emitAskQuestionCard(e,n.toolInput)}emitAskQuestionCard(e,t){const n=e.event,s=Ae(t);if(!s){e.seq+=1,this.callbacks.sendStreamChunk(n.event_id,n.session_id,"[AskQuestion] \u95EE\u9898\u5185\u5BB9\u89E3\u6790\u5931\u8D25\uFF0C\u672A\u4E0B\u53D1\u95EE\u9898\u5361\u3002",e.seq,!1),h.warn("cursor-adapter",`AskQuestion parse failed: event=${n.event_id}`);return}if(!this.callbacks.sendAgentQuestionCard){h.warn("cursor-adapter","AskQuestion skipped: sendAgentQuestionCard callback not wired");return}const i=Z(),r=Date.now();this.pendingQuestionByRequestId.set(i,{eventId:n.event_id,sessionId:n.session_id,createdAt:r}),this.callbacks.sendAgentQuestionCard(n.event_id,n.session_id,{request_id:i,mode:"form",questions:s,expires_at:r+x}),h.info("cursor-adapter",`Sent agent_question card: request_id=${i} questions=${s.length} event=${n.event_id}`)}async handleQuestionReply(e){const t=e.params??{},n=String(t.request_id??"").trim();if(!n)return this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"request_id_required","request_id is required"),{handled:!0,kind:"question_reply_no_id"};const s=this.pendingQuestionByRequestId.get(n),i=s?Date.now()-s.createdAt>x+3e4:!0;if(!s||i)return this.pendingQuestionByRequestId.delete(n),this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"interaction_request_not_pending","The question is no longer pending; the reply was not delivered."),{handled:!0,kind:"question_reply_not_pending"};const r=t.resolution??{},o=String(r.type??"");if(o==="action"&&String(r.value??"")==="cancel")return this.pendingQuestionByRequestId.delete(n),this.callbacks.sendLocalActionResult(e.action_id,"ok",{request_id:n,resolution:"cancel"}),{handled:!0,kind:"question_reply_cancel"};let a="";return o==="text"?a=String(r.value??""):o==="map"&&(a=(Array.isArray(r.entries)?r.entries:[]).map(c=>c.value).join(", ")),a?(this.pendingQuestionByRequestId.delete(n),this.pendingQuestionAnswerBySession.set(s.sessionId,a),this.callbacks.sendLocalActionResult(e.action_id,"ok",{request_id:n,resolution:"answer"}),h.info("cursor-adapter",`Question reply cached for next prompt: request_id=${n} session=${s.sessionId}`),{handled:!0,kind:"question_reply"}):(this.pendingQuestionByRequestId.delete(n),this.callbacks.sendLocalActionResult(e.action_id,"ok",{request_id:n,resolution:"cancel"}),{handled:!0,kind:"question_reply_empty"})}enqueueAssistantStreamDelta(e,t){t&&(e.assistantTextEmitted+=t,e.streamBuffer+=t,e.streamBuffer.length>=ye&&this.flushAssistantStreamBuffer(e))}flushAssistantStreamBuffer(e){if(!e.streamBuffer)return;const t=e.streamBuffer;e.streamBuffer="",e.seq+=1,this.callbacks.sendStreamChunk(e.event.event_id,e.event.session_id,t,e.seq,!1,void 0,void 0)}shouldExtendByLiveness(e){const t=this.activeBySession.get(e);if(!t||t.done)return!1;const n=t.child?.pid;if(!n||!B(n)||t.sawResult)return!1;const s=Date.now(),i=s-t.lastIoAt,r=this.transcriptFreshMsForSession(e);if(i<F||r!==null&&r<F)return t.livenessExtendStartAt=s,h.info("cursor-adapter",`Liveness check: fresh progress for ${t.event.event_id} (ioAge=${i}ms, transcriptAge=${r??"n/a"}, toolsInFlight=${t.toolCallsInFlight.size}), extending`),!0;const a=t.livenessExtendStartAt??s;return t.livenessExtendStartAt===void 0&&(t.livenessExtendStartAt=a),s-a>j?(h.warn("cursor-adapter",`Liveness extension budget exhausted for ${t.event.event_id} (no progress for ${Math.round((s-a)/6e4)}min), allowing idle kill`),!1):(h.info("cursor-adapter",`Liveness check: turn in progress for ${t.event.event_id} (toolsInFlight=${t.toolCallsInFlight.size}, ioAge=${i}ms), extending`),!0)}transcriptFreshMsForSession(e){const t=this.sessionRuntime.get(e)?.cursorSessionId;if(!t)return null;let n=this.transcriptPathBySession.get(e);if(!n){const s=K(t);if(!s)return null;this.transcriptPathBySession.set(e,s),n=s}try{return Date.now()-D(n).mtimeMs}catch{return this.transcriptPathBySession.delete(e),null}}hasPendingQuestionForSession(e){const t=Date.now();for(const[n,s]of this.pendingQuestionByRequestId)if(s.sessionId===e){if(t-s.createdAt>x){this.pendingQuestionByRequestId.delete(n);continue}return!0}return!1}armActiveIdleTimer(e){const t=this.activeBySession.get(e);!t||t.done||(t.idleTimer&&clearTimeout(t.idleTimer),t.idleTimer=setTimeout(()=>{if(t.done)return;if(this.hasPendingQuestionForSession(e)){h.info("cursor-adapter",`Idle timeout skipped: awaiting AskQuestion for ${t.event.event_id}, resetting timer`),this.armActiveIdleTimer(e);return}if(this.shouldExtendByLiveness(e)){this.armActiveIdleTimer(e);return}if(t.sawResult){h.warn("cursor-adapter",`Idle after result with no close \u2014 finishing as responded: event=${t.event.event_id} session=${e}`),this.killChildWithFallback(t.child),this.finishActive(e,"responded");return}const n=t.child?.pid,i=!!(n&&B(n))?`liveness budget exhausted after ${j/6e4}min`:"child process dead";h.error("cursor-adapter",`Idle timeout (${i}, toolsInFlight=${t.toolCallsInFlight.size}) \u2014 killing cursor child: event=${t.event.event_id} session=${e}`),this.killChildWithFallback(t.child),this.finishActive(e,"failed",`idle timeout: ${i}`)},Se),t.idleTimer.unref?.())}finishActive(e,t,n){const s=this.activeBySession.get(e);if(!s)return;s.done=!0,s.timer&&clearTimeout(s.timer),s.idleTimer&&clearTimeout(s.idleTimer),this.flushAssistantStreamBuffer(s),s.seq+=1;const i=String(s.event.quoted_message_id??"").trim()||void 0;this.callbacks.sendStreamChunk(s.event.event_id,s.event.session_id,"",s.seq,!0,void 0,i),h.info("cursor-adapter",`job finish: event=${s.event.event_id} session=${s.event.session_id} status=${t}${n?` msg=${n}`:""}`),this.snapshotAuditBoundary(s.event.event_id,e),this.emit("eventDone",s.event.event_id),this.callbacks.sendEventResult(s.event.event_id,t,n),t==="responded"?s.handle.emitDone({status:"completed"}):t==="canceled"?s.handle.emitDone({status:"canceled",error:n}):s.handle.emitDone({status:"failed",error:n}),this.activeBySession.delete(e),this.notifyBindingReady(e),this.tryStartNext(e)}snapshotAuditBoundary(e,t){const n=this.auditCaptures.get(e);if(!n)return;const s=this.sessionRuntime.get(t);this.completedAuditBoundaries.set(e,{adapterType:"cursor",providerSessionId:s?.cursorSessionId,cursorEvidence:{events:n}}),this.auditCaptures.delete(e)}shouldRetryWithoutContinue(e){if(!e.usedContinue||e.retryCount>0)return!1;const t=e.stderr.toLowerCase(),n=t.includes("resume")||t.includes("continue")||t.includes("chat")||t.includes("session"),s=t.includes("not found")||t.includes("no previous session")||t.includes("does not exist")||t.includes("invalid");return n&&s}ensureWorkspaceMcpAndSkills(e){if(!this.internalApi)return;this.ensureCursorMcpConfig(e,this.internalApi.url);const t=A(N(),".cursor","skills"),n=ce(t);n.length>0&&h.info("cursor-adapter",`Synced connector skills to ${t}: [${n.join(", ")}]`)}ensureCursorMcpConfig(e,t){const n=ae(this.callbacks.getAgentId?.()),s={command:process.execPath,args:[te(se(import.meta.url),"../../../mcp/acp-mcp-server.js"),"--api-url",t]},i=[e],r=this.resolveGitRoot(e);r&&r!==e&&i.push(r);let o=null;for(const a of i){const l=this.writeCursorMcpConfig(a,n,s,t);!o&&l&&(o=l)}o&&this.recordCursorMcpRegistry(e,o,s)}resolveGitRoot(e){try{return Y("git",["-C",e,"rev-parse","--show-toplevel"],{timeout:5e3,stdio:["ignore","pipe","ignore"],windowsHide:!0}).toString("utf8").trim()||null}catch{return null}}writeCursorMcpConfig(e,t,n,s){try{const i=A(e,".cursor"),r=A(i,"mcp.json");E(i,{recursive:!0});let o={};try{o=JSON.parse(L(r,"utf8"))}catch{o={}}(!o.mcpServers||typeof o.mcpServers!="object")&&(o.mcpServers={});const a=de(o.mcpServers,s);return o.mcpServers[t]=n,P(r,`${JSON.stringify(o,null,2)}
|
|
22
|
+
`,"utf8"),h.info("cursor-adapter",`MCP config synced: dir=${e} file=${r} server=${t}${a.length>0?` pruned=${a.join(",")}`:""}`),r}catch(i){return h.warn("cursor-adapter",`Failed to ensure ${A(e,".cursor","mcp.json")}: ${String(i)}`),null}}recordCursorMcpRegistry(e,t,n){try{const s=A(ne.data,"cursor"),i=A(s,"mcp-registry.json");E(s,{recursive:!0});let r={};try{r=JSON.parse(L(i,"utf8"))}catch{r={}}r[e]={mcp_path:t,server:n,updated_at:new Date().toISOString()},P(i,`${JSON.stringify(r,null,2)}
|
|
23
|
+
`,"utf8")}catch(s){h.warn("cursor-adapter",`Failed to record MCP registry: ${String(s)}`)}}}export{G as CURSOR_MODE_OPTIONS,T as CursorAdapter,we as extractCursorAssistantStreamDelta,K as findCursorTranscript,be as formatCursorCreatePlanText,z as isCursorAskQuestionTool,J as isCursorCreatePlanTool,ke as mapCursorStreamJsonToRawEnvelope,Ae as parseCursorAskQuestionPayload};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{JsonRpcTransport as
|
|
2
|
-
`)){const r=t.trim();if(!r||r.toLowerCase().includes("available model")||r.toLowerCase().startsWith("tip:"))continue;const
|
|
1
|
+
import{JsonRpcTransport as v}from"../../core/transport/json-rpc.js";import{log as c}from"../../core/log/index.js";import{killProcessGroup as g,spawnCommand as w}from"../../core/runtime/spawn.js";import{resolveCursorSpawn as h}from"./resolve-command.js";const E=3e4,u="none|low|medium|high|xhigh|extra-high|max";function y(o,e){const t=o.trim(),r=e.trim();return t==="default"||t==="default[]"||/^default\[.*\]$/.test(t)?{id:"auto",displayName:!r||r==="default"||r==="Auto"?"Auto (default)":r}:{id:t,displayName:r||t}}function M(o){const e=o.trim();if(!e||e==="auto"||e==="default"||e==="default[]")return"auto";let t=e;return t=t.replace(new RegExp(`-thinking-(?:${u})(?:-fast)?$`),""),t=t.replace(new RegExp(`-(?:${u})-thinking$`),""),t=t.replace(/-thinking(?:-fast)?$/,""),t=t.replace(new RegExp(`-(?:${u})(?:-fast)?$`),""),t=t.replace(/-fast$/,""),t||e}function $(o){let e=o.trim();e=e.replace(/\s*\(default\)\s*$/i,""),e=e.replace(/\s*\(NO ZDR\)\s*$/i,"");const t=/(?:\s+(?:None|Low|Medium|High|Extra High|Max|Fast|Thinking|1M))$/i;for(let r=0;r<8&&t.test(e);r++)e=e.replace(t,"").trim();return e||o.trim()}function A(o){const e=[];for(const t of o.split(`
|
|
2
|
+
`)){const r=t.trim();if(!r||r.toLowerCase().includes("available model")||r.toLowerCase().startsWith("tip:"))continue;const s=r.match(/^(\S+)\s+-\s+(.+)$/);s&&e.push({id:s[1],displayName:s[2].trim()})}return e}function I(o){const e=new Set,t=[];for(const r of o){const s=M(r.id);if(e.has(s))continue;e.add(s);const n=s==="auto"?"Auto (default)":$(r.displayName);t.push({id:s,displayName:n})}return t}async function S(o){return new Promise(e=>{let t="";o.stdout?.on("data",r=>{t+=String(r)}),o.once("close",()=>e(t)),o.once("error",()=>e(t))})}async function x(o){const e={...process.env,...o.env??{}},t=h(o.command,e),{process:r}=w(t.command,[...t.prefixArgs,"models"],{cwd:o.cwd??process.cwd(),env:t.env,stdio:["ignore","pipe","pipe"]}),s=await S(r);return A(s)}async function F(o){const e=await x(o);return I(e)}async function T(o){const e=o.timeoutMs??E,t=o.cwd??process.cwd(),r={...process.env,...o.env??{}},s=h(o.command,r),{process:n}=w(s.command,[...s.prefixArgs,"acp"],{cwd:t,env:s.env,stdio:["pipe","pipe","pipe"]});if(!n.stdout||!n.stdin)throw g(n,"SIGTERM"),new Error("cursor acp spawn missing stdio pipes");const a=new v(n.stdout,n.stdin);a.setHandlers(void 0,(d,m)=>{String(d).startsWith("cursor/")?a.respondSuccess(m,{}):a.respondError(m,-32601,"method not implemented")});const l=new AbortController,C=setTimeout(()=>l.abort(),e),p=d=>{l.abort(d)};n.once("error",p);try{await a.call("initialize",{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!1,writeTextFile:!1}},clientInfo:{name:"grix-connector",version:"0"}},l.signal);const f=((await a.call("session/new",{cwd:t,mcpServers:[]},l.signal)).models?.availableModels??[]).filter(i=>typeof i.modelId=="string"&&i.modelId.length>0).map(i=>y(i.modelId,i.name??i.modelId));if(f.length===0)throw new Error("cursor acp session/new returned no models");return f}finally{clearTimeout(C),n.off("error",p);try{a.close()}catch{}g(n,"SIGTERM")}}async function P(o){try{const e=await x(o);if(e.length>0)return c.info("cursor-adapter",`Loaded ${e.length} models via CLI agent models`),e;c.warn("cursor-adapter","CLI agent models returned empty list, falling back to ACP")}catch(e){const t=e instanceof Error?e.message:String(e);c.warn("cursor-adapter",`CLI agent models failed, falling back to ACP: ${t}`)}try{const e=await T(o);return c.info("cursor-adapter",`Loaded ${e.length} parameterized models via acp fallback`),e}catch(e){const t=e instanceof Error?e.message:String(e);return c.warn("cursor-adapter",`ACP model fallback failed: ${t}`),[]}}export{$ as collapseCursorDisplayName,M as collapseCursorModelId,I as collapseExplodedCursorModels,F as fetchCollapsedModelsFromCli,P as fetchCursorParameterizedModels,T as fetchCursorParameterizedModelsViaAcp,x as fetchExplodedModelsFromCli,y as normalizeCursorAvailableModel,A as parseExplodedCursorModels};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as d,readdirSync as u}from"node:fs";import{dirname as p,join as i}from"node:path";const
|
|
1
|
+
import{existsSync as d,readdirSync as u}from"node:fs";import{dirname as p,join as i}from"node:path";import{resolveCommandPath as m}from"../../core/runtime/spawn.js";const l=/^\d{4}\.\d{1,2}\.\d{1,2}(-\d{2}-\d{2}-\d{2})?-[a-f0-9]+$/;function f(r){const t=r.split("-")[0],[e,n,s]=t.split(".");return!e||!n||!s?0:Number(e+n.padStart(2,"0")+s.padStart(2,"0"))}function A(r){const t={command:r,prefixArgs:[],viaNode:!1};if(process.platform!=="win32"||!/\.cmd$/i.test(r))return t;try{const e=p(r),n=i(e,"versions"),s=u(n,{withFileTypes:!0}).filter(o=>o.isDirectory()&&l.test(o.name)).map(o=>o.name).sort((o,a)=>f(a)-f(o));for(const o of s){const a=i(n,o,"node.exe"),c=i(n,o,"index.js");if(d(a)&&d(c))return{command:a,prefixArgs:[c],viaNode:!0}}}catch{}return t}function x(r,t){if(!t.viaNode)return r;const e={...r};return e.CURSOR_INVOKED_AS??="cursor-agent",e.NODE_COMPILE_CACHE??=i(r.LOCALAPPDATA??i(r.USERPROFILE??"","AppData","Local"),"cursor-compile-cache"),e}function C(r,t){const e=A(m(r,typeof t.PATH=="string"?t.PATH:void 0));return{...e,env:x(t,e)}}export{A as resolveCursorCommand,C as resolveCursorSpawn,x as withCursorShimEnv};
|