@leviyuan/lodestar 0.14.3 → 0.14.4
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/lodestar.js +1 -1
- package/package.json +1 -1
package/dist/lodestar.js
CHANGED
|
@@ -369,7 +369,7 @@ ${z}`,card:sY({slug:"wt",branch:"work/*",status:Q,body:z,template:"red"})}}}asyn
|
|
|
369
369
|
`);return XZ(x,!0,K,"success")}catch(z){let Z=`❌ 解散 ${Q} 失败: ${$1(z)}`;return XZ(x,!1,Z,"error")}}var Sm=M0(()=>{zm();L6();l1();J1();Om()});import{closeSync as TD0,openSync as ID0,readSync as cD0,readdirSync as qD0,statSync as ED0}from"node:fs";import{join as AD0}from"node:path";function o9(x){return f7(x.sessionName)??x.worktreeProjectName()??x.sessionName}function jm(x,Y){return Y>=1?x[Y-1]?.uuid:void 0}function kD0(x,Y,Q){let J;try{J=OL(x)}catch{return[]}let X;try{X=qD0(J)}catch{return[]}let z=Date.now()-Y,Z=[];for(let H of X){if(!H.endsWith(".jsonl"))continue;let W=AD0(J,H),$;try{$=ED0(W).mtimeMs}catch{continue}Z.push({sessionId:H.slice(0,-6),preview:PD0(W),ts:$,within:$>=z})}Z.sort((H,W)=>W.ts-H.ts);let G=Z.filter((H)=>H.within).length,K=Math.max(Q,G);return Z.slice(0,K).map(({sessionId:H,preview:W,ts:$})=>({sessionId:H,preview:W,ts:$}))}function PD0(x){let Y="";try{let J=ID0(x,"r"),X=Buffer.alloc(65536),z=cD0(J,X,0,65536,0);TD0(J),Y=X.subarray(0,z).toString("utf8")}catch{return""}let Q="";for(let J of Y.split(`
|
|
370
370
|
`)){let X=J.trim();if(!X)continue;let z;try{z=JSON.parse(X)}catch{continue}if(z.type==="queue-operation"&&z.operation==="enqueue"&&typeof z.content==="string"){let Z=z.content.trim();if(Z)return Z.slice(0,80)}if(!Q&&z.type==="user"&&z.message){let Z=gD0(z.message);if(Z)Q=Z}}return Q.slice(0,80)}function gD0(x){let Y=x?.content;if(typeof Y==="string")return Y;if(Array.isArray(Y)){for(let Q of Y)if(Q?.type==="text"&&typeof Q.text==="string")return Q.text}return""}async function Tm(x){let Q=AY(x.sessionName).map((z,Z)=>({idx:Z,preview:z.preview,ts:z.ts})).reverse(),J=oz({projectName:o9(x),mode:"fork",entries:Q});if(!await E1(x.chatId,J))await R1(x.chatId,"❌ fk 列表发送失败")}async function Im(x){let Q=AY(x.sessionName).map((z,Z)=>({idx:Z,preview:z.preview,ts:z.ts})).reverse(),J=oz({projectName:o9(x),mode:"back",entries:Q});if(!await E1(x.chatId,J))await R1(x.chatId,"❌ bk 列表发送失败")}async function cm(x){let Y=kD0(x.workDir,bD0,10),Q=VN({projectName:o9(x),entries:Y});if(!await E1(x.chatId,Q))await R1(x.chatId,"❌ rs 列表发送失败")}async function qm(x,Y){if(!Y){await V0(x.chatId,"❌ 找不到发起人,无法建临时群。");return}if(!x.opts.onCreateTempSession){await V0(x.chatId,"❌ 临时群能力未就绪(daemon 未注入回调)。");return}if(x.selectedProvider!=="claude"){await V0(x.chatId,"❌ 临时会话/fork/back 暂只支持 Claude 后端(Codex 无 resumeSessionAt 能力)。群里发 model 切到 Claude 再试。");return}let Q=IL(o9(x));await V0(x.chatId,`\uD83D\uDE80 开临时会话 ${Q}(同目录,自动启动)…`);let J=await x.opts.onCreateTempSession({chatName:Q,userOpenId:Y});if(!J.ok)await V0(x.chatId,`❌ 建临时会话失败: ${J.error??"未知"}`)}async function Em(x){if(!f7(x.sessionName)){await V0(x.chatId,"❌ bye 只能在临时会话群(*开头的群)里用。");return}if(!x.opts.onDisbandTempSession){await V0(x.chatId,"❌ 解散能力未就绪(daemon 未注入回调)。");return}if(x.isRunning()){await V0(x.chatId,"⏳ 当前会话还在跑,先 stop/kill 再 bye。");return}await V0(x.chatId,`\uD83D\uDC4B 解散临时会话 ${x.sessionName}…`);let Y=await x.opts.onDisbandTempSession(x.sessionName);if(!Y.ok)await V0(x.chatId,`❌ 解散失败: ${Y.error??"未知"}`)}async function Am(x,Y,Q){if(x.selectedProvider!=="claude"){await V0(x.chatId,"❌ fork 暂只支持 Claude 后端(Codex 无 resumeSessionAt 能力)。群里发 model 切到 Claude。");return}if(!Q){await V0(x.chatId,"❌ 找不到发起人,无法建临时群。");return}if(!x.opts.onCreateTempSession){await V0(x.chatId,"❌ 临时群能力未就绪。");return}let J=AY(x.sessionName);if(Y<0||Y>=J.length){await V0(x.chatId,"❌ 无效的分叉点。");return}let X=Y===0,z=X?void 0:x.lastSessionId??void 0,Z=X?void 0:jm(J,Y);if(!X&&!z){await V0(x.chatId,"❌ 当前会话还没有 session id,无法分叉。");return}let G=IL(o9(x));A(`session-temp: fork ${x.sessionName}@${Y} → ${G} (at=${Z?.slice(0,8)??"origin"})`),await V0(x.chatId,`\uD83D\uDD31 分叉到 ${G}…`);let K=await x.opts.onCreateTempSession({chatName:G,userOpenId:Q,resumeSessionId:z,resumeSessionAt:Z});if(!K?.ok)await V0(x.chatId,`❌ 分叉失败: ${K?.error??"未知"}`)}async function bm(x,Y){if(x.selectedProvider!=="claude"){await V0(x.chatId,"❌ back 暂只支持 Claude 后端(Codex 无 resumeSessionAt 能力)。群里发 model 切到 Claude。");return}let Q=AY(x.sessionName);if(Y<0||Y>=Q.length){await V0(x.chatId,"❌ 无效的回滚点。");return}let J=Y===0,X=J?void 0:x.lastSessionId??void 0,z=J?void 0:jm(Q,Y),Z=Q.slice(Y).flatMap((K)=>K.writes);if(await E1(x.chatId,HN({projectName:o9(x),entries:Z})).catch(()=>{}),A(`session-temp: back ${x.sessionName}@${Y} (at=${z?.slice(0,8)??"origin"}, writes=${Z.length})`),await x.rollbackTo(X,z))Zf(x.sessionName,Y);else await V0(x.chatId,"❌ 回滚失败,锚点未改动,请检查日志后重试。")}async function km(x,Y){if(x.selectedProvider!=="claude"){await V0(x.chatId,"❌ 历史会话恢复只支持 Claude 后端(transcript 是 Claude 的)。群里发 model 切到 Claude 再 rs。");return}if(await V0(x.chatId,`\uD83D\uDD01 在本群恢复会话 ${Y.slice(0,8)}…`),A(`session-temp: resume ${x.sessionName} ← claude session ${Y.slice(0,8)}`),await x.rollbackTo(Y,void 0))u7(x.sessionName);else await V0(x.chatId,"❌ 恢复失败,请检查日志。")}var bD0=86400000;var Pm=M0(()=>{l1();L6();J1();vL()});import{existsSync as uD0}from"node:fs";import{isAbsolute as fD0,join as yD0}from"node:path";function hD0(x){return x.itemId||x.turnId||"__latest__"}function mD0(x){let Y=null;for(let Q of x.contextCompactionPending.keys())Y=Q;return Y}function _D0(x,Y){if(!x)return Y;return{...x,...Y,phase:"end"}}function a7(){return a0.runtime?.live_elapsed??"bucket"}function fm(x,Y){return`${x} (${F3(Date.now()-Y,a7()).label})`}var lD0="Thinking...",nD0="Writing...",dD0="Working...",gm=1e4,wm=120000,iD0=50,tN=5,um=250,x5;var ym=M0(()=>{d5();QG();s5();E8();J4();Lc();vL();l7();L6();l1();J1();tL();XW();WW();cN();py();Gh();Nh();fN();Ch();yh();mh();rh();Ym();Sm();Pm();x5=class x5{sessionName;chatId;opts;static all=new Set;proc=null;currentTurn=null;backgroundTasks=[];pendingBgTasks=[];backgroundCard=null;backgroundRefreshTimer=null;backgroundRefreshTick=null;openingBackground=!1;backgroundDetailAdded=new Set;lastMainTaskToolUseId=null;pendingRebuildBackgroundCard=!1;bgResumePending=!1;orphanAssistantSegments=[];orphanAssistantCurrent="";bgResumeCardless=!1;sawResultWhileOpening=!1;pendingPermissions=new Map;pendingAsks=new Map;currentGoal=null;status="stopped";pendingUserMessageCount=0;pendingMidTurnMsgs=[];pendingTurnInputs=[];multiMsgBuffer=null;multiMsgReactions=new Map;lastUserOpenId="";pendingReactionIds=new Map;currentBatchReactionIds=new Map;initCount=0;openingTurn=!1;turnCounter=0;userInterrupted=!1;lastSessionId=null;selectedProvider="claude";selectedModel=null;selectedEffort=null;selectedTokenSourceId=null;modelPanels=new Map;modelCustomPrompt=null;startedAt=0;cumStats={tokens:0,costUsd:0,turns:0};lastTurnDelta=null;currentTurnUsageBaseline=null;currentTurnUsageBaselineKnown=!1;lastTurnUsage=null;usageTotalsSeedUnknown=!1;manualContextCompactionPending=!1;runningAgy=null;startingAgy=!1;agyForwardPrompts=new Map;taskBoard=[];constructor(x,Y,Q={}){this.sessionName=x;this.chatId=Y;this.opts=Q;x5.all.add(this);let J=Xf(x);this.selectedProvider=J?.provider??"claude",this.selectedModel=J?.model??null,this.selectedEffort=J?.effort??null,this.selectedTokenSourceId=this.deriveTokenSourceId(J);let X=Q8(this.selectedTokenSourceId);if(X){if(this.selectedProvider=X.agent,X.id==="glm"&&this.selectedModel==="claude:glm")this.selectedModel=X.defaultModel,this.selectedEffort="max";if(X.id==="claude-native"&&this.selectedModel&&!X.models.some((z)=>z.model===this.selectedModel))this.selectedModel=X.defaultModel}if(this.selectedModel)A(`session "${x}": restored selected provider=${this.selectedProvider} model=${this.selectedModel} effort=${this.selectedEffort??"unset"}`);if(this.lastSessionId=jL(x,this.selectedProvider),this.lastSessionId)A(`session "${x}": restored ${this.selectedProvider} lastSessionId=${this.lastSessionId.slice(0,8)}…`)}peerSnapshot(){return{name:this.sessionName,status:this.status,uptimeMs:this.startedAt?Date.now()-this.startedAt:void 0}}get workDir(){let x=f7(this.sessionName)??this.sessionName,Y=SL(x)?.cwd;return Y&&Y.trim()?Y:yD0(w7,x)}isRunning(){return!!this.proc&&this.proc.isAlive()}deriveTokenSourceId(x){let Y=x?.tokenSourceId,Q=typeof Y==="string"?Q8(Y):void 0;if(Q?.enabled)return Q.id;let J=x?.provider??this.selectedProvider;return UJ(J==="codex"?"codex":"claude")[0]?.id??null}currentTokenSource(){return Q8(this.selectedTokenSourceId)}currentProvider(){return this.selectedProvider}hasRunningPeerSession(x){return[...x5.all].some((Y)=>Y.sessionName===x&&Y.isRunning())}modelForSpawn(){if(this.selectedProvider==="codex")return;return this.selectedModel??void 0}effortForSpawn(){if(this.selectedProvider==="codex"){let x=this.currentTokenSource();if(!x||!x.enabled)return;return Y6(this.selectedEffort)?this.selectedEffort:W2}return W2}claudeEffortForSpawn(){return this.selectedProvider==="claude"&&L3(this.selectedEffort)?this.selectedEffort:U3}currentModelLabel(){return(this.selectedModel??this.currentTokenSource()?.defaultModel??this.proc?.lastModel??null)?.replace(/^claude:/i,"").replace(/\[1m\]$/i,"")??null}currentEffortLabel(){return this.selectedEffort??this.proc?.lastEffort??(this.selectedProvider==="claude"?U3:W2)}runtimeModelSelection(){let x=this.proc?.isAlive()?this.proc:null,Y=x?.provider??this.selectedProvider,Q=!x||x.provider===this.selectedProvider,J=(x?.lastModel??(Q?this.currentModelLabel():null))?.replace(/^claude:/i,"").replace(/\[1m\]$/i,"")??null,X=x?.lastEffort??(Q?this.currentEffortLabel():Y==="claude"?U3:W2);return{provider:Y,model:J,effort:X}}modelEffortLabel(x=this.currentTurn??this.runtimeModelSelection()){let Y=x.provider==="claude"?x.model?.replace(/^claude:/i,"").replace(/\[1m\]$/i,""):x.model,Q=Y?`${Y}/${x.effort}`:x.effort;return x.provider==="claude"?`${b6(x.provider)} · ${Q}`:Q}withModel(x,Y){let Q=this.modelEffortLabel(Y);return x.includes(Q)?x:`${x} · ${Q}`}replaceFooterContent(x,Y){return Q1(x,W0.footer,{tag:"markdown",element_id:W0.footer,content:Y.trim()||" "})}modelLine(x){return this.modelEffortLabel(x)}backendLabel(x=this.selectedProvider){return b6(x)}_forkSpawn=null;lastTurnUserPreview="";spawnAgent(x){let Y=this._forkSpawn,Q=Y?.resumeSessionId??x,J=Y?.resumeSessionAt,X=!!Y,z=this.currentTokenSource(),Z=z?.enabled?z:void 0,G=Z?(H)=>Z.spawnEnv(H):void 0,K=Z?Z.resolveSpawnModel(this.selectedModel??Z.defaultModel):this.modelForSpawn();if(this.selectedProvider==="claude")return Iu(),new BL({workDir:this.workDir,model:K,effort:this.claudeEffortForSpawn(),resumeSessionId:Q,resumeSessionAt:J,forkSession:X,appendSystemPrompt:this.spawnDeveloperInstructions(),profile:SL(f7(this.sessionName)??this.sessionName),...Z?.settingSources?{settingSources:Z.settingSources}:{},tokenSourceId:Z?.id??null,transformEnv:G});return new lH({workDir:this.workDir,model:K,effort:this.effortForSpawn(),resumeSessionId:Q,appendSystemPrompt:this.spawnDeveloperInstructions(),tokenSourceId:Z?.id??null,transformEnv:G})}async applyModelSelection(x,Y,Q,J){let X=this.selectedProvider;this.selectedProvider=x,this.selectedTokenSourceId=J??this.selectedTokenSourceId;let z=Q8(this.selectedTokenSourceId);if(z)this.selectedModel=Y||null,this.selectedEffort=Q??z.models.find((Z)=>Z.model===Y)?.defaultEffort??z.models[0]?.defaultEffort??null;else this.selectedModel=x==="codex"?null:Y,this.selectedEffort=x==="codex"?null:Q;if(this.lastSessionId=jL(this.sessionName,x),X!==x)u7(this.sessionName);Jf(this.sessionName,x,this.selectedModel,this.selectedEffort,this.selectedTokenSourceId),await this.stopIdleMismatchedProcess()}async stopIdleMismatchedProcess(){if(!this.proc?.isAlive())return;if(this.proc.provider===this.selectedProvider&&this.proc.tokenSourceId===this.selectedTokenSourceId)return;if(this.currentTurn||this.openingTurn||this.pendingUserMessageCount>0||this.pendingMidTurnMsgs.length>0)return;let x=this.proc;A(`session "${this.sessionName}": stop idle ${x.provider} process after switching to ${this.selectedProvider}`),this.proc=null,this.initCount=0,this.bgResumePending=!1,this.sawResultWhileOpening=!1,this.discardOrphanAssistant(),this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,this.usageTotalsSeedUnknown=!1,this.status="stopped",this.opts.onLifecycleChange?.(),await x.kill(1000)}async stopIdleCurrentProcess(x){if(!this.proc?.isAlive())return!1;if(this.currentTurn||this.openingTurn||this.pendingUserMessageCount>0||this.pendingMidTurnMsgs.length>0)return!1;let Y=this.proc;return A(`session "${this.sessionName}": stop idle ${Y.provider} process: ${x}`),this.proc=null,this.initCount=0,this.bgResumePending=!1,this.sawResultWhileOpening=!1,this.discardOrphanAssistant(),this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,this.usageTotalsSeedUnknown=!1,this.status="stopped",this.opts.onLifecycleChange?.(),await Y.kill(1000),!0}startFooterTimer(x,Y,Q=(J)=>J){let J=Date.now(),X=Y,z=!1,Z=()=>{if(z)return;this.replaceFooterContent(x,Q(fm(X,J)))},G=null,K=()=>{if(z)return;let{nextDelayMs:H}=F3(Date.now()-J,a7());G=setTimeout(()=>{Z(),K()},Math.max(1,Math.ceil(H)))};return Z(),K(),{setStatus(H){X=H,Z()},stop(){if(z=!0,G)clearTimeout(G)},elapsedSec(){return((Date.now()-J)/1000).toFixed(1)}}}async openStatusCard(x,Y,Q="blue"){let J=Date.now(),X=eL({sessionName:this.sessionName,title:x,status:fm(Y,J),template:Q}),z=await E1(this.chatId,X);if(!z)return A(`session "${this.sessionName}": status card send failed title=${x}`),await R1(this.chatId,`❌ 创建状态卡片失败: ${x}`),null;let Z;try{Z=await H6(z)}catch(G){return A(`session "${this.sessionName}": status card id_convert failed title=${x}: ${G}`),await R1(this.chatId,`❌ 状态卡片初始化失败: ${x}`),null}return m7(Z,1),{cardId:Z,title:x,timer:this.startFooterTimer(Z,Y,(G)=>iY(x,G))}}setStatusCard(x,Y){x?.timer.setStatus(Y)}async closeStatusCard(x,Y){if(!x)return;x.timer.stop();let Q=x.timer.elapsedSec(),J=iY(x.title,`${Y} (${Q}s)`);await y4(x.cardId),await this.replaceFooterContent(x.cardId,J),S8(x.cardId),await g8(x.cardId,F6({durationSec:Q,suffix:Y})),await G6(x.cardId)}beginAgyForwardToCodex(x,Y=""){return Wh(this,x,Y)}runAgyCommand(x){return Kh(this,x)}stopAgyTask(x="\uD83D\uDED1 agy 已打断"){return Hh(this,x)}resetFreshConversationState(){this.turnCounter=0,u7(this.sessionName),this.currentGoal=null,this.cumStats={tokens:0,costUsd:0,turns:0},this.lastTurnDelta=null,this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,this.lastTurnUsage=null,this.usageTotalsSeedUnknown=!1}async start(x={}){let Y=x.announce??!0,Q=x.onStatus;if(this.isRunning()){if(this.proc?.provider===this.selectedProvider)return Q?.(this.withModel(`✅ ${this.backendLabel()} 已运行`)),!0;if(await this.stopIdleMismatchedProcess(),this.proc?.isAlive())return Q?.(`⚠️ 当前 ${this.backendLabel(this.proc.provider)} turn 尚未结束,模型切换将在后续新 turn 生效`),!0}if(this.selectedProvider==="codex")Q?.("\uD83D\uDD0E 检查 Codex 登录");else Q?.("\uD83D\uDD0E 检查 Claude Code");if(this.selectedProvider==="codex"&&!Lf()){if(this.status="stopped",this.opts.onLifecycleChange?.(),Q?.("❌ Codex 未登录 ChatGPT 账号"),Y)await V0(this.chatId,"❌ Codex 未登录 ChatGPT 账号。\n请在服务器上运行 `codex login` 后再试。");return!1}if(!uD0(this.workDir)){if(Q?.(`\uD83C\uDD95 创建项目目录 ~/${this.sessionName}`),Y)await V0(this.chatId,`\uD83C\uDD95 目录 ~/${this.sessionName} 不存在,正在创建…`);try{Uf(this.workDir)}catch(G){if(this.status="stopped",this.opts.onLifecycleChange?.(),Q?.(`❌ 创建项目失败: ${G}`),Y)await V0(this.chatId,`❌ 创建项目失败: ${G}`);return!1}}if(!x.freshConversationStateAlreadyReset)this.resetFreshConversationState();this.status="starting",Q?.(this.withModel(`\uD83D\uDE80 启动 ${this.backendLabel()}`));let J;try{J=this.spawnAgent()}catch(G){let K=`${this.backendLabel()} 启动失败: ${$1(G)}`;if(A(`session "${this.sessionName}": ${K}`),Q?.(`❌ ${K}`),Y)await V0(this.chatId,`❌ ${K}`);return this.proc=null,this.status="stopped",this.opts.onLifecycleChange?.(),!1}this.proc=J,this.wireProc(this.proc);let X=this.backendLabel(),z=this.selectedProvider==="claude"?this.waitForProcEarlyFailure(this.proc,um):this.waitForProcInit(this.proc,5000);Q?.(this.selectedProvider==="claude"?`⏳ 检查 ${X} 启动`:`⏳ 等待 ${X} init`),this.proc.sendInitialize();let Z=await z;if(Z.state==="error"||Z.state==="exit"){let G=Z.error?$1(Z.error):Z.state;if(A(`session "${this.sessionName}": ${this.selectedProvider} init failed: ${G}`),Q?.(`❌ ${X} 启动失败: ${G}`),Y)await V0(this.chatId,`❌ ${X} 启动失败: ${G}`);return await this.proc?.kill(1000).catch(()=>{}),this.proc=null,this.status="stopped",this.opts.onLifecycleChange?.(),!1}if(Z.state==="timeout")A(`session "${this.sessionName}": ${this.selectedProvider} init wait timeout (5s)`),Q?.(this.withModel(this.withWorktreeInstructionNotice(`⏳ ${X} 已启动,init 确认超时`)));if(Y){let G=this.modelLine();await V0(this.chatId,[this.withWorktreeInstructionNotice(`✅ Lodestar session "${this.sessionName}" 已就绪,发消息开始对话。`),G].filter(Boolean).join(`
|
|
371
371
|
`))}return this.status="idle",this.startedAt=Date.now(),this.opts.onLifecycleChange?.(),Q?.(this.withModel(this.withWorktreeInstructionNotice(`✅ ${this.backendLabel()} 已就绪`))),!0}async waitForProcInit(x,Y){return await new Promise((Q)=>{let J=!1,X=(H,W)=>{if(J)return;J=!0,clearTimeout(z),x.off("init",Z),x.off("error",G),x.off("exit",K),Q({state:H,error:W})},z=setTimeout(()=>X("timeout"),Y),Z=()=>X("init"),G=(H)=>X("error",H),K=(H)=>X("exit",H);x.once("init",Z),x.once("error",G),x.once("exit",K)})}async waitForProcEarlyFailure(x,Y){return await new Promise((Q)=>{let J=!1,X=(H,W)=>{if(J)return;J=!0,clearTimeout(z),x.off("init",Z),x.off("error",G),x.off("exit",K),Q({state:H,error:W})},z=setTimeout(()=>X("ready"),Y),Z=()=>X("init"),G=(H)=>X("error",H),K=(H)=>X("exit",H);x.once("init",Z),x.once("error",G),x.once("exit",K)})}async waitForProcResumeInit(x,Y){return await new Promise((Q)=>{let J=!1,X=(W,$)=>{if(J)return;J=!0,clearTimeout(z),clearTimeout(Z),x.off("init",G),x.off("error",K),x.off("exit",H),Q({state:W,error:$})},z=setTimeout(()=>{if(!J)Y()},gm),Z=setTimeout(()=>{X("timeout",Error(`resume init timed out after ${wm/1000}s`))},wm),G=()=>X("init"),K=(W)=>X("error",W),H=(W)=>X("exit",W);x.once("init",G),x.once("error",K),x.once("exit",H)})}releaseAllReactions(){for(let[x,Y]of[...this.pendingReactionIds.entries(),...this.currentBatchReactionIds.entries()])if(Y)f4(x,Y);this.pendingReactionIds=new Map,this.currentBatchReactionIds=new Map}clearStaleIdleQueueState(x){if(this.initCount<1||this.currentTurn||this.openingTurn||this.pendingUserMessageCount===0)return;A(`session "${this.sessionName}": clear stale pending queue before ${x} pendingCount=${this.pendingUserMessageCount} reactions=${this.pendingReactionIds.size}`),this.pendingUserMessageCount=0;for(let[Y,Q]of this.pendingReactionIds)if(Q)f4(Y,Q);this.pendingReactionIds=new Map}async stop(x="已终止",Y={}){let Q=Y.announce??!0,J=Y.onStatus,X=await this.stopAgyTask(`\uD83D\uDED1 ${x}`);if(!this.proc){if(this.status="stopped",this.opts.onLifecycleChange?.(),J?.(X?`✅ ${x}`:"⚪ session 当前未运行"),Q&&!X)await V0(this.chatId,`⚪ session "${this.sessionName}" 当前未运行`);return}J?.(`\uD83D\uDED1 停止 ${this.backendLabel(this.proc.provider)}`),A(`session "${this.sessionName}": stop (${x})`);let z=this.proc;if(this.proc=null,this.stopFooterStatus(this.currentTurn),this.currentTurn=null,this.clearMultiMsgBuffer("stop"),this.pendingUserMessageCount=0,this.pendingMidTurnMsgs=[],this.pendingTurnInputs=[],this.lastUserOpenId="",this.releaseAllReactions(),this.initCount=0,this.openingTurn=!1,this.bgResumePending=!1,this.sawResultWhileOpening=!1,this.discardOrphanAssistant(),this.pendingAsks.clear(),this.pendingPermissions.clear(),this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,this.usageTotalsSeedUnknown=!1,this.status="stopped",this.opts.onLifecycleChange?.(),await z.kill(),await this.resetBackgroundTasks(),J?.(`✅ ${x}`),Q)await V0(this.chatId,`\uD83D\uDD34 ${x} (session: ${this.sessionName})`)}async restart(x=!1,Y={}){let Q=Y.announce??!0,J=Y.onStatus,X=this.lastSessionId,z=X?X.slice(0,8):"",Z=null;if(!J&&Q&&x&&X){let H=this.proc?this.withModel(`\uD83D\uDD01 重启 ${this.backendLabel(this.proc.provider)}`):this.withModel(`\uD83D\uDD01 恢复上一会话 thread=${z}…`);if(Z=await this.openStatusCard("restart",H),Z)J=(W)=>this.setStatusCard(Z,W)}let G=Q&&!Z,K=async(H)=>{if(Z)await this.closeStatusCard(Z,H)};if(this.bgResumePending=!1,this.sawResultWhileOpening=!1,this.discardOrphanAssistant(),this.proc){J?.(`\uD83D\uDED1 停止当前 ${this.backendLabel(this.proc.provider)}`);let H=this.proc;this.proc=null,await H.kill()}if(this.stopFooterStatus(this.currentTurn),this.currentTurn=null,this.clearMultiMsgBuffer("restart"),this.pendingUserMessageCount=0,this.pendingMidTurnMsgs=[],this.pendingTurnInputs=[],this.lastUserOpenId="",this.releaseAllReactions(),this.initCount=0,this.openingTurn=!1,this.pendingAsks.clear(),this.pendingPermissions.clear(),this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,await this.resetBackgroundTasks(),x&&X){this.status="starting",this.usageTotalsSeedUnknown=!0,J?.(this.withModel(`\uD83D\uDD01 恢复上一会话 thread=${z}…`));let H;try{H=this.spawnAgent(X)}catch(O){let v=`❌ ${this.backendLabel()} 恢复失败: ${$1(O)}`;if(A(`session "${this.sessionName}": ${this.selectedProvider} resume failed before spawn: ${$1(O)}`),J?.(v),G)await V0(this.chatId,v);return this.proc=null,this.status="stopped",this.opts.onLifecycleChange?.(),await K(v),!1}this.proc=H,this.wireProc(this.proc);let W=this.backendLabel(),$=this.selectedProvider==="claude"?this.waitForProcEarlyFailure(this.proc,um):this.waitForProcResumeInit(this.proc,()=>{A(`session "${this.sessionName}": ${this.selectedProvider} resume init still pending after ${gm/1000}s`),J?.(this.withModel(`⏳ 仍在等待 ${W} init 确认 thread=${z}…`))});J?.(this.selectedProvider==="claude"?`⏳ 检查 ${W} 恢复启动`:`⏳ 等待 ${W} init 确认`),this.proc.sendInitialize();let N=await $;if(N.state==="error"||N.state==="exit"||N.state==="timeout"){let O=N.error?$1(N.error):N.state;A(`session "${this.sessionName}": ${this.selectedProvider} resume failed: ${O}`);let v=N.state==="timeout"?`❌ ${W} 恢复超时`:`❌ ${W} 恢复失败: ${O}`;if(J?.(v),G)await V0(this.chatId,v);return await this.proc?.kill(1000).catch(()=>{}),this.proc=null,this.status="stopped",this.opts.onLifecycleChange?.(),await K(v),!1}let D=this.withModel(this.withWorktreeInstructionNotice(this.selectedProvider==="claude"&&N.state==="ready"?`✅ 已准备恢复上一会话 thread=${z}…`:`✅ 已恢复上一会话 thread=${z}…`));if(J?.(D),G)await V0(this.chatId,D);return this.status="idle",this.startedAt=Date.now(),this.opts.onLifecycleChange?.(),await K(D),!0}else{if(x){if(J?.("⚠️ 没有可恢复的上一会话,将以新会话启动"),G)await V0(this.chatId,"⚠️ 没有可恢复的上一会话,将以新会话启动")}return this.resetFreshConversationState(),await this.start({...Y,freshConversationStateAlreadyReset:!0})}}async startForked(x,Y,Q={}){this._forkSpawn={resumeSessionId:x,resumeSessionAt:Y};try{return await this.start(Q)}finally{this._forkSpawn=null}}async rollbackTo(x,Y,Q={}){let J=this.lastSessionId;if(x)this.lastSessionId=x,this._forkSpawn={resumeSessionId:x,resumeSessionAt:Y};else this._forkSpawn=null;try{let X=x?await this.restart(!0,Q):await this.restart(!1,Q);if(!X)this.lastSessionId=J;return X}finally{this._forkSpawn=null}}dispose(){x5.all.delete(this)}recordTurnAnchor(){let x=this.proc;if(!x)return;let Y=x.lastAssistantUuid;if(!Y)return;let Q=this.collectTurnWrites();Yf(this.sessionName,{uuid:Y,sid:x.sessionId??"",preview:this.lastTurnUserPreview.slice(0,80),ts:Date.now(),writes:Q}),this.lastTurnUserPreview=""}collectTurnWrites(){let x=this.currentTurn;if(!x)return[];let Y=[];for(let Q of x.toolByUseId.values()){if(!["Write","Edit","NotebookEdit","MultiEdit"].includes(Q.name))continue;let J=Q.input?.file_path??Q.input?.path??"?",X=GN(Q.name,Q.input);Y.push({tool:Q.name,path:J,body:X})}return Y}worktreeProjectName(){return e7(this)}worktreeProjectDir(){return s9(this)}spawnDeveloperInstructions(){return Bm(this)}worktreeInstructionLoadedNotice(){return oN(this)}withWorktreeInstructionNotice(x){return vm(this,x)}worktreeExtraInstruction(){return BW(this)}runWorktreeCommand(x,Y){return Mm(this,x,Y)}showWorktrees(){return rN(this)}showTasklistPanel(){return th(this)}onTasklistEnable(){return eh(this)}onTasklistDeletePrompt(x){return ah(this,x)}onTasklistDeleteConfirm(x){return xm(this,x)}runCompactCommand(){return hh(this)}showModelPanel(){return lh(this)}onModelSelect(x,Y="",Q="",J=null){return sh(this,x,Y,Q,J)}onModelEffortSelect(x,Y,Q="",J="",X=""){return oh(this,x,Y,Q,J,X)}onProviderSelect(x,Y=""){return nh(this,x,Y)}onModelPanelCancel(){return ph(this)}onModelCustomPrompt(x,Y,Q=""){return dh(this,x,Y,Q)}consumeModelCustomMessage(x,Y){return ih(this,x,Y)}onWorktreeDisband(x){return Cm(this,x)}showForkList(){return Tm(this)}showBackList(){return Im(this)}showResumeList(){return cm(this)}runBtwCommand(x){return qm(this,x)}runByeCommand(){return Em(this)}onForkSelect(x,Y=""){return Am(this,x,Y)}onBackSelect(x){return bm(this,x)}onResumeSelect(x){return km(this,x)}runCommand(x,Y=""){return fh(this,x,Y)}async buildConsoleOpts(x,Y){let Q=await zy(),J=this.runtimeModelSelection();return{sessionName:this.sessionName,status:this.status,provider:J.provider,model:J.model??void 0,effort:J.effort,worktreeInstructionNotice:this.worktreeInstructionLoadedNotice(),peers:[...x5.all].filter((X)=>X.isRunning()).map((X)=>({...X.peerSnapshot(),isCurrent:X===this})),usage:x,glmUsage:Y,sysinfo:Q}}async buildConsoleCard(x){return aL(await this.buildConsoleOpts(x))}async patchConsoleUsage(x){let Y=await this.buildConsoleOpts(void 0),Q=this.currentTokenSource(),J=Q?.agent===Y.provider&&Q.enabled?Q:UJ(Y.provider)[0];if(J)Y.unifiedUsage=await J.readUsage();else if(Y.provider==="claude")Y.glmUsage=await IN();else Y.usage=await JW();await Q1(x,W0.consoleUsage,pY(Y))}patchConsoleUsageLater(x){(async()=>{try{await this.patchConsoleUsage(x)}catch(Y){A(`session "${this.sessionName}": consoleUsage patch failed: ${Y}`)}finally{try{await G6(x)}catch(Y){A(`session "${this.sessionName}": console card dispose failed: ${Y}`)}}})()}async replaceStatusCardWithConsole(x,Y){x.timer.stop();let Q=x.timer.elapsedSec(),J=await this.buildConsoleOpts(void 0);await y4(x.cardId),await Q1(x.cardId,W0.footer,lz(J,W0.footer)),await j1(x.cardId,_z(J),{type:"insert_after",targetElementId:W0.footer}),await j1(x.cardId,nz(J.sysinfo),{type:"insert_after",targetElementId:W0.consoleProjects}),await j1(x.cardId,pY(J),{type:"insert_after",targetElementId:W0.consoleHost}),S8(x.cardId),await g8(x.cardId,F6({durationSec:Q,suffix:Y})),this.patchConsoleUsageLater(x.cardId)}async showConsole(){let x=await this.buildConsoleCard(void 0),Y=await E1(this.chatId,x);if(!Y)return;(async()=>{let Q="";try{Q=await H6(Y),await this.patchConsoleUsage(Q)}catch(J){A(`session "${this.sessionName}": consoleUsage patch failed: ${J}`)}finally{if(Q)try{await G6(Q)}catch(J){A(`session "${this.sessionName}": console card dispose failed: ${J}`)}}})()}interrupt(){if(!this.proc)return;A(`session "${this.sessionName}": interrupt`),this.proc.sendInterrupt()}async startColdUserTurn(x,Y,Q){this.openingTurn=!0,this.resetFreshConversationState(),this.pendingTurnInputs.push(x);try{await this.openTurnCard(Q,"user_message",{initialFooter:"Waiting...(0s)",startThinking:!1,directStart:!0});let J=this.currentTurn;if(!J)return;let X=this.startFooterTimer(J.cardId,`\uD83D\uDE80 启动 ${this.backendLabel()}`,(G)=>this.withModel(G)),z=`\uD83D\uDE80 启动 ${this.backendLabel()}`,Z=await this.start({announce:!1,freshConversationStateAlreadyReset:!0,onStatus:(G)=>{z=G,X.setStatus(G)}});if(X.stop(),await y4(J.cardId),!Z){this.pendingUserMessageCount=0,this.pendingMidTurnMsgs=[],this.pendingTurnInputs=[],this.lastUserOpenId="",this.releaseAllReactions(),await this.closeTurnCard(z.startsWith("❌")?z:"❌ 启动失败",{forcePush:!0});return}this.startThinkingFooter(J),this.proc.sendUserText(Y,[]),this.pendingUserMessageCount++,this.status="working"}finally{this.openingTurn=!1}}async onUserMessage(x,Y=[],Q="",J=""){if(this.clearStaleIdleQueueState("user_message"),this.startingAgy||this.runningAgy){await V0(this.chatId,"⏳ agy 任务正在执行;请等待完成,或发送 stop 打断后再继续。");return}if(this.proc?.isAlive()&&this.proc.provider!==this.selectedProvider&&!this.currentTurn&&!this.openingTurn&&this.pendingUserMessageCount===0&&this.pendingMidTurnMsgs.length===0)await this.stopIdleMismatchedProcess();let X=this.currentTurn!==null||this.openingTurn||this.pendingUserMessageCount>0||this.pendingMidTurnMsgs.length>0;this.lastUserOpenId=Q;let Z=(Y.length?Y.map((K)=>`[file: ${K}]`).join(" ")+`
|
|
372
|
-
`:"")+x,G=(K)=>{this.pendingReactionIds.set(K,""),(async()=>{let H=await L4(K,"OneSecond");if(!H)return;if(this.pendingReactionIds.has(K))this.pendingReactionIds.set(K,H);else if(this.currentBatchReactionIds.has(K))this.currentBatchReactionIds.set(K,H);else f4(K,H)})()};if(!this.isRunning()){if(this.openingTurn||this.currentTurn){if(this.pendingMidTurnMsgs.push({text:x,wireText:Z,userOpenId:Q,msgId:J}),J)G(J);return}await this.startColdUserTurn(x,Z,Q);return}if(this.currentTurn!==null){if(this.pendingMidTurnMsgs.push({text:x,wireText:Z,userOpenId:Q,msgId:J}),J)G(J);return}if(!this.openingTurn&&this.initCount>=1){this.openingTurn=!0;try{if(this.pendingTurnInputs.push(x),await this.openTurnCard(Q,"user_message"),!this.currentTurn)return;this.proc.sendUserText(Z,[]),this.pendingUserMessageCount++,this.status="working"}finally{this.openingTurn=!1}return}if(this.openingTurn||this.pendingUserMessageCount>0){if(this.pendingMidTurnMsgs.push({text:x,wireText:Z,userOpenId:Q,msgId:J}),J)G(J);return}if(this.pendingTurnInputs.push(x),this.proc.sendUserText(Z,[]),this.pendingUserMessageCount++,X&&J)G(J)}hasPendingAsk(){return Dh(this)}onMultiMessageInbound(x,Y,Q,J){return iy(this,x,Y,Q,J)}clearMultiMsgBuffer(x){EN(this,x)}onAskMessageAnswer(x,Y,Q){return Oh(this,x,Y,Q)}onAskAnswer(x,Y,Q,J){return Bh(this,x,Y,Q,J)}onAskCustomAnswer(x,Y,Q,J){return wN(this,x,Y,Q,J)}onPermissionDecision(x,Y,Q){return Mh(this,x,Y,Q)}persistResumableSessionId(){let x=this.proc,Y=x?.sessionId;if(!x||!Y)return;if(au(this.sessionName,Y,x.provider),x.provider!==this.selectedProvider)return;if(Y===this.lastSessionId)return;this.lastSessionId=Y}bgStore(){return{active:this.backgroundTasks,pending:this.pendingBgTasks}}applyBgStore(x){this.backgroundTasks=x.active,this.pendingBgTasks=x.pending}onMainThreadAdvance(){if(this.pendingBgTasks.length===0)return;this.applyBgStore(rH(this.bgStore())),this.onBackgroundTaskChanged()}bgTaskOwns(x){return this.backgroundTasks.some((Y)=>Y.toolUseId===x)||this.pendingBgTasks.some((Y)=>Y.toolUseId===x)}onBackgroundTaskChanged(){if(!$7(this.backgroundTasks)){if(this.backgroundCard)this.settleBackgroundCard();return}if(!this.backgroundCard&&!this.openingBackground){this.openingBackground=!0,this.openBackgroundCard().finally(()=>{this.openingBackground=!1});return}this.scheduleBackgroundRefresh()}async openBackgroundCard(){if(this.backgroundCard)return;let x=YG(this.backgroundTasks,Date.now(),a7()),Y=await E1(this.chatId,x);if(!Y){A(`session "${this.sessionName}": background card send failed`);return}let Q;try{Q=await H6(Y)}catch(J){A(`session "${this.sessionName}": background card id_convert failed: ${J}`);return}if(m7(Q,this.backgroundTasks.length),this.backgroundCard={messageId:Y,cardId:Q},this.backgroundDetailAdded=new Set(this.backgroundTasks.map((J)=>J.id)),A(`session "${this.sessionName}": background card opened cardId=${Q.slice(0,12)} tasks=${this.backgroundTasks.length}`),!$7(this.backgroundTasks)){this.settleBackgroundCard();return}this.startBackgroundRefreshTick()}startBackgroundRefreshTick(){if(this.backgroundRefreshTick)return;let x=()=>{if(!this.backgroundCard||!$7(this.backgroundTasks))return;let Y=a7(),Q=Date.now(),J=1/0;for(let X of this.backgroundTasks){if(Q4(X))continue;let z=F3(Q-X.startedAt,Y).nextDelayMs;if(z<J)J=z}if(!isFinite(J))return;this.backgroundRefreshTick=setTimeout(()=>{this.refreshBackgroundCardFull(),x()},Math.max(1,Math.ceil(J)))};x()}stopBackgroundRefreshTick(){if(this.backgroundRefreshTick)clearTimeout(this.backgroundRefreshTick),this.backgroundRefreshTick=null}scheduleBackgroundRefresh(){if(!this.backgroundCard)return;if(this.backgroundRefreshTimer)return;this.backgroundRefreshTimer=setTimeout(()=>{this.backgroundRefreshTimer=null,this.refreshBackgroundCardFull()},1500)}refreshBackgroundCardFull(){let x=this.backgroundCard;if(!x)return;let Y=Date.now(),Q=a7();for(let J of this.backgroundTasks)if(!this.backgroundDetailAdded.has(J.id))this.backgroundDetailAdded.add(J.id),j1(x.cardId,i5(J,Y,Q));else Q1(x.cardId,K2.panel(J.id),i5(J,Y,Q));_7(x.cardId,$J(this.backgroundTasks))}async resetBackgroundTasks(){if(this.backgroundTasks.some((x)=>!Q4(x))){let x=Date.now();this.backgroundTasks=this.backgroundTasks.map((Y)=>Q4(Y)?Y:{...Y,status:"killed",endTime:Y.endTime??x})}if(this.pendingBgTasks=[],this.backgroundCard){await this.settleBackgroundCard();return}if(this.stopBackgroundRefreshTick(),this.backgroundRefreshTimer)clearTimeout(this.backgroundRefreshTimer),this.backgroundRefreshTimer=null;this.backgroundTasks=[],this.backgroundDetailAdded.clear(),this.openingBackground=!1}async settleBackgroundCard(){let x=this.backgroundCard;if(!x)return;this.backgroundCard=null;let Y=[...this.backgroundTasks];if(this.backgroundRefreshTimer)clearTimeout(this.backgroundRefreshTimer),this.backgroundRefreshTimer=null;if(this.stopBackgroundRefreshTick(),await y4(x.cardId),await y7(x.messageId,FJ(Y)),S8(x.cardId),await g8(x.cardId,F6({suffix:"\uD83E\uDDED 后台任务已结束"})),await G6(x.cardId),this.backgroundTasks=this.backgroundTasks.filter((Q)=>!Q4(Q)),this.backgroundDetailAdded.clear(),A(`session "${this.sessionName}": background card settled cardId=${x.cardId.slice(0,12)} remaining=${this.backgroundTasks.length}`),this.backgroundTasks.length>0)this.onBackgroundTaskChanged()}async migrateBackgroundCard(){let x=this.backgroundCard;if(!x)return;if(this.backgroundRefreshTimer)clearTimeout(this.backgroundRefreshTimer),this.backgroundRefreshTimer=null;this.stopBackgroundRefreshTick();let Y=this.backgroundTasks.filter(Q4).length;if(await y4(x.cardId),Y>0)await y7(x.messageId,FJ(this.backgroundTasks));else await y7(x.messageId,ZG());S8(x.cardId),await g8(x.cardId,F6({suffix:"\uD83E\uDDED 已迁移至新卡"})),await G6(x.cardId),this.backgroundCard=null,this.backgroundTasks=this.backgroundTasks.filter((Q)=>!Q4(Q)),this.backgroundDetailAdded.clear(),A(`session "${this.sessionName}": background card migrated cardId=${x.cardId.slice(0,12)} terminal=${Y} active=${this.backgroundTasks.length}`)}wireProc(x){x.on("error",(Y)=>{A(`session "${this.sessionName}": ${x.provider} process error: ${Y}`)}),x.on("init",()=>{if(Uc(),this.persistResumableSessionId(),this.initCount++,A(`session "${this.sessionName}": SDK init#${this.initCount} pendingCount=${this.pendingUserMessageCount} midBuffer=${this.pendingMidTurnMsgs.length} currentTurn=${this.currentTurn?"yes":"no"} openingTurn=${this.openingTurn}`),this.currentTurn||this.openingTurn)return;let Y=this.pendingUserMessageCount>0,Q=!Y&&this.bgResumePending;if(!Y&&!Q)return;this.bgResumePending=!1;let J=this.lastUserOpenId;if(Y)this.pendingUserMessageCount=0,this.currentBatchReactionIds=this.pendingReactionIds,this.pendingReactionIds=new Map;this.openingTurn=!0,this.sawResultWhileOpening=!1,(async()=>{try{if(await this.openTurnCard(J,Y?"user_message":"bg_task_resume"),!this.currentTurn)if(Y)A(`session "${this.sessionName}": init-path openTurnCard failed — sendInterrupt + release reactions`),this.proc?.sendInterrupt(),this.releaseAllReactions();else if(this.bgResumeCardless=!0,this.sawResultWhileOpening)this.sawResultWhileOpening=!1,A(`session "${this.sessionName}": bg-resume openTurnCard failed, result already arrived — flushing orphan now`),this.flushOrphanAssistantToChat("bg-resume open failed, result already arrived");else A(`session "${this.sessionName}": bg-resume openTurnCard failed — orphan text flush will cover the output`);else if(this.sawResultWhileOpening)this.sawResultWhileOpening=!1,A(`session "${this.sessionName}": result raced card-open — closing freshly-opened turn card now`),await this.closeTurnCard(void 0,{hasFreshResult:!0}),this.status="idle";else this.status="working"}finally{this.openingTurn=!1}})()}),x.on("turn_started",()=>{this.persistResumableSessionId();let Y=this.proc?.lastTotalUsage;if(this.usageTotalsSeedUnknown&&!Y){this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1;return}this.currentTurnUsageBaseline=Y?{...Y}:null,this.currentTurnUsageBaselineKnown=!0}),x.on("token_usage",({totalUsage:Y})=>{if(this.persistResumableSessionId(),Y)this.usageTotalsSeedUnknown=!1}),x.on("turn_plan_updated",(Y)=>{this.handleTurnPlanUpdated(Y)}),x.on("plan_delta",(Y)=>{this.handlePlanDelta(Y)}),x.on("context_compacted",(Y)=>{this.handleContextCompacted(Y)}),x.on("rate_limits_updated",(Y)=>{if(x.provider==="codex")gy(Y)}),x.on("thread_goal_updated",(Y)=>{this.handleThreadGoalUpdated(Y)}),x.on("thread_goal_cleared",()=>{this.handleThreadGoalCleared()}),x.on("assistant_text",({text:Y})=>{this.appendAssistant(Y)}),x.on("assistant_block_stop",()=>{this.finalizeCurrentAssistantSegment(),this.onMainThreadAdvance()}),x.on("tool_use",({id:Y,name:Q,input:J,parentToolUseId:X})=>{if(Fh(this,Y,Q,J),!X)this.onMainThreadAdvance();if(!X&&(Q==="Task"||Q==="Agent"))this.lastMainTaskToolUseId=Y;if(X&&this.bgTaskOwns(X))this.applyBgStore(eH({active:this.backgroundTasks,pending:this.pendingBgTasks},X,Y,Q,J)),this.onBackgroundTaskChanged()}),x.on("tool_result",({tool_use_id:Y,content:Q,is_error:J,parentToolUseId:X})=>{if(Uh(this,Y,Q,J),X&&this.bgTaskOwns(X))this.applyBgStore(xG({active:this.backgroundTasks,pending:this.pendingBgTasks},X,Y,Q,J)),this.onBackgroundTaskChanged()}),x.on("can_use_tool",(Y)=>{Rh(this,Y)}),x.on("hook_callback",(Y)=>{this.proc?.sendHookResponse(Y.request_id,{})}),x.on("result",()=>{if(this.persistResumableSessionId(),this.accumulateResultStats(),this.openingTurn)this.sawResultWhileOpening=!0;if(this.userInterrupted){this.userInterrupted=!1,this.discardOrphanAssistant(),this.bgResumePending=!1;let G=this.proc?.lastResult.subtype??"unknown",K=this.proc?.lastResult.is_error===!0;A(`session "${this.sessionName}": SDK result after user stop subtype=${G} isError=${K} — ignored`),this.status="idle";return}if(this.recordTurnAnchor(),!this.currentTurn&&!this.openingTurn)this.flushOrphanAssistantToChat("result with no turn card");let Y=this.pendingMidTurnMsgs.length>0,Q=this.proc?.lastResult.is_error===!0,J=this.proc?.lastResult.subtype??"success",X,z=!1,Z=this.proc?this.backendLabel(this.proc.provider):this.backendLabel();if(Y)X=Q?`⚠️ ${Z} ${J},用户已介入`:"\uD83D\uDCE8 转交新卡";else if(Q)X=`⚠️ ${Z} ${J}`,z=!0;if(A(`session "${this.sessionName}": SDK result subtype=${J} isError=${Q} midBuffer=${this.pendingMidTurnMsgs.length} forcePush=${z}`),this.closeTurnCard(X,{forcePush:z,hasFreshResult:!0}),this.status="idle",Y)this.drainMidTurnAndOpen()}),x.on("bg_task_started",(Y)=>{let Q=Y.tool_use_id??this.lastMainTaskToolUseId??void 0;A(`session "${this.sessionName}": bg_task_started task=${Y.task_id} type=${Y.task_type??"-"} subagent=${Y.subagent_type??"-"} toolUseId=${Q?.slice(0,8)??"-"} desc=${(Y.description??"").slice(0,40)}`),this.applyBgStore(pH(this.bgStore(),{...Y,tool_use_id:Q})),this.onBackgroundTaskChanged()}),x.on("bg_task_progress",(Y)=>{this.applyBgStore(sH(this.bgStore(),Y)),this.onBackgroundTaskChanged()}),x.on("bg_task_updated",(Y)=>{this.applyBgStore(oH(this.bgStore(),Y)),this.onBackgroundTaskChanged()}),x.on("bg_task_settled",(Y)=>{if(A(`session "${this.sessionName}": bg_task_settled task=${Y.task_id} status=${Y.status}`),this.applyBgStore(tH(this.bgStore(),Y)),this.onBackgroundTaskChanged(),x.provider==="claude"&&!this.currentTurn&&!this.openingTurn&&this.initCount>=1)this.bgResumePending=!0}),x.on("subagent_step",(Y)=>{this.applyBgStore(aH(this.bgStore(),Y.thread_id,Y.item_id,Y.tool,Y.phase,Y.brief)),this.onBackgroundTaskChanged()}),x.on("exit",({code:Y,signal:Q,expected:J})=>{if(A(`session "${this.sessionName}": ${x.provider} exited code=${Y} signal=${Q} expected=${J}`),this.proc!==x){A(`session "${this.sessionName}": ignore stale ${x.provider} exit; current=${this.proc?.provider??"none"}`);return}if(this.proc=null,this.flushOrphanAssistantToChat("process exit"),this.bgResumePending=!1,this.bgResumeCardless=!1,this.sawResultWhileOpening=!1,this.stopFooterStatus(this.currentTurn),this.currentTurn=null,this.clearMultiMsgBuffer("process exit"),this.pendingUserMessageCount=0,this.pendingMidTurnMsgs=[],this.pendingTurnInputs=[],this.lastUserOpenId="",this.releaseAllReactions(),this.initCount=0,this.openingTurn=!1,this.pendingAsks.clear(),this.pendingPermissions.clear(),this.userInterrupted=!1,this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,this.usageTotalsSeedUnknown=!1,this.status="stopped",this.opts.onLifecycleChange?.(),!J&&Y!==0&&Q!=="SIGTERM")V0(this.chatId,`⚠️ ${this.backendLabel(x.provider)} 异常退出 (code=${Y}, signal=${Q})。回复任意消息将重新启动。`)})}accumulateResultStats(){let x=this.proc?.lastResult;if(!x)return;let Y=this.currentTurnUsageBaselineKnown?hH(this.proc?.lastTotalUsage,this.currentTurnUsageBaseline):this.proc?.provider==="claude"&&x.usage?{...x.usage}:null;this.lastTurnUsage=Y,this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1;let Q=mH(Y),J=this.proc?.provider==="claude"?0:x.cost_delta_usd??0,X=x.duration_ms??0;if(Q!=null)this.cumStats.tokens+=Q;this.cumStats.costUsd+=J,this.cumStats.turns+=x.num_turns??1,this.lastTurnDelta={tokens:Q,costUsd:J,durationMs:X}}currentContextTokens(){if(this.proc?.provider==="claude")return this.proc?.lastContextTokens??null;let x=this.proc?.lastUsage;return Rz(x)}contextLimitForDisplay(){return Cz(this.proc?.lastContextWindow)}async drainMidTurnAndOpen(){if(this.pendingMidTurnMsgs.length===0)return;let x=this.pendingMidTurnMsgs;this.pendingMidTurnMsgs=[],this.openingTurn=!0;try{for(let X of x)if(this.pendingTurnInputs.push(X.text),X.msgId){let z=this.pendingReactionIds.get(X.msgId)??"";this.currentBatchReactionIds.set(X.msgId,z),this.pendingReactionIds.delete(X.msgId)}let Y=x.map((X)=>X.wireText).join(`
|
|
372
|
+
`:"")+x,G=(K)=>{this.pendingReactionIds.set(K,""),(async()=>{let H=await L4(K,"OneSecond");if(!H)return;if(this.pendingReactionIds.has(K))this.pendingReactionIds.set(K,H);else if(this.currentBatchReactionIds.has(K))this.currentBatchReactionIds.set(K,H);else f4(K,H)})()};if(!this.isRunning()){if(this.openingTurn||this.currentTurn){if(this.pendingMidTurnMsgs.push({text:x,wireText:Z,userOpenId:Q,msgId:J}),J)G(J);return}await this.startColdUserTurn(x,Z,Q);return}if(this.currentTurn!==null){if(this.pendingMidTurnMsgs.push({text:x,wireText:Z,userOpenId:Q,msgId:J}),J)G(J);return}if(!this.openingTurn&&this.initCount>=1){this.openingTurn=!0;try{if(this.pendingTurnInputs.push(x),await this.openTurnCard(Q,"user_message"),!this.currentTurn)return;this.proc.sendUserText(Z,[]),this.pendingUserMessageCount++,this.status="working"}finally{this.openingTurn=!1}return}if(this.openingTurn||this.pendingUserMessageCount>0){if(this.pendingMidTurnMsgs.push({text:x,wireText:Z,userOpenId:Q,msgId:J}),J)G(J);return}if(this.pendingTurnInputs.push(x),this.proc.sendUserText(Z,[]),this.pendingUserMessageCount++,X&&J)G(J)}hasPendingAsk(){return Dh(this)}onMultiMessageInbound(x,Y,Q,J){return iy(this,x,Y,Q,J)}clearMultiMsgBuffer(x){EN(this,x)}onAskMessageAnswer(x,Y,Q){return Oh(this,x,Y,Q)}onAskAnswer(x,Y,Q,J){return Bh(this,x,Y,Q,J)}onAskCustomAnswer(x,Y,Q,J){return wN(this,x,Y,Q,J)}onPermissionDecision(x,Y,Q){return Mh(this,x,Y,Q)}persistResumableSessionId(){let x=this.proc,Y=x?.sessionId;if(!x||!Y)return;if(au(this.sessionName,Y,x.provider),x.provider!==this.selectedProvider)return;if(Y===this.lastSessionId)return;this.lastSessionId=Y}bgStore(){return{active:this.backgroundTasks,pending:this.pendingBgTasks}}applyBgStore(x){this.backgroundTasks=x.active,this.pendingBgTasks=x.pending}onMainThreadAdvance(){if(this.pendingBgTasks.length===0)return;this.applyBgStore(rH(this.bgStore())),this.onBackgroundTaskChanged()}bgTaskOwns(x){return this.backgroundTasks.some((Y)=>Y.toolUseId===x)||this.pendingBgTasks.some((Y)=>Y.toolUseId===x)}onBackgroundTaskChanged(){if(!$7(this.backgroundTasks)){if(this.backgroundCard)this.settleBackgroundCard();return}if(!this.backgroundCard&&!this.openingBackground){this.openingBackground=!0,this.openBackgroundCard().finally(()=>{this.openingBackground=!1});return}this.scheduleBackgroundRefresh()}async openBackgroundCard(){if(this.backgroundCard)return;let x=YG(this.backgroundTasks,Date.now(),a7()),Y=await E1(this.chatId,x);if(!Y){A(`session "${this.sessionName}": background card send failed`);return}let Q;try{Q=await H6(Y)}catch(J){A(`session "${this.sessionName}": background card id_convert failed: ${J}`);return}if(m7(Q,this.backgroundTasks.length),this.backgroundCard={messageId:Y,cardId:Q},this.backgroundDetailAdded=new Set(this.backgroundTasks.map((J)=>J.id)),A(`session "${this.sessionName}": background card opened cardId=${Q.slice(0,12)} tasks=${this.backgroundTasks.length}`),!$7(this.backgroundTasks)){this.settleBackgroundCard();return}this.startBackgroundRefreshTick()}startBackgroundRefreshTick(){if(this.backgroundRefreshTick)return;let x=()=>{if(!this.backgroundCard||!$7(this.backgroundTasks))return;let Y=a7(),Q=Date.now(),J=1/0;for(let X of this.backgroundTasks){if(Q4(X))continue;let z=F3(Q-X.startedAt,Y).nextDelayMs;if(z<J)J=z}if(!isFinite(J))return;this.backgroundRefreshTick=setTimeout(()=>{this.refreshBackgroundCardFull(),x()},Math.max(1,Math.ceil(J)))};x()}stopBackgroundRefreshTick(){if(this.backgroundRefreshTick)clearTimeout(this.backgroundRefreshTick),this.backgroundRefreshTick=null}scheduleBackgroundRefresh(){if(!this.backgroundCard)return;if(this.backgroundRefreshTimer)return;this.backgroundRefreshTimer=setTimeout(()=>{this.backgroundRefreshTimer=null,this.refreshBackgroundCardFull()},1500)}refreshBackgroundCardFull(){let x=this.backgroundCard;if(!x)return;let Y=Date.now(),Q=a7();for(let J of this.backgroundTasks)if(!this.backgroundDetailAdded.has(J.id))this.backgroundDetailAdded.add(J.id),j1(x.cardId,i5(J,Y,Q));else Q1(x.cardId,K2.panel(J.id),i5(J,Y,Q));_7(x.cardId,$J(this.backgroundTasks))}async resetBackgroundTasks(){if(this.backgroundTasks.some((x)=>!Q4(x))){let x=Date.now();this.backgroundTasks=this.backgroundTasks.map((Y)=>Q4(Y)?Y:{...Y,status:"killed",endTime:Y.endTime??x})}if(this.pendingBgTasks=[],this.backgroundCard){await this.settleBackgroundCard();return}if(this.stopBackgroundRefreshTick(),this.backgroundRefreshTimer)clearTimeout(this.backgroundRefreshTimer),this.backgroundRefreshTimer=null;this.backgroundTasks=[],this.backgroundDetailAdded.clear(),this.openingBackground=!1}async settleBackgroundCard(){let x=this.backgroundCard;if(!x)return;this.backgroundCard=null;let Y=[...this.backgroundTasks];if(this.backgroundRefreshTimer)clearTimeout(this.backgroundRefreshTimer),this.backgroundRefreshTimer=null;if(this.stopBackgroundRefreshTick(),await y4(x.cardId),await y7(x.messageId,FJ(Y)),S8(x.cardId),await g8(x.cardId,F6({suffix:"\uD83E\uDDED 后台任务已结束"})),await G6(x.cardId),this.backgroundTasks=this.backgroundTasks.filter((Q)=>!Q4(Q)),this.backgroundDetailAdded.clear(),A(`session "${this.sessionName}": background card settled cardId=${x.cardId.slice(0,12)} remaining=${this.backgroundTasks.length}`),this.backgroundTasks.length>0)this.onBackgroundTaskChanged()}async migrateBackgroundCard(){let x=this.backgroundCard;if(!x)return;if(this.backgroundRefreshTimer)clearTimeout(this.backgroundRefreshTimer),this.backgroundRefreshTimer=null;this.stopBackgroundRefreshTick();let Y=this.backgroundTasks.filter(Q4).length;if(await y4(x.cardId),Y>0)await y7(x.messageId,FJ(this.backgroundTasks));else await y7(x.messageId,ZG());S8(x.cardId),await g8(x.cardId,F6({suffix:"\uD83E\uDDED 已迁移至新卡"})),await G6(x.cardId),this.backgroundCard=null,this.backgroundTasks=this.backgroundTasks.filter((Q)=>!Q4(Q)),this.backgroundDetailAdded.clear(),A(`session "${this.sessionName}": background card migrated cardId=${x.cardId.slice(0,12)} terminal=${Y} active=${this.backgroundTasks.length}`)}wireProc(x){x.on("error",(Y)=>{A(`session "${this.sessionName}": ${x.provider} process error: ${Y}`)}),x.on("init",()=>{if(Uc(),this.persistResumableSessionId(),this.initCount++,A(`session "${this.sessionName}": SDK init#${this.initCount} pendingCount=${this.pendingUserMessageCount} midBuffer=${this.pendingMidTurnMsgs.length} currentTurn=${this.currentTurn?"yes":"no"} openingTurn=${this.openingTurn}`),this.currentTurn||this.openingTurn)return;let Y=this.pendingUserMessageCount>0,Q=!Y&&this.bgResumePending;if(!Y&&!Q)return;this.bgResumePending=!1;let J=this.lastUserOpenId;if(Y)this.pendingUserMessageCount=0,this.currentBatchReactionIds=this.pendingReactionIds,this.pendingReactionIds=new Map;this.openingTurn=!0,this.sawResultWhileOpening=!1,(async()=>{try{if(await this.openTurnCard(J,Y?"user_message":"bg_task_resume"),!this.currentTurn)if(Y)A(`session "${this.sessionName}": init-path openTurnCard failed — sendInterrupt + release reactions`),this.proc?.sendInterrupt(),this.releaseAllReactions();else if(this.bgResumeCardless=!0,this.sawResultWhileOpening)this.sawResultWhileOpening=!1,A(`session "${this.sessionName}": bg-resume openTurnCard failed, result already arrived — flushing orphan now`),this.flushOrphanAssistantToChat("bg-resume open failed, result already arrived");else A(`session "${this.sessionName}": bg-resume openTurnCard failed — orphan text flush will cover the output`);else if(this.sawResultWhileOpening)this.sawResultWhileOpening=!1,A(`session "${this.sessionName}": result raced card-open — closing freshly-opened turn card now`),await this.closeTurnCard(void 0,{hasFreshResult:!0}),this.status="idle";else this.status="working"}finally{this.openingTurn=!1}})()}),x.on("turn_started",()=>{this.persistResumableSessionId();let Y=this.proc?.lastTotalUsage;if(this.usageTotalsSeedUnknown&&!Y){this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1;return}this.currentTurnUsageBaseline=Y?{...Y}:null,this.currentTurnUsageBaselineKnown=!0}),x.on("token_usage",({totalUsage:Y})=>{if(this.persistResumableSessionId(),Y)this.usageTotalsSeedUnknown=!1}),x.on("turn_plan_updated",(Y)=>{this.handleTurnPlanUpdated(Y)}),x.on("plan_delta",(Y)=>{this.handlePlanDelta(Y)}),x.on("context_compacted",(Y)=>{this.handleContextCompacted(Y)}),x.on("rate_limits_updated",(Y)=>{if(x.provider==="codex")gy(Y)}),x.on("thread_goal_updated",(Y)=>{this.handleThreadGoalUpdated(Y)}),x.on("thread_goal_cleared",()=>{this.handleThreadGoalCleared()}),x.on("assistant_text",({text:Y})=>{this.appendAssistant(Y)}),x.on("assistant_block_stop",()=>{this.finalizeCurrentAssistantSegment(),this.onMainThreadAdvance()}),x.on("tool_use",({id:Y,name:Q,input:J,parentToolUseId:X})=>{if(X&&this.bgTaskOwns(X)){this.applyBgStore(eH({active:this.backgroundTasks,pending:this.pendingBgTasks},X,Y,Q,J)),this.onBackgroundTaskChanged();return}if(Fh(this,Y,Q,J),!X)this.onMainThreadAdvance();if(!X&&(Q==="Task"||Q==="Agent"))this.lastMainTaskToolUseId=Y}),x.on("tool_result",({tool_use_id:Y,content:Q,is_error:J,parentToolUseId:X})=>{if(X&&this.bgTaskOwns(X)){this.applyBgStore(xG({active:this.backgroundTasks,pending:this.pendingBgTasks},X,Y,Q,J)),this.onBackgroundTaskChanged();return}Uh(this,Y,Q,J)}),x.on("can_use_tool",(Y)=>{Rh(this,Y)}),x.on("hook_callback",(Y)=>{this.proc?.sendHookResponse(Y.request_id,{})}),x.on("result",()=>{if(this.persistResumableSessionId(),this.accumulateResultStats(),this.openingTurn)this.sawResultWhileOpening=!0;if(this.userInterrupted){this.userInterrupted=!1,this.discardOrphanAssistant(),this.bgResumePending=!1;let G=this.proc?.lastResult.subtype??"unknown",K=this.proc?.lastResult.is_error===!0;A(`session "${this.sessionName}": SDK result after user stop subtype=${G} isError=${K} — ignored`),this.status="idle";return}if(this.recordTurnAnchor(),!this.currentTurn&&!this.openingTurn)this.flushOrphanAssistantToChat("result with no turn card");let Y=this.pendingMidTurnMsgs.length>0,Q=this.proc?.lastResult.is_error===!0,J=this.proc?.lastResult.subtype??"success",X,z=!1,Z=this.proc?this.backendLabel(this.proc.provider):this.backendLabel();if(Y)X=Q?`⚠️ ${Z} ${J},用户已介入`:"\uD83D\uDCE8 转交新卡";else if(Q)X=`⚠️ ${Z} ${J}`,z=!0;if(A(`session "${this.sessionName}": SDK result subtype=${J} isError=${Q} midBuffer=${this.pendingMidTurnMsgs.length} forcePush=${z}`),this.closeTurnCard(X,{forcePush:z,hasFreshResult:!0}),this.status="idle",Y)this.drainMidTurnAndOpen()}),x.on("bg_task_started",(Y)=>{let Q=Y.tool_use_id??this.lastMainTaskToolUseId??void 0;A(`session "${this.sessionName}": bg_task_started task=${Y.task_id} type=${Y.task_type??"-"} subagent=${Y.subagent_type??"-"} toolUseId=${Q?.slice(0,8)??"-"} desc=${(Y.description??"").slice(0,40)}`),this.applyBgStore(pH(this.bgStore(),{...Y,tool_use_id:Q})),this.onBackgroundTaskChanged()}),x.on("bg_task_progress",(Y)=>{this.applyBgStore(sH(this.bgStore(),Y)),this.onBackgroundTaskChanged()}),x.on("bg_task_updated",(Y)=>{this.applyBgStore(oH(this.bgStore(),Y)),this.onBackgroundTaskChanged()}),x.on("bg_task_settled",(Y)=>{if(A(`session "${this.sessionName}": bg_task_settled task=${Y.task_id} status=${Y.status}`),this.applyBgStore(tH(this.bgStore(),Y)),this.onBackgroundTaskChanged(),x.provider==="claude"&&!this.currentTurn&&!this.openingTurn&&this.initCount>=1)this.bgResumePending=!0}),x.on("subagent_step",(Y)=>{this.applyBgStore(aH(this.bgStore(),Y.thread_id,Y.item_id,Y.tool,Y.phase,Y.brief)),this.onBackgroundTaskChanged()}),x.on("exit",({code:Y,signal:Q,expected:J})=>{if(A(`session "${this.sessionName}": ${x.provider} exited code=${Y} signal=${Q} expected=${J}`),this.proc!==x){A(`session "${this.sessionName}": ignore stale ${x.provider} exit; current=${this.proc?.provider??"none"}`);return}if(this.proc=null,this.flushOrphanAssistantToChat("process exit"),this.bgResumePending=!1,this.bgResumeCardless=!1,this.sawResultWhileOpening=!1,this.stopFooterStatus(this.currentTurn),this.currentTurn=null,this.clearMultiMsgBuffer("process exit"),this.pendingUserMessageCount=0,this.pendingMidTurnMsgs=[],this.pendingTurnInputs=[],this.lastUserOpenId="",this.releaseAllReactions(),this.initCount=0,this.openingTurn=!1,this.pendingAsks.clear(),this.pendingPermissions.clear(),this.userInterrupted=!1,this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1,this.usageTotalsSeedUnknown=!1,this.status="stopped",this.opts.onLifecycleChange?.(),!J&&Y!==0&&Q!=="SIGTERM")V0(this.chatId,`⚠️ ${this.backendLabel(x.provider)} 异常退出 (code=${Y}, signal=${Q})。回复任意消息将重新启动。`)})}accumulateResultStats(){let x=this.proc?.lastResult;if(!x)return;let Y=this.currentTurnUsageBaselineKnown?hH(this.proc?.lastTotalUsage,this.currentTurnUsageBaseline):this.proc?.provider==="claude"&&x.usage?{...x.usage}:null;this.lastTurnUsage=Y,this.currentTurnUsageBaseline=null,this.currentTurnUsageBaselineKnown=!1;let Q=mH(Y),J=this.proc?.provider==="claude"?0:x.cost_delta_usd??0,X=x.duration_ms??0;if(Q!=null)this.cumStats.tokens+=Q;this.cumStats.costUsd+=J,this.cumStats.turns+=x.num_turns??1,this.lastTurnDelta={tokens:Q,costUsd:J,durationMs:X}}currentContextTokens(){if(this.proc?.provider==="claude")return this.proc?.lastContextTokens??null;let x=this.proc?.lastUsage;return Rz(x)}contextLimitForDisplay(){return Cz(this.proc?.lastContextWindow)}async drainMidTurnAndOpen(){if(this.pendingMidTurnMsgs.length===0)return;let x=this.pendingMidTurnMsgs;this.pendingMidTurnMsgs=[],this.openingTurn=!0;try{for(let X of x)if(this.pendingTurnInputs.push(X.text),X.msgId){let z=this.pendingReactionIds.get(X.msgId)??"";this.currentBatchReactionIds.set(X.msgId,z),this.pendingReactionIds.delete(X.msgId)}let Y=x.map((X)=>X.wireText).join(`
|
|
373
373
|
|
|
374
374
|
`);this.proc.sendUserText(Y,[]),this.pendingUserMessageCount++;let J=x[x.length-1]?.userOpenId??this.lastUserOpenId;await this.openTurnCard(J,"user_message"),this.status="working"}finally{this.openingTurn=!1}}async openTurnCard(x,Y,Q={}){if(this.bgResumePending=!1,this.backgroundCard&&$7(this.backgroundTasks))try{await this.migrateBackgroundCard(),this.pendingRebuildBackgroundCard=!0}catch(D){A(`session "${this.sessionName}": background migrate failed (non-blocking): ${D}`)}let J=++this.turnCounter,X=this.pendingTurnInputs;this.pendingTurnInputs=[],this.lastTurnUserPreview=X[0]?.slice(0,80)??this.lastTurnUserPreview,A(`session "${this.sessionName}": openTurnCard turn=${J} trigger=${Y} inputs=${X.length}`);let z=this.runtimeModelSelection(),Z=this.withModel(Q.initialFooter??"Waiting...(0s)",z),G=mz({sessionName:this.sessionName,turn:J,provider:z.provider,model:z.model??void 0,effort:z.effort,kind:Y,userInputs:X,initialFooter:Z,directStart:Q.directStart}),K=await E1(this.chatId,G);if(!K){if(A(`session "${this.sessionName}": openTurnCard sendCard EXHAUSTED retries — surfacing via raw text`),Y==="user_message")await R1(this.chatId,"❌ 创建对话卡片失败 (Feishu SDK 重试 3 次后仍连不上)。你这条消息没能送到 Codex,请稍后重发。");return}let H;try{H=await H6(K)}catch(D){A(`session "${this.sessionName}": id_convert failed: ${D}`);return}let W=(Y==="bg_task_resume"?1:0)+(X.length>0?1:0)+1;m7(H,W,(D)=>this.onCardWriteFailure(D));let $={cardId:H,...z,messageId:K,userOpenId:x,trigger:Y,toolCount:0,toolByUseId:new Map,planSteps:[],planExplanation:null,planUpdateCount:0,goalUpdateCount:0,contextCompactCount:0,contextCompactionPending:new Map,toolBatches:new Map,openBatchI:null,taskCreateI:null,taskUpdateI:null,taskBoardResetThisTurn:!1,taskLiveInserted:!1,planLiveInserted:!1,assistantSegmentCount:0,currentAssistantSegmentId:null,currentAssistantText:"",segmentTexts:new Map,startedAt:Date.now(),footerStatusHandle:null,footerStatusStartedAt:0,footerStatusLabel:null,rotating:null,rotateCount:0,failureRotateCount:0,rotateGivenUp:!1,outboundSeenPaths:new Set,outboundSentPaths:new Set};if(this.currentTurn=$,Q.startThinking!==!1)this.startThinkingFooter($);let N=this.takeOrphanAssistantText();if(N)this.appendAssistant(N),this.finalizeCurrentAssistantSegment();if(this.pendingRebuildBackgroundCard){if(this.pendingRebuildBackgroundCard=!1,$7(this.backgroundTasks))this.openBackgroundCard()}}maybeMidTurnRotate(){let x=this.currentTurn;if(!x)return;if(x.rotating)return;if(EL(x.cardId)<iD0)return;this.startMidTurnRotate(x)}onCardWriteFailure(x){let Y=this.currentTurn;if(!Y)return;if(Y.rotating)return;if(Y.rotateGivenUp)return;if(Y.failureRotateCount>=tN){Y.rotateGivenUp=!0,this.stopFooterStatus(Y),Df(Y.cardId),A(`session "${this.sessionName}": failure-rotate cap (${tN}) hit — giving up, rest of turn is log-only`),R1(this.chatId,`⚠️ 卡片写入失败已触发 ${tN} 次换卡仍未恢复(疑似飞书故障或元素超限),本轮后续输出仅日志可见。`);return}let Q=Nf(x)?`element limit (${x})`:`write failure (code=${x??"n/a"})`;A(`session "${this.sessionName}": ${Q} on card=${Y.cardId.slice(0,8)}… — rotating to fresh card`),Y.failureRotateCount++,this.startMidTurnRotate(Y)}startMidTurnRotate(x){if(x.rotating)return;x.rotateCount++;let{cardId:Y,toolByUseId:Q,toolBatches:J}=x;x.rotating=(async()=>{try{A(`session "${this.sessionName}": mid-turn rotate triggered card=${Y.slice(0,8)}… elementCount=${EL(Y)}`);let X=mz({sessionName:this.sessionName,turn:this.turnCounter,provider:x.provider,model:x.model??void 0,effort:x.effort,kind:"card_full",userInputs:[]}),z=await E1(this.chatId,X);if(!z){A(`session "${this.sessionName}": mid-turn rotate sendCard EXHAUSTED — staying on old card,subsequent adds will drop`),await R1(this.chatId,"⚠️ 卡片元素超出飞书上限,本轮后续输出仅日志可见(开新卡失败)。");return}let Z;try{Z=await H6(z)}catch(W){A(`session "${this.sessionName}": mid-turn rotate id_convert failed: ${W}`);return}m7(Z,2,(W)=>this.onCardWriteFailure(W)),this.stopFooterStatus(x),x.cardId=Z,x.messageId=z,x.toolCount=0,x.toolByUseId=new Map,x.toolBatches=new Map,x.openBatchI=null,x.planUpdateCount=0,x.goalUpdateCount=0;let G=x.currentAssistantSegmentId,K=(x.currentAssistantText??"").trim(),H=x.segmentTexts;if(x.assistantSegmentCount=0,x.currentAssistantSegmentId=null,x.currentAssistantText="",x.segmentTexts=new Map,K)this.startWritingFooter(x);else this.startThinkingFooter(x);if(x.taskLiveInserted)j1(x.cardId,o7(this.taskBoard),{type:"insert_before",targetElementId:W0.footer});if(x.planLiveInserted)j1(x.cardId,_Y(x.planSteps,x.planExplanation,W0.planLive),{type:"insert_before",targetElementId:x.taskLiveInserted?W0.taskBoardLive:W0.footer});for(let[W,$]of H){if(G&&K&&W===G)continue;if(!wY(Y,W))continue;let N=x.assistantSegmentCount++,D=W0.assistant(N);x.segmentTexts.set(D,$),j1(Z,this.completedAssistantElement(D,$),{type:"insert_before",targetElementId:j8(x)})}if(Lh(this,Y,Z,Q,J),G&&K){let W=x.assistantSegmentCount++,$=W0.assistant(W);x.currentAssistantSegmentId=$,x.currentAssistantText=K,x.segmentTexts.set($,K)}try{await y4(Y);for(let[$,N]of H){if(G&&K&&$===G)continue;if(wY(Y,$))continue;await Q1(Y,$,{tag:"markdown",element_id:$,content:this.cleanAssistantTextForDisplay(N).trim()||" "})}let W=x.contextCompactCount>0?` · \uD83D\uDEA8 压缩×${x.contextCompactCount}`:"";await this.replaceFooterContent(Y,this.withModel(`\uD83D\uDCE8 已续至下一张卡 ↓${W}`)),S8(Y),await g8(Y,F6({suffix:"\uD83D\uDCE8 转下一张"})),await G6(Y)}catch(W){A(`session "${this.sessionName}": mid-turn rotate close-old failed: ${W}`)}A(`session "${this.sessionName}": mid-turn rotate done old=${Y.slice(0,8)}… new=${Z.slice(0,8)}…`)}finally{x.rotating=null}})()}addPlanSnapshotOnCurrentTurn(){let x=this.currentTurn;if(!x||x.planSteps.length===0)return;this.maybeMidTurnRotate();let Y=x.cardId,Q=W0.planUpdate(x.planUpdateCount++);j1(Y,sL(x.planSteps,x.planExplanation,"",Q),{type:"insert_before",targetElementId:j8(x)})}addGoalUpdateOnCurrentTurn(x){let Y=this.currentTurn;if(!Y)return;this.maybeMidTurnRotate();let Q=W0.goalUpdate(Y.goalUpdateCount++);j1(Y.cardId,oL(x,Q),{type:"insert_before",targetElementId:j8(Y)})}addGoalClearedOnCurrentTurn(){let x=this.currentTurn;if(!x)return;this.maybeMidTurnRotate();let Y=W0.goalUpdate(x.goalUpdateCount++);j1(x.cardId,{tag:"markdown",element_id:Y,content:`**\uD83C\uDFAF 当前目标**
|
|
375
375
|
|