@quantiya/codevibe-codex-plugin 2.0.68 → 2.0.69
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/server.js +1 -1
- package/node_modules/@quantiya/codevibe-core/dist/index.js +540 -529
- package/node_modules/@quantiya/codevibe-core/dist/prompt-parser.d.ts +3 -0
- package/node_modules/@quantiya/codevibe-core/dist/terminal-menu.d.ts +3 -2
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -14,7 +14,7 @@ ${Ke(c,500)}`,metadata:{toolName:o,toolOutput:r,callId:s,status:"completed"}}}re
|
|
|
14
14
|
`);if(typeof a=="object"&&typeof a.text=="string")return a.text;try{return JSON.stringify(a)??""}catch{return String(a)}}function Ke(a,t){return typeof a!="string"?Ke(ge(a),t):a?a.length<=t?a:a.substring(0,t)+"...":""}function Ue(){H.clear(),Q()}var C=require("@quantiya/codevibe-core"),ft=3e3,Ii=8,bi=10,Ei=100;function gt(a){let t=Buffer.byteLength(a.carryover);return{status:"partial",progressKey:`${a.fileIdentity.dev}:${a.fileIdentity.ino}:${a.size}:${a.endOfComplete}:${t}`,size:a.size,carryoverBytes:t,endOfComplete:a.endOfComplete}}var Ri="tool_activity",ee=class{constructor(t){this.consolidator=null;this.ledger=null;this.sessionMap=null;this.ownership=null;this.cursor=null;this.backendSessionId=null;this.rolloutId=null;this.transcriptPath=null;this.backstopTimer=null;this.backstopInFlight=null;this.cursorReady=Promise.resolve();this.cursorRepaired=!1;this.deps=t}static mintBackendSessionId(){return C.ToolActivitySessionMap.mintCodexBackendSessionId()}async recordedBackendSessionId(t){return new C.ToolActivitySessionMap({agent:"codex",logger:this.deps.logger,lock:new C.InProcessRolloutLock,root:this.deps.root}).ownerBackendSessionId(t)}get sessionId(){return this.backendSessionId}get rollout(){return this.rolloutId}isActive(){return this.consolidator!==null}async start(t,e,i){this.backendSessionId=t,this.rolloutId=e;let s=(0,C.createRolloutLock)({agent:"codex",logger:this.deps.logger,socketDir:this.deps.socketDir,root:this.deps.root});this.sessionMap=new C.ToolActivitySessionMap({agent:"codex",logger:this.deps.logger,lock:s,root:this.deps.root}),this.ownership=await this.sessionMap.claimOwnership(e,t);let r=new C.ToolActivityOutbox({agent:"codex",logger:this.deps.logger,root:this.deps.root});this.ledger=new C.ToolActivityLedger({agent:"codex",sessionId:t,logger:this.deps.logger,root:this.deps.root}),await this.deps.recoverPending?.(t,r,this.ledger);let n=this.buildTransport(),o=this.deps.selectTransport?await this.deps.selectTransport(t,n):n;this.consolidator=new C.ToolActivityConsolidator({agent:"codex",sessionId:t,logger:this.deps.logger,outbox:r,ledger:this.ledger,transport:o}),await this.consolidator.init(),i&&this.bindTranscript(i),this.deps.logger.info("[tool-activity] codex consolidator started",{sessionId:t,rollout:e,hasTranscript:!!i})}bindTranscript(t){if(!this.consolidator||!t||this.transcriptPath===t)return;this.transcriptPath=t;let e=new C.ToolReplayCursor({agent:"codex",sessionId:this.backendSessionId,canonicalPath:t,logger:this.deps.logger,root:this.deps.root,readBytes:this.deps.replayReadBytes,maxFrameBytes:this.deps.replayMaxFrameBytes});this.cursor=e,this.cursorRepaired=!1,this.cursorReady=e.load().catch(s=>this.deps.logger.warn("[tool-activity] codex cursor load failed (rescanning fresh)",{sessionId:this.backendSessionId,err:String(s)}));let i=this.deps.backstopIntervalMs??3e3;i>0&&!this.backstopTimer&&(this.backstopTimer=setInterval(()=>{this.runTranscriptBackstop().catch(s=>this.deps.logger.warn("[tool-activity] codex transcript backstop failed",{sessionId:this.backendSessionId,err:String(s)}))},i),this.backstopTimer.unref?.())}async observeCall(t,e){if(!this.consolidator||!this.sessionMap||!this.ownership||!t.callId||!t.toolName)return;let i=this.consolidator;await this.sessionMap.bindCall(this.ownership,t.callId);let s={id:t.callId,tool:t.toolName,normalizedTarget:Oi(t.toolName,t.toolInput),ts:t.ts??new Date().toISOString(),byteOffset:t.byteOffset??0,...t.toolInput!==void 0?{digest:(0,C.digestOf)(t.toolInput)}:{}},r=await i.observe(s,e);return r==="closed"?await i.captureTerminal(s,this.deps.shutdownDrainMs??ft)?"sealed-terminal":"closed":r}async runTranscriptBackstop(t=!1){await this.runTranscriptBackstopTurn(t)}runTranscriptBackstopTurn(t=!1){if(this.backstopInFlight)return this.backstopInFlight;let e=this.cursor,i=this.cursorReady,s=this.consolidator;if(!s||!e)return Promise.resolve("caught-up");let n=(async()=>{if(await i,this.cursor!==e)return"more";if(!this.cursorRepaired){if(await s.repairLostWindows(e),this.cursor!==e)return"more";this.cursorRepaired=!0}return this.doTranscriptBackstop(e,t)})().finally(()=>{this.backstopInFlight===n&&(this.backstopInFlight=null)});return this.backstopInFlight=n,n}async doTranscriptBackstop(t,e=!1){let i=this.consolidator;if(!i)return"caught-up";this.ledger&&await this.ledger.reloadLegacyOwned();for(let s=0;s<Ii;s+=1){if(this.cursor!==t)return"caught-up";let r=await t.readFrames();if(r.missing)return"caught-up";if(r.frames.length===0)return r.carryover.length>0?gt(r):"caught-up";let n=Number.POSITIVE_INFINITY,o=e?{includeInFlight:!0}:void 0;for(let c of r.frames)for(let d of _i(c.line,c.startOffset))await this.observeCall(d,o)==="deferred-in-flight"&&(n=Math.min(n,c.startOffset));if(await i.flush(),n<r.endOfComplete)return await t.checkpoint(n,{fileIdentity:r.fileIdentity,size:r.size,carryover:""}),"more";if(await t.checkpoint(r.endOfComplete,{fileIdentity:r.fileIdentity,size:r.size,carryover:r.carryover}),!r.hasMore)return r.carryover.length>0?gt(r):"caught-up"}return"more"}async flush(){await this.consolidator?.flush()}async stop(){this.backstopTimer&&(clearInterval(this.backstopTimer),this.backstopTimer=null),await this.runTranscriptBackstop().catch(()=>{});let t=Math.max(1,Math.trunc(this.deps.shutdownPartialNoProgressTurns??Ei)),e=null,i=0;for(;;){let s=await this.runTranscriptBackstopTurn(!0);if(s==="caught-up")break;if(typeof s!="string"){if(s.progressKey===e?i+=1:(e=s.progressKey,i=1),i>=t){this.deps.logger.warn("[tool-activity] deferring unchanged incomplete rollout suffix during shutdown; the next owner will re-read it from the durable complete-line boundary",{size:s.size,carryoverBytes:s.carryoverBytes,endOfComplete:s.endOfComplete,unchangedTurns:i});break}await new Promise(r=>setTimeout(r,bi))}else e=null,i=0,await new Promise(r=>setImmediate(r))}await this.consolidator?.drainSends(this.deps.shutdownDrainMs??ft).catch(()=>{});try{await this.consolidator?.shutdown()}finally{await this.ownership?.release().catch(()=>{}),this.ownership=null,this.consolidator=null,this.ledger=null,this.sessionMap=null,this.cursor=null}}buildTransport(){let t=async(e,i,s)=>{let r=s?s.sessionKey:this.deps.getSessionKey();if(!r)throw new Error("[tool-activity] no session key at send (retryable)");let n=s?s.sessionKeyGen:this.deps.getSessionKeyGen();await this.deps.createEvent({sessionId:e,type:C.EventType.TOOL_ACTIVITY,source:C.EventSource.DESKTOP,content:this.deps.encryptContent(Ri,r),metadata:{encrypted:this.deps.encryptMetadata({manifest:i.manifest},r)},timestamp:i.windowStart,isEncrypted:!0,clientEventId:i.clientEventId,...n?{expectedSessionKeyGen:n}:{}})};return{send:async(e,i)=>{try{await t(e,i)}catch(s){if((0,C.isSessionKeyStaleError)(s)&&this.deps.refreshSessionKey){let r=await this.deps.refreshSessionKey(e);if(!r)throw s;await t(e,i,r);return}throw s}}}}};function _i(a,t){let e;try{e=JSON.parse(a)}catch{return[]}if(e?.type!=="response_item"||!e.payload)return[];let i=e.payload,s=typeof e.timestamp=="string"?e.timestamp:new Date(0).toISOString();if(i.type==="function_call"&&typeof i.call_id=="string"&&typeof i.name=="string"){let r;try{r=JSON.parse(i.arguments||"{}")}catch{r={raw:i.arguments}}return[{callId:i.call_id,toolName:Ti(i.name),toolInput:r,ts:s,byteOffset:t}]}if(i.type==="custom_tool_call"&&typeof i.call_id=="string"){let r=xi(typeof i.input=="string"?i.input:""),n=r?{file_path:r,patch:i.input}:{patch:i.input};return[{callId:i.call_id,toolName:"Edit",toolInput:n,ts:s,byteOffset:t}]}return[]}function Ti(a){return a==="shell"||a==="shell_command"||a==="local_shell"?"Bash":a==="apply_patch"?"Edit":a}function xi(a){let t=a.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/m);return t?t[1].trim():void 0}function Oi(a,t){if(!t||typeof t!="object")return;let e=t,i=r=>typeof r=="string"&&r.length>0?r:void 0,s=Array.isArray(e.command)?e.command.filter(r=>typeof r=="string").join(" ").trim().split(/\s+/)[0]:typeof e.command=="string"?e.command.trim().split(/\s+/)[0]:void 0;return i(e.file_path)??i(e.path)??i(e.pattern)??i(e.url)??(s&&s.length>0?s:void 0)}var yt=require("events"),vt=require("@quantiya/codevibe-core");var ve=class a extends yt.EventEmitter{constructor(){super();this.pendingCalls=new Map;this.timers=new Map;this.timeoutMs=(0,vt.getConfig)().codex.approvalTimeoutMs,l.info("Approval detector initialized",{timeoutMs:this.timeoutMs})}onToolCallStart(e,i,s){l.debug("Tool call started",{callId:e,name:i});let r=this.parseInput(s),n=this.extractFilePath(i,s,r),o=this.extractDiff(i,s,r),c={callId:e,name:i,input:s,filePath:n,diff:o,parsedInput:r,timestamp:Date.now(),notificationSent:!1};if(this.pendingCalls.set(e,c),!this.shouldScheduleApprovalTimeout(i,r)){l.debug("Skipping approval timeout for non-escalated tool call",{callId:e,name:i});return}let d=setTimeout(()=>{this.checkPendingCall(e)},this.timeoutMs);this.timers.set(e,d)}onToolCallComplete(e){l.debug("Tool call completed",{callId:e}),this.pendingCalls.delete(e);let i=this.timers.get(e);i&&(clearTimeout(i),this.timers.delete(e))}checkPendingCall(e){let i=this.pendingCalls.get(e);if(!i||i.notificationSent)return;let s=Date.now()-i.timestamp;l.info("Tool call still pending after timeout",{callId:e,name:i.name,elapsedMs:s}),i.notificationSent=!0,this.pendingCalls.set(e,i),this.emit("approval-pending",{callId:e,toolName:i.name,hint:this.extractHint(i.name,i.input,i.filePath),filePath:i.filePath,diff:i.diff,toolInput:i.parsedInput,rawInput:i.input,elapsedMs:s})}extractHint(e,i,s){if(s)return`File: ${s}`;if(e==="apply_patch"&&i){let r=i.match(/\*\*\* (?:Update|Add|Delete) File: (.+)/);if(r)return`File: ${r[1].trim()}`}if(a.SHELL_TOOL_NAMES.has(e))try{let r=JSON.parse(i),n=typeof r.command=="string"?r.command:typeof r.cmd=="string"?r.cmd:void 0;if(n)return`Command: ${n.substring(0,50)}${n.length>50?"...":""}`}catch{}return`Tool: ${this.mapToolName(e)}`}mapToolName(e){return{exec_command:"Bash",shell_command:"Bash",shell:"Bash",exec:"Bash",local_shell:"Bash",apply_patch:"File Edit",write_file:"Write File",read_file:"Read File"}[e]||e}parseInput(e){if(e)try{return JSON.parse(e)}catch{return}}static{this.SHELL_TOOL_NAMES=new Set(["exec_command","shell_command","shell","exec","local_shell"])}shouldScheduleApprovalTimeout(e,i){return a.SHELL_TOOL_NAMES.has(e)?i?.sandbox_permissions==="require_escalated":!1}extractFilePath(e,i,s){if(e==="apply_patch"&&i){let n=i.match(/\*\*\* (?:Update|Add|Delete) File: (.+)/);if(n)return n[1].trim()}let r=s?.file_path||s?.path||s?.filePath;if(r&&typeof r=="string")return r}extractDiff(e,i,s){if(e==="apply_patch"&&i)return i;if(s?.diff&&typeof s.diff=="string")return s.diff}getPendingCalls(){return Array.from(this.pendingCalls.values())}hasPendingCalls(){return this.pendingCalls.size>0}clear(){for(let e of this.timers.values())clearTimeout(e);this.timers.clear(),this.pendingCalls.clear(),l.debug("Approval detector cleared")}shutdown(){this.clear(),this.removeAllListeners(),l.info("Approval detector shutdown")}};var St=require("child_process"),Pt=require("util");var He=(0,Pt.promisify)(St.exec),te="__CODEVIBE_CODEX_KEY_ESCAPE__",Se=class{async sendLiteral(t,e){return this.sendTerminalOperation(t,async i=>{await this.sendLiteralViaTmux(i,e)})}async sendKey(t,e){return this.sendTerminalOperation(t,async i=>{await this.sendKeyViaTmux(i,e)})}async sendInput(t,e){l.info("Attempting to send input to Codex",{sessionId:t,input:e});try{let i=process.env.CODEVIBE_CODEX_TMUX_SESSION;return i?(l.info("Using tmux send-keys",{tmuxSession:i}),e===te?await this.sendKeyViaTmux(i,"Escape"):await this.sendViaTmux(i,e),l.info("Successfully sent input to Codex",{sessionId:t,input:e}),!0):(l.error("No tmux session found - CodeVibe Companion launch is required",{sessionId:t,hint:"Start Codex CLI using `codevibe --agent codex`"}),!1)}catch(i){return l.error("Failed to send input to Codex",{sessionId:t,error:i instanceof Error?i.message:String(i)}),!1}}async sendTerminalOperation(t,e){let i=process.env.CODEVIBE_CODEX_TMUX_SESSION;if(!i)return l.error("No tmux session found - CodeVibe Companion launch is required",{sessionId:t,hint:"Start Codex CLI using `codevibe --agent codex`"}),!1;try{return await e(i),!0}catch(s){return l.error("Failed to send terminal input to Codex",{sessionId:t,error:s instanceof Error?s.message:String(s)}),!1}}async sendViaTmux(t,e){l.info("Sending via tmux",{sessionName:t,inputLength:e.length});try{await this.sendLiteralViaTmux(t,e),await this.delay(500);let i=`tmux send-keys -t "${t}" Enter`;await He(i),l.info("tmux send-keys completed")}catch(i){throw l.error("tmux send-keys failed",{sessionName:t,error:i}),i}}async sendLiteralViaTmux(t,e){let i=e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\$/g,"\\$").replace(/`/g,"\\`"),s=`tmux send-keys -t "${t}" -l "${i}"`;await He(s)}async sendKeyViaTmux(t,e){l.info("Sending special key via tmux",{sessionName:t,key:e});try{let i=`tmux send-keys -t "${t}" ${e}`;await He(i),l.info("tmux special-key send completed")}catch(i){throw l.error("tmux special-key send failed",{sessionName:t,key:e,error:i}),i}}delay(t){return new Promise(e=>setTimeout(e,t))}isApprovalResponse(t){let e=t.trim().toLowerCase();return["y","n","a","q","e","yes","no"].includes(e)||/^[0-9]+$/.test(e)}};var y=T(require("fs")),we=T(require("os")),M=T(require("path")),ie=require("crypto"),It=require("child_process"),bt=require("events"),Et=require("util");var ae=require("@quantiya/codevibe-core"),$e=(0,Et.promisify)(It.execFile),wt=512*1024,X="writer.state",Ci=2e3,Ai=10,Ni=16*1024*1024,ki=10080*60*1e3,Pe=class extends bt.EventEmitter{constructor(e={}){super();this.sessionName=null;this.started=!1;this.pipeDirPath=null;this.pipeDirIdentity=null;this.pipeFilePath=null;this.pipeFileFd=null;this.pipeFileIdentity=null;this.writerStatePath=null;this.writerStateFd=null;this.writerStateIdentity=null;this.writerGeneration=null;this.pipeEnabled=!1;this.filePosition=0;this.pollTimer=null;this.processing=!1;this.pendingRead=!1;this.promptInspectionChain=Promise.resolve();this.lastPromptHash=null;this.lastPromptWasMenu=!1;this.lifecycleGeneration=0;this.retainedMirrors=[];this.retainedMirrorContainmentLost=!1;this.maxPaneFileBytes=e.maxPaneFileBytes??Ni,this.stalePaneRetentionMs=e.stalePaneRetentionMs??ki,this.tempDir=e.tempDir??we.tmpdir(),this.writerPath=M.resolve(__dirname,"..","libexec","pane-mirror-writer.js");let i=e.runtimePlatform??process.platform,s=e.runtimeRelease??we.release();if(this.wslDetected=i==="linux"&&(/microsoft/i.test(s)||!!process.env.WSL_DISTRO_NAME||!!process.env.WSL_INTEROP),!Number.isSafeInteger(this.maxPaneFileBytes)||this.maxPaneFileBytes<=0)throw new RangeError("maxPaneFileBytes must be a positive safe integer");if(!Number.isSafeInteger(this.stalePaneRetentionMs)||this.stalePaneRetentionMs<0)throw new RangeError("stalePaneRetentionMs must be a non-negative safe integer")}async start(e){if(this.wslDetected)throw new Error("Tmux pane mirror fallback is disabled on unqualified WSL; using hook-based prompts only");if(this.started&&this.sessionName===e&&this.pipeEnabled){l.debug("Tmux pane observer already started",{sessionName:e});return}this.started&&await this.stop(),this.lifecycleGeneration++,this.sessionName=e,this.filePosition=0,this.lastPromptHash=null;try{if(this.cleanupStalePipeFiles(),this.reapOwnedRetainedMirrors(),this.retainedMirrorContainmentLost||this.retainedMirrors.length>0)throw new Error("Prior bounded tmux pane writer is still unconfirmed; refusing another mirror");this.createSecureMirror(),this.started=!0,await this.enablePipePane(),this.pipeEnabled=!0,this.startPolling()}catch(i){this.started=!1,this.lifecycleGeneration++;let s=this.writerGeneration===null;if(!s)try{await this.disablePipePane(),s=!0}catch(r){l.error("Failed to confirm tmux pane writer quiescence after startup failure",{disableError:r})}throw s&&(this.pipeEnabled=!1),this.clearPolling(),s?this.releaseSecureMirror():this.abandonSecureMirror(),this.resetLifecycleState(),i}l.info("Tmux pane observer started",{sessionName:e})}async stop(){if(!this.started&&this.pipeFileFd===null)return;this.started=!1,this.lifecycleGeneration++;let e=!1;try{await this.disablePipePane(),e=!0}catch(i){l.error("Failed to confirm tmux pane writer quiescence during stop",{error:i}),this.emit("observer-error",i)}e&&(this.pipeEnabled=!1),this.clearPolling(),e?this.releaseSecureMirror():this.abandonSecureMirror(),l.info("Tmux pane observer stopped",{sessionName:this.sessionName,writerQuiesced:e}),this.resetLifecycleState()}identityOf(e){return{dev:e.dev,ino:e.ino}}identitiesEqual(e,i){return e.dev===i.dev&&e.ino===i.ino}openMirrorFile(e){return y.openSync(e,y.constants.O_RDWR|y.constants.O_CREAT|y.constants.O_EXCL|(y.constants.O_NOFOLLOW??0),384)}truncateMirror(e){y.ftruncateSync(e,0)}createSecureMirror(){y.mkdirSync(this.tempDir,{recursive:!0,mode:448});let e=y.mkdtempSync(M.join(this.tempDir,`codevibe-codex-pane-${process.pid}-`));y.chmodSync(e,448);let i=M.join(e,"pane.log"),s=M.join(e,X),r=null,n=null;try{r=this.openMirrorFile(i),y.fchmodSync(r,384);let o=y.fstatSync(r);if(!o.isFile())throw new Error("Tmux pane mirror is not a regular file");n=this.openMirrorFile(s),y.fchmodSync(n,384);let c=y.fstatSync(n);if(!c.isFile())throw new Error("Tmux pane writer state is not a regular file");y.writeSync(n,Buffer.from(`idle
|
|
15
15
|
`),0,5,0),this.pipeDirPath=e,this.pipeDirIdentity=this.identityOf(y.lstatSync(e)),this.pipeFilePath=i,this.pipeFileFd=r,this.pipeFileIdentity=this.identityOf(o),this.writerStatePath=s,this.writerStateFd=n,this.writerStateIdentity=this.identityOf(c),r=null,n=null}catch(o){if(r!==null)try{y.closeSync(r)}catch{}if(n!==null)try{y.closeSync(n)}catch{}try{y.unlinkSync(i)}catch{}try{y.unlinkSync(s)}catch{}try{y.rmdirSync(e)}catch{}throw o}}pathMatchesMirrorIdentity(){if(!this.pipeFilePath||!this.pipeFileIdentity)return!1;try{let e=y.lstatSync(this.pipeFilePath);return e.isFile()&&!e.isSymbolicLink()&&this.identitiesEqual(this.pipeFileIdentity,this.identityOf(e))}catch{return!1}}quarantineIfIdentityMatches(e,i){let s=`${e}.reap-${process.pid}-${(0,ie.randomBytes)(6).toString("hex")}`;try{y.renameSync(e,s);let r=y.lstatSync(s);return this.identitiesEqual(i,this.identityOf(r))?s:(y.existsSync(e)||y.renameSync(s,e),null)}catch{return null}}restoreQuarantine(e,i){try{y.existsSync(i)||y.renameSync(e,i)}catch{}}pathMatchesIdentity(e,i){if(!e||!i)return!1;try{let s=y.lstatSync(e);return s.isFile()&&!s.isSymbolicLink()&&this.identitiesEqual(i,this.identityOf(s))}catch{return!1}}closeOwnedDescriptors(){if(this.pipeFileFd!==null)try{y.closeSync(this.pipeFileFd)}catch{}if(this.writerStateFd!==null)try{y.closeSync(this.writerStateFd)}catch{}this.pipeFileFd=null,this.writerStateFd=null}unlinkOwnedFile(e,i){if(!e||!i||!this.pathMatchesIdentity(e,i))return;let s=this.quarantineIfIdentityMatches(e,i);s&&y.unlinkSync(s)}releaseSecureMirror(){let e=this.pipeFilePath,i=this.writerStatePath,s=this.pipeDirPath,r=this.pipeFileIdentity,n=this.writerStateIdentity;this.closeOwnedDescriptors();try{this.unlinkOwnedFile(e,r)}catch{}try{this.unlinkOwnedFile(i,n)}catch{}if(s)try{y.rmdirSync(s)}catch{}this.pipeDirPath=null,this.pipeDirIdentity=null,this.pipeFilePath=null,this.pipeFileIdentity=null,this.writerStatePath=null,this.writerStateIdentity=null,this.writerGeneration=null}abandonSecureMirror(){let e=this.pipeDirPath,i=this.pipeFilePath;e&&this.pipeDirIdentity&&i&&this.pipeFileIdentity&&this.writerStatePath&&this.writerStateIdentity&&this.writerGeneration?this.retainedMirrors.push({dirPath:e,dirIdentity:this.pipeDirIdentity,panePath:i,paneIdentity:this.pipeFileIdentity,statePath:this.writerStatePath,stateIdentity:this.writerStateIdentity,writerGeneration:this.writerGeneration}):(e||i)&&(this.retainedMirrorContainmentLost=!0),this.closeOwnedDescriptors(),l.warn("Retaining bounded tmux pane mirror because writer quiescence is unconfirmed",{retainedDir:e,retainedFile:i,maxBytes:this.maxPaneFileBytes}),this.pipeDirPath=null,this.pipeDirIdentity=null,this.pipeFilePath=null,this.pipeFileIdentity=null,this.writerStatePath=null,this.writerStateIdentity=null,this.writerGeneration=null}resetLifecycleState(){this.sessionName=null,this.pipeDirPath=null,this.pipeDirIdentity=null,this.pipeFilePath=null,this.pipeFileFd=null,this.pipeFileIdentity=null,this.writerStatePath=null,this.writerStateFd=null,this.writerStateIdentity=null,this.writerGeneration=null,this.pipeEnabled=!1,this.filePosition=0,this.processing=!1,this.pendingRead=!1,this.lastPromptHash=null}async failClosedPipe(e){let i=!1;try{await this.disablePipePane(),i=!0}catch(s){l.error("Failed to confirm unsafe tmux pane writer quiescence",{disableError:s})}i&&(this.pipeEnabled=!1),this.clearPolling(),l.error("Tmux pane mirror entered fail-closed containment after integrity/cap failure",{error:e,writerQuiesced:i,independentlyBounded:!0}),this.emit("observer-error",e)}resetLastPromptHash(){this.lastPromptHash=null}async captureSnapshot(e=120){if(!this.sessionName)throw new Error("Tmux pane observer is not started");let i=Math.max(1,Math.floor(e));try{let{stdout:s}=await $e("tmux",["capture-pane","-p","-e","-J","-S",`-${i}`,"-t",this.sessionName],{timeout:5e3,maxBuffer:2097152});return s}catch(s){throw l.error("Failed to capture tmux pane snapshot",{sessionName:this.sessionName,error:s}),this.emit("observer-error",s),s}}quoteShellArg(e){return`'${e.replace(/'/g,"'\\''")}'`}writerStatePathMatchesIdentity(){return this.pathMatchesIdentity(this.writerStatePath,this.writerStateIdentity)}writeWriterState(e){if(this.writerStateFd===null||!this.writerStateIdentity||!this.writerStatePathMatchesIdentity())throw new Error("Tmux pane writer state identity is not valid");let i=y.fstatSync(this.writerStateFd);if(!this.identitiesEqual(this.writerStateIdentity,this.identityOf(i)))throw new Error("Tmux pane writer state descriptor identity changed");let s=Buffer.from(e,"utf8");y.ftruncateSync(this.writerStateFd,0);let r=0;for(;r<s.length;){let n=y.writeSync(this.writerStateFd,s,r,s.length-r,r);if(n<=0)throw new Error("Short tmux pane writer-state write");r+=n}y.fsyncSync(this.writerStateFd)}readWriterState(){if(this.writerStateFd===null||!this.writerStateIdentity||!this.writerStatePathMatchesIdentity())throw new Error("Tmux pane writer state identity is not valid");let e=y.fstatSync(this.writerStateFd);if(!this.identitiesEqual(this.writerStateIdentity,this.identityOf(e)))throw new Error("Tmux pane writer state descriptor identity changed");let i=Math.min(e.size,512);if(i===0)return"";let s=Buffer.alloc(i),r=y.readSync(this.writerStateFd,s,0,i,0);return s.subarray(0,r).toString("utf8").trim()}async waitForWriterState(e,i,s=Ci){let r=Date.now()+s;do{let n=this.readWriterState();if(i.some(o=>n.startsWith(`${o} ${e} `)))return n;if(Date.now()>=r)return null;await new Promise(o=>setTimeout(o,Ai))}while(!0)}async enablePipePane(){if(!this.sessionName||!this.pipeFilePath||!this.writerStatePath)throw new Error("Tmux pane observer is not initialized");if(this.pipeFileFd===null||!this.pipeFileIdentity||!this.pathMatchesMirrorIdentity()||this.writerStateFd===null||!this.writerStateIdentity||!this.writerStatePathMatchesIdentity())throw new Error("Tmux pane mirror identity is not valid");let e=(0,ie.randomBytes)(16).toString("hex");this.writerGeneration=e,this.writeWriterState(`starting ${e}
|
|
16
16
|
`);let i=[process.execPath,this.writerPath,this.pipeFilePath,String(this.pipeFileIdentity.dev),String(this.pipeFileIdentity.ino),this.writerStatePath,String(this.writerStateIdentity.dev),String(this.writerStateIdentity.ino),e,String(this.maxPaneFileBytes)].map(r=>this.quoteShellArg(r)).join(" ");try{await $e("tmux",["pipe-pane","-O","-t",this.sessionName,i])}catch(r){throw this.writerGeneration=null,r}let s=await this.waitForWriterState(e,["ready","done"]);if(!s)throw new Error("Tmux pane writer did not confirm startup");if(s.startsWith(`done ${e} `))throw new Error("Tmux pane writer terminated during startup");l.debug("Enabled tmux pipe-pane mirroring",{sessionName:this.sessionName,pipeFilePath:this.pipeFilePath,writerGeneration:e})}async disablePipePane(){let e=this.writerGeneration;if(!this.sessionName||!e)return;let i=null;try{await $e("tmux",["pipe-pane","-t",this.sessionName])}catch(n){i=n}if(!e){if(i)throw i;return}if(await this.waitForWriterState(e,["done"])){this.writerGeneration=null;return}let r=i instanceof Error?`: ${i.message}`:"";throw new Error(`Tmux pane writer quiescence was not confirmed${r}`)}startPolling(){this.clearPolling(),this.pollTimer=setInterval(()=>{this.processFileChanges()},100),this.pollTimer.unref?.()}clearPolling(){this.pollTimer&&clearInterval(this.pollTimer),this.pollTimer=null}async processFileChanges(){if(!(!this.started||!this.pipeFilePath)){if(this.processing){this.pendingRead=!0;return}this.processing=!0;try{do{this.pendingRead=!1;let e="";try{e=this.readAppendedChunk()}catch(i){l.error("Failed to read bounded tmux pane mirror",{error:i}),await this.failClosedPipe(i);return}await this.rotatePipeFileIfNeeded(),e&&this.queuePromptInspection(e,this.lifecycleGeneration)}while(this.pendingRead)}catch(e){l.error("Failed to process tmux pane changes",{error:e}),this.emit("observer-error",e)}finally{this.processing=!1}}}queuePromptInspection(e,i){this.promptInspectionChain=this.promptInspectionChain.then(async()=>{if(!(!this.started||this.lifecycleGeneration!==i))try{await this.inspectChunkForPrompt(e)}catch(s){l.error("Failed to inspect tmux pane delta",{error:s}),this.emit("observer-error",s)}})}async inspectChunkForPrompt(e){if(!this.lastPromptHash&&!this.looksLikePromptDelta(e))return;let i=await this.captureSnapshot();this.inspectSnapshotForPrompt(i,e)}inspectSnapshotForPrompt(e,i){let s=e?this.extractActivePromptBlock(e):null;if(!s){if(this.lastPromptHash){let n=this.lastPromptHash;this.lastPromptHash=null,this.lastPromptWasMenu=!1,this.emit("prompt-cleared",{promptHash:n})}e&&l.debug("tmux delta cue matched but no active dialog isolated (no candidate emitted)",{snapshotTail:e.split(`
|
|
17
|
-
`).slice(-6).join("\\n")});return}let r=this.hashPromptSnapshot(s);r!==this.lastPromptHash&&(this.lastPromptHash&&(this.lastPromptWasMenu||(0,ae.parseActiveTerminalMenu)(s))&&this.emit("prompt-cleared",{promptHash:this.lastPromptHash}),this.lastPromptHash=r,this.lastPromptWasMenu=!!(0,ae.parseActiveTerminalMenu)(s),this.emit("prompt-candidate",{rawDelta:i,snapshot:s,promptHash:r,detectedAt:Date.now()}))}queueCurrentSnapshotInspection(e){this.promptInspectionChain=this.promptInspectionChain.then(async()=>{if(!(!this.started||this.lifecycleGeneration!==e))try{let i=await this.captureSnapshot();this.inspectSnapshotForPrompt(i,"")}catch(i){l.error("Failed to inspect tmux pane snapshot after rotation",{error:i}),this.emit("observer-error",i)}})}async rotatePipeFileIfNeeded(){let e=this.pipeFilePath,i=this.pipeFileFd,s=this.pipeFileIdentity,r=this.sessionName,n=this.lifecycleGeneration;if(!e||i===null||!s||!r||!this.started)return;let o;try{let d=y.fstatSync(i);if(!this.identitiesEqual(s,this.identityOf(d)))throw new Error("Tmux pane mirror descriptor identity changed");o=d.size}catch(d){await this.failClosedPipe(d);return}if(o<this.maxPaneFileBytes)return;let c="";try{await this.disablePipePane(),this.pipeEnabled=!1}catch(d){l.error("Tmux pane mirror rotation deferred because writer quiescence is unconfirmed",{error:d}),this.emit("observer-error",d),this.clearPolling();return}if(!(!this.started||this.lifecycleGeneration!==n||this.pipeFilePath!==e)){try{c=this.readAppendedChunk()}catch(d){l.error("Failed to drain final tmux pane suffix during rotation; mirror remains intact and disabled",{error:d}),this.emit("observer-error",d),this.clearPolling();return}try{this.truncateMirror(i);let d=y.fstatSync(i);if(!this.identitiesEqual(s,this.identityOf(d))||d.size!==0)throw new Error("Tmux pane mirror truncation could not be verified");if(!this.pathMatchesMirrorIdentity())throw new Error("Tmux pane mirror path was replaced during rotation")}catch(d){l.error("Tmux pane mirror remains disabled after truncation verification failure",{error:d}),this.emit("observer-error",d),this.clearPolling();return}if(this.filePosition=0,l.info("Rotated bounded tmux pane mirror",{sessionName:r,priorBytes:o,maxBytes:this.maxPaneFileBytes}),this.started&&this.lifecycleGeneration===n&&this.pipeFilePath===e&&this.sessionName===r)try{await this.enablePipePane(),this.pipeEnabled=!0}catch(d){this.pipeEnabled=!1,l.error("Tmux pane mirror remains disabled after re-enable failure",{error:d}),this.emit("observer-error",d),this.clearPolling()}c&&this.queuePromptInspection(c,n),this.pipeEnabled&&this.queueCurrentSnapshotInspection(n)}}retainedPathMatchesIdentity(e,i,s){try{let r=y.lstatSync(e);return(s==="file"?r.isFile():r.isDirectory())&&!r.isSymbolicLink()&&(typeof process.getuid!="function"||r.uid===process.getuid())&&this.identitiesEqual(i,this.identityOf(r))}catch{return!1}}readRetainedWriterState(e,i){let s=null;try{s=y.openSync(e,y.constants.O_RDONLY|(y.constants.O_NOFOLLOW??0));let r=y.fstatSync(s);if(!r.isFile()||typeof process.getuid=="function"&&r.uid!==process.getuid()||!this.identitiesEqual(i,this.identityOf(r))||r.size>512)return null;let n=Buffer.alloc(r.size),o=r.size===0?0:y.readSync(s,n,0,r.size,0);return n.subarray(0,o).toString("utf8").trim()}catch{return null}finally{if(s!==null)try{y.closeSync(s)}catch{}}}reapOwnedRetainedMirror(e){if(!this.retainedPathMatchesIdentity(e.dirPath,e.dirIdentity,"directory"))return!1;let i;try{i=y.readdirSync(e.dirPath).sort()}catch{return!1}if(i.length!==2||i[0]!=="pane.log"||i[1]!==X||!this.retainedPathMatchesIdentity(e.panePath,e.paneIdentity,"file")||!this.retainedPathMatchesIdentity(e.statePath,e.stateIdentity,"file"))return!1;let s=new RegExp(`^done ${e.writerGeneration} \\d+ \\d+$`);if(!s.test(this.readRetainedWriterState(e.statePath,e.stateIdentity)??""))return!1;let r=this.quarantineIfIdentityMatches(e.dirPath,e.dirIdentity);if(!r)return!1;let n=!1;try{let o=M.join(r,"pane.log"),c=M.join(r,X);if(!this.retainedPathMatchesIdentity(o,e.paneIdentity,"file"))throw new Error("pane identity changed");if(!this.retainedPathMatchesIdentity(c,e.stateIdentity,"file"))throw new Error("state identity changed");if(!s.test(this.readRetainedWriterState(c,e.stateIdentity)??""))throw new Error("writer generation is no longer done");if(this.unlinkOwnedFile(o,e.paneIdentity),this.unlinkOwnedFile(c,e.stateIdentity),y.existsSync(o)||y.existsSync(c))throw new Error("retained mirror unlink was incomplete");y.rmdirSync(r),n=!0,l.info("Removed completed same-owner tmux pane mirror",{retainedDir:e.dirPath})}catch{y.existsSync(r)&&this.restoreQuarantine(r,e.dirPath)}return n}reapOwnedRetainedMirrors(){this.retainedMirrors=this.retainedMirrors.filter(e=>!this.reapOwnedRetainedMirror(e))}cleanupStalePipeFiles(){let e=Date.now()-this.stalePaneRetentionMs,i;try{i=y.readdirSync(this.tempDir,{withFileTypes:!0})}catch{return}for(let s of i){let r=/^codevibe-codex-pane-(\d+)\.log$/.exec(s.name);if(r){let d=M.join(this.tempDir,s.name),p=null;try{let u=y.lstatSync(d);if(!u.isFile()||u.isSymbolicLink()||u.mtimeMs>e||typeof process.getuid=="function"&&u.uid!==process.getuid()||this.isProcessAlive(Number(r[1]))||(p=this.quarantineIfIdentityMatches(d,this.identityOf(u)),!p))continue;y.unlinkSync(p),p=null,l.info("Removed stale legacy tmux pane mirror",{candidate:d,ageMs:Date.now()-u.mtimeMs})}catch{p&&this.restoreQuarantine(p,d)}continue}let n=/^codevibe-codex-pane-(\d+)-[A-Za-z0-9_-]+$/.exec(s.name);if(!n||!s.isDirectory())continue;let o=M.join(this.tempDir,s.name),c=null;try{let d=y.lstatSync(o);if(!d.isDirectory()||d.isSymbolicLink()||d.mtimeMs>e||typeof process.getuid=="function"&&d.uid!==process.getuid())continue;let p=Number(n[1]);if(this.isProcessAlive(p)||(c=this.quarantineIfIdentityMatches(o,this.identityOf(d)),!c))continue;let u=M.join(c,"pane.log"),f=M.join(c,X),v=y.readdirSync(c);if(v.some(m=>m!=="pane.log"&&m!==X)){this.restoreQuarantine(c,o);continue}for(let m of v.map(g=>M.join(c,g))){let g=y.lstatSync(m);if(!g.isFile()||g.isSymbolicLink()||typeof process.getuid=="function"&&g.uid!==process.getuid()){this.restoreQuarantine(c,o),c=null;break}}if(!c)continue;if(v.includes(X)){let m=y.readFileSync(f,"utf8").trim(),g=/^ready [a-f0-9]{32} (\d+)$/.exec(m);if(!(m==="idle"||/^done [a-f0-9]{32} \d+ \d+$/.test(m)||!!g)||g&&this.isProcessAlive(Number(g[1]))){this.restoreQuarantine(c,o);continue}}v.includes("pane.log")&&y.unlinkSync(u),v.includes(X)&&y.unlinkSync(f),y.rmdirSync(c),c=null,l.info("Removed stale tmux pane mirror directory",{candidate:o,ageMs:Date.now()-d.mtimeMs})}catch{c&&this.restoreQuarantine(c,o)}}}isProcessAlive(e){try{return process.kill(e,0),!0}catch(i){return i?.code==="EPERM"}}readAppendedChunk(){if(!this.pipeFilePath||this.pipeFileFd===null||!this.pipeFileIdentity)return"";if(!this.pathMatchesMirrorIdentity())throw new Error("Tmux pane mirror path was replaced");let e=y.fstatSync(this.pipeFileFd);if(!this.identitiesEqual(this.pipeFileIdentity,this.identityOf(e)))throw new Error("Tmux pane mirror descriptor identity changed");if(e.size<=this.filePosition)return"";{let s=e.size-this.filePosition>wt?e.size-wt:this.filePosition,r=e.size-s,n=Buffer.alloc(r),o=0;for(;o<r;){let c=y.readSync(this.pipeFileFd,n,o,r-o,s+o);if(c===0)break;o+=c}return this.filePosition=s+o,n.subarray(0,o).toString("utf-8")}}looksLikePromptDelta(e){return/Would you like to run/i.test(e)||/[
|
|
17
|
+
`).slice(-6).join("\\n")});return}let r=this.hashPromptSnapshot(s);r!==this.lastPromptHash&&(this.lastPromptHash&&(this.lastPromptWasMenu||(0,ae.parseActiveTerminalMenu)(s))&&this.emit("prompt-cleared",{promptHash:this.lastPromptHash}),this.lastPromptHash=r,this.lastPromptWasMenu=!!(0,ae.parseActiveTerminalMenu)(s),this.emit("prompt-candidate",{rawDelta:i,snapshot:s,promptHash:r,detectedAt:Date.now()}))}queueCurrentSnapshotInspection(e){this.promptInspectionChain=this.promptInspectionChain.then(async()=>{if(!(!this.started||this.lifecycleGeneration!==e))try{let i=await this.captureSnapshot();this.inspectSnapshotForPrompt(i,"")}catch(i){l.error("Failed to inspect tmux pane snapshot after rotation",{error:i}),this.emit("observer-error",i)}})}async rotatePipeFileIfNeeded(){let e=this.pipeFilePath,i=this.pipeFileFd,s=this.pipeFileIdentity,r=this.sessionName,n=this.lifecycleGeneration;if(!e||i===null||!s||!r||!this.started)return;let o;try{let d=y.fstatSync(i);if(!this.identitiesEqual(s,this.identityOf(d)))throw new Error("Tmux pane mirror descriptor identity changed");o=d.size}catch(d){await this.failClosedPipe(d);return}if(o<this.maxPaneFileBytes)return;let c="";try{await this.disablePipePane(),this.pipeEnabled=!1}catch(d){l.error("Tmux pane mirror rotation deferred because writer quiescence is unconfirmed",{error:d}),this.emit("observer-error",d),this.clearPolling();return}if(!(!this.started||this.lifecycleGeneration!==n||this.pipeFilePath!==e)){try{c=this.readAppendedChunk()}catch(d){l.error("Failed to drain final tmux pane suffix during rotation; mirror remains intact and disabled",{error:d}),this.emit("observer-error",d),this.clearPolling();return}try{this.truncateMirror(i);let d=y.fstatSync(i);if(!this.identitiesEqual(s,this.identityOf(d))||d.size!==0)throw new Error("Tmux pane mirror truncation could not be verified");if(!this.pathMatchesMirrorIdentity())throw new Error("Tmux pane mirror path was replaced during rotation")}catch(d){l.error("Tmux pane mirror remains disabled after truncation verification failure",{error:d}),this.emit("observer-error",d),this.clearPolling();return}if(this.filePosition=0,l.info("Rotated bounded tmux pane mirror",{sessionName:r,priorBytes:o,maxBytes:this.maxPaneFileBytes}),this.started&&this.lifecycleGeneration===n&&this.pipeFilePath===e&&this.sessionName===r)try{await this.enablePipePane(),this.pipeEnabled=!0}catch(d){this.pipeEnabled=!1,l.error("Tmux pane mirror remains disabled after re-enable failure",{error:d}),this.emit("observer-error",d),this.clearPolling()}c&&this.queuePromptInspection(c,n),this.pipeEnabled&&this.queueCurrentSnapshotInspection(n)}}retainedPathMatchesIdentity(e,i,s){try{let r=y.lstatSync(e);return(s==="file"?r.isFile():r.isDirectory())&&!r.isSymbolicLink()&&(typeof process.getuid!="function"||r.uid===process.getuid())&&this.identitiesEqual(i,this.identityOf(r))}catch{return!1}}readRetainedWriterState(e,i){let s=null;try{s=y.openSync(e,y.constants.O_RDONLY|(y.constants.O_NOFOLLOW??0));let r=y.fstatSync(s);if(!r.isFile()||typeof process.getuid=="function"&&r.uid!==process.getuid()||!this.identitiesEqual(i,this.identityOf(r))||r.size>512)return null;let n=Buffer.alloc(r.size),o=r.size===0?0:y.readSync(s,n,0,r.size,0);return n.subarray(0,o).toString("utf8").trim()}catch{return null}finally{if(s!==null)try{y.closeSync(s)}catch{}}}reapOwnedRetainedMirror(e){if(!this.retainedPathMatchesIdentity(e.dirPath,e.dirIdentity,"directory"))return!1;let i;try{i=y.readdirSync(e.dirPath).sort()}catch{return!1}if(i.length!==2||i[0]!=="pane.log"||i[1]!==X||!this.retainedPathMatchesIdentity(e.panePath,e.paneIdentity,"file")||!this.retainedPathMatchesIdentity(e.statePath,e.stateIdentity,"file"))return!1;let s=new RegExp(`^done ${e.writerGeneration} \\d+ \\d+$`);if(!s.test(this.readRetainedWriterState(e.statePath,e.stateIdentity)??""))return!1;let r=this.quarantineIfIdentityMatches(e.dirPath,e.dirIdentity);if(!r)return!1;let n=!1;try{let o=M.join(r,"pane.log"),c=M.join(r,X);if(!this.retainedPathMatchesIdentity(o,e.paneIdentity,"file"))throw new Error("pane identity changed");if(!this.retainedPathMatchesIdentity(c,e.stateIdentity,"file"))throw new Error("state identity changed");if(!s.test(this.readRetainedWriterState(c,e.stateIdentity)??""))throw new Error("writer generation is no longer done");if(this.unlinkOwnedFile(o,e.paneIdentity),this.unlinkOwnedFile(c,e.stateIdentity),y.existsSync(o)||y.existsSync(c))throw new Error("retained mirror unlink was incomplete");y.rmdirSync(r),n=!0,l.info("Removed completed same-owner tmux pane mirror",{retainedDir:e.dirPath})}catch{y.existsSync(r)&&this.restoreQuarantine(r,e.dirPath)}return n}reapOwnedRetainedMirrors(){this.retainedMirrors=this.retainedMirrors.filter(e=>!this.reapOwnedRetainedMirror(e))}cleanupStalePipeFiles(){let e=Date.now()-this.stalePaneRetentionMs,i;try{i=y.readdirSync(this.tempDir,{withFileTypes:!0})}catch{return}for(let s of i){let r=/^codevibe-codex-pane-(\d+)\.log$/.exec(s.name);if(r){let d=M.join(this.tempDir,s.name),p=null;try{let u=y.lstatSync(d);if(!u.isFile()||u.isSymbolicLink()||u.mtimeMs>e||typeof process.getuid=="function"&&u.uid!==process.getuid()||this.isProcessAlive(Number(r[1]))||(p=this.quarantineIfIdentityMatches(d,this.identityOf(u)),!p))continue;y.unlinkSync(p),p=null,l.info("Removed stale legacy tmux pane mirror",{candidate:d,ageMs:Date.now()-u.mtimeMs})}catch{p&&this.restoreQuarantine(p,d)}continue}let n=/^codevibe-codex-pane-(\d+)-[A-Za-z0-9_-]+$/.exec(s.name);if(!n||!s.isDirectory())continue;let o=M.join(this.tempDir,s.name),c=null;try{let d=y.lstatSync(o);if(!d.isDirectory()||d.isSymbolicLink()||d.mtimeMs>e||typeof process.getuid=="function"&&d.uid!==process.getuid())continue;let p=Number(n[1]);if(this.isProcessAlive(p)||(c=this.quarantineIfIdentityMatches(o,this.identityOf(d)),!c))continue;let u=M.join(c,"pane.log"),f=M.join(c,X),v=y.readdirSync(c);if(v.some(m=>m!=="pane.log"&&m!==X)){this.restoreQuarantine(c,o);continue}for(let m of v.map(g=>M.join(c,g))){let g=y.lstatSync(m);if(!g.isFile()||g.isSymbolicLink()||typeof process.getuid=="function"&&g.uid!==process.getuid()){this.restoreQuarantine(c,o),c=null;break}}if(!c)continue;if(v.includes(X)){let m=y.readFileSync(f,"utf8").trim(),g=/^ready [a-f0-9]{32} (\d+)$/.exec(m);if(!(m==="idle"||/^done [a-f0-9]{32} \d+ \d+$/.test(m)||!!g)||g&&this.isProcessAlive(Number(g[1]))){this.restoreQuarantine(c,o);continue}}v.includes("pane.log")&&y.unlinkSync(u),v.includes(X)&&y.unlinkSync(f),y.rmdirSync(c),c=null,l.info("Removed stale tmux pane mirror directory",{candidate:o,ageMs:Date.now()-d.mtimeMs})}catch{c&&this.restoreQuarantine(c,o)}}}isProcessAlive(e){try{return process.kill(e,0),!0}catch(i){return i?.code==="EPERM"}}readAppendedChunk(){if(!this.pipeFilePath||this.pipeFileFd===null||!this.pipeFileIdentity)return"";if(!this.pathMatchesMirrorIdentity())throw new Error("Tmux pane mirror path was replaced");let e=y.fstatSync(this.pipeFileFd);if(!this.identitiesEqual(this.pipeFileIdentity,this.identityOf(e)))throw new Error("Tmux pane mirror descriptor identity changed");if(e.size<=this.filePosition)return"";{let s=e.size-this.filePosition>wt?e.size-wt:this.filePosition,r=e.size-s,n=Buffer.alloc(r),o=0;for(;o<r;){let c=y.readSync(this.pipeFileFd,n,o,r-o,s+o);if(c===0)break;o+=c}return this.filePosition=s+o,n.subarray(0,o).toString("utf-8")}}looksLikePromptDelta(e){return/Would you like to run/i.test(e)||/[>›❯▸▶]\s*[1-9]\d?\.\s/.test(e)||/\x1b\[[0-9;]*m[^\n]{0,80}[1-9]\d?\.\s/.test(e)||/Press enter to confirm/i.test(e)||/enter to (?:submit|confirm|select|continue)/i.test(e)||/\besc to cancel\b/i.test(e)||/\bYes,\s+proceed\b/i.test(e)||/\bNo,\s+and tell Codex\b/i.test(e)||/don't ask again/i.test(e)||/Requesting permission for:|Do you want to proceed\?/i.test(e)||/\[(?:y\/n|Y\/n|y\/N)\]|\b(?:apply|approve|allow|reject|deny|continue)\b/i.test(e)}looksLikePromptSnapshot(e){return this.extractActivePromptBlock(e)!==null}extractActivePromptBlock(e){return this.extractActiveApprovalBlock(e)??(0,ae.parseActiveTerminalMenu)(e)?.snapshot??null}extractActiveApprovalBlock(e){let s=e.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g,"").split(`
|
|
18
18
|
`).map(m=>m.replace(/\s+$/,"")),r=m=>m.trim().length>0,n=m=>{let g=m.trim();return/^(?:[>›❯]\s*)?press enter to confirm(?: or esc to cancel)?$/i.test(g)||/^(?:[>›❯]\s*)?(?:press )?esc to cancel$/i.test(g)},o=m=>/Would you like to |Do you want to |The model would like to |Allow .+ to run|Requesting permission for:/i.test(m),c=m=>/^[>›❯\s]*[1-9][.)]\s+\S/.test(m),d=m=>/\[(?:y\/n|Y\/n|y\/N)\]/i.test(m),p=m=>{let g=new Set;for(let w of m)c(w)&&(/\bYes,\s+proceed\b/i.test(w)&&g.add("proceed"),/\bNo,\s+and tell Codex\b/i.test(w)&&g.add("reject"),/don't ask again/i.test(w)&&g.add("dont-ask"));return g.size},u=m=>c(m)&&(/\bYes,\s+proceed\b/i.test(m)||/\bNo,\s+and tell Codex\b/i.test(m)||/don't ask again/i.test(m)),f=-1;for(let m=s.length-1;m>=0;m--)if(r(s[m])){f=m;break}if(f===-1)return null;if(d(s[f])){let m=f;for(let g=f-1;g>=0&&f-g<=8&&!(!r(s[g])||n(s[g])||c(s[g]));g--)m=g;return s.slice(m,f+1).join(`
|
|
19
19
|
`)}let v=-1;for(let m=s.length-1;m>=0;m--)if(n(s[m])){v=m;break}if(v===f){let m=-1;for(let w=v-1;w>=0&&!n(s[w]);w--)if(o(s[w])){m=w;break}if(m===-1)return null;let g=s.slice(m,v+1);return g.some(c)?g.join(`
|
|
20
20
|
`):null}if(u(s[f])){let m=-1;for(let S=f-1;S>=0;S--){if(n(s[S]))return null;if(o(s[S])){m=S;break}}if(m===-1)return null;let g=S=>{let P=S.match(/^[>›❯\s]*([1-9])[.)]\s/);return P?parseInt(P[1],10):null},w=[],E=Number.POSITIVE_INFINITY;for(let S=f;S>m&&c(s[S]);S--){let P=g(s[S]);if(P===null||P>=E)break;w.push(s[S]),E=P}return p(w)<2?null:s.slice(m,f+1).join(`
|