@quantiya/codevibe-codex-plugin 2.0.92 → 2.0.93
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 +2 -1
- package/node_modules/@quantiya/codevibe-core/dist/appsync/appsync-client.d.ts +3 -1
- package/node_modules/@quantiya/codevibe-core/dist/credential-broker/index.d.ts +1 -1
- package/node_modules/@quantiya/codevibe-core/dist/credential-broker/oauth-account-lock.d.ts +24 -0
- package/node_modules/@quantiya/codevibe-core/dist/index.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/index.js +466 -466
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +220 -202
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -28,7 +28,8 @@ ${We(c,500)}`,metadata:{toolName:h,toolOutput:u,callId:l,status:"completed"}}}re
|
|
|
28
28
|
`).trim();return(0,ce.createHash)("sha256").update(s).digest("hex")}};var j=require("@quantiya/codevibe-core");var ie=require("@quantiya/codevibe-core");var Ye=A(require("express")),Z=A(require("fs")),At=A(require("path")),kt=A(require("os"));var Ui=1800*1e3,Qi=60*1e3,Hi=1440*60*1e3;var ke=class{constructor(){this.assignedPort=0;this.portRefreshTimer=null;this.app=(0,Ye.default)(),this.setupMiddleware(),this.setupRoutes(),this.tmuxSession=process.env.CODEVIBE_CODEX_TMUX_SESSION}getPort(){return this.assignedPort}setupMiddleware(){this.app.use(Ye.default.json({limit:"1mb"})),this.app.use((e,t,i)=>{d.debug(`${e.method} ${e.path}`,{body:e.body}),i()})}setupRoutes(){this.app.get("/health",(e,t)=>{t.json({success:!0,service:"codevibe-codex",pid:process.pid,data:{status:"healthy",uptime:process.uptime()}})}),this.app.post("/event",this.handleEvent.bind(this))}async handleEvent(e,t){try{let i=e.body;if(!i.session_id||!i.hook_event_name){t.status(400).json({success:!1,error:"Missing session_id or hook_event_name"});return}let s=this.transformHookToEvent(i);if(d.info("Received hook event",{sessionId:i.session_id,hookEvent:i.hook_event_name,type:s.type}),this.eventHandler){let r=this.eventHandler(s);if(i.hook_event_name==="PermissionRequest"){r.catch(n=>{d.error("Error resolving PermissionRequest after acknowledgement:",n)}),t.json({success:!0});return}await r}t.json({success:!0})}catch(i){d.error("Error handling event:",i),t.status(500).json({success:!1,error:i instanceof Error?i.message:"Unknown error"})}}transformHookToEvent(e){let t={cwd:e.cwd,hook_event_name:e.hook_event_name,transcript_path:e.transcript_path,...e.metadata||{}},i,s;switch(e.hook_event_name){case"SessionStart":i="NOTIFICATION",s="Session started",t.source=e.source,t.model=e.model;break;case"UserPromptSubmit":i="USER_PROMPT",s=e.prompt||"";break;case"PreToolUse":i="NOTIFICATION",s="PreToolUse observed",t.tool_name=e.tool_name,t.tool_input=e.tool_input,t.tool_use_id=e.tool_use_id,t.approval_status="observed_pre_tool",t.requires_user_action=!1;break;case"PermissionRequest":i="NOTIFICATION",s="PermissionRequest observed",t.tool_name=e.tool_name,t.tool_input=e.tool_input,t.permission_mode=e.permission_mode,t.turn_id=e.turn_id,t.requires_user_action=!0;break;case"PostToolUse":i="TOOL_USE",s=JSON.stringify({tool_name:e.tool_name,tool_input:e.tool_input,tool_response:e.tool_response}),t.tool_name=e.tool_name,t.tool_input=e.tool_input,t.tool_use_id=e.tool_use_id;break;case"Stop":i="ASSISTANT_RESPONSE",s=e.last_assistant_message||"";break;default:i="NOTIFICATION",s=`Hook: ${e.hook_event_name}`}return{session_id:e.session_id,hook_event_name:e.hook_event_name,type:i,source:"DESKTOP",content:s,metadata:t}}onEvent(e){this.eventHandler=e}async start(){return new Promise((e,t)=>{try{this.server=this.app.listen(0,"localhost",()=>{let i=this.server.address();this.assignedPort=i.port,d.info(`HTTP API listening on http://localhost:${this.assignedPort}`),this.writePortFile(this.assignedPort),this.startPortFileKeepalive(),e(this.assignedPort)}),this.server.on("error",i=>{d.error("HTTP server error:",i),t(i)})}catch(i){t(i)}})}portFilePath(){return this.tmuxSession?At.join(kt.tmpdir(),`codevibe-codex-${this.tmuxSession}.port`):null}writePortFile(e){let t=this.portFilePath();if(!t){d.warn("No CODEVIBE_CODEX_TMUX_SESSION set, skipping port file");return}try{Z.writeFileSync(t,e.toString()),d.info(`Port file written: ${t} -> ${e}`)}catch(i){d.error(`Failed to write port file: ${t}`,i)}}removePortFile(){let e=this.portFilePath();if(e)try{Z.existsSync(e)&&(Z.unlinkSync(e),d.info(`Port file removed: ${e}`))}catch(t){d.warn(`Failed to remove port file: ${e}`,t)}}startPortFileKeepalive(){this.portRefreshTimer&&(clearInterval(this.portRefreshTimer),this.portRefreshTimer=null);let e=Number(process.env.CODEVIBE_PORTFILE_REFRESH_MS),t=Number.isFinite(e)&&e>0?Math.min(Hi,Math.max(Qi,e)):Ui;this.portRefreshTimer=setInterval(()=>this.refreshPortFile(),t)}refreshPortFile(){let e=this.portFilePath();if(e)try{let t=new Date;Z.utimesSync(e,t,t)}catch(t){t?.code==="ENOENT"?this.writePortFile(this.assignedPort):d.warn(`Port-file refresh failed: ${e}`,t)}}async stop(){return this.portRefreshTimer&&(clearInterval(this.portRefreshTimer),this.portRefreshTimer=null),this.removePortFile(),new Promise(e=>{this.server?this.server.close(()=>{d.info("HTTP API stopped"),e()}):e()})}};var Ne=class{constructor(e={}){this.pendingBySession=new Map;this.expiryMs=e.expiryMs??1e4,this.minFuzzyEchoLength=e.minFuzzyEchoLength??16,this.minFuzzyEchoRatio=e.minFuzzyEchoRatio??.35,this.now=e.now??Date.now}track(e,t){let i=this.normalize(t);if(!i)return;let s=this.validEntries(e);s.push({normalized:i,timestamp:this.now()}),this.pendingBySession.set(e,s)}forget(e,t){let i=this.normalize(t);if(!i)return;let s=!1,r=this.validEntries(e).filter(n=>!s&&n.normalized===i?(s=!0,!1):!0);this.replaceEntries(e,r)}consumeIfDuplicate(e,t){let i=this.normalize(t);if(!i)return null;let s=null,r=this.validEntries(e).filter(n=>{if(!s){let o=this.matchType(n.normalized,i);if(o)return s={matchType:o,originalLength:n.normalized.length,echoLength:i.length},!1}return!0});return this.replaceEntries(e,r),s}peekIfDuplicate(e,t){let i=this.normalize(t);if(!i)return null;for(let s of this.validEntries(e)){let r=this.matchType(s.normalized,i);if(r)return{matchType:r,originalLength:s.normalized.length,echoLength:i.length}}return null}validEntries(e){let t=this.now()-this.expiryMs;return(this.pendingBySession.get(e)||[]).filter(i=>i.timestamp>=t)}replaceEntries(e,t){t.length>0?this.pendingBySession.set(e,t):this.pendingBySession.delete(e)}matchType(e,t){if(e===t)return"exact";let i=t.length>=this.minFuzzyEchoLength,s=t.length/e.length>=this.minFuzzyEchoRatio;return i&&s&&e.endsWith(t)?"suffix":null}normalize(e){return e.replace(/\s+/g," ").trim()}};var Ft=A(require("crypto")),Dt=A(require("fs")),Mt=A(require("https")),Fe=A(require("os")),Lt=A(require("path")),$i="G-GS74YEQTB8",Wi="lAfOF6OxRzSQ-NsLBRjhAg",ji="www.google-analytics.com",zi=`/mp/collect?measurement_id=${$i}&api_secret=${Wi}`,Nt=800;function Gi(){try{let a=Lt.resolve(__dirname,"..","package.json"),e=Dt.readFileSync(a,"utf-8"),t=JSON.parse(e);if(typeof t.version=="string"&&t.version.length>0&&t.version.length<30)return t.version}catch{}return"unknown"}var Vi=Gi();function Yi(){let a=typeof process.getuid=="function"?process.getuid():0;return Ft.createHash("sha256").update(`${Fe.hostname()}-${a}`).digest("hex").substring(0,36)}function Ji(a){if(!a)return"";let e=Fe.homedir(),t=a.replace(/[\n\r\t]/g," ");if(e&&e.length>0){let i=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");t=t.replace(new RegExp(i,"g"),"~")}return t=t.replace(/\/Users\/[^/\s"'`]+/g,"/Users/<user>").replace(/\/home\/[^/\s"'`]+/g,"/home/<user>").replace(/[^\x20-\x7E]/g,""),t.trim().substring(0,100)}function k(a,e){return new Promise(t=>{let i,s=!1,r=()=>{s||(s=!0,clearTimeout(n),t())},n=setTimeout(()=>{try{i?.destroy()}catch{}r()},Nt);typeof n.unref=="function"&&n.unref();try{let o={...e};typeof o.error_message=="string"&&(o.error_message=Ji(o.error_message));let l=JSON.stringify({client_id:Yi(),events:[{name:a,params:{agent:"codex",plugin_version:Vi,platform:process.platform,source:process.env.CODEVIBE_TELEMETRY_SOURCE||"production",...o}}]});i=Mt.request({hostname:ji,path:zi,method:"POST",headers:{"Content-Type":"application/json"},timeout:Nt},u=>{u.resume(),u.on("end",r),u.on("close",r),u.on("error",r)}),i.on("error",r),i.on("timeout",()=>{try{i?.destroy()}catch{}r()}),i.on("close",r),i.write(l),i.end()}catch{r()}})}var De=class{constructor(){this.originated=new Set;this.externallyResolved=new Set}markOriginated(e){this.originated.add(e)}clearOriginated(e){this.originated.delete(e)}getOriginated(){return new Set(this.originated)}getExternallyResolved(){return new Set(this.externallyResolved)}isExternallyResolved(e){return this.externallyResolved.has(e)}dispatch(e){let{gateId:t}=e;return this.originated.has(t)?(this.originated.delete(t),this.externallyResolved.add(t),"self_echo"):(this.externallyResolved.add(t),"foreign")}clear(){this.originated.clear(),this.externallyResolved.clear()}};function qt(a){return`[CodeVibe] Decision recorded on another device: ${a} \u2014 type any number to dismiss the open AskUserQuestion`}var Bt=require("@quantiya/codevibe-core"),Xi=new Set(["stall-retirement","stall-tmux-probe"]),Zi=1e3,Me;function es(a=process.env){let e=new Map,t=a.CODEVIBE_DEV_FAULTS;if(t&&(0,Bt.getEnvironment)()==="development")for(let i of t.split(",")){let[s,r]=i.trim().split(":");if(!Xi.has(s))continue;let n=r===void 0?1:Number.parseInt(r,10);!Number.isSafeInteger(n)||n<=0||n>Zi||e.set(s,n)}return Me=e,e}function Je(a){Me||es();let e=Me.get(a)??0;return e<=0?!1:(Me.set(a,e-1),!0)}async function Xe(a,e,t){let i;try{let s=(()=>{try{return Promise.resolve(a())}catch(o){return Promise.reject(o)}})(),r=new Promise(o=>{i=setTimeout(()=>o("timeout"),e),i.unref&&i.unref()}),n=await Promise.race([s.then(()=>"settled",()=>"settled"),r]);if(n==="timeout"){s.catch(()=>{});try{t?.()}catch{}}return n}finally{i&&clearTimeout(i)}}function Ie(a,e,t=25e3,i=()=>!0){let s=setTimeout(()=>{try{e()}catch{}let r=!1;try{r=i()}catch{r=!1}a(r?0:1)},t);return()=>clearTimeout(s)}var we=A(require("crypto")),T=A(require("fs")),qe=A(require("os")),H=A(require("path")),Qt=require("@quantiya/codevibe-core"),Ze=2*1024*1024,ts=600*1e3,z=1e3;function Ht(){return typeof process.getuid=="function"?process.getuid():void 0}function et(a,e){let t=Ht();if(t!==void 0&&a.uid!==t)throw new Error(`E1_STATE_FOREIGN_OWNER: ${e}`)}function $t(a){T.mkdirSync(a,{recursive:!0,mode:448});let e=T.lstatSync(a);if(!e.isDirectory()||e.isSymbolicLink())throw new Error(`E1_STATE_ROOT_NOT_PRIVATE_DIRECTORY: ${a}`);et(e,a),process.platform!=="win32"&&T.chmodSync(a,448)}function Kt(a,e){let t=H.dirname(a);$t(t);let i=`${JSON.stringify(e)}
|
|
29
29
|
`;if(Buffer.byteLength(i,"utf8")>Ze)throw new Error(`E1_STATE_TOO_LARGE: ${a}`);let s=H.join(t,`.${H.basename(a)}.${process.pid}.${we.randomUUID()}.tmp`),r=T.constants.O_NOFOLLOW??0,n=null;try{n=T.openSync(s,T.constants.O_WRONLY|T.constants.O_CREAT|T.constants.O_EXCL|r,384),T.writeFileSync(n,i,{encoding:"utf8"}),T.fsyncSync(n),T.closeSync(n),n=null,process.platform!=="win32"&&T.chmodSync(s,384),T.renameSync(s,a),process.platform!=="win32"&&T.chmodSync(a,384);try{let o=T.openSync(t,T.constants.O_RDONLY);try{T.fsyncSync(o)}finally{T.closeSync(o)}}catch{}}finally{n!==null&&T.closeSync(n);try{T.unlinkSync(s)}catch(o){if(o.code!=="ENOENT")throw o}}}function Ut(a){let e;try{e=T.lstatSync(a)}catch(s){if(s.code==="ENOENT")return null;throw s}if(!e.isFile()||e.isSymbolicLink())throw new Error(`E1_STATE_NOT_REGULAR_FILE: ${a}`);if(et(e,a),process.platform!=="win32"&&(e.mode&63)!==0)throw new Error(`E1_STATE_PERMISSIONS_LOOSE: ${a}`);if(e.size>Ze)throw new Error(`E1_STATE_TOO_LARGE: ${a}`);let t=T.constants.O_NOFOLLOW??0,i=T.openSync(a,T.constants.O_RDONLY|t);try{let s=T.fstatSync(i);if(et(s,a),!s.isFile()||e.dev!==s.dev||e.ino!==s.ino)throw new Error(`E1_STATE_FILE_CHANGED_DURING_OPEN: ${a}`);if(s.size>Ze)throw new Error(`E1_STATE_TOO_LARGE: ${a}`);return JSON.parse(T.readFileSync(i,{encoding:"utf8"}))}finally{T.closeSync(i)}}function L(a){return a!==null&&typeof a=="object"&&!Array.isArray(a)}function C(a,e=256*1024){return typeof a=="string"&&Buffer.byteLength(a,"utf8")<=e}function Wt(a){if(!L(a)||!C(a.promptId,512)||!C(a.ownerToken,512)||!C(a.sessionId,1024)||a.producerKind!=="PLUGIN_APPROVAL"||a.agentType!==void 0&&a.agentType!=="CODEX"||a.title!==void 0&&!C(a.title,4096)||typeof a.mobileActionable!="boolean"||typeof a.raisedAtMs!="number"||!Number.isFinite(a.raisedAtMs))return!1;try{return(0,Qt.deriveOpenPromptId)(a.ownerToken)===a.promptId}catch{return!1}}function is(a){if(!L(a)||!Wt(a.record))return!1;for(let e of["contentPlain","resolutionDedupeKey","resolutionCompletionKey","resolutionCallId","suppressedObserverSnapshotKey"])if(a[e]!==void 0&&!C(a[e]))return!1;return!(a.metadataPlain!==void 0&&!L(a.metadataPlain)||a.suppressTmuxObserverUntilResolved!==void 0&&typeof a.suppressTmuxObserverUntilResolved!="boolean")}function jt(a){return L(a)&&Wt(a.record)&&C(a.resolutionAt,128)&&!Number.isNaN(Date.parse(a.resolutionAt))&&typeof a.attempts=="number"&&Number.isSafeInteger(a.attempts)&&a.attempts>=0}function zt(a){if(!L(a)||a.nativeQuestionTitleSha256!==void 0&&(typeof a.nativeQuestionTitleSha256!="string"||!/^[a-f0-9]{64}$/.test(a.nativeQuestionTitleSha256))||!C(a.promptId,512)||!["yes_no","numbered","text","queued_question"].includes(String(a.kind))||!Array.isArray(a.options)||a.options.length>100||!a.options.every(i=>L(i)&&C(i.number,32)&&C(i.text,32*1024)&&(i.description===void 0||C(i.description,32*1024))&&(i.preview===void 0||C(i.preview,32*1024)))||!L(a.submitMap)||!Object.entries(a.submitMap).every(([i,s])=>C(i,128)&&C(s,32*1024))||!C(a.promptText)||typeof a.createdAt!="number"||!Number.isFinite(a.createdAt)||!["permission_hook","tmux","heuristic","queued_question"].includes(String(a.source)))return!1;for(let i of["callId","dedupeKey","completionKey","ownerSessionId","observerMatchKey","observerPromptHash","terminalMenuIdentity"])if(a[i]!==void 0&&!C(a[i],32*1024))return!1;if(a.requiresFollowUpText!==void 0&&typeof a.requiresFollowUpText!="boolean")return!1;let e=a.preemptedQueuedQuestionId!==void 0,t=a.preemptedQueuedQuestionAt!==void 0;if(e!==t||e&&(!C(a.preemptedQueuedQuestionId,512)||a.preemptedQueuedQuestionId.trim().length===0||typeof a.preemptedQueuedQuestionAt!="number"||!Number.isFinite(a.preemptedQueuedQuestionAt)||a.preemptedQueuedQuestionAt<=0))return!1;if(a.allQuestions!==void 0){if(!Array.isArray(a.allQuestions)||a.allQuestions.length>100)return!1;for(let i of a.allQuestions){if(!L(i)||!C(i.question,32*1024)||!Array.isArray(i.options)||i.options.length>100||i.header!==void 0&&!C(i.header,1024)||i.multiSelect!==void 0&&typeof i.multiSelect!="boolean")return!1;for(let s of i.options)if(typeof s=="string"){if(!C(s,32*1024))return!1}else if(L(s)){if(!C(s.label,32*1024)||s.description!==void 0&&!C(s.description,32*1024)||s.preview!==void 0&&!C(s.preview,32*1024))return!1}else return!1}}return!0}function ss(a){return L(a)&&zt(a.prompt)&&C(a.content)&&L(a.metadata)}function rs(a,e,t){if(!L(a)||a.version!==1)throw new Error("E1_HANDOFF_UNSUPPORTED_VERSION");if(a.tmuxSession!==e||!C(a.backendSessionId,1024))throw new Error("E1_HANDOFF_INSTANCE_MISMATCH");if(typeof a.createdAtMs!="number"||!Number.isFinite(a.createdAtMs))throw new Error("E1_HANDOFF_INVALID_TIMESTAMP");if(a.createdAtMs>t+6e4||t-a.createdAtMs>ts)throw new Error("E1_HANDOFF_STALE");if(!Array.isArray(a.openRaises)||a.openRaises.length>z||!a.openRaises.every(is))throw new Error("E1_HANDOFF_INVALID_OPEN_RAISES");if(!Array.isArray(a.pendingResolutions)||a.pendingResolutions.length>z||!a.pendingResolutions.every(jt))throw new Error("E1_HANDOFF_INVALID_PENDING_RESOLUTIONS");if(!Array.isArray(a.needsReRaisePromptIds)||a.needsReRaisePromptIds.length>z||!a.needsReRaisePromptIds.every(s=>C(s,512)))throw new Error("E1_HANDOFF_INVALID_RERAISE_IDS");if(!Array.isArray(a.permissionOccurrences)||a.permissionOccurrences.length>z)throw new Error("E1_HANDOFF_INVALID_OCCURRENCES");if(!a.permissionOccurrences.every(s=>Array.isArray(s)&&s.length===2&&C(s[0],256*1024)&&Array.isArray(s[1])&&s[1].length<=z&&s[1].every(r=>L(r)&&C(r.occurrenceKey,512)&&typeof r.hookObserved=="boolean"&&typeof r.jsonlObserved=="boolean")))throw new Error("E1_HANDOFF_INVALID_OCCURRENCES");if(a.waitingPermissionRequests!==void 0&&(!Array.isArray(a.waitingPermissionRequests)||a.waitingPermissionRequests.length>z||!a.waitingPermissionRequests.every(s=>L(s)&&C(s.occurrenceKey,512)&&(s.dedupeKey===void 0||C(s.dedupeKey))&&L(s.payload)&&s.payload.hook_event_name==="PermissionRequest"&&(s.payload.metadata===void 0||L(s.payload.metadata)))))throw new Error("E1_HANDOFF_INVALID_WAITING_REQUESTS");if(a.pendingInteractivePrompt!==null&&!zt(a.pendingInteractivePrompt))throw new Error("E1_HANDOFF_INVALID_ACTIVE_PROMPT");if(!Array.isArray(a.queuedInteractivePrompts)||a.queuedInteractivePrompts.length>z||!a.queuedInteractivePrompts.every(ss))throw new Error("E1_HANDOFF_INVALID_QUEUED_PROMPTS");if(!Array.isArray(a.resolvedApprovalDedupeKeys)||a.resolvedApprovalDedupeKeys.length>z||!a.resolvedApprovalDedupeKeys.every(s=>Array.isArray(s)&&s.length===2&&C(s[0])&&typeof s[1]=="number"&&Number.isFinite(s[1])))throw new Error("E1_HANDOFF_INVALID_RESOLVED_KEYS");if(a.historicalQueuedQuestionPromptIds!==void 0&&(!Array.isArray(a.historicalQueuedQuestionPromptIds)||a.historicalQueuedQuestionPromptIds.length>z||!a.historicalQueuedQuestionPromptIds.every(s=>C(s,512))))throw new Error("E1_HANDOFF_INVALID_HISTORICAL_QUESTION_IDS");return a}function ns(a){if(!L(a)||a.version!==1||!jt(a.pending))throw new Error("E1_RESOLUTION_OUTBOX_INVALID_RECORD");if(typeof a.updatedAtMs!="number"||!Number.isFinite(a.updatedAtMs))throw new Error("E1_RESOLUTION_OUTBOX_INVALID_TIMESTAMP");return a}var Le=class{constructor(e={}){let t=Ht()??"nouid";this.handoffRoot=e.handoffRoot??H.join(qe.tmpdir(),`codevibe-codex-handoff-${t}`),this.resolutionRoot=e.resolutionRoot??H.join(qe.homedir(),".codevibe","codex","e1-resolution-outbox"),this.now=e.now??Date.now}handoffPath(e){let t=we.createHash("sha256").update(e).digest("hex").slice(0,32);return H.join(this.handoffRoot,`${t}.json`)}resolutionPath(e){let t=we.createHash("sha256").update(e).digest("hex");return H.join(this.resolutionRoot,`${t}.json`)}writeHandoff(e){Kt(this.handoffPath(e.tmuxSession),e)}readHandoff(e){let t=Ut(this.handoffPath(e));if(t===null)return null;try{return rs(t,e,this.now())}catch(i){if(i.message==="E1_HANDOFF_STALE")return this.removeHandoff(e),null;throw i}}removeHandoff(e){try{T.unlinkSync(this.handoffPath(e))}catch(t){if(t.code!=="ENOENT")throw t}}writeResolution(e){Kt(this.resolutionPath(e.record.promptId),{version:1,updatedAtMs:this.now(),pending:e})}removeResolution(e){try{T.unlinkSync(this.resolutionPath(e))}catch(t){if(t.code!=="ENOENT")throw t}}readResolutions(){let e;try{$t(this.resolutionRoot),e=T.readdirSync(this.resolutionRoot).filter(s=>s.endsWith(".json"))}catch(s){if(s.code==="ENOENT")return{records:[],rejected:[]};throw s}let t=[],i=[];for(let s of e.slice(0,z)){let r=H.join(this.resolutionRoot,s);try{let n=Ut(r);if(n!==null){let o=ns(n).pending;if(H.basename(this.resolutionPath(o.record.promptId))!==s)throw new Error("E1_RESOLUTION_OUTBOX_IDENTITY_MISMATCH");t.push(o)}}catch(n){i.push({file:r,reason:n instanceof Error?n.message:String(n)})}}return e.length>z&&i.push({file:this.resolutionRoot,reason:`E1_RESOLUTION_OUTBOX_RECORD_LIMIT: ${e.length}`}),{records:t,rejected:i}}};var Xt=(0,rt.promisify)(Qe.exec),os=(0,rt.promisify)(Qe.execFile),as="/quit",ee="CODEVIBE_CODEX_TMUX_SESSION",Be="CODEVIBE_CODEX_DAEMON_RECOVERY",ls=1e3,ds=1e4,Ke=3,us=100,Zt=["SIGINT","SIGTERM","SIGHUP"],ps=600*1e3,tt=30*1e3,cs=/^(?:[a-z0-9]|esc|escape)$/;function Yt(a,e){let t=a?.[e];return typeof t=="string"?t:Buffer.isBuffer(t)?t.toString("utf8"):""}function ei(a){if(typeof a?.code!="number")return"unknown";let e=`${Yt(a,"stderr")}
|
|
30
30
|
${Yt(a,"stdout")}`;return/^can't find session:/m.test(e)||/^no server running on /m.test(e)||/^error connecting to .* \((?:No such file or directory|Connection refused)\)$/m.test(e)?"absent":"unknown"}async function hs(a,e){let t=async(i,s)=>{try{await Xt(i)}catch(r){d.warn("tmux send-keys failed during self-terminate",{sessionName:a,label:s,error:String(r)})}};await t(`tmux send-keys -t "${a}" C-c`,"ctrl-c"),await new Promise(i=>setTimeout(i,200)),await t(`tmux send-keys -t "${a}" -l "${e}"`,"quit-text"),await new Promise(i=>setTimeout(i,500)),await t(`tmux send-keys -t "${a}" Enter`,"enter")}function ot(a){let e=a.split(`
|
|
31
|
-
`),t=n=>/^[\s>]*\d+\.\s/.test(n),i=-1;for(let n=e.length-1;n>=0;n-=1)if(/^\s*\$\s+/.test(e[n])){i=n;break}if(i===-1)return;let s=e[i].trim().match(/^\$\s+(.+)$/);if(!s?.[1]?.trim())return;let r=[s[1].trim()];for(let n=i+1;n<e.length;n+=1){let o=e[n];if(t(o)||/^\s*$/.test(o)||/^\s*\$\s+/.test(o))break;r.push(o.trim())}return r.length>0?r:void 0}function ti(a){let e=ot(a);if(!e)return;let t=e.join(" ").trim();return t.length>0?t:void 0}function ii(a,e){return ms(a,e).has(e)}function ms(a,e){if(a.length===0)return new Set;let t=e,i=new Set([a[0]]);for(let s of a.slice(1)){let r=s,n=new Set;for(let o of i)for(let l of[""," "
|
|
31
|
+
`),t=n=>/^[\s>]*\d+\.\s/.test(n),i=-1;for(let n=e.length-1;n>=0;n-=1)if(/^\s*\$\s+/.test(e[n])){i=n;break}if(i===-1)return;let s=e[i].trim().match(/^\$\s+(.+)$/);if(!s?.[1]?.trim())return;let r=[s[1].trim()];for(let n=i+1;n<e.length;n+=1){let o=e[n];if(t(o)||/^\s*$/.test(o)||/^\s*\$\s+/.test(o))break;r.push(o.trim())}return r.length>0?r:void 0}function ti(a){let e=ot(a);if(!e)return;let t=e.join(" ").trim();return t.length>0?t:void 0}function ii(a,e){return ms(a,e).has(e)}function ms(a,e){if(a.length===0)return new Set;let t=e,i=new Set([a[0]]);for(let s of a.slice(1)){let r=s,n=new Set;for(let o of i)for(let l of[""," ",`
|
|
32
|
+
`]){let u=`${o}${l}${r}`;t.startsWith(u)&&n.add(u)}if(n.size===0)return new Set;i=n}return i}function fs(a,e,t){let i=/^\[\u2026\s+\d+\s+lines\]\s+ctrl\s*\+\s*a\s+view\s+all$/i,s=a.split(`
|
|
32
33
|
`).map(r=>r.trim()).filter(Boolean);return s.length<2||!i.test(s[s.length-1])||!t?!1:gs(t,e)}function gs(a,e){let t=st(e),i=ri(a,"2");if(!t||!i)return!1;let s=new Set;for(let r of ni(i)){let n=r.match(/^Yes, and don't ask again for commands that start with `([^`]*)`\s*\(p\)$/);if(!n)continue;let o=st(n[1]);o&&JSON.stringify(o)===JSON.stringify(t)&&s.add(JSON.stringify(o))}return s.size===1}function si(a,e,t){if(!a.find(h=>h.number==="2"&&/\(p\)\s*$/i.test(h.text)))return a;let s="Yes, and don't ask again for commands that start with",r="Yes, and don't ask again (p)",n=ri(t,"2");if(!n)return null;let o=ni(n);if(o.has(r))return a.map(h=>h.number==="2"?{...h,text:r}:h);if(!e)return null;let l=new Map;for(let h of o){let c=h.match(/^Yes, and don't ask again for commands that start with `([^`]*)`\s*\(p\)$/);if(!c)continue;let g=st(c[1]);!g||!vs(g,e)||l.set(JSON.stringify(g),g)}if(l.size!==1)return null;let u=[...l.values()][0],p=ys(u);return a.map(h=>h.number==="2"?{...h,text:`${s} \`${p}\` (p)`}:h)}function ri(a,e){if(!a)return null;let t=(0,j.normalizeSnapshot)(a).split(`
|
|
33
34
|
`).map(o=>o.trim()),i=new RegExp(`^(?:[>\u203A\u276F\u25B8\u25B6\u279C\u27A4*\u25CF]\\s*)?${e}\\.\\s+(.*)$`),s=-1,r="";for(let o=t.length-1;o>=0;o-=1){let l=t[o].match(i);if(l){s=o,r=l[1];break}}if(s<0)return null;let n=[r];for(let o=s+1;o<t.length&&!(/^(?:[>›❯▸▶➜➤*●]\s*)?\d+\.\s+/.test(t[o])||!t[o]||(n.push(t[o]),/\(p\)\s*$/i.test(t[o])));o+=1);return n.some(o=>/\(p\)\s*$/i.test(o))?n:null}function ni(a){if(a.length===0||a.length>13)return new Set;let e=new Set([a[0]]);for(let t of a.slice(1)){let i=new Set;for(let s of e)i.add(`${s}${t}`),i.add(`${s} ${t}`);e=i}return e}function st(a){try{let e=(0,nt.parse)(a,t=>`\${${t}}`);return e.every(t=>typeof t=="string")?e:null}catch{return null}}function ys(a){return a.map(e=>/^[A-Za-z0-9_@%+=:,./-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`).join(" ")}function ne(a){return a.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g,"")}function Jt(a){return a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function vs(a,e){if(a.length===0)return!1;let t;try{t=(0,nt.parse)(e,s=>`\${${s}}`)}catch{return!1}let i=[[]];for(let s of t){if(typeof s=="string"){i[i.length-1].push(s);continue}if("op"in s&&["&&","||",";","|","|&","&"].includes(s.op)){i.push([]);continue}return!1}return i.some(s=>a.every((r,n)=>s[n]===r))}var Ue=class a{constructor(){this.sessionState=null;this.unsubscribe=null;this.sessionKey=null;this.sessionIsEncrypted=!1;this.sessionKeyGen=null;this.e1PromptRaises=new Map;this.e1PendingResolutions=new Map;this.e1ResolutionInFlight=new Map;this.e1RaiseInFlight=new Map;this.acknowledgedQueuedQuestionRaises=new WeakSet;this.e1NeedsReRaise=new Set;this.e1RetirementOrphans=new Map;this.e1ContentKeyIndex=new Map;this.e1TtlRefreshTimer=null;this.toolActivity=null;this.toolActivityStartPromise=null;this.toolActivityLegacyRecorders=new Map;this.pendingInteractivePrompt=null;this.queuedInteractivePrompts=[];this.isInitializingSession=!1;this.bufferedLogEntries=[];this.logEntryChain=Promise.resolve();this.nativeSourceSelection=null;this.nativeSourceOwners=new Map;this.nativeSourceRetryTimer=null;this.hookEventChain=Promise.resolve();this.hooksActive=!1;this.hooksCompatibilityNoticeSent=!1;this.permissionRequestHookInFlight=null;this.queuedPermissionRequestDedupeKeys=new Map;this.queuedPermissionRequestSessionCounts=new Map;this.queuedPermissionRequestRegistrations=new Map;this.waitingPermissionRequests=new Map;this.permissionRequestOccurrencesByCompletionKey=new Map;this.deferredTmuxPromptCandidates=new Map;this.recoveryPermissionReplay=null;this.resolvedApprovalDedupeKeys=new Map;this.queuedQuestionCallIds=new Set;this.historicalQueuedQuestionPromptIds=new Set;this.subscribedSessionId=null;this.subscribedSessionState=null;this.terminalInputChain=Promise.resolve();this.terminalInputBlockedStates=new WeakSet;this.mobilePromptDeduper=new Ne({expiryMs:1e4});this.launchSessionInitPromise=null;this.sessionStartedInitPromise=null;this.bootstrapSessionId=null;this.recoveryBootstrapOwnerBound=!1;this.resumeBackendSession=f.resumeOrCreateSession;this.sessionBootstrapFailureCount=0;this.sessionBootstrapRetryAt=0;this.retiredSessionRecoveryPromise=null;this.lifecycleGeneration=0;this.isStopping=!1;this.stopPromise=null;this.terminalRetirementRequested=!1;this.teardownStepsTimedOut=[];this.retirementOwed=!1;this.tmuxLifecycleTimer=null;this.tmuxLifecycleCheckInFlight=!1;this.tmuxLifecycleObservedAlive=!1;this.tmuxLifecycleInitDeadlineMs=Number.POSITIVE_INFINITY;this.v1Bridge=new De;this.orchestrationClient=null;this.userDecisionUnsubscribe=null;this.httpApi=new ke,this.sessionWatcher=new Re({restoreCursor:(e,t)=>this.retryNativeAdmission(()=>this.restoreNativeSource(e,t)),beforeGap:(e,t)=>this.retryNativeAdmission(()=>this.admitNativeSourceGap(e,t)),beforeEntry:(e,t)=>this.retryNativeAdmission(()=>this.admitNativeSourceEntry(e,t))}),this.approvalDetector=new xe,this.promptResponder=new Ce,this.tmuxPaneObserver=new Oe,this.e1DurableState=new Le({handoffRoot:process.env.CODEVIBE_CODEX_HANDOFF_ROOT,resolutionRoot:process.env.CODEVIBE_CODEX_E1_OUTBOX_ROOT})}static{this.E1_TTL_REFRESH_MS=300*1e3}async start(){if(d.info("Starting CodeVibe Codex companion server",{environment:(0,f.getEnvironment)()}),this.appSyncClient=new f.AppSyncClient,!await this.appSyncClient.authenticateWithStoredTokens()){let i=(0,f.describeStoredAuthFailure)(this.appSyncClient.getLastAuthFailureKind(),this.appSyncClient.getLastAuthFailureDetail());d.error("Authentication with stored credentials failed",{kind:this.appSyncClient.getLastAuthFailureKind(),exitCode:i.exitCode}),console.error(i.message),process.exit(i.exitCode)}d.info("Authenticated successfully",{userId:this.appSyncClient.getCurrentUserId(),email:this.appSyncClient.getCurrentUserEmail()});try{let i=this.appSyncClient.getCurrentUserId(),s=AbortSignal.timeout(5e3),r=new Promise((l,u)=>s.addEventListener("abort",()=>u(new Error("status read timed out")),{once:!0})),n=await Promise.race([this.appSyncClient.getSubscriptionStatus(s),r]);if(this.appSyncClient.getCurrentUserId()!==i)throw new Error("account changed during read");let o=await Promise.race([this.appSyncClient.getCompanionSyncState(s),r]);if(this.appSyncClient.getCurrentUserId()!==i)throw new Error("account changed during read");if(n.tier!==o.tier)throw new Error("tier changed during read");d.info("Standalone Companion sync status",{tier:o.tier,protocol:o.protocol,syncState:o.usage?.syncState??null,resetAtEpochMs:o.resetAtEpochMs})}catch{d.warn("Standalone Companion sync status unavailable; cloud admission remains authoritative")}await this.restorePendingE1ResolutionsFromOutbox(),await(0,f.registerDeviceEncryptionKey)(this.appSyncClient,d),(0,f.startDeviceKeyWatcher)(this.appSyncClient,d),(0,f.pushDetectedAgents)(this.appSyncClient,d).catch(i=>{d.warn("Failed to update available agents (non-fatal)",{error:i?.message})});try{let i=await this.appSyncClient.sweepOrphanSessions({agentType:"CODEX"});i>0&&d.info("Orphan sweep: marked stale Codex sessions INACTIVE",{swept:i})}catch(i){d.warn("Orphan sweep failed, continuing startup",{error:i instanceof Error?i.message:String(i)})}this.httpApi.onEvent(this.handleEventFromHook.bind(this));let t=await this.httpApi.start();d.info("HTTP API started for hooks",{port:t}),this.startTmuxLifecycleMonitor(),await this.createLaunchSession(),this.setupEventHandlers(),this.sessionWatcher.start(),d.info("CodeVibe Codex companion server started")}async createLaunchSession(){if(this.isStopping)return;if(process.env[Be]==="1"){d.info("Recovery daemon deferring backend bootstrap until the native rollout is known");return}let e=this.lifecycleGeneration,t=process.env.CODEVIBE_CODEX_TMUX_SESSION;if(!t){d.warn("No CODEVIBE_CODEX_TMUX_SESSION \u2014 skipping launch session");return}let i;this.launchSessionInitPromise=new Promise(s=>{i=s});try{let s=process.env.CODEX_WORKING_DIRECTORY||process.cwd(),r=this.getOrCreateBootstrapSessionId(),n=this.appSyncClient.getCurrentUserId();d.info("Creating launch session",{sessionId:r,projectPath:s});let o=!1;try{let l=await(0,f.resumeOrCreateSession)({sessionId:r,userId:n,agentType:f.AgentType.CODEX,projectPath:s,metadata:{launchSession:!0}},this.appSyncClient,d);if(r=l.sessionId,!this.isLifecycleCurrent(e)){await this.retireCancelledBootstrap(r,"launch_session");return}this.sessionKey=l.sessionKey,this.sessionKeyGen=l.sessionKeyGen,this.sessionIsEncrypted=!!l.sessionKey,o=!0,this.sessionState={sessionId:r,userId:n,projectPath:s,cwd:s,createdAt:new Date,subscriptionActive:!1,metadata:{launchSession:!0},encryptionSnapshot:{sessionKey:l.sessionKey,sessionIsEncrypted:!!l.sessionKey},codexSessionId:t,codexLogFile:void 0},this.clearSessionBootstrapFailure(),this.bootstrapSessionId=null,await k("daemon_init_step_completed",{step:"session_resume_or_create",path:"launch_session"})}catch(l){if(!this.isLifecycleCurrent(e)){let u=this.authoritativeSessionIdFromError(l)??r;await this.retireCancelledBootstrap(u,"launch_session_error");return}await k("daemon_init_step_failed",{step:"session_resume_or_create",path:"launch_session",error_class:l?.name||"Error",error_message:l?.message||String(l)}),l?.code==="ENCRYPTED_SESSION_NO_KEY"&&(this.sessionIsEncrypted=!0,this.sessionKey=null),this.bindBootstrapIdentityFromError(l),this.recordSessionBootstrapFailure(l,"launch_session"),d.error("Failed to create/resume launch session (non-fatal)",{error:l})}if(!o)return;await k("daemon_init_step_completed",{step:"session_state_set",path:"launch_session"});try{this.subscribeToMobileEvents(r)?await k("daemon_init_step_completed",{step:"subscribe_mobile_events",path:"launch_session"}):await k("daemon_init_step_failed",{step:"subscribe_mobile_events",path:"launch_session",error_class:"SubscriptionSetupFailed",error_message:"subscribeToMobileEvents returned false"})}catch(l){await k("daemon_init_step_failed",{step:"subscribe_mobile_events",path:"launch_session",error_class:l?.name||"Error",error_message:l?.message||String(l)}),d.error("Failed to subscribe to mobile events for launch session",{error:l})}try{await this.appSyncClient.startHeartbeat(r)?await k("daemon_init_step_completed",{step:"heartbeat_start",path:"launch_session"}):(await k("daemon_init_step_failed",{step:"heartbeat_start",path:"launch_session",error_class:"InitialHeartbeatNotPersisted",error_message:"Backend did not confirm the initial heartbeat mutation"}),d.error("Initial launch-session heartbeat was not persisted",{sessionId:r}))}catch(l){await k("daemon_init_step_failed",{step:"heartbeat_start",path:"launch_session",error_class:l?.name||"Error",error_message:l?.message||String(l)}),d.error("Failed to start heartbeat for launch session",{error:l})}try{await this.subscribeToOnApplyUserDecision(r)}catch(l){d.error("Failed to subscribe to onApplyUserDecision for launch session (non-fatal)",{error:l})}this.startMobileEndWatcher(r),d.info("Launch session created",{sessionId:r})}finally{i()}}encryptForEmit(e,t,i,s){let r=this.sessionState;if(!r||r.sessionId!==s||!r.encryptionSnapshot)return d.warn("Dropping event from stale or unresolved session generation (#638)",{type:i,sessionId:s,currentSessionId:r?.sessionId}),null;let{sessionKey:n,sessionIsEncrypted:o}=r.encryptionSnapshot,l=(0,f.encryptForEmit)(n,o,e,t);return l===null&&d.error("No session key for ENCRYPTED session \u2014 dropping event (fail-closed, #638)",{type:i,sessionId:s}),l}newE1Raise(e,t,i,s){let{record:r}=(0,f.newPromptRaise)({sessionId:e,producerKind:"PLUGIN_APPROVAL",mobileActionable:t,agentType:"CODEX",...i!==void 0&&{title:i}});return this.e1PromptRaises.set(r.promptId,{record:r,...s?.dedupeKey!==void 0?{resolutionDedupeKey:s.dedupeKey}:{},...s?.completionKey!==void 0?{resolutionCompletionKey:s.completionKey}:{},...s?.callId!==void 0?{resolutionCallId:s.callId}:{}}),this.e1TtlRefreshTimer||this.startE1TtlRefresh(),r}stashE1RaiseContent(e,t,i){let s=this.e1PromptRaises.get(e);s&&(s.contentPlain=t,s.metadataPlain=i)}async emitSuppressedPromptCarrier(e,t,i){return this.publishE1Prompt(e,t,f.EventType.NOTIFICATION,"\u26A0\uFE0F A prompt is waiting in your desktop terminal, but its options could not be shown here. Please answer it on your desktop.",{e1SuppressedPrompt:!0},i)}publishE1Prompt(e,t,i,s,r,n){let o=(0,f.prepareEventTimestamp)({orderingKey:e}),l={sessionId:e,type:i,source:f.EventSource.DESKTOP,content:s,metadata:r,...(0,f.raiseFieldsFromRecord)(t),timestamp:o},u=this.e1PromptRaises.get(t.promptId),p=()=>u?.record===t&&(0,f.isOpenPromptRaise)(u,this.e1PromptRaises.get(t.promptId));if(!p())return Promise.resolve("CLOSED");let h=c=>(p()&&(i===f.EventType.INTERACTIVE_PROMPT&&r.isQueuedQuestion===!0&&u&&(c==="RERAISED"?this.acknowledgedQueuedQuestionRaises.add(u):this.acknowledgedQueuedQuestionRaises.delete(u)),c==="RETRY"?this.e1NeedsReRaise.add(t.promptId):(c==="RERAISED"||c==="OMITTED")&&this.e1NeedsReRaise.delete(t.promptId)),c);return this.trackE1Raise(t.promptId,this.appSyncClient.publishCompanionPrompt(l,async()=>{let c=this.encryptForEmit(s,r,i,e);return c?(await this.appSyncClient.createEvent({...l,content:c.content,metadata:c.metadata,...i===f.EventType.NOTIFICATION&&{notificationText:s},...c.isEncrypted?{isEncrypted:!0}:{}}),!0):!1},{reRaiseToken:n}).then(h,c=>{throw h("RETRY"),c}))}raiseSuppressedBadge(e,t,i={}){if(t){if(this.hasRecentlyResolvedApprovalDedupeKey(e,t)){d.debug("Skipping suppressed-prompt carrier; approval completed while producer was in flight",{sessionId:e,dedupeKey:t});return}let r=`${e}::${t}`,n=this.e1ContentKeyIndex.get(r);if(n&&this.e1PromptRaises.has(n)){if(i.suppressTmuxObserverUntilResolved){let o=this.e1PromptRaises.get(n);o&&(o.suppressTmuxObserverUntilResolved=!0,i.observerSnapshot&&(o.suppressedObserverSnapshotKey=this.buildObserverSnapshotMatchKey(i.observerSnapshot)))}return}n&&this.e1ContentKeyIndex.delete(r)}let s=this.newE1Raise(e,!1,void 0,t?{dedupeKey:t,completionKey:i.completionKey}:void 0);if(i.suppressTmuxObserverUntilResolved){let r=this.e1PromptRaises.get(s.promptId);r&&(r.suppressTmuxObserverUntilResolved=!0,i.observerSnapshot&&(r.suppressedObserverSnapshotKey=this.buildObserverSnapshotMatchKey(i.observerSnapshot)))}t&&this.e1ContentKeyIndex.set(`${e}::${t}`,s.promptId),this.emitSuppressedPromptCarrier(e,s).catch(r=>{d.error("E1: failed to emit suppressed-prompt badge carrier",{sessionId:e,promptId:s.promptId,error:r instanceof Error?r.message:String(r)})})}snapshotOpenE1(e){return[...this.e1PromptRaises.values()].filter(t=>t.record.sessionId===e).map(t=>({record:{...t.record},...t.contentPlain!==void 0&&{contentPlain:t.contentPlain},...t.metadataPlain!==void 0&&{metadataPlain:t.metadataPlain},...t.resolutionDedupeKey!==void 0&&{resolutionDedupeKey:t.resolutionDedupeKey},...t.resolutionCompletionKey!==void 0&&{resolutionCompletionKey:t.resolutionCompletionKey},...t.resolutionCallId!==void 0&&{resolutionCallId:t.resolutionCallId},...t.suppressTmuxObserverUntilResolved!==void 0&&{suppressTmuxObserverUntilResolved:t.suppressTmuxObserverUntilResolved},...t.suppressedObserverSnapshotKey!==void 0&&{suppressedObserverSnapshotKey:t.suppressedObserverSnapshotKey}}))}buildDaemonHandoffSnapshot(e){let t=process.env[ee];if(!t)throw new Error("E1_DAEMON_HANDOFF_MISSING_TMUX_SESSION");return{version:1,createdAtMs:Date.now(),tmuxSession:t,backendSessionId:e.sessionId,openRaises:this.snapshotOpenE1(e.sessionId),pendingResolutions:[...this.e1PendingResolutions.values()].map(i=>({record:{...i.record},resolutionAt:i.resolutionAt,attempts:i.attempts})),needsReRaisePromptIds:[...this.e1NeedsReRaise],permissionOccurrences:[...this.permissionRequestOccurrencesByCompletionKey.entries()].map(([i,s])=>[i,s.map(r=>({...r}))]),waitingPermissionRequests:[...this.waitingPermissionRequests.values()].filter(i=>i.ownerState===e).map(({occurrenceKey:i,dedupeKey:s,payload:r})=>({occurrenceKey:i,dedupeKey:s,payload:r})),pendingInteractivePrompt:this.pendingInteractivePrompt?{...this.pendingInteractivePrompt}:null,queuedInteractivePrompts:this.queuedInteractivePrompts.map(i=>({prompt:{...i.prompt},content:i.content,metadata:{...i.metadata}})),resolvedApprovalDedupeKeys:[...this.resolvedApprovalDedupeKeys.entries()].filter(([,i])=>i>Date.now()-tt),historicalQueuedQuestionPromptIds:[...this.historicalQueuedQuestionPromptIds].filter(i=>typeof i=="string"&&i.trim().length>0&&Buffer.byteLength(i,"utf8")<=512).slice(-1e3)}}persistDaemonHandoffState(e){for(let i of this.e1PendingResolutions.values())this.e1DurableState.writeResolution(i);let t=this.buildDaemonHandoffSnapshot(e);this.e1DurableState.writeHandoff(t),d.info("E1: persisted daemon handoff state",{sessionId:e.sessionId,openPrompts:t.openRaises.length,pendingResolutions:t.pendingResolutions.length,completionQueues:t.permissionOccurrences.length})}async adoptDaemonHandoffState(e){if(process.env[Be]!=="1")return!1;let t=process.env[ee];if(!t)return!1;let i=this.e1DurableState.readHandoff(t);if(!i)return!1;let s=this.sessionState;if(!s||s.sessionId!==e)throw new Error("E1_DAEMON_HANDOFF_WITHOUT_CURRENT_SESSION");for(let l of i.pendingResolutions)this.e1PendingResolutions.has(l.record.promptId)||this.e1PendingResolutions.set(l.record.promptId,{record:{...l.record},resolutionAt:l.resolutionAt,attempts:l.attempts}),this.e1DurableState.writeResolution(l);for(let l of i.openRaises){let u={...l,record:{...l.record},...l.metadataPlain!==void 0&&{metadataPlain:{...l.metadataPlain}}};this.e1PromptRaises.set(u.record.promptId,u),i.backendSessionId!==e&&this.e1RetirementOrphans.set(u.record.promptId,{...u,record:{...u.record}}),u.resolutionDedupeKey&&this.e1ContentKeyIndex.set(`${e}::${u.resolutionDedupeKey}`,u.record.promptId)}this.permissionRequestOccurrencesByCompletionKey=new Map(i.permissionOccurrences.map(([l,u])=>[l,u.map(p=>({...p}))])),this.e1NeedsReRaise=new Set(i.needsReRaisePromptIds);for(let l of i.waitingPermissionRequests??[])this.waitingPermissionRequests.set(l.occurrenceKey,{...l,ownerState:s,context:this.buildApprovalPromptContextFromHookPayload(l.payload)});this.pendingInteractivePrompt=i.pendingInteractivePrompt?{...i.pendingInteractivePrompt,ownerSessionId:e}:null;let r=this.pendingInteractivePrompt,n=r?.completionKey?this.permissionRequestOccurrencesByCompletionKey.get(r.completionKey):void 0;this.recoveryPermissionReplay=r?.source==="permission_hook"&&r.completionKey&&r.dedupeKey&&this.isPermissionRequestOccurrenceKey(r.dedupeKey)&&n?.some(l=>l.occurrenceKey===r.dedupeKey)?{ownerSessionId:e,completionKey:r.completionKey,occurrenceKey:r.dedupeKey}:null,this.queuedInteractivePrompts=i.queuedInteractivePrompts.map(l=>({prompt:{...l.prompt,ownerSessionId:e},content:l.content,metadata:{...l.metadata},ownerState:s}));let o=Date.now()-tt;for(let[l,u]of i.resolvedApprovalDedupeKeys){if(u<=o)continue;let p=`${i.backendSessionId}::`,h=l.startsWith(p)?`${e}::${l.slice(p.length)}`:l;this.resolvedApprovalDedupeKeys.set(h,u)}if(i.historicalQueuedQuestionPromptIds)for(let l of i.historicalQueuedQuestionPromptIds)this.recordHistoricalQueuedQuestionId(l);return i.backendSessionId!==e&&await this.drainRetirementOrphans(e),await this.drainPendingE1Resolutions(),await this.drainPendingE1ReRaises(),(this.e1PromptRaises.size>0||this.e1PendingResolutions.size>0)&&this.startE1TtlRefresh(),this.e1DurableState.removeHandoff(t),d.info("E1: adopted daemon handoff state",{fromSessionId:i.backendSessionId,replacementSessionId:e,openPrompts:i.openRaises.length,pendingResolutions:i.pendingResolutions.length,completionQueues:i.permissionOccurrences.length}),!0}parkRetirementOrphans(e){for(let t of this.snapshotOpenE1(e))this.e1RetirementOrphans.set(t.record.promptId,t)}async drainRetirementOrphans(e){if(this.e1RetirementOrphans.size===0){this.e1PendingResolutions.size>0&&!this.e1TtlRefreshTimer&&this.startE1TtlRefresh();return}d.info("E1 (\xA76a-4): re-homing parked retirement-orphan prompts onto replacement session",{replacementSessionId:e,count:this.e1RetirementOrphans.size});for(let[t,i]of[...this.e1RetirementOrphans]){let r=this.e1PromptRaises.get(t)??{record:{...i.record},...i.contentPlain!==void 0&&{contentPlain:i.contentPlain},...i.metadataPlain!==void 0&&{metadataPlain:i.metadataPlain},...i.resolutionDedupeKey!==void 0&&{resolutionDedupeKey:i.resolutionDedupeKey},...i.resolutionCompletionKey!==void 0&&{resolutionCompletionKey:i.resolutionCompletionKey},...i.resolutionCallId!==void 0&&{resolutionCallId:i.resolutionCallId}};for(let[o,l]of this.e1ContentKeyIndex.entries())l===t&&this.e1ContentKeyIndex.delete(o);r.record.sessionId=e,this.e1PromptRaises.set(t,r),r.resolutionDedupeKey&&this.e1ContentKeyIndex.set(`${e}::${r.resolutionDedupeKey}`,t);let n=await this.reRaiseOneE1(e,r,{untilAck:!0});if(n!=="RERAISED"&&n!=="OMITTED"){if(!this.e1RetirementOrphans.has(t))continue;break}this.e1RetirementOrphans.delete(t)}this.e1TtlRefreshTimer||this.startE1TtlRefresh()}isReRaiseTargetCurrent(e){return!this.isStopping&&this.sessionState!==null&&this.sessionState.sessionId===e}async reRaiseOneE1(e,t,i){let s=t.record;if(!(0,f.canRecoverPromptRaise)(t,this.e1RaiseInFlight.has(s.promptId)))return"RETRY";let r=s.mobileActionable&&t.contentPlain!==void 0,n=i?.untilAck??!1,o=4,l=4e3;for(let u=1;n||u<=o;u++){if(!(0,f.isOpenPromptRaise)(t,this.e1PromptRaises.get(s.promptId)))return"CLOSED";if(n&&!this.isReRaiseTargetCurrent(e))return this.e1NeedsReRaise.add(s.promptId),d.warn("E1: retirement re-raise aborted (stopping/superseded) \u2014 parked",{sessionId:e,promptId:s.promptId}),"RETRY";try{let p;return r?p=await this.publishE1Prompt(e,s,f.EventType.INTERACTIVE_PROMPT,t.contentPlain,t.metadataPlain??{},i?.reRaiseToken):(s.mobileActionable=!1,p=await this.emitSuppressedPromptCarrier(e,s,i?.reRaiseToken)),p==="RETRY"||p==="CLOSED"||(this.e1NeedsReRaise.delete(s.promptId),d.info("E1: prompt publication settled",{sessionId:e,promptId:s.promptId,actionable:r,disposition:p})),p}catch(p){if(!n&&u===o)return this.e1NeedsReRaise.add(s.promptId),d.error("E1: re-raise unacked after backoff \u2014 parked for retry-until-ack",{sessionId:e,promptId:s.promptId,error:p instanceof Error?p.message:String(p)}),"RETRY";if(n){let h=Date.now()+Math.min(250*2**(u-1),l);for(;Date.now()<h&&this.isReRaiseTargetCurrent(e);)await new Promise(c=>setTimeout(c,Math.min(50,h-Date.now())))}else await new Promise(h=>setTimeout(h,250*u))}}return"RETRY"}async drainPendingE1ReRaises(){if(this.e1NeedsReRaise.size!==0)for(let e of[...this.e1NeedsReRaise]){let t=this.e1PromptRaises.get(e);if(!t){this.e1NeedsReRaise.delete(e);continue}!this.sessionState||t.record.sessionId!==this.sessionState.sessionId||await this.reRaiseOneE1(t.record.sessionId,t)}}beginE1Resolution(e,t){if(this.e1PendingResolutions.has(e))return!0;let i=this.e1PromptRaises.get(e);if(!i||i.record.sessionId!==t)return!1;this.e1PromptRaises.delete(e),this.e1NeedsReRaise.delete(e),this.e1RetirementOrphans.delete(e);for(let[s,r]of this.e1ContentKeyIndex.entries())r===e&&this.e1ContentKeyIndex.delete(s);return this.e1PendingResolutions.set(e,{record:{...i.record},resolutionAt:new Date().toISOString(),attempts:0}),this.e1TtlRefreshTimer||this.startE1TtlRefresh(),!0}async emitE1Resolution(e){let t=this.e1ResolutionInFlight.get(e);if(t)return t;if(!this.e1PendingResolutions.has(e))return;let i=(async()=>{let s=this.e1PendingResolutions.get(e);if(s){try{this.e1DurableState.writeResolution(s)}catch(r){d.error("E1: failed to persist exact-clear outbox record",{promptId:e,error:r instanceof Error?r.message:String(r)})}try{let r=this.e1RaiseInFlight.get(e);if(r&&await r,s=this.e1PendingResolutions.get(e),!s)return;if(!await this.appSyncClient.resolveCompanionPrompt({sessionId:s.record.sessionId,promptId:s.record.promptId,ownerToken:s.record.ownerToken,resolutionAt:s.resolutionAt}))throw new Error("E1_PLUGIN_RESOLUTION_NOT_ACKNOWLEDGED: exact prompt id was not returned");this.e1PendingResolutions.delete(e);try{this.e1DurableState.removeResolution(e)}catch(o){d.warn("E1: exact-clear ACKed but outbox cleanup failed",{promptId:e,error:o instanceof Error?o.message:String(o)})}d.info("E1: plugin approval resolution acknowledged",{sessionId:s.record.sessionId,promptId:e})}catch(r){let n=this.e1PendingResolutions.get(e);d.warn("E1: plugin approval resolution unacknowledged; parked for retry",{sessionId:n?.record.sessionId,promptId:e,error:r instanceof Error?r.message:String(r)})}}})();this.e1ResolutionInFlight.set(e,i);try{await i}finally{this.e1ResolutionInFlight.get(e)===i&&this.e1ResolutionInFlight.delete(e)}}trackE1Raise(e,t){let i=t.then(()=>{},()=>{});return this.e1RaiseInFlight.set(e,i),i.then(()=>{this.e1RaiseInFlight.get(e)===i&&this.e1RaiseInFlight.delete(e)}),t}async drainPendingE1Resolutions(){for(let[e,t]of[...this.e1PendingResolutions.entries()])t.attempts+=1,await this.emitE1Resolution(e)}async restorePendingE1ResolutionsFromOutbox(){let{records:e,rejected:t}=this.e1DurableState.readResolutions();for(let i of t)d.error("E1: rejected unsafe or invalid resolution outbox record",i);for(let i of e){let s=this.e1PendingResolutions.get(i.record.promptId);(!s||i.attempts>s.attempts)&&this.e1PendingResolutions.set(i.record.promptId,{record:{...i.record},resolutionAt:i.resolutionAt,attempts:i.attempts})}e.length>0&&(d.info("E1: recovered pending exact-clear outbox records",{count:e.length}),await this.drainPendingE1Resolutions(),this.e1PendingResolutions.size>0&&!this.e1TtlRefreshTimer&&this.startE1TtlRefresh())}async drainPendingE1ResolutionsForLifecycleEnd(e={}){let t=e.maxWaitMs??4e3,i=e.retryDelayMs??250,s=Date.now()+Math.max(0,t),r=0;do{if(await this.drainPendingE1Resolutions(),this.e1PendingResolutions.size===0)return;if(r+=1,Date.now()>=s)break;await new Promise(n=>setTimeout(n,Math.min(i*r,Math.max(0,s-Date.now()))))}while(Date.now()<s);for(let n of this.e1PendingResolutions.values())this.e1DurableState.writeResolution(n);d.warn("E1: graceful lifecycle ended with durable exact-clear work pending",{count:this.e1PendingResolutions.size})}beginE1PromptResolutions(e,t){let i=[];for(let s of new Set(e))this.beginE1Resolution(s,t)&&i.push(s);return i}launchE1Resolutions(e){Promise.all([...e].map(t=>this.emitE1Resolution(t)))}async exactClearOpenE1ForLifecycleEnd(e){let t=[...this.e1PromptRaises.values()].filter(s=>s.record.sessionId===e).map(s=>s.record.promptId),i=this.beginE1PromptResolutions(t,e);await Promise.all(i.map(s=>this.emitE1Resolution(s)))}async refreshE1Ttls(){await this.drainPendingE1Resolutions(),await this.drainPendingE1ReRaises();let e=this.sessionState?.sessionId;if(!e)return;let t=[...this.e1PromptRaises.values()].filter(i=>i.record.sessionId===e&&(0,f.canRecoverPromptRaise)(i,this.e1RaiseInFlight.has(i.record.promptId))).map(i=>i.record.promptId);if(t.length!==0)try{await this.appSyncClient.refreshSessionOpenPromptTtl({sessionId:e,promptIds:t},async(i,s)=>{let r=this.e1PromptRaises.get(i);return!r||r.record.sessionId!==e||this.sessionState?.sessionId!==e?"CLOSED":this.reRaiseOneE1(e,r,{reRaiseToken:s})})}catch(i){d.warn("E1: TTL-refresh tick failed (non-fatal, retries next tick)",{error:i instanceof Error?i.message:String(i)})}}startE1TtlRefresh(){this.e1TtlRefreshTimer&&clearInterval(this.e1TtlRefreshTimer),this.e1TtlRefreshTimer=setInterval(()=>{this.refreshE1Ttls()},a.E1_TTL_REFRESH_MS)}stopE1TtlRefresh(){this.e1TtlRefreshTimer&&(clearInterval(this.e1TtlRefreshTimer),this.e1TtlRefreshTimer=null)}isExpectedSessionStateCurrent(e){return!this.isStopping&&this.sessionState===e&&!this.terminalInputBlockedStates.has(e)}sendSessionPinnedInput(e,t,i){if(!this.isExpectedSessionStateCurrent(e)||this.terminalInputBlockedStates.has(e))return Promise.resolve(!1);let s=this.terminalInputChain.then(async()=>!this.isExpectedSessionStateCurrent(e)||this.terminalInputBlockedStates.has(e)||!await this.verifyNoActiveCodexChooser(e.sessionId)||i&&(await i(),!this.isExpectedSessionStateCurrent(e)||!await this.verifyNoActiveCodexChooser(e.sessionId)||!this.isExpectedSessionStateCurrent(e))||!await this.promptResponder.sendLiteral(e.sessionId,t)||(await new Promise(r=>setTimeout(r,500)),!this.isExpectedSessionStateCurrent(e))||!await this.verifyNoActiveCodexChooser(e.sessionId)?!1:this.promptResponder.sendKey(e.sessionId,"Enter"));return this.terminalInputChain=s.then(()=>{},()=>{}),s}async verifyNoActiveCodexChooser(e){try{let t=await this.tmuxPaneObserver.captureSnapshot();if(this.tmuxPaneObserver.extractActivePromptBlock(t))return!1;let s=ne(t).split(`
|
|
34
35
|
`).slice(-25).join(`
|
|
@@ -1041,7 +1041,9 @@ export declare class AppSyncClient {
|
|
|
1041
1041
|
/**
|
|
1042
1042
|
* Update a session
|
|
1043
1043
|
*/
|
|
1044
|
-
updateSession(input: UpdateSessionInput
|
|
1044
|
+
updateSession(input: UpdateSessionInput, options?: {
|
|
1045
|
+
expectedUserId?: string;
|
|
1046
|
+
}): Promise<Session>;
|
|
1045
1047
|
private doUpdateSession;
|
|
1046
1048
|
/**
|
|
1047
1049
|
* Get a session
|
|
@@ -9,7 +9,7 @@ export { KeychainVendorKeyStore } from "./vendor-key-store";
|
|
|
9
9
|
export { BrokerTokenMinter, type RotationHandle } from "./broker-token";
|
|
10
10
|
export { CHATGPT_UPSTREAM_CONFIG, chatGptUpstreamUrl, CHATGPT_TOKEN_ENDPOINT, CHATGPT_OAUTH_CLIENT_ID, CHATGPT_REFRESH_CONTENT_TYPE, } from "./chatgpt-config";
|
|
11
11
|
export { FetchRefreshTransport, refreshOAuthToken, buildRefreshBody, type RefreshTransport, type RefreshOutcome, } from "./oauth-refresh";
|
|
12
|
-
export { OAuthAccountLock, createOAuthAccountLock, defaultOAuthLockDir, type OAuthAccountLockOptions, type LockHandle, type LockOwner, } from "./oauth-account-lock";
|
|
12
|
+
export { OAuthAccountLock, LocalLockBusyError, type LocalLockRole, createOAuthAccountLock, defaultOAuthLockDir, type OAuthAccountLockOptions, type LockHandle, type LockOwner, } from "./oauth-account-lock";
|
|
13
13
|
export { buildCanonicalRequest, selfCredentialGuard, requestSha256, CanonicalRejectError, } from "./canonical";
|
|
14
14
|
export type { CanonicalInput, CanonicalRequest } from "./canonical";
|
|
15
15
|
export { scrubRequestBody } from "./scrubber";
|
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
/** Liveness of a recorded lock owner (only `dead` is ever reclaimed). */
|
|
2
2
|
export type OwnerLiveness = "alive" | "dead" | "unknown";
|
|
3
|
+
export type LocalLockRole = "oauth-account" | "sync-journal" | "sync-journal-store" | "tool-sync-recovery";
|
|
4
|
+
/** Contention, not proof of corrupt persisted work. Never authorizes reclaim. */
|
|
5
|
+
export declare class LocalLockBusyError extends Error {
|
|
6
|
+
readonly diagnostic: {
|
|
7
|
+
role: LocalLockRole;
|
|
8
|
+
lockId: string;
|
|
9
|
+
holderPid: number | null;
|
|
10
|
+
holderState: OwnerLiveness | "absent" | "unreadable";
|
|
11
|
+
heldMs: number | null;
|
|
12
|
+
waitMs: number;
|
|
13
|
+
};
|
|
14
|
+
readonly code = "LOCAL_LOCK_BUSY";
|
|
15
|
+
constructor(diagnostic: {
|
|
16
|
+
role: LocalLockRole;
|
|
17
|
+
lockId: string;
|
|
18
|
+
holderPid: number | null;
|
|
19
|
+
holderState: OwnerLiveness | "absent" | "unreadable";
|
|
20
|
+
heldMs: number | null;
|
|
21
|
+
waitMs: number;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
3
24
|
/** The `owner.json` record written once per acquisition. */
|
|
4
25
|
export interface LockOwner {
|
|
5
26
|
pid: number;
|
|
@@ -12,6 +33,7 @@ export interface LockOwner {
|
|
|
12
33
|
export interface OAuthAccountLockOptions {
|
|
13
34
|
/** The canonical lockdir path (keyed to the OAuth account). */
|
|
14
35
|
lockDir: string;
|
|
36
|
+
role?: LocalLockRole;
|
|
15
37
|
/** GC callers must retain their recovery index unless unlink/rmdir succeeds.
|
|
16
38
|
* Default callers keep the existing best-effort release behavior. */
|
|
17
39
|
requireRemovalOnRelease?: boolean;
|
|
@@ -66,6 +88,7 @@ export interface LockHandle {
|
|
|
66
88
|
/** The portable cross-process OAuth-account lock (§5 / AMEND-1). */
|
|
67
89
|
export declare class OAuthAccountLock {
|
|
68
90
|
private readonly lockDir;
|
|
91
|
+
private readonly role;
|
|
69
92
|
private readonly requireRemovalOnRelease;
|
|
70
93
|
private readonly ownerFile;
|
|
71
94
|
private readonly reclaimGuardDir;
|
|
@@ -90,6 +113,7 @@ export declare class OAuthAccountLock {
|
|
|
90
113
|
* ZERO side effects on the persisted bundle on any fail-closed path.
|
|
91
114
|
*/
|
|
92
115
|
acquire(): Promise<LockHandle>;
|
|
116
|
+
private contentionError;
|
|
93
117
|
/** Whether the EXISTING lockdir holder is reclaimable (dead), an ownerless strand
|
|
94
118
|
* (F6), or must be waited on. */
|
|
95
119
|
private classifyExistingHolder;
|
|
@@ -59,6 +59,7 @@ export * as AuditKeys from './audit-keys';
|
|
|
59
59
|
export * as Substrate from './substrate';
|
|
60
60
|
export { buildSeatbeltProfile, SandboxExecSubstrate } from './substrate';
|
|
61
61
|
export * as CredentialBroker from './credential-broker';
|
|
62
|
+
export { LocalLockBusyError } from './credential-broker/oauth-account-lock';
|
|
62
63
|
export * as SubstrateLaunch from './substrate-launch';
|
|
63
64
|
export * from './types';
|
|
64
65
|
export * as Planner from './planner';
|