aicodeman 1.19.2 → 1.19.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/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.2396d253.js +34 -0
- package/dist/web/public/app.2396d253.js.br +0 -0
- package/dist/web/public/app.2396d253.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/constants.d474d7d9.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/i18n.bb8949de.js.gz +0 -0
- package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
- package/dist/web/public/index.html +2 -2
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.0454a3e9.js.gz +0 -0
- package/dist/web/public/mobile-handlers.05b89237.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.c40d28a6.css.gz +0 -0
- package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/panels-ui.c5a82b6e.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/session-ui.71a0ce9a.js.gz +0 -0
- package/dist/web/public/settings-ui.6cb12d4b.js.gz +0 -0
- package/dist/web/public/styles.325eb4f3.css.gz +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/terminal-ui.02b89e2c.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.4ec670b0.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/routes/approval-routes.d.ts +3 -1
- package/dist/web/routes/approval-routes.d.ts.map +1 -1
- package/dist/web/routes/approval-routes.js +15 -2
- package/dist/web/routes/approval-routes.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/app.e1e1fe4d.js +0 -34
- package/dist/web/public/app.e1e1fe4d.js.br +0 -0
- package/dist/web/public/app.e1e1fe4d.js.gz +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";const _crashDiag={_entries:[],_maxEntries:50,_pageId:Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8),log(h){const e=`${new Date().toISOString().slice(11,23)} ${h}`;this._entries.push(e),this._entries.length>this._maxEntries&&this._entries.shift();try{localStorage.setItem("codeman-crash-diag",this._entries.join(`
|
|
2
|
+
`))}catch{}}};try{const h=localStorage.getItem("codeman-crash-diag");h&&(console.log(`[CRASH-DIAG] Previous session breadcrumbs:
|
|
3
|
+
`+h),navigator.sendBeacon("/api/crash-diag",JSON.stringify({data:h,id:_crashDiag._pageId+"-prev"})))}catch{}_crashDiag.log("PAGE LOAD");function _crashDiagBeacon(){try{_crashDiag._entries.length>0&&navigator.sendBeacon("/api/crash-diag",JSON.stringify({data:_crashDiag._entries.join(`
|
|
4
|
+
`),id:_crashDiag._pageId}))}catch{}}if(setInterval(()=>{try{localStorage.setItem("codeman-crash-heartbeat",String(Date.now()))}catch{}_crashDiagBeacon()},2e3),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&_crashDiagBeacon()}),window.addEventListener("error",h=>{_crashDiag.log(`ERROR: ${h.message} at ${h.filename}:${h.lineno}`),console.error("[CRASH-DIAG] Uncaught error:",h.message,`
|
|
5
|
+
File:`,h.filename,":",h.lineno,":",h.colno,`
|
|
6
|
+
Stack:`,h.error?.stack)}),window.addEventListener("unhandledrejection",h=>{_crashDiag.log(`UNHANDLED: ${h.reason?.message||h.reason}`),console.error("[CRASH-DIAG] Unhandled promise rejection:",h.reason?.message||h.reason,`
|
|
7
|
+
Stack:`,h.reason?.stack)}),typeof PerformanceObserver<"u")try{new PerformanceObserver(e=>{for(const t of e.getEntries())t.duration>200&&(_crashDiag.log(`LONG_TASK: ${t.duration.toFixed(0)}ms`),console.warn(`[CRASH-DIAG] Long task: ${t.duration.toFixed(0)}ms (type: ${t.entryType}, name: ${t.name})`))}).observe({type:"longtask",buffered:!0})}catch{}const _origGetContext=HTMLCanvasElement.prototype.getContext;HTMLCanvasElement.prototype.getContext=function(h,...e){const t=_origGetContext.call(this,h,...e);return(h==="webgl2"||h==="webgl")&&(this.addEventListener("webglcontextlost",s=>{_crashDiag.log(`WEBGL_LOST: ${this.width}x${this.height}`),console.error("[CRASH-DIAG] WebGL context LOST on canvas",this.width,"x",this.height,"\u2014 prevented:",s.defaultPrevented)}),this.addEventListener("webglcontextrestored",()=>{_crashDiag.log("WEBGL_RESTORED"),console.warn("[CRASH-DIAG] WebGL context restored")})),t};const _SSE_HANDLER_MAP=[[SSE_EVENTS.INIT,"_onInit"],[SSE_EVENTS.SESSION_CREATED,"_onSessionCreated"],[SSE_EVENTS.SESSION_UPDATED,"_onSessionUpdated"],[SSE_EVENTS.SESSION_DELETED,"_onSessionDeleted"],[SSE_EVENTS.SESSION_TERMINAL,"_onSSETerminal"],[SSE_EVENTS.SESSION_NEEDS_REFRESH,"_onSSENeedsRefresh"],[SSE_EVENTS.SESSION_CLEAR_TERMINAL,"_onSSEClearTerminal"],[SSE_EVENTS.SESSION_COMPLETION,"_onSessionCompletion"],[SSE_EVENTS.SESSION_ERROR,"_onSessionError"],[SSE_EVENTS.SESSION_EXIT,"_onSessionExit"],[SSE_EVENTS.SESSION_IDLE,"_onSessionIdle"],[SSE_EVENTS.SESSION_WORKING,"_onSessionWorking"],[SSE_EVENTS.SESSION_AUTO_CLEAR,"_onSessionAutoClear"],[SSE_EVENTS.SESSION_LIMIT_PAUSE_SCHEDULED,"_onSessionLimitPauseScheduled"],[SSE_EVENTS.SESSION_LIMIT_RESUME,"_onSessionLimitResume"],[SSE_EVENTS.SESSION_LIMIT_RESUME_CANCELLED,"_onSessionLimitResumeCancelled"],[SSE_EVENTS.SESSION_RESPAWN_BREAKER_TRIPPED,"_onSessionRespawnBreakerTripped"],[SSE_EVENTS.SESSION_CLI_INFO,"_onSessionCliInfo"],[SSE_EVENTS.SESSION_STATUS_TELEMETRY,"_onSessionStatusTelemetry"],[SSE_EVENTS.SCHEDULED_CREATED,"_onScheduledCreated"],[SSE_EVENTS.SCHEDULED_UPDATED,"_onScheduledUpdated"],[SSE_EVENTS.SCHEDULED_COMPLETED,"_onScheduledCompleted"],[SSE_EVENTS.SCHEDULED_STOPPED,"_onScheduledStopped"],[SSE_EVENTS.CRON_JOBS_CHANGED,"_onCronJobsChanged"],[SSE_EVENTS.CRON_JOB_DELETED,"_onCronJobsChanged"],[SSE_EVENTS.CRON_RUN_CREATED,"_onCronRunChanged"],[SSE_EVENTS.CRON_RUN_UPDATED,"_onCronRunChanged"],[SSE_EVENTS.RESPAWN_STARTED,"_onRespawnStarted"],[SSE_EVENTS.RESPAWN_STOPPED,"_onRespawnStopped"],[SSE_EVENTS.RESPAWN_STATE_CHANGED,"_onRespawnStateChanged"],[SSE_EVENTS.RESPAWN_CYCLE_STARTED,"_onRespawnCycleStarted"],[SSE_EVENTS.RESPAWN_BLOCKED,"_onRespawnBlocked"],[SSE_EVENTS.RESPAWN_AUTO_ACCEPT_SENT,"_onRespawnAutoAcceptSent"],[SSE_EVENTS.RESPAWN_DETECTION_UPDATE,"_onRespawnDetectionUpdate"],[SSE_EVENTS.RESPAWN_TIMER_STARTED,"_onRespawnTimerStarted"],[SSE_EVENTS.RESPAWN_TIMER_CANCELLED,"_onRespawnTimerCancelled"],[SSE_EVENTS.RESPAWN_TIMER_COMPLETED,"_onRespawnTimerCompleted"],[SSE_EVENTS.RESPAWN_ERROR,"_onRespawnError"],[SSE_EVENTS.RESPAWN_ACTION_LOG,"_onRespawnActionLog"],[SSE_EVENTS.TASK_CREATED,"_onTaskCreated"],[SSE_EVENTS.TASK_COMPLETED,"_onTaskCompleted"],[SSE_EVENTS.TASK_FAILED,"_onTaskFailed"],[SSE_EVENTS.TASK_UPDATED,"_onTaskUpdated"],[SSE_EVENTS.MUX_CREATED,"_onMuxCreated"],[SSE_EVENTS.MUX_KILLED,"_onMuxKilled"],[SSE_EVENTS.MUX_DIED,"_onMuxDied"],[SSE_EVENTS.MUX_STATS_UPDATED,"_onMuxStatsUpdated"],[SSE_EVENTS.REMOTE_SESSION_RECONNECTED,"_onRemoteSessionReconnected"],[SSE_EVENTS.REMOTE_RECONNECT_EXHAUSTED,"_onRemoteReconnectExhausted"],[SSE_EVENTS.SESSION_RALPH_LOOP_UPDATE,"_onRalphLoopUpdate"],[SSE_EVENTS.SESSION_RALPH_TODO_UPDATE,"_onRalphTodoUpdate"],[SSE_EVENTS.SESSION_RALPH_COMPLETION_DETECTED,"_onRalphCompletionDetected"],[SSE_EVENTS.SESSION_RALPH_STATUS_UPDATE,"_onRalphStatusUpdate"],[SSE_EVENTS.SESSION_CIRCUIT_BREAKER_UPDATE,"_onCircuitBreakerUpdate"],[SSE_EVENTS.SESSION_EXIT_GATE_MET,"_onExitGateMet"],[SSE_EVENTS.SESSION_BASH_TOOL_START,"_onBashToolStart"],[SSE_EVENTS.SESSION_BASH_TOOL_END,"_onBashToolEnd"],[SSE_EVENTS.SESSION_BASH_TOOLS_UPDATE,"_onBashToolsUpdate"],[SSE_EVENTS.HOOK_IDLE_PROMPT,"_onHookIdlePrompt"],[SSE_EVENTS.HOOK_PERMISSION_PROMPT,"_onHookPermissionPrompt"],[SSE_EVENTS.HOOK_ELICITATION_DIALOG,"_onHookElicitationDialog"],[SSE_EVENTS.HOOK_ELICITATION_COMPLETE,"_onHookElicitationComplete"],[SSE_EVENTS.HOOK_ELICITATION_RESPONSE,"_onHookElicitationResponse"],[SSE_EVENTS.HOOK_STOP,"_onHookStop"],[SSE_EVENTS.HOOK_TEAMMATE_IDLE,"_onHookTeammateIdle"],[SSE_EVENTS.HOOK_TASK_COMPLETED,"_onHookTaskCompleted"],[SSE_EVENTS.APPROVAL_PENDING,"_onApprovalPending"],[SSE_EVENTS.APPROVAL_UPDATED,"_onApprovalUpdated"],[SSE_EVENTS.APPROVAL_RESOLVED,"_onApprovalResolved"],[SSE_EVENTS.SUBAGENT_DISCOVERED,"_onSubagentDiscovered"],[SSE_EVENTS.SUBAGENT_UPDATED,"_onSubagentUpdated"],[SSE_EVENTS.SUBAGENT_TOOL_CALL,"_onSubagentToolCall"],[SSE_EVENTS.SUBAGENT_PROGRESS,"_onSubagentProgress"],[SSE_EVENTS.SUBAGENT_MESSAGE,"_onSubagentMessage"],[SSE_EVENTS.SUBAGENT_TOOL_RESULT,"_onSubagentToolResult"],[SSE_EVENTS.SUBAGENT_COMPLETED,"_onSubagentCompleted"],[SSE_EVENTS.WORKFLOW_RUN_DISCOVERED,"_onWorkflowRunDiscovered"],[SSE_EVENTS.WORKFLOW_RUN_UPDATED,"_onWorkflowRunUpdated"],[SSE_EVENTS.WORKFLOW_RUN_REMOVED,"_onWorkflowRunRemoved"],[SSE_EVENTS.IMAGE_DETECTED,"_onImageDetected"],[SSE_EVENTS.ATTACHMENT_DETECTED,"_onAttachmentDetected"],[SSE_EVENTS.TUNNEL_STARTED,"_onTunnelStarted"],[SSE_EVENTS.TUNNEL_STOPPED,"_onTunnelStopped"],[SSE_EVENTS.TUNNEL_PROGRESS,"_onTunnelProgress"],[SSE_EVENTS.TUNNEL_ERROR,"_onTunnelError"],[SSE_EVENTS.TUNNEL_QR_ROTATED,"_onTunnelQrRotated"],[SSE_EVENTS.TUNNEL_QR_REGENERATED,"_onTunnelQrRegenerated"],[SSE_EVENTS.TUNNEL_QR_AUTH_USED,"_onTunnelQrAuthUsed"],[SSE_EVENTS.PLAN_SUBAGENT,"_onPlanSubagent"],[SSE_EVENTS.PLAN_PROGRESS,"_onPlanProgress"],[SSE_EVENTS.PLAN_STARTED,"_onPlanStarted"],[SSE_EVENTS.PLAN_CANCELLED,"_onPlanCancelled"],[SSE_EVENTS.PLAN_COMPLETED,"_onPlanCompleted"],[SSE_EVENTS.ORCHESTRATOR_STATE_CHANGED,"_onOrchestratorStateChanged"],[SSE_EVENTS.ORCHESTRATOR_PLAN_PROGRESS,"_onOrchestratorPlanProgress"],[SSE_EVENTS.ORCHESTRATOR_PLAN_READY,"_onOrchestratorPlanReady"],[SSE_EVENTS.ORCHESTRATOR_PHASE_STARTED,"_onOrchestratorPhaseStarted"],[SSE_EVENTS.ORCHESTRATOR_PHASE_COMPLETED,"_onOrchestratorPhaseCompleted"],[SSE_EVENTS.ORCHESTRATOR_PHASE_FAILED,"_onOrchestratorPhaseFailed"],[SSE_EVENTS.ORCHESTRATOR_VERIFICATION,"_onOrchestratorVerification"],[SSE_EVENTS.ORCHESTRATOR_TASK_ASSIGNED,"_onOrchestratorTaskAssigned"],[SSE_EVENTS.ORCHESTRATOR_TASK_COMPLETED,"_onOrchestratorTaskCompleted"],[SSE_EVENTS.ORCHESTRATOR_TASK_FAILED,"_onOrchestratorTaskFailed"],[SSE_EVENTS.ORCHESTRATOR_COMPLETED,"_onOrchestratorCompleted"],[SSE_EVENTS.ORCHESTRATOR_ERROR,"_onOrchestratorError"],[SSE_EVENTS.CLIPBOARD_WRITE,"_onClipboardWrite"],[SSE_EVENTS.SESSION_ORDER_CHANGED,"_onSessionOrderChanged"],[SSE_EVENTS.WEBVIEW_CHANGED,"_onWebviewChanged"]];function parseSessionPrefix(h){if(!h)return null;const e=h.match(/^(w\d+-[a-zA-Z0-9_-]+|s\d+-[a-zA-Z0-9_-]+)/);if(!e)return null;const t=e[1],s=h.slice(t.length);return s===""?{prefix:t,suffix:""}:s.startsWith(": ")?{prefix:t,suffix:s.slice(2)}:null}const DEFAULT_SHORTCUTS=[{id:"show-shortcuts",group:"Panels",label:"Show Shortcuts",bindings:[{modifiers:["ctrl"],key:"?",code:"Slash"},{modifiers:["ctrl","shift"],key:"?"},{modifiers:["alt"],key:"?",code:"Slash"}],action:"showShortcutOverlay"},{id:"close-session",group:"Session",label:"Close Session",bindings:[{modifiers:["ctrl"],key:"w"}],action:"killActiveSession"},{id:"next-session",group:"Session",label:"Next Session",bindings:[{modifiers:["ctrl"],key:"Tab"}],action:"nextSession"},{id:"clear-terminal",group:"Terminal",label:"Clear Terminal",bindings:[{modifiers:["ctrl"],key:"l"}],action:"clearTerminal"},{id:"copy-selection",group:"Terminal",label:"Copy Selection",bindings:[{modifiers:["ctrl"],key:"c"},{modifiers:["ctrl","shift"],key:"C"}],action:"copyTerminalSelection"},{id:"increase-font",group:"Terminal",label:"Increase Font",bindings:[{modifiers:["ctrl"],key:"=",code:"Equal"},{modifiers:["ctrl"],key:"+",code:"Equal"}],action:"increaseFontSize"},{id:"decrease-font",group:"Terminal",label:"Decrease Font",bindings:[{modifiers:["ctrl"],key:"-",code:"Minus"}],action:"decreaseFontSize"},{id:"voice-input",group:"Terminal",label:"Voice Input",bindings:[{modifiers:["ctrl","shift"],key:"V"}],action:"toggleVoiceInput"},{id:"restore-terminal-size",group:"Terminal",label:"Restore Terminal Size",bindings:[{modifiers:["ctrl","shift"],key:"R"}],action:"restoreTerminalSize"},{id:"move-tab-left",group:"Tabs",label:"Move Active Tab Left",bindings:[{modifiers:["ctrl","shift"],key:"{",code:"BracketLeft"}],action:"moveActiveTabLeft"},{id:"move-tab-right",group:"Tabs",label:"Move Active Tab Right",bindings:[{modifiers:["ctrl","shift"],key:"}",code:"BracketRight"}],action:"moveActiveTabRight"},{id:"command-palette",group:"Session",label:"Find Open Session",bindings:[{modifiers:["ctrl"],key:"k",code:"KeyK"},{modifiers:["meta"],key:"k",code:"KeyK"},{modifiers:["alt"],key:"k",code:"KeyK"}],action:"openCommandPalette"},{id:"toggle-session-sidebar",group:"Session",label:"Toggle Session Sidebar",bindings:[{modifiers:["alt"],key:"b",code:"KeyB"}],action:"toggleSessionSidebar"},{id:"previous-next-session",group:"Session",label:"Previous / Next Session",displayBindings:["Alt/Option+[","Alt/Option+]"]},{id:"switch-tab-n",group:"Session",label:"Switch to Tab N",displayBindings:["Alt/Option+1-9"]},{id:"focus-tabs",group:"Tabs",label:"Focus Tabs",displayBindings:["ArrowLeft","ArrowRight","Home","End"]},{id:"activate-focused-tab",group:"Tabs",label:"Activate Focused Tab",displayBindings:["Enter","Space"]},{id:"insert-newline",group:"Terminal",label:"Insert Newline",displayBindings:["Shift+Enter","Ctrl+Enter"]},{id:"close-panels",group:"Panels",label:"Close Panels",displayBindings:["Escape"]}];class CodemanApp{constructor(){this.sessions=new Map,this._shortIdCache=new Map,this.sessionOrder=[],this.draggedTabId=null,this.cases=[],this.currentRun=null,this.totalTokens=0,this.globalStats=null,this.eventSource=null,this._clientId=typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"c-"+Math.random().toString(36).slice(2)+Date.now().toString(36),this._wsTabNonce=this._clientId,this.terminal=null,this.fitAddon=null,this.activeSessionId=null,this.soloSessionId=this._detectSoloSessionId(),this.isSoloWindow=!!this.soloSessionId,this.detachedSessions=new Set,this.detachedWindows=new Map,this._detachWatchTimers=new Map,this.windowChannel=null,this._redockGrace=new Map,this._detachPingPending=null,this._detachLivenessTimer=null,this._detachOrphanStrikes=new Map,this._initGeneration=0,this._initFallbackTimer=null,this._selectGeneration=0,this._fullHistoryLoaded=new Set,this._fullHistoryRepullAt=new Map,this._fullHistoryRepullInFlight=!1,this._fullHistoryRepullUseless=new Set,this.terminalLoadStates=new Map,this.respawnStatus={},this.respawnTimers={},this.respawnCountdownTimers={},this.respawnActionLogs={},this.timerCountdownInterval=null,this.terminalBuffers=new Map,this.editingSessionId=null,this.pendingCloseSessionId=null,this.muxSessions=[],this.ralphStates=new Map,this.subagents=new Map,this.subagentActivity=new Map,this.subagentToolResults=new Map,this.activeSubagentId=null,this.subagentPanelVisible=!1,this.workflowRuns=new Map,this.workflowRunDetails=new Map,this.activeWorkflowRunId=null,this.activeWorkflowPhaseIndex=null,this.ultracodeWindows=new Map,this.ultracodeWindowsClosed=new Set,this.ultracodeWindowCloseTimers=new Map,this.ultracodeWindowZIndex=1e3,this.subagentWindows=new Map,this.subagentWindowZIndex=ZINDEX_SUBAGENT_BASE,this.minimizedSubagents=new Map,this._subagentHideTimeout=null,this.subagentParentMap=new Map,this.teams=new Map,this.teamTasks=new Map,this.teammateMap=new Map,this.teammatePanesByName=new Map,this.teammateTerminals=new Map,this.terminalBufferCache=new Map,this.ralphStatePanelCollapsed=!0,this.ralphClosedSessions=new Set,this.planSubagents=new Map,this.planSubagentWindowZIndex=ZINDEX_PLAN_SUBAGENT_BASE,this.planGenerationStopped=!1,this.planAgentsMinimized=!1,this.wizardDragState=null,this.wizardDragListeners=null,this.wizardPosition=null,this.projectInsights=new Map,this.logViewerWindows=new Map,this.logViewerWindowZIndex=ZINDEX_LOG_VIEWER_BASE,this.projectInsightsPanelVisible=!1,this.orchestratorState=null,this.orchestratorPanelVisible=!1,this.currentSessionWorkingDir=null,this.imagePopups=new Map,this.imagePopupZIndex=ZINDEX_IMAGE_POPUP_BASE,this.attachmentCards=new Map,this.attachmentCardStack=null,this.attachmentHistoryCounts=new Map,this.attachmentHistoryItems=[],this.attachmentHistoryDrawerOpen=!1,this.fileBrowserData=null,this.fileBrowserExpandedDirs=new Set,this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1,this.fileBrowserDragListeners=null,this.fileBrowserShowHidden=this._loadFileBrowserShowHidden?.()??!1,this.filePreviewContent="",this._toastContainer=null,this._tunnelUrl=null,this.tabAlerts=new Map,this.pendingHooks=new Map,this.approvals=new Map,this._ws=null,this._wsSessionId=null,this._wsReady=!1,this._wsState="disconnected",this._wsLastRecvAt=0,this.pendingWrites=[],this.writeFrameScheduled=!1,this._wasAtBottomBeforeWrite=!0,this.syncWaitTimeout=null,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadSeq=0,this._bufferLoadOwner=null,this.flickerFilterBuffer="",this.flickerFilterActive=!1,this.flickerFilterTimeout=null,this._debounceTimers=Object.create(null),this.systemStatsInterval=null,this.sseReconnectTimeout=null,this._sseListenerCleanup=null,this.reconnectAttempts=0,this.maxReconnectAttempts=10,this.isOnline=navigator.onLine,this._sseLastMessageAt=0,this._sseStaleTimeoutMs=window.CodemanSseStale?.TIMEOUT_MS??45e3,this._sseStaleWatchdog=null,this._connDownSince=null,this._nextSseRetryAt=null,this._offlineOverlayDismissed=!1,this._offlineRetryPending=!1,this._offlineUiTicker=null,this._lastOfflineUiKey="",this._connectionStatus="connected",this._clientId="",this._seqCounters=new Map,this._pendingDeliveries=new Map,this._lastIndicatorDescriptor=null,this._postDraining=new Set,this._persistReliableTimer=null,this._reliableAckTimeoutMs=4e3,this._reliableMaxBytes=256*1024,this._loadReliableState(),this._reliableSweepTimer=setInterval(()=>this._redeliverSweep(),2e3),window.addEventListener("pagehide",()=>this._persistReliableNow()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?this._persistReliableNow():this._checkSseStale()}),this._localEchoOverlay=null,this._localEchoEnabled=!1,this._predictiveEcho=null,this._localEchoPolicy="off",this._restoringFlushedState=!1,this.activeFocusTrap=null,this.notificationManager=new NotificationManager(this),this.idleTimers=new Map,this._elemCache={},this.init()}$(e){return this._elemCache[e]||(this._elemCache[e]=document.getElementById(e)),this._elemCache[e]}_clearTimer(e){this[e]&&(clearTimeout(this[e]),this[e]=null)}_isStaleSelect(e){return e!==this._selectGeneration?(this._isLoadingBuffer&&this._finishBufferLoad(e),this._restoringFlushedState=!1,!0):!1}formatTokens(e){if(e>=1e6){const t=e/1e6;return t>=10?`${t.toFixed(1)}m`:`${t.toFixed(2)}m`}else if(e>=1e3){const t=e/1e3;return t>=100?`${t.toFixed(0)}k`:`${t.toFixed(1)}k`}return String(e)}estimateCost(e,t){const s=e/1e6*15,n=t/1e6*75;return s+n}setPendingHook(e,t){this.pendingHooks.has(e)||this.pendingHooks.set(e,new Set),this.pendingHooks.get(e).add(t),this.updateTabAlertFromHooks(e)}clearPendingHooks(e,t=null){const s=this.pendingHooks.get(e);s&&(t?s.delete(t):s.clear(),s.size===0&&this.pendingHooks.delete(e),this.updateTabAlertFromHooks(e))}markIdleAlertSeen(e){this.pendingHooks?.get(e)?.has("idle_prompt")&&(this.clearPendingHooks(e,"idle_prompt"),this.acknowledgeIdleApprovalOnView?.(e))}updateTabAlertFromHooks(e){const t=this.pendingHooks.get(e);!t||t.size===0?this.tabAlerts.delete(e):t.has("permission_prompt")||t.has("elicitation_dialog")?this.tabAlerts.set(e,"action"):t.has("idle_prompt")&&this.tabAlerts.set(e,"idle"),this.renderSessionTabs()}init(){MobileDetection.init(),this._initWindowChannel(),this.isSoloWindow&&document.body.classList.add("solo-mode"),KeyboardHandler.init(),SwipeHandler.init(),VoiceInput.init(),KeyboardAccessoryBar.init();const e=this.loadAppSettingsFromStorage();KeyboardAccessoryBar.setMode(e.extendedKeyboardBar?"extended":"simple"),this.applyHeaderVisibilitySettings(),this.restorePlanUsageChip(),this.applySkin(),this.applyLocalization(),this.applySessionListLayout(),this.applyMonitorVisibility(),this.applyLineageLineSettings?.(),this._installLineageStripScrollListener?.(),this._setupTabMiddleClickClose(),this.initEntranceAnimations?.(),document.documentElement.classList.remove("mobile-init"),requestAnimationFrame(()=>{this.initTerminal(),this.loadFontSize(),this.connectSSE(),this._initFallbackTimer=setTimeout(()=>{this._initGeneration===0&&this.loadState()},3e3)}),this.registerServiceWorker(),this.loadTunnelStatus();const t=fetch("/api/settings").then(s=>s.ok?s.json():null).then(s=>s?.data??null).catch(()=>null);if(this.loadQuickStartCases(null,t),this._initRunMode(),this.initWebviews?.(),this.setupEventListeners(),MobileDetection.isTouchDevice()){const s=n=>{n&&n.addEventListener("touchstart",i=>{if(!KeyboardHandler.keyboardVisible)return;const o=i.target.closest("button");o&&(i.preventDefault(),o.click(),typeof app<"u"&&app.terminal&&app.terminal.focus())},{passive:!1})};s(document.querySelector(".toolbar")),s(document.querySelector(".welcome-overlay"))}this.setupOnlineDetection(),this.loadAppSettingsFromServer(t).then(()=>{this.applyHeaderVisibilitySettings(),this.applySkin(),this.applyLocalization(),this.applySessionListLayout(),this.applyMonitorVisibility(),this.applyLineageLineSettings?.(),typeof this.syncAllUltracodeFloatingWindows=="function"&&this.syncAllUltracodeFloatingWindows()}),document.body.classList.add("app-loaded")}_initWebGL(){if(!(typeof WebglAddon>"u"))try{this._webglAddon=new WebglAddon.WebglAddon,this._webglAddon.onContextLoss(()=>{console.error("[CRASH-DIAG] WebGL context LOST \u2014 falling back to canvas renderer"),_crashDiag.log("WEBGL_LOST"),this._disableWebGLSticky("context-lost"),this._disposeWebGLObserver(),this._webglAddon?.dispose(),this._webglAddon=null,this._scheduleTerminalRepaint()}),this.terminal.loadAddon(this._webglAddon),console.log("[CRASH-DIAG] WebGL renderer enabled"),this._installWebGLLongTaskGuard()}catch{}}_installWebGLLongTaskGuard(){if(typeof PerformanceObserver>"u"||this._webglLongTaskObserver)return;const e=performance.now(),t=[];try{this._webglLongTaskObserver=new PerformanceObserver(s=>{if(!this._webglAddon)return;const n=performance.now();n-e<WEBGL_FALLBACK.GRACE_MS||evaluateWebGLLongTaskTrip(t,s.getEntries(),n)&&(console.warn(`[CRASH-DIAG] WebGL long-task threshold (${t.length} stalls/${WEBGL_FALLBACK.WINDOW_MS}ms) \u2014 falling back to canvas renderer`),_crashDiag.log(`WEBGL_FALLBACK: ${t.length}`),this._disableWebGLSticky("long-tasks"),this._disposeWebGLObserver(),this._webglAddon?.dispose(),this._webglAddon=null,this._scheduleTerminalRepaint())}),this._webglLongTaskObserver.observe({type:"longtask",buffered:!1})}catch{}}_disposeWebGLObserver(){if(this._webglLongTaskObserver){try{this._webglLongTaskObserver.disconnect()}catch{}this._webglLongTaskObserver=null}}_scheduleTerminalRepaint(){if(this._terminalRepaintScheduled)return;this._terminalRepaintScheduled=!0,(typeof requestAnimationFrame=="function"?requestAnimationFrame:t=>setTimeout(t,0))(()=>{this._terminalRepaintScheduled=!1;try{this.terminal?.refresh(0,this.terminal.rows-1)}catch{}})}_disableWebGLSticky(e){try{localStorage.setItem("codeman-webgl-disabled",JSON.stringify({reason:e,at:Date.now()}))}catch{}}setupEventListeners(){const e={showShortcutOverlay:()=>this.showShortcutOverlay(),killActiveSession:()=>this.killActiveSession(),nextSession:()=>this.nextSession(),clearTerminal:()=>this.clearTerminal(),restoreTerminalSize:()=>this.restoreTerminalSize(),increaseFontSize:()=>this.increaseFontSize(),decreaseFontSize:()=>this.decreaseFontSize(),toggleVoiceInput:()=>VoiceInput.toggle(),moveActiveTabLeft:()=>this.moveActiveTabLeft(),moveActiveTabRight:()=>this.moveActiveTabRight(),toggleSessionSidebar:()=>this.toggleSessionSidebar()};document.addEventListener("keydown",s=>{if(!(s.isComposing||s.keyCode===229)){if(this.shouldOpenCommandPaletteFromShortcut?.(s)){s.preventDefault(),this.openCommandPalette();return}if(s.key==="Escape"&&(this.closeAllPanels(),this.closeHelp(),this.attachmentHistoryDrawerOpen&&this.closeAttachmentHistory(),this.closeSessionManager(),this.closeCommandPalette?.(),this.closeShortcutOverlay?.(),this._isSessionSidebarOverlay()&&this.isSessionSidebarActive()&&!this.isSessionSidebarCollapsed()&&(this.toggleSessionSidebar(),document.getElementById("sidebarToggleBtn")?.focus())),s.altKey&&!s.ctrlKey&&!s.shiftKey){const i=(s.code||"").match(/^Digit([1-9])$/);if(i){const o=parseInt(i[1],10)-1,r=this.sessionOrder.filter(a=>this.sessions.has(a));if(o<r.length)s.preventDefault(),this.selectSession(r[o]);else{const a=o-r.length,l=(this.webviewOrder||[])[a];l&&(s.preventDefault(),this.openWebview(l))}return}if(s.code==="BracketLeft"){s.preventDefault(),this.prevSession();return}if(s.code==="BracketRight"){s.preventDefault(),this.nextSession();return}}if(!(!s.ctrlKey&&!s.metaKey&&!s.altKey))for(const n of this.getShortcutRegistry()){if(n.disabled||!n.action)continue;const i=e[n.action];if(i&&this.matchesShortcutEvent(s,n)){s.preventDefault(),i();return}}}},!0);const t=this.$("headerTokens");t&&!t._statsHandlerAttached&&(t.classList.add("clickable"),t._statsHandlerAttached=!0,t.addEventListener("click",()=>this.openTokenStats())),this.setupColorPicker()}_updateSseSubscription(e){try{const t=JSON.stringify({clientId:this._clientId,sessions:e?[e]:null});fetch("/api/events/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:t,keepalive:!0}).catch(()=>{})}catch{}}_detectSoloSessionId(){try{if(typeof window<"u"&&typeof window.__CODEMAN_SOLO__=="string"&&window.__CODEMAN_SOLO__)return window.__CODEMAN_SOLO__;const e=location.pathname.match(/^\/session\/([^/]+)\/?$/);return e?decodeURIComponent(e[1]):null}catch{return null}}detachSession(e){if(this.isSoloWindow||!this.sessions.has(e)||this.detachedSessions.has(e)&&this._raiseDetached(e))return;const t="width=960,height=680,menubar=no,toolbar=no,location=no,status=no";let s=null;try{s=window.open("/session/"+encodeURIComponent(e),"codeman-session-"+e,t)}catch{}if(!s){this.showToast?.("Pop-out blocked \u2014 allow popups for this site to detach a session","error");return}this.detachedWindows.set(e,s),this._markDetached(e,!0),this._watchDetachedWindow(e,s),this._postWindowMessage({type:"detached",id:e});try{s.focus()}catch{}}_raiseDetached(e){const t=this.detachedWindows.get(e);if(t&&!t.closed){try{t.focus()}catch{}return!0}return t&&t.closed?(this._redock(e),!1):(this._postWindowMessage({type:"focus-request",id:e}),!0)}redockSession(e){const t=this.detachedWindows.get(e);if(t&&!t.closed)try{t.close()}catch{}this._postWindowMessage({type:"close-request",id:e}),this._redock(e)}_redock(e){const t=this._detachWatchTimers.get(e);t&&(clearInterval(t),this._detachWatchTimers.delete(e)),this._cancelPendingRedock(e),this._detachOrphanStrikes.delete(e),this.detachedWindows.delete(e),this._markDetached(e,!1)}_scheduleRedock(e){if(this._redockGrace.has(e))return;const t=setTimeout(()=>{this._redockGrace.delete(e),this._redock(e)},1500);this._redockGrace.set(e,t)}_cancelPendingRedock(e){const t=this._redockGrace.get(e);t&&(clearTimeout(t),this._redockGrace.delete(e))}_markDetached(e,t){t?this.detachedSessions.add(e):this.detachedSessions.delete(e);const s=this.$("sessionTabs"),n=s&&s.querySelector(`.session-tab[data-id="${e}"]`);n&&n.classList.toggle("detached",t)}_watchDetachedWindow(e,t){const s=this._detachWatchTimers.get(e);s&&clearInterval(s);const n=setInterval(()=>{(!t||t.closed)&&(clearInterval(n),this._detachWatchTimers.delete(e),this._redock(e))},800);this._detachWatchTimers.set(e,n)}_initWindowChannel(){if(!(typeof BroadcastChannel>"u")){try{this.windowChannel=new BroadcastChannel("codeman-windows")}catch{this.windowChannel=null;return}if(this.windowChannel.onmessage=e=>this._onWindowMessage(e.data),this.isSoloWindow){this._postWindowMessage({type:"detached",id:this.soloSessionId});const e=()=>this._postWindowMessage({type:"redocked",id:this.soloSessionId});window.addEventListener("pagehide",e),window.addEventListener("beforeunload",e)}else this._postWindowMessage({type:"roll-call"}),this._startDetachLiveness()}}_postWindowMessage(e){try{this.windowChannel&&this.windowChannel.postMessage(e)}catch{}}_onWindowMessage(e){if(!(!e||typeof e!="object")){if(this.isSoloWindow){if(e.type==="roll-call"){this._postWindowMessage({type:"detached",id:this.soloSessionId});return}if(e.id!==this.soloSessionId)return;if(e.type==="close-request")try{window.close()}catch{}else if(e.type==="focus-request")try{window.focus()}catch{}return}e.type==="detached"&&e.id?(this._cancelPendingRedock(e.id),this._detachPingPending?.delete(e.id),this._detachOrphanStrikes.delete(e.id),this._markDetached(e.id,!0)):e.type==="redocked"&&e.id?this._scheduleRedock(e.id):e.type==="detach-request"&&e.id&&this.detachSession(e.id)}}_startDetachLiveness(){this._detachLivenessTimer||(this._detachLivenessTimer=setInterval(()=>this._pingDetached(),5e3))}_pingDetached(){const e=[];for(const t of this.detachedSessions){const s=this.detachedWindows.get(t);s?s.closed&&this._redock(t):e.push(t)}e.length&&(this._detachPingPending=new Set(e),this._postWindowMessage({type:"roll-call"}),setTimeout(()=>{if(this._detachPingPending){for(const t of this._detachPingPending){const s=(this._detachOrphanStrikes.get(t)||0)+1;s>=2?(this._detachOrphanStrikes.delete(t),this._redock(t)):this._detachOrphanStrikes.set(t,s)}this._detachPingPending=null}},1200))}_applySoloMode(){document.body.classList.add("solo-mode");const e=this.sessions.get(this.soloSessionId);if(!e){this._showSoloSessionGone();return}this.activeSessionId=null,this.selectSession(this.soloSessionId,{auto:!0});const t=this.getSessionName(e)||"Session",s=document.getElementById("soloSessionTitle");s&&(s.textContent=t,s.style.display="");const n=document.getElementById("soloRedockBtn");n&&(n.style.display=""),document.title=t+" \u2014 "+(window.CodemanI18n?.displayName||"Codeman"),this.notificationManager&&(this.notificationManager.originalTitle=document.title);const i=document.querySelector(".header-brand .logo");i&&(i.onclick=o=>{o.preventDefault()})}_showSoloSessionGone(){if(document.body.classList.add("solo-mode"),document.querySelector(".solo-gone-overlay"))return;const e=document.createElement("div");e.className="solo-gone-overlay",e.innerHTML='<h2>Session unavailable</h2><p>This session has ended or is no longer available.</p><button class="btn-primary" onclick="window.close()">Close window</button>',document.body.appendChild(e),document.title=(window.codemanT?.("Session ended")||"Session ended")+" \u2014 "+(window.CodemanI18n?.displayName||"Codeman")}connectSSE(){if(!navigator.onLine){this.setConnectionStatus("offline");return}this._clearTimer("sseReconnectTimeout"),this._sseStaleWatchdog&&(clearInterval(this._sseStaleWatchdog),this._sseStaleWatchdog=null),this._sseListenerCleanup&&(this._sseListenerCleanup(),this._sseListenerCleanup=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.reconnectAttempts===0?this.setConnectionStatus("connecting"):this.setConnectionStatus("reconnecting");const e=new URLSearchParams({clientId:this._clientId});this.activeSessionId&&e.set("sessions",this.activeSessionId),this.eventSource=new EventSource(`/api/events?${e.toString()}`);const t=[],s=(n,i)=>{const o=r=>{this._sseLastMessageAt=Date.now(),i(r)};this.eventSource.addEventListener(n,o),t.push({event:n,handler:o})};if(this._sseListenerCleanup=()=>{for(const{event:n,handler:i}of t)this.eventSource&&this.eventSource.removeEventListener(n,i);t.length=0},this.eventSource.onopen=()=>{this.reconnectAttempts=0,this._sseLastMessageAt=Date.now(),this.setConnectionStatus("connected")},this.eventSource.onerror=()=>{this.reconnectAttempts++,this.reconnectAttempts>=this.maxReconnectAttempts?this.setConnectionStatus("disconnected"):this.setConnectionStatus("reconnecting"),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this._clearTimer("sseReconnectTimeout");const n=this.reconnectAttempts<=1?200:Math.min(500*Math.pow(2,this.reconnectAttempts-2),3e4);this._nextSseRetryAt=Date.now()+n,this._updateConnectionLossUi(),this.sseReconnectTimeout=setTimeout(()=>this.connectSSE(),n)},!this._sseHandlerWrappers){this._sseHandlerWrappers=new Map;for(const[n,i]of _SSE_HANDLER_MAP){const o=this[i];this._sseHandlerWrappers.set(n,r=>{try{o.call(this,r.data?JSON.parse(r.data):{})}catch(a){console.error(`[SSE] Error handling ${n}:`,a)}})}}for(const[n]of _SSE_HANDLER_MAP)s(n,this._sseHandlerWrappers.get(n));for(const n of[SSE_EVENTS.SESSION_CREATED,SSE_EVENTS.SESSION_DELETED])s(n,()=>this._onSessionListMaybeChanged());s(SSE_EVENTS.DOCKER_EXPORT_COMPLETE,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Docker export ready: ${i.bundle} (${Math.round((i.sizeBytes||0)/1e6)} MB)`,"success"),this.refreshDockerExports?.()}catch(i){console.error("[SSE] docker export complete:",i)}}),s(SSE_EVENTS.DOCKER_EXPORT_FAILED,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Docker export failed: ${i.error||"unknown error"}`,"error")}catch(i){console.error("[SSE] docker export failed:",i)}}),s(SSE_EVENTS.DOCKER_IMPORT_COMPLETE,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Docker bundle imported as case "${i.name}"`,"success"),this.loadQuickStartCases?.(),this.refreshDockerExports?.()}catch(i){console.error("[SSE] docker import complete:",i)}}),s(SSE_EVENTS.DOCKER_CONTAINER_RECREATED,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Container for "${i.name}" removed \u2014 next launch recreates it with the new config`,"info")}catch(i){console.error("[SSE] docker container recreated:",i)}}),s(SSE_EVENTS.ADMIN_USERS_CHANGED,()=>{window.codemanAdmin?.onUsersChanged?.()}),s(SSE_EVENTS.DOCKER_IMAGE_BUILD_STARTED,()=>{this.showToast("Building the Codeman agent image (first Docker case, a few minutes)...","info",{duration:8e3})}),s(SSE_EVENTS.DOCKER_IMAGE_BUILD_COMPLETE,n=>{try{const i=n.data?JSON.parse(n.data):{};i.error?this.showToast(`Agent image build failed: ${i.error}`,"error"):this.showToast("Agent image ready. Starting the container...","success")}catch(i){console.error("[SSE] docker image build complete:",i)}}),s(SSE_EVENTS.DOCKER_IMAGE_BUILD_FAILED,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Agent image build failed: ${i.error||"unknown error"}`,"error")}catch(i){console.error("[SSE] docker image build failed:",i)}}),s(SSE_EVENTS.SESSION_PINNED,n=>{let i=null;try{i=JSON.parse(n.data)}catch{}if(i&&i.id){const o=this.sessions.get(i.id);o&&(o.pinned=i.pinned===!0,o.pinnedAt=i.pinned?i.pinnedAt:void 0)}this._onSessionListMaybeChanged()}),s(SSE_EVENTS.HEARTBEAT,()=>{}),this._sseStaleWatchdog=setInterval(()=>this._checkSseStale(),5e3)}_checkSseStale(){const e=window.CodemanSseStale;if(!e)return;const t=Date.now();e.compute({lastMessageAt:this._sseLastMessageAt,now:t,status:this._connectionStatus,isOnline:this.isOnline,timeoutMs:this._sseStaleTimeoutMs})&&(console.log(`[SSE] stream stale: no frame for ${t-this._sseLastMessageAt}ms (threshold ${this._sseStaleTimeoutMs}ms), forcing reconnect`),this.connectSSE())}_onInit(e){_crashDiag.log(`INIT: ${e.sessions?.length||0} sessions`),this.handleInit(e)}_onSessionCreated(e){this.sessions.set(e.id,e),this.sessionOrder.includes(e.id)||(this.sessionOrder.push(e.id),this.saveSessionOrder()),this.markSessionTabEntering?.(e.id),this.markTerminalEntering?.(e.id),e.parentSessionId&&this.markConnectionLineEntering?.("lineage:"+e.id),this.renderSessionTabs(),this.updateCost(),this.sessions.size===1&&this.startSystemStatsPolling()}_onSessionUpdated(e){const t=e.session||e,s=this.sessions.get(t.id),n=t.claudeSessionId&&(!s||!s.claudeSessionId);this.sessions.set(t.id,t),this.renderSessionTabs(),this.updateCost(),t.id===this.activeSessionId&&t.tokens&&this.updateRespawnTokens(t.tokens),this.updateSubagentParentNames(t.id),n&&(this.recheckOrphanSubagents(),requestAnimationFrame(()=>{this.updateConnectionLines()}))}_onSessionDeleted(e){if(this._wsSessionId===e.id&&this._disconnectWs(),this.isSoloWindow&&e.id===this.soloSessionId&&this._showSoloSessionGone(),this.detachedSessions.has(e.id)&&this._redock(e.id),this._cleanupSessionData(e.id),this.activeSessionId===e.id){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.terminal.clear(),this.showWelcome()}this.renderSessionTabs(),this.renderRalphStatePanel(),this.renderProjectInsightsPanel(),this.sessions.size===0&&this.stopSystemStatsPolling()}_onSSETerminal(e){this._wsReady&&this._wsSessionId===e.id||this._onSessionTerminal(e)}_onSSENeedsRefresh(e){this._wsReady&&this._wsSessionId===e?.id||this._onSessionNeedsRefresh(e)}_onSSEClearTerminal(e){this._wsReady&&this._wsSessionId===e?.id||this._onSessionClearTerminal(e)}_onSessionTerminal(e){if(e.id===this.activeSessionId){if(e.data.length>32768&&_crashDiag.log(`TERMINAL: ${(e.data.length/1024).toFixed(0)}KB`),(this.pendingWrites?.reduce((s,n)=>s+n.length,0)||0)+(this.flickerFilterBuffer?.length||0)>131072){this._clientDropRecoveryTimer||(this._clientDropRecoveryTimer=setTimeout(()=>{this._clientDropRecoveryTimer=null,this._onSessionNeedsRefresh()},2e3));return}this.batchTerminalWrite(e.data)}}_sanitizeHtml(e){return typeof window<"u"&&typeof window.sanitizeMarkdownHtml=="function"?window.sanitizeMarkdownHtml(e):String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}_cleanTerminalBuffer(e){const t=e.replace(/\x1b\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]/g,"").replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,"").replace(/\x1b[PX^_][^\x1b]*\x1b\\/g,"").replace(/\x1b[NO()][A-Z0-9]?/g,"").replace(/\x1b[>=<78cDEHM]/g,"").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"").replace(/\r\n/g,`
|
|
8
|
+
`).replace(/\r/g,`
|
|
9
|
+
`),s=[/^\s*❯\s*/,/^\s*[⏵⏺⏸⏹]+\s*/,/^\s*✻\s*(Crunching|Crunched|Thinking)/i,/bypass permissions/i,/\bshift\+tab to cycle\b/i,/^\s*focus\s*$/,/^\s*new task\?/i,/\/clear to save/i,/^\s*─{5,}\s*$/,/\[(Opus|Sonnet|Haiku|GPT|Claude)[\s\S]*(tokens?|\$|¥|%|↑|↓)/i,/^\s*\[\d+[km]?\/\d+[km]?\]/i,/[█░▓▒]{3,}/,/^\s*\(.*\s*(tokens?|context).*\)\s*$/i];return t.split(`
|
|
10
|
+
`).filter(o=>o.trim()?!s.some(a=>a.test(o)):!0).join(`
|
|
11
|
+
`).replace(/[ \t]+$/gm,"").replace(/\n{4,}/g,`
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
`).trim()}_preprocessAsciiArt(e){const t=/[─-╿▀-▟]/,s=/```[\s\S]*?```/g,n=[];return e.replace(s,r=>(n.push(r),`__CODEMAN_FENCE_${n.length-1}__`)).split(/(\n{2,})/).map(r=>/^\n{2,}$/.test(r)||!r.trim()||r.includes("__CODEMAN_FENCE_")?r:t.test(r)?"\n```\n"+r+"\n```\n":r).join("").replace(/__CODEMAN_FENCE_(\d+)__/g,(r,a)=>n[Number(a)])}_renderMarkdown(e){const t=e||"";if(typeof marked<"u"&&marked.parse)try{const n=this._preprocessAsciiArt(t);let i=this._sanitizeHtml(marked.parse(n,{breaks:!0,gfm:!0}));i=i.replace(/<table>/g,'<div class="rv-table-wrap"><table>').replace(/<\/table>/g,"</table></div>");const o=/[─-╿▀-▟]/,r=document.createElement("template");return r.innerHTML=i,r.content.querySelectorAll("pre > code").forEach(a=>{const l=a.parentElement,c=o.test(a.textContent||""),d=document.createElement("div");d.className=c?"rv-code-wrap rv-diagram-wrap":"rv-code-wrap";const E=document.createElement("div");E.className="rv-code-actions";const p=document.createElement("button");if(p.className="rv-copy-btn",p.type="button",p.setAttribute("aria-label","Copy code"),p.setAttribute("title","Copy code"),E.appendChild(p),c){l.classList.add("rv-diagram");const S=document.createElement("button");S.className="rv-wrap-toggle",S.type="button",S.setAttribute("aria-label","Toggle line wrapping"),S.setAttribute("title","Toggle line wrapping"),E.appendChild(S)}l.parentNode.insertBefore(d,l),d.appendChild(E),d.appendChild(l)}),r.innerHTML}catch{}return`<pre style="white-space:pre-wrap;word-break:break-word">${t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</pre>`}_bindResponseViewerInteractions(e){!e||e.dataset.rvBound==="1"||(e.dataset.rvBound="1",e.addEventListener("click",async t=>{const s=t.target.closest("a.rv-path");if(s){t.preventDefault(),t.stopPropagation();const l=s.dataset.path;l&&this.openFilePreview(l,this.activeSessionId);return}const n=t.target.closest(".rv-copy-btn");if(n){t.preventDefault(),t.stopPropagation();const l=n.closest(".rv-code-wrap")?.querySelector("pre code"),c=l?await this._copyText(l.textContent||""):!1;n.classList.remove("rv-copied","rv-copy-failed"),n.classList.add(c?"rv-copied":"rv-copy-failed"),clearTimeout(n._resetTimer),n._resetTimer=setTimeout(()=>{n.classList.remove("rv-copied","rv-copy-failed")},1500);return}const i=t.target.closest(".rv-wrap-toggle");if(!i)return;t.preventDefault(),t.stopPropagation();const o=i.closest(".rv-diagram-wrap"),r=o?.querySelector("pre.rv-diagram");if(!r||!o)return;const a=r.classList.toggle("rv-nowrap");o.classList.toggle("rv-wrap-nowrap",a)}))}async _copyText(e){if(!e)return!1;try{if(navigator.clipboard?.writeText)return await navigator.clipboard.writeText(e),!0}catch{}try{const t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.cssText="position:fixed;top:0;left:0;opacity:0;pointer-events:none",document.body.appendChild(t),t.select();const s=document.execCommand("copy");return document.body.removeChild(t),s}catch{return!1}}_buildResponseViewerMessage(e,t,s){const n=document.createElement("div"),i=t==="user";n.className="rv-message "+(i?"rv-msg-user":"rv-msg-assistant");const o=document.createElement("div");o.className="rv-role "+(i?"rv-role-user":"rv-role-assistant"),o.textContent=i?"You":s,n.appendChild(o);const r=document.createElement("div");return r.className="rv-text",r.innerHTML=this._renderMarkdown(e),this._linkifyFilePaths(r),n.appendChild(r),n}_linkifyFilePaths(e){if(!e||typeof document>"u"||typeof absoluteFilePathPattern!="function")return;const t=absoluteFilePathPattern(),s=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];for(let i=s.nextNode();i;i=s.nextNode())i.parentElement?.closest("a")||(t.lastIndex=0,t.test(i.nodeValue||"")&&n.push(i));for(const i of n){const o=i.nodeValue,r=document.createDocumentFragment();let a=0,l;for(t.lastIndex=0;(l=t.exec(o))!==null;){const c=l[1];l.index>a&&r.appendChild(document.createTextNode(o.slice(a,l.index)));const d=document.createElement("a");d.className="rv-path",d.href="#",d.dataset.path=c,d.title=c,d.textContent=c,r.appendChild(d),a=l.index+c.length}a<o.length&&r.appendChild(document.createTextNode(o.slice(a))),i.parentNode?.replaceChild(r,i)}}_getResponseViewerAgentLabel(){const e=this.sessions.get(this.activeSessionId)?.mode;return e==="codex"?"Codex":e==="gemini"?"Gemini":e==="antigravity"?"Antigravity":e==="pi"?"Pi":e==="opencode"?"OpenCode":"Claude"}async toggleResponseViewer(){const e=document.getElementById("responseViewer"),t=document.getElementById("responseViewerBackdrop");if(!e)return;if(e.classList.contains("visible")){e.classList.remove("visible"),t.classList.remove("visible");return}if(this.activeSessionId)try{let o=((await(await fetch(`/api/sessions/${this.activeSessionId}/last-response`)).json())?.data??{}).text||"";const r=this.sessions.get(this.activeSessionId)?.mode||"claude";if(!o&&(r==="claude"||r==="shell")){const E=(await(await fetch(`/api/sessions/${this.activeSessionId}/terminal`)).json())?.data??{};E.terminalBuffer&&(o=this._cleanTerminalBuffer(E.terminalBuffer))}const a=document.getElementById("responseViewerBody");o?(a.innerHTML="",a.appendChild(this._buildResponseViewerMessage(o,"assistant",this._getResponseViewerAgentLabel())),this._bindResponseViewerInteractions(a)):a.textContent=window.codemanT?.("No response yet \u2014 send a message in this session first.")||"No response yet \u2014 send a message in this session first.";const l=document.getElementById("responseViewerTitle"),c=document.getElementById("responseViewerMore");l&&(l.textContent="Last Response"),c&&(c.style.display="",c.textContent="More"),e.classList.add("visible"),t.classList.add("visible"),a.scrollTop=0}catch(n){console.error("Failed to load response:",n)}}async loadFullContext(){if(!this.activeSessionId)return;const e=document.getElementById("responseViewerMore");e&&(e.textContent="...");try{const n=((await(await fetch(`/api/sessions/${this.activeSessionId}/last-response?context=full`)).json())?.data??{}).messages||[],i=document.getElementById("responseViewerBody"),o=document.getElementById("responseViewerTitle");if(!i)return;if(n.length===0){i.textContent="No conversation history available";return}const r=this._getResponseViewerAgentLabel();i.innerHTML="";for(const a of n)i.appendChild(this._buildResponseViewerMessage(a.text,a.role,r));this._bindResponseViewerInteractions(i),o&&(o.textContent=`Conversation (${n.length} messages)`),e&&(e.style.display="none"),i.scrollTop=i.scrollHeight}catch(t){console.error("Failed to load context:",t)}finally{e&&(e.textContent="More")}}async _onSessionNeedsRefresh(){if(!this.activeSessionId||!this.terminal||this._isLoadingBuffer)return;const e=this.activeSessionId;try{let t=await fetch(`/api/sessions/${e}/terminal?full=1`),s=(await t.json())?.data??{};if(s.terminalBuffer&&this._replayWouldShrinkBuffer(s.terminalBuffer)&&(t=await fetch(`/api/sessions/${e}/terminal?tail=${TERMINAL_TAIL_SIZE}`),s=(await t.json())?.data??{}),this.activeSessionId!==e)return;if(s.terminalBuffer){const n=this.terminal.buffer?.active,i=n?Math.max(0,(n.baseY||0)-(n.viewportY||0)):0;this.terminal.clear(),this.terminal.reset(),await this.chunkedTerminalWrite(s.terminalBuffer),this._setHistoryTruncation(e,s);const o=computeRewriteScrollLine({linesFromBottom:i,baseY:this.terminal.buffer?.active?.baseY??0});o===null||typeof this.terminal.scrollToLine!="function"?this.terminal.scrollToBottom():this.terminal.scrollToLine(o),this._localEchoOverlay?.rerender(),this.activeSessionId&&this.sendResize(this.activeSessionId)}}catch(t){console.error("needsRefresh reload failed:",t)}}async _onSessionClearTerminal(e){if(e.id===this.activeSessionId){if(this._isLoadingBuffer)return;try{const s=(await(await fetch(`/api/sessions/${e.id}/terminal`)).json())?.data??{};if(this.terminal.clear(),this.terminal.reset(),s.terminalBuffer){const n=s.terminalBuffer.replace(DEC_SYNC_STRIP_RE,"");await this.chunkedTerminalWrite(n)}this.sendResize(e.id),this._localEchoOverlay?.rerender()}catch(t){console.error("clearTerminal refresh failed:",t)}}}_onSessionCompletion(e){this.totalCost+=e.cost||0,this.updateCost(),e.id===this.activeSessionId&&(this.terminal.writeln(""),this.terminal.writeln(`\x1B[1;32m Done (Cost: $${(e.cost||0).toFixed(4)})\x1B[0m`))}_onSessionError(e){e.id===this.activeSessionId&&this.terminal.writeln(`\x1B[1;31m Error: ${e.error}\x1B[0m`),this._notifySession(e.id,"critical","session-error","Session Error",e.error||"Unknown error")}_onSessionExit(e){this._wsSessionId===e.id&&this._disconnectWs();const t=this.sessions.get(e.id);t&&(t.status="stopped",this.renderSessionTabs(),e.id===this.activeSessionId&&this._updateLocalEchoState()),e.code&&e.code!==0&&this._notifySession(e.id,"critical","session-crash","Session Crashed",`Exited with code ${e.code}`)}_onSessionIdle(e){const t=this.sessions.get(e.id);if(t&&(t.status="idle",this.renderSessionTabs(),this.sendPendingCtrlL(e.id),e.id===this.activeSessionId&&this._updateLocalEchoState()),!this.respawnStatus[e.id]?.enabled){const s=this.notificationManager?.preferences?.stuckThresholdMs||6e5;clearTimeout(this.idleTimers.get(e.id)),this.idleTimers.set(e.id,setTimeout(()=>{this._notifySession(e.id,"warning","session-stuck","Session Idle",`Idle for ${Math.round(s/6e4)}+ minutes`),this.idleTimers.delete(e.id)},s))}}_onSessionWorking(e){const t=this.sessions.get(e.id);t&&(t.status="busy",this.pendingHooks.has(e.id)||this.tabAlerts.delete(e.id),this.renderSessionTabs(),this.sendPendingCtrlL(e.id),e.id===this.activeSessionId&&this._updateLocalEchoState());const s=this.idleTimers.get(e.id);s&&(clearTimeout(s),this.idleTimers.delete(e.id))}_onSessionAutoClear(e){e.sessionId===this.activeSessionId&&(this.showToast(`Auto-cleared at ${e.tokens.toLocaleString()} tokens`,"info"),this.updateRespawnTokens(0)),this._notifySession(e.sessionId,"info","auto-clear","Auto-Cleared",`Context reset at ${(e.tokens||0).toLocaleString()} tokens`)}_onSessionLimitPauseScheduled(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=e.resumeAt);const s=new Date(e.resumeAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});e.sessionId===this.activeSessionId&&this.showToast(`Usage limit reached \u2014 auto-resume at ${s}`,"warning"),this._notifySession(e.sessionId,"warning","limit-pause","Usage Limit Reached",`Auto-resume scheduled for ${s}`),this.updateAutoResumeStatus(e.sessionId)}_onSessionLimitResume(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=void 0),e.sessionId===this.activeSessionId&&this.showToast("Usage limit reset \u2014 work resumed automatically","success"),this._notifySession(e.sessionId,"info","limit-resume","Auto-Resumed","Usage limit reset \u2014 continuing work"),this.updateAutoResumeStatus(e.sessionId)}_onSessionLimitResumeCancelled(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=void 0),this.updateAutoResumeStatus(e.sessionId)}_onSessionRespawnBreakerTripped(e){const s=this.sessions.get(e.sessionId)?.name||"Session";this.showToast?.(`${s} stopped: repeated crashes detected. Restart to retry.`,"error")}_onSessionCliInfo(e){const t=this.sessions.get(e.sessionId);t&&(e.version&&(t.cliVersion=e.version),e.model&&(t.cliModel=e.model),e.accountType&&(t.cliAccountType=e.accountType),e.latestVersion&&(t.cliLatestVersion=e.latestVersion)),e.sessionId===this.activeSessionId&&this.updateCliInfoDisplay()}_onSessionStatusTelemetry(e){this.updatePlanUsageChip(e);try{localStorage.setItem("codeman:planUsage",JSON.stringify({t:Date.now(),data:e}))}catch{}}restorePlanUsageChip(){try{const e=localStorage.getItem("codeman:planUsage");if(!e)return;const t=JSON.parse(e);t?.data&&Date.now()-(t.t||0)<12*3600*1e3&&this.updatePlanUsageChip(t.data)}catch{}}updatePlanUsageChip(e){const t=document.getElementById("planUsageChip");if(!t||!e)return;const s=l=>l&&typeof l.usedPercentage=="number"?Math.round(l.usedPercentage):null,n=s(e.fiveHour),i=s(e.sevenDay);if(n===null&&i===null)return;const o=l=>l>=85?"pu-red":l>=60?"pu-yellow":"pu-green",r=(l,c)=>{if(c===null)return"";const d=Math.round(Number(c));return Number.isFinite(d)?`<span class="pu-win"><span class="pu-label">${l}</span><span class="pu-val ${o(d)}">${d}%</span></span>`:""};t.innerHTML=[r("5h",n),r("7d",i)].filter(Boolean).join('<span class="pu-sep">\xB7</span>');const a=l=>l&&l.resetAt?new Date(l.resetAt).toLocaleString():"\u2014";t.title=`Claude plan usage
|
|
15
|
+
5-hour limit: ${n??"\u2014"}% used (resets ${a(e.fiveHour)})
|
|
16
|
+
Weekly limit: ${i??"\u2014"}% used (resets ${a(e.sevenDay)})`}_onScheduledCreated(e){this.currentRun=e,this.showTimer()}_onScheduledUpdated(e){this.currentRun=e,this.updateTimer()}_onScheduledCompleted(e){this.currentRun=e,this.hideTimer(),this.showToast("Scheduled run completed!","success")}_onScheduledStopped(){this.currentRun=null,this.hideTimer()}setConnectionStatus(e){this._connectionStatus=e,e==="connected"?(this._connDownSince=null,this._nextSseRetryAt=null,this._offlineOverlayDismissed=!1):this._connDownSince===null&&(this._connDownSince=Date.now()),this._updateConnectionIndicator(),this._updateConnectionLossUi(),e==="connected"&&this._redeliverSweep()}_connectWs(e){this._disconnectWs(),this._wsState="connecting",this._updateConnectionIndicator();const t=location.protocol==="https:"?"wss:":"ws:",s=this._clientId?`${this._clientId}:${this._wsTabNonce}`:"",n=s?`?cid=${encodeURIComponent(s)}`:"",i=`${t}//${location.host}/ws/sessions/${e}/terminal${n}`,o=new WebSocket(i);this._ws=o,this._wsSessionId=e,o.onopen=()=>{this._ws===o&&(this._wsReady=!0,this._wsState="connected",this._wsReconnectAttempts=0,this._updateConnectionIndicator(),this.sendResize(e)?.catch?.(()=>{}),this._startMobileResizeRetry(e),this._onWsReady(e))},o.onmessage=r=>{if(this._ws===o){this._wsLastRecvAt=Date.now();try{const a=JSON.parse(r.data);a.t==="o"?this._onSessionTerminal({id:e,data:a.d}):a.t==="c"?this._onSessionClearTerminal({id:e}):a.t==="r"?this._onSessionNeedsRefresh({id:e}):a.t==="ia"&&this._onWsInputAck(a.seq)}catch{}}},o.onclose=r=>{if(this._ws!==o)return;this._ws=null,this._wsSessionId=null,this._wsReady=!1,this._stopMobileResizeRetry();const a=window.CodemanWsReconnect.plan(r.code,this._wsReconnectAttempts||0);_crashDiag.log(`WS CLOSE code=${r.code} reason=${r.reason||""} action=${a.action} attempts=${this._wsReconnectAttempts||0}`);const l=this.activeSessionId===e;if(a.action==="give-up")this._wsState=l?"fallback":"disconnected",this._updateConnectionIndicator();else if(a.action==="reconnect")if(l){this._wsState="reconnecting",this._updateConnectionIndicator();const c=a.delayMs+Math.floor(Math.random()*250);this._wsReconnectAttempts=(this._wsReconnectAttempts||0)+1,this._wsReconnectTimer=setTimeout(()=>{this._wsReconnectTimer=null,this.activeSessionId===e&&this._connectWs(e)},c)}else this._wsState="disconnected",this._updateConnectionIndicator();else this._wsState=l?"fallback":"disconnected",this._updateConnectionIndicator(),l&&(this._wsReconnectAttempts=(this._wsReconnectAttempts||0)+1,this._wsReconnectTimer=setTimeout(()=>{this._wsReconnectTimer=null,this.activeSessionId===e&&this._connectWs(e)},a.delayMs))},o.onerror=()=>{}}_disconnectWs(){this._clearTimer("_wsReconnectTimer"),this._wsState="disconnected",this._stopMobileResizeRetry(),this._ws&&(this._ws.onclose=null,this._ws.close(),this._ws=null,this._wsSessionId=null,this._wsReady=!1)}_startMobileResizeRetry(e){this._stopMobileResizeRetry(),(typeof MobileDetection<"u"&&MobileDetection.getDeviceType?MobileDetection.getDeviceType():"desktop")!=="desktop"&&(this._mobileResizeRetryTimer=setInterval(()=>{document.visibilityState==="visible"&&(!this._wsReady||this._wsSessionId!==e||typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible||this.sendResize(e)?.catch?.(()=>{}))},MOBILE_RESIZE_RETRY_MS))}_stopMobileResizeRetry(){this._mobileResizeRetryTimer&&(clearInterval(this._mobileResizeRetryTimer),this._mobileResizeRetryTimer=null)}_sendInputAsync(e,t,s){!e||!t||this._reliableSend(e,t,s?.useMux===!0)}_sendInputEphemeral(e,t){if(!(!e||!t)){if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e)try{this._ws.send(JSON.stringify({t:"i",d:t}));return}catch{}try{fetch(`/api/sessions/${e}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:t}),keepalive:!0}).catch(()=>{})}catch{}}}_reliableSend(e,t,s){const i={seq:this._nextSeq(e),data:t,useMux:!!s,ts:Date.now(),tries:0,sentAt:0};let o=this._pendingDeliveries.get(e);o||(o=[],this._pendingDeliveries.set(e,o)),o.push(i),this._persistReliableState(),this._updateConnectionIndicator(),this._drainSession(e)}_nextSeq(e){const t=(this._seqCounters.get(e)||0)+1;return this._seqCounters.set(e,t),t}_drainSession(e){const t=this._pendingDeliveries.get(e);if(!(!t||t.length===0)){if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e){for(const s of t)if(s.sentAt===0)try{this._ws.send(JSON.stringify({t:"i",d:s.data,seq:s.seq,cid:this._clientId})),s.sentAt=Date.now(),s.tries++}catch{break}return}this._postDraining.has(e)||(this._postDraining.add(e),(async()=>{try{for(;;){const s=this._pendingDeliveries.get(e);if(!s||s.length===0||this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e)break;const n=s[0];n.tries++,n.sentAt=Date.now();let i=null;try{const o={input:n.data,seq:n.seq,clientId:this._clientId};n.useMux&&(o.useMux=!0),i=await fetch(`/api/sessions/${e}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o),keepalive:n.data.length<65536})}catch{i=null}if(i&&i.ok)this._ackDelivery(e,n.seq);else if(i&&(i.status===404||i.status===410))this._ackDelivery(e,n.seq);else break}}finally{this._postDraining.delete(e)}})())}}_ackDelivery(e,t){const s=this._pendingDeliveries.get(e);if(s){const n=s.findIndex(i=>i.seq===t);n!==-1&&(s.splice(n,1),s.length===0&&this._pendingDeliveries.delete(e),this._pendingDeliveries.size===0?this._persistReliableNow():this._persistReliableState(),this._updateConnectionIndicator())}this.markIdleAlertSeen?.(e)}_onWsInputAck(e){this._wsSessionId&&Number.isInteger(e)&&this._ackDelivery(this._wsSessionId,e)}_onWsReady(e){const t=this._pendingDeliveries.get(e);if(t)for(const s of t)s.sentAt=0;this._drainSession(e)}_redeliverSweep(){if(this._pendingDeliveries.size!==0)for(const e of[...this._pendingDeliveries.keys()]){const t=this._pendingDeliveries.get(e);if(!t||t.length===0)continue;if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e){const n=t[0],i=n&&n.sentAt&&Date.now()-n.sentAt>this._reliableAckTimeoutMs,o=Date.now()-this._wsLastRecvAt>this._reliableAckTimeoutMs;if(i&&o){try{this._ws.close()}catch{}continue}if(i)for(const r of t)r.sentAt&&Date.now()-r.sentAt>this._reliableAckTimeoutMs&&(r.sentAt=0)}this._drainSession(e)}}_pendingBytes(){let e=0,t=0;for(const s of this._pendingDeliveries.values())for(const n of s)e+=n.data.length,t++;return{bytes:e,count:t}}_loadReliableState(){try{this._clientId=localStorage.getItem("codeman:clientId")||""}catch{this._clientId=""}if(!this._clientId){this._clientId="c-"+Math.random().toString(36).slice(2)+"-"+Date.now().toString(36);try{localStorage.setItem("codeman:clientId",this._clientId)}catch{}}try{const e=localStorage.getItem("codeman:pendingInput");if(!e)return;const t=JSON.parse(e);if(t&&t.seqs)for(const[s,n]of Object.entries(t.seqs))Number.isFinite(n)&&this._seqCounters.set(s,n);if(t&&t.pending)for(const[s,n]of Object.entries(t.pending))Array.isArray(n)&&n.length&&this._pendingDeliveries.set(s,n.filter(i=>i&&typeof i.data=="string"&&Number.isInteger(i.seq)).map(i=>({seq:i.seq,data:i.data,useMux:!!i.useMux,ts:i.ts||Date.now(),tries:0,sentAt:0})))}catch{}}_persistReliableState(){this._persistReliableTimer||(this._persistReliableTimer=setTimeout(()=>{this._persistReliableTimer=null,this._persistReliableNow()},250))}_persistReliableNow(){this._persistReliableTimer&&(clearTimeout(this._persistReliableTimer),this._persistReliableTimer=null);try{const e={};for(const[i,o]of this._seqCounters)e[i]=o;const t={};let s=0;for(const[i,o]of this._pendingDeliveries)if(o.length){t[i]=o.map(r=>({seq:r.seq,data:r.data,useMux:r.useMux,ts:r.ts,tries:r.tries}));for(const r of o)s+=r.data.length}const n=s>this._reliableMaxBytes?{seqs:e}:{seqs:e,pending:t};localStorage.setItem("codeman:pendingInput",JSON.stringify(n))}catch{}}_computeConnectionDescriptor(){const{bytes:e,count:t}=this._pendingBytes(),s=t>0,i=e>4,o=a=>a<1024?`${a}B`:`${(a/1024).toFixed(1)}KB`,r=i?` \xB7 ${o(e)} queued`:"";if(!this.isOnline||this._connectionStatus==="offline")return{display:"flex",dotClass:"connection-dot offline",text:i?`Offline (${o(e)} queued)`:"Offline",title:"No network connection"};if(this.activeSessionId){let a,l,c;switch(this._wsState){case"connected":a="connected",l="WS",c="Terminal connected over WebSocket";break;case"fallback":a="fallback",l="HTTP",c="WebSocket unavailable \u2014 input sent over HTTP";break;case"reconnecting":a="reconnecting",l="WS\u2026",c="Reconnecting WebSocket";break;default:a="reconnecting",l="WS\u2026",c="Connecting WebSocket";break}return{display:"flex",dotClass:`connection-dot ${a}`,text:`${l}${r}`,title:c}}return this._connectionStatus==="reconnecting"||this._connectionStatus==="disconnected"?{display:"flex",dotClass:"connection-dot reconnecting",text:i?`Reconnecting (${o(e)} queued)`:"Reconnecting...",title:"Reconnecting to server"}:s?{display:"flex",dotClass:"connection-dot draining",text:i?`Sending ${o(e)}...`:"Sending...",title:"Delivering queued input"}:{display:"none",dotClass:"",text:"",title:""}}_updateConnectionIndicator(){const e=this.$("connectionIndicator"),t=this.$("connectionDot"),s=this.$("connectionText");if(!e||!t||!s)return;const n=this._computeConnectionDescriptor(),i=this._lastIndicatorDescriptor;i&&i.display===n.display&&i.dotClass===n.dotClass&&i.text===n.text&&i.title===n.title||(this._lastIndicatorDescriptor=n,e.style.display=n.display,n.display!=="none"&&(t.className=n.dotClass,s.textContent=n.text,e.title=n.title))}setupOnlineDetection(){window.addEventListener("online",()=>{this.isOnline=!0,this.reconnectAttempts=0,this._connDownSince=Date.now(),this.connectSSE(),this._redeliverSweep()}),window.addEventListener("offline",()=>{this.isOnline=!1,this.setConnectionStatus("offline")})}_updateConnectionLossUi(){const e=window.CodemanConnectionLoss,t=this.$("offlineBanner"),s=this.$("offlineOverlay");if(!e||!t||!s)return;const n=e.compute({isOnline:this.isOnline,status:this._connectionStatus,everLoaded:this._initGeneration>0,downSince:this._connDownSince,now:Date.now(),nextRetryAt:this._nextSseRetryAt,overlayDismissed:this._offlineOverlayDismissed,retryPending:this._offlineRetryPending});this._connDownSince===null?this._stopOfflineTicker():this._startOfflineTicker();const i=this._offlineRetryPending?"Reconnecting\u2026":n.retryInSec!=null&&n.retryInSec>0?`Retrying in ${n.retryInSec}s`:"Retrying\u2026",o=`${n.mode}|${n.kind}|${i}`;if(o!==this._lastOfflineUiKey){if(this._lastOfflineUiKey=o,t.hidden=n.mode!=="banner",s.hidden=n.mode!=="overlay",document.body.classList.toggle("connection-lost",n.mode!=="hidden"),n.mode==="banner"){const r=this.$("offlineBannerText"),a=this.$("offlineBannerDetail");r&&(r.textContent=n.title),a&&(a.textContent=i)}else if(n.mode==="overlay"){const r=this.$("offlineOverlayTitle"),a=this.$("offlineOverlayBody"),l=this.$("offlineOverlayHost"),c=this.$("offlineOverlayStatus");r&&(r.textContent=n.title),a&&(a.textContent=n.detail),l&&(l.textContent=location.host),c&&(c.textContent=i)}}}_startOfflineTicker(){this._offlineUiTicker||(this._offlineUiTicker=setInterval(()=>this._updateConnectionLossUi(),1e3))}_stopOfflineTicker(){this._offlineUiTicker&&(clearInterval(this._offlineUiTicker),this._offlineUiTicker=null)}retryConnection(){this._offlineRetryPending=!0,this._nextSseRetryAt=null,this.reconnectAttempts=0,this._clearTimer("sseReconnectTimeout"),this.isOnline=navigator.onLine,this._lastOfflineUiKey="",this._updateConnectionLossUi(),this.connectSSE(),this.activeSessionId&&this._wsState!=="connected"&&(this._wsReconnectAttempts=0,this._connectWs(this.activeSessionId)),this._clearTimer("_offlineRetryTimer"),this._offlineRetryTimer=setTimeout(()=>{this._offlineRetryPending=!1,this._lastOfflineUiKey="",this._updateConnectionLossUi()},1500)}dismissOfflineOverlay(){this._offlineOverlayDismissed=!0,this._lastOfflineUiKey="",this._updateConnectionLossUi()}_updateCjkInputState(){const e=document.getElementById("cjkInput");if(!e)return;const t=this.loadAppSettingsFromStorage(),s=this.getDefaultSettings?.()||{},i=(this._serverCjkOverride||(t.cjkInputEnabled??s.cjkInputEnabled??!1))&&!!this.activeSessionId;e.classList.toggle("cjk-input-visible",!!i),document.body.classList.toggle("cjk-input-visible",!!i),e.style.display=i?"block":"none",e.setAttribute("aria-hidden",i?"false":"true"),i||(window.cjkActive=!1),typeof KeyboardHandler<"u"&&KeyboardHandler.updateLayoutForKeyboard()}_resetAllAppState(){this.sessions.clear(),this.ralphStates.clear(),this.terminalBuffers.clear(),this.terminalBufferCache.clear(),this._xtermSnapshots?.clear(),this.projectInsights.clear(),this.teams.clear(),this.teamTasks.clear();for(const e of this.idleTimers.values())clearTimeout(e);if(this.idleTimers.clear(),this._clearTimer("flickerFilterTimeout"),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1,this._localEchoOverlay?.rerender(),this._predictiveEcho?.clearPredictions(),this.pendingHooks.clear(),this.approvals?.clear(),this._parentNameCache&&this._parentNameCache.clear(),this.subagentActivity.clear(),this.subagentToolResults.clear(),this.workflowRuns&&this.workflowRuns.clear(),this.workflowRunDetails&&this.workflowRunDetails.clear(),this.activeWorkflowRunId=null,this.activeWorkflowPhaseIndex=null,MobileDetection.cleanup(),KeyboardHandler.cleanup(),MobileDetection.init(),KeyboardHandler.init(),this.tabAlerts.clear(),this.attachmentHistoryCounts.clear(),this._shownCompletions&&this._shownCompletions.clear(),this.notificationManager?.titleFlashInterval&&(clearInterval(this.notificationManager.titleFlashInterval),this.notificationManager.titleFlashInterval=null),this.notificationManager?.groupingMap){for(const{timeout:e}of this.notificationManager.groupingMap.values())clearTimeout(e);this.notificationManager.groupingMap.clear()}this.terminalResizeObserver&&(this.terminalResizeObserver.disconnect(),this.terminalResizeObserver=null),this.planLoadingTimer&&(clearInterval(this.planLoadingTimer),this.planLoadingTimer=null),this.timerCountdownInterval&&(clearInterval(this.timerCountdownInterval),this.timerCountdownInterval=null),this.runSummaryAutoRefreshTimer&&(clearInterval(this.runSummaryAutoRefreshTimer),this.runSummaryAutoRefreshTimer=null)}handleInit(e){this._clearTimer("_initFallbackTimer");const t=++this._initGeneration;if(this._serverCjkOverride=e.inputCjkForm||!1,this._updateCjkInputState(),e.planUsage&&this.updatePlanUsageChip(e.planUsage),e.version){const i=this.$("versionDisplay"),o=this.$("headerVersion");i&&(i.textContent=`v${e.version}`,i.title=`Codeman v${e.version}`),o&&(o.textContent=`v${e.version}`,o.title=`Codeman v${e.version}`)}VoiceInput.cleanup(),this._resetAllAppState(),e.sessions.forEach(i=>{this.sessions.set(i.id,i),(i.ralphLoop||i.ralphTodos)&&!this.ralphClosedSessions.has(i.id)&&this.ralphStates.set(i.id,{loop:i.ralphLoop||null,todos:i.ralphTodos||[]})});try{localStorage.removeItem("codeman-tab-meta")}catch{}if(Array.isArray(e.sessionOrder)&&e.sessionOrder.length)try{localStorage.setItem("codeman-session-order",JSON.stringify(e.sessionOrder))}catch{}this.syncSessionOrder(),e.respawnStatus?this.respawnStatus=e.respawnStatus:this.respawnStatus={},this.respawnTimers={},this.respawnCountdownTimers={},this.respawnActionLogs={},e.globalStats&&(this.globalStats=e.globalStats),this.totalCost=e.sessions.reduce((i,o)=>i+(o.totalCost||0),0),this.totalCost+=e.scheduledRuns.reduce((i,o)=>i+(o.totalCost||0),0);const s=e.scheduledRuns.find(i=>i.status==="running");if(s&&(this.currentRun=s,this.showTimer()),this.updateCost(),this.renderSessionTabs(),this.seedApprovals?.(),this.sessions.size>0?this.startSystemStatsPolling():this.stopSystemStatsPolling(),this.cleanupAllFloatingWindows(),e.subagents&&(this.subagents.clear(),this.subagentActivity.clear(),this.subagentToolResults.clear(),e.subagents.forEach(i=>{this.subagents.set(i.agentId,i)}),this.renderSubagentPanel(),this.subagentParentMap.clear(),this.loadSubagentParentMap().then(()=>{for(const[i,o]of this.subagentParentMap){const r=this.subagents.get(i);if(r&&this.sessions.has(o)){r.parentSessionId=o;const a=this.sessions.get(o);a&&(r.parentSessionName=this.getSessionName(a)),this.subagents.set(i,r)}}for(const[i]of this.subagents)this.subagentParentMap.has(i)||this.findParentSessionForSubagent(i);this.restoreSubagentWindowStates()})),e.workflowRuns&&this.seedWorkflowRuns(e.workflowRuns),t!==this._initGeneration)return;if(this.isSoloWindow){this._applySoloMode();return}const n=this.activeSessionId;if(this.activeSessionId=null,this.sessionOrder.length>0){let i=n;if(!i||!this.sessions.has(i))try{i=localStorage.getItem("codeman-active-session")}catch{}i&&this.sessions.has(i)?this.selectSession(i,{auto:!0}):this.selectSession(this.sessionOrder[0],{auto:!0})}}async loadState(){try{const t=await(await fetch("/api/status")).json();this.handleInit(t?.data??{})}catch(e){console.error("Failed to load state:",e)}}_debouncedCall(e,t,s=100){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{this._debounceTimers[e]=null,t.call(this)},s)}getSessionListLayout(){if(this.soloSessionId)return"header";const e=this.loadAppSettingsFromStorage(),t=this.getDefaultSettings();return(e.sessionListLayout??t.sessionListLayout??"header")==="sidebar"?"sidebar":"header"}isSessionSidebarActive(){return document.documentElement.dataset.sessionList==="sidebar"}_isSessionSidebarOverlay(){return window.innerWidth<1024}isSessionSidebarCollapsed(){if(this._sidebarCollapsedOverride!==void 0)return this._sidebarCollapsedOverride;let e=null;try{e=localStorage.getItem("codeman-sidebar-collapsed")}catch{}return e===null?this._isSessionSidebarOverlay():e==="1"}shouldToggleSessionSidebarFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey||!this.isSessionSidebarActive()||typeof this.getShortcutRegistry!="function"||typeof this.matchesShortcutEvent!="function")return!1;const t=this.getShortcutRegistry().find(s=>s.id==="toggle-session-sidebar");return!t||t.disabled?!1:this.matchesShortcutEvent(e,t)}applySessionListLayout(){const e=this.getSessionListLayout(),t=this.isSessionSidebarCollapsed(),s=document.documentElement.dataset.sessionList,n=document.getElementById("sessionTabs"),i=document.getElementById("sessionTabsHost"),o=document.getElementById("sessionSidebarList");if(!n||!i||!o)return;const r=e==="sidebar"?o:i;n.parentElement!==r&&r.appendChild(n),document.documentElement.dataset.sessionList=e,document.documentElement.dataset.sidebar=t?"collapsed":"expanded",n.setAttribute("aria-orientation",e==="sidebar"?"vertical":"horizontal");const a=document.getElementById("sidebarToggleBtn");if(a){a.classList.toggle("btn-sidebar-toggle--hidden",e!=="sidebar");const d=t?"Expand session sidebar":"Collapse session sidebar";a.setAttribute("aria-expanded",t?"false":"true"),a.setAttribute("aria-label",d),a.setAttribute("title",d)}const l=document.getElementById("sessionSidebar");if(l){l.classList.toggle("open",e==="sidebar"&&!t);const d=e==="sidebar"&&t&&this._isSessionSidebarOverlay();l.toggleAttribute("inert",d),d?l.setAttribute("aria-hidden","true"):l.removeAttribute("aria-hidden")}if(e!=="sidebar"){this._sidebarFilter="";const d=document.getElementById("sessionSidebarFilter");d&&(d.value="")}const c=this._tallTabsEnabled;this.applyTabWrapSettings(),s!==e&&c===this._tallTabsEnabled&&this._fullRenderSessionTabs(),e==="sidebar"&&n.classList.remove("tabs-auto-wrap"),this.applySidebarFilter(this._sidebarFilter),this.updateConnectionLines(),document.getElementById("welcomeOverlay")?.classList.contains("visible")&&this.showHomeSessions?.()}toggleSessionSidebar(){if(!this.isSessionSidebarActive())return;const e=!this.isSessionSidebarCollapsed();this._sidebarCollapsedOverride=e;try{localStorage.setItem("codeman-sidebar-collapsed",e?"1":"0")}catch{}e&&this.$("sessionSidebar")?.contains(document.activeElement)&&document.getElementById("sidebarToggleBtn")?.focus(),this.applySessionListLayout(),!e&&this._isSessionSidebarOverlay()&&this.$("sessionTabs")?.querySelector(".session-tab.active")?.focus()}closeSessionSidebarOnHandheld(){this._isSessionSidebarOverlay()&&(!this.isSessionSidebarActive()||this.isSessionSidebarCollapsed()||this.toggleSessionSidebar())}updateSidebarCount(){const e=document.getElementById("sessionSidebarCount");if(!e)return;const t=this.$("sessionTabs"),s=t?t.querySelectorAll(".session-tab:not(.tab-filtered-out)").length:this.sessions?.size??0;e.textContent=String(s)}applySidebarFilter(e){this._sidebarFilter=(e??"").trim().toLowerCase();const t=this.$("sessionTabs");if(!t)return;const n=this.isSessionSidebarActive()&&document.documentElement.dataset.sidebar!=="collapsed"?this._sidebarFilter:"";for(const i of t.querySelectorAll(".session-tab")){if(!n){i.classList.remove("tab-filtered-out");continue}const o=`${i.getAttribute("aria-label")||""} ${i.getAttribute("title")||""}`.toLowerCase();i.classList.toggle("tab-filtered-out",!o.includes(n))}this.updateSidebarCount()}renderSessionTabs(){this._inlineRenameActive||this._debouncedCall("sessionTabs",this._renderSessionTabsImmediate)}_updateActiveTabImmediate(e){const t=this.$("sessionTabs");if(!t)return;const s=t.querySelectorAll(".session-tab[data-id]");for(const n of s)n.dataset.id===e?n.classList.add("active"):n.classList.remove("active");this._scrollActiveTabIntoView(e)}_scrollActiveTabIntoView(e,t="smooth"){const s=this.$("sessionTabs");if(!s)return;const n=e&&s.querySelector(`.session-tab[data-id="${e}"]`)||s.querySelector(".session-tab.active");if(!n)return;if(this.isSessionSidebarActive()){n.scrollIntoView({block:"nearest"});return}const i=window.CodemanTabOverflow?.computeTabScrollLeft;if(!i)return;const o=s.getBoundingClientRect(),r=n.getBoundingClientRect(),a=i({scrollLeft:s.scrollLeft,clientWidth:s.clientWidth,scrollWidth:s.scrollWidth,tabLeft:r.left-o.left+s.scrollLeft,tabWidth:r.width});if(Math.abs(a-s.scrollLeft)<1)return;const l=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;typeof s.scrollTo=="function"?s.scrollTo({left:a,behavior:l?"auto":t}):s.scrollLeft=a}_tabAnchor(e){return this.isSessionSidebarActive()?{x:e.right,y:e.top+e.height/2,spawnLeft:e.right+14,spawnTop:e.top,vertical:!1}:{x:e.left+e.width/2,y:e.bottom,spawnLeft:e.left,spawnTop:e.bottom,vertical:!0}}_tabConnectorPath(e,t){if(e.vertical){const o=t.left+t.width/2,r=t.top,a=(e.y+r)/2;return`M ${e.x} ${e.y} C ${e.x} ${a}, ${o} ${a}, ${o} ${r}`}const s=t.left,n=t.top+t.height/2,i=(e.x+s)/2;return`M ${e.x} ${e.y} C ${i} ${e.y}, ${i} ${n}, ${s} ${n}`}_setTerminalLoadState(e,t,s){this.terminalLoadStates.set(e,{generation:t,phase:s}),this._updateTerminalLoadTab(e)}_clearTerminalLoadState(e,t){const s=this.terminalLoadStates.get(e);s&&s.generation!==t||(this.terminalLoadStates.delete(e),this._updateTerminalLoadTab(e))}_updateTerminalLoadTab(e){const t=this.$("sessionTabs")?.querySelector(`.session-tab[data-id="${e}"]`);if(!t)return;const s=this.terminalLoadStates.get(e);if(t.classList.toggle("tab-loading",!!s),s){if(t.setAttribute("aria-busy","true"),t.dataset.loadPhase=s.phase,!t.querySelector(".tab-load-spinner")){const n=document.createElement("span");n.className="tab-load-spinner",n.setAttribute("aria-hidden","true");const i=t.querySelector(".tab-number");i?i.insertAdjacentElement("afterend",n):t.insertBefore(n,t.firstChild)}}else t.setAttribute("aria-busy","false"),delete t.dataset.loadPhase,t.querySelector(".tab-load-spinner")?.remove()}_renderSessionTabsImmediate(){if(this._inlineRenameActive)return;const e=this.$("sessionTabs"),t=e.querySelectorAll(".session-tab[data-id]"),s=new Set([...t].map(l=>l.dataset.id)),n=new Set(this.sessions.keys()),i=[...e.querySelectorAll(".session-tab[data-webview-id]")].map(l=>l.dataset.webviewId),o=(this.webviewOrder||[]).filter(l=>this.webviews?.has(l)),r=i.length===o.length&&i.every((l,c)=>l===o[c]);if(s.size===n.size&&[...s].every(l=>n.has(l))&&r)for(const[l,c]of this.sessions){const d=e.querySelector(`.session-tab[data-id="${l}"]`);if(!d)continue;const E=l===this.activeSessionId&&!this.activeWebviewId,p=c.status||"idle",S=this.getSessionName(c),v=c.taskStats||{running:0,total:0},C=v.running>0,y=this.terminalLoadStates.get(l);if(E&&!d.classList.contains("active")?d.classList.add("active"):!E&&d.classList.contains("active")&&d.classList.remove("active"),d.classList.toggle("tab-loading",!!y),y){if(d.setAttribute("aria-busy","true"),d.dataset.loadPhase=y.phase,!d.querySelector(".tab-load-spinner")){const u=document.createElement("span");u.className="tab-load-spinner",u.setAttribute("aria-hidden","true");const _=d.querySelector(".tab-number");_?_.insertAdjacentElement("afterend",u):d.insertBefore(u,d.firstChild)}}else d.setAttribute("aria-busy","false"),delete d.dataset.loadPhase,d.querySelector(".tab-load-spinner")?.remove();const A=this.tabAlerts.get(l),L=A==="action",R=A==="idle",T=d.classList.contains("tab-alert-action"),k=d.classList.contains("tab-alert-idle");if(L&&!T?(d.classList.add("tab-alert-action"),d.classList.remove("tab-alert-idle")):R&&!k?(d.classList.add("tab-alert-idle"),d.classList.remove("tab-alert-action")):!A&&(T||k)&&d.classList.remove("tab-alert-action","tab-alert-idle"),!d.querySelector(".tab-number")){const u=this.sessionOrder.indexOf(l);if(u>=0&&u<9){const _=document.createElement("span");_.className="tab-number",_.textContent=String(u+1),d.insertBefore(_,d.firstChild)}}const f=d.querySelector(".tab-status");f&&!f.classList.contains(p)&&(f.className=`tab-status ${p}`);const b=d.querySelector(".tab-name");if(b){const u=parseSessionPrefix(S),_=u&&u.suffix?u.suffix:S;b.textContent!==_&&(b.textContent=_,d.title=u&&u.suffix?c.workingDir?`${u.prefix} (${c.workingDir})`:u.prefix:c.workingDir||"")}const O=d.querySelector(".tab-badge");if(C)if(O)O.textContent!==String(v.running)&&(O.textContent=v.running);else{this._fullRenderSessionTabs();return}else if(O){this._fullRenderSessionTabs();return}const m=d.querySelector(".tab-subagent-badge"),w=this.minimizedSubagents.get(l),g=w?.size||0;if(g>0&&m){const u=m.querySelector(".subagent-label"),_=g===1?"AGENT":`AGENTS (${g})`;u&&u.textContent!==_&&(u.textContent=_);const I=m.querySelector(".subagent-dropdown");if(I){const x=this.renderSubagentTabBadge(l,w),N=document.createElement("div");N.innerHTML=x;const D=N.querySelector(".subagent-dropdown");D&&(I.innerHTML=D.innerHTML)}}else if(g>0&&!m){const u=this.renderSubagentTabBadge(l,w),_=d.querySelector(".tab-actions");_&&_.insertAdjacentHTML("beforebegin",u)}else g===0&&m&&m.remove()}else this._fullRenderSessionTabs();this._lastRenderedActiveTabId=this.activeSessionId,this.updateTabOverflowMode(),this._applyTabEntrances?.(),this._refreshMobileOverviewIfVisible?.(),this._refreshHomeSessionsIfVisible?.(),(this._lineageEdgeCount>0||this.isSessionSidebarActive())&&this.updateConnectionLines(),this.applySidebarFilter(this._sidebarFilter)}updateTabOverflowMode(){const e=this.$("sessionTabs");if(!e)return;if(this.isSessionSidebarActive()){e.classList.remove("tabs-auto-wrap");return}const t=MobileDetection.getDeviceType(),s=this.loadAppSettingsFromStorage(),n=this.getDefaultSettings(),i=t==="desktop"?s.tabTwoRows??n.tabTwoRows??!1:!1;if(i||t!=="desktop"){e.classList.remove("tabs-auto-wrap");return}e.classList.remove("tabs-auto-wrap");const o=window.CodemanTabOverflow?.shouldAutoWrapTabs?window.CodemanTabOverflow.shouldAutoWrapTabs({deviceType:t,manualTwoRows:i,tabCount:this.sessions.size,scrollWidth:e.scrollWidth,clientWidth:e.clientWidth}):e.scrollWidth>e.clientWidth+1;e.classList.toggle("tabs-auto-wrap",o)}_setupTabMiddleClickClose(){const e=this.$("sessionTabs");!e||this._tabAuxClickBound||(this._tabAuxClickBound=!0,e.addEventListener("auxclick",t=>{if(t.button!==1)return;const s=t.target.closest?.(".session-tab");s&&(t.preventDefault(),t.stopPropagation(),s.dataset.id?this.requestCloseSession(s.dataset.id):s.dataset.webviewId&&this.closeWebviewTab?.(s.dataset.webviewId))}))}_fullRenderSessionTabs(){if(this._inlineRenameActive)return;const e=this.$("sessionTabs");this.isSessionSidebarActive()&&(this._tallTabsEnabled=!0,e.classList.add("tabs-show-folder"),e.classList.remove("tabs-two-rows","tabs-auto-wrap")),document.querySelectorAll("body > .subagent-dropdown").forEach(l=>l.remove()),this.cancelHideSubagentDropdown();const t=e.scrollLeft,s=e.scrollTop,n=this._lastRenderedActiveTabId,i=!e.querySelector(".session-tab"),o=[],r=this.sessionOrder;let a=0;for(const l of r){const c=this.sessions.get(l);if(!c)continue;const d=l===this.activeSessionId&&!this.activeWebviewId,E=c.status||"idle",p=this.getSessionName(c),S=c.mode||"claude",v=c.color||"default",C=c.taskStats||{running:0,total:0},y=C.running>0,A=this.tabAlerts.get(l),L=A==="action"?" tab-alert-action":A==="idle"?" tab-alert-idle":"",R=this.terminalLoadStates.get(l),T=this.minimizedSubagents.get(l),f=(T?.size||0)>0?this.renderSubagentTabBadge(l,T):"",b=this.renderUltracodeTabBadge?this.renderUltracodeTabBadge(l):"",O=c.workingDir&&c.workingDir.split("/").pop()||"",w=(this._tallTabsEnabled??!1)&&c.name&&O&&O!==p,g=parseSessionPrefix(p),u=g&&g.suffix?g.suffix:p,_=g&&g.suffix?c.workingDir?`${g.prefix} (${c.workingDir})`:g.prefix:c.workingDir||"";o.push(`<div class="session-tab ${d?"active":""}${L}${R?" tab-loading":""}${this.hasTabDetachOverride(l)?" tab-show-detach":""}" data-id="${l}" data-color="${v}" ${R?`data-load-phase="${escapeHtml(R.phase)}"`:""} onclick="app.handleSessionTabClick(event, ${escapeHtml(JSON.stringify(l))})" oncontextmenu="event.preventDefault(); app.startInlineRename(${escapeHtml(JSON.stringify(l))})" tabindex="0" role="tab" aria-selected="${d?"true":"false"}" aria-busy="${R?"true":"false"}" aria-label="${escapeHtml(p)} session" ${_?`title="${escapeHtml(_)}"`:""}>
|
|
17
|
+
${a<9?'<span class="tab-number">'+(a+1)+"</span>":""}
|
|
18
|
+
${R?'<span class="tab-load-spinner" aria-hidden="true"></span>':""}
|
|
19
|
+
<span class="tab-status ${E}" aria-hidden="true"></span>
|
|
20
|
+
<span class="tab-info">
|
|
21
|
+
<span class="tab-name-row">
|
|
22
|
+
${S==="shell"?'<span class="tab-mode shell" aria-hidden="true">sh</span>':S==="opencode"?'<span class="tab-mode opencode" aria-hidden="true">oc</span>':S==="codex"?'<span class="tab-mode codex" aria-hidden="true">cx</span>':S==="gemini"?'<span class="tab-mode gemini" aria-hidden="true">gm</span>':S==="antigravity"?'<span class="tab-mode antigravity" aria-hidden="true">ag</span>':S==="pi"?'<span class="tab-mode pi" aria-hidden="true">pi</span>':""}
|
|
23
|
+
<span class="tab-name" data-session-id="${l}">${escapeHtml(u)}</span>
|
|
24
|
+
<span class="tab-detached-badge" aria-hidden="true">detached</span>
|
|
25
|
+
</span>
|
|
26
|
+
${w?`<span class="tab-folder">\u{1F4C1} ${escapeHtml(O)}</span>`:""}
|
|
27
|
+
</span>
|
|
28
|
+
${y?`<span class="tab-badge" onclick="event.stopPropagation(); app.toggleTaskPanel()" aria-label="${C.running} running tasks">${C.running}</span>`:""}
|
|
29
|
+
${f}
|
|
30
|
+
${b}
|
|
31
|
+
<span class="tab-actions"><span class="tab-gear" onclick="event.stopPropagation(); app.openSessionOptions(${escapeHtml(JSON.stringify(l))})" title="Session options" aria-label="Session options" tabindex="0">⚙</span><span class="tab-detach" onclick="event.stopPropagation(); app.detachSession(${escapeHtml(JSON.stringify(l))})" title="Open in a new window" aria-label="Open session in a new window" tabindex="0">⧉</span><span class="tab-close" onclick="event.stopPropagation(); app.requestCloseSession(${escapeHtml(JSON.stringify(l))})" title="Close session" aria-label="Close session" tabindex="0">×</span></span>
|
|
32
|
+
</div>`),a++}o.push(this.renderWebviewTabs?this.renderWebviewTabs(a):""),e.innerHTML=o.join(""),e.scrollLeft=t,e.scrollTop=s,this._lastRenderedActiveTabId=this.activeSessionId,(i||n!==this.activeSessionId)&&this._scrollActiveTabIntoView(this.activeSessionId,i?"auto":"smooth"),this.setupTabDragHandlers(),this.setupTabKeyboardNavigation(e),this.updateConnectionLines(),this.updateTabOverflowMode(),this._applyTabEntrances?.(),this.applySidebarFilter(this._sidebarFilter)}setupTabKeyboardNavigation(e){this._tabKeydownHandler&&e.removeEventListener("keydown",this._tabKeydownHandler),this._tabKeydownHandler=t=>{if(!["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","Enter"," "].includes(t.key))return;const s=[...e.querySelectorAll(".session-tab:not(.tab-filtered-out)")],n=s.indexOf(document.activeElement);if((t.key==="Enter"||t.key===" ")&&n>=0){t.preventDefault();const o=s[n].dataset.id;this.selectSession(o,{forceReload:!0});return}if(n<0)return;let i;switch(t.key){case"ArrowLeft":case"ArrowUp":i=n>0?n-1:s.length-1;break;case"ArrowRight":case"ArrowDown":i=n<s.length-1?n+1:0;break;case"Home":i=0;break;case"End":i=s.length-1;break;default:return}t.preventDefault(),s[i]?.focus()},e.addEventListener("keydown",this._tabKeydownHandler)}handleSessionTabClick(e,t){return e?.preventDefault?.(),!(typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible===!0)&&MobileDetection.isTouchDevice()&&document.activeElement?.blur?.(),this.selectSession(t,{forceReload:!0})}syncSessionOrder(){const e=new Set(this.sessions.keys()),s=this.loadSessionOrder().filter(o=>e.has(o)),n=new Set(s),i=[...e].filter(o=>!n.has(o));this.sessionOrder=[...s,...i]}loadSessionOrder(){try{const e=localStorage.getItem("codeman-session-order");return e?JSON.parse(e):[]}catch{return[]}}saveSessionOrder(){try{localStorage.setItem("codeman-session-order",JSON.stringify(this.sessionOrder))}catch{}const e=[...this.sessionOrder];this._debouncedCall("saveSessionOrderServer",()=>{fetch("/api/session-order",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({order:e})}).catch(()=>{})},400)}_onSessionOrderChanged(e){if(!e||!Array.isArray(e.order))return;try{localStorage.setItem("codeman-session-order",JSON.stringify(e.order))}catch{}const t=JSON.stringify(this.sessionOrder);this.syncSessionOrder(),JSON.stringify(this.sessionOrder)!==t&&this._fullRenderSessionTabs()}setupTabDragHandlers(){const e=this.$("sessionTabs");e.querySelectorAll(".session-tab[data-id]").forEach(s=>{s.setAttribute("draggable","true"),s.addEventListener("dragstart",n=>{this.draggedTabId=s.dataset.id,s.classList.add("dragging"),n.dataTransfer.effectAllowed="move",n.dataTransfer.setData("text/plain",s.dataset.id)}),s.addEventListener("dragend",()=>{s.classList.remove("dragging"),this.draggedTabId=null,e.querySelectorAll(".session-tab").forEach(n=>{n.classList.remove("drag-over-left","drag-over-right")})}),s.addEventListener("dragover",n=>{if(n.preventDefault(),!this.draggedTabId||this.draggedTabId===s.dataset.id)return;n.dataTransfer.dropEffect="move";const i=s.getBoundingClientRect(),o=this.isSessionSidebarActive()?n.clientY<i.top+i.height/2:n.clientX<i.left+i.width/2;s.classList.toggle("drag-over-left",o),s.classList.toggle("drag-over-right",!o)}),s.addEventListener("dragleave",()=>{s.classList.remove("drag-over-left","drag-over-right")}),s.addEventListener("drop",n=>{if(n.preventDefault(),s.classList.remove("drag-over-left","drag-over-right"),!this.draggedTabId||this.draggedTabId===s.dataset.id)return;const i=s.dataset.id,o=this.draggedTabId,r=s.getBoundingClientRect(),a=this.isSessionSidebarActive()?n.clientY<r.top+r.height/2:n.clientX<r.left+r.width/2,l=this.sessionOrder.indexOf(o);let c=this.sessionOrder.indexOf(i);l===-1||c===-1||(this.sessionOrder.splice(l,1),c=this.sessionOrder.indexOf(i),c!==-1&&(a?this.sessionOrder.splice(c,0,o):this.sessionOrder.splice(c+1,0,o),this.saveSessionOrder(),this._fullRenderSessionTabs()))})})}moveActiveTabLeft(){if(!this.activeSessionId)return;const e=this.sessionOrder.indexOf(this.activeSessionId);e<=0||([this.sessionOrder[e-1],this.sessionOrder[e]]=[this.sessionOrder[e],this.sessionOrder[e-1]],this.saveSessionOrder(),this._fullRenderSessionTabs())}moveActiveTabRight(){if(!this.activeSessionId)return;const e=this.sessionOrder.indexOf(this.activeSessionId);e===-1||e>=this.sessionOrder.length-1||([this.sessionOrder[e],this.sessionOrder[e+1]]=[this.sessionOrder[e+1],this.sessionOrder[e]],this.saveSessionOrder(),this._fullRenderSessionTabs())}getShortId(e){if(!e)return"";let t=this._shortIdCache.get(e);return t||(t=e.slice(0,8),this._shortIdCache.set(e,t)),t}getSessionName(e){return e.name?e.name:e.workingDir?e.workingDir.split("/").pop()||e.workingDir:this.getShortId(e.id)}_notifySession(e,t,s,n,i){const o=this.sessions.get(e);this.notificationManager?.notify({urgency:t,category:s,sessionId:e,sessionName:o?.name||this.getShortId(e),title:n,message:i})}_isUsableXtermSnapshot(e){return!e||typeof e!="string"||e.length<8?!1:e.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,"").replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g,"").replace(/\x1b[()][0-2A-Z]/g,"").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"").trim().length>=3}_persistXtermSnapshot(e,t){const s="codeman-xs-",i=()=>Object.keys(localStorage).filter(o=>o.startsWith(s)&&o!==e);try{if(localStorage.getItem(e)===null){const o=new Set(Array.from(this.sessions?.keys?.()||[])),r=i().sort((a,l)=>Number(o.has(a.slice(s.length)))-Number(o.has(l.slice(s.length))));for(;r.length>=10;)localStorage.removeItem(r.shift())}try{localStorage.setItem(e,t)}catch{for(const r of i()){localStorage.removeItem(r);try{localStorage.setItem(e,t);return}catch{}}try{localStorage.removeItem(e)}catch{}}}catch{}}_cleanupPreviousSession(e){const t=this.activeSessionId?this.sessions?.get?.(this.activeSessionId):null;if(this.activeSessionId&&t?.mode!=="shell"&&this._serializeAddon&&this._xtermSnapshots)try{const s=this._serializeAddon.serialize({scrollback:1e3});if(this._isUsableXtermSnapshot(s)){if(this._xtermSnapshots.delete(this.activeSessionId),this._xtermSnapshots.set(this.activeSessionId,s),this._xtermSnapshots.size>20){const n=this._xtermSnapshots.keys().next().value;this._xtermSnapshots.delete(n)}s.length<256*1024&&this._persistXtermSnapshot(`codeman-xs-${this.activeSessionId}`,s)}else{this._xtermSnapshots.delete(this.activeSessionId);try{localStorage.removeItem(`codeman-xs-${this.activeSessionId}`)}catch{}}}catch{}if(this._disconnectWs(),typeof CjkInput<"u")CjkInput.clear();else{const s=document.getElementById("cjkInput");s&&(s.value="")}this._clearTimer("flickerFilterTimeout"),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._tabCompletionSessionId=null,this._tabCompletionRetries=0,this._tabCompletionBaseText=null,this._clearTimer("_tabCompletionFallback"),this._clearTimer("_clientDropRecoveryTimer"),this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1;try{const s=this.terminal?._core?._compositionHelper;if(s?._isComposing){s._isComposing=!1;const n=this.terminal?.element?.querySelector(".xterm-helper-textarea");n&&n.dispatchEvent(new CompositionEvent("compositionend",{data:""}))}}catch{}if(this.activeSessionId){const s=this._localEchoOverlay?.pendingText||"",n=this._localEchoOverlay?.getFlushed()?.count||0,i=this._localEchoOverlay?.getFlushed()?.text||"";s&&this._sendInputAsync(this.activeSessionId,s);const o=n+s.length;o>0&&(this._flushedOffsets||(this._flushedOffsets=new Map),this._flushedTexts||(this._flushedTexts=new Map),this._flushedOffsets.set(this.activeSessionId,o),this._flushedTexts.set(this.activeSessionId,i+s))}this._localEchoOverlay?.clear(),this._predictiveEcho?.clearPredictions(),this._localEchoOverlay&&!this._flushedOffsets?.has(e)&&this._localEchoOverlay.suppressBufferDetection()}_resetTerminalForReplay(){this.terminal.reset(),this.terminal.write("\x1B[3J\x1B[H\x1B[2J")}async _maybeRefetchFullHistory({force:e=!1}={}){const t=this.activeSessionId;if(!t||this._fullHistoryRepullInFlight||this._isLoadingBuffer||this.detachedSessions?.has(t))return;const s=Date.now(),n=this._fullHistoryRepullUseless?.has(t)?6e4:4e3;if(!(!e&&s-(this._fullHistoryRepullAt.get(t)||0)<n)){this._fullHistoryRepullAt.set(t,s),this._fullHistoryRepullInFlight=!0;try{const o=(await(await fetch(`/api/sessions/${t}/terminal?full=1`)).json())?.data??{},r=o.terminalBuffer;if(!r||this.activeSessionId!==t)return;if(this._replayWouldShrinkBuffer(r)){(this._fullHistoryRepullUseless||=new Set).add(t),this._logScrollRouting?.("repull-refused-downgrade"),this._setHistoryTruncation(t,{...o,exhausted:!0});return}this._setHistoryTruncation(t,o),this._fullHistoryRepullUseless?.delete(t);const a=this.terminal.buffer.active.length;if(this._resetTerminalForReplay(),await this.chunkedTerminalWrite(r,TERMINAL_CHUNK_SIZE,t),this.activeSessionId!==t)return;this.terminalBufferCache.set(t,r);const l=this.terminal.buffer.active.length-a;l>0?this.terminal.scrollToLine(l):this.terminal.scrollToTop()}catch{}finally{this._fullHistoryRepullInFlight=!1}}}_setHistoryTruncation(e,t={}){e&&((this._historyTruncation||=new Map).set(e,{truncated:!!t.truncated,reason:t.truncationReason??null,source:t.source??null,fullSize:t.fullSize??0,retainedBytes:t.retainedBytes??0,exhausted:!!t.exhausted}),e===this.activeSessionId&&this._renderHistoryTruncationBanner())}_clearHistoryTruncation(e){this._historyTruncation?.delete(e),e===this.activeSessionId&&this._renderHistoryTruncationBanner()}_renderHistoryTruncationBanner(){const e=document.getElementById("historyTruncationBar");if(!e)return;const t=this.activeSessionId?this._historyTruncation?.get(this.activeSessionId):null,s=computeHistoryTruncationNotice(t||{});if(!s.visible){e.hidden=!0;return}e.textContent="";const n=document.createElement("span");if(n.className="history-trunc-text",n.textContent=s.message,e.appendChild(n),s.canLoadMore){const o=document.createElement("button");o.type="button",o.className="history-trunc-load",o.textContent="Load full history",o.onclick=()=>{o.disabled=!0,o.textContent="Loading\u2026",this._maybeRefetchFullHistory({force:!0}).finally(()=>{this._renderHistoryTruncationBanner()})},e.appendChild(o)}const i=document.createElement("button");i.type="button",i.className="history-trunc-dismiss",i.setAttribute("aria-label","Dismiss history notice"),i.textContent="\xD7",i.onclick=()=>{e.hidden=!0},e.appendChild(i),e.hidden=!1}_shouldFocusTerminalForTabSwitch(){return typeof MobileDetection>"u"||!MobileDetection.isTouchDevice()?!0:typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible}async selectSession(e,t={}){if(!this.isSoloWindow&&this.detachedSessions.has(e)&&this._raiseDetached(e))return;const s=t?.forceReload===!0,n=t?.auto!==!0;if(this.activeSessionId===e&&!s){n&&this.markIdleAlertSeen(e);return}if(this.activeSessionId===e&&s){this.terminalBufferCache?.delete(e),this._xtermSnapshots?.delete(e);try{localStorage.removeItem(`codeman-xs-${e}`)}catch{}this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1,this.activeSessionId=null}const i=this._shouldFocusTerminalForTabSwitch();i&&this.terminal&&this.terminal.focus();const o=performance.now(),r=this.sessions.get(e)?.name||e.slice(0,8);_crashDiag.log(`SELECT: ${r}`),console.log(`[CRASH-DIAG] selectSession START: ${e.slice(0,8)}`);const a=++this._selectGeneration;if(this._setTerminalLoadState(e,a,"resizing"),a!==this._selectGeneration){this._clearTerminalLoadState(e,a);return}this._hideWebviewLayer?.(),this._cleanupPreviousSession(e),this.activeSessionId=e,this._renderHistoryTruncationBanner();try{localStorage.setItem("codeman-active-session",e)}catch{}this._updateSseSubscription(e),this.hideWelcome(),this.playTerminalEntrance?.(e),n&&this.markIdleAlertSeen(e),this._updateActiveTabImmediate(e),this.closeSessionSidebarOnHandheld(),this.renderSessionTabs(),this.updateAttachmentHistoryBadge?.(),this.attachmentHistoryDrawerOpen&&this.loadAttachmentHistory?.(e),this._updateLocalEchoState(),typeof KeyboardAccessoryBar<"u"&&KeyboardAccessoryBar.refreshForActiveSession(),this._flushedOffsets?.has(e)&&this._localEchoOverlay&&this._localEchoOverlay.setFlushed(this._flushedOffsets.get(e),this._flushedTexts?.get(e)||"",!1);const l=document.querySelector(`.session-tab.active[data-id="${e}"]`);l&&(l.classList.add("tab-glow"),l.addEventListener("animationend",()=>l.classList.remove("tab-glow"),{once:!0}));const c=this.sessions.get(e);if(this.currentSessionWorkingDir=c?.workingDir||null,c&&c.pid===null)if(c.respawnBlocked){const p=c.name||"Session";if(window.confirm(`${p} was stopped after crashing repeatedly. Restart it?`))try{await fetch(`/api/sessions/${e}/interactive`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clearBreaker:!0})}),c.respawnBlocked=!1,c.status="busy"}catch(S){console.error("Failed to restart crash-looped session:",S)}}else try{const p=c.mode==="shell"?`/api/sessions/${e}/shell`:`/api/sessions/${e}/interactive`;await fetch(p,{method:"POST"}),c.status="busy"}catch(p){console.error("Failed to attach to restored session:",p)}this._restoringFlushedState=!0;const d=this._beginBufferLoad(a);let E=!1;try{this.fitAddon&&this.fitAddon.fit();const p=await this.sendResize(e,{forceHttp:!0}).catch(()=>!1);if(this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}let S=this._xtermSnapshots?.get(e);if(S&&!this._isUsableXtermSnapshot(S)&&(this._xtermSnapshots?.delete(e),S=null),!S)try{const f=localStorage.getItem(`codeman-xs-${e}`);f&&this._isUsableXtermSnapshot(f)?(S=f,this._xtermSnapshots?.delete(e),this._xtermSnapshots?.set(e,f)):f&&localStorage.removeItem(`codeman-xs-${e}`)}catch{}const v=c&&(c.status==="busy"||c.status==="working");let C=!1;if(S&&!v&&c?.mode!=="shell"){if(_crashDiag.log(`SNAPSHOT_RESTORE: ${(S.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),await new Promise(f=>this.terminal.write(S,f)),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.scrollToLastNonEmptyLine(),_crashDiag.log("SNAPSHOT_RESTORE_DONE"),C=!0}const y=this.terminalBufferCache.get(e);let A=!1;if(y&&!v&&!C){if(_crashDiag.log(`CACHE_WRITE: ${(y.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),await this.chunkedTerminalWrite(y,TERMINAL_CHUNK_SIZE,d),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.terminal.scrollToBottom(),_crashDiag.log("CACHE_DONE")}else v&&(this._resetTerminalForReplay(),A=!0,_crashDiag.log("CACHE_SKIP_BUSY"));if(c?.mode!=="shell"&&p&&(await new Promise(f=>setTimeout(f,TUI_REDRAW_SETTLE_MS)),this._isStaleSelect(a))){this._clearTerminalLoadState(e,a);return}this._setTerminalLoadState(e,a,"fetching"),_crashDiag.log("FETCH_START");const L=!this._fullHistoryLoaded.has(e);L&&this._fullHistoryLoaded.add(e);const R=await fetch(L?`/api/sessions/${e}/terminal?full=1`:`/api/sessions/${e}/terminal?tail=${TERMINAL_TAIL_SIZE}`);if(this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}const T=(await R.json())?.data??{};if(_crashDiag.log(`FETCH_DONE: ${T.terminalBuffer?(T.terminalBuffer.length/1024).toFixed(0)+"KB":"empty"} truncated=${T.truncated}`),T.terminalBuffer){if(C||A||T.terminalBuffer!==y){if(_crashDiag.log(`REWRITE: ${(T.terminalBuffer.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),this._setHistoryTruncation(e,T),await this.chunkedTerminalWrite(T.terminalBuffer,TERMINAL_CHUNK_SIZE,d),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.terminal.scrollToBottom()}if(this.terminalBufferCache.set(e,T.terminalBuffer),this.terminalBufferCache.size>20){const b=this.terminalBufferCache.keys().next().value;this.terminalBufferCache.delete(b)}}else y||(this._resetTerminalForReplay(),E=!0);if(this._isLoadingBuffer&&this._finishBufferLoad(d,{flushQueued:E}),this._restoringFlushedState=!1,this._flushedOffsets?.has(e)&&this._localEchoOverlay){this._localEchoOverlay.setFlushed(this._flushedOffsets.get(e),this._flushedTexts?.get(e)||"",!1);const f=this._localEchoOverlay;this.terminal.write("",()=>{f.hasPending&&f.rerender()})}this.sendResize(e),(typeof requestIdleCallback=="function"?requestIdleCallback:f=>setTimeout(f,16))(()=>{if(a!==this._selectGeneration)return;this.respawnStatus[e]?(this.showRespawnBanner(),this.updateRespawnBanner(this.respawnStatus[e].state),document.getElementById("respawnCycleCount").textContent=this.respawnStatus[e].cycleCount||0,this.updateCountdownTimerDisplay(),this.updateActionLogDisplay(),Object.keys(this.respawnCountdownTimers[e]||{}).length>0&&this.startCountdownInterval()):(this.hideRespawnBanner(),this.stopCountdownInterval());const f=document.getElementById("taskPanel");f&&f.classList.contains("open")&&this.renderTaskPanel();const b=this.sessions.get(e);if(b&&(b.ralphLoop||b.ralphTodos)&&this.updateRalphState(e,{loop:b.ralphLoop,todos:b.ralphTodos}),this.renderRalphStatePanel(),this.updateCliInfoDisplay(),this.renderProjectInsightsPanel(),this.updateSubagentWindowVisibility(),this.loadAppSettingsFromStorage().showFileBrowser){const m=this.$("fileBrowserPanel");if(m&&(m.classList.add("visible"),this.loadFileBrowser(e),!this.fileBrowserDragListeners)){const w=m.querySelector(".file-browser-header");if(w){const g=()=>{if(!m.style.left){const u=m.getBoundingClientRect();m.style.left=`${u.left}px`,m.style.top=`${u.top}px`,m.style.right="auto"}};w.addEventListener("mousedown",g),w.addEventListener("touchstart",g,{passive:!0}),this.fileBrowserDragListeners=this.makeWindowDraggable(m,w),this.fileBrowserDragListeners._onFirstDrag=g}}}}),this._connectWs(e),_crashDiag.log("FOCUS"),i&&this.terminal&&this.terminal.focus(),this.scrollToLastNonEmptyLine(),typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible&&KeyboardHandler.onKeyboardShow(),this._clearTerminalLoadState(e,a),_crashDiag.log(`SELECT_DONE: ${(performance.now()-o).toFixed(0)}ms`),console.log(`[CRASH-DIAG] selectSession DONE: ${e.slice(0,8)} in ${(performance.now()-o).toFixed(0)}ms`)}catch(p){this._isLoadingBuffer&&this._finishBufferLoad(d),this._restoringFlushedState=!1,this._setTerminalLoadState(e,a,"failed"),console.error("Failed to load session terminal:",p)}}_cleanupSessionData(e){this._activeRename?.sessionId===e&&this._activeRename.cancel(),this.sessions.delete(e);const t=this.sessionOrder.indexOf(e);t!==-1&&(this.sessionOrder.splice(t,1),this.saveSessionOrder()),this.terminalBuffers.delete(e),this.terminalBufferCache.delete(e),this._clearHistoryTruncation(e),this._xtermSnapshots?.delete(e);try{localStorage.removeItem(`codeman-xs-${e}`)}catch{}this._flushedOffsets?.delete(e),this._flushedTexts?.delete(e),this._pendingDeliveries?.delete(e),this._seqCounters?.delete(e),this._postDraining?.delete(e),this._persistReliableState(),this.ralphStates.delete(e),this.ralphClosedSessions.delete(e),this.projectInsights.delete(e),this.pendingHooks.delete(e),this.tabAlerts.delete(e),this.attachmentHistoryCounts.delete(e),this.attachmentHistoryDrawerOpen&&this.activeSessionId===e&&this.closeAttachmentHistory?.(),this.terminalLoadStates.delete(e),this.clearCountdownTimers(e),this.closeSessionLogViewerWindows(e),this.closeSessionImagePopups(e),this.closeSessionAttachmentCards(e),this.closeSessionSubagentWindows(e,!0);const s=this.idleTimers.get(e);s&&(clearTimeout(s),this.idleTimers.delete(e)),delete this.respawnStatus[e],delete this.respawnTimers[e],delete this.respawnCountdownTimers[e],delete this.respawnActionLogs[e]}async closeSession(e,t=!0){try{if(await this._apiDelete(`/api/sessions/${e}?killMux=${t}`),this._cleanupSessionData(e),this.activeSessionId===e){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}if(this.sessionOrder.length>0&&this.sessions.size>0){const s=this.sessionOrder[0];this.selectSession(s,{auto:!0})}else this.terminal.clear(),this.showWelcome(),this.renderRalphStatePanel()}this.renderSessionTabs(),t?this.showToast("Session closed and tmux killed","success"):this.showToast("Tab hidden, tmux still running","info")}catch{this.showToast("Failed to close session","error")}}requestCloseSession(e){const t=this.sessions.get(e);if(!t)return;this.pendingCloseSessionId=e;const s=this.getSessionName(t),n=document.getElementById("closeConfirmSessionName");n.textContent=s;const i=document.getElementById("closeConfirmKillTitle");i&&(i.textContent=t.mode==="opencode"?"Kill Tmux & OpenCode":t.mode==="codex"?"Kill Tmux & Codex":t.mode==="gemini"?"Kill Tmux & Gemini":t.mode==="antigravity"?"Kill Tmux & Antigravity":t.mode==="pi"?"Kill Tmux & Pi":"Kill Tmux & Claude Code"),document.getElementById("closeConfirmModal").classList.add("active")}cancelCloseSession(){this.pendingCloseSessionId=null,document.getElementById("closeConfirmModal").classList.remove("active")}async confirmCloseSession(e=!0){const t=this.pendingCloseSessionId;this.cancelCloseSession(),t&&await this.closeSession(t,e)}nextSession(){if(this.sessionOrder.length<=1)return;const t=(this.sessionOrder.indexOf(this.activeSessionId)+1)%this.sessionOrder.length;this.selectSession(this.sessionOrder[t])}prevSession(){if(this.sessionOrder.length<=1)return;const t=(this.sessionOrder.indexOf(this.activeSessionId)-1+this.sessionOrder.length)%this.sessionOrder.length;this.selectSession(this.sessionOrder[t])}goHome(){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.terminal.clear(),this.showWelcome(),this.renderSessionTabs(),this.renderRalphStatePanel()}ralphWizardStep=1;ralphWizardConfig={taskDescription:"",completionPhrase:"COMPLETE",maxIterations:10,caseName:"testcase",enableRespawn:!1,generatedPlan:null,planGenerated:!1,skipPlanGeneration:!1,planDetailLevel:"detailed",existingPlan:null,useExistingPlan:!1};planLoadingTimer=null;planLoadingStartTime=null;async killActiveSession(){if(!this.activeSessionId){this.showToast("No active session","warning");return}await this.closeSession(this.activeSessionId)}async killAllSessions(){if(this.sessions.size!==0&&confirm(`Kill all ${this.sessions.size} session(s)?`))try{await this._apiDelete("/api/sessions"),this.sessions.clear(),this.terminalBuffers.clear(),this.terminalBufferCache.clear(),this.terminalLoadStates.clear(),this._xtermSnapshots?.clear();try{for(const e of Object.keys(localStorage))e.startsWith("codeman-xs-")&&localStorage.removeItem(e)}catch{}this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.respawnStatus={},this.respawnCountdownTimers={},this.respawnActionLogs={},this.stopCountdownInterval(),this.hideRespawnBanner(),this.renderSessionTabs(),this.terminal.clear(),this.showWelcome(),this.showToast("All sessions killed","success")}catch{this.showToast("Failed to kill sessions","error")}}showTimer(){document.getElementById("timerBanner").style.display="flex",this.updateTimer(),this.timerInterval=setInterval(()=>this.updateTimer(),1e3)}hideTimer(){document.getElementById("timerBanner").style.display="none",this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}updateTimer(){if(!this.currentRun||this.currentRun.status!=="running")return;const e=Date.now(),t=Math.max(0,this.currentRun.endAt-e),s=this.currentRun.endAt-this.currentRun.startedAt,n=e-this.currentRun.startedAt,i=Math.min(100,n/s*100);document.getElementById("timerValue").textContent=this.formatTime(t),document.getElementById("timerProgress").style.width=`${i}%`,document.getElementById("timerMeta").textContent=`${this.currentRun.completedTasks} tasks | $${this.currentRun.totalCost.toFixed(2)}`}async stopCurrentRun(){if(this.currentRun)try{await fetch(`/api/scheduled/${this.currentRun.id}`,{method:"DELETE"})}catch{this.showToast("Failed to stop run","error")}}formatTime(e){const t=Math.floor(e/1e3),s=Math.floor(t/3600),n=Math.floor(t%3600/60),i=t%60;return`${s.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}`}updateCost(){this.updateTokens()}updateTokens(){this._clearTimer("_updateTokensTimeout"),this._updateTokensTimeout=setTimeout(()=>{this._updateTokensTimeout=null,this._updateTokensImmediate()},200)}_updateTokensImmediate(){let e=0,t=0;this.globalStats?(e=this.globalStats.totalInputTokens||0,t=this.globalStats.totalOutputTokens||0):this.sessions.forEach(r=>{r.tokens&&(e+=r.tokens.input||0,t+=r.tokens.output||0)});const s=e+t;this.totalTokens=s;const n=this.formatTokens(s),i=this.estimateCost(e,t),o=this.$("headerTokens");if(o){const a=this.loadAppSettingsFromStorage().showCost??!1;o.textContent=s>0?a?`${n} tokens \xB7 $${i.toFixed(2)}`:`${n} tokens`:"0 tokens",o.title=this.globalStats?`Lifetime: ${this.globalStats.totalSessionsCreated} sessions created${a?`
|
|
33
|
+
Estimated cost based on Claude Opus pricing`:""}`:`Token usage across active sessions${a?`
|
|
34
|
+
Estimated cost based on Claude Opus pricing`:""}`}}getShortcutRegistry(){const t=this.loadAppSettingsFromStorage().shortcutOverrides||{};return DEFAULT_SHORTCUTS.map(s=>{const n=t[s.id];if(!n)return s;const i={...s};return Array.isArray(n.bindings)&&(i.bindings=n.bindings,delete i.displayBindings),typeof n.disabled=="boolean"&&(i.disabled=n.disabled),i})}matchesShortcutEvent(e,t){return!t||!Array.isArray(t.bindings)?!1:t.bindings.some(s=>{const n=s.modifiers||[];return(n.includes("ctrl")||n.includes("meta"))!==!!(e.ctrlKey||e.metaKey)||n.includes("shift")!==!!e.shiftKey||n.includes("alt")!==!!e.altKey?!1:!!(s.code&&e.code===s.code||s.key&&typeof e.key=="string"&&e.key.toLowerCase()===s.key.toLowerCase())})}showShortcutOverlay(){const e=document.getElementById("shortcutOverlayModal");e&&(this.renderShortcutOverlay(),e.classList.add("active"),e.focus?.())}renderShortcutOverlay(){const e=document.getElementById("shortcutOverlayList");if(!e)return;const t=this.getShortcutRegistry(),s={};for(const i of t){const o=i.group||"General";s[o]||(s[o]=[]),s[o].push(i)}const n=i=>i.displayBindings?i.displayBindings.map(o=>`<kbd>${escapeHtml(o)}</kbd>`).join(" / "):i.bindings?i.bindings.map(o=>{const r=[...(o.modifiers||[]).map(a=>a.charAt(0).toUpperCase()+a.slice(1)),o.key||o.code||""];return`<kbd>${escapeHtml(r.join("+"))}</kbd>`}).join(" / "):"";e.innerHTML=Object.entries(s).map(([i,o])=>`<div class="shortcut-overlay-group"><div class="shortcut-overlay-group-label">${escapeHtml(i)}</div>`+o.map(r=>`<div class="shortcut-overlay-row"><span class="shortcut-overlay-label">${escapeHtml(r.label)}</span><span class="shortcut-overlay-keys">${n(r)}</span></div>`).join("")+"</div>").join("")}closeShortcutOverlay(){const e=document.getElementById("shortcutOverlayModal");e&&e.classList.remove("active")}}try{for(let h=0;h<localStorage.length;h++){const e=localStorage.key(h);if(e&&(e.startsWith("claudeman-")||e.startsWith("claudeman_"))){const t=e.replace(/^claudeman[-_]/,s=>"codeman"+s.charAt(s.length-1));localStorage.getItem(t)===null&&localStorage.setItem(t,localStorage.getItem(e))}}}catch{}let app;document.addEventListener("DOMContentLoaded",()=>{app=new CodemanApp,window.app=app}),window.MobileDetection=MobileDetection;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
instead of waiting until <script> tags at bottom-of-body are reached. -->
|
|
26
26
|
<link rel="preload" href="vendor/xterm.min.js" as="script">
|
|
27
27
|
<link rel="preload" href="constants.d474d7d9.js" as="script">
|
|
28
|
-
<link rel="preload" href="app.
|
|
28
|
+
<link rel="preload" href="app.2396d253.js" as="script">
|
|
29
29
|
<!-- Self-hosted xterm.js — eliminates CDN DNS/TLS latency (~100ms).
|
|
30
30
|
'defer' preserves execution order (xterm loads before fit addon). -->
|
|
31
31
|
<script defer src="vendor/xterm.min.js"></script>
|
|
@@ -3292,7 +3292,7 @@
|
|
|
3292
3292
|
<script defer src="input-cjk.63794d0b.js"></script>
|
|
3293
3293
|
<!-- Hardened markdown HTML sanitizer (wires DOMPurify). Must precede app.js. -->
|
|
3294
3294
|
<script defer src="sanitize-html.bc7078d6.js"></script>
|
|
3295
|
-
<script defer src="app.
|
|
3295
|
+
<script defer src="app.2396d253.js"></script>
|
|
3296
3296
|
<script defer src="terminal-ui.02b89e2c.js"></script>
|
|
3297
3297
|
<script defer src="respawn-ui.ff0dae4c.js"></script>
|
|
3298
3298
|
<script defer src="ralph-panel.6de2d0f8.js"></script>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/web/public/sw.js.gz
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The cross-session queue of prompts waiting on a human (see
|
|
5
5
|
* web/approval-inbox.ts, docs/approvals-inbox-plan.md):
|
|
6
|
-
* - `GET /api/approvals`: pending items, ownership-scoped in multi-user mode
|
|
6
|
+
* - `GET /api/approvals`: pending items, ownership-scoped in multi-user mode,
|
|
7
|
+
* with a pane-capture staleness sweep (a dialog answered in the terminal is
|
|
8
|
+
* resolved here rather than re-arming a tab alert on the next page load)
|
|
7
9
|
* - `POST /api/approvals/:id/answer`: answer in place by sending the
|
|
8
10
|
* corresponding keystrokes to the session (digit / Esc / idle-prompt text)
|
|
9
11
|
* - `POST /api/approvals/:id/dismiss`: drop the item without keystrokes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/approval-routes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"approval-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/approval-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAsCrD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CA4FnF"}
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The cross-session queue of prompts waiting on a human (see
|
|
5
5
|
* web/approval-inbox.ts, docs/approvals-inbox-plan.md):
|
|
6
|
-
* - `GET /api/approvals`: pending items, ownership-scoped in multi-user mode
|
|
6
|
+
* - `GET /api/approvals`: pending items, ownership-scoped in multi-user mode,
|
|
7
|
+
* with a pane-capture staleness sweep (a dialog answered in the terminal is
|
|
8
|
+
* resolved here rather than re-arming a tab alert on the next page load)
|
|
7
9
|
* - `POST /api/approvals/:id/answer`: answer in place by sending the
|
|
8
10
|
* corresponding keystrokes to the session (digit / Esc / idle-prompt text)
|
|
9
11
|
* - `POST /api/approvals/:id/dismiss`: drop the item without keystrokes
|
|
@@ -70,7 +72,18 @@ export function registerApprovalRoutes(app, ctx) {
|
|
|
70
72
|
approvalInbox.resolveForSession(item.sessionId, 'session_ended');
|
|
71
73
|
return false;
|
|
72
74
|
}
|
|
73
|
-
|
|
75
|
+
if (!canAccessOwned(user, session.owner))
|
|
76
|
+
return false;
|
|
77
|
+
// Staleness sweep, on the caller's own items only. Claude Code fires no
|
|
78
|
+
// "permission answered" hook, so a dialog answered IN the terminal leaves
|
|
79
|
+
// its item pending until `stop`, and this list is what re-arms tab alerts
|
|
80
|
+
// on every page load: a red "needs you" would come back for a dialog that
|
|
81
|
+
// is long gone. The pane is the truth, so ask it, using the SAME
|
|
82
|
+
// conservative rule the answer path uses (`verifyStillAnswerable`): only
|
|
83
|
+
// an item whose original frame parsed options can be resolved this way, so
|
|
84
|
+
// an unreadable capture keeps the alert rather than dropping it. Resolving
|
|
85
|
+
// here broadcasts `approval:resolved`, so the other devices clear too.
|
|
86
|
+
return approvalInbox.verifyStillAnswerable(item.id);
|
|
74
87
|
});
|
|
75
88
|
return { success: true, data: { approvals } };
|
|
76
89
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-routes.js","sourceRoot":"","sources":["../../../src/web/routes/approval-routes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"approval-routes.js","sourceRoot":"","sources":["../../../src/web/routes/approval-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAqB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAGpE;;;;;;;GAOG;AACH,SAAS,aAAa,CACpB,IAAkB,EAClB,MAA0F;IAE1F,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;QACtB,KAAK,SAAS;YACZ,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,KAAK,EAAE,mDAAmD,EAAE,CAAC;YAChG,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,KAAK,EAAE,mDAAmD,EAAE,CAAC;YAChG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC1B,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,KAAK,EAAE,sDAAsD,EAAE,CAAC;YACnG,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;YAC/F,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtD,OAAO,EAAE,KAAK,EAAE,UAAU,MAAM,CAAC,MAAM,yCAAyC,EAAE,CAAC;YACrF,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,KAAK,EAAE,8CAA8C,EAAE,CAAC;YAC3F,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACjE,IAAI,CAAC,IAAI;gBAAE,OAAO,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC;YACrE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAoB,EAAE,GAAgB;IAC3E,4EAA4E;IAC5E,0EAA0E;IAC1E,4CAA4C;IAC5C,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACtC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5D,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,aAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;gBACjE,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YACvD,wEAAwE;YACxE,0EAA0E;YAC1E,0EAA0E;YAC1E,0EAA0E;YAC1E,iEAAiE;YACjE,yEAAyE;YACzE,2EAA2E;YAC3E,2EAA2E;YAC3E,uEAAuE;YACvE,OAAO,aAAa,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAA6B,2BAA2B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9E,MAAM,MAAM,GAAG,SAAS,CAAC,oBAAoB,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,sEAAsE;YACtE,OAAO,mBAAmB,CAAC,YAAY,CAAC,SAAS,EAAE,yCAAyC,CAAC,CAAC;QAChG,CAAC;QACD,kEAAkE;QAClE,uDAAuD;QACvD,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC5D,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,OAAO,mBAAmB,CAAC,YAAY,CAAC,QAAQ,EAAE,4CAA4C,CAAC,CAAC;QAClG,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,uEAAuE;QACvE,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAClD,OAAO,mBAAmB,CAAC,YAAY,CAAC,QAAQ,EAAE,mCAAmC,CAAC,CAAC;QACzF,CAAC;QAED,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;YACxB,OAAO,mBAAmB,CAAC,YAAY,CAAC,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,mBAAmB,CAAC,YAAY,CAAC,QAAQ,EAAE,wCAAwC,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,mBAAmB,CAAC,YAAY,CAAC,gBAAgB,EAAE,gCAAgC,CAAC,CAAC;QAC9F,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IACpG,CAAC,CAAC,CAAC;IAEH;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,IAAI,CAAoC,0CAA0C,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACpG,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAA6B,4BAA4B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC/E,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,mBAAmB,CAAC,YAAY,CAAC,SAAS,EAAE,yCAAyC,CAAC,CAAC;QAChG,CAAC;QACD,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC5C,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";const _crashDiag={_entries:[],_maxEntries:50,_pageId:Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8),log(h){const e=`${new Date().toISOString().slice(11,23)} ${h}`;this._entries.push(e),this._entries.length>this._maxEntries&&this._entries.shift();try{localStorage.setItem("codeman-crash-diag",this._entries.join(`
|
|
2
|
-
`))}catch{}}};try{const h=localStorage.getItem("codeman-crash-diag");h&&(console.log(`[CRASH-DIAG] Previous session breadcrumbs:
|
|
3
|
-
`+h),navigator.sendBeacon("/api/crash-diag",JSON.stringify({data:h,id:_crashDiag._pageId+"-prev"})))}catch{}_crashDiag.log("PAGE LOAD");function _crashDiagBeacon(){try{_crashDiag._entries.length>0&&navigator.sendBeacon("/api/crash-diag",JSON.stringify({data:_crashDiag._entries.join(`
|
|
4
|
-
`),id:_crashDiag._pageId}))}catch{}}if(setInterval(()=>{try{localStorage.setItem("codeman-crash-heartbeat",String(Date.now()))}catch{}_crashDiagBeacon()},2e3),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&_crashDiagBeacon()}),window.addEventListener("error",h=>{_crashDiag.log(`ERROR: ${h.message} at ${h.filename}:${h.lineno}`),console.error("[CRASH-DIAG] Uncaught error:",h.message,`
|
|
5
|
-
File:`,h.filename,":",h.lineno,":",h.colno,`
|
|
6
|
-
Stack:`,h.error?.stack)}),window.addEventListener("unhandledrejection",h=>{_crashDiag.log(`UNHANDLED: ${h.reason?.message||h.reason}`),console.error("[CRASH-DIAG] Unhandled promise rejection:",h.reason?.message||h.reason,`
|
|
7
|
-
Stack:`,h.reason?.stack)}),typeof PerformanceObserver<"u")try{new PerformanceObserver(e=>{for(const t of e.getEntries())t.duration>200&&(_crashDiag.log(`LONG_TASK: ${t.duration.toFixed(0)}ms`),console.warn(`[CRASH-DIAG] Long task: ${t.duration.toFixed(0)}ms (type: ${t.entryType}, name: ${t.name})`))}).observe({type:"longtask",buffered:!0})}catch{}const _origGetContext=HTMLCanvasElement.prototype.getContext;HTMLCanvasElement.prototype.getContext=function(h,...e){const t=_origGetContext.call(this,h,...e);return(h==="webgl2"||h==="webgl")&&(this.addEventListener("webglcontextlost",s=>{_crashDiag.log(`WEBGL_LOST: ${this.width}x${this.height}`),console.error("[CRASH-DIAG] WebGL context LOST on canvas",this.width,"x",this.height,"\u2014 prevented:",s.defaultPrevented)}),this.addEventListener("webglcontextrestored",()=>{_crashDiag.log("WEBGL_RESTORED"),console.warn("[CRASH-DIAG] WebGL context restored")})),t};const _SSE_HANDLER_MAP=[[SSE_EVENTS.INIT,"_onInit"],[SSE_EVENTS.SESSION_CREATED,"_onSessionCreated"],[SSE_EVENTS.SESSION_UPDATED,"_onSessionUpdated"],[SSE_EVENTS.SESSION_DELETED,"_onSessionDeleted"],[SSE_EVENTS.SESSION_TERMINAL,"_onSSETerminal"],[SSE_EVENTS.SESSION_NEEDS_REFRESH,"_onSSENeedsRefresh"],[SSE_EVENTS.SESSION_CLEAR_TERMINAL,"_onSSEClearTerminal"],[SSE_EVENTS.SESSION_COMPLETION,"_onSessionCompletion"],[SSE_EVENTS.SESSION_ERROR,"_onSessionError"],[SSE_EVENTS.SESSION_EXIT,"_onSessionExit"],[SSE_EVENTS.SESSION_IDLE,"_onSessionIdle"],[SSE_EVENTS.SESSION_WORKING,"_onSessionWorking"],[SSE_EVENTS.SESSION_AUTO_CLEAR,"_onSessionAutoClear"],[SSE_EVENTS.SESSION_LIMIT_PAUSE_SCHEDULED,"_onSessionLimitPauseScheduled"],[SSE_EVENTS.SESSION_LIMIT_RESUME,"_onSessionLimitResume"],[SSE_EVENTS.SESSION_LIMIT_RESUME_CANCELLED,"_onSessionLimitResumeCancelled"],[SSE_EVENTS.SESSION_RESPAWN_BREAKER_TRIPPED,"_onSessionRespawnBreakerTripped"],[SSE_EVENTS.SESSION_CLI_INFO,"_onSessionCliInfo"],[SSE_EVENTS.SESSION_STATUS_TELEMETRY,"_onSessionStatusTelemetry"],[SSE_EVENTS.SCHEDULED_CREATED,"_onScheduledCreated"],[SSE_EVENTS.SCHEDULED_UPDATED,"_onScheduledUpdated"],[SSE_EVENTS.SCHEDULED_COMPLETED,"_onScheduledCompleted"],[SSE_EVENTS.SCHEDULED_STOPPED,"_onScheduledStopped"],[SSE_EVENTS.CRON_JOBS_CHANGED,"_onCronJobsChanged"],[SSE_EVENTS.CRON_JOB_DELETED,"_onCronJobsChanged"],[SSE_EVENTS.CRON_RUN_CREATED,"_onCronRunChanged"],[SSE_EVENTS.CRON_RUN_UPDATED,"_onCronRunChanged"],[SSE_EVENTS.RESPAWN_STARTED,"_onRespawnStarted"],[SSE_EVENTS.RESPAWN_STOPPED,"_onRespawnStopped"],[SSE_EVENTS.RESPAWN_STATE_CHANGED,"_onRespawnStateChanged"],[SSE_EVENTS.RESPAWN_CYCLE_STARTED,"_onRespawnCycleStarted"],[SSE_EVENTS.RESPAWN_BLOCKED,"_onRespawnBlocked"],[SSE_EVENTS.RESPAWN_AUTO_ACCEPT_SENT,"_onRespawnAutoAcceptSent"],[SSE_EVENTS.RESPAWN_DETECTION_UPDATE,"_onRespawnDetectionUpdate"],[SSE_EVENTS.RESPAWN_TIMER_STARTED,"_onRespawnTimerStarted"],[SSE_EVENTS.RESPAWN_TIMER_CANCELLED,"_onRespawnTimerCancelled"],[SSE_EVENTS.RESPAWN_TIMER_COMPLETED,"_onRespawnTimerCompleted"],[SSE_EVENTS.RESPAWN_ERROR,"_onRespawnError"],[SSE_EVENTS.RESPAWN_ACTION_LOG,"_onRespawnActionLog"],[SSE_EVENTS.TASK_CREATED,"_onTaskCreated"],[SSE_EVENTS.TASK_COMPLETED,"_onTaskCompleted"],[SSE_EVENTS.TASK_FAILED,"_onTaskFailed"],[SSE_EVENTS.TASK_UPDATED,"_onTaskUpdated"],[SSE_EVENTS.MUX_CREATED,"_onMuxCreated"],[SSE_EVENTS.MUX_KILLED,"_onMuxKilled"],[SSE_EVENTS.MUX_DIED,"_onMuxDied"],[SSE_EVENTS.MUX_STATS_UPDATED,"_onMuxStatsUpdated"],[SSE_EVENTS.REMOTE_SESSION_RECONNECTED,"_onRemoteSessionReconnected"],[SSE_EVENTS.REMOTE_RECONNECT_EXHAUSTED,"_onRemoteReconnectExhausted"],[SSE_EVENTS.SESSION_RALPH_LOOP_UPDATE,"_onRalphLoopUpdate"],[SSE_EVENTS.SESSION_RALPH_TODO_UPDATE,"_onRalphTodoUpdate"],[SSE_EVENTS.SESSION_RALPH_COMPLETION_DETECTED,"_onRalphCompletionDetected"],[SSE_EVENTS.SESSION_RALPH_STATUS_UPDATE,"_onRalphStatusUpdate"],[SSE_EVENTS.SESSION_CIRCUIT_BREAKER_UPDATE,"_onCircuitBreakerUpdate"],[SSE_EVENTS.SESSION_EXIT_GATE_MET,"_onExitGateMet"],[SSE_EVENTS.SESSION_BASH_TOOL_START,"_onBashToolStart"],[SSE_EVENTS.SESSION_BASH_TOOL_END,"_onBashToolEnd"],[SSE_EVENTS.SESSION_BASH_TOOLS_UPDATE,"_onBashToolsUpdate"],[SSE_EVENTS.HOOK_IDLE_PROMPT,"_onHookIdlePrompt"],[SSE_EVENTS.HOOK_PERMISSION_PROMPT,"_onHookPermissionPrompt"],[SSE_EVENTS.HOOK_ELICITATION_DIALOG,"_onHookElicitationDialog"],[SSE_EVENTS.HOOK_ELICITATION_COMPLETE,"_onHookElicitationComplete"],[SSE_EVENTS.HOOK_ELICITATION_RESPONSE,"_onHookElicitationResponse"],[SSE_EVENTS.HOOK_STOP,"_onHookStop"],[SSE_EVENTS.HOOK_TEAMMATE_IDLE,"_onHookTeammateIdle"],[SSE_EVENTS.HOOK_TASK_COMPLETED,"_onHookTaskCompleted"],[SSE_EVENTS.APPROVAL_PENDING,"_onApprovalPending"],[SSE_EVENTS.APPROVAL_UPDATED,"_onApprovalUpdated"],[SSE_EVENTS.APPROVAL_RESOLVED,"_onApprovalResolved"],[SSE_EVENTS.SUBAGENT_DISCOVERED,"_onSubagentDiscovered"],[SSE_EVENTS.SUBAGENT_UPDATED,"_onSubagentUpdated"],[SSE_EVENTS.SUBAGENT_TOOL_CALL,"_onSubagentToolCall"],[SSE_EVENTS.SUBAGENT_PROGRESS,"_onSubagentProgress"],[SSE_EVENTS.SUBAGENT_MESSAGE,"_onSubagentMessage"],[SSE_EVENTS.SUBAGENT_TOOL_RESULT,"_onSubagentToolResult"],[SSE_EVENTS.SUBAGENT_COMPLETED,"_onSubagentCompleted"],[SSE_EVENTS.WORKFLOW_RUN_DISCOVERED,"_onWorkflowRunDiscovered"],[SSE_EVENTS.WORKFLOW_RUN_UPDATED,"_onWorkflowRunUpdated"],[SSE_EVENTS.WORKFLOW_RUN_REMOVED,"_onWorkflowRunRemoved"],[SSE_EVENTS.IMAGE_DETECTED,"_onImageDetected"],[SSE_EVENTS.ATTACHMENT_DETECTED,"_onAttachmentDetected"],[SSE_EVENTS.TUNNEL_STARTED,"_onTunnelStarted"],[SSE_EVENTS.TUNNEL_STOPPED,"_onTunnelStopped"],[SSE_EVENTS.TUNNEL_PROGRESS,"_onTunnelProgress"],[SSE_EVENTS.TUNNEL_ERROR,"_onTunnelError"],[SSE_EVENTS.TUNNEL_QR_ROTATED,"_onTunnelQrRotated"],[SSE_EVENTS.TUNNEL_QR_REGENERATED,"_onTunnelQrRegenerated"],[SSE_EVENTS.TUNNEL_QR_AUTH_USED,"_onTunnelQrAuthUsed"],[SSE_EVENTS.PLAN_SUBAGENT,"_onPlanSubagent"],[SSE_EVENTS.PLAN_PROGRESS,"_onPlanProgress"],[SSE_EVENTS.PLAN_STARTED,"_onPlanStarted"],[SSE_EVENTS.PLAN_CANCELLED,"_onPlanCancelled"],[SSE_EVENTS.PLAN_COMPLETED,"_onPlanCompleted"],[SSE_EVENTS.ORCHESTRATOR_STATE_CHANGED,"_onOrchestratorStateChanged"],[SSE_EVENTS.ORCHESTRATOR_PLAN_PROGRESS,"_onOrchestratorPlanProgress"],[SSE_EVENTS.ORCHESTRATOR_PLAN_READY,"_onOrchestratorPlanReady"],[SSE_EVENTS.ORCHESTRATOR_PHASE_STARTED,"_onOrchestratorPhaseStarted"],[SSE_EVENTS.ORCHESTRATOR_PHASE_COMPLETED,"_onOrchestratorPhaseCompleted"],[SSE_EVENTS.ORCHESTRATOR_PHASE_FAILED,"_onOrchestratorPhaseFailed"],[SSE_EVENTS.ORCHESTRATOR_VERIFICATION,"_onOrchestratorVerification"],[SSE_EVENTS.ORCHESTRATOR_TASK_ASSIGNED,"_onOrchestratorTaskAssigned"],[SSE_EVENTS.ORCHESTRATOR_TASK_COMPLETED,"_onOrchestratorTaskCompleted"],[SSE_EVENTS.ORCHESTRATOR_TASK_FAILED,"_onOrchestratorTaskFailed"],[SSE_EVENTS.ORCHESTRATOR_COMPLETED,"_onOrchestratorCompleted"],[SSE_EVENTS.ORCHESTRATOR_ERROR,"_onOrchestratorError"],[SSE_EVENTS.CLIPBOARD_WRITE,"_onClipboardWrite"],[SSE_EVENTS.SESSION_ORDER_CHANGED,"_onSessionOrderChanged"],[SSE_EVENTS.WEBVIEW_CHANGED,"_onWebviewChanged"]];function parseSessionPrefix(h){if(!h)return null;const e=h.match(/^(w\d+-[a-zA-Z0-9_-]+|s\d+-[a-zA-Z0-9_-]+)/);if(!e)return null;const t=e[1],s=h.slice(t.length);return s===""?{prefix:t,suffix:""}:s.startsWith(": ")?{prefix:t,suffix:s.slice(2)}:null}const DEFAULT_SHORTCUTS=[{id:"show-shortcuts",group:"Panels",label:"Show Shortcuts",bindings:[{modifiers:["ctrl"],key:"?",code:"Slash"},{modifiers:["ctrl","shift"],key:"?"},{modifiers:["alt"],key:"?",code:"Slash"}],action:"showShortcutOverlay"},{id:"close-session",group:"Session",label:"Close Session",bindings:[{modifiers:["ctrl"],key:"w"}],action:"killActiveSession"},{id:"next-session",group:"Session",label:"Next Session",bindings:[{modifiers:["ctrl"],key:"Tab"}],action:"nextSession"},{id:"clear-terminal",group:"Terminal",label:"Clear Terminal",bindings:[{modifiers:["ctrl"],key:"l"}],action:"clearTerminal"},{id:"copy-selection",group:"Terminal",label:"Copy Selection",bindings:[{modifiers:["ctrl"],key:"c"},{modifiers:["ctrl","shift"],key:"C"}],action:"copyTerminalSelection"},{id:"increase-font",group:"Terminal",label:"Increase Font",bindings:[{modifiers:["ctrl"],key:"=",code:"Equal"},{modifiers:["ctrl"],key:"+",code:"Equal"}],action:"increaseFontSize"},{id:"decrease-font",group:"Terminal",label:"Decrease Font",bindings:[{modifiers:["ctrl"],key:"-",code:"Minus"}],action:"decreaseFontSize"},{id:"voice-input",group:"Terminal",label:"Voice Input",bindings:[{modifiers:["ctrl","shift"],key:"V"}],action:"toggleVoiceInput"},{id:"restore-terminal-size",group:"Terminal",label:"Restore Terminal Size",bindings:[{modifiers:["ctrl","shift"],key:"R"}],action:"restoreTerminalSize"},{id:"move-tab-left",group:"Tabs",label:"Move Active Tab Left",bindings:[{modifiers:["ctrl","shift"],key:"{",code:"BracketLeft"}],action:"moveActiveTabLeft"},{id:"move-tab-right",group:"Tabs",label:"Move Active Tab Right",bindings:[{modifiers:["ctrl","shift"],key:"}",code:"BracketRight"}],action:"moveActiveTabRight"},{id:"command-palette",group:"Session",label:"Find Open Session",bindings:[{modifiers:["ctrl"],key:"k",code:"KeyK"},{modifiers:["meta"],key:"k",code:"KeyK"},{modifiers:["alt"],key:"k",code:"KeyK"}],action:"openCommandPalette"},{id:"toggle-session-sidebar",group:"Session",label:"Toggle Session Sidebar",bindings:[{modifiers:["alt"],key:"b",code:"KeyB"}],action:"toggleSessionSidebar"},{id:"previous-next-session",group:"Session",label:"Previous / Next Session",displayBindings:["Alt/Option+[","Alt/Option+]"]},{id:"switch-tab-n",group:"Session",label:"Switch to Tab N",displayBindings:["Alt/Option+1-9"]},{id:"focus-tabs",group:"Tabs",label:"Focus Tabs",displayBindings:["ArrowLeft","ArrowRight","Home","End"]},{id:"activate-focused-tab",group:"Tabs",label:"Activate Focused Tab",displayBindings:["Enter","Space"]},{id:"insert-newline",group:"Terminal",label:"Insert Newline",displayBindings:["Shift+Enter","Ctrl+Enter"]},{id:"close-panels",group:"Panels",label:"Close Panels",displayBindings:["Escape"]}];class CodemanApp{constructor(){this.sessions=new Map,this._shortIdCache=new Map,this.sessionOrder=[],this.draggedTabId=null,this.cases=[],this.currentRun=null,this.totalTokens=0,this.globalStats=null,this.eventSource=null,this._clientId=typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"c-"+Math.random().toString(36).slice(2)+Date.now().toString(36),this._wsTabNonce=this._clientId,this.terminal=null,this.fitAddon=null,this.activeSessionId=null,this.soloSessionId=this._detectSoloSessionId(),this.isSoloWindow=!!this.soloSessionId,this.detachedSessions=new Set,this.detachedWindows=new Map,this._detachWatchTimers=new Map,this.windowChannel=null,this._redockGrace=new Map,this._detachPingPending=null,this._detachLivenessTimer=null,this._detachOrphanStrikes=new Map,this._initGeneration=0,this._initFallbackTimer=null,this._selectGeneration=0,this._fullHistoryLoaded=new Set,this._fullHistoryRepullAt=new Map,this._fullHistoryRepullInFlight=!1,this._fullHistoryRepullUseless=new Set,this.terminalLoadStates=new Map,this.respawnStatus={},this.respawnTimers={},this.respawnCountdownTimers={},this.respawnActionLogs={},this.timerCountdownInterval=null,this.terminalBuffers=new Map,this.editingSessionId=null,this.pendingCloseSessionId=null,this.muxSessions=[],this.ralphStates=new Map,this.subagents=new Map,this.subagentActivity=new Map,this.subagentToolResults=new Map,this.activeSubagentId=null,this.subagentPanelVisible=!1,this.workflowRuns=new Map,this.workflowRunDetails=new Map,this.activeWorkflowRunId=null,this.activeWorkflowPhaseIndex=null,this.ultracodeWindows=new Map,this.ultracodeWindowsClosed=new Set,this.ultracodeWindowCloseTimers=new Map,this.ultracodeWindowZIndex=1e3,this.subagentWindows=new Map,this.subagentWindowZIndex=ZINDEX_SUBAGENT_BASE,this.minimizedSubagents=new Map,this._subagentHideTimeout=null,this.subagentParentMap=new Map,this.teams=new Map,this.teamTasks=new Map,this.teammateMap=new Map,this.teammatePanesByName=new Map,this.teammateTerminals=new Map,this.terminalBufferCache=new Map,this.ralphStatePanelCollapsed=!0,this.ralphClosedSessions=new Set,this.planSubagents=new Map,this.planSubagentWindowZIndex=ZINDEX_PLAN_SUBAGENT_BASE,this.planGenerationStopped=!1,this.planAgentsMinimized=!1,this.wizardDragState=null,this.wizardDragListeners=null,this.wizardPosition=null,this.projectInsights=new Map,this.logViewerWindows=new Map,this.logViewerWindowZIndex=ZINDEX_LOG_VIEWER_BASE,this.projectInsightsPanelVisible=!1,this.orchestratorState=null,this.orchestratorPanelVisible=!1,this.currentSessionWorkingDir=null,this.imagePopups=new Map,this.imagePopupZIndex=ZINDEX_IMAGE_POPUP_BASE,this.attachmentCards=new Map,this.attachmentCardStack=null,this.attachmentHistoryCounts=new Map,this.attachmentHistoryItems=[],this.attachmentHistoryDrawerOpen=!1,this.fileBrowserData=null,this.fileBrowserExpandedDirs=new Set,this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1,this.fileBrowserDragListeners=null,this.fileBrowserShowHidden=this._loadFileBrowserShowHidden?.()??!1,this.filePreviewContent="",this._toastContainer=null,this._tunnelUrl=null,this.tabAlerts=new Map,this.pendingHooks=new Map,this.approvals=new Map,this._ws=null,this._wsSessionId=null,this._wsReady=!1,this._wsState="disconnected",this._wsLastRecvAt=0,this.pendingWrites=[],this.writeFrameScheduled=!1,this._wasAtBottomBeforeWrite=!0,this.syncWaitTimeout=null,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadSeq=0,this._bufferLoadOwner=null,this.flickerFilterBuffer="",this.flickerFilterActive=!1,this.flickerFilterTimeout=null,this._debounceTimers=Object.create(null),this.systemStatsInterval=null,this.sseReconnectTimeout=null,this._sseListenerCleanup=null,this.reconnectAttempts=0,this.maxReconnectAttempts=10,this.isOnline=navigator.onLine,this._sseLastMessageAt=0,this._sseStaleTimeoutMs=window.CodemanSseStale?.TIMEOUT_MS??45e3,this._sseStaleWatchdog=null,this._connDownSince=null,this._nextSseRetryAt=null,this._offlineOverlayDismissed=!1,this._offlineRetryPending=!1,this._offlineUiTicker=null,this._lastOfflineUiKey="",this._connectionStatus="connected",this._clientId="",this._seqCounters=new Map,this._pendingDeliveries=new Map,this._lastIndicatorDescriptor=null,this._postDraining=new Set,this._persistReliableTimer=null,this._reliableAckTimeoutMs=4e3,this._reliableMaxBytes=256*1024,this._loadReliableState(),this._reliableSweepTimer=setInterval(()=>this._redeliverSweep(),2e3),window.addEventListener("pagehide",()=>this._persistReliableNow()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?this._persistReliableNow():this._checkSseStale()}),this._localEchoOverlay=null,this._localEchoEnabled=!1,this._predictiveEcho=null,this._localEchoPolicy="off",this._restoringFlushedState=!1,this.activeFocusTrap=null,this.notificationManager=new NotificationManager(this),this.idleTimers=new Map,this._elemCache={},this.init()}$(e){return this._elemCache[e]||(this._elemCache[e]=document.getElementById(e)),this._elemCache[e]}_clearTimer(e){this[e]&&(clearTimeout(this[e]),this[e]=null)}_isStaleSelect(e){return e!==this._selectGeneration?(this._isLoadingBuffer&&this._finishBufferLoad(e),this._restoringFlushedState=!1,!0):!1}formatTokens(e){if(e>=1e6){const t=e/1e6;return t>=10?`${t.toFixed(1)}m`:`${t.toFixed(2)}m`}else if(e>=1e3){const t=e/1e3;return t>=100?`${t.toFixed(0)}k`:`${t.toFixed(1)}k`}return String(e)}estimateCost(e,t){const s=e/1e6*15,n=t/1e6*75;return s+n}setPendingHook(e,t){this.pendingHooks.has(e)||this.pendingHooks.set(e,new Set),this.pendingHooks.get(e).add(t),this.updateTabAlertFromHooks(e)}clearPendingHooks(e,t=null){const s=this.pendingHooks.get(e);s&&(t?s.delete(t):s.clear(),s.size===0&&this.pendingHooks.delete(e),this.updateTabAlertFromHooks(e))}markIdleAlertSeen(e){this.pendingHooks.get(e)?.has("idle_prompt")&&(this.clearPendingHooks(e,"idle_prompt"),this.acknowledgeIdleApprovalOnView?.(e))}updateTabAlertFromHooks(e){const t=this.pendingHooks.get(e);!t||t.size===0?this.tabAlerts.delete(e):t.has("permission_prompt")||t.has("elicitation_dialog")?this.tabAlerts.set(e,"action"):t.has("idle_prompt")&&this.tabAlerts.set(e,"idle"),this.renderSessionTabs()}init(){MobileDetection.init(),this._initWindowChannel(),this.isSoloWindow&&document.body.classList.add("solo-mode"),KeyboardHandler.init(),SwipeHandler.init(),VoiceInput.init(),KeyboardAccessoryBar.init();const e=this.loadAppSettingsFromStorage();KeyboardAccessoryBar.setMode(e.extendedKeyboardBar?"extended":"simple"),this.applyHeaderVisibilitySettings(),this.restorePlanUsageChip(),this.applySkin(),this.applyLocalization(),this.applySessionListLayout(),this.applyMonitorVisibility(),this.applyLineageLineSettings?.(),this._installLineageStripScrollListener?.(),this._setupTabMiddleClickClose(),this.initEntranceAnimations?.(),document.documentElement.classList.remove("mobile-init"),requestAnimationFrame(()=>{this.initTerminal(),this.loadFontSize(),this.connectSSE(),this._initFallbackTimer=setTimeout(()=>{this._initGeneration===0&&this.loadState()},3e3)}),this.registerServiceWorker(),this.loadTunnelStatus();const t=fetch("/api/settings").then(s=>s.ok?s.json():null).then(s=>s?.data??null).catch(()=>null);if(this.loadQuickStartCases(null,t),this._initRunMode(),this.initWebviews?.(),this.setupEventListeners(),MobileDetection.isTouchDevice()){const s=n=>{n&&n.addEventListener("touchstart",i=>{if(!KeyboardHandler.keyboardVisible)return;const o=i.target.closest("button");o&&(i.preventDefault(),o.click(),typeof app<"u"&&app.terminal&&app.terminal.focus())},{passive:!1})};s(document.querySelector(".toolbar")),s(document.querySelector(".welcome-overlay"))}this.setupOnlineDetection(),this.loadAppSettingsFromServer(t).then(()=>{this.applyHeaderVisibilitySettings(),this.applySkin(),this.applyLocalization(),this.applySessionListLayout(),this.applyMonitorVisibility(),this.applyLineageLineSettings?.(),typeof this.syncAllUltracodeFloatingWindows=="function"&&this.syncAllUltracodeFloatingWindows()}),document.body.classList.add("app-loaded")}_initWebGL(){if(!(typeof WebglAddon>"u"))try{this._webglAddon=new WebglAddon.WebglAddon,this._webglAddon.onContextLoss(()=>{console.error("[CRASH-DIAG] WebGL context LOST \u2014 falling back to canvas renderer"),_crashDiag.log("WEBGL_LOST"),this._disableWebGLSticky("context-lost"),this._disposeWebGLObserver(),this._webglAddon?.dispose(),this._webglAddon=null,this._scheduleTerminalRepaint()}),this.terminal.loadAddon(this._webglAddon),console.log("[CRASH-DIAG] WebGL renderer enabled"),this._installWebGLLongTaskGuard()}catch{}}_installWebGLLongTaskGuard(){if(typeof PerformanceObserver>"u"||this._webglLongTaskObserver)return;const e=performance.now(),t=[];try{this._webglLongTaskObserver=new PerformanceObserver(s=>{if(!this._webglAddon)return;const n=performance.now();n-e<WEBGL_FALLBACK.GRACE_MS||evaluateWebGLLongTaskTrip(t,s.getEntries(),n)&&(console.warn(`[CRASH-DIAG] WebGL long-task threshold (${t.length} stalls/${WEBGL_FALLBACK.WINDOW_MS}ms) \u2014 falling back to canvas renderer`),_crashDiag.log(`WEBGL_FALLBACK: ${t.length}`),this._disableWebGLSticky("long-tasks"),this._disposeWebGLObserver(),this._webglAddon?.dispose(),this._webglAddon=null,this._scheduleTerminalRepaint())}),this._webglLongTaskObserver.observe({type:"longtask",buffered:!1})}catch{}}_disposeWebGLObserver(){if(this._webglLongTaskObserver){try{this._webglLongTaskObserver.disconnect()}catch{}this._webglLongTaskObserver=null}}_scheduleTerminalRepaint(){if(this._terminalRepaintScheduled)return;this._terminalRepaintScheduled=!0,(typeof requestAnimationFrame=="function"?requestAnimationFrame:t=>setTimeout(t,0))(()=>{this._terminalRepaintScheduled=!1;try{this.terminal?.refresh(0,this.terminal.rows-1)}catch{}})}_disableWebGLSticky(e){try{localStorage.setItem("codeman-webgl-disabled",JSON.stringify({reason:e,at:Date.now()}))}catch{}}setupEventListeners(){const e={showShortcutOverlay:()=>this.showShortcutOverlay(),killActiveSession:()=>this.killActiveSession(),nextSession:()=>this.nextSession(),clearTerminal:()=>this.clearTerminal(),restoreTerminalSize:()=>this.restoreTerminalSize(),increaseFontSize:()=>this.increaseFontSize(),decreaseFontSize:()=>this.decreaseFontSize(),toggleVoiceInput:()=>VoiceInput.toggle(),moveActiveTabLeft:()=>this.moveActiveTabLeft(),moveActiveTabRight:()=>this.moveActiveTabRight(),toggleSessionSidebar:()=>this.toggleSessionSidebar()};document.addEventListener("keydown",s=>{if(!(s.isComposing||s.keyCode===229)){if(this.shouldOpenCommandPaletteFromShortcut?.(s)){s.preventDefault(),this.openCommandPalette();return}if(s.key==="Escape"&&(this.closeAllPanels(),this.closeHelp(),this.attachmentHistoryDrawerOpen&&this.closeAttachmentHistory(),this.closeSessionManager(),this.closeCommandPalette?.(),this.closeShortcutOverlay?.(),this._isSessionSidebarOverlay()&&this.isSessionSidebarActive()&&!this.isSessionSidebarCollapsed()&&(this.toggleSessionSidebar(),document.getElementById("sidebarToggleBtn")?.focus())),s.altKey&&!s.ctrlKey&&!s.shiftKey){const i=(s.code||"").match(/^Digit([1-9])$/);if(i){const o=parseInt(i[1],10)-1,a=this.sessionOrder.filter(l=>this.sessions.has(l));if(o<a.length)s.preventDefault(),this.selectSession(a[o]);else{const l=o-a.length,r=(this.webviewOrder||[])[l];r&&(s.preventDefault(),this.openWebview(r))}return}if(s.code==="BracketLeft"){s.preventDefault(),this.prevSession();return}if(s.code==="BracketRight"){s.preventDefault(),this.nextSession();return}}if(!(!s.ctrlKey&&!s.metaKey&&!s.altKey))for(const n of this.getShortcutRegistry()){if(n.disabled||!n.action)continue;const i=e[n.action];if(i&&this.matchesShortcutEvent(s,n)){s.preventDefault(),i();return}}}},!0);const t=this.$("headerTokens");t&&!t._statsHandlerAttached&&(t.classList.add("clickable"),t._statsHandlerAttached=!0,t.addEventListener("click",()=>this.openTokenStats())),this.setupColorPicker()}_updateSseSubscription(e){try{const t=JSON.stringify({clientId:this._clientId,sessions:e?[e]:null});fetch("/api/events/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:t,keepalive:!0}).catch(()=>{})}catch{}}_detectSoloSessionId(){try{if(typeof window<"u"&&typeof window.__CODEMAN_SOLO__=="string"&&window.__CODEMAN_SOLO__)return window.__CODEMAN_SOLO__;const e=location.pathname.match(/^\/session\/([^/]+)\/?$/);return e?decodeURIComponent(e[1]):null}catch{return null}}detachSession(e){if(this.isSoloWindow||!this.sessions.has(e)||this.detachedSessions.has(e)&&this._raiseDetached(e))return;const t="width=960,height=680,menubar=no,toolbar=no,location=no,status=no";let s=null;try{s=window.open("/session/"+encodeURIComponent(e),"codeman-session-"+e,t)}catch{}if(!s){this.showToast?.("Pop-out blocked \u2014 allow popups for this site to detach a session","error");return}this.detachedWindows.set(e,s),this._markDetached(e,!0),this._watchDetachedWindow(e,s),this._postWindowMessage({type:"detached",id:e});try{s.focus()}catch{}}_raiseDetached(e){const t=this.detachedWindows.get(e);if(t&&!t.closed){try{t.focus()}catch{}return!0}return t&&t.closed?(this._redock(e),!1):(this._postWindowMessage({type:"focus-request",id:e}),!0)}redockSession(e){const t=this.detachedWindows.get(e);if(t&&!t.closed)try{t.close()}catch{}this._postWindowMessage({type:"close-request",id:e}),this._redock(e)}_redock(e){const t=this._detachWatchTimers.get(e);t&&(clearInterval(t),this._detachWatchTimers.delete(e)),this._cancelPendingRedock(e),this._detachOrphanStrikes.delete(e),this.detachedWindows.delete(e),this._markDetached(e,!1)}_scheduleRedock(e){if(this._redockGrace.has(e))return;const t=setTimeout(()=>{this._redockGrace.delete(e),this._redock(e)},1500);this._redockGrace.set(e,t)}_cancelPendingRedock(e){const t=this._redockGrace.get(e);t&&(clearTimeout(t),this._redockGrace.delete(e))}_markDetached(e,t){t?this.detachedSessions.add(e):this.detachedSessions.delete(e);const s=this.$("sessionTabs"),n=s&&s.querySelector(`.session-tab[data-id="${e}"]`);n&&n.classList.toggle("detached",t)}_watchDetachedWindow(e,t){const s=this._detachWatchTimers.get(e);s&&clearInterval(s);const n=setInterval(()=>{(!t||t.closed)&&(clearInterval(n),this._detachWatchTimers.delete(e),this._redock(e))},800);this._detachWatchTimers.set(e,n)}_initWindowChannel(){if(!(typeof BroadcastChannel>"u")){try{this.windowChannel=new BroadcastChannel("codeman-windows")}catch{this.windowChannel=null;return}if(this.windowChannel.onmessage=e=>this._onWindowMessage(e.data),this.isSoloWindow){this._postWindowMessage({type:"detached",id:this.soloSessionId});const e=()=>this._postWindowMessage({type:"redocked",id:this.soloSessionId});window.addEventListener("pagehide",e),window.addEventListener("beforeunload",e)}else this._postWindowMessage({type:"roll-call"}),this._startDetachLiveness()}}_postWindowMessage(e){try{this.windowChannel&&this.windowChannel.postMessage(e)}catch{}}_onWindowMessage(e){if(!(!e||typeof e!="object")){if(this.isSoloWindow){if(e.type==="roll-call"){this._postWindowMessage({type:"detached",id:this.soloSessionId});return}if(e.id!==this.soloSessionId)return;if(e.type==="close-request")try{window.close()}catch{}else if(e.type==="focus-request")try{window.focus()}catch{}return}e.type==="detached"&&e.id?(this._cancelPendingRedock(e.id),this._detachPingPending?.delete(e.id),this._detachOrphanStrikes.delete(e.id),this._markDetached(e.id,!0)):e.type==="redocked"&&e.id?this._scheduleRedock(e.id):e.type==="detach-request"&&e.id&&this.detachSession(e.id)}}_startDetachLiveness(){this._detachLivenessTimer||(this._detachLivenessTimer=setInterval(()=>this._pingDetached(),5e3))}_pingDetached(){const e=[];for(const t of this.detachedSessions){const s=this.detachedWindows.get(t);s?s.closed&&this._redock(t):e.push(t)}e.length&&(this._detachPingPending=new Set(e),this._postWindowMessage({type:"roll-call"}),setTimeout(()=>{if(this._detachPingPending){for(const t of this._detachPingPending){const s=(this._detachOrphanStrikes.get(t)||0)+1;s>=2?(this._detachOrphanStrikes.delete(t),this._redock(t)):this._detachOrphanStrikes.set(t,s)}this._detachPingPending=null}},1200))}_applySoloMode(){document.body.classList.add("solo-mode");const e=this.sessions.get(this.soloSessionId);if(!e){this._showSoloSessionGone();return}this.activeSessionId=null,this.selectSession(this.soloSessionId);const t=this.getSessionName(e)||"Session",s=document.getElementById("soloSessionTitle");s&&(s.textContent=t,s.style.display="");const n=document.getElementById("soloRedockBtn");n&&(n.style.display=""),document.title=t+" \u2014 "+(window.CodemanI18n?.displayName||"Codeman"),this.notificationManager&&(this.notificationManager.originalTitle=document.title);const i=document.querySelector(".header-brand .logo");i&&(i.onclick=o=>{o.preventDefault()})}_showSoloSessionGone(){if(document.body.classList.add("solo-mode"),document.querySelector(".solo-gone-overlay"))return;const e=document.createElement("div");e.className="solo-gone-overlay",e.innerHTML='<h2>Session unavailable</h2><p>This session has ended or is no longer available.</p><button class="btn-primary" onclick="window.close()">Close window</button>',document.body.appendChild(e),document.title=(window.codemanT?.("Session ended")||"Session ended")+" \u2014 "+(window.CodemanI18n?.displayName||"Codeman")}connectSSE(){if(!navigator.onLine){this.setConnectionStatus("offline");return}this._clearTimer("sseReconnectTimeout"),this._sseStaleWatchdog&&(clearInterval(this._sseStaleWatchdog),this._sseStaleWatchdog=null),this._sseListenerCleanup&&(this._sseListenerCleanup(),this._sseListenerCleanup=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.reconnectAttempts===0?this.setConnectionStatus("connecting"):this.setConnectionStatus("reconnecting");const e=new URLSearchParams({clientId:this._clientId});this.activeSessionId&&e.set("sessions",this.activeSessionId),this.eventSource=new EventSource(`/api/events?${e.toString()}`);const t=[],s=(n,i)=>{const o=a=>{this._sseLastMessageAt=Date.now(),i(a)};this.eventSource.addEventListener(n,o),t.push({event:n,handler:o})};if(this._sseListenerCleanup=()=>{for(const{event:n,handler:i}of t)this.eventSource&&this.eventSource.removeEventListener(n,i);t.length=0},this.eventSource.onopen=()=>{this.reconnectAttempts=0,this._sseLastMessageAt=Date.now(),this.setConnectionStatus("connected")},this.eventSource.onerror=()=>{this.reconnectAttempts++,this.reconnectAttempts>=this.maxReconnectAttempts?this.setConnectionStatus("disconnected"):this.setConnectionStatus("reconnecting"),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this._clearTimer("sseReconnectTimeout");const n=this.reconnectAttempts<=1?200:Math.min(500*Math.pow(2,this.reconnectAttempts-2),3e4);this._nextSseRetryAt=Date.now()+n,this._updateConnectionLossUi(),this.sseReconnectTimeout=setTimeout(()=>this.connectSSE(),n)},!this._sseHandlerWrappers){this._sseHandlerWrappers=new Map;for(const[n,i]of _SSE_HANDLER_MAP){const o=this[i];this._sseHandlerWrappers.set(n,a=>{try{o.call(this,a.data?JSON.parse(a.data):{})}catch(l){console.error(`[SSE] Error handling ${n}:`,l)}})}}for(const[n]of _SSE_HANDLER_MAP)s(n,this._sseHandlerWrappers.get(n));for(const n of[SSE_EVENTS.SESSION_CREATED,SSE_EVENTS.SESSION_DELETED])s(n,()=>this._onSessionListMaybeChanged());s(SSE_EVENTS.DOCKER_EXPORT_COMPLETE,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Docker export ready: ${i.bundle} (${Math.round((i.sizeBytes||0)/1e6)} MB)`,"success"),this.refreshDockerExports?.()}catch(i){console.error("[SSE] docker export complete:",i)}}),s(SSE_EVENTS.DOCKER_EXPORT_FAILED,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Docker export failed: ${i.error||"unknown error"}`,"error")}catch(i){console.error("[SSE] docker export failed:",i)}}),s(SSE_EVENTS.DOCKER_IMPORT_COMPLETE,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Docker bundle imported as case "${i.name}"`,"success"),this.loadQuickStartCases?.(),this.refreshDockerExports?.()}catch(i){console.error("[SSE] docker import complete:",i)}}),s(SSE_EVENTS.DOCKER_CONTAINER_RECREATED,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Container for "${i.name}" removed \u2014 next launch recreates it with the new config`,"info")}catch(i){console.error("[SSE] docker container recreated:",i)}}),s(SSE_EVENTS.ADMIN_USERS_CHANGED,()=>{window.codemanAdmin?.onUsersChanged?.()}),s(SSE_EVENTS.DOCKER_IMAGE_BUILD_STARTED,()=>{this.showToast("Building the Codeman agent image (first Docker case, a few minutes)...","info",{duration:8e3})}),s(SSE_EVENTS.DOCKER_IMAGE_BUILD_COMPLETE,n=>{try{const i=n.data?JSON.parse(n.data):{};i.error?this.showToast(`Agent image build failed: ${i.error}`,"error"):this.showToast("Agent image ready. Starting the container...","success")}catch(i){console.error("[SSE] docker image build complete:",i)}}),s(SSE_EVENTS.DOCKER_IMAGE_BUILD_FAILED,n=>{try{const i=n.data?JSON.parse(n.data):{};this.showToast(`Agent image build failed: ${i.error||"unknown error"}`,"error")}catch(i){console.error("[SSE] docker image build failed:",i)}}),s(SSE_EVENTS.SESSION_PINNED,n=>{let i=null;try{i=JSON.parse(n.data)}catch{}if(i&&i.id){const o=this.sessions.get(i.id);o&&(o.pinned=i.pinned===!0,o.pinnedAt=i.pinned?i.pinnedAt:void 0)}this._onSessionListMaybeChanged()}),s(SSE_EVENTS.HEARTBEAT,()=>{}),this._sseStaleWatchdog=setInterval(()=>this._checkSseStale(),5e3)}_checkSseStale(){const e=window.CodemanSseStale;if(!e)return;const t=Date.now();e.compute({lastMessageAt:this._sseLastMessageAt,now:t,status:this._connectionStatus,isOnline:this.isOnline,timeoutMs:this._sseStaleTimeoutMs})&&(console.log(`[SSE] stream stale: no frame for ${t-this._sseLastMessageAt}ms (threshold ${this._sseStaleTimeoutMs}ms), forcing reconnect`),this.connectSSE())}_onInit(e){_crashDiag.log(`INIT: ${e.sessions?.length||0} sessions`),this.handleInit(e)}_onSessionCreated(e){this.sessions.set(e.id,e),this.sessionOrder.includes(e.id)||(this.sessionOrder.push(e.id),this.saveSessionOrder()),this.markSessionTabEntering?.(e.id),this.markTerminalEntering?.(e.id),e.parentSessionId&&this.markConnectionLineEntering?.("lineage:"+e.id),this.renderSessionTabs(),this.updateCost(),this.sessions.size===1&&this.startSystemStatsPolling()}_onSessionUpdated(e){const t=e.session||e,s=this.sessions.get(t.id),n=t.claudeSessionId&&(!s||!s.claudeSessionId);this.sessions.set(t.id,t),this.renderSessionTabs(),this.updateCost(),t.id===this.activeSessionId&&t.tokens&&this.updateRespawnTokens(t.tokens),this.updateSubagentParentNames(t.id),n&&(this.recheckOrphanSubagents(),requestAnimationFrame(()=>{this.updateConnectionLines()}))}_onSessionDeleted(e){if(this._wsSessionId===e.id&&this._disconnectWs(),this.isSoloWindow&&e.id===this.soloSessionId&&this._showSoloSessionGone(),this.detachedSessions.has(e.id)&&this._redock(e.id),this._cleanupSessionData(e.id),this.activeSessionId===e.id){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.terminal.clear(),this.showWelcome()}this.renderSessionTabs(),this.renderRalphStatePanel(),this.renderProjectInsightsPanel(),this.sessions.size===0&&this.stopSystemStatsPolling()}_onSSETerminal(e){this._wsReady&&this._wsSessionId===e.id||this._onSessionTerminal(e)}_onSSENeedsRefresh(e){this._wsReady&&this._wsSessionId===e?.id||this._onSessionNeedsRefresh(e)}_onSSEClearTerminal(e){this._wsReady&&this._wsSessionId===e?.id||this._onSessionClearTerminal(e)}_onSessionTerminal(e){if(e.id===this.activeSessionId){if(e.data.length>32768&&_crashDiag.log(`TERMINAL: ${(e.data.length/1024).toFixed(0)}KB`),(this.pendingWrites?.reduce((s,n)=>s+n.length,0)||0)+(this.flickerFilterBuffer?.length||0)>131072){this._clientDropRecoveryTimer||(this._clientDropRecoveryTimer=setTimeout(()=>{this._clientDropRecoveryTimer=null,this._onSessionNeedsRefresh()},2e3));return}this.batchTerminalWrite(e.data)}}_sanitizeHtml(e){return typeof window<"u"&&typeof window.sanitizeMarkdownHtml=="function"?window.sanitizeMarkdownHtml(e):String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}_cleanTerminalBuffer(e){const t=e.replace(/\x1b\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]/g,"").replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,"").replace(/\x1b[PX^_][^\x1b]*\x1b\\/g,"").replace(/\x1b[NO()][A-Z0-9]?/g,"").replace(/\x1b[>=<78cDEHM]/g,"").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"").replace(/\r\n/g,`
|
|
8
|
-
`).replace(/\r/g,`
|
|
9
|
-
`),s=[/^\s*❯\s*/,/^\s*[⏵⏺⏸⏹]+\s*/,/^\s*✻\s*(Crunching|Crunched|Thinking)/i,/bypass permissions/i,/\bshift\+tab to cycle\b/i,/^\s*focus\s*$/,/^\s*new task\?/i,/\/clear to save/i,/^\s*─{5,}\s*$/,/\[(Opus|Sonnet|Haiku|GPT|Claude)[\s\S]*(tokens?|\$|¥|%|↑|↓)/i,/^\s*\[\d+[km]?\/\d+[km]?\]/i,/[█░▓▒]{3,}/,/^\s*\(.*\s*(tokens?|context).*\)\s*$/i];return t.split(`
|
|
10
|
-
`).filter(o=>o.trim()?!s.some(l=>l.test(o)):!0).join(`
|
|
11
|
-
`).replace(/[ \t]+$/gm,"").replace(/\n{4,}/g,`
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`).trim()}_preprocessAsciiArt(e){const t=/[─-╿▀-▟]/,s=/```[\s\S]*?```/g,n=[];return e.replace(s,a=>(n.push(a),`__CODEMAN_FENCE_${n.length-1}__`)).split(/(\n{2,})/).map(a=>/^\n{2,}$/.test(a)||!a.trim()||a.includes("__CODEMAN_FENCE_")?a:t.test(a)?"\n```\n"+a+"\n```\n":a).join("").replace(/__CODEMAN_FENCE_(\d+)__/g,(a,l)=>n[Number(l)])}_renderMarkdown(e){const t=e||"";if(typeof marked<"u"&&marked.parse)try{const n=this._preprocessAsciiArt(t);let i=this._sanitizeHtml(marked.parse(n,{breaks:!0,gfm:!0}));i=i.replace(/<table>/g,'<div class="rv-table-wrap"><table>').replace(/<\/table>/g,"</table></div>");const o=/[─-╿▀-▟]/,a=document.createElement("template");return a.innerHTML=i,a.content.querySelectorAll("pre > code").forEach(l=>{const r=l.parentElement,d=o.test(l.textContent||""),c=document.createElement("div");c.className=d?"rv-code-wrap rv-diagram-wrap":"rv-code-wrap";const p=document.createElement("div");p.className="rv-code-actions";const u=document.createElement("button");if(u.className="rv-copy-btn",u.type="button",u.setAttribute("aria-label","Copy code"),u.setAttribute("title","Copy code"),p.appendChild(u),d){r.classList.add("rv-diagram");const _=document.createElement("button");_.className="rv-wrap-toggle",_.type="button",_.setAttribute("aria-label","Toggle line wrapping"),_.setAttribute("title","Toggle line wrapping"),p.appendChild(_)}r.parentNode.insertBefore(c,r),c.appendChild(p),c.appendChild(r)}),a.innerHTML}catch{}return`<pre style="white-space:pre-wrap;word-break:break-word">${t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</pre>`}_bindResponseViewerInteractions(e){!e||e.dataset.rvBound==="1"||(e.dataset.rvBound="1",e.addEventListener("click",async t=>{const s=t.target.closest("a.rv-path");if(s){t.preventDefault(),t.stopPropagation();const r=s.dataset.path;r&&this.openFilePreview(r,this.activeSessionId);return}const n=t.target.closest(".rv-copy-btn");if(n){t.preventDefault(),t.stopPropagation();const r=n.closest(".rv-code-wrap")?.querySelector("pre code"),d=r?await this._copyText(r.textContent||""):!1;n.classList.remove("rv-copied","rv-copy-failed"),n.classList.add(d?"rv-copied":"rv-copy-failed"),clearTimeout(n._resetTimer),n._resetTimer=setTimeout(()=>{n.classList.remove("rv-copied","rv-copy-failed")},1500);return}const i=t.target.closest(".rv-wrap-toggle");if(!i)return;t.preventDefault(),t.stopPropagation();const o=i.closest(".rv-diagram-wrap"),a=o?.querySelector("pre.rv-diagram");if(!a||!o)return;const l=a.classList.toggle("rv-nowrap");o.classList.toggle("rv-wrap-nowrap",l)}))}async _copyText(e){if(!e)return!1;try{if(navigator.clipboard?.writeText)return await navigator.clipboard.writeText(e),!0}catch{}try{const t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.cssText="position:fixed;top:0;left:0;opacity:0;pointer-events:none",document.body.appendChild(t),t.select();const s=document.execCommand("copy");return document.body.removeChild(t),s}catch{return!1}}_buildResponseViewerMessage(e,t,s){const n=document.createElement("div"),i=t==="user";n.className="rv-message "+(i?"rv-msg-user":"rv-msg-assistant");const o=document.createElement("div");o.className="rv-role "+(i?"rv-role-user":"rv-role-assistant"),o.textContent=i?"You":s,n.appendChild(o);const a=document.createElement("div");return a.className="rv-text",a.innerHTML=this._renderMarkdown(e),this._linkifyFilePaths(a),n.appendChild(a),n}_linkifyFilePaths(e){if(!e||typeof document>"u"||typeof absoluteFilePathPattern!="function")return;const t=absoluteFilePathPattern(),s=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];for(let i=s.nextNode();i;i=s.nextNode())i.parentElement?.closest("a")||(t.lastIndex=0,t.test(i.nodeValue||"")&&n.push(i));for(const i of n){const o=i.nodeValue,a=document.createDocumentFragment();let l=0,r;for(t.lastIndex=0;(r=t.exec(o))!==null;){const d=r[1];r.index>l&&a.appendChild(document.createTextNode(o.slice(l,r.index)));const c=document.createElement("a");c.className="rv-path",c.href="#",c.dataset.path=d,c.title=d,c.textContent=d,a.appendChild(c),l=r.index+d.length}l<o.length&&a.appendChild(document.createTextNode(o.slice(l))),i.parentNode?.replaceChild(a,i)}}_getResponseViewerAgentLabel(){const e=this.sessions.get(this.activeSessionId)?.mode;return e==="codex"?"Codex":e==="gemini"?"Gemini":e==="antigravity"?"Antigravity":e==="pi"?"Pi":e==="opencode"?"OpenCode":"Claude"}async toggleResponseViewer(){const e=document.getElementById("responseViewer"),t=document.getElementById("responseViewerBackdrop");if(!e)return;if(e.classList.contains("visible")){e.classList.remove("visible"),t.classList.remove("visible");return}if(this.activeSessionId)try{let o=((await(await fetch(`/api/sessions/${this.activeSessionId}/last-response`)).json())?.data??{}).text||"";const a=this.sessions.get(this.activeSessionId)?.mode||"claude";if(!o&&(a==="claude"||a==="shell")){const p=(await(await fetch(`/api/sessions/${this.activeSessionId}/terminal`)).json())?.data??{};p.terminalBuffer&&(o=this._cleanTerminalBuffer(p.terminalBuffer))}const l=document.getElementById("responseViewerBody");o?(l.innerHTML="",l.appendChild(this._buildResponseViewerMessage(o,"assistant",this._getResponseViewerAgentLabel())),this._bindResponseViewerInteractions(l)):l.textContent=window.codemanT?.("No response yet \u2014 send a message in this session first.")||"No response yet \u2014 send a message in this session first.";const r=document.getElementById("responseViewerTitle"),d=document.getElementById("responseViewerMore");r&&(r.textContent="Last Response"),d&&(d.style.display="",d.textContent="More"),e.classList.add("visible"),t.classList.add("visible"),l.scrollTop=0}catch(n){console.error("Failed to load response:",n)}}async loadFullContext(){if(!this.activeSessionId)return;const e=document.getElementById("responseViewerMore");e&&(e.textContent="...");try{const n=((await(await fetch(`/api/sessions/${this.activeSessionId}/last-response?context=full`)).json())?.data??{}).messages||[],i=document.getElementById("responseViewerBody"),o=document.getElementById("responseViewerTitle");if(!i)return;if(n.length===0){i.textContent="No conversation history available";return}const a=this._getResponseViewerAgentLabel();i.innerHTML="";for(const l of n)i.appendChild(this._buildResponseViewerMessage(l.text,l.role,a));this._bindResponseViewerInteractions(i),o&&(o.textContent=`Conversation (${n.length} messages)`),e&&(e.style.display="none"),i.scrollTop=i.scrollHeight}catch(t){console.error("Failed to load context:",t)}finally{e&&(e.textContent="More")}}async _onSessionNeedsRefresh(){if(!this.activeSessionId||!this.terminal||this._isLoadingBuffer)return;const e=this.activeSessionId;try{let t=await fetch(`/api/sessions/${e}/terminal?full=1`),s=(await t.json())?.data??{};if(s.terminalBuffer&&this._replayWouldShrinkBuffer(s.terminalBuffer)&&(t=await fetch(`/api/sessions/${e}/terminal?tail=${TERMINAL_TAIL_SIZE}`),s=(await t.json())?.data??{}),this.activeSessionId!==e)return;if(s.terminalBuffer){const n=this.terminal.buffer?.active,i=n?Math.max(0,(n.baseY||0)-(n.viewportY||0)):0;this.terminal.clear(),this.terminal.reset(),await this.chunkedTerminalWrite(s.terminalBuffer),this._setHistoryTruncation(e,s);const o=computeRewriteScrollLine({linesFromBottom:i,baseY:this.terminal.buffer?.active?.baseY??0});o===null||typeof this.terminal.scrollToLine!="function"?this.terminal.scrollToBottom():this.terminal.scrollToLine(o),this._localEchoOverlay?.rerender(),this.activeSessionId&&this.sendResize(this.activeSessionId)}}catch(t){console.error("needsRefresh reload failed:",t)}}async _onSessionClearTerminal(e){if(e.id===this.activeSessionId){if(this._isLoadingBuffer)return;try{const s=(await(await fetch(`/api/sessions/${e.id}/terminal`)).json())?.data??{};if(this.terminal.clear(),this.terminal.reset(),s.terminalBuffer){const n=s.terminalBuffer.replace(DEC_SYNC_STRIP_RE,"");await this.chunkedTerminalWrite(n)}this.sendResize(e.id),this._localEchoOverlay?.rerender()}catch(t){console.error("clearTerminal refresh failed:",t)}}}_onSessionCompletion(e){this.totalCost+=e.cost||0,this.updateCost(),e.id===this.activeSessionId&&(this.terminal.writeln(""),this.terminal.writeln(`\x1B[1;32m Done (Cost: $${(e.cost||0).toFixed(4)})\x1B[0m`))}_onSessionError(e){e.id===this.activeSessionId&&this.terminal.writeln(`\x1B[1;31m Error: ${e.error}\x1B[0m`),this._notifySession(e.id,"critical","session-error","Session Error",e.error||"Unknown error")}_onSessionExit(e){this._wsSessionId===e.id&&this._disconnectWs();const t=this.sessions.get(e.id);t&&(t.status="stopped",this.renderSessionTabs(),e.id===this.activeSessionId&&this._updateLocalEchoState()),e.code&&e.code!==0&&this._notifySession(e.id,"critical","session-crash","Session Crashed",`Exited with code ${e.code}`)}_onSessionIdle(e){const t=this.sessions.get(e.id);if(t&&(t.status="idle",this.renderSessionTabs(),this.sendPendingCtrlL(e.id),e.id===this.activeSessionId&&this._updateLocalEchoState()),!this.respawnStatus[e.id]?.enabled){const s=this.notificationManager?.preferences?.stuckThresholdMs||6e5;clearTimeout(this.idleTimers.get(e.id)),this.idleTimers.set(e.id,setTimeout(()=>{this._notifySession(e.id,"warning","session-stuck","Session Idle",`Idle for ${Math.round(s/6e4)}+ minutes`),this.idleTimers.delete(e.id)},s))}}_onSessionWorking(e){const t=this.sessions.get(e.id);t&&(t.status="busy",this.pendingHooks.has(e.id)||this.tabAlerts.delete(e.id),this.renderSessionTabs(),this.sendPendingCtrlL(e.id),e.id===this.activeSessionId&&this._updateLocalEchoState());const s=this.idleTimers.get(e.id);s&&(clearTimeout(s),this.idleTimers.delete(e.id))}_onSessionAutoClear(e){e.sessionId===this.activeSessionId&&(this.showToast(`Auto-cleared at ${e.tokens.toLocaleString()} tokens`,"info"),this.updateRespawnTokens(0)),this._notifySession(e.sessionId,"info","auto-clear","Auto-Cleared",`Context reset at ${(e.tokens||0).toLocaleString()} tokens`)}_onSessionLimitPauseScheduled(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=e.resumeAt);const s=new Date(e.resumeAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});e.sessionId===this.activeSessionId&&this.showToast(`Usage limit reached \u2014 auto-resume at ${s}`,"warning"),this._notifySession(e.sessionId,"warning","limit-pause","Usage Limit Reached",`Auto-resume scheduled for ${s}`),this.updateAutoResumeStatus(e.sessionId)}_onSessionLimitResume(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=void 0),e.sessionId===this.activeSessionId&&this.showToast("Usage limit reset \u2014 work resumed automatically","success"),this._notifySession(e.sessionId,"info","limit-resume","Auto-Resumed","Usage limit reset \u2014 continuing work"),this.updateAutoResumeStatus(e.sessionId)}_onSessionLimitResumeCancelled(e){const t=this.sessions.get(e.sessionId);t&&(t.autoResumeAt=void 0),this.updateAutoResumeStatus(e.sessionId)}_onSessionRespawnBreakerTripped(e){const s=this.sessions.get(e.sessionId)?.name||"Session";this.showToast?.(`${s} stopped: repeated crashes detected. Restart to retry.`,"error")}_onSessionCliInfo(e){const t=this.sessions.get(e.sessionId);t&&(e.version&&(t.cliVersion=e.version),e.model&&(t.cliModel=e.model),e.accountType&&(t.cliAccountType=e.accountType),e.latestVersion&&(t.cliLatestVersion=e.latestVersion)),e.sessionId===this.activeSessionId&&this.updateCliInfoDisplay()}_onSessionStatusTelemetry(e){this.updatePlanUsageChip(e);try{localStorage.setItem("codeman:planUsage",JSON.stringify({t:Date.now(),data:e}))}catch{}}restorePlanUsageChip(){try{const e=localStorage.getItem("codeman:planUsage");if(!e)return;const t=JSON.parse(e);t?.data&&Date.now()-(t.t||0)<12*3600*1e3&&this.updatePlanUsageChip(t.data)}catch{}}updatePlanUsageChip(e){const t=document.getElementById("planUsageChip");if(!t||!e)return;const s=r=>r&&typeof r.usedPercentage=="number"?Math.round(r.usedPercentage):null,n=s(e.fiveHour),i=s(e.sevenDay);if(n===null&&i===null)return;const o=r=>r>=85?"pu-red":r>=60?"pu-yellow":"pu-green",a=(r,d)=>{if(d===null)return"";const c=Math.round(Number(d));return Number.isFinite(c)?`<span class="pu-win"><span class="pu-label">${r}</span><span class="pu-val ${o(c)}">${c}%</span></span>`:""};t.innerHTML=[a("5h",n),a("7d",i)].filter(Boolean).join('<span class="pu-sep">\xB7</span>');const l=r=>r&&r.resetAt?new Date(r.resetAt).toLocaleString():"\u2014";t.title=`Claude plan usage
|
|
15
|
-
5-hour limit: ${n??"\u2014"}% used (resets ${l(e.fiveHour)})
|
|
16
|
-
Weekly limit: ${i??"\u2014"}% used (resets ${l(e.sevenDay)})`}_onScheduledCreated(e){this.currentRun=e,this.showTimer()}_onScheduledUpdated(e){this.currentRun=e,this.updateTimer()}_onScheduledCompleted(e){this.currentRun=e,this.hideTimer(),this.showToast("Scheduled run completed!","success")}_onScheduledStopped(){this.currentRun=null,this.hideTimer()}setConnectionStatus(e){this._connectionStatus=e,e==="connected"?(this._connDownSince=null,this._nextSseRetryAt=null,this._offlineOverlayDismissed=!1):this._connDownSince===null&&(this._connDownSince=Date.now()),this._updateConnectionIndicator(),this._updateConnectionLossUi(),e==="connected"&&this._redeliverSweep()}_connectWs(e){this._disconnectWs(),this._wsState="connecting",this._updateConnectionIndicator();const t=location.protocol==="https:"?"wss:":"ws:",s=this._clientId?`${this._clientId}:${this._wsTabNonce}`:"",n=s?`?cid=${encodeURIComponent(s)}`:"",i=`${t}//${location.host}/ws/sessions/${e}/terminal${n}`,o=new WebSocket(i);this._ws=o,this._wsSessionId=e,o.onopen=()=>{this._ws===o&&(this._wsReady=!0,this._wsState="connected",this._wsReconnectAttempts=0,this._updateConnectionIndicator(),this.sendResize(e)?.catch?.(()=>{}),this._startMobileResizeRetry(e),this._onWsReady(e))},o.onmessage=a=>{if(this._ws===o){this._wsLastRecvAt=Date.now();try{const l=JSON.parse(a.data);l.t==="o"?this._onSessionTerminal({id:e,data:l.d}):l.t==="c"?this._onSessionClearTerminal({id:e}):l.t==="r"?this._onSessionNeedsRefresh({id:e}):l.t==="ia"&&this._onWsInputAck(l.seq)}catch{}}},o.onclose=a=>{if(this._ws!==o)return;this._ws=null,this._wsSessionId=null,this._wsReady=!1,this._stopMobileResizeRetry();const l=window.CodemanWsReconnect.plan(a.code,this._wsReconnectAttempts||0);_crashDiag.log(`WS CLOSE code=${a.code} reason=${a.reason||""} action=${l.action} attempts=${this._wsReconnectAttempts||0}`);const r=this.activeSessionId===e;if(l.action==="give-up")this._wsState=r?"fallback":"disconnected",this._updateConnectionIndicator();else if(l.action==="reconnect")if(r){this._wsState="reconnecting",this._updateConnectionIndicator();const d=l.delayMs+Math.floor(Math.random()*250);this._wsReconnectAttempts=(this._wsReconnectAttempts||0)+1,this._wsReconnectTimer=setTimeout(()=>{this._wsReconnectTimer=null,this.activeSessionId===e&&this._connectWs(e)},d)}else this._wsState="disconnected",this._updateConnectionIndicator();else this._wsState=r?"fallback":"disconnected",this._updateConnectionIndicator(),r&&(this._wsReconnectAttempts=(this._wsReconnectAttempts||0)+1,this._wsReconnectTimer=setTimeout(()=>{this._wsReconnectTimer=null,this.activeSessionId===e&&this._connectWs(e)},l.delayMs))},o.onerror=()=>{}}_disconnectWs(){this._clearTimer("_wsReconnectTimer"),this._wsState="disconnected",this._stopMobileResizeRetry(),this._ws&&(this._ws.onclose=null,this._ws.close(),this._ws=null,this._wsSessionId=null,this._wsReady=!1)}_startMobileResizeRetry(e){this._stopMobileResizeRetry(),(typeof MobileDetection<"u"&&MobileDetection.getDeviceType?MobileDetection.getDeviceType():"desktop")!=="desktop"&&(this._mobileResizeRetryTimer=setInterval(()=>{document.visibilityState==="visible"&&(!this._wsReady||this._wsSessionId!==e||typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible||this.sendResize(e)?.catch?.(()=>{}))},MOBILE_RESIZE_RETRY_MS))}_stopMobileResizeRetry(){this._mobileResizeRetryTimer&&(clearInterval(this._mobileResizeRetryTimer),this._mobileResizeRetryTimer=null)}_sendInputAsync(e,t,s){!e||!t||this._reliableSend(e,t,s?.useMux===!0)}_sendInputEphemeral(e,t){if(!(!e||!t)){if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e)try{this._ws.send(JSON.stringify({t:"i",d:t}));return}catch{}try{fetch(`/api/sessions/${e}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:t}),keepalive:!0}).catch(()=>{})}catch{}}}_reliableSend(e,t,s){const i={seq:this._nextSeq(e),data:t,useMux:!!s,ts:Date.now(),tries:0,sentAt:0};let o=this._pendingDeliveries.get(e);o||(o=[],this._pendingDeliveries.set(e,o)),o.push(i),this._persistReliableState(),this._updateConnectionIndicator(),this._drainSession(e)}_nextSeq(e){const t=(this._seqCounters.get(e)||0)+1;return this._seqCounters.set(e,t),t}_drainSession(e){const t=this._pendingDeliveries.get(e);if(!(!t||t.length===0)){if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e){for(const s of t)if(s.sentAt===0)try{this._ws.send(JSON.stringify({t:"i",d:s.data,seq:s.seq,cid:this._clientId})),s.sentAt=Date.now(),s.tries++}catch{break}return}this._postDraining.has(e)||(this._postDraining.add(e),(async()=>{try{for(;;){const s=this._pendingDeliveries.get(e);if(!s||s.length===0||this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e)break;const n=s[0];n.tries++,n.sentAt=Date.now();let i=null;try{const o={input:n.data,seq:n.seq,clientId:this._clientId};n.useMux&&(o.useMux=!0),i=await fetch(`/api/sessions/${e}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o),keepalive:n.data.length<65536})}catch{i=null}if(i&&i.ok)this._ackDelivery(e,n.seq);else if(i&&(i.status===404||i.status===410))this._ackDelivery(e,n.seq);else break}}finally{this._postDraining.delete(e)}})())}}_ackDelivery(e,t){const s=this._pendingDeliveries.get(e);if(s){const n=s.findIndex(i=>i.seq===t);n!==-1&&(s.splice(n,1),s.length===0&&this._pendingDeliveries.delete(e),this._pendingDeliveries.size===0?this._persistReliableNow():this._persistReliableState(),this._updateConnectionIndicator())}this.clearPendingHooks?.(e)}_onWsInputAck(e){this._wsSessionId&&Number.isInteger(e)&&this._ackDelivery(this._wsSessionId,e)}_onWsReady(e){const t=this._pendingDeliveries.get(e);if(t)for(const s of t)s.sentAt=0;this._drainSession(e)}_redeliverSweep(){if(this._pendingDeliveries.size!==0)for(const e of[...this._pendingDeliveries.keys()]){const t=this._pendingDeliveries.get(e);if(!t||t.length===0)continue;if(this._ws&&this._ws.readyState===WebSocket.OPEN&&this._wsSessionId===e){const n=t[0],i=n&&n.sentAt&&Date.now()-n.sentAt>this._reliableAckTimeoutMs,o=Date.now()-this._wsLastRecvAt>this._reliableAckTimeoutMs;if(i&&o){try{this._ws.close()}catch{}continue}if(i)for(const a of t)a.sentAt&&Date.now()-a.sentAt>this._reliableAckTimeoutMs&&(a.sentAt=0)}this._drainSession(e)}}_pendingBytes(){let e=0,t=0;for(const s of this._pendingDeliveries.values())for(const n of s)e+=n.data.length,t++;return{bytes:e,count:t}}_loadReliableState(){try{this._clientId=localStorage.getItem("codeman:clientId")||""}catch{this._clientId=""}if(!this._clientId){this._clientId="c-"+Math.random().toString(36).slice(2)+"-"+Date.now().toString(36);try{localStorage.setItem("codeman:clientId",this._clientId)}catch{}}try{const e=localStorage.getItem("codeman:pendingInput");if(!e)return;const t=JSON.parse(e);if(t&&t.seqs)for(const[s,n]of Object.entries(t.seqs))Number.isFinite(n)&&this._seqCounters.set(s,n);if(t&&t.pending)for(const[s,n]of Object.entries(t.pending))Array.isArray(n)&&n.length&&this._pendingDeliveries.set(s,n.filter(i=>i&&typeof i.data=="string"&&Number.isInteger(i.seq)).map(i=>({seq:i.seq,data:i.data,useMux:!!i.useMux,ts:i.ts||Date.now(),tries:0,sentAt:0})))}catch{}}_persistReliableState(){this._persistReliableTimer||(this._persistReliableTimer=setTimeout(()=>{this._persistReliableTimer=null,this._persistReliableNow()},250))}_persistReliableNow(){this._persistReliableTimer&&(clearTimeout(this._persistReliableTimer),this._persistReliableTimer=null);try{const e={};for(const[i,o]of this._seqCounters)e[i]=o;const t={};let s=0;for(const[i,o]of this._pendingDeliveries)if(o.length){t[i]=o.map(a=>({seq:a.seq,data:a.data,useMux:a.useMux,ts:a.ts,tries:a.tries}));for(const a of o)s+=a.data.length}const n=s>this._reliableMaxBytes?{seqs:e}:{seqs:e,pending:t};localStorage.setItem("codeman:pendingInput",JSON.stringify(n))}catch{}}_computeConnectionDescriptor(){const{bytes:e,count:t}=this._pendingBytes(),s=t>0,i=e>4,o=l=>l<1024?`${l}B`:`${(l/1024).toFixed(1)}KB`,a=i?` \xB7 ${o(e)} queued`:"";if(!this.isOnline||this._connectionStatus==="offline")return{display:"flex",dotClass:"connection-dot offline",text:i?`Offline (${o(e)} queued)`:"Offline",title:"No network connection"};if(this.activeSessionId){let l,r,d;switch(this._wsState){case"connected":l="connected",r="WS",d="Terminal connected over WebSocket";break;case"fallback":l="fallback",r="HTTP",d="WebSocket unavailable \u2014 input sent over HTTP";break;case"reconnecting":l="reconnecting",r="WS\u2026",d="Reconnecting WebSocket";break;default:l="reconnecting",r="WS\u2026",d="Connecting WebSocket";break}return{display:"flex",dotClass:`connection-dot ${l}`,text:`${r}${a}`,title:d}}return this._connectionStatus==="reconnecting"||this._connectionStatus==="disconnected"?{display:"flex",dotClass:"connection-dot reconnecting",text:i?`Reconnecting (${o(e)} queued)`:"Reconnecting...",title:"Reconnecting to server"}:s?{display:"flex",dotClass:"connection-dot draining",text:i?`Sending ${o(e)}...`:"Sending...",title:"Delivering queued input"}:{display:"none",dotClass:"",text:"",title:""}}_updateConnectionIndicator(){const e=this.$("connectionIndicator"),t=this.$("connectionDot"),s=this.$("connectionText");if(!e||!t||!s)return;const n=this._computeConnectionDescriptor(),i=this._lastIndicatorDescriptor;i&&i.display===n.display&&i.dotClass===n.dotClass&&i.text===n.text&&i.title===n.title||(this._lastIndicatorDescriptor=n,e.style.display=n.display,n.display!=="none"&&(t.className=n.dotClass,s.textContent=n.text,e.title=n.title))}setupOnlineDetection(){window.addEventListener("online",()=>{this.isOnline=!0,this.reconnectAttempts=0,this._connDownSince=Date.now(),this.connectSSE(),this._redeliverSweep()}),window.addEventListener("offline",()=>{this.isOnline=!1,this.setConnectionStatus("offline")})}_updateConnectionLossUi(){const e=window.CodemanConnectionLoss,t=this.$("offlineBanner"),s=this.$("offlineOverlay");if(!e||!t||!s)return;const n=e.compute({isOnline:this.isOnline,status:this._connectionStatus,everLoaded:this._initGeneration>0,downSince:this._connDownSince,now:Date.now(),nextRetryAt:this._nextSseRetryAt,overlayDismissed:this._offlineOverlayDismissed,retryPending:this._offlineRetryPending});this._connDownSince===null?this._stopOfflineTicker():this._startOfflineTicker();const i=this._offlineRetryPending?"Reconnecting\u2026":n.retryInSec!=null&&n.retryInSec>0?`Retrying in ${n.retryInSec}s`:"Retrying\u2026",o=`${n.mode}|${n.kind}|${i}`;if(o!==this._lastOfflineUiKey){if(this._lastOfflineUiKey=o,t.hidden=n.mode!=="banner",s.hidden=n.mode!=="overlay",document.body.classList.toggle("connection-lost",n.mode!=="hidden"),n.mode==="banner"){const a=this.$("offlineBannerText"),l=this.$("offlineBannerDetail");a&&(a.textContent=n.title),l&&(l.textContent=i)}else if(n.mode==="overlay"){const a=this.$("offlineOverlayTitle"),l=this.$("offlineOverlayBody"),r=this.$("offlineOverlayHost"),d=this.$("offlineOverlayStatus");a&&(a.textContent=n.title),l&&(l.textContent=n.detail),r&&(r.textContent=location.host),d&&(d.textContent=i)}}}_startOfflineTicker(){this._offlineUiTicker||(this._offlineUiTicker=setInterval(()=>this._updateConnectionLossUi(),1e3))}_stopOfflineTicker(){this._offlineUiTicker&&(clearInterval(this._offlineUiTicker),this._offlineUiTicker=null)}retryConnection(){this._offlineRetryPending=!0,this._nextSseRetryAt=null,this.reconnectAttempts=0,this._clearTimer("sseReconnectTimeout"),this.isOnline=navigator.onLine,this._lastOfflineUiKey="",this._updateConnectionLossUi(),this.connectSSE(),this.activeSessionId&&this._wsState!=="connected"&&(this._wsReconnectAttempts=0,this._connectWs(this.activeSessionId)),this._clearTimer("_offlineRetryTimer"),this._offlineRetryTimer=setTimeout(()=>{this._offlineRetryPending=!1,this._lastOfflineUiKey="",this._updateConnectionLossUi()},1500)}dismissOfflineOverlay(){this._offlineOverlayDismissed=!0,this._lastOfflineUiKey="",this._updateConnectionLossUi()}_updateCjkInputState(){const e=document.getElementById("cjkInput");if(!e)return;const t=this.loadAppSettingsFromStorage(),s=this.getDefaultSettings?.()||{},i=(this._serverCjkOverride||(t.cjkInputEnabled??s.cjkInputEnabled??!1))&&!!this.activeSessionId;e.classList.toggle("cjk-input-visible",!!i),document.body.classList.toggle("cjk-input-visible",!!i),e.style.display=i?"block":"none",e.setAttribute("aria-hidden",i?"false":"true"),i||(window.cjkActive=!1),typeof KeyboardHandler<"u"&&KeyboardHandler.updateLayoutForKeyboard()}_resetAllAppState(){this.sessions.clear(),this.ralphStates.clear(),this.terminalBuffers.clear(),this.terminalBufferCache.clear(),this._xtermSnapshots?.clear(),this.projectInsights.clear(),this.teams.clear(),this.teamTasks.clear();for(const e of this.idleTimers.values())clearTimeout(e);if(this.idleTimers.clear(),this._clearTimer("flickerFilterTimeout"),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1,this._localEchoOverlay?.rerender(),this._predictiveEcho?.clearPredictions(),this.pendingHooks.clear(),this.approvals?.clear(),this._parentNameCache&&this._parentNameCache.clear(),this.subagentActivity.clear(),this.subagentToolResults.clear(),this.workflowRuns&&this.workflowRuns.clear(),this.workflowRunDetails&&this.workflowRunDetails.clear(),this.activeWorkflowRunId=null,this.activeWorkflowPhaseIndex=null,MobileDetection.cleanup(),KeyboardHandler.cleanup(),MobileDetection.init(),KeyboardHandler.init(),this.tabAlerts.clear(),this.attachmentHistoryCounts.clear(),this._shownCompletions&&this._shownCompletions.clear(),this.notificationManager?.titleFlashInterval&&(clearInterval(this.notificationManager.titleFlashInterval),this.notificationManager.titleFlashInterval=null),this.notificationManager?.groupingMap){for(const{timeout:e}of this.notificationManager.groupingMap.values())clearTimeout(e);this.notificationManager.groupingMap.clear()}this.terminalResizeObserver&&(this.terminalResizeObserver.disconnect(),this.terminalResizeObserver=null),this.planLoadingTimer&&(clearInterval(this.planLoadingTimer),this.planLoadingTimer=null),this.timerCountdownInterval&&(clearInterval(this.timerCountdownInterval),this.timerCountdownInterval=null),this.runSummaryAutoRefreshTimer&&(clearInterval(this.runSummaryAutoRefreshTimer),this.runSummaryAutoRefreshTimer=null)}handleInit(e){this._clearTimer("_initFallbackTimer");const t=++this._initGeneration;if(this._serverCjkOverride=e.inputCjkForm||!1,this._updateCjkInputState(),e.planUsage&&this.updatePlanUsageChip(e.planUsage),e.version){const i=this.$("versionDisplay"),o=this.$("headerVersion");i&&(i.textContent=`v${e.version}`,i.title=`Codeman v${e.version}`),o&&(o.textContent=`v${e.version}`,o.title=`Codeman v${e.version}`)}VoiceInput.cleanup(),this._resetAllAppState(),e.sessions.forEach(i=>{this.sessions.set(i.id,i),(i.ralphLoop||i.ralphTodos)&&!this.ralphClosedSessions.has(i.id)&&this.ralphStates.set(i.id,{loop:i.ralphLoop||null,todos:i.ralphTodos||[]})});try{localStorage.removeItem("codeman-tab-meta")}catch{}if(Array.isArray(e.sessionOrder)&&e.sessionOrder.length)try{localStorage.setItem("codeman-session-order",JSON.stringify(e.sessionOrder))}catch{}this.syncSessionOrder(),e.respawnStatus?this.respawnStatus=e.respawnStatus:this.respawnStatus={},this.respawnTimers={},this.respawnCountdownTimers={},this.respawnActionLogs={},e.globalStats&&(this.globalStats=e.globalStats),this.totalCost=e.sessions.reduce((i,o)=>i+(o.totalCost||0),0),this.totalCost+=e.scheduledRuns.reduce((i,o)=>i+(o.totalCost||0),0);const s=e.scheduledRuns.find(i=>i.status==="running");if(s&&(this.currentRun=s,this.showTimer()),this.updateCost(),this.renderSessionTabs(),this.seedApprovals?.(),this.sessions.size>0?this.startSystemStatsPolling():this.stopSystemStatsPolling(),this.cleanupAllFloatingWindows(),e.subagents&&(this.subagents.clear(),this.subagentActivity.clear(),this.subagentToolResults.clear(),e.subagents.forEach(i=>{this.subagents.set(i.agentId,i)}),this.renderSubagentPanel(),this.subagentParentMap.clear(),this.loadSubagentParentMap().then(()=>{for(const[i,o]of this.subagentParentMap){const a=this.subagents.get(i);if(a&&this.sessions.has(o)){a.parentSessionId=o;const l=this.sessions.get(o);l&&(a.parentSessionName=this.getSessionName(l)),this.subagents.set(i,a)}}for(const[i]of this.subagents)this.subagentParentMap.has(i)||this.findParentSessionForSubagent(i);this.restoreSubagentWindowStates()})),e.workflowRuns&&this.seedWorkflowRuns(e.workflowRuns),t!==this._initGeneration)return;if(this.isSoloWindow){this._applySoloMode();return}const n=this.activeSessionId;if(this.activeSessionId=null,this.sessionOrder.length>0){let i=n;if(!i||!this.sessions.has(i))try{i=localStorage.getItem("codeman-active-session")}catch{}i&&this.sessions.has(i)?this.selectSession(i):this.selectSession(this.sessionOrder[0])}}async loadState(){try{const t=await(await fetch("/api/status")).json();this.handleInit(t?.data??{})}catch(e){console.error("Failed to load state:",e)}}_debouncedCall(e,t,s=100){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{this._debounceTimers[e]=null,t.call(this)},s)}getSessionListLayout(){if(this.soloSessionId)return"header";const e=this.loadAppSettingsFromStorage(),t=this.getDefaultSettings();return(e.sessionListLayout??t.sessionListLayout??"header")==="sidebar"?"sidebar":"header"}isSessionSidebarActive(){return document.documentElement.dataset.sessionList==="sidebar"}_isSessionSidebarOverlay(){return window.innerWidth<1024}isSessionSidebarCollapsed(){if(this._sidebarCollapsedOverride!==void 0)return this._sidebarCollapsedOverride;let e=null;try{e=localStorage.getItem("codeman-sidebar-collapsed")}catch{}return e===null?this._isSessionSidebarOverlay():e==="1"}shouldToggleSessionSidebarFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey||!this.isSessionSidebarActive()||typeof this.getShortcutRegistry!="function"||typeof this.matchesShortcutEvent!="function")return!1;const t=this.getShortcutRegistry().find(s=>s.id==="toggle-session-sidebar");return!t||t.disabled?!1:this.matchesShortcutEvent(e,t)}applySessionListLayout(){const e=this.getSessionListLayout(),t=this.isSessionSidebarCollapsed(),s=document.documentElement.dataset.sessionList,n=document.getElementById("sessionTabs"),i=document.getElementById("sessionTabsHost"),o=document.getElementById("sessionSidebarList");if(!n||!i||!o)return;const a=e==="sidebar"?o:i;n.parentElement!==a&&a.appendChild(n),document.documentElement.dataset.sessionList=e,document.documentElement.dataset.sidebar=t?"collapsed":"expanded",n.setAttribute("aria-orientation",e==="sidebar"?"vertical":"horizontal");const l=document.getElementById("sidebarToggleBtn");if(l){l.classList.toggle("btn-sidebar-toggle--hidden",e!=="sidebar");const c=t?"Expand session sidebar":"Collapse session sidebar";l.setAttribute("aria-expanded",t?"false":"true"),l.setAttribute("aria-label",c),l.setAttribute("title",c)}const r=document.getElementById("sessionSidebar");if(r){r.classList.toggle("open",e==="sidebar"&&!t);const c=e==="sidebar"&&t&&this._isSessionSidebarOverlay();r.toggleAttribute("inert",c),c?r.setAttribute("aria-hidden","true"):r.removeAttribute("aria-hidden")}if(e!=="sidebar"){this._sidebarFilter="";const c=document.getElementById("sessionSidebarFilter");c&&(c.value="")}const d=this._tallTabsEnabled;this.applyTabWrapSettings(),s!==e&&d===this._tallTabsEnabled&&this._fullRenderSessionTabs(),e==="sidebar"&&n.classList.remove("tabs-auto-wrap"),this.applySidebarFilter(this._sidebarFilter),this.updateConnectionLines(),document.getElementById("welcomeOverlay")?.classList.contains("visible")&&this.showHomeSessions?.()}toggleSessionSidebar(){if(!this.isSessionSidebarActive())return;const e=!this.isSessionSidebarCollapsed();this._sidebarCollapsedOverride=e;try{localStorage.setItem("codeman-sidebar-collapsed",e?"1":"0")}catch{}e&&this.$("sessionSidebar")?.contains(document.activeElement)&&document.getElementById("sidebarToggleBtn")?.focus(),this.applySessionListLayout(),!e&&this._isSessionSidebarOverlay()&&this.$("sessionTabs")?.querySelector(".session-tab.active")?.focus()}closeSessionSidebarOnHandheld(){this._isSessionSidebarOverlay()&&(!this.isSessionSidebarActive()||this.isSessionSidebarCollapsed()||this.toggleSessionSidebar())}updateSidebarCount(){const e=document.getElementById("sessionSidebarCount");if(!e)return;const t=this.$("sessionTabs"),s=t?t.querySelectorAll(".session-tab:not(.tab-filtered-out)").length:this.sessions?.size??0;e.textContent=String(s)}applySidebarFilter(e){this._sidebarFilter=(e??"").trim().toLowerCase();const t=this.$("sessionTabs");if(!t)return;const n=this.isSessionSidebarActive()&&document.documentElement.dataset.sidebar!=="collapsed"?this._sidebarFilter:"";for(const i of t.querySelectorAll(".session-tab")){if(!n){i.classList.remove("tab-filtered-out");continue}const o=`${i.getAttribute("aria-label")||""} ${i.getAttribute("title")||""}`.toLowerCase();i.classList.toggle("tab-filtered-out",!o.includes(n))}this.updateSidebarCount()}renderSessionTabs(){this._inlineRenameActive||this._debouncedCall("sessionTabs",this._renderSessionTabsImmediate)}_updateActiveTabImmediate(e){const t=this.$("sessionTabs");if(!t)return;const s=t.querySelectorAll(".session-tab[data-id]");for(const n of s)n.dataset.id===e?n.classList.add("active"):n.classList.remove("active");this._scrollActiveTabIntoView(e)}_scrollActiveTabIntoView(e,t="smooth"){const s=this.$("sessionTabs");if(!s)return;const n=e&&s.querySelector(`.session-tab[data-id="${e}"]`)||s.querySelector(".session-tab.active");if(!n)return;if(this.isSessionSidebarActive()){n.scrollIntoView({block:"nearest"});return}const i=window.CodemanTabOverflow?.computeTabScrollLeft;if(!i)return;const o=s.getBoundingClientRect(),a=n.getBoundingClientRect(),l=i({scrollLeft:s.scrollLeft,clientWidth:s.clientWidth,scrollWidth:s.scrollWidth,tabLeft:a.left-o.left+s.scrollLeft,tabWidth:a.width});if(Math.abs(l-s.scrollLeft)<1)return;const r=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;typeof s.scrollTo=="function"?s.scrollTo({left:l,behavior:r?"auto":t}):s.scrollLeft=l}_tabAnchor(e){return this.isSessionSidebarActive()?{x:e.right,y:e.top+e.height/2,spawnLeft:e.right+14,spawnTop:e.top,vertical:!1}:{x:e.left+e.width/2,y:e.bottom,spawnLeft:e.left,spawnTop:e.bottom,vertical:!0}}_tabConnectorPath(e,t){if(e.vertical){const o=t.left+t.width/2,a=t.top,l=(e.y+a)/2;return`M ${e.x} ${e.y} C ${e.x} ${l}, ${o} ${l}, ${o} ${a}`}const s=t.left,n=t.top+t.height/2,i=(e.x+s)/2;return`M ${e.x} ${e.y} C ${i} ${e.y}, ${i} ${n}, ${s} ${n}`}_setTerminalLoadState(e,t,s){this.terminalLoadStates.set(e,{generation:t,phase:s}),this._updateTerminalLoadTab(e)}_clearTerminalLoadState(e,t){const s=this.terminalLoadStates.get(e);s&&s.generation!==t||(this.terminalLoadStates.delete(e),this._updateTerminalLoadTab(e))}_updateTerminalLoadTab(e){const t=this.$("sessionTabs")?.querySelector(`.session-tab[data-id="${e}"]`);if(!t)return;const s=this.terminalLoadStates.get(e);if(t.classList.toggle("tab-loading",!!s),s){if(t.setAttribute("aria-busy","true"),t.dataset.loadPhase=s.phase,!t.querySelector(".tab-load-spinner")){const n=document.createElement("span");n.className="tab-load-spinner",n.setAttribute("aria-hidden","true");const i=t.querySelector(".tab-number");i?i.insertAdjacentElement("afterend",n):t.insertBefore(n,t.firstChild)}}else t.setAttribute("aria-busy","false"),delete t.dataset.loadPhase,t.querySelector(".tab-load-spinner")?.remove()}_renderSessionTabsImmediate(){if(this._inlineRenameActive)return;const e=this.$("sessionTabs"),t=e.querySelectorAll(".session-tab[data-id]"),s=new Set([...t].map(r=>r.dataset.id)),n=new Set(this.sessions.keys()),i=[...e.querySelectorAll(".session-tab[data-webview-id]")].map(r=>r.dataset.webviewId),o=(this.webviewOrder||[]).filter(r=>this.webviews?.has(r)),a=i.length===o.length&&i.every((r,d)=>r===o[d]);if(s.size===n.size&&[...s].every(r=>n.has(r))&&a)for(const[r,d]of this.sessions){const c=e.querySelector(`.session-tab[data-id="${r}"]`);if(!c)continue;const p=r===this.activeSessionId&&!this.activeWebviewId,u=d.status||"idle",_=this.getSessionName(d),v=d.taskStats||{running:0,total:0},w=v.running>0,R=this.terminalLoadStates.get(r);if(p&&!c.classList.contains("active")?c.classList.add("active"):!p&&c.classList.contains("active")&&c.classList.remove("active"),c.classList.toggle("tab-loading",!!R),R){if(c.setAttribute("aria-busy","true"),c.dataset.loadPhase=R.phase,!c.querySelector(".tab-load-spinner")){const S=document.createElement("span");S.className="tab-load-spinner",S.setAttribute("aria-hidden","true");const g=c.querySelector(".tab-number");g?g.insertAdjacentElement("afterend",S):c.insertBefore(S,c.firstChild)}}else c.setAttribute("aria-busy","false"),delete c.dataset.loadPhase,c.querySelector(".tab-load-spinner")?.remove();const C=this.tabAlerts.get(r),k=C==="action",E=C==="idle",O=c.classList.contains("tab-alert-action"),f=c.classList.contains("tab-alert-idle");if(k&&!O?(c.classList.add("tab-alert-action"),c.classList.remove("tab-alert-idle")):E&&!f?(c.classList.add("tab-alert-idle"),c.classList.remove("tab-alert-action")):!C&&(O||f)&&c.classList.remove("tab-alert-action","tab-alert-idle"),!c.querySelector(".tab-number")){const S=this.sessionOrder.indexOf(r);if(S>=0&&S<9){const g=document.createElement("span");g.className="tab-number",g.textContent=String(S+1),c.insertBefore(g,c.firstChild)}}const b=c.querySelector(".tab-status");b&&!b.classList.contains(u)&&(b.className=`tab-status ${u}`);const L=c.querySelector(".tab-name");if(L){const S=parseSessionPrefix(_),g=S&&S.suffix?S.suffix:_;L.textContent!==g&&(L.textContent=g,c.title=S&&S.suffix?d.workingDir?`${S.prefix} (${d.workingDir})`:S.prefix:d.workingDir||"")}const m=c.querySelector(".tab-badge");if(w)if(m)m.textContent!==String(v.running)&&(m.textContent=v.running);else{this._fullRenderSessionTabs();return}else if(m){this._fullRenderSessionTabs();return}const y=c.querySelector(".tab-subagent-badge"),A=this.minimizedSubagents.get(r),T=A?.size||0;if(T>0&&y){const S=y.querySelector(".subagent-label"),g=T===1?"AGENT":`AGENTS (${T})`;S&&S.textContent!==g&&(S.textContent=g);const I=y.querySelector(".subagent-dropdown");if(I){const x=this.renderSubagentTabBadge(r,A),N=document.createElement("div");N.innerHTML=x;const D=N.querySelector(".subagent-dropdown");D&&(I.innerHTML=D.innerHTML)}}else if(T>0&&!y){const S=this.renderSubagentTabBadge(r,A),g=c.querySelector(".tab-actions");g&&g.insertAdjacentHTML("beforebegin",S)}else T===0&&y&&y.remove()}else this._fullRenderSessionTabs();this._lastRenderedActiveTabId=this.activeSessionId,this.updateTabOverflowMode(),this._applyTabEntrances?.(),this._refreshMobileOverviewIfVisible?.(),this._refreshHomeSessionsIfVisible?.(),(this._lineageEdgeCount>0||this.isSessionSidebarActive())&&this.updateConnectionLines(),this.applySidebarFilter(this._sidebarFilter)}updateTabOverflowMode(){const e=this.$("sessionTabs");if(!e)return;if(this.isSessionSidebarActive()){e.classList.remove("tabs-auto-wrap");return}const t=MobileDetection.getDeviceType(),s=this.loadAppSettingsFromStorage(),n=this.getDefaultSettings(),i=t==="desktop"?s.tabTwoRows??n.tabTwoRows??!1:!1;if(i||t!=="desktop"){e.classList.remove("tabs-auto-wrap");return}e.classList.remove("tabs-auto-wrap");const o=window.CodemanTabOverflow?.shouldAutoWrapTabs?window.CodemanTabOverflow.shouldAutoWrapTabs({deviceType:t,manualTwoRows:i,tabCount:this.sessions.size,scrollWidth:e.scrollWidth,clientWidth:e.clientWidth}):e.scrollWidth>e.clientWidth+1;e.classList.toggle("tabs-auto-wrap",o)}_setupTabMiddleClickClose(){const e=this.$("sessionTabs");!e||this._tabAuxClickBound||(this._tabAuxClickBound=!0,e.addEventListener("auxclick",t=>{if(t.button!==1)return;const s=t.target.closest?.(".session-tab");s&&(t.preventDefault(),t.stopPropagation(),s.dataset.id?this.requestCloseSession(s.dataset.id):s.dataset.webviewId&&this.closeWebviewTab?.(s.dataset.webviewId))}))}_fullRenderSessionTabs(){if(this._inlineRenameActive)return;const e=this.$("sessionTabs");this.isSessionSidebarActive()&&(this._tallTabsEnabled=!0,e.classList.add("tabs-show-folder"),e.classList.remove("tabs-two-rows","tabs-auto-wrap")),document.querySelectorAll("body > .subagent-dropdown").forEach(r=>r.remove()),this.cancelHideSubagentDropdown();const t=e.scrollLeft,s=e.scrollTop,n=this._lastRenderedActiveTabId,i=!e.querySelector(".session-tab"),o=[],a=this.sessionOrder;let l=0;for(const r of a){const d=this.sessions.get(r);if(!d)continue;const c=r===this.activeSessionId&&!this.activeWebviewId,p=d.status||"idle",u=this.getSessionName(d),_=d.mode||"claude",v=d.color||"default",w=d.taskStats||{running:0,total:0},R=w.running>0,C=this.tabAlerts.get(r),k=C==="action"?" tab-alert-action":C==="idle"?" tab-alert-idle":"",E=this.terminalLoadStates.get(r),O=this.minimizedSubagents.get(r),b=(O?.size||0)>0?this.renderSubagentTabBadge(r,O):"",L=this.renderUltracodeTabBadge?this.renderUltracodeTabBadge(r):"",m=d.workingDir&&d.workingDir.split("/").pop()||"",A=(this._tallTabsEnabled??!1)&&d.name&&m&&m!==u,T=parseSessionPrefix(u),S=T&&T.suffix?T.suffix:u,g=T&&T.suffix?d.workingDir?`${T.prefix} (${d.workingDir})`:T.prefix:d.workingDir||"";o.push(`<div class="session-tab ${c?"active":""}${k}${E?" tab-loading":""}${this.hasTabDetachOverride(r)?" tab-show-detach":""}" data-id="${r}" data-color="${v}" ${E?`data-load-phase="${escapeHtml(E.phase)}"`:""} onclick="app.handleSessionTabClick(event, ${escapeHtml(JSON.stringify(r))})" oncontextmenu="event.preventDefault(); app.startInlineRename(${escapeHtml(JSON.stringify(r))})" tabindex="0" role="tab" aria-selected="${c?"true":"false"}" aria-busy="${E?"true":"false"}" aria-label="${escapeHtml(u)} session" ${g?`title="${escapeHtml(g)}"`:""}>
|
|
17
|
-
${l<9?'<span class="tab-number">'+(l+1)+"</span>":""}
|
|
18
|
-
${E?'<span class="tab-load-spinner" aria-hidden="true"></span>':""}
|
|
19
|
-
<span class="tab-status ${p}" aria-hidden="true"></span>
|
|
20
|
-
<span class="tab-info">
|
|
21
|
-
<span class="tab-name-row">
|
|
22
|
-
${_==="shell"?'<span class="tab-mode shell" aria-hidden="true">sh</span>':_==="opencode"?'<span class="tab-mode opencode" aria-hidden="true">oc</span>':_==="codex"?'<span class="tab-mode codex" aria-hidden="true">cx</span>':_==="gemini"?'<span class="tab-mode gemini" aria-hidden="true">gm</span>':_==="antigravity"?'<span class="tab-mode antigravity" aria-hidden="true">ag</span>':_==="pi"?'<span class="tab-mode pi" aria-hidden="true">pi</span>':""}
|
|
23
|
-
<span class="tab-name" data-session-id="${r}">${escapeHtml(S)}</span>
|
|
24
|
-
<span class="tab-detached-badge" aria-hidden="true">detached</span>
|
|
25
|
-
</span>
|
|
26
|
-
${A?`<span class="tab-folder">\u{1F4C1} ${escapeHtml(m)}</span>`:""}
|
|
27
|
-
</span>
|
|
28
|
-
${R?`<span class="tab-badge" onclick="event.stopPropagation(); app.toggleTaskPanel()" aria-label="${w.running} running tasks">${w.running}</span>`:""}
|
|
29
|
-
${b}
|
|
30
|
-
${L}
|
|
31
|
-
<span class="tab-actions"><span class="tab-gear" onclick="event.stopPropagation(); app.openSessionOptions(${escapeHtml(JSON.stringify(r))})" title="Session options" aria-label="Session options" tabindex="0">⚙</span><span class="tab-detach" onclick="event.stopPropagation(); app.detachSession(${escapeHtml(JSON.stringify(r))})" title="Open in a new window" aria-label="Open session in a new window" tabindex="0">⧉</span><span class="tab-close" onclick="event.stopPropagation(); app.requestCloseSession(${escapeHtml(JSON.stringify(r))})" title="Close session" aria-label="Close session" tabindex="0">×</span></span>
|
|
32
|
-
</div>`),l++}o.push(this.renderWebviewTabs?this.renderWebviewTabs(l):""),e.innerHTML=o.join(""),e.scrollLeft=t,e.scrollTop=s,this._lastRenderedActiveTabId=this.activeSessionId,(i||n!==this.activeSessionId)&&this._scrollActiveTabIntoView(this.activeSessionId,i?"auto":"smooth"),this.setupTabDragHandlers(),this.setupTabKeyboardNavigation(e),this.updateConnectionLines(),this.updateTabOverflowMode(),this._applyTabEntrances?.(),this.applySidebarFilter(this._sidebarFilter)}setupTabKeyboardNavigation(e){this._tabKeydownHandler&&e.removeEventListener("keydown",this._tabKeydownHandler),this._tabKeydownHandler=t=>{if(!["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","Enter"," "].includes(t.key))return;const s=[...e.querySelectorAll(".session-tab:not(.tab-filtered-out)")],n=s.indexOf(document.activeElement);if((t.key==="Enter"||t.key===" ")&&n>=0){t.preventDefault();const o=s[n].dataset.id;this.selectSession(o,{forceReload:!0});return}if(n<0)return;let i;switch(t.key){case"ArrowLeft":case"ArrowUp":i=n>0?n-1:s.length-1;break;case"ArrowRight":case"ArrowDown":i=n<s.length-1?n+1:0;break;case"Home":i=0;break;case"End":i=s.length-1;break;default:return}t.preventDefault(),s[i]?.focus()},e.addEventListener("keydown",this._tabKeydownHandler)}handleSessionTabClick(e,t){return e?.preventDefault?.(),!(typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible===!0)&&MobileDetection.isTouchDevice()&&document.activeElement?.blur?.(),this.selectSession(t,{forceReload:!0})}syncSessionOrder(){const e=new Set(this.sessions.keys()),s=this.loadSessionOrder().filter(o=>e.has(o)),n=new Set(s),i=[...e].filter(o=>!n.has(o));this.sessionOrder=[...s,...i]}loadSessionOrder(){try{const e=localStorage.getItem("codeman-session-order");return e?JSON.parse(e):[]}catch{return[]}}saveSessionOrder(){try{localStorage.setItem("codeman-session-order",JSON.stringify(this.sessionOrder))}catch{}const e=[...this.sessionOrder];this._debouncedCall("saveSessionOrderServer",()=>{fetch("/api/session-order",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({order:e})}).catch(()=>{})},400)}_onSessionOrderChanged(e){if(!e||!Array.isArray(e.order))return;try{localStorage.setItem("codeman-session-order",JSON.stringify(e.order))}catch{}const t=JSON.stringify(this.sessionOrder);this.syncSessionOrder(),JSON.stringify(this.sessionOrder)!==t&&this._fullRenderSessionTabs()}setupTabDragHandlers(){const e=this.$("sessionTabs");e.querySelectorAll(".session-tab[data-id]").forEach(s=>{s.setAttribute("draggable","true"),s.addEventListener("dragstart",n=>{this.draggedTabId=s.dataset.id,s.classList.add("dragging"),n.dataTransfer.effectAllowed="move",n.dataTransfer.setData("text/plain",s.dataset.id)}),s.addEventListener("dragend",()=>{s.classList.remove("dragging"),this.draggedTabId=null,e.querySelectorAll(".session-tab").forEach(n=>{n.classList.remove("drag-over-left","drag-over-right")})}),s.addEventListener("dragover",n=>{if(n.preventDefault(),!this.draggedTabId||this.draggedTabId===s.dataset.id)return;n.dataTransfer.dropEffect="move";const i=s.getBoundingClientRect(),o=this.isSessionSidebarActive()?n.clientY<i.top+i.height/2:n.clientX<i.left+i.width/2;s.classList.toggle("drag-over-left",o),s.classList.toggle("drag-over-right",!o)}),s.addEventListener("dragleave",()=>{s.classList.remove("drag-over-left","drag-over-right")}),s.addEventListener("drop",n=>{if(n.preventDefault(),s.classList.remove("drag-over-left","drag-over-right"),!this.draggedTabId||this.draggedTabId===s.dataset.id)return;const i=s.dataset.id,o=this.draggedTabId,a=s.getBoundingClientRect(),l=this.isSessionSidebarActive()?n.clientY<a.top+a.height/2:n.clientX<a.left+a.width/2,r=this.sessionOrder.indexOf(o);let d=this.sessionOrder.indexOf(i);r===-1||d===-1||(this.sessionOrder.splice(r,1),d=this.sessionOrder.indexOf(i),d!==-1&&(l?this.sessionOrder.splice(d,0,o):this.sessionOrder.splice(d+1,0,o),this.saveSessionOrder(),this._fullRenderSessionTabs()))})})}moveActiveTabLeft(){if(!this.activeSessionId)return;const e=this.sessionOrder.indexOf(this.activeSessionId);e<=0||([this.sessionOrder[e-1],this.sessionOrder[e]]=[this.sessionOrder[e],this.sessionOrder[e-1]],this.saveSessionOrder(),this._fullRenderSessionTabs())}moveActiveTabRight(){if(!this.activeSessionId)return;const e=this.sessionOrder.indexOf(this.activeSessionId);e===-1||e>=this.sessionOrder.length-1||([this.sessionOrder[e],this.sessionOrder[e+1]]=[this.sessionOrder[e+1],this.sessionOrder[e]],this.saveSessionOrder(),this._fullRenderSessionTabs())}getShortId(e){if(!e)return"";let t=this._shortIdCache.get(e);return t||(t=e.slice(0,8),this._shortIdCache.set(e,t)),t}getSessionName(e){return e.name?e.name:e.workingDir?e.workingDir.split("/").pop()||e.workingDir:this.getShortId(e.id)}_notifySession(e,t,s,n,i){const o=this.sessions.get(e);this.notificationManager?.notify({urgency:t,category:s,sessionId:e,sessionName:o?.name||this.getShortId(e),title:n,message:i})}_isUsableXtermSnapshot(e){return!e||typeof e!="string"||e.length<8?!1:e.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,"").replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g,"").replace(/\x1b[()][0-2A-Z]/g,"").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"").trim().length>=3}_persistXtermSnapshot(e,t){const s="codeman-xs-",i=()=>Object.keys(localStorage).filter(o=>o.startsWith(s)&&o!==e);try{if(localStorage.getItem(e)===null){const o=new Set(Array.from(this.sessions?.keys?.()||[])),a=i().sort((l,r)=>Number(o.has(l.slice(s.length)))-Number(o.has(r.slice(s.length))));for(;a.length>=10;)localStorage.removeItem(a.shift())}try{localStorage.setItem(e,t)}catch{for(const a of i()){localStorage.removeItem(a);try{localStorage.setItem(e,t);return}catch{}}try{localStorage.removeItem(e)}catch{}}}catch{}}_cleanupPreviousSession(e){const t=this.activeSessionId?this.sessions?.get?.(this.activeSessionId):null;if(this.activeSessionId&&t?.mode!=="shell"&&this._serializeAddon&&this._xtermSnapshots)try{const s=this._serializeAddon.serialize({scrollback:1e3});if(this._isUsableXtermSnapshot(s)){if(this._xtermSnapshots.delete(this.activeSessionId),this._xtermSnapshots.set(this.activeSessionId,s),this._xtermSnapshots.size>20){const n=this._xtermSnapshots.keys().next().value;this._xtermSnapshots.delete(n)}s.length<256*1024&&this._persistXtermSnapshot(`codeman-xs-${this.activeSessionId}`,s)}else{this._xtermSnapshots.delete(this.activeSessionId);try{localStorage.removeItem(`codeman-xs-${this.activeSessionId}`)}catch{}}}catch{}if(this._disconnectWs(),typeof CjkInput<"u")CjkInput.clear();else{const s=document.getElementById("cjkInput");s&&(s.value="")}this._clearTimer("flickerFilterTimeout"),this.flickerFilterBuffer="",this.flickerFilterActive=!1,this._tabCompletionSessionId=null,this._tabCompletionRetries=0,this._tabCompletionBaseText=null,this._clearTimer("_tabCompletionFallback"),this._clearTimer("_clientDropRecoveryTimer"),this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._bufferLoadOwner=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1;try{const s=this.terminal?._core?._compositionHelper;if(s?._isComposing){s._isComposing=!1;const n=this.terminal?.element?.querySelector(".xterm-helper-textarea");n&&n.dispatchEvent(new CompositionEvent("compositionend",{data:""}))}}catch{}if(this.activeSessionId){const s=this._localEchoOverlay?.pendingText||"",n=this._localEchoOverlay?.getFlushed()?.count||0,i=this._localEchoOverlay?.getFlushed()?.text||"";s&&this._sendInputAsync(this.activeSessionId,s);const o=n+s.length;o>0&&(this._flushedOffsets||(this._flushedOffsets=new Map),this._flushedTexts||(this._flushedTexts=new Map),this._flushedOffsets.set(this.activeSessionId,o),this._flushedTexts.set(this.activeSessionId,i+s))}this._localEchoOverlay?.clear(),this._predictiveEcho?.clearPredictions(),this._localEchoOverlay&&!this._flushedOffsets?.has(e)&&this._localEchoOverlay.suppressBufferDetection()}_resetTerminalForReplay(){this.terminal.reset(),this.terminal.write("\x1B[3J\x1B[H\x1B[2J")}async _maybeRefetchFullHistory({force:e=!1}={}){const t=this.activeSessionId;if(!t||this._fullHistoryRepullInFlight||this._isLoadingBuffer||this.detachedSessions?.has(t))return;const s=Date.now(),n=this._fullHistoryRepullUseless?.has(t)?6e4:4e3;if(!(!e&&s-(this._fullHistoryRepullAt.get(t)||0)<n)){this._fullHistoryRepullAt.set(t,s),this._fullHistoryRepullInFlight=!0;try{const o=(await(await fetch(`/api/sessions/${t}/terminal?full=1`)).json())?.data??{},a=o.terminalBuffer;if(!a||this.activeSessionId!==t)return;if(this._replayWouldShrinkBuffer(a)){(this._fullHistoryRepullUseless||=new Set).add(t),this._logScrollRouting?.("repull-refused-downgrade"),this._setHistoryTruncation(t,{...o,exhausted:!0});return}this._setHistoryTruncation(t,o),this._fullHistoryRepullUseless?.delete(t);const l=this.terminal.buffer.active.length;if(this._resetTerminalForReplay(),await this.chunkedTerminalWrite(a,TERMINAL_CHUNK_SIZE,t),this.activeSessionId!==t)return;this.terminalBufferCache.set(t,a);const r=this.terminal.buffer.active.length-l;r>0?this.terminal.scrollToLine(r):this.terminal.scrollToTop()}catch{}finally{this._fullHistoryRepullInFlight=!1}}}_setHistoryTruncation(e,t={}){e&&((this._historyTruncation||=new Map).set(e,{truncated:!!t.truncated,reason:t.truncationReason??null,source:t.source??null,fullSize:t.fullSize??0,retainedBytes:t.retainedBytes??0,exhausted:!!t.exhausted}),e===this.activeSessionId&&this._renderHistoryTruncationBanner())}_clearHistoryTruncation(e){this._historyTruncation?.delete(e),e===this.activeSessionId&&this._renderHistoryTruncationBanner()}_renderHistoryTruncationBanner(){const e=document.getElementById("historyTruncationBar");if(!e)return;const t=this.activeSessionId?this._historyTruncation?.get(this.activeSessionId):null,s=computeHistoryTruncationNotice(t||{});if(!s.visible){e.hidden=!0;return}e.textContent="";const n=document.createElement("span");if(n.className="history-trunc-text",n.textContent=s.message,e.appendChild(n),s.canLoadMore){const o=document.createElement("button");o.type="button",o.className="history-trunc-load",o.textContent="Load full history",o.onclick=()=>{o.disabled=!0,o.textContent="Loading\u2026",this._maybeRefetchFullHistory({force:!0}).finally(()=>{this._renderHistoryTruncationBanner()})},e.appendChild(o)}const i=document.createElement("button");i.type="button",i.className="history-trunc-dismiss",i.setAttribute("aria-label","Dismiss history notice"),i.textContent="\xD7",i.onclick=()=>{e.hidden=!0},e.appendChild(i),e.hidden=!1}_shouldFocusTerminalForTabSwitch(){return typeof MobileDetection>"u"||!MobileDetection.isTouchDevice()?!0:typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible}async selectSession(e,t={}){if(!this.isSoloWindow&&this.detachedSessions.has(e)&&this._raiseDetached(e))return;const s=t?.forceReload===!0;if(this.activeSessionId===e&&!s){this.markIdleAlertSeen(e);return}if(this.activeSessionId===e&&s){this.terminalBufferCache?.delete(e),this._xtermSnapshots?.delete(e);try{localStorage.removeItem(`codeman-xs-${e}`)}catch{}this._clearTimer("syncWaitTimeout"),this.pendingWrites=[],this.writeFrameScheduled=!1,this._isLoadingBuffer=!1,this._loadBufferQueue=null,this._chunkedWriteGen=(this._chunkedWriteGen||0)+1,this.activeSessionId=null}const n=this._shouldFocusTerminalForTabSwitch();n&&this.terminal&&this.terminal.focus();const i=performance.now(),o=this.sessions.get(e)?.name||e.slice(0,8);_crashDiag.log(`SELECT: ${o}`),console.log(`[CRASH-DIAG] selectSession START: ${e.slice(0,8)}`);const a=++this._selectGeneration;if(this._setTerminalLoadState(e,a,"resizing"),a!==this._selectGeneration){this._clearTerminalLoadState(e,a);return}this._hideWebviewLayer?.(),this._cleanupPreviousSession(e),this.activeSessionId=e,this._renderHistoryTruncationBanner();try{localStorage.setItem("codeman-active-session",e)}catch{}this._updateSseSubscription(e),this.hideWelcome(),this.playTerminalEntrance?.(e),this.markIdleAlertSeen(e),this._updateActiveTabImmediate(e),this.closeSessionSidebarOnHandheld(),this.renderSessionTabs(),this.updateAttachmentHistoryBadge?.(),this.attachmentHistoryDrawerOpen&&this.loadAttachmentHistory?.(e),this._updateLocalEchoState(),typeof KeyboardAccessoryBar<"u"&&KeyboardAccessoryBar.refreshForActiveSession(),this._flushedOffsets?.has(e)&&this._localEchoOverlay&&this._localEchoOverlay.setFlushed(this._flushedOffsets.get(e),this._flushedTexts?.get(e)||"",!1);const l=document.querySelector(`.session-tab.active[data-id="${e}"]`);l&&(l.classList.add("tab-glow"),l.addEventListener("animationend",()=>l.classList.remove("tab-glow"),{once:!0}));const r=this.sessions.get(e);if(this.currentSessionWorkingDir=r?.workingDir||null,r&&r.pid===null)if(r.respawnBlocked){const p=r.name||"Session";if(window.confirm(`${p} was stopped after crashing repeatedly. Restart it?`))try{await fetch(`/api/sessions/${e}/interactive`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clearBreaker:!0})}),r.respawnBlocked=!1,r.status="busy"}catch(u){console.error("Failed to restart crash-looped session:",u)}}else try{const p=r.mode==="shell"?`/api/sessions/${e}/shell`:`/api/sessions/${e}/interactive`;await fetch(p,{method:"POST"}),r.status="busy"}catch(p){console.error("Failed to attach to restored session:",p)}this._restoringFlushedState=!0;const d=this._beginBufferLoad(a);let c=!1;try{this.fitAddon&&this.fitAddon.fit();const p=await this.sendResize(e,{forceHttp:!0}).catch(()=>!1);if(this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}let u=this._xtermSnapshots?.get(e);if(u&&!this._isUsableXtermSnapshot(u)&&(this._xtermSnapshots?.delete(e),u=null),!u)try{const f=localStorage.getItem(`codeman-xs-${e}`);f&&this._isUsableXtermSnapshot(f)?(u=f,this._xtermSnapshots?.delete(e),this._xtermSnapshots?.set(e,f)):f&&localStorage.removeItem(`codeman-xs-${e}`)}catch{}const _=r&&(r.status==="busy"||r.status==="working");let v=!1;if(u&&!_&&r?.mode!=="shell"){if(_crashDiag.log(`SNAPSHOT_RESTORE: ${(u.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),await new Promise(f=>this.terminal.write(u,f)),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.scrollToLastNonEmptyLine(),_crashDiag.log("SNAPSHOT_RESTORE_DONE"),v=!0}const w=this.terminalBufferCache.get(e);let R=!1;if(w&&!_&&!v){if(_crashDiag.log(`CACHE_WRITE: ${(w.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),await this.chunkedTerminalWrite(w,TERMINAL_CHUNK_SIZE,d),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.terminal.scrollToBottom(),_crashDiag.log("CACHE_DONE")}else _&&(this._resetTerminalForReplay(),R=!0,_crashDiag.log("CACHE_SKIP_BUSY"));if(r?.mode!=="shell"&&p&&(await new Promise(f=>setTimeout(f,TUI_REDRAW_SETTLE_MS)),this._isStaleSelect(a))){this._clearTerminalLoadState(e,a);return}this._setTerminalLoadState(e,a,"fetching"),_crashDiag.log("FETCH_START");const C=!this._fullHistoryLoaded.has(e);C&&this._fullHistoryLoaded.add(e);const k=await fetch(C?`/api/sessions/${e}/terminal?full=1`:`/api/sessions/${e}/terminal?tail=${TERMINAL_TAIL_SIZE}`);if(this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}const E=(await k.json())?.data??{};if(_crashDiag.log(`FETCH_DONE: ${E.terminalBuffer?(E.terminalBuffer.length/1024).toFixed(0)+"KB":"empty"} truncated=${E.truncated}`),E.terminalBuffer){if(v||R||E.terminalBuffer!==w){if(_crashDiag.log(`REWRITE: ${(E.terminalBuffer.length/1024).toFixed(0)}KB`),this._setTerminalLoadState(e,a,"replaying"),this._resetTerminalForReplay(),this._setHistoryTruncation(e,E),await this.chunkedTerminalWrite(E.terminalBuffer,TERMINAL_CHUNK_SIZE,d),this._isStaleSelect(a)){this._clearTerminalLoadState(e,a);return}this.terminal.scrollToBottom()}if(this.terminalBufferCache.set(e,E.terminalBuffer),this.terminalBufferCache.size>20){const b=this.terminalBufferCache.keys().next().value;this.terminalBufferCache.delete(b)}}else w||(this._resetTerminalForReplay(),c=!0);if(this._isLoadingBuffer&&this._finishBufferLoad(d,{flushQueued:c}),this._restoringFlushedState=!1,this._flushedOffsets?.has(e)&&this._localEchoOverlay){this._localEchoOverlay.setFlushed(this._flushedOffsets.get(e),this._flushedTexts?.get(e)||"",!1);const f=this._localEchoOverlay;this.terminal.write("",()=>{f.hasPending&&f.rerender()})}this.sendResize(e),(typeof requestIdleCallback=="function"?requestIdleCallback:f=>setTimeout(f,16))(()=>{if(a!==this._selectGeneration)return;this.respawnStatus[e]?(this.showRespawnBanner(),this.updateRespawnBanner(this.respawnStatus[e].state),document.getElementById("respawnCycleCount").textContent=this.respawnStatus[e].cycleCount||0,this.updateCountdownTimerDisplay(),this.updateActionLogDisplay(),Object.keys(this.respawnCountdownTimers[e]||{}).length>0&&this.startCountdownInterval()):(this.hideRespawnBanner(),this.stopCountdownInterval());const f=document.getElementById("taskPanel");f&&f.classList.contains("open")&&this.renderTaskPanel();const b=this.sessions.get(e);if(b&&(b.ralphLoop||b.ralphTodos)&&this.updateRalphState(e,{loop:b.ralphLoop,todos:b.ralphTodos}),this.renderRalphStatePanel(),this.updateCliInfoDisplay(),this.renderProjectInsightsPanel(),this.updateSubagentWindowVisibility(),this.loadAppSettingsFromStorage().showFileBrowser){const m=this.$("fileBrowserPanel");if(m&&(m.classList.add("visible"),this.loadFileBrowser(e),!this.fileBrowserDragListeners)){const y=m.querySelector(".file-browser-header");if(y){const A=()=>{if(!m.style.left){const T=m.getBoundingClientRect();m.style.left=`${T.left}px`,m.style.top=`${T.top}px`,m.style.right="auto"}};y.addEventListener("mousedown",A),y.addEventListener("touchstart",A,{passive:!0}),this.fileBrowserDragListeners=this.makeWindowDraggable(m,y),this.fileBrowserDragListeners._onFirstDrag=A}}}}),this._connectWs(e),_crashDiag.log("FOCUS"),n&&this.terminal&&this.terminal.focus(),this.scrollToLastNonEmptyLine(),typeof KeyboardHandler<"u"&&KeyboardHandler.keyboardVisible&&KeyboardHandler.onKeyboardShow(),this._clearTerminalLoadState(e,a),_crashDiag.log(`SELECT_DONE: ${(performance.now()-i).toFixed(0)}ms`),console.log(`[CRASH-DIAG] selectSession DONE: ${e.slice(0,8)} in ${(performance.now()-i).toFixed(0)}ms`)}catch(p){this._isLoadingBuffer&&this._finishBufferLoad(d),this._restoringFlushedState=!1,this._setTerminalLoadState(e,a,"failed"),console.error("Failed to load session terminal:",p)}}_cleanupSessionData(e){this._activeRename?.sessionId===e&&this._activeRename.cancel(),this.sessions.delete(e);const t=this.sessionOrder.indexOf(e);t!==-1&&(this.sessionOrder.splice(t,1),this.saveSessionOrder()),this.terminalBuffers.delete(e),this.terminalBufferCache.delete(e),this._clearHistoryTruncation(e),this._xtermSnapshots?.delete(e);try{localStorage.removeItem(`codeman-xs-${e}`)}catch{}this._flushedOffsets?.delete(e),this._flushedTexts?.delete(e),this._pendingDeliveries?.delete(e),this._seqCounters?.delete(e),this._postDraining?.delete(e),this._persistReliableState(),this.ralphStates.delete(e),this.ralphClosedSessions.delete(e),this.projectInsights.delete(e),this.pendingHooks.delete(e),this.tabAlerts.delete(e),this.attachmentHistoryCounts.delete(e),this.attachmentHistoryDrawerOpen&&this.activeSessionId===e&&this.closeAttachmentHistory?.(),this.terminalLoadStates.delete(e),this.clearCountdownTimers(e),this.closeSessionLogViewerWindows(e),this.closeSessionImagePopups(e),this.closeSessionAttachmentCards(e),this.closeSessionSubagentWindows(e,!0);const s=this.idleTimers.get(e);s&&(clearTimeout(s),this.idleTimers.delete(e)),delete this.respawnStatus[e],delete this.respawnTimers[e],delete this.respawnCountdownTimers[e],delete this.respawnActionLogs[e]}async closeSession(e,t=!0){try{if(await this._apiDelete(`/api/sessions/${e}?killMux=${t}`),this._cleanupSessionData(e),this.activeSessionId===e){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}if(this.sessionOrder.length>0&&this.sessions.size>0){const s=this.sessionOrder[0];this.selectSession(s)}else this.terminal.clear(),this.showWelcome(),this.renderRalphStatePanel()}this.renderSessionTabs(),t?this.showToast("Session closed and tmux killed","success"):this.showToast("Tab hidden, tmux still running","info")}catch{this.showToast("Failed to close session","error")}}requestCloseSession(e){const t=this.sessions.get(e);if(!t)return;this.pendingCloseSessionId=e;const s=this.getSessionName(t),n=document.getElementById("closeConfirmSessionName");n.textContent=s;const i=document.getElementById("closeConfirmKillTitle");i&&(i.textContent=t.mode==="opencode"?"Kill Tmux & OpenCode":t.mode==="codex"?"Kill Tmux & Codex":t.mode==="gemini"?"Kill Tmux & Gemini":t.mode==="antigravity"?"Kill Tmux & Antigravity":t.mode==="pi"?"Kill Tmux & Pi":"Kill Tmux & Claude Code"),document.getElementById("closeConfirmModal").classList.add("active")}cancelCloseSession(){this.pendingCloseSessionId=null,document.getElementById("closeConfirmModal").classList.remove("active")}async confirmCloseSession(e=!0){const t=this.pendingCloseSessionId;this.cancelCloseSession(),t&&await this.closeSession(t,e)}nextSession(){if(this.sessionOrder.length<=1)return;const t=(this.sessionOrder.indexOf(this.activeSessionId)+1)%this.sessionOrder.length;this.selectSession(this.sessionOrder[t])}prevSession(){if(this.sessionOrder.length<=1)return;const t=(this.sessionOrder.indexOf(this.activeSessionId)-1+this.sessionOrder.length)%this.sessionOrder.length;this.selectSession(this.sessionOrder[t])}goHome(){this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.terminal.clear(),this.showWelcome(),this.renderSessionTabs(),this.renderRalphStatePanel()}ralphWizardStep=1;ralphWizardConfig={taskDescription:"",completionPhrase:"COMPLETE",maxIterations:10,caseName:"testcase",enableRespawn:!1,generatedPlan:null,planGenerated:!1,skipPlanGeneration:!1,planDetailLevel:"detailed",existingPlan:null,useExistingPlan:!1};planLoadingTimer=null;planLoadingStartTime=null;async killActiveSession(){if(!this.activeSessionId){this.showToast("No active session","warning");return}await this.closeSession(this.activeSessionId)}async killAllSessions(){if(this.sessions.size!==0&&confirm(`Kill all ${this.sessions.size} session(s)?`))try{await this._apiDelete("/api/sessions"),this.sessions.clear(),this.terminalBuffers.clear(),this.terminalBufferCache.clear(),this.terminalLoadStates.clear(),this._xtermSnapshots?.clear();try{for(const e of Object.keys(localStorage))e.startsWith("codeman-xs-")&&localStorage.removeItem(e)}catch{}this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.respawnStatus={},this.respawnCountdownTimers={},this.respawnActionLogs={},this.stopCountdownInterval(),this.hideRespawnBanner(),this.renderSessionTabs(),this.terminal.clear(),this.showWelcome(),this.showToast("All sessions killed","success")}catch{this.showToast("Failed to kill sessions","error")}}showTimer(){document.getElementById("timerBanner").style.display="flex",this.updateTimer(),this.timerInterval=setInterval(()=>this.updateTimer(),1e3)}hideTimer(){document.getElementById("timerBanner").style.display="none",this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}updateTimer(){if(!this.currentRun||this.currentRun.status!=="running")return;const e=Date.now(),t=Math.max(0,this.currentRun.endAt-e),s=this.currentRun.endAt-this.currentRun.startedAt,n=e-this.currentRun.startedAt,i=Math.min(100,n/s*100);document.getElementById("timerValue").textContent=this.formatTime(t),document.getElementById("timerProgress").style.width=`${i}%`,document.getElementById("timerMeta").textContent=`${this.currentRun.completedTasks} tasks | $${this.currentRun.totalCost.toFixed(2)}`}async stopCurrentRun(){if(this.currentRun)try{await fetch(`/api/scheduled/${this.currentRun.id}`,{method:"DELETE"})}catch{this.showToast("Failed to stop run","error")}}formatTime(e){const t=Math.floor(e/1e3),s=Math.floor(t/3600),n=Math.floor(t%3600/60),i=t%60;return`${s.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}`}updateCost(){this.updateTokens()}updateTokens(){this._clearTimer("_updateTokensTimeout"),this._updateTokensTimeout=setTimeout(()=>{this._updateTokensTimeout=null,this._updateTokensImmediate()},200)}_updateTokensImmediate(){let e=0,t=0;this.globalStats?(e=this.globalStats.totalInputTokens||0,t=this.globalStats.totalOutputTokens||0):this.sessions.forEach(a=>{a.tokens&&(e+=a.tokens.input||0,t+=a.tokens.output||0)});const s=e+t;this.totalTokens=s;const n=this.formatTokens(s),i=this.estimateCost(e,t),o=this.$("headerTokens");if(o){const l=this.loadAppSettingsFromStorage().showCost??!1;o.textContent=s>0?l?`${n} tokens \xB7 $${i.toFixed(2)}`:`${n} tokens`:"0 tokens",o.title=this.globalStats?`Lifetime: ${this.globalStats.totalSessionsCreated} sessions created${l?`
|
|
33
|
-
Estimated cost based on Claude Opus pricing`:""}`:`Token usage across active sessions${l?`
|
|
34
|
-
Estimated cost based on Claude Opus pricing`:""}`}}getShortcutRegistry(){const t=this.loadAppSettingsFromStorage().shortcutOverrides||{};return DEFAULT_SHORTCUTS.map(s=>{const n=t[s.id];if(!n)return s;const i={...s};return Array.isArray(n.bindings)&&(i.bindings=n.bindings,delete i.displayBindings),typeof n.disabled=="boolean"&&(i.disabled=n.disabled),i})}matchesShortcutEvent(e,t){return!t||!Array.isArray(t.bindings)?!1:t.bindings.some(s=>{const n=s.modifiers||[];return(n.includes("ctrl")||n.includes("meta"))!==!!(e.ctrlKey||e.metaKey)||n.includes("shift")!==!!e.shiftKey||n.includes("alt")!==!!e.altKey?!1:!!(s.code&&e.code===s.code||s.key&&typeof e.key=="string"&&e.key.toLowerCase()===s.key.toLowerCase())})}showShortcutOverlay(){const e=document.getElementById("shortcutOverlayModal");e&&(this.renderShortcutOverlay(),e.classList.add("active"),e.focus?.())}renderShortcutOverlay(){const e=document.getElementById("shortcutOverlayList");if(!e)return;const t=this.getShortcutRegistry(),s={};for(const i of t){const o=i.group||"General";s[o]||(s[o]=[]),s[o].push(i)}const n=i=>i.displayBindings?i.displayBindings.map(o=>`<kbd>${escapeHtml(o)}</kbd>`).join(" / "):i.bindings?i.bindings.map(o=>{const a=[...(o.modifiers||[]).map(l=>l.charAt(0).toUpperCase()+l.slice(1)),o.key||o.code||""];return`<kbd>${escapeHtml(a.join("+"))}</kbd>`}).join(" / "):"";e.innerHTML=Object.entries(s).map(([i,o])=>`<div class="shortcut-overlay-group"><div class="shortcut-overlay-group-label">${escapeHtml(i)}</div>`+o.map(a=>`<div class="shortcut-overlay-row"><span class="shortcut-overlay-label">${escapeHtml(a.label)}</span><span class="shortcut-overlay-keys">${n(a)}</span></div>`).join("")+"</div>").join("")}closeShortcutOverlay(){const e=document.getElementById("shortcutOverlayModal");e&&e.classList.remove("active")}}try{for(let h=0;h<localStorage.length;h++){const e=localStorage.key(h);if(e&&(e.startsWith("claudeman-")||e.startsWith("claudeman_"))){const t=e.replace(/^claudeman[-_]/,s=>"codeman"+s.charAt(s.length-1));localStorage.getItem(t)===null&&localStorage.setItem(t,localStorage.getItem(e))}}}catch{}let app;document.addEventListener("DOMContentLoaded",()=>{app=new CodemanApp,window.app=app}),window.MobileDetection=MobileDetection;
|
|
Binary file
|
|
Binary file
|