@spencer-kit/coder-studio 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import{r as e}from"./rolldown-runtime-CpWojdLp.js";import{$ as t,$t as n,A as r,At as i,B as a,C as o,Ct as s,Dt as c,E as l,Et as u,F as d,Gt as f,Ht as ee,I as p,Kt as m,L as te,Lt as h,Mt as ne,Nt as re,Ot as ie,P as g,Pt as _,Q as ae,Qt as v,R as oe,Rt as se,St as y,T as ce,Tt as le,Ut as ue,V as de,Wt as b,X as x,Zt as S,_t as C,at as w,b as fe,bt as T,c as E,en as D,gt as O,ht as pe,it as k,jt as me,kt as he,nn as ge,nt as _e,q as A,qt as j,rn as M,rt as N,t as ve,tn as P,tt as ye,vt as be,w as F,wt as I,x as xe,xt as L,yt as R,z,zt as Se}from"./components-omWbMLvf.js";import"./xterm-BVlcrOZ1.js";var B=e(M(),1),Ce=e(S(),1),V=O();function we(){return m()===`mobile`?(0,V.jsx)(ve,{}):(0,V.jsx)(E,{})}function H(){return(0,V.jsx)(j,{children:(0,V.jsx)(we,{})})}var U=1e3;function Te(){let e=D(me),t=D(le),r=D(f),[i,a]=n(b),[o,s]=n(ee),c=P(ue),l=(0,B.useRef)(null),u=(0,B.useRef)(null),d=(0,B.useCallback)(async()=>{if(!e)return!1;if(t!==`connected`)try{await e.connect()}catch{return c(null),a(e=>e===`gated`?e:`idle`),!1}if(l.current)return l.current;a(`claiming`);let n=e.sendCommand(`activation.claim`,{clientInstanceId:r}).then(e=>(s(e.generation),c(null),a(`active`),!0)).catch(()=>(c(null),a(e=>e===`gated`?e:`idle`),!1)).finally(()=>{l.current=null});return l.current=n,n},[r,t,s,c,a,e]);return(0,B.useEffect)(()=>{if(u.current!==null&&(clearTimeout(u.current),u.current=null),!(!e||t!==`connected`||i!==`idle`))return u.current=setTimeout(()=>{u.current=null,l.current||d()},U),()=>{u.current!==null&&(clearTimeout(u.current),u.current=null)}},[d,t,i,e]),(0,B.useEffect)(()=>()=>{u.current!==null&&(clearTimeout(u.current),u.current=null),!(!e||o===null)&&e.sendCommand(`activation.release`,{clientInstanceId:r,generation:o}).catch(()=>{})},[r,o,e]),{status:i,generation:o,claim:d}}var W=null,G=null,Ee={refreshGit:!1,refreshBranches:!1,refreshWorktrees:!1,markTreeStale:!1,refreshEditorBuffers:!1},De=250,K=`ui.themeId`,Oe=`ui.theme`;function q(e){return e===`fs_change`}function ke(){let e=localStorage.getItem(K);if(e!==null)try{return JSON.parse(e)}catch{return}let t=localStorage.getItem(Oe);if(t!==null)try{return JSON.parse(t)}catch{return}}function Ae(e){let t=se(Se(e));return document.documentElement.setAttribute(`data-theme`,t.documentThemeAttr),t.id}function je(e,t){console.error(`[RecoveryCoordinator] ${e} failed:`,t)}function Me(e,t){return{refreshGit:e.refreshGit||!!t.refreshGit,refreshBranches:e.refreshBranches||!!t.refreshBranches,refreshWorktrees:e.refreshWorktrees||!!t.refreshWorktrees,markTreeStale:e.markTreeStale||!!t.markTreeStale,refreshEditorBuffers:e.refreshEditorBuffers||!!t.refreshEditorBuffers}}function Ne(e){let n=e.get(R),i=e.get(T),a=Object.values(e.get(C)).map(e=>e.terminalId).filter(e=>!!e);e.set(T,{}),e.set(R,[]),e.set(y,`idle`),e.set(L,null),e.set(C,{}),e.set(be,null),e.set(r,new Map);for(let r of n){let n=i[r];n&&g.disposeWorkspace(n.path),e.set(N(r),null),e.set(w(r),new Set),e.set(_e(r),null),e.set(ae(r),null),e.set(x(r),{current:``,branches:[],loading:!1}),e.set(t(r),{items:[],loading:!1}),e.set(k(r),!1),e.set(ye(r),0)}for(let t of a)e.set(l(t),null)}function Pe(e,t){let n=e.match(/^workspace\.([^.]+)\.(fs\.dirty|git\.state)$/);if(!n)return null;let r=n[1];if(n[2]===`fs.dirty`){let e=t??{};return{workspaceId:r,hint:{refreshGit:!0,refreshBranches:e.reason===`git_metadata`,refreshWorktrees:e.reason===`git_metadata`,markTreeStale:q(e.reason),refreshEditorBuffers:e.reason===`fs_change`||e.reason===`file_content`}}}let i=t??{};return{workspaceId:r,hint:{refreshGit:!0,refreshBranches:!!i.branchChanged,refreshWorktrees:!!i.worktreeChanged,markTreeStale:!!i.treeChanged,refreshEditorBuffers:!!i.treeChanged}}}function J({children:e}){pe();let[,l]=n(me),[f,m]=n(h),g=D(s),v=D(_),y=D(le),S=D(b),w=D(be),E=P(le),O=P(I),_e=P(i),A=P(s),j=P(he),M=P(ie),N=P(c),ve=P(T),L=P(C),R=P(r),Ce=P(a),we=P(d),H=ge(),U=D(u),{claim:Oe}=Te();de();let q=(0,B.useRef)(null),J=(0,B.useRef)(U),Y=(0,B.useRef)(new Map),X=(0,B.useRef)(new Map),Ie=(0,B.useRef)(w),Z=(0,B.useRef)(!1),Q=(0,B.useRef)(null),$=(0,B.useRef)({mode:`inactive`,workspaceId:null}),Le=(0,B.useRef)({theme:0}),Re=(0,B.useRef)(!1);(0,B.useEffect)(()=>{J.current=U},[U]);let ze=()=>{if(!Z.current||y!==`connected`||document.visibilityState!==`visible`||S!==`active`)return;let e=w;e&&(Z.current=!1,J.current(`git.status`,{workspaceId:e}).then(t=>{t.ok&&t.data&&H.set(ae(e),t.data)}),J.current(`git.branches`,{workspaceId:e}).then(t=>{t.ok&&t.data&&H.set(x(e),{current:t.data.current,branches:t.data.branches,loading:!1})}),J.current(`worktree.list`,{workspaceId:e}).then(n=>{n.ok&&n.data&&Array.isArray(n.data.worktrees)&&H.set(t(e),{items:n.data.worktrees,loading:!1,lastLoadedAt:Date.now()})}))};return(0,B.useEffect)(()=>{ze()},[S,w,y]),(0,B.useEffect)(()=>{if(y!==`connected`)return;let e=!1,t=H.get(a),n=!1,r=!1,i=!1,o=H.sub(a,()=>{let e=H.get(a);e.copyOnSelect!==t.copyOnSelect&&(n=!0),e.desktopFontSize!==t.desktopFontSize&&(r=!0),e.mobileFontSize!==t.mobileFontSize&&(i=!0),t=e});return(async()=>{let t=await U(`settings.get`,{});if(e||!t.ok||!t.data)return;let o=H.get(a),s=r?o.desktopFontSize:z(t.data,`desktop`),c=i?o.mobileFontSize:z(t.data,`mobile`),l=te(t.data),u=p(t.data,`desktop`),d=p(t.data,`mobile`);Ce({copyOnSelect:n?o.copyOnSelect:oe(t.data),desktopFontSize:s,mobileFontSize:c,fontSize:u||d||l?z(t.data,`desktop`):o.fontSize})})(),()=>{e=!0,o()}},[y,U,Ce,H]),(0,B.useEffect)(()=>{if(y!==`connected`)return;let e=!1;return(async()=>{let t=await U(`updates.getState`,{});e||!t.ok||!t.data||we(t.data)})(),()=>{e=!0}},[y,U,we]),(0,B.useEffect)(()=>{Ie.current=w},[w]),(0,B.useEffect)(()=>{y===`connected`&&H.get(b)!==`gated`&&Oe()},[Oe,y,H]),(0,B.useEffect)(()=>{Re.current=localStorage.getItem(K)!==null;let e=Ae(ke());m(e),localStorage.setItem(K,JSON.stringify(e))},[m]),(0,B.useEffect)(()=>{let e=se(f);document.documentElement.setAttribute(`data-theme`,e.documentThemeAttr),localStorage.setItem(K,JSON.stringify(e.id))},[f]),(0,B.useEffect)(()=>{if(y!==`connected`)return;let e=!1;return(async()=>{let t={...Le.current},n=await U(`settings.get`,{});if(e||!n.ok||!n.data||Le.current.theme!==t.theme)return;if(Re.current){Re.current=!1;return}let r=n.data;m(Se(r[`appearance.themeId`]??r[`appearance.theme`]??ke()))})(),()=>{e=!0}},[y,U,m]),(0,B.useEffect)(()=>{let e=H.sub(h,()=>{Le.current.theme+=1});return()=>{e()}},[H]),(0,B.useEffect)(()=>{(async()=>{try{let e=await(await fetch(`/auth/status`)).json();A(!!e.authEnabled),H.set(_,!!e.authenticated||e.authEnabled===!1)}catch{H.set(_,!1)}})()},[A,H]),(0,B.useEffect)(()=>{if(g===null)return;if(g===!0&&!v){G&&=(clearTimeout(G),null),W&&=(W.disconnect(`auth_required`),null),F(),q.current=null,l(null),E(`connecting`),O(null),_e(null),j(0),M(null),N(!1);return}let e=e=>{E(e),e===`reconnecting`&&(j(e=>e+1),M(e=>e??Date.now()),H.set(b,e=>e===`gated`?e:`idle`),$.current={mode:`inactive`,workspaceId:null},Z.current=!0),(e===`disconnected`||e===`rejected`)&&(N(!1),H.set(b,e=>e===`gated`?e:`idle`),$.current={mode:`inactive`,workspaceId:null},e===`disconnected`&&(Z.current=!0)),e===`connected`&&(j(0),M(null),a(!0))},n=e=>{J.current(`git.status`,{workspaceId:e}).then(t=>{t.ok&&t.data&&H.set(ae(e),t.data)}).catch(e=>{console.error(`[Git Status] git.status command threw error:`,e)})},r=()=>{if($.current.mode===`inactive`)return;let e=q.current;e&&($.current={mode:`inactive`,workspaceId:null},e.sendCommand(`workspace.deactivate`,{}).catch(()=>{}))},i=e=>{if(H.get(b)!==`active`)return;let t=$.current;if(t.mode===`active`&&t.workspaceId===e)return;let n=q.current;n&&($.current={mode:`active`,workspaceId:e},n.sendCommand(`workspace.activate`,{workspaceId:e}).catch(()=>{}))},a=(e=!1)=>{if(document.visibilityState===`hidden`){r();return}let t=Ie.current;if(!t){r();return}e&&($.current={mode:`inactive`,workspaceId:null}),i(t)},s=()=>{if(H.get(b)===`gated`)return;if(a(),document.visibilityState!==`visible`){Q.current=null;return}let e=Date.now(),t=Q.current;t!==null&&e-t<De||(Q.current=e,o()?.notifyReason(`foreground_resume`).catch(e=>{je(`foreground_resume`,e)}))},c=()=>{if(document.visibilityState===`hidden`){Q.current=null,a();return}s()},u=()=>{s()},d=()=>{s()},f=()=>{H.get(b)!==`gated`&&o()?.notifyReason(`network_online`).catch(e=>{je(`network_online`,e)})},p=e=>{J.current(`git.branches`,{workspaceId:e}).then(t=>{if(t.ok&&t.data){H.set(x(e),{current:t.data.current,branches:t.data.branches,loading:!1});return}H.set(x(e),e=>({...e,loading:!1,error:t.error?.message??e.error}))}).catch(e=>{console.error(`[Git Branches] git.branches command threw error:`,e)})},m=e=>{H.set(t(e),e=>({...e,loading:!0,error:void 0})),J.current(`worktree.list`,{workspaceId:e}).then(n=>{if(n.ok&&n.data&&Array.isArray(n.data.worktrees)){H.set(t(e),{items:n.data.worktrees,loading:!1,lastLoadedAt:Date.now()});return}H.set(t(e),e=>({...e,loading:!1,error:n.error?.message??e.error}))}).catch(n=>{console.error(`[Worktree List] worktree.list command threw error:`,n),H.set(t(e),e=>({...e,loading:!1,error:n instanceof Error?n.message:String(n)}))})},te=(e,t)=>{let r=Me(X.current.get(e)??Ee,t);if(X.current.set(e,r),Y.current.get(e))return;let i=setTimeout(()=>{Y.current.delete(e);let t=X.current.get(e)??Ee;X.current.delete(e),t.markTreeStale&&H.set(k(e),!0),t.refreshEditorBuffers&&H.set(ye(e),e=>e+1),t.refreshGit&&n(e),t.refreshBranches&&p(e),t.refreshWorktrees&&m(e)},60);Y.current.set(e,i)},h=(e,t,n)=>{if(e===`activation.revoked`){let e=t??{};H.set(b,`gated`),H.set(ue,typeof e.reason==`string`&&e.reason.length>0?e.reason:`displaced`),H.set(ee,typeof e.generation==`number`?e.generation:null),Ne(H),$.current={mode:`inactive`,workspaceId:null},Z.current=!1,q.current?.disconnect(`single_active_displaced`);return}let r=Pe(e,t);r&&te(r.workspaceId,r.hint);try{Fe(e,t,H)}catch(t){console.error(`Error handling event for topic ${e}:`,t)}},ie=[`connection.*`,`activation.*`,`update.*`,`workspace.*`];if(G&&=(clearTimeout(G),null),W){q.current=W,l(W);let t=W.getStatus();E(t);let n=W.onStatus(e),r=W.subscribe(ie,h);return o()||ce(fe({wsClient:W,sendCommand:xe((e,t,n)=>W.sendCommand(e,t,n)),applyReplay:async()=>{},applySnapshot:async()=>{}})),(t===`disconnected`||t===`reconnecting`)&&W.recoverConnection(`manual_retry`),a(),document.addEventListener(`visibilitychange`,c),window.addEventListener(`focus`,u),window.addEventListener(`pageshow`,d),window.addEventListener(`online`,f),()=>{document.removeEventListener(`visibilitychange`,c),window.removeEventListener(`focus`,u),window.removeEventListener(`pageshow`,d),window.removeEventListener(`online`,f),n(),r(),Y.current.forEach(e=>clearTimeout(e)),Y.current.clear(),X.current.clear(),q.current=null,W&&(G=setTimeout(()=>{W&&=(W.disconnect(`app_unmount`),null),F(),G=null},50))}}let _=new ne(re());W=_,ce(fe({wsClient:_,sendCommand:xe((e,t,n)=>_.sendCommand(e,t,n)),applyReplay:async()=>{},applySnapshot:async()=>{}})),q.current=_,l(_);let oe=_.onStatus(e),se=_.subscribe(ie,h);return _.connect().catch(e=>{console.error(`Failed to connect WebSocket:`,e),O(e.message||`Connection failed`)}),a(),document.addEventListener(`visibilitychange`,c),window.addEventListener(`focus`,u),window.addEventListener(`pageshow`,d),window.addEventListener(`online`,f),()=>{document.removeEventListener(`visibilitychange`,c),window.removeEventListener(`focus`,u),window.removeEventListener(`pageshow`,d),window.removeEventListener(`online`,f),oe(),se(),Y.current.forEach(e=>clearTimeout(e)),Y.current.clear(),X.current.clear(),q.current=null,G=setTimeout(()=>{W&&=(W.disconnect(`app_unmount`),null),F(),G=null},50)}},[l,E,O,_e,A,j,M,N,ve,L,R,H,g,v]),(0,B.useEffect)(()=>{if(g===null)return;if(g===!0&&!v){$.current={mode:`inactive`,workspaceId:null};return}if(y!==`connected`||S!==`active`)return;if(document.visibilityState===`hidden`){if($.current.mode!==`inactive`){let e=q.current;if(!e)return;$.current={mode:`inactive`,workspaceId:null},e.sendCommand(`workspace.deactivate`,{}).catch(()=>{})}return}if(!w){if($.current.mode!==`inactive`){let e=q.current;if(!e)return;$.current={mode:`inactive`,workspaceId:null},e.sendCommand(`workspace.deactivate`,{}).catch(()=>{})}return}if($.current.mode===`active`&&$.current.workspaceId===w)return;let e=q.current;e&&($.current={mode:`active`,workspaceId:w},e.sendCommand(`workspace.activate`,{workspaceId:w}).catch(()=>{}))},[w,S,g,v,y]),(0,V.jsx)(V.Fragment,{children:e})}function Y(e,t){let n=e;return typeof n.version!=`string`||typeof n.serverInstanceId!=`string`?!1:(t.set(i,{version:n.version,serverInstanceId:n.serverInstanceId,authEnabled:typeof n.authEnabled==`boolean`?n.authEnabled:void 0}),typeof n.isWriter==`boolean`&&t.set(c,n.isWriter),!0)}function Fe(e,t,n){if(e===`connection.ready`){Y(t,n),n.set(I,null);return}if(e===`connection.status`){let e=t;e.status===`connected`&&Y(t,n),e.status===`connected`&&e.authEnabled===!1&&n.set(_,!0),e.status===`error`&&e.message&&n.set(I,e.message);return}if(e===`update.state.changed`){n.set(d,t);return}let i=e.match(/^workspace\.([^.]+)\.(.+)$/);if(i){let e=i[1],a=i[2];if(a===`meta`){let r=t;if(!(n.get(T)[e]||r.path))return;n.set(T,t=>({...t,[e]:{...t[e],...r,id:e}}));let i=r.uiState?.paneLayout;i&&n.set(A(e),X(i)),n.set(R,t=>t.includes(e)?t:[...t,e]),n.set(y,`ready`),n.set(L,null);return}if(a===`fs.dirty`){if(q((t??{}).reason)){let t=k(e);n.set(t,!0)}return}if(a===`git.state`)return;let o=a.match(/^session\.([^.]+)\.(.+)$/);if(o){let e=o[1],i=o[2];if(i===`lifecycle`){if(t.event===`removed`){let t=n.get(C)[e];t?.terminalId&&n.set(l(t.terminalId),null),n.set(C,t=>{if(!(e in t))return t;let n={...t};return delete n[e],n})}return}if(i===`state`){let e=t;n.set(C,t=>({...t,[e.id]:e}));return}if(i===`progress`){console.log(`Session ${e} progress:`,t);return}if(i===`supervisor.state`){let e=t;if(e.event===`deleted`&&e.supervisorId)n.set(r,t=>{let n=new Map(t);for(let[t,r]of n.entries())if(r.id===e.supervisorId){n.delete(t);break}return n});else if(e.supervisor){let t=e.supervisor;n.set(r,e=>{let n=new Map(e);return n.set(t.sessionId,t),n})}return}}let s=a.match(/^terminal\.([^.]+)\.(.+)$/);if(s){let r=s[1],i=s[2];if(i===`created`){let i=t,a=l(r);n.set(a,{id:i.id,workspaceId:e,kind:i.kind,alive:!0,title:i.title});return}if(i===`output`)return;if(i===`exit`){let e=t,i=l(r),a=n.get(i);a&&n.set(i,{...a,exitCode:e.code,alive:!1});return}}}console.log(`Unhandled event topic: ${e}`,t)}function X(e){return{id:e?.id??`root`,type:e?.type??`leaf`,sessionId:e?.sessionId,direction:e?.direction,children:e?.children?.map(e=>X(e))}}Ce.createRoot(document.getElementById(`root`)).render((0,V.jsx)(v,{children:(0,V.jsx)(J,{children:(0,V.jsx)(H,{})})}));
2
- //# sourceMappingURL=main-D3dXqSaA.js.map
1
+ import{r as e}from"./rolldown-runtime-CpWojdLp.js";import{$ as t,$t as n,A as r,At as i,B as a,C as o,Ct as s,Dt as c,E as l,Et as u,F as d,Gt as f,Ht as ee,I as p,Kt as m,L as te,Lt as h,Mt as ne,Nt as re,Ot as ie,P as g,Pt as _,Q as ae,Qt as v,R as oe,Rt as se,St as y,T as ce,Tt as le,Ut as ue,V as de,Wt as b,X as x,Zt as S,_t as C,at as w,b as fe,bt as T,c as E,en as D,gt as O,ht as pe,it as k,jt as me,kt as he,nn as ge,nt as _e,q as A,qt as j,rn as M,rt as N,t as ve,tn as P,tt as ye,vt as be,w as F,wt as I,x as xe,xt as L,yt as R,z,zt as Se}from"./components-BZf_jLGv.js";import"./xterm-BVlcrOZ1.js";var B=e(M(),1),Ce=e(S(),1),V=O();function we(){return m()===`mobile`?(0,V.jsx)(ve,{}):(0,V.jsx)(E,{})}function H(){return(0,V.jsx)(j,{children:(0,V.jsx)(we,{})})}var U=1e3;function Te(){let e=D(me),t=D(le),r=D(f),[i,a]=n(b),[o,s]=n(ee),c=P(ue),l=(0,B.useRef)(null),u=(0,B.useRef)(null),d=(0,B.useCallback)(async()=>{if(!e)return!1;if(t!==`connected`)try{await e.connect()}catch{return c(null),a(e=>e===`gated`?e:`idle`),!1}if(l.current)return l.current;a(`claiming`);let n=e.sendCommand(`activation.claim`,{clientInstanceId:r}).then(e=>(s(e.generation),c(null),a(`active`),!0)).catch(()=>(c(null),a(e=>e===`gated`?e:`idle`),!1)).finally(()=>{l.current=null});return l.current=n,n},[r,t,s,c,a,e]);return(0,B.useEffect)(()=>{if(u.current!==null&&(clearTimeout(u.current),u.current=null),!(!e||t!==`connected`||i!==`idle`))return u.current=setTimeout(()=>{u.current=null,l.current||d()},U),()=>{u.current!==null&&(clearTimeout(u.current),u.current=null)}},[d,t,i,e]),(0,B.useEffect)(()=>()=>{u.current!==null&&(clearTimeout(u.current),u.current=null),!(!e||o===null)&&e.sendCommand(`activation.release`,{clientInstanceId:r,generation:o}).catch(()=>{})},[r,o,e]),{status:i,generation:o,claim:d}}var W=null,G=null,Ee={refreshGit:!1,refreshBranches:!1,refreshWorktrees:!1,markTreeStale:!1,refreshEditorBuffers:!1},De=250,K=`ui.themeId`,Oe=`ui.theme`;function q(e){return e===`fs_change`}function ke(){let e=localStorage.getItem(K);if(e!==null)try{return JSON.parse(e)}catch{return}let t=localStorage.getItem(Oe);if(t!==null)try{return JSON.parse(t)}catch{return}}function Ae(e){let t=se(Se(e));return document.documentElement.setAttribute(`data-theme`,t.documentThemeAttr),t.id}function je(e,t){console.error(`[RecoveryCoordinator] ${e} failed:`,t)}function Me(e,t){return{refreshGit:e.refreshGit||!!t.refreshGit,refreshBranches:e.refreshBranches||!!t.refreshBranches,refreshWorktrees:e.refreshWorktrees||!!t.refreshWorktrees,markTreeStale:e.markTreeStale||!!t.markTreeStale,refreshEditorBuffers:e.refreshEditorBuffers||!!t.refreshEditorBuffers}}function Ne(e){let n=e.get(R),i=e.get(T),a=Object.values(e.get(C)).map(e=>e.terminalId).filter(e=>!!e);e.set(T,{}),e.set(R,[]),e.set(y,`idle`),e.set(L,null),e.set(C,{}),e.set(be,null),e.set(r,new Map);for(let r of n){let n=i[r];n&&g.disposeWorkspace(n.path),e.set(N(r),null),e.set(w(r),new Set),e.set(_e(r),null),e.set(ae(r),null),e.set(x(r),{current:``,branches:[],loading:!1}),e.set(t(r),{items:[],loading:!1}),e.set(k(r),!1),e.set(ye(r),0)}for(let t of a)e.set(l(t),null)}function Pe(e,t){let n=e.match(/^workspace\.([^.]+)\.(fs\.dirty|git\.state)$/);if(!n)return null;let r=n[1];if(n[2]===`fs.dirty`){let e=t??{};return{workspaceId:r,hint:{refreshGit:!0,refreshBranches:e.reason===`git_metadata`,refreshWorktrees:e.reason===`git_metadata`,markTreeStale:q(e.reason),refreshEditorBuffers:e.reason===`fs_change`||e.reason===`file_content`}}}let i=t??{};return{workspaceId:r,hint:{refreshGit:!0,refreshBranches:!!i.branchChanged,refreshWorktrees:!!i.worktreeChanged,markTreeStale:!!i.treeChanged,refreshEditorBuffers:!!i.treeChanged}}}function J({children:e}){pe();let[,l]=n(me),[f,m]=n(h),g=D(s),v=D(_),y=D(le),S=D(b),w=D(be),E=P(le),O=P(I),_e=P(i),A=P(s),j=P(he),M=P(ie),N=P(c),ve=P(T),L=P(C),R=P(r),Ce=P(a),we=P(d),H=ge(),U=D(u),{claim:Oe}=Te();de();let q=(0,B.useRef)(null),J=(0,B.useRef)(U),Y=(0,B.useRef)(new Map),X=(0,B.useRef)(new Map),Ie=(0,B.useRef)(w),Z=(0,B.useRef)(!1),Q=(0,B.useRef)(null),$=(0,B.useRef)({mode:`inactive`,workspaceId:null}),Le=(0,B.useRef)({theme:0}),Re=(0,B.useRef)(!1);(0,B.useEffect)(()=>{J.current=U},[U]);let ze=()=>{if(!Z.current||y!==`connected`||document.visibilityState!==`visible`||S!==`active`)return;let e=w;e&&(Z.current=!1,J.current(`git.status`,{workspaceId:e}).then(t=>{t.ok&&t.data&&H.set(ae(e),t.data)}),J.current(`git.branches`,{workspaceId:e}).then(t=>{t.ok&&t.data&&H.set(x(e),{current:t.data.current,branches:t.data.branches,loading:!1})}),J.current(`worktree.list`,{workspaceId:e}).then(n=>{n.ok&&n.data&&Array.isArray(n.data.worktrees)&&H.set(t(e),{items:n.data.worktrees,loading:!1,lastLoadedAt:Date.now()})}))};return(0,B.useEffect)(()=>{ze()},[S,w,y]),(0,B.useEffect)(()=>{if(y!==`connected`)return;let e=!1,t=H.get(a),n=!1,r=!1,i=!1,o=H.sub(a,()=>{let e=H.get(a);e.copyOnSelect!==t.copyOnSelect&&(n=!0),e.desktopFontSize!==t.desktopFontSize&&(r=!0),e.mobileFontSize!==t.mobileFontSize&&(i=!0),t=e});return(async()=>{let t=await U(`settings.get`,{});if(e||!t.ok||!t.data)return;let o=H.get(a),s=r?o.desktopFontSize:z(t.data,`desktop`),c=i?o.mobileFontSize:z(t.data,`mobile`),l=te(t.data),u=p(t.data,`desktop`),d=p(t.data,`mobile`);Ce({copyOnSelect:n?o.copyOnSelect:oe(t.data),desktopFontSize:s,mobileFontSize:c,fontSize:u||d||l?z(t.data,`desktop`):o.fontSize})})(),()=>{e=!0,o()}},[y,U,Ce,H]),(0,B.useEffect)(()=>{if(y!==`connected`)return;let e=!1;return(async()=>{let t=await U(`updates.getState`,{});e||!t.ok||!t.data||we(t.data)})(),()=>{e=!0}},[y,U,we]),(0,B.useEffect)(()=>{Ie.current=w},[w]),(0,B.useEffect)(()=>{y===`connected`&&H.get(b)!==`gated`&&Oe()},[Oe,y,H]),(0,B.useEffect)(()=>{Re.current=localStorage.getItem(K)!==null;let e=Ae(ke());m(e),localStorage.setItem(K,JSON.stringify(e))},[m]),(0,B.useEffect)(()=>{let e=se(f);document.documentElement.setAttribute(`data-theme`,e.documentThemeAttr),localStorage.setItem(K,JSON.stringify(e.id))},[f]),(0,B.useEffect)(()=>{if(y!==`connected`)return;let e=!1;return(async()=>{let t={...Le.current},n=await U(`settings.get`,{});if(e||!n.ok||!n.data||Le.current.theme!==t.theme)return;if(Re.current){Re.current=!1;return}let r=n.data;m(Se(r[`appearance.themeId`]??r[`appearance.theme`]??ke()))})(),()=>{e=!0}},[y,U,m]),(0,B.useEffect)(()=>{let e=H.sub(h,()=>{Le.current.theme+=1});return()=>{e()}},[H]),(0,B.useEffect)(()=>{(async()=>{try{let e=await(await fetch(`/auth/status`)).json();A(!!e.authEnabled),H.set(_,!!e.authenticated||e.authEnabled===!1)}catch{H.set(_,!1)}})()},[A,H]),(0,B.useEffect)(()=>{if(g===null)return;if(g===!0&&!v){G&&=(clearTimeout(G),null),W&&=(W.disconnect(`auth_required`),null),F(),q.current=null,l(null),E(`connecting`),O(null),_e(null),j(0),M(null),N(!1);return}let e=e=>{E(e),e===`reconnecting`&&(j(e=>e+1),M(e=>e??Date.now()),H.set(b,e=>e===`gated`?e:`idle`),$.current={mode:`inactive`,workspaceId:null},Z.current=!0),(e===`disconnected`||e===`rejected`)&&(N(!1),H.set(b,e=>e===`gated`?e:`idle`),$.current={mode:`inactive`,workspaceId:null},e===`disconnected`&&(Z.current=!0)),e===`connected`&&(j(0),M(null),a(!0))},n=e=>{J.current(`git.status`,{workspaceId:e}).then(t=>{t.ok&&t.data&&H.set(ae(e),t.data)}).catch(e=>{console.error(`[Git Status] git.status command threw error:`,e)})},r=()=>{if($.current.mode===`inactive`)return;let e=q.current;e&&($.current={mode:`inactive`,workspaceId:null},e.sendCommand(`workspace.deactivate`,{}).catch(()=>{}))},i=e=>{if(H.get(b)!==`active`)return;let t=$.current;if(t.mode===`active`&&t.workspaceId===e)return;let n=q.current;n&&($.current={mode:`active`,workspaceId:e},n.sendCommand(`workspace.activate`,{workspaceId:e}).catch(()=>{}))},a=(e=!1)=>{if(document.visibilityState===`hidden`){r();return}let t=Ie.current;if(!t){r();return}e&&($.current={mode:`inactive`,workspaceId:null}),i(t)},s=()=>{if(H.get(b)===`gated`)return;if(a(),document.visibilityState!==`visible`){Q.current=null;return}let e=Date.now(),t=Q.current;t!==null&&e-t<De||(Q.current=e,o()?.notifyReason(`foreground_resume`).catch(e=>{je(`foreground_resume`,e)}))},c=()=>{if(document.visibilityState===`hidden`){Q.current=null,a();return}s()},u=()=>{s()},d=()=>{s()},f=()=>{H.get(b)!==`gated`&&o()?.notifyReason(`network_online`).catch(e=>{je(`network_online`,e)})},p=e=>{J.current(`git.branches`,{workspaceId:e}).then(t=>{if(t.ok&&t.data){H.set(x(e),{current:t.data.current,branches:t.data.branches,loading:!1});return}H.set(x(e),e=>({...e,loading:!1,error:t.error?.message??e.error}))}).catch(e=>{console.error(`[Git Branches] git.branches command threw error:`,e)})},m=e=>{H.set(t(e),e=>({...e,loading:!0,error:void 0})),J.current(`worktree.list`,{workspaceId:e}).then(n=>{if(n.ok&&n.data&&Array.isArray(n.data.worktrees)){H.set(t(e),{items:n.data.worktrees,loading:!1,lastLoadedAt:Date.now()});return}H.set(t(e),e=>({...e,loading:!1,error:n.error?.message??e.error}))}).catch(n=>{console.error(`[Worktree List] worktree.list command threw error:`,n),H.set(t(e),e=>({...e,loading:!1,error:n instanceof Error?n.message:String(n)}))})},te=(e,t)=>{let r=Me(X.current.get(e)??Ee,t);if(X.current.set(e,r),Y.current.get(e))return;let i=setTimeout(()=>{Y.current.delete(e);let t=X.current.get(e)??Ee;X.current.delete(e),t.markTreeStale&&H.set(k(e),!0),t.refreshEditorBuffers&&H.set(ye(e),e=>e+1),t.refreshGit&&n(e),t.refreshBranches&&p(e),t.refreshWorktrees&&m(e)},60);Y.current.set(e,i)},h=(e,t,n)=>{if(e===`activation.revoked`){let e=t??{};H.set(b,`gated`),H.set(ue,typeof e.reason==`string`&&e.reason.length>0?e.reason:`displaced`),H.set(ee,typeof e.generation==`number`?e.generation:null),Ne(H),$.current={mode:`inactive`,workspaceId:null},Z.current=!1,q.current?.disconnect(`single_active_displaced`);return}let r=Pe(e,t);r&&te(r.workspaceId,r.hint);try{Fe(e,t,H)}catch(t){console.error(`Error handling event for topic ${e}:`,t)}},ie=[`connection.*`,`activation.*`,`update.*`,`workspace.*`];if(G&&=(clearTimeout(G),null),W){q.current=W,l(W);let t=W.getStatus();E(t);let n=W.onStatus(e),r=W.subscribe(ie,h);return o()||ce(fe({wsClient:W,sendCommand:xe((e,t,n)=>W.sendCommand(e,t,n)),applyReplay:async()=>{},applySnapshot:async()=>{}})),(t===`disconnected`||t===`reconnecting`)&&W.recoverConnection(`manual_retry`),a(),document.addEventListener(`visibilitychange`,c),window.addEventListener(`focus`,u),window.addEventListener(`pageshow`,d),window.addEventListener(`online`,f),()=>{document.removeEventListener(`visibilitychange`,c),window.removeEventListener(`focus`,u),window.removeEventListener(`pageshow`,d),window.removeEventListener(`online`,f),n(),r(),Y.current.forEach(e=>clearTimeout(e)),Y.current.clear(),X.current.clear(),q.current=null,W&&(G=setTimeout(()=>{W&&=(W.disconnect(`app_unmount`),null),F(),G=null},50))}}let _=new ne(re());W=_,ce(fe({wsClient:_,sendCommand:xe((e,t,n)=>_.sendCommand(e,t,n)),applyReplay:async()=>{},applySnapshot:async()=>{}})),q.current=_,l(_);let oe=_.onStatus(e),se=_.subscribe(ie,h);return _.connect().catch(e=>{console.error(`Failed to connect WebSocket:`,e),O(e.message||`Connection failed`)}),a(),document.addEventListener(`visibilitychange`,c),window.addEventListener(`focus`,u),window.addEventListener(`pageshow`,d),window.addEventListener(`online`,f),()=>{document.removeEventListener(`visibilitychange`,c),window.removeEventListener(`focus`,u),window.removeEventListener(`pageshow`,d),window.removeEventListener(`online`,f),oe(),se(),Y.current.forEach(e=>clearTimeout(e)),Y.current.clear(),X.current.clear(),q.current=null,G=setTimeout(()=>{W&&=(W.disconnect(`app_unmount`),null),F(),G=null},50)}},[l,E,O,_e,A,j,M,N,ve,L,R,H,g,v]),(0,B.useEffect)(()=>{if(g===null)return;if(g===!0&&!v){$.current={mode:`inactive`,workspaceId:null};return}if(y!==`connected`||S!==`active`)return;if(document.visibilityState===`hidden`){if($.current.mode!==`inactive`){let e=q.current;if(!e)return;$.current={mode:`inactive`,workspaceId:null},e.sendCommand(`workspace.deactivate`,{}).catch(()=>{})}return}if(!w){if($.current.mode!==`inactive`){let e=q.current;if(!e)return;$.current={mode:`inactive`,workspaceId:null},e.sendCommand(`workspace.deactivate`,{}).catch(()=>{})}return}if($.current.mode===`active`&&$.current.workspaceId===w)return;let e=q.current;e&&($.current={mode:`active`,workspaceId:w},e.sendCommand(`workspace.activate`,{workspaceId:w}).catch(()=>{}))},[w,S,g,v,y]),(0,V.jsx)(V.Fragment,{children:e})}function Y(e,t){let n=e;return typeof n.version!=`string`||typeof n.serverInstanceId!=`string`?!1:(t.set(i,{version:n.version,serverInstanceId:n.serverInstanceId,authEnabled:typeof n.authEnabled==`boolean`?n.authEnabled:void 0}),typeof n.isWriter==`boolean`&&t.set(c,n.isWriter),!0)}function Fe(e,t,n){if(e===`connection.ready`){Y(t,n),n.set(I,null);return}if(e===`connection.status`){let e=t;e.status===`connected`&&Y(t,n),e.status===`connected`&&e.authEnabled===!1&&n.set(_,!0),e.status===`error`&&e.message&&n.set(I,e.message);return}if(e===`update.state.changed`){n.set(d,t);return}let i=e.match(/^workspace\.([^.]+)\.(.+)$/);if(i){let e=i[1],a=i[2];if(a===`meta`){let r=t;if(!(n.get(T)[e]||r.path))return;n.set(T,t=>({...t,[e]:{...t[e],...r,id:e}}));let i=r.uiState?.paneLayout;i&&n.set(A(e),X(i)),n.set(R,t=>t.includes(e)?t:[...t,e]),n.set(y,`ready`),n.set(L,null);return}if(a===`fs.dirty`){if(q((t??{}).reason)){let t=k(e);n.set(t,!0)}return}if(a===`git.state`)return;let o=a.match(/^session\.([^.]+)\.(.+)$/);if(o){let e=o[1],i=o[2];if(i===`lifecycle`){if(t.event===`removed`){let t=n.get(C)[e];t?.terminalId&&n.set(l(t.terminalId),null),n.set(C,t=>{if(!(e in t))return t;let n={...t};return delete n[e],n})}return}if(i===`state`){let e=t;n.set(C,t=>({...t,[e.id]:e}));return}if(i===`progress`){console.log(`Session ${e} progress:`,t);return}if(i===`supervisor.state`){let e=t;if(e.event===`deleted`&&e.supervisorId)n.set(r,t=>{let n=new Map(t);for(let[t,r]of n.entries())if(r.id===e.supervisorId){n.delete(t);break}return n});else if(e.supervisor){let t=e.supervisor;n.set(r,e=>{let n=new Map(e);return n.set(t.sessionId,t),n})}return}}let s=a.match(/^terminal\.([^.]+)\.(.+)$/);if(s){let r=s[1],i=s[2];if(i===`created`){let i=t,a=l(r);n.set(a,{id:i.id,workspaceId:e,kind:i.kind,alive:!0,title:i.title});return}if(i===`output`)return;if(i===`exit`){let e=t,i=l(r),a=n.get(i);a&&n.set(i,{...a,exitCode:e.code,alive:!1});return}}}console.log(`Unhandled event topic: ${e}`,t)}function X(e){return{id:e?.id??`root`,type:e?.type??`leaf`,sessionId:e?.sessionId,direction:e?.direction,children:e?.children?.map(e=>X(e))}}Ce.createRoot(document.getElementById(`root`)).render((0,V.jsx)(v,{children:(0,V.jsx)(J,{children:(0,V.jsx)(H,{})})}));
2
+ //# sourceMappingURL=main-CEv6hML1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"main-D3dXqSaA.js","names":[],"sources":["../../src/app.tsx","../../src/hooks/use-activation.ts","../../src/ws/reconnect.ts","../../src/app/providers.tsx","../../src/main.tsx"],"sourcesContent":["/**\n * Application root.\n *\n * Provides BrowserRouter and picks a shell based on viewport:\n * - mobile (< 900px) -> MobileShell\n * - desktop -> DesktopShell\n */\n\nimport { BrowserRouter } from \"react-router-dom\";\nimport { useViewport } from \"./hooks/use-viewport\";\nimport { DesktopShell } from \"./shells/desktop-shell\";\nimport { MobileShell } from \"./shells/mobile-shell\";\n\nfunction ShellSwitch() {\n const viewport = useViewport();\n\n return viewport === \"mobile\" ? <MobileShell /> : <DesktopShell />;\n}\n\nfunction App() {\n return (\n <BrowserRouter>\n <ShellSwitch />\n </BrowserRouter>\n );\n}\n\nexport default App;\n","import { useAtom, useAtomValue, useSetAtom } from \"jotai\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport {\n activationGenerationAtom,\n activationReasonAtom,\n activationStatusAtom,\n clientInstanceIdAtom,\n} from \"../atoms/activation\";\nimport { connectionStatusAtom, wsClientAtom } from \"../atoms/connection\";\n\ninterface ActivationClaimPayload {\n active: true;\n generation: number;\n recoveryMode: \"fresh\" | \"grace_recover\" | \"takeover\";\n}\n\nconst CLAIM_RETRY_DELAY_MS = 1_000;\n\nexport function useActivation() {\n const wsClient = useAtomValue(wsClientAtom);\n const connectionStatus = useAtomValue(connectionStatusAtom);\n const clientInstanceId = useAtomValue(clientInstanceIdAtom);\n const [status, setStatus] = useAtom(activationStatusAtom);\n const [generation, setGeneration] = useAtom(activationGenerationAtom);\n const setReason = useSetAtom(activationReasonAtom);\n const claimInFlightRef = useRef<Promise<boolean> | null>(null);\n const claimRetryTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const claim = useCallback(async (): Promise<boolean> => {\n if (!wsClient) {\n return false;\n }\n\n if (connectionStatus !== \"connected\") {\n try {\n await wsClient.connect();\n } catch {\n setReason(null);\n setStatus((current) => (current === \"gated\" ? current : \"idle\"));\n return false;\n }\n }\n\n if (claimInFlightRef.current) {\n return claimInFlightRef.current;\n }\n\n setStatus(\"claiming\");\n\n const pending = wsClient\n .sendCommand<ActivationClaimPayload>(\"activation.claim\", {\n clientInstanceId,\n })\n .then((result) => {\n setGeneration(result.generation);\n setReason(null);\n setStatus(\"active\");\n return true;\n })\n .catch(() => {\n setReason(null);\n setStatus((current) => (current === \"gated\" ? current : \"idle\"));\n return false;\n })\n .finally(() => {\n claimInFlightRef.current = null;\n });\n\n claimInFlightRef.current = pending;\n return pending;\n }, [clientInstanceId, connectionStatus, setGeneration, setReason, setStatus, wsClient]);\n\n useEffect(() => {\n if (claimRetryTimerRef.current !== null) {\n clearTimeout(claimRetryTimerRef.current);\n claimRetryTimerRef.current = null;\n }\n\n if (!wsClient || connectionStatus !== \"connected\" || status !== \"idle\") {\n return;\n }\n\n claimRetryTimerRef.current = setTimeout(() => {\n claimRetryTimerRef.current = null;\n if (!claimInFlightRef.current) {\n void claim();\n }\n }, CLAIM_RETRY_DELAY_MS);\n\n return () => {\n if (claimRetryTimerRef.current !== null) {\n clearTimeout(claimRetryTimerRef.current);\n claimRetryTimerRef.current = null;\n }\n };\n }, [claim, connectionStatus, status, wsClient]);\n\n useEffect(() => {\n return () => {\n if (claimRetryTimerRef.current !== null) {\n clearTimeout(claimRetryTimerRef.current);\n claimRetryTimerRef.current = null;\n }\n\n if (!wsClient || generation === null) {\n return;\n }\n\n void wsClient\n .sendCommand(\"activation.release\", {\n clientInstanceId,\n generation,\n })\n .catch(() => {});\n };\n }, [clientInstanceId, generation, wsClient]);\n\n return {\n status,\n generation,\n claim,\n };\n}\n","/**\n * Reconnection Utilities\n *\n * Exponential backoff and reconnect state management.\n */\n\nexport interface ReconnectState {\n attempts: number;\n lastAttemptAt: number | null;\n nextDelayMs: number;\n maxAttemptsReached: boolean;\n}\n\nexport interface ReconnectConfig {\n maxAttempts: number;\n baseDelayMs: number;\n maxDelayMs: number;\n jitterMs: number;\n}\n\nconst DEFAULT_CONFIG: ReconnectConfig = {\n maxAttempts: Number.POSITIVE_INFINITY,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n jitterMs: 100,\n};\n\n/**\n * Calculate next reconnect delay using exponential backoff with jitter\n */\nexport function calculateReconnectDelay(\n attempts: number,\n config: Partial<ReconnectConfig> = {}\n): number {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n\n // Exponential backoff: base * 2^attempts\n const exponentialDelay = cfg.baseDelayMs * Math.pow(2, attempts);\n\n // Cap at max delay\n const cappedDelay = Math.min(exponentialDelay, cfg.maxDelayMs);\n\n // Add jitter to prevent thundering herd\n const jitter = Math.random() * cfg.jitterMs;\n\n return cappedDelay + jitter;\n}\n\n/**\n * Create reconnect state tracker\n */\nexport function createReconnectTracker(config: Partial<ReconnectConfig> = {}) {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n let attempts = 0;\n let lastAttemptAt: number | null = null;\n\n return {\n recordAttempt(): ReconnectState {\n attempts++;\n lastAttemptAt = Date.now();\n\n return {\n attempts,\n lastAttemptAt,\n nextDelayMs: calculateReconnectDelay(attempts, cfg),\n maxAttemptsReached: attempts >= cfg.maxAttempts,\n };\n },\n\n reset(): void {\n attempts = 0;\n lastAttemptAt = null;\n },\n\n getState(): ReconnectState {\n return {\n attempts,\n lastAttemptAt,\n nextDelayMs: calculateReconnectDelay(attempts, cfg),\n maxAttemptsReached: attempts >= cfg.maxAttempts,\n };\n },\n };\n}\n","/**\n * Application Providers\n *\n * Initializes WebSocket connection and sets up event routing.\n * Manages connection lifecycle and maps WS events to Jotai atoms.\n */\n\nimport type {\n GitBranch,\n GitStatus,\n Session,\n Supervisor,\n UpdateStateView,\n Workspace,\n WorktreeInfo,\n} from \"@coder-studio/core\";\nimport { useAtom, useAtomValue, useSetAtom, useStore } from \"jotai\";\nimport type { Store } from \"jotai/vanilla/store\";\nimport { useEffect, useRef } from \"react\";\nimport {\n authEnabledAtom,\n connectionErrorAtom,\n connectionStatusAtom,\n dispatchCommandAtom,\n isWriterAtom,\n lastReconnectAttemptAtom,\n reconnectAttemptCountAtom,\n serverInfoAtom,\n sessionsAtom,\n workspaceOrderAtom,\n workspacesAtom,\n workspacesLoadErrorAtom,\n workspacesLoadStateAtom,\n wsClientAtom,\n} from \"../atoms\";\nimport {\n activationGenerationAtom,\n activationReasonAtom,\n activationStatusAtom,\n} from \"../atoms/activation\";\nimport { authenticatedAtom, themeAtom } from \"../atoms/app-ui\";\nimport type { DispatchCommand } from \"../atoms/connection\";\nimport { activeWorkspaceIdAtom } from \"../atoms/workspaces\";\nimport { type PaneNode, paneLayoutAtomFamily } from \"../features/agent-panes/atoms/pane-layout\";\nimport { monacoModelRegistry } from \"../features/code-editor/monaco/model-registry\";\nimport { useSessionNotifications } from \"../features/notifications\";\nimport { supervisorsAtom } from \"../features/supervisor/atoms\";\nimport { terminalMetaAtomFamily } from \"../features/terminal-panel/atoms\";\nimport {\n hasExplicitTerminalFontSizeSetting,\n hasLegacyTerminalFontSizeSetting,\n resolveTerminalCopyOnSelectSetting,\n resolveTerminalFontSizeSetting,\n terminalPreferencesAtom,\n} from \"../features/terminal-panel/preferences\";\nimport {\n createRecoveryCoordinator,\n createRecoveryDispatchCommand,\n} from \"../features/terminal-panel/recovery-coordinator\";\nimport {\n getGlobalRecoveryCoordinator,\n resetGlobalRecoveryCoordinator,\n setGlobalRecoveryCoordinator,\n} from \"../features/terminal-panel/recovery-singleton\";\nimport { updateStateAtom } from \"../features/updates/atoms\";\nimport {\n editorRefreshTokenAtomFamily,\n expandedDirsAtomFamily,\n fileTreeAtomFamily,\n fileTreeStaleAtomFamily,\n gitBranchListAtomFamily,\n gitStateAtomFamily,\n loadedDirsAtomFamily,\n worktreeListAtomFamily,\n} from \"../features/workspace/atoms\";\nimport { useActivation } from \"../hooks/use-activation\";\nimport { useTranslation } from \"../lib/i18n\";\nimport { getThemeById, resolveStoredThemeId } from \"../theme\";\nimport type { ConnectionStatus, EventListener } from \"../ws\";\nimport { resolveWsUrl, WsClient } from \"../ws\";\n\n/**\n * Module-level WebSocket client singleton.\n * Prevents duplicate connections in React StrictMode.\n */\nlet globalWsClient: WsClient | null = null;\nlet pendingDisconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\ninterface WorkspaceRefreshHint {\n refreshGit: boolean;\n refreshBranches: boolean;\n refreshWorktrees: boolean;\n markTreeStale: boolean;\n refreshEditorBuffers: boolean;\n}\n\ninterface WorkspaceActivityState {\n mode: \"active\" | \"inactive\";\n workspaceId: string | null;\n}\n\ninterface AppearanceSelectionVersion {\n theme: number;\n}\n\nconst DEFAULT_REFRESH_HINT: WorkspaceRefreshHint = {\n refreshGit: false,\n refreshBranches: false,\n refreshWorktrees: false,\n markTreeStale: false,\n refreshEditorBuffers: false,\n};\nconst FOREGROUND_RECOVERY_COOLDOWN_MS = 250;\nconst THEME_ID_STORAGE_KEY = \"ui.themeId\";\nconst LEGACY_THEME_STORAGE_KEY = \"ui.theme\";\n\nfunction shouldMarkTreeStaleForFsReason(reason?: string): boolean {\n return reason === \"fs_change\";\n}\n\nfunction readStoredThemePreference(): unknown {\n const storedThemeId = localStorage.getItem(THEME_ID_STORAGE_KEY);\n if (storedThemeId !== null) {\n try {\n return JSON.parse(storedThemeId);\n } catch {\n return undefined;\n }\n }\n\n const legacyTheme = localStorage.getItem(LEGACY_THEME_STORAGE_KEY);\n if (legacyTheme !== null) {\n try {\n return JSON.parse(legacyTheme);\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n}\n\nfunction applyResolvedTheme(themeId: unknown): string {\n const resolvedTheme = getThemeById(resolveStoredThemeId(themeId));\n document.documentElement.setAttribute(\"data-theme\", resolvedTheme.documentThemeAttr);\n return resolvedTheme.id;\n}\n\nexport function resetAppProvidersSingletonsForTests() {\n if (pendingDisconnectTimer) {\n clearTimeout(pendingDisconnectTimer);\n pendingDisconnectTimer = null;\n }\n globalWsClient = null;\n resetGlobalRecoveryCoordinator();\n}\n\nfunction reportRecoveryCoordinatorError(context: string, error: unknown) {\n console.error(`[RecoveryCoordinator] ${context} failed:`, error);\n}\n\nfunction mergeRefreshHints(\n current: WorkspaceRefreshHint,\n next: Partial<WorkspaceRefreshHint>\n): WorkspaceRefreshHint {\n return {\n refreshGit: current.refreshGit || Boolean(next.refreshGit),\n refreshBranches: current.refreshBranches || Boolean(next.refreshBranches),\n refreshWorktrees: current.refreshWorktrees || Boolean(next.refreshWorktrees),\n markTreeStale: current.markTreeStale || Boolean(next.markTreeStale),\n refreshEditorBuffers: current.refreshEditorBuffers || Boolean(next.refreshEditorBuffers),\n };\n}\n\nfunction resetServerProjectedState(store: Store): void {\n const workspaceIds = store.get(workspaceOrderAtom);\n const workspaces = store.get(workspacesAtom);\n const terminalIds = Object.values(store.get(sessionsAtom))\n .map((session) => session.terminalId)\n .filter((terminalId): terminalId is string => Boolean(terminalId));\n\n store.set(workspacesAtom, {});\n store.set(workspaceOrderAtom, []);\n store.set(workspacesLoadStateAtom, \"idle\");\n store.set(workspacesLoadErrorAtom, null);\n store.set(sessionsAtom, {});\n store.set(activeWorkspaceIdAtom, null);\n store.set(supervisorsAtom, new Map());\n\n for (const workspaceId of workspaceIds) {\n const workspace = workspaces[workspaceId];\n if (workspace) {\n monacoModelRegistry.disposeWorkspace(workspace.path);\n }\n store.set(fileTreeAtomFamily(workspaceId), null);\n store.set(loadedDirsAtomFamily(workspaceId), new Set());\n store.set(expandedDirsAtomFamily(workspaceId), null);\n store.set(gitStateAtomFamily(workspaceId), null);\n store.set(gitBranchListAtomFamily(workspaceId), {\n current: \"\",\n branches: [],\n loading: false,\n });\n store.set(worktreeListAtomFamily(workspaceId), {\n items: [],\n loading: false,\n });\n store.set(fileTreeStaleAtomFamily(workspaceId), false);\n store.set(editorRefreshTokenAtomFamily(workspaceId), 0);\n }\n\n for (const terminalId of terminalIds) {\n store.set(terminalMetaAtomFamily(terminalId), null);\n }\n}\n\nfunction parseWorkspaceRefreshHint(\n topic: string,\n payload: unknown\n): {\n workspaceId: string;\n hint: WorkspaceRefreshHint;\n} | null {\n const match = topic.match(/^workspace\\.([^.]+)\\.(fs\\.dirty|git\\.state)$/);\n if (!match) {\n return null;\n }\n\n const workspaceId = match[1]!;\n const subtopic = match[2]!;\n\n if (subtopic === \"fs.dirty\") {\n const data = (payload ?? {}) as { reason?: string };\n return {\n workspaceId,\n hint: {\n refreshGit: true,\n refreshBranches: data.reason === \"git_metadata\",\n refreshWorktrees: data.reason === \"git_metadata\",\n markTreeStale: shouldMarkTreeStaleForFsReason(data.reason),\n refreshEditorBuffers: data.reason === \"fs_change\" || data.reason === \"file_content\",\n },\n };\n }\n\n const data = (payload ?? {}) as {\n treeChanged?: boolean;\n branchChanged?: boolean;\n worktreeChanged?: boolean;\n };\n\n return {\n workspaceId,\n hint: {\n refreshGit: true,\n refreshBranches: Boolean(data.branchChanged),\n refreshWorktrees: Boolean(data.worktreeChanged),\n markTreeStale: Boolean(data.treeChanged),\n refreshEditorBuffers: Boolean(data.treeChanged),\n },\n };\n}\n\ninterface AppProvidersProps {\n children: React.ReactNode;\n}\n\nexport function AppProviders({ children }: AppProvidersProps) {\n const t = useTranslation();\n const [, setWsClient] = useAtom(wsClientAtom);\n const [theme, setTheme] = useAtom(themeAtom);\n const authEnabled = useAtomValue(authEnabledAtom);\n const authenticated = useAtomValue(authenticatedAtom);\n const connectionStatus = useAtomValue(connectionStatusAtom);\n const activationStatus = useAtomValue(activationStatusAtom);\n const activeWorkspaceId = useAtomValue(activeWorkspaceIdAtom);\n const setConnectionStatus = useSetAtom(connectionStatusAtom);\n const setConnectionError = useSetAtom(connectionErrorAtom);\n const setServerInfo = useSetAtom(serverInfoAtom);\n const setAuthEnabled = useSetAtom(authEnabledAtom);\n const setReconnectCount = useSetAtom(reconnectAttemptCountAtom);\n const setLastReconnect = useSetAtom(lastReconnectAttemptAtom);\n const setIsWriter = useSetAtom(isWriterAtom);\n\n // Server state atoms\n const setWorkspaces = useSetAtom(workspacesAtom);\n const setSessions = useSetAtom(sessionsAtom);\n // Supervisor state atoms\n const setSupervisors = useSetAtom(supervisorsAtom);\n const setTerminalPreferences = useSetAtom(terminalPreferencesAtom);\n const setUpdateState = useSetAtom(updateStateAtom);\n\n // Get Jotai store for writing to atomFamily atoms\n const store = useStore();\n const dispatch = useAtomValue(dispatchCommandAtom);\n const { claim } = useActivation();\n\n useSessionNotifications();\n\n // Use refs to avoid stale closures in event handlers\n const wsClientRef = useRef<WsClient | null>(null);\n const dispatchRef = useRef<DispatchCommand>(dispatch);\n const refreshTimersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n const refreshHintsRef = useRef<Map<string, WorkspaceRefreshHint>>(new Map());\n const activeWorkspaceIdRef = useRef<string | null>(activeWorkspaceId);\n const pendingReconnectRefreshRef = useRef(false);\n const lastForegroundRecoveryAtRef = useRef<number | null>(null);\n const workspaceActivityRef = useRef<WorkspaceActivityState>({\n mode: \"inactive\",\n workspaceId: null,\n });\n const appearanceSelectionVersionRef = useRef<AppearanceSelectionVersion>({\n theme: 0,\n });\n const preferPersistedThemeOnFirstHydrationRef = useRef(false);\n\n // Keep dispatchRef in sync\n useEffect(() => {\n dispatchRef.current = dispatch;\n }, [dispatch]);\n\n const refreshPendingReconnectState = () => {\n if (!pendingReconnectRefreshRef.current) {\n return;\n }\n\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n if (document.visibilityState !== \"visible\") {\n return;\n }\n\n if (activationStatus !== \"active\") {\n return;\n }\n\n const workspaceId = activeWorkspaceId;\n if (!workspaceId) {\n return;\n }\n\n pendingReconnectRefreshRef.current = false;\n dispatchRef.current<GitStatus>(\"git.status\", { workspaceId }).then((result) => {\n if (result.ok && result.data) {\n store.set(gitStateAtomFamily(workspaceId), result.data);\n }\n });\n dispatchRef\n .current<{ current: string; branches: GitBranch[] }>(\"git.branches\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data) {\n store.set(gitBranchListAtomFamily(workspaceId), {\n current: result.data.current,\n branches: result.data.branches,\n loading: false,\n });\n }\n });\n dispatchRef\n .current<{ worktrees: WorktreeInfo[] }>(\"worktree.list\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data && Array.isArray(result.data.worktrees)) {\n store.set(worktreeListAtomFamily(workspaceId), {\n items: result.data.worktrees,\n loading: false,\n lastLoadedAt: Date.now(),\n });\n }\n });\n };\n\n useEffect(() => {\n refreshPendingReconnectState();\n }, [activationStatus, activeWorkspaceId, connectionStatus]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n let cancelled = false;\n let terminalPreferencesAtSubscriptionStart = store.get(terminalPreferencesAtom);\n let localTerminalCopyOnSelectUpdated = false;\n let localDesktopTerminalFontSizeUpdated = false;\n let localMobileTerminalFontSizeUpdated = false;\n const unsubscribeTerminalPreferences = store.sub(terminalPreferencesAtom, () => {\n const nextTerminalPreferences = store.get(terminalPreferencesAtom);\n if (\n nextTerminalPreferences.copyOnSelect !== terminalPreferencesAtSubscriptionStart.copyOnSelect\n ) {\n localTerminalCopyOnSelectUpdated = true;\n }\n if (\n nextTerminalPreferences.desktopFontSize !==\n terminalPreferencesAtSubscriptionStart.desktopFontSize\n ) {\n localDesktopTerminalFontSizeUpdated = true;\n }\n if (\n nextTerminalPreferences.mobileFontSize !==\n terminalPreferencesAtSubscriptionStart.mobileFontSize\n ) {\n localMobileTerminalFontSizeUpdated = true;\n }\n terminalPreferencesAtSubscriptionStart = nextTerminalPreferences;\n });\n\n const hydrateTerminalPreferences = async () => {\n const result = await dispatch<Record<string, unknown>>(\"settings.get\", {});\n if (cancelled || !result.ok || !result.data) {\n return;\n }\n\n const currentTerminalPreferences = store.get(terminalPreferencesAtom);\n const shouldHydrateDesktopTerminalFontSize = localDesktopTerminalFontSizeUpdated\n ? currentTerminalPreferences.desktopFontSize\n : resolveTerminalFontSizeSetting(result.data, \"desktop\");\n const shouldHydrateMobileTerminalFontSize = localMobileTerminalFontSizeUpdated\n ? currentTerminalPreferences.mobileFontSize\n : resolveTerminalFontSizeSetting(result.data, \"mobile\");\n const hasLegacyFontSize = hasLegacyTerminalFontSizeSetting(result.data);\n const hasExplicitDesktopFontSize = hasExplicitTerminalFontSizeSetting(result.data, \"desktop\");\n const hasExplicitMobileFontSize = hasExplicitTerminalFontSizeSetting(result.data, \"mobile\");\n const nextTerminalPreferences = {\n copyOnSelect: localTerminalCopyOnSelectUpdated\n ? currentTerminalPreferences.copyOnSelect\n : resolveTerminalCopyOnSelectSetting(result.data),\n desktopFontSize: shouldHydrateDesktopTerminalFontSize,\n mobileFontSize: shouldHydrateMobileTerminalFontSize,\n fontSize:\n hasExplicitDesktopFontSize || hasExplicitMobileFontSize || hasLegacyFontSize\n ? resolveTerminalFontSizeSetting(result.data, \"desktop\")\n : currentTerminalPreferences.fontSize,\n };\n setTerminalPreferences(nextTerminalPreferences);\n };\n\n void hydrateTerminalPreferences();\n\n return () => {\n cancelled = true;\n unsubscribeTerminalPreferences();\n };\n }, [connectionStatus, dispatch, setTerminalPreferences, store]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n let cancelled = false;\n\n const hydrateUpdateState = async () => {\n const result = await dispatch<UpdateStateView>(\"updates.getState\", {});\n if (cancelled || !result.ok || !result.data) {\n return;\n }\n setUpdateState(result.data);\n };\n\n void hydrateUpdateState();\n\n return () => {\n cancelled = true;\n };\n }, [connectionStatus, dispatch, setUpdateState]);\n\n useEffect(() => {\n activeWorkspaceIdRef.current = activeWorkspaceId;\n }, [activeWorkspaceId]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n if (store.get(activationStatusAtom) === \"gated\") {\n return;\n }\n\n void claim();\n }, [claim, connectionStatus, store]);\n\n // Initialize theme from localStorage\n useEffect(() => {\n preferPersistedThemeOnFirstHydrationRef.current =\n localStorage.getItem(THEME_ID_STORAGE_KEY) !== null;\n const resolvedThemeId = applyResolvedTheme(readStoredThemePreference());\n setTheme(resolvedThemeId);\n localStorage.setItem(THEME_ID_STORAGE_KEY, JSON.stringify(resolvedThemeId));\n }, [setTheme]);\n\n useEffect(() => {\n const resolvedTheme = getThemeById(theme);\n document.documentElement.setAttribute(\"data-theme\", resolvedTheme.documentThemeAttr);\n localStorage.setItem(THEME_ID_STORAGE_KEY, JSON.stringify(resolvedTheme.id));\n }, [theme]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n let cancelled = false;\n\n const hydrateTheme = async () => {\n const appearanceSelectionVersionAtRequestStart = {\n ...appearanceSelectionVersionRef.current,\n };\n const result = await dispatch<Record<string, unknown>>(\"settings.get\", {});\n if (cancelled || !result.ok || !result.data) {\n return;\n }\n\n if (\n appearanceSelectionVersionRef.current.theme !==\n appearanceSelectionVersionAtRequestStart.theme\n ) {\n return;\n }\n\n if (preferPersistedThemeOnFirstHydrationRef.current) {\n preferPersistedThemeOnFirstHydrationRef.current = false;\n return;\n }\n\n const settings = result.data;\n const resolvedThemeId = resolveStoredThemeId(\n settings[\"appearance.themeId\"] ??\n settings[\"appearance.theme\"] ??\n readStoredThemePreference()\n );\n\n setTheme(resolvedThemeId);\n };\n\n void hydrateTheme();\n\n return () => {\n cancelled = true;\n };\n }, [connectionStatus, dispatch, setTheme]);\n\n useEffect(() => {\n const unsubscribeTheme = store.sub(themeAtom, () => {\n appearanceSelectionVersionRef.current.theme += 1;\n });\n\n return () => {\n unsubscribeTheme();\n };\n }, [store]);\n\n useEffect(() => {\n const loadAuthStatus = async () => {\n try {\n const response = await fetch(\"/auth/status\");\n const data = await response.json();\n setAuthEnabled(Boolean(data.authEnabled));\n store.set(authenticatedAtom, Boolean(data.authenticated) || data.authEnabled === false);\n } catch {\n store.set(authenticatedAtom, false);\n }\n };\n\n void loadAuthStatus();\n }, [setAuthEnabled, store]);\n\n useEffect(() => {\n if (authEnabled === null) {\n return;\n }\n\n if (authEnabled === true && !authenticated) {\n if (pendingDisconnectTimer) {\n clearTimeout(pendingDisconnectTimer);\n pendingDisconnectTimer = null;\n }\n\n if (globalWsClient) {\n globalWsClient.disconnect(\"auth_required\");\n globalWsClient = null;\n }\n resetGlobalRecoveryCoordinator();\n\n wsClientRef.current = null;\n setWsClient(null);\n setConnectionStatus(\"connecting\");\n setConnectionError(null);\n setServerInfo(null);\n setReconnectCount(0);\n setLastReconnect(null);\n setIsWriter(false);\n return;\n }\n\n // Subscribe to connection status changes\n const handleStatusChange = (status: ConnectionStatus) => {\n setConnectionStatus(status);\n\n // Track reconnect attempts\n if (status === \"reconnecting\") {\n setReconnectCount((count) => count + 1);\n setLastReconnect((previous) => previous ?? Date.now());\n store.set(activationStatusAtom, (current) => (current === \"gated\" ? current : \"idle\"));\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n pendingReconnectRefreshRef.current = true;\n }\n\n // Reset writer status on disconnect\n if (status === \"disconnected\" || status === \"rejected\") {\n setIsWriter(false);\n store.set(activationStatusAtom, (current) => (current === \"gated\" ? current : \"idle\"));\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n if (status === \"disconnected\") {\n pendingReconnectRefreshRef.current = true;\n }\n }\n\n if (status === \"connected\") {\n setReconnectCount(0);\n setLastReconnect(null);\n syncWorkspaceActivity(true);\n }\n };\n\n const refreshGitState = (workspaceId: string) => {\n dispatchRef\n .current<GitStatus>(\"git.status\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data) {\n store.set(gitStateAtomFamily(workspaceId), result.data);\n }\n })\n .catch((error) => {\n console.error(\"[Git Status] git.status command threw error:\", error);\n });\n };\n\n const sendWorkspaceDeactivate = () => {\n const currentState = workspaceActivityRef.current;\n if (currentState.mode === \"inactive\") {\n return;\n }\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n void client.sendCommand(\"workspace.deactivate\", {}).catch(() => {});\n };\n\n const sendWorkspaceActivate = (workspaceId: string) => {\n if (store.get(activationStatusAtom) !== \"active\") {\n return;\n }\n\n const currentState = workspaceActivityRef.current;\n if (currentState.mode === \"active\" && currentState.workspaceId === workspaceId) {\n return;\n }\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"active\",\n workspaceId,\n };\n void client.sendCommand(\"workspace.activate\", { workspaceId }).catch(() => {});\n };\n\n const syncWorkspaceActivity = (force = false) => {\n if (document.visibilityState === \"hidden\") {\n sendWorkspaceDeactivate();\n return;\n }\n\n const workspaceId = activeWorkspaceIdRef.current;\n if (!workspaceId) {\n sendWorkspaceDeactivate();\n return;\n }\n\n if (force) {\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n }\n\n sendWorkspaceActivate(workspaceId);\n };\n\n const triggerForegroundRecovery = () => {\n if (store.get(activationStatusAtom) === \"gated\") {\n return;\n }\n\n syncWorkspaceActivity();\n if (document.visibilityState !== \"visible\") {\n lastForegroundRecoveryAtRef.current = null;\n return;\n }\n\n const now = Date.now();\n const lastForegroundRecoveryAt = lastForegroundRecoveryAtRef.current;\n if (\n lastForegroundRecoveryAt !== null &&\n now - lastForegroundRecoveryAt < FOREGROUND_RECOVERY_COOLDOWN_MS\n ) {\n return;\n }\n\n lastForegroundRecoveryAtRef.current = now;\n void getGlobalRecoveryCoordinator()\n ?.notifyReason(\"foreground_resume\")\n .catch((error) => {\n reportRecoveryCoordinatorError(\"foreground_resume\", error);\n });\n };\n\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n lastForegroundRecoveryAtRef.current = null;\n syncWorkspaceActivity();\n return;\n }\n\n triggerForegroundRecovery();\n };\n\n const handleWindowFocus = () => {\n triggerForegroundRecovery();\n };\n\n const handlePageShow = () => {\n triggerForegroundRecovery();\n };\n\n const handleOnline = () => {\n if (store.get(activationStatusAtom) === \"gated\") {\n return;\n }\n\n void getGlobalRecoveryCoordinator()\n ?.notifyReason(\"network_online\")\n .catch((error) => {\n reportRecoveryCoordinatorError(\"network_online\", error);\n });\n };\n\n const refreshBranchState = (workspaceId: string) => {\n dispatchRef\n .current<{ current: string; branches: GitBranch[] }>(\"git.branches\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data) {\n store.set(gitBranchListAtomFamily(workspaceId), {\n current: result.data.current,\n branches: result.data.branches,\n loading: false,\n });\n return;\n }\n\n store.set(gitBranchListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: false,\n error: result.error?.message ?? prev.error,\n }));\n })\n .catch((error) => {\n console.error(\"[Git Branches] git.branches command threw error:\", error);\n });\n };\n\n const refreshWorktreeList = (workspaceId: string) => {\n store.set(worktreeListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: true,\n error: undefined,\n }));\n dispatchRef\n .current<{ worktrees: WorktreeInfo[] }>(\"worktree.list\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data && Array.isArray(result.data.worktrees)) {\n store.set(worktreeListAtomFamily(workspaceId), {\n items: result.data.worktrees,\n loading: false,\n lastLoadedAt: Date.now(),\n });\n return;\n }\n\n store.set(worktreeListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: false,\n error: result.error?.message ?? prev.error,\n }));\n })\n .catch((error) => {\n console.error(\"[Worktree List] worktree.list command threw error:\", error);\n store.set(worktreeListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: false,\n error: error instanceof Error ? error.message : String(error),\n }));\n });\n };\n\n const queueWorkspaceRefresh = (workspaceId: string, hint: Partial<WorkspaceRefreshHint>) => {\n const nextHint = mergeRefreshHints(\n refreshHintsRef.current.get(workspaceId) ?? DEFAULT_REFRESH_HINT,\n hint\n );\n refreshHintsRef.current.set(workspaceId, nextHint);\n\n const existingTimer = refreshTimersRef.current.get(workspaceId);\n if (existingTimer) {\n return;\n }\n\n const timer = setTimeout(() => {\n refreshTimersRef.current.delete(workspaceId);\n const queuedHint = refreshHintsRef.current.get(workspaceId) ?? DEFAULT_REFRESH_HINT;\n refreshHintsRef.current.delete(workspaceId);\n\n if (queuedHint.markTreeStale) {\n store.set(fileTreeStaleAtomFamily(workspaceId), true);\n }\n if (queuedHint.refreshEditorBuffers) {\n store.set(editorRefreshTokenAtomFamily(workspaceId), (prev) => prev + 1);\n }\n if (queuedHint.refreshGit) {\n refreshGitState(workspaceId);\n }\n if (queuedHint.refreshBranches) {\n refreshBranchState(workspaceId);\n }\n if (queuedHint.refreshWorktrees) {\n refreshWorktreeList(workspaceId);\n }\n }, 60);\n\n refreshTimersRef.current.set(workspaceId, timer);\n };\n\n // Event handler: route WS events to atoms\n const handleEvent: EventListener = (topic: string, payload: unknown, _seq: number) => {\n if (topic === \"activation.revoked\") {\n const data = (payload ?? {}) as {\n reason?: string;\n generation?: number;\n };\n\n store.set(activationStatusAtom, \"gated\");\n store.set(\n activationReasonAtom,\n typeof data.reason === \"string\" && data.reason.length > 0 ? data.reason : \"displaced\"\n );\n store.set(\n activationGenerationAtom,\n typeof data.generation === \"number\" ? data.generation : null\n );\n resetServerProjectedState(store);\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n pendingReconnectRefreshRef.current = false;\n wsClientRef.current?.disconnect(\"single_active_displaced\");\n return;\n }\n\n const refreshInfo = parseWorkspaceRefreshHint(topic, payload);\n if (refreshInfo) {\n queueWorkspaceRefresh(refreshInfo.workspaceId, refreshInfo.hint);\n }\n\n try {\n routeEventToAtom(topic, payload, store);\n } catch (err) {\n console.error(`Error handling event for topic ${topic}:`, err);\n }\n };\n\n // Subscribe to all topics we care about\n const topics = [\n \"connection.*\", // Connection-level events\n \"activation.*\",\n \"update.*\",\n \"workspace.*\", // All workspace events (glob pattern)\n ];\n\n // Reuse existing WebSocket client if available (StrictMode safety)\n // Cancel any pending disconnect from StrictMode cleanup\n if (pendingDisconnectTimer) {\n clearTimeout(pendingDisconnectTimer);\n pendingDisconnectTimer = null;\n }\n\n if (globalWsClient) {\n wsClientRef.current = globalWsClient;\n setWsClient(globalWsClient);\n const status = globalWsClient.getStatus();\n setConnectionStatus(status);\n\n // Re-establish subscriptions for this mount\n const unsubscribeStatus = globalWsClient.onStatus(handleStatusChange);\n const unsubscribeEvents = globalWsClient.subscribe(topics, handleEvent);\n\n if (!getGlobalRecoveryCoordinator()) {\n setGlobalRecoveryCoordinator(\n createRecoveryCoordinator({\n wsClient: globalWsClient,\n sendCommand: createRecoveryDispatchCommand((op, args, options) =>\n globalWsClient!.sendCommand(op, args, options)\n ),\n applyReplay: async () => {},\n applySnapshot: async () => {},\n })\n );\n }\n\n if (status === \"disconnected\" || status === \"reconnecting\") {\n globalWsClient.recoverConnection(\"manual_retry\");\n }\n\n syncWorkspaceActivity();\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n window.addEventListener(\"focus\", handleWindowFocus);\n window.addEventListener(\"pageshow\", handlePageShow);\n window.addEventListener(\"online\", handleOnline);\n\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n window.removeEventListener(\"focus\", handleWindowFocus);\n window.removeEventListener(\"pageshow\", handlePageShow);\n window.removeEventListener(\"online\", handleOnline);\n unsubscribeStatus();\n unsubscribeEvents();\n refreshTimersRef.current.forEach((timer) => clearTimeout(timer));\n refreshTimersRef.current.clear();\n refreshHintsRef.current.clear();\n wsClientRef.current = null;\n // Deferred disconnect: wait 50ms to see if StrictMode remounts\n if (globalWsClient) {\n pendingDisconnectTimer = setTimeout(() => {\n if (globalWsClient) {\n globalWsClient.disconnect(\"app_unmount\");\n globalWsClient = null;\n }\n resetGlobalRecoveryCoordinator();\n pendingDisconnectTimer = null;\n }, 50);\n }\n };\n }\n\n // Create new WebSocket client singleton\n const client = new WsClient(resolveWsUrl());\n globalWsClient = client;\n setGlobalRecoveryCoordinator(\n createRecoveryCoordinator({\n wsClient: client,\n sendCommand: createRecoveryDispatchCommand((op, args, options) =>\n client.sendCommand(op, args, options)\n ),\n applyReplay: async () => {},\n applySnapshot: async () => {},\n })\n );\n wsClientRef.current = client;\n setWsClient(client);\n\n // Subscribe to connection status changes\n const unsubscribeStatus = client.onStatus(handleStatusChange);\n\n // Subscribe to events\n const unsubscribeEvents = client.subscribe(topics, handleEvent);\n\n // Connect to server\n client.connect().catch((err) => {\n console.error(\"Failed to connect WebSocket:\", err);\n setConnectionError(err.message || \"Connection failed\");\n });\n\n syncWorkspaceActivity();\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n window.addEventListener(\"focus\", handleWindowFocus);\n window.addEventListener(\"pageshow\", handlePageShow);\n window.addEventListener(\"online\", handleOnline);\n\n // Cleanup on unmount\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n window.removeEventListener(\"focus\", handleWindowFocus);\n window.removeEventListener(\"pageshow\", handlePageShow);\n window.removeEventListener(\"online\", handleOnline);\n unsubscribeStatus();\n unsubscribeEvents();\n refreshTimersRef.current.forEach((timer) => clearTimeout(timer));\n refreshTimersRef.current.clear();\n refreshHintsRef.current.clear();\n wsClientRef.current = null;\n // Deferred disconnect: wait 50ms to see if StrictMode remounts\n pendingDisconnectTimer = setTimeout(() => {\n if (globalWsClient) {\n globalWsClient.disconnect(\"app_unmount\");\n globalWsClient = null;\n }\n resetGlobalRecoveryCoordinator();\n pendingDisconnectTimer = null;\n }, 50);\n };\n }, [\n setWsClient,\n setConnectionStatus,\n setConnectionError,\n setServerInfo,\n setAuthEnabled,\n setReconnectCount,\n setLastReconnect,\n setIsWriter,\n setWorkspaces,\n setSessions,\n setSupervisors,\n store,\n authEnabled,\n authenticated,\n ]);\n\n useEffect(() => {\n if (authEnabled === null) {\n return;\n }\n\n if (authEnabled === true && !authenticated) {\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n return;\n }\n\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n if (activationStatus !== \"active\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n if (workspaceActivityRef.current.mode !== \"inactive\") {\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n void client.sendCommand(\"workspace.deactivate\", {}).catch(() => {});\n }\n return;\n }\n\n if (!activeWorkspaceId) {\n if (workspaceActivityRef.current.mode !== \"inactive\") {\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n void client.sendCommand(\"workspace.deactivate\", {}).catch(() => {});\n }\n return;\n }\n\n if (\n workspaceActivityRef.current.mode === \"active\" &&\n workspaceActivityRef.current.workspaceId === activeWorkspaceId\n ) {\n return;\n }\n\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n\n workspaceActivityRef.current = {\n mode: \"active\",\n workspaceId: activeWorkspaceId,\n };\n void client\n .sendCommand(\"workspace.activate\", { workspaceId: activeWorkspaceId })\n .catch(() => {});\n }, [activeWorkspaceId, activationStatus, authEnabled, authenticated, connectionStatus]);\n\n return <>{children}</>;\n}\n\nfunction storeServerMetadata(\n payload: unknown,\n store: Store\n): payload is {\n version: string;\n serverInstanceId: string;\n authEnabled?: boolean;\n isWriter?: boolean;\n} {\n const data = payload as {\n version?: unknown;\n serverInstanceId?: unknown;\n authEnabled?: unknown;\n isWriter?: unknown;\n };\n\n if (typeof data.version !== \"string\" || typeof data.serverInstanceId !== \"string\") {\n return false;\n }\n\n store.set(serverInfoAtom, {\n version: data.version,\n serverInstanceId: data.serverInstanceId,\n authEnabled: typeof data.authEnabled === \"boolean\" ? data.authEnabled : undefined,\n });\n if (typeof data.isWriter === \"boolean\") {\n store.set(isWriterAtom, data.isWriter);\n }\n\n return true;\n}\n\n/**\n * Route incoming WebSocket events to appropriate Jotai atoms\n */\nexport function routeEventToAtom(topic: string, payload: unknown, store: Store): void {\n // Parse topic to determine event type\n // Topic format: workspace.{id}.session.{sessionId}.state\n // or: connection.ready\n\n if (topic === \"connection.ready\") {\n storeServerMetadata(payload, store);\n store.set(connectionErrorAtom, null);\n return;\n }\n\n if (topic === \"connection.status\") {\n // Connection-level status event\n const data = payload as {\n status: string;\n message?: string;\n authEnabled?: boolean;\n version?: string;\n serverInstanceId?: string;\n isWriter?: boolean;\n };\n if (data.status === \"connected\") {\n storeServerMetadata(payload, store);\n }\n if (data.status === \"connected\" && data.authEnabled === false) {\n store.set(authenticatedAtom, true);\n }\n if (data.status === \"error\" && data.message) {\n store.set(connectionErrorAtom, data.message);\n }\n return;\n }\n\n if (topic === \"update.state.changed\") {\n store.set(updateStateAtom, payload as UpdateStateView);\n return;\n }\n\n // Workspace-level events: workspace.{id}.{subtopic}\n const workspaceMatch = topic.match(/^workspace\\.([^.]+)\\.(.+)$/);\n if (workspaceMatch) {\n const workspaceId = workspaceMatch[1]!;\n const subtopic = workspaceMatch[2]!;\n\n // workspace.{id}.meta - workspace metadata update\n if (subtopic === \"meta\") {\n const patch = payload as Partial<Workspace>;\n const existing = store.get(workspacesAtom)[workspaceId];\n const shouldAcceptWorkspace = Boolean(existing || patch.path);\n\n if (!shouldAcceptWorkspace) {\n return;\n }\n\n store.set(workspacesAtom, (prev: Record<string, Workspace>) => ({\n ...prev,\n [workspaceId]: {\n ...prev[workspaceId],\n ...patch,\n id: workspaceId,\n } as Workspace,\n }));\n const paneLayout = patch.uiState?.paneLayout;\n if (paneLayout) {\n store.set(paneLayoutAtomFamily(workspaceId), normalizePaneLayout(paneLayout));\n }\n store.set(workspaceOrderAtom, (prev: string[]) => {\n if (prev.includes(workspaceId)) {\n return prev;\n }\n return [...prev, workspaceId];\n });\n store.set(workspacesLoadStateAtom, \"ready\");\n store.set(workspacesLoadErrorAtom, null);\n return;\n }\n\n // workspace.{id}.fs.dirty - filesystem dirty state\n if (subtopic === \"fs.dirty\") {\n const data = (payload ?? {}) as { reason?: string };\n if (shouldMarkTreeStaleForFsReason(data.reason)) {\n const atom = fileTreeStaleAtomFamily(workspaceId);\n store.set(atom, true);\n }\n return;\n }\n\n // workspace.{id}.git.state - git state changed notification\n if (subtopic === \"git.state\") {\n return;\n }\n\n // workspace.{id}.session.{sessionId}.{type}\n const sessionMatch = subtopic.match(/^session\\.([^.]+)\\.(.+)$/);\n if (sessionMatch) {\n const sessionId = sessionMatch[1]!;\n const sessionSubtopic = sessionMatch[2]!;\n\n if (sessionSubtopic === \"lifecycle\") {\n const data = payload as { event?: string };\n if (data.event === \"removed\") {\n const removedSession = store.get(sessionsAtom)[sessionId];\n if (removedSession?.terminalId) {\n store.set(terminalMetaAtomFamily(removedSession.terminalId), null);\n }\n store.set(sessionsAtom, (prev: Record<string, Session>) => {\n if (!(sessionId in prev)) {\n return prev;\n }\n const next = { ...prev };\n delete next[sessionId];\n return next;\n });\n }\n return;\n }\n\n // workspace.{id}.session.{sessionId}.state\n if (sessionSubtopic === \"state\") {\n const session = payload as Session;\n store.set(sessionsAtom, (prev: Record<string, Session>) => ({\n ...prev,\n [session.id]: session,\n }));\n return;\n }\n\n // workspace.{id}.session.{sessionId}.progress\n if (sessionSubtopic === \"progress\") {\n // Progress updates can be handled separately if needed\n // For now, we'll just log them\n console.log(`Session ${sessionId} progress:`, payload);\n return;\n }\n\n // workspace.{id}.session.{sessionId}.supervisor.state\n if (sessionSubtopic === \"supervisor.state\") {\n const data = payload as { supervisor?: Supervisor; supervisorId?: string; event: string };\n if (data.event === \"deleted\" && data.supervisorId) {\n store.set(supervisorsAtom, (prev: Map<string, Supervisor>) => {\n const next = new Map(prev);\n // Find and remove by supervisor ID\n for (const [sessId, sup] of next.entries()) {\n if (sup.id === data.supervisorId) {\n next.delete(sessId);\n break;\n }\n }\n return next;\n });\n } else if (data.supervisor) {\n const supervisor = data.supervisor;\n store.set(supervisorsAtom, (prev: Map<string, Supervisor>) => {\n const next = new Map(prev);\n next.set(supervisor.sessionId, supervisor);\n return next;\n });\n }\n return;\n }\n }\n\n // workspace.{id}.terminal.{terminalId}.{type}\n const terminalMatch = subtopic.match(/^terminal\\.([^.]+)\\.(.+)$/);\n if (terminalMatch) {\n const terminalId = terminalMatch[1]!;\n const terminalSubtopic = terminalMatch[2]!;\n\n // workspace.{id}.terminal.{terminalId}.created\n if (terminalSubtopic === \"created\") {\n const data = payload as { id: string; kind: string; title?: string; cwd?: string };\n const atom = terminalMetaAtomFamily(terminalId);\n store.set(atom, {\n id: data.id,\n workspaceId,\n kind: data.kind as \"agent\" | \"shell\",\n alive: true,\n title: data.title,\n });\n return;\n }\n\n // workspace.{id}.terminal.{terminalId}.output\n // Terminal panels consume output directly via xterm.js — no router-level\n // handling needed.\n if (terminalSubtopic === \"output\") {\n return;\n }\n\n // workspace.{id}.terminal.{terminalId}.exit\n if (terminalSubtopic === \"exit\") {\n const data = payload as { code: number };\n const atom = terminalMetaAtomFamily(terminalId);\n const current = store.get(atom);\n if (current) {\n store.set(atom, {\n ...current,\n exitCode: data.code,\n alive: false,\n });\n }\n return;\n }\n }\n }\n\n // Unknown topic - log for debugging\n console.log(`Unhandled event topic: ${topic}`, payload);\n}\n\nfunction normalizePaneLayout(layout: Workspace[\"uiState\"][\"paneLayout\"]): PaneNode {\n return {\n id: layout?.id ?? \"root\",\n type: layout?.type ?? \"leaf\",\n sessionId: layout?.sessionId,\n direction: layout?.direction,\n children: layout?.children?.map((child) => normalizePaneLayout(child)),\n };\n}\n","/**\n * Application Entry Point\n */\n\nimport \"@vitejs/plugin-react/preamble\";\nimport { Provider } from \"jotai\";\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport App from \"./app\";\nimport { AppProviders } from \"./app/providers\";\n\nimport \"@xterm/xterm/css/xterm.css\";\n\n// Import fonts\nimport \"./styles/fonts.css\";\n\n// Import styles\nimport \"./styles/tokens.css\";\nimport \"./styles/base.css\";\nimport \"./styles/components.css\";\n\n// Mount application\nconst root = ReactDOM.createRoot(document.getElementById(\"root\") as HTMLElement);\n\nroot.render(\n <Provider>\n <AppProviders>\n <App />\n </AppProviders>\n </Provider>\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"main-CEv6hML1.js","names":[],"sources":["../../src/app.tsx","../../src/hooks/use-activation.ts","../../src/ws/reconnect.ts","../../src/app/providers.tsx","../../src/main.tsx"],"sourcesContent":["/**\n * Application root.\n *\n * Provides BrowserRouter and picks a shell based on viewport:\n * - mobile (< 900px) -> MobileShell\n * - desktop -> DesktopShell\n */\n\nimport { BrowserRouter } from \"react-router-dom\";\nimport { useViewport } from \"./hooks/use-viewport\";\nimport { DesktopShell } from \"./shells/desktop-shell\";\nimport { MobileShell } from \"./shells/mobile-shell\";\n\nfunction ShellSwitch() {\n const viewport = useViewport();\n\n return viewport === \"mobile\" ? <MobileShell /> : <DesktopShell />;\n}\n\nfunction App() {\n return (\n <BrowserRouter>\n <ShellSwitch />\n </BrowserRouter>\n );\n}\n\nexport default App;\n","import { useAtom, useAtomValue, useSetAtom } from \"jotai\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport {\n activationGenerationAtom,\n activationReasonAtom,\n activationStatusAtom,\n clientInstanceIdAtom,\n} from \"../atoms/activation\";\nimport { connectionStatusAtom, wsClientAtom } from \"../atoms/connection\";\n\ninterface ActivationClaimPayload {\n active: true;\n generation: number;\n recoveryMode: \"fresh\" | \"grace_recover\" | \"takeover\";\n}\n\nconst CLAIM_RETRY_DELAY_MS = 1_000;\n\nexport function useActivation() {\n const wsClient = useAtomValue(wsClientAtom);\n const connectionStatus = useAtomValue(connectionStatusAtom);\n const clientInstanceId = useAtomValue(clientInstanceIdAtom);\n const [status, setStatus] = useAtom(activationStatusAtom);\n const [generation, setGeneration] = useAtom(activationGenerationAtom);\n const setReason = useSetAtom(activationReasonAtom);\n const claimInFlightRef = useRef<Promise<boolean> | null>(null);\n const claimRetryTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const claim = useCallback(async (): Promise<boolean> => {\n if (!wsClient) {\n return false;\n }\n\n if (connectionStatus !== \"connected\") {\n try {\n await wsClient.connect();\n } catch {\n setReason(null);\n setStatus((current) => (current === \"gated\" ? current : \"idle\"));\n return false;\n }\n }\n\n if (claimInFlightRef.current) {\n return claimInFlightRef.current;\n }\n\n setStatus(\"claiming\");\n\n const pending = wsClient\n .sendCommand<ActivationClaimPayload>(\"activation.claim\", {\n clientInstanceId,\n })\n .then((result) => {\n setGeneration(result.generation);\n setReason(null);\n setStatus(\"active\");\n return true;\n })\n .catch(() => {\n setReason(null);\n setStatus((current) => (current === \"gated\" ? current : \"idle\"));\n return false;\n })\n .finally(() => {\n claimInFlightRef.current = null;\n });\n\n claimInFlightRef.current = pending;\n return pending;\n }, [clientInstanceId, connectionStatus, setGeneration, setReason, setStatus, wsClient]);\n\n useEffect(() => {\n if (claimRetryTimerRef.current !== null) {\n clearTimeout(claimRetryTimerRef.current);\n claimRetryTimerRef.current = null;\n }\n\n if (!wsClient || connectionStatus !== \"connected\" || status !== \"idle\") {\n return;\n }\n\n claimRetryTimerRef.current = setTimeout(() => {\n claimRetryTimerRef.current = null;\n if (!claimInFlightRef.current) {\n void claim();\n }\n }, CLAIM_RETRY_DELAY_MS);\n\n return () => {\n if (claimRetryTimerRef.current !== null) {\n clearTimeout(claimRetryTimerRef.current);\n claimRetryTimerRef.current = null;\n }\n };\n }, [claim, connectionStatus, status, wsClient]);\n\n useEffect(() => {\n return () => {\n if (claimRetryTimerRef.current !== null) {\n clearTimeout(claimRetryTimerRef.current);\n claimRetryTimerRef.current = null;\n }\n\n if (!wsClient || generation === null) {\n return;\n }\n\n void wsClient\n .sendCommand(\"activation.release\", {\n clientInstanceId,\n generation,\n })\n .catch(() => {});\n };\n }, [clientInstanceId, generation, wsClient]);\n\n return {\n status,\n generation,\n claim,\n };\n}\n","/**\n * Reconnection Utilities\n *\n * Exponential backoff and reconnect state management.\n */\n\nexport interface ReconnectState {\n attempts: number;\n lastAttemptAt: number | null;\n nextDelayMs: number;\n maxAttemptsReached: boolean;\n}\n\nexport interface ReconnectConfig {\n maxAttempts: number;\n baseDelayMs: number;\n maxDelayMs: number;\n jitterMs: number;\n}\n\nconst DEFAULT_CONFIG: ReconnectConfig = {\n maxAttempts: Number.POSITIVE_INFINITY,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n jitterMs: 100,\n};\n\n/**\n * Calculate next reconnect delay using exponential backoff with jitter\n */\nexport function calculateReconnectDelay(\n attempts: number,\n config: Partial<ReconnectConfig> = {}\n): number {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n\n // Exponential backoff: base * 2^attempts\n const exponentialDelay = cfg.baseDelayMs * Math.pow(2, attempts);\n\n // Cap at max delay\n const cappedDelay = Math.min(exponentialDelay, cfg.maxDelayMs);\n\n // Add jitter to prevent thundering herd\n const jitter = Math.random() * cfg.jitterMs;\n\n return cappedDelay + jitter;\n}\n\n/**\n * Create reconnect state tracker\n */\nexport function createReconnectTracker(config: Partial<ReconnectConfig> = {}) {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n let attempts = 0;\n let lastAttemptAt: number | null = null;\n\n return {\n recordAttempt(): ReconnectState {\n attempts++;\n lastAttemptAt = Date.now();\n\n return {\n attempts,\n lastAttemptAt,\n nextDelayMs: calculateReconnectDelay(attempts, cfg),\n maxAttemptsReached: attempts >= cfg.maxAttempts,\n };\n },\n\n reset(): void {\n attempts = 0;\n lastAttemptAt = null;\n },\n\n getState(): ReconnectState {\n return {\n attempts,\n lastAttemptAt,\n nextDelayMs: calculateReconnectDelay(attempts, cfg),\n maxAttemptsReached: attempts >= cfg.maxAttempts,\n };\n },\n };\n}\n","/**\n * Application Providers\n *\n * Initializes WebSocket connection and sets up event routing.\n * Manages connection lifecycle and maps WS events to Jotai atoms.\n */\n\nimport type {\n GitBranch,\n GitStatus,\n Session,\n Supervisor,\n UpdateStateView,\n Workspace,\n WorktreeInfo,\n} from \"@coder-studio/core\";\nimport { useAtom, useAtomValue, useSetAtom, useStore } from \"jotai\";\nimport type { Store } from \"jotai/vanilla/store\";\nimport { useEffect, useRef } from \"react\";\nimport {\n authEnabledAtom,\n connectionErrorAtom,\n connectionStatusAtom,\n dispatchCommandAtom,\n isWriterAtom,\n lastReconnectAttemptAtom,\n reconnectAttemptCountAtom,\n serverInfoAtom,\n sessionsAtom,\n workspaceOrderAtom,\n workspacesAtom,\n workspacesLoadErrorAtom,\n workspacesLoadStateAtom,\n wsClientAtom,\n} from \"../atoms\";\nimport {\n activationGenerationAtom,\n activationReasonAtom,\n activationStatusAtom,\n} from \"../atoms/activation\";\nimport { authenticatedAtom, themeAtom } from \"../atoms/app-ui\";\nimport type { DispatchCommand } from \"../atoms/connection\";\nimport { activeWorkspaceIdAtom } from \"../atoms/workspaces\";\nimport { type PaneNode, paneLayoutAtomFamily } from \"../features/agent-panes/atoms/pane-layout\";\nimport { monacoModelRegistry } from \"../features/code-editor/monaco/model-registry\";\nimport { useSessionNotifications } from \"../features/notifications\";\nimport { supervisorsAtom } from \"../features/supervisor/atoms\";\nimport { terminalMetaAtomFamily } from \"../features/terminal-panel/atoms\";\nimport {\n hasExplicitTerminalFontSizeSetting,\n hasLegacyTerminalFontSizeSetting,\n resolveTerminalCopyOnSelectSetting,\n resolveTerminalFontSizeSetting,\n terminalPreferencesAtom,\n} from \"../features/terminal-panel/preferences\";\nimport {\n createRecoveryCoordinator,\n createRecoveryDispatchCommand,\n} from \"../features/terminal-panel/recovery-coordinator\";\nimport {\n getGlobalRecoveryCoordinator,\n resetGlobalRecoveryCoordinator,\n setGlobalRecoveryCoordinator,\n} from \"../features/terminal-panel/recovery-singleton\";\nimport { updateStateAtom } from \"../features/updates/atoms\";\nimport {\n editorRefreshTokenAtomFamily,\n expandedDirsAtomFamily,\n fileTreeAtomFamily,\n fileTreeStaleAtomFamily,\n gitBranchListAtomFamily,\n gitStateAtomFamily,\n loadedDirsAtomFamily,\n worktreeListAtomFamily,\n} from \"../features/workspace/atoms\";\nimport { useActivation } from \"../hooks/use-activation\";\nimport { useTranslation } from \"../lib/i18n\";\nimport { getThemeById, resolveStoredThemeId } from \"../theme\";\nimport type { ConnectionStatus, EventListener } from \"../ws\";\nimport { resolveWsUrl, WsClient } from \"../ws\";\n\n/**\n * Module-level WebSocket client singleton.\n * Prevents duplicate connections in React StrictMode.\n */\nlet globalWsClient: WsClient | null = null;\nlet pendingDisconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\ninterface WorkspaceRefreshHint {\n refreshGit: boolean;\n refreshBranches: boolean;\n refreshWorktrees: boolean;\n markTreeStale: boolean;\n refreshEditorBuffers: boolean;\n}\n\ninterface WorkspaceActivityState {\n mode: \"active\" | \"inactive\";\n workspaceId: string | null;\n}\n\ninterface AppearanceSelectionVersion {\n theme: number;\n}\n\nconst DEFAULT_REFRESH_HINT: WorkspaceRefreshHint = {\n refreshGit: false,\n refreshBranches: false,\n refreshWorktrees: false,\n markTreeStale: false,\n refreshEditorBuffers: false,\n};\nconst FOREGROUND_RECOVERY_COOLDOWN_MS = 250;\nconst THEME_ID_STORAGE_KEY = \"ui.themeId\";\nconst LEGACY_THEME_STORAGE_KEY = \"ui.theme\";\n\nfunction shouldMarkTreeStaleForFsReason(reason?: string): boolean {\n return reason === \"fs_change\";\n}\n\nfunction readStoredThemePreference(): unknown {\n const storedThemeId = localStorage.getItem(THEME_ID_STORAGE_KEY);\n if (storedThemeId !== null) {\n try {\n return JSON.parse(storedThemeId);\n } catch {\n return undefined;\n }\n }\n\n const legacyTheme = localStorage.getItem(LEGACY_THEME_STORAGE_KEY);\n if (legacyTheme !== null) {\n try {\n return JSON.parse(legacyTheme);\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n}\n\nfunction applyResolvedTheme(themeId: unknown): string {\n const resolvedTheme = getThemeById(resolveStoredThemeId(themeId));\n document.documentElement.setAttribute(\"data-theme\", resolvedTheme.documentThemeAttr);\n return resolvedTheme.id;\n}\n\nexport function resetAppProvidersSingletonsForTests() {\n if (pendingDisconnectTimer) {\n clearTimeout(pendingDisconnectTimer);\n pendingDisconnectTimer = null;\n }\n globalWsClient = null;\n resetGlobalRecoveryCoordinator();\n}\n\nfunction reportRecoveryCoordinatorError(context: string, error: unknown) {\n console.error(`[RecoveryCoordinator] ${context} failed:`, error);\n}\n\nfunction mergeRefreshHints(\n current: WorkspaceRefreshHint,\n next: Partial<WorkspaceRefreshHint>\n): WorkspaceRefreshHint {\n return {\n refreshGit: current.refreshGit || Boolean(next.refreshGit),\n refreshBranches: current.refreshBranches || Boolean(next.refreshBranches),\n refreshWorktrees: current.refreshWorktrees || Boolean(next.refreshWorktrees),\n markTreeStale: current.markTreeStale || Boolean(next.markTreeStale),\n refreshEditorBuffers: current.refreshEditorBuffers || Boolean(next.refreshEditorBuffers),\n };\n}\n\nfunction resetServerProjectedState(store: Store): void {\n const workspaceIds = store.get(workspaceOrderAtom);\n const workspaces = store.get(workspacesAtom);\n const terminalIds = Object.values(store.get(sessionsAtom))\n .map((session) => session.terminalId)\n .filter((terminalId): terminalId is string => Boolean(terminalId));\n\n store.set(workspacesAtom, {});\n store.set(workspaceOrderAtom, []);\n store.set(workspacesLoadStateAtom, \"idle\");\n store.set(workspacesLoadErrorAtom, null);\n store.set(sessionsAtom, {});\n store.set(activeWorkspaceIdAtom, null);\n store.set(supervisorsAtom, new Map());\n\n for (const workspaceId of workspaceIds) {\n const workspace = workspaces[workspaceId];\n if (workspace) {\n monacoModelRegistry.disposeWorkspace(workspace.path);\n }\n store.set(fileTreeAtomFamily(workspaceId), null);\n store.set(loadedDirsAtomFamily(workspaceId), new Set());\n store.set(expandedDirsAtomFamily(workspaceId), null);\n store.set(gitStateAtomFamily(workspaceId), null);\n store.set(gitBranchListAtomFamily(workspaceId), {\n current: \"\",\n branches: [],\n loading: false,\n });\n store.set(worktreeListAtomFamily(workspaceId), {\n items: [],\n loading: false,\n });\n store.set(fileTreeStaleAtomFamily(workspaceId), false);\n store.set(editorRefreshTokenAtomFamily(workspaceId), 0);\n }\n\n for (const terminalId of terminalIds) {\n store.set(terminalMetaAtomFamily(terminalId), null);\n }\n}\n\nfunction parseWorkspaceRefreshHint(\n topic: string,\n payload: unknown\n): {\n workspaceId: string;\n hint: WorkspaceRefreshHint;\n} | null {\n const match = topic.match(/^workspace\\.([^.]+)\\.(fs\\.dirty|git\\.state)$/);\n if (!match) {\n return null;\n }\n\n const workspaceId = match[1]!;\n const subtopic = match[2]!;\n\n if (subtopic === \"fs.dirty\") {\n const data = (payload ?? {}) as { reason?: string };\n return {\n workspaceId,\n hint: {\n refreshGit: true,\n refreshBranches: data.reason === \"git_metadata\",\n refreshWorktrees: data.reason === \"git_metadata\",\n markTreeStale: shouldMarkTreeStaleForFsReason(data.reason),\n refreshEditorBuffers: data.reason === \"fs_change\" || data.reason === \"file_content\",\n },\n };\n }\n\n const data = (payload ?? {}) as {\n treeChanged?: boolean;\n branchChanged?: boolean;\n worktreeChanged?: boolean;\n };\n\n return {\n workspaceId,\n hint: {\n refreshGit: true,\n refreshBranches: Boolean(data.branchChanged),\n refreshWorktrees: Boolean(data.worktreeChanged),\n markTreeStale: Boolean(data.treeChanged),\n refreshEditorBuffers: Boolean(data.treeChanged),\n },\n };\n}\n\ninterface AppProvidersProps {\n children: React.ReactNode;\n}\n\nexport function AppProviders({ children }: AppProvidersProps) {\n const t = useTranslation();\n const [, setWsClient] = useAtom(wsClientAtom);\n const [theme, setTheme] = useAtom(themeAtom);\n const authEnabled = useAtomValue(authEnabledAtom);\n const authenticated = useAtomValue(authenticatedAtom);\n const connectionStatus = useAtomValue(connectionStatusAtom);\n const activationStatus = useAtomValue(activationStatusAtom);\n const activeWorkspaceId = useAtomValue(activeWorkspaceIdAtom);\n const setConnectionStatus = useSetAtom(connectionStatusAtom);\n const setConnectionError = useSetAtom(connectionErrorAtom);\n const setServerInfo = useSetAtom(serverInfoAtom);\n const setAuthEnabled = useSetAtom(authEnabledAtom);\n const setReconnectCount = useSetAtom(reconnectAttemptCountAtom);\n const setLastReconnect = useSetAtom(lastReconnectAttemptAtom);\n const setIsWriter = useSetAtom(isWriterAtom);\n\n // Server state atoms\n const setWorkspaces = useSetAtom(workspacesAtom);\n const setSessions = useSetAtom(sessionsAtom);\n // Supervisor state atoms\n const setSupervisors = useSetAtom(supervisorsAtom);\n const setTerminalPreferences = useSetAtom(terminalPreferencesAtom);\n const setUpdateState = useSetAtom(updateStateAtom);\n\n // Get Jotai store for writing to atomFamily atoms\n const store = useStore();\n const dispatch = useAtomValue(dispatchCommandAtom);\n const { claim } = useActivation();\n\n useSessionNotifications();\n\n // Use refs to avoid stale closures in event handlers\n const wsClientRef = useRef<WsClient | null>(null);\n const dispatchRef = useRef<DispatchCommand>(dispatch);\n const refreshTimersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n const refreshHintsRef = useRef<Map<string, WorkspaceRefreshHint>>(new Map());\n const activeWorkspaceIdRef = useRef<string | null>(activeWorkspaceId);\n const pendingReconnectRefreshRef = useRef(false);\n const lastForegroundRecoveryAtRef = useRef<number | null>(null);\n const workspaceActivityRef = useRef<WorkspaceActivityState>({\n mode: \"inactive\",\n workspaceId: null,\n });\n const appearanceSelectionVersionRef = useRef<AppearanceSelectionVersion>({\n theme: 0,\n });\n const preferPersistedThemeOnFirstHydrationRef = useRef(false);\n\n // Keep dispatchRef in sync\n useEffect(() => {\n dispatchRef.current = dispatch;\n }, [dispatch]);\n\n const refreshPendingReconnectState = () => {\n if (!pendingReconnectRefreshRef.current) {\n return;\n }\n\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n if (document.visibilityState !== \"visible\") {\n return;\n }\n\n if (activationStatus !== \"active\") {\n return;\n }\n\n const workspaceId = activeWorkspaceId;\n if (!workspaceId) {\n return;\n }\n\n pendingReconnectRefreshRef.current = false;\n dispatchRef.current<GitStatus>(\"git.status\", { workspaceId }).then((result) => {\n if (result.ok && result.data) {\n store.set(gitStateAtomFamily(workspaceId), result.data);\n }\n });\n dispatchRef\n .current<{ current: string; branches: GitBranch[] }>(\"git.branches\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data) {\n store.set(gitBranchListAtomFamily(workspaceId), {\n current: result.data.current,\n branches: result.data.branches,\n loading: false,\n });\n }\n });\n dispatchRef\n .current<{ worktrees: WorktreeInfo[] }>(\"worktree.list\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data && Array.isArray(result.data.worktrees)) {\n store.set(worktreeListAtomFamily(workspaceId), {\n items: result.data.worktrees,\n loading: false,\n lastLoadedAt: Date.now(),\n });\n }\n });\n };\n\n useEffect(() => {\n refreshPendingReconnectState();\n }, [activationStatus, activeWorkspaceId, connectionStatus]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n let cancelled = false;\n let terminalPreferencesAtSubscriptionStart = store.get(terminalPreferencesAtom);\n let localTerminalCopyOnSelectUpdated = false;\n let localDesktopTerminalFontSizeUpdated = false;\n let localMobileTerminalFontSizeUpdated = false;\n const unsubscribeTerminalPreferences = store.sub(terminalPreferencesAtom, () => {\n const nextTerminalPreferences = store.get(terminalPreferencesAtom);\n if (\n nextTerminalPreferences.copyOnSelect !== terminalPreferencesAtSubscriptionStart.copyOnSelect\n ) {\n localTerminalCopyOnSelectUpdated = true;\n }\n if (\n nextTerminalPreferences.desktopFontSize !==\n terminalPreferencesAtSubscriptionStart.desktopFontSize\n ) {\n localDesktopTerminalFontSizeUpdated = true;\n }\n if (\n nextTerminalPreferences.mobileFontSize !==\n terminalPreferencesAtSubscriptionStart.mobileFontSize\n ) {\n localMobileTerminalFontSizeUpdated = true;\n }\n terminalPreferencesAtSubscriptionStart = nextTerminalPreferences;\n });\n\n const hydrateTerminalPreferences = async () => {\n const result = await dispatch<Record<string, unknown>>(\"settings.get\", {});\n if (cancelled || !result.ok || !result.data) {\n return;\n }\n\n const currentTerminalPreferences = store.get(terminalPreferencesAtom);\n const shouldHydrateDesktopTerminalFontSize = localDesktopTerminalFontSizeUpdated\n ? currentTerminalPreferences.desktopFontSize\n : resolveTerminalFontSizeSetting(result.data, \"desktop\");\n const shouldHydrateMobileTerminalFontSize = localMobileTerminalFontSizeUpdated\n ? currentTerminalPreferences.mobileFontSize\n : resolveTerminalFontSizeSetting(result.data, \"mobile\");\n const hasLegacyFontSize = hasLegacyTerminalFontSizeSetting(result.data);\n const hasExplicitDesktopFontSize = hasExplicitTerminalFontSizeSetting(result.data, \"desktop\");\n const hasExplicitMobileFontSize = hasExplicitTerminalFontSizeSetting(result.data, \"mobile\");\n const nextTerminalPreferences = {\n copyOnSelect: localTerminalCopyOnSelectUpdated\n ? currentTerminalPreferences.copyOnSelect\n : resolveTerminalCopyOnSelectSetting(result.data),\n desktopFontSize: shouldHydrateDesktopTerminalFontSize,\n mobileFontSize: shouldHydrateMobileTerminalFontSize,\n fontSize:\n hasExplicitDesktopFontSize || hasExplicitMobileFontSize || hasLegacyFontSize\n ? resolveTerminalFontSizeSetting(result.data, \"desktop\")\n : currentTerminalPreferences.fontSize,\n };\n setTerminalPreferences(nextTerminalPreferences);\n };\n\n void hydrateTerminalPreferences();\n\n return () => {\n cancelled = true;\n unsubscribeTerminalPreferences();\n };\n }, [connectionStatus, dispatch, setTerminalPreferences, store]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n let cancelled = false;\n\n const hydrateUpdateState = async () => {\n const result = await dispatch<UpdateStateView>(\"updates.getState\", {});\n if (cancelled || !result.ok || !result.data) {\n return;\n }\n setUpdateState(result.data);\n };\n\n void hydrateUpdateState();\n\n return () => {\n cancelled = true;\n };\n }, [connectionStatus, dispatch, setUpdateState]);\n\n useEffect(() => {\n activeWorkspaceIdRef.current = activeWorkspaceId;\n }, [activeWorkspaceId]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n if (store.get(activationStatusAtom) === \"gated\") {\n return;\n }\n\n void claim();\n }, [claim, connectionStatus, store]);\n\n // Initialize theme from localStorage\n useEffect(() => {\n preferPersistedThemeOnFirstHydrationRef.current =\n localStorage.getItem(THEME_ID_STORAGE_KEY) !== null;\n const resolvedThemeId = applyResolvedTheme(readStoredThemePreference());\n setTheme(resolvedThemeId);\n localStorage.setItem(THEME_ID_STORAGE_KEY, JSON.stringify(resolvedThemeId));\n }, [setTheme]);\n\n useEffect(() => {\n const resolvedTheme = getThemeById(theme);\n document.documentElement.setAttribute(\"data-theme\", resolvedTheme.documentThemeAttr);\n localStorage.setItem(THEME_ID_STORAGE_KEY, JSON.stringify(resolvedTheme.id));\n }, [theme]);\n\n useEffect(() => {\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n let cancelled = false;\n\n const hydrateTheme = async () => {\n const appearanceSelectionVersionAtRequestStart = {\n ...appearanceSelectionVersionRef.current,\n };\n const result = await dispatch<Record<string, unknown>>(\"settings.get\", {});\n if (cancelled || !result.ok || !result.data) {\n return;\n }\n\n if (\n appearanceSelectionVersionRef.current.theme !==\n appearanceSelectionVersionAtRequestStart.theme\n ) {\n return;\n }\n\n if (preferPersistedThemeOnFirstHydrationRef.current) {\n preferPersistedThemeOnFirstHydrationRef.current = false;\n return;\n }\n\n const settings = result.data;\n const resolvedThemeId = resolveStoredThemeId(\n settings[\"appearance.themeId\"] ??\n settings[\"appearance.theme\"] ??\n readStoredThemePreference()\n );\n\n setTheme(resolvedThemeId);\n };\n\n void hydrateTheme();\n\n return () => {\n cancelled = true;\n };\n }, [connectionStatus, dispatch, setTheme]);\n\n useEffect(() => {\n const unsubscribeTheme = store.sub(themeAtom, () => {\n appearanceSelectionVersionRef.current.theme += 1;\n });\n\n return () => {\n unsubscribeTheme();\n };\n }, [store]);\n\n useEffect(() => {\n const loadAuthStatus = async () => {\n try {\n const response = await fetch(\"/auth/status\");\n const data = await response.json();\n setAuthEnabled(Boolean(data.authEnabled));\n store.set(authenticatedAtom, Boolean(data.authenticated) || data.authEnabled === false);\n } catch {\n store.set(authenticatedAtom, false);\n }\n };\n\n void loadAuthStatus();\n }, [setAuthEnabled, store]);\n\n useEffect(() => {\n if (authEnabled === null) {\n return;\n }\n\n if (authEnabled === true && !authenticated) {\n if (pendingDisconnectTimer) {\n clearTimeout(pendingDisconnectTimer);\n pendingDisconnectTimer = null;\n }\n\n if (globalWsClient) {\n globalWsClient.disconnect(\"auth_required\");\n globalWsClient = null;\n }\n resetGlobalRecoveryCoordinator();\n\n wsClientRef.current = null;\n setWsClient(null);\n setConnectionStatus(\"connecting\");\n setConnectionError(null);\n setServerInfo(null);\n setReconnectCount(0);\n setLastReconnect(null);\n setIsWriter(false);\n return;\n }\n\n // Subscribe to connection status changes\n const handleStatusChange = (status: ConnectionStatus) => {\n setConnectionStatus(status);\n\n // Track reconnect attempts\n if (status === \"reconnecting\") {\n setReconnectCount((count) => count + 1);\n setLastReconnect((previous) => previous ?? Date.now());\n store.set(activationStatusAtom, (current) => (current === \"gated\" ? current : \"idle\"));\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n pendingReconnectRefreshRef.current = true;\n }\n\n // Reset writer status on disconnect\n if (status === \"disconnected\" || status === \"rejected\") {\n setIsWriter(false);\n store.set(activationStatusAtom, (current) => (current === \"gated\" ? current : \"idle\"));\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n if (status === \"disconnected\") {\n pendingReconnectRefreshRef.current = true;\n }\n }\n\n if (status === \"connected\") {\n setReconnectCount(0);\n setLastReconnect(null);\n syncWorkspaceActivity(true);\n }\n };\n\n const refreshGitState = (workspaceId: string) => {\n dispatchRef\n .current<GitStatus>(\"git.status\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data) {\n store.set(gitStateAtomFamily(workspaceId), result.data);\n }\n })\n .catch((error) => {\n console.error(\"[Git Status] git.status command threw error:\", error);\n });\n };\n\n const sendWorkspaceDeactivate = () => {\n const currentState = workspaceActivityRef.current;\n if (currentState.mode === \"inactive\") {\n return;\n }\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n void client.sendCommand(\"workspace.deactivate\", {}).catch(() => {});\n };\n\n const sendWorkspaceActivate = (workspaceId: string) => {\n if (store.get(activationStatusAtom) !== \"active\") {\n return;\n }\n\n const currentState = workspaceActivityRef.current;\n if (currentState.mode === \"active\" && currentState.workspaceId === workspaceId) {\n return;\n }\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"active\",\n workspaceId,\n };\n void client.sendCommand(\"workspace.activate\", { workspaceId }).catch(() => {});\n };\n\n const syncWorkspaceActivity = (force = false) => {\n if (document.visibilityState === \"hidden\") {\n sendWorkspaceDeactivate();\n return;\n }\n\n const workspaceId = activeWorkspaceIdRef.current;\n if (!workspaceId) {\n sendWorkspaceDeactivate();\n return;\n }\n\n if (force) {\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n }\n\n sendWorkspaceActivate(workspaceId);\n };\n\n const triggerForegroundRecovery = () => {\n if (store.get(activationStatusAtom) === \"gated\") {\n return;\n }\n\n syncWorkspaceActivity();\n if (document.visibilityState !== \"visible\") {\n lastForegroundRecoveryAtRef.current = null;\n return;\n }\n\n const now = Date.now();\n const lastForegroundRecoveryAt = lastForegroundRecoveryAtRef.current;\n if (\n lastForegroundRecoveryAt !== null &&\n now - lastForegroundRecoveryAt < FOREGROUND_RECOVERY_COOLDOWN_MS\n ) {\n return;\n }\n\n lastForegroundRecoveryAtRef.current = now;\n void getGlobalRecoveryCoordinator()\n ?.notifyReason(\"foreground_resume\")\n .catch((error) => {\n reportRecoveryCoordinatorError(\"foreground_resume\", error);\n });\n };\n\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n lastForegroundRecoveryAtRef.current = null;\n syncWorkspaceActivity();\n return;\n }\n\n triggerForegroundRecovery();\n };\n\n const handleWindowFocus = () => {\n triggerForegroundRecovery();\n };\n\n const handlePageShow = () => {\n triggerForegroundRecovery();\n };\n\n const handleOnline = () => {\n if (store.get(activationStatusAtom) === \"gated\") {\n return;\n }\n\n void getGlobalRecoveryCoordinator()\n ?.notifyReason(\"network_online\")\n .catch((error) => {\n reportRecoveryCoordinatorError(\"network_online\", error);\n });\n };\n\n const refreshBranchState = (workspaceId: string) => {\n dispatchRef\n .current<{ current: string; branches: GitBranch[] }>(\"git.branches\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data) {\n store.set(gitBranchListAtomFamily(workspaceId), {\n current: result.data.current,\n branches: result.data.branches,\n loading: false,\n });\n return;\n }\n\n store.set(gitBranchListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: false,\n error: result.error?.message ?? prev.error,\n }));\n })\n .catch((error) => {\n console.error(\"[Git Branches] git.branches command threw error:\", error);\n });\n };\n\n const refreshWorktreeList = (workspaceId: string) => {\n store.set(worktreeListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: true,\n error: undefined,\n }));\n dispatchRef\n .current<{ worktrees: WorktreeInfo[] }>(\"worktree.list\", { workspaceId })\n .then((result) => {\n if (result.ok && result.data && Array.isArray(result.data.worktrees)) {\n store.set(worktreeListAtomFamily(workspaceId), {\n items: result.data.worktrees,\n loading: false,\n lastLoadedAt: Date.now(),\n });\n return;\n }\n\n store.set(worktreeListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: false,\n error: result.error?.message ?? prev.error,\n }));\n })\n .catch((error) => {\n console.error(\"[Worktree List] worktree.list command threw error:\", error);\n store.set(worktreeListAtomFamily(workspaceId), (prev) => ({\n ...prev,\n loading: false,\n error: error instanceof Error ? error.message : String(error),\n }));\n });\n };\n\n const queueWorkspaceRefresh = (workspaceId: string, hint: Partial<WorkspaceRefreshHint>) => {\n const nextHint = mergeRefreshHints(\n refreshHintsRef.current.get(workspaceId) ?? DEFAULT_REFRESH_HINT,\n hint\n );\n refreshHintsRef.current.set(workspaceId, nextHint);\n\n const existingTimer = refreshTimersRef.current.get(workspaceId);\n if (existingTimer) {\n return;\n }\n\n const timer = setTimeout(() => {\n refreshTimersRef.current.delete(workspaceId);\n const queuedHint = refreshHintsRef.current.get(workspaceId) ?? DEFAULT_REFRESH_HINT;\n refreshHintsRef.current.delete(workspaceId);\n\n if (queuedHint.markTreeStale) {\n store.set(fileTreeStaleAtomFamily(workspaceId), true);\n }\n if (queuedHint.refreshEditorBuffers) {\n store.set(editorRefreshTokenAtomFamily(workspaceId), (prev) => prev + 1);\n }\n if (queuedHint.refreshGit) {\n refreshGitState(workspaceId);\n }\n if (queuedHint.refreshBranches) {\n refreshBranchState(workspaceId);\n }\n if (queuedHint.refreshWorktrees) {\n refreshWorktreeList(workspaceId);\n }\n }, 60);\n\n refreshTimersRef.current.set(workspaceId, timer);\n };\n\n // Event handler: route WS events to atoms\n const handleEvent: EventListener = (topic: string, payload: unknown, _seq: number) => {\n if (topic === \"activation.revoked\") {\n const data = (payload ?? {}) as {\n reason?: string;\n generation?: number;\n };\n\n store.set(activationStatusAtom, \"gated\");\n store.set(\n activationReasonAtom,\n typeof data.reason === \"string\" && data.reason.length > 0 ? data.reason : \"displaced\"\n );\n store.set(\n activationGenerationAtom,\n typeof data.generation === \"number\" ? data.generation : null\n );\n resetServerProjectedState(store);\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n pendingReconnectRefreshRef.current = false;\n wsClientRef.current?.disconnect(\"single_active_displaced\");\n return;\n }\n\n const refreshInfo = parseWorkspaceRefreshHint(topic, payload);\n if (refreshInfo) {\n queueWorkspaceRefresh(refreshInfo.workspaceId, refreshInfo.hint);\n }\n\n try {\n routeEventToAtom(topic, payload, store);\n } catch (err) {\n console.error(`Error handling event for topic ${topic}:`, err);\n }\n };\n\n // Subscribe to all topics we care about\n const topics = [\n \"connection.*\", // Connection-level events\n \"activation.*\",\n \"update.*\",\n \"workspace.*\", // All workspace events (glob pattern)\n ];\n\n // Reuse existing WebSocket client if available (StrictMode safety)\n // Cancel any pending disconnect from StrictMode cleanup\n if (pendingDisconnectTimer) {\n clearTimeout(pendingDisconnectTimer);\n pendingDisconnectTimer = null;\n }\n\n if (globalWsClient) {\n wsClientRef.current = globalWsClient;\n setWsClient(globalWsClient);\n const status = globalWsClient.getStatus();\n setConnectionStatus(status);\n\n // Re-establish subscriptions for this mount\n const unsubscribeStatus = globalWsClient.onStatus(handleStatusChange);\n const unsubscribeEvents = globalWsClient.subscribe(topics, handleEvent);\n\n if (!getGlobalRecoveryCoordinator()) {\n setGlobalRecoveryCoordinator(\n createRecoveryCoordinator({\n wsClient: globalWsClient,\n sendCommand: createRecoveryDispatchCommand((op, args, options) =>\n globalWsClient!.sendCommand(op, args, options)\n ),\n applyReplay: async () => {},\n applySnapshot: async () => {},\n })\n );\n }\n\n if (status === \"disconnected\" || status === \"reconnecting\") {\n globalWsClient.recoverConnection(\"manual_retry\");\n }\n\n syncWorkspaceActivity();\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n window.addEventListener(\"focus\", handleWindowFocus);\n window.addEventListener(\"pageshow\", handlePageShow);\n window.addEventListener(\"online\", handleOnline);\n\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n window.removeEventListener(\"focus\", handleWindowFocus);\n window.removeEventListener(\"pageshow\", handlePageShow);\n window.removeEventListener(\"online\", handleOnline);\n unsubscribeStatus();\n unsubscribeEvents();\n refreshTimersRef.current.forEach((timer) => clearTimeout(timer));\n refreshTimersRef.current.clear();\n refreshHintsRef.current.clear();\n wsClientRef.current = null;\n // Deferred disconnect: wait 50ms to see if StrictMode remounts\n if (globalWsClient) {\n pendingDisconnectTimer = setTimeout(() => {\n if (globalWsClient) {\n globalWsClient.disconnect(\"app_unmount\");\n globalWsClient = null;\n }\n resetGlobalRecoveryCoordinator();\n pendingDisconnectTimer = null;\n }, 50);\n }\n };\n }\n\n // Create new WebSocket client singleton\n const client = new WsClient(resolveWsUrl());\n globalWsClient = client;\n setGlobalRecoveryCoordinator(\n createRecoveryCoordinator({\n wsClient: client,\n sendCommand: createRecoveryDispatchCommand((op, args, options) =>\n client.sendCommand(op, args, options)\n ),\n applyReplay: async () => {},\n applySnapshot: async () => {},\n })\n );\n wsClientRef.current = client;\n setWsClient(client);\n\n // Subscribe to connection status changes\n const unsubscribeStatus = client.onStatus(handleStatusChange);\n\n // Subscribe to events\n const unsubscribeEvents = client.subscribe(topics, handleEvent);\n\n // Connect to server\n client.connect().catch((err) => {\n console.error(\"Failed to connect WebSocket:\", err);\n setConnectionError(err.message || \"Connection failed\");\n });\n\n syncWorkspaceActivity();\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n window.addEventListener(\"focus\", handleWindowFocus);\n window.addEventListener(\"pageshow\", handlePageShow);\n window.addEventListener(\"online\", handleOnline);\n\n // Cleanup on unmount\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n window.removeEventListener(\"focus\", handleWindowFocus);\n window.removeEventListener(\"pageshow\", handlePageShow);\n window.removeEventListener(\"online\", handleOnline);\n unsubscribeStatus();\n unsubscribeEvents();\n refreshTimersRef.current.forEach((timer) => clearTimeout(timer));\n refreshTimersRef.current.clear();\n refreshHintsRef.current.clear();\n wsClientRef.current = null;\n // Deferred disconnect: wait 50ms to see if StrictMode remounts\n pendingDisconnectTimer = setTimeout(() => {\n if (globalWsClient) {\n globalWsClient.disconnect(\"app_unmount\");\n globalWsClient = null;\n }\n resetGlobalRecoveryCoordinator();\n pendingDisconnectTimer = null;\n }, 50);\n };\n }, [\n setWsClient,\n setConnectionStatus,\n setConnectionError,\n setServerInfo,\n setAuthEnabled,\n setReconnectCount,\n setLastReconnect,\n setIsWriter,\n setWorkspaces,\n setSessions,\n setSupervisors,\n store,\n authEnabled,\n authenticated,\n ]);\n\n useEffect(() => {\n if (authEnabled === null) {\n return;\n }\n\n if (authEnabled === true && !authenticated) {\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n return;\n }\n\n if (connectionStatus !== \"connected\") {\n return;\n }\n\n if (activationStatus !== \"active\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n if (workspaceActivityRef.current.mode !== \"inactive\") {\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n void client.sendCommand(\"workspace.deactivate\", {}).catch(() => {});\n }\n return;\n }\n\n if (!activeWorkspaceId) {\n if (workspaceActivityRef.current.mode !== \"inactive\") {\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n workspaceActivityRef.current = {\n mode: \"inactive\",\n workspaceId: null,\n };\n void client.sendCommand(\"workspace.deactivate\", {}).catch(() => {});\n }\n return;\n }\n\n if (\n workspaceActivityRef.current.mode === \"active\" &&\n workspaceActivityRef.current.workspaceId === activeWorkspaceId\n ) {\n return;\n }\n\n const client = wsClientRef.current;\n if (!client) {\n return;\n }\n\n workspaceActivityRef.current = {\n mode: \"active\",\n workspaceId: activeWorkspaceId,\n };\n void client\n .sendCommand(\"workspace.activate\", { workspaceId: activeWorkspaceId })\n .catch(() => {});\n }, [activeWorkspaceId, activationStatus, authEnabled, authenticated, connectionStatus]);\n\n return <>{children}</>;\n}\n\nfunction storeServerMetadata(\n payload: unknown,\n store: Store\n): payload is {\n version: string;\n serverInstanceId: string;\n authEnabled?: boolean;\n isWriter?: boolean;\n} {\n const data = payload as {\n version?: unknown;\n serverInstanceId?: unknown;\n authEnabled?: unknown;\n isWriter?: unknown;\n };\n\n if (typeof data.version !== \"string\" || typeof data.serverInstanceId !== \"string\") {\n return false;\n }\n\n store.set(serverInfoAtom, {\n version: data.version,\n serverInstanceId: data.serverInstanceId,\n authEnabled: typeof data.authEnabled === \"boolean\" ? data.authEnabled : undefined,\n });\n if (typeof data.isWriter === \"boolean\") {\n store.set(isWriterAtom, data.isWriter);\n }\n\n return true;\n}\n\n/**\n * Route incoming WebSocket events to appropriate Jotai atoms\n */\nexport function routeEventToAtom(topic: string, payload: unknown, store: Store): void {\n // Parse topic to determine event type\n // Topic format: workspace.{id}.session.{sessionId}.state\n // or: connection.ready\n\n if (topic === \"connection.ready\") {\n storeServerMetadata(payload, store);\n store.set(connectionErrorAtom, null);\n return;\n }\n\n if (topic === \"connection.status\") {\n // Connection-level status event\n const data = payload as {\n status: string;\n message?: string;\n authEnabled?: boolean;\n version?: string;\n serverInstanceId?: string;\n isWriter?: boolean;\n };\n if (data.status === \"connected\") {\n storeServerMetadata(payload, store);\n }\n if (data.status === \"connected\" && data.authEnabled === false) {\n store.set(authenticatedAtom, true);\n }\n if (data.status === \"error\" && data.message) {\n store.set(connectionErrorAtom, data.message);\n }\n return;\n }\n\n if (topic === \"update.state.changed\") {\n store.set(updateStateAtom, payload as UpdateStateView);\n return;\n }\n\n // Workspace-level events: workspace.{id}.{subtopic}\n const workspaceMatch = topic.match(/^workspace\\.([^.]+)\\.(.+)$/);\n if (workspaceMatch) {\n const workspaceId = workspaceMatch[1]!;\n const subtopic = workspaceMatch[2]!;\n\n // workspace.{id}.meta - workspace metadata update\n if (subtopic === \"meta\") {\n const patch = payload as Partial<Workspace>;\n const existing = store.get(workspacesAtom)[workspaceId];\n const shouldAcceptWorkspace = Boolean(existing || patch.path);\n\n if (!shouldAcceptWorkspace) {\n return;\n }\n\n store.set(workspacesAtom, (prev: Record<string, Workspace>) => ({\n ...prev,\n [workspaceId]: {\n ...prev[workspaceId],\n ...patch,\n id: workspaceId,\n } as Workspace,\n }));\n const paneLayout = patch.uiState?.paneLayout;\n if (paneLayout) {\n store.set(paneLayoutAtomFamily(workspaceId), normalizePaneLayout(paneLayout));\n }\n store.set(workspaceOrderAtom, (prev: string[]) => {\n if (prev.includes(workspaceId)) {\n return prev;\n }\n return [...prev, workspaceId];\n });\n store.set(workspacesLoadStateAtom, \"ready\");\n store.set(workspacesLoadErrorAtom, null);\n return;\n }\n\n // workspace.{id}.fs.dirty - filesystem dirty state\n if (subtopic === \"fs.dirty\") {\n const data = (payload ?? {}) as { reason?: string };\n if (shouldMarkTreeStaleForFsReason(data.reason)) {\n const atom = fileTreeStaleAtomFamily(workspaceId);\n store.set(atom, true);\n }\n return;\n }\n\n // workspace.{id}.git.state - git state changed notification\n if (subtopic === \"git.state\") {\n return;\n }\n\n // workspace.{id}.session.{sessionId}.{type}\n const sessionMatch = subtopic.match(/^session\\.([^.]+)\\.(.+)$/);\n if (sessionMatch) {\n const sessionId = sessionMatch[1]!;\n const sessionSubtopic = sessionMatch[2]!;\n\n if (sessionSubtopic === \"lifecycle\") {\n const data = payload as { event?: string };\n if (data.event === \"removed\") {\n const removedSession = store.get(sessionsAtom)[sessionId];\n if (removedSession?.terminalId) {\n store.set(terminalMetaAtomFamily(removedSession.terminalId), null);\n }\n store.set(sessionsAtom, (prev: Record<string, Session>) => {\n if (!(sessionId in prev)) {\n return prev;\n }\n const next = { ...prev };\n delete next[sessionId];\n return next;\n });\n }\n return;\n }\n\n // workspace.{id}.session.{sessionId}.state\n if (sessionSubtopic === \"state\") {\n const session = payload as Session;\n store.set(sessionsAtom, (prev: Record<string, Session>) => ({\n ...prev,\n [session.id]: session,\n }));\n return;\n }\n\n // workspace.{id}.session.{sessionId}.progress\n if (sessionSubtopic === \"progress\") {\n // Progress updates can be handled separately if needed\n // For now, we'll just log them\n console.log(`Session ${sessionId} progress:`, payload);\n return;\n }\n\n // workspace.{id}.session.{sessionId}.supervisor.state\n if (sessionSubtopic === \"supervisor.state\") {\n const data = payload as { supervisor?: Supervisor; supervisorId?: string; event: string };\n if (data.event === \"deleted\" && data.supervisorId) {\n store.set(supervisorsAtom, (prev: Map<string, Supervisor>) => {\n const next = new Map(prev);\n // Find and remove by supervisor ID\n for (const [sessId, sup] of next.entries()) {\n if (sup.id === data.supervisorId) {\n next.delete(sessId);\n break;\n }\n }\n return next;\n });\n } else if (data.supervisor) {\n const supervisor = data.supervisor;\n store.set(supervisorsAtom, (prev: Map<string, Supervisor>) => {\n const next = new Map(prev);\n next.set(supervisor.sessionId, supervisor);\n return next;\n });\n }\n return;\n }\n }\n\n // workspace.{id}.terminal.{terminalId}.{type}\n const terminalMatch = subtopic.match(/^terminal\\.([^.]+)\\.(.+)$/);\n if (terminalMatch) {\n const terminalId = terminalMatch[1]!;\n const terminalSubtopic = terminalMatch[2]!;\n\n // workspace.{id}.terminal.{terminalId}.created\n if (terminalSubtopic === \"created\") {\n const data = payload as { id: string; kind: string; title?: string; cwd?: string };\n const atom = terminalMetaAtomFamily(terminalId);\n store.set(atom, {\n id: data.id,\n workspaceId,\n kind: data.kind as \"agent\" | \"shell\",\n alive: true,\n title: data.title,\n });\n return;\n }\n\n // workspace.{id}.terminal.{terminalId}.output\n // Terminal panels consume output directly via xterm.js — no router-level\n // handling needed.\n if (terminalSubtopic === \"output\") {\n return;\n }\n\n // workspace.{id}.terminal.{terminalId}.exit\n if (terminalSubtopic === \"exit\") {\n const data = payload as { code: number };\n const atom = terminalMetaAtomFamily(terminalId);\n const current = store.get(atom);\n if (current) {\n store.set(atom, {\n ...current,\n exitCode: data.code,\n alive: false,\n });\n }\n return;\n }\n }\n }\n\n // Unknown topic - log for debugging\n console.log(`Unhandled event topic: ${topic}`, payload);\n}\n\nfunction normalizePaneLayout(layout: Workspace[\"uiState\"][\"paneLayout\"]): PaneNode {\n return {\n id: layout?.id ?? \"root\",\n type: layout?.type ?? \"leaf\",\n sessionId: layout?.sessionId,\n direction: layout?.direction,\n children: layout?.children?.map((child) => normalizePaneLayout(child)),\n };\n}\n","/**\n * Application Entry Point\n */\n\nimport \"@vitejs/plugin-react/preamble\";\nimport { Provider } from \"jotai\";\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport App from \"./app\";\nimport { AppProviders } from \"./app/providers\";\n\nimport \"@xterm/xterm/css/xterm.css\";\n\n// Import fonts\nimport \"./styles/fonts.css\";\n\n// Import styles\nimport \"./styles/tokens.css\";\nimport \"./styles/base.css\";\nimport \"./styles/components.css\";\n\n// Mount application\nconst root = ReactDOM.createRoot(document.getElementById(\"root\") as HTMLElement);\n\nroot.render(\n <Provider>\n <AppProviders>\n <App />\n </AppProviders>\n </Provider>\n);\n"],"mappings":"moBAaA,SAAA,IAAA,CAGE,OAAA,GAAA,GAAA,UAAA,EAAA,EAAA,KAAA,GAAA,EAAA,CAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,CAGF,SAAA,GAAA,CACE,OAAA,EAAA,EAAA,KAAA,EAAA,CAAA,UAAA,EAAA,EAAA,KAAA,GAAA,EAAA,CAAA,CAAA,CAAA,CCJF,IAAM,EAAuB,IAE7B,SAAgB,IAAgB,CAC9B,IAAM,EAAW,EAAa,GAAa,CACrC,EAAmB,EAAa,GAAqB,CACrD,EAAmB,EAAa,EAAqB,CACrD,CAAC,EAAQ,GAAa,EAAQ,EAAqB,CACnD,CAAC,EAAY,GAAiB,EAAQ,GAAyB,CAC/D,EAAY,EAAW,GAAqB,CAC5C,GAAA,EAAA,EAAA,QAAmD,KAAK,CACxD,GAAA,EAAA,EAAA,QAAkE,KAAK,CAEvE,GAAA,EAAA,EAAA,aAAoB,SAA8B,CACtD,GAAI,CAAC,EACH,MAAO,GAGT,GAAI,IAAqB,YACvB,GAAI,CACF,MAAM,EAAS,SAAS,MAClB,CAGN,OAFA,EAAU,KAAK,CACf,EAAW,GAAa,IAAY,QAAU,EAAU,OAAQ,CACzD,GAIX,GAAI,EAAiB,QACnB,OAAO,EAAiB,QAG1B,EAAU,WAAW,CAErB,IAAM,EAAU,EACb,YAAoC,mBAAoB,CACvD,mBACD,CAAC,CACD,KAAM,IACL,EAAc,EAAO,WAAW,CAChC,EAAU,KAAK,CACf,EAAU,SAAS,CACZ,IACP,CACD,WACC,EAAU,KAAK,CACf,EAAW,GAAa,IAAY,QAAU,EAAU,OAAQ,CACzD,IACP,CACD,YAAc,CACb,EAAiB,QAAU,MAC3B,CAGJ,MADA,GAAiB,QAAU,EACpB,GACN,CAAC,EAAkB,EAAkB,EAAe,EAAW,EAAW,EAAS,CAAC,CA+CvF,OA7CA,EAAA,EAAA,eAAgB,CACd,GAAI,EAAmB,UAAY,OACjC,aAAa,EAAmB,QAAQ,CACxC,EAAmB,QAAU,MAG3B,GAAC,GAAY,IAAqB,aAAe,IAAW,QAWhE,MAPA,GAAmB,QAAU,eAAiB,CAC5C,EAAmB,QAAU,KACxB,EAAiB,SACf,GAAO,EAEb,EAAqB,KAEX,CACP,EAAmB,UAAY,OACjC,aAAa,EAAmB,QAAQ,CACxC,EAAmB,QAAU,QAGhC,CAAC,EAAO,EAAkB,EAAQ,EAAS,CAAC,EAE/C,EAAA,EAAA,mBACe,CACP,EAAmB,UAAY,OACjC,aAAa,EAAmB,QAAQ,CACxC,EAAmB,QAAU,MAG3B,GAAC,GAAY,IAAe,OAI3B,EACF,YAAY,qBAAsB,CACjC,mBACA,aACD,CAAC,CACD,UAAY,GAAG,EAEnB,CAAC,EAAkB,EAAY,EAAS,CAAC,CAErC,CACL,SACA,aACA,QACD,CEpCH,IAAI,EAAkC,KAClC,EAA+D,KAmB7D,GAA6C,CACjD,WAAY,GACZ,gBAAiB,GACjB,iBAAkB,GAClB,cAAe,GACf,qBAAsB,GACvB,CACK,GAAkC,IAClC,EAAuB,aACvB,GAA2B,WAEjC,SAAS,EAA+B,EAA0B,CAChE,OAAO,IAAW,YAGpB,SAAS,IAAqC,CAC5C,IAAM,EAAgB,aAAa,QAAQ,EAAqB,CAChE,GAAI,IAAkB,KACpB,GAAI,CACF,OAAO,KAAK,MAAM,EAAc,MAC1B,CACN,OAIJ,IAAM,EAAc,aAAa,QAAQ,GAAyB,CAClE,GAAI,IAAgB,KAClB,GAAI,CACF,OAAO,KAAK,MAAM,EAAY,MACxB,CACN,QAON,SAAS,GAAmB,EAA0B,CACpD,IAAM,EAAgB,GAAa,GAAqB,EAAQ,CAAC,CAEjE,OADA,SAAS,gBAAgB,aAAa,aAAc,EAAc,kBAAkB,CAC7E,EAAc,GAYvB,SAAS,GAA+B,EAAiB,EAAgB,CACvE,QAAQ,MAAM,yBAAyB,EAAQ,UAAW,EAAM,CAGlE,SAAS,GACP,EACA,EACsB,CACtB,MAAO,CACL,WAAY,EAAQ,YAAc,EAAQ,EAAK,WAC/C,gBAAiB,EAAQ,iBAAmB,EAAQ,EAAK,gBACzD,iBAAkB,EAAQ,kBAAoB,EAAQ,EAAK,iBAC3D,cAAe,EAAQ,eAAiB,EAAQ,EAAK,cACrD,qBAAsB,EAAQ,sBAAwB,EAAQ,EAAK,qBACpE,CAGH,SAAS,GAA0B,EAAoB,CACrD,IAAM,EAAe,EAAM,IAAI,EAAmB,CAC5C,EAAa,EAAM,IAAI,EAAe,CACtC,EAAc,OAAO,OAAO,EAAM,IAAI,EAAa,CAAC,CACvD,IAAK,GAAY,EAAQ,WAAW,CACpC,OAAQ,GAAqC,EAAQ,EAAY,CAEpE,EAAM,IAAI,EAAgB,EAAE,CAAC,CAC7B,EAAM,IAAI,EAAoB,EAAE,CAAC,CACjC,EAAM,IAAI,EAAyB,OAAO,CAC1C,EAAM,IAAI,EAAyB,KAAK,CACxC,EAAM,IAAI,EAAc,EAAE,CAAC,CAC3B,EAAM,IAAI,GAAuB,KAAK,CACtC,EAAM,IAAI,EAAiB,IAAI,IAAM,CAErC,IAAK,IAAM,KAAe,EAAc,CACtC,IAAM,EAAY,EAAW,GACzB,GACF,EAAoB,iBAAiB,EAAU,KAAK,CAEtD,EAAM,IAAI,EAAmB,EAAY,CAAE,KAAK,CAChD,EAAM,IAAI,EAAqB,EAAY,CAAE,IAAI,IAAM,CACvD,EAAM,IAAI,GAAuB,EAAY,CAAE,KAAK,CACpD,EAAM,IAAI,GAAmB,EAAY,CAAE,KAAK,CAChD,EAAM,IAAI,EAAwB,EAAY,CAAE,CAC9C,QAAS,GACT,SAAU,EAAE,CACZ,QAAS,GACV,CAAC,CACF,EAAM,IAAI,EAAuB,EAAY,CAAE,CAC7C,MAAO,EAAE,CACT,QAAS,GACV,CAAC,CACF,EAAM,IAAI,EAAwB,EAAY,CAAE,GAAM,CACtD,EAAM,IAAI,GAA6B,EAAY,CAAE,EAAE,CAGzD,IAAK,IAAM,KAAc,EACvB,EAAM,IAAI,EAAuB,EAAW,CAAE,KAAK,CAIvD,SAAS,GACP,EACA,EAIO,CACP,IAAM,EAAQ,EAAM,MAAM,+CAA+C,CACzE,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,EAAc,EAAM,GAG1B,GAFiB,EAAM,KAEN,WAAY,CAC3B,IAAM,EAAQ,GAAW,EAAE,CAC3B,MAAO,CACL,cACA,KAAM,CACJ,WAAY,GACZ,gBAAiB,EAAK,SAAW,eACjC,iBAAkB,EAAK,SAAW,eAClC,cAAe,EAA+B,EAAK,OAAO,CAC1D,qBAAsB,EAAK,SAAW,aAAe,EAAK,SAAW,eACtE,CACF,CAGH,IAAM,EAAQ,GAAW,EAAE,CAM3B,MAAO,CACL,cACA,KAAM,CACJ,WAAY,GACZ,gBAAiB,EAAQ,EAAK,cAC9B,iBAAkB,EAAQ,EAAK,gBAC/B,cAAe,EAAQ,EAAK,YAC5B,qBAAsB,EAAQ,EAAK,YACpC,CACF,CAOH,SAAgB,EAAa,CAAE,YAA+B,CAClD,IAAgB,CAC1B,GAAM,EAAG,GAAe,EAAQ,GAAa,CACvC,CAAC,EAAO,GAAY,EAAQ,EAAU,CACtC,EAAc,EAAa,EAAgB,CAC3C,EAAgB,EAAa,EAAkB,CAC/C,EAAmB,EAAa,GAAqB,CACrD,EAAmB,EAAa,EAAqB,CACrD,EAAoB,EAAa,GAAsB,CACvD,EAAsB,EAAW,GAAqB,CACtD,EAAqB,EAAW,EAAoB,CACpD,GAAgB,EAAW,EAAe,CAC1C,EAAiB,EAAW,EAAgB,CAC5C,EAAoB,EAAW,GAA0B,CACzD,EAAmB,EAAW,GAAyB,CACvD,EAAc,EAAW,EAAa,CAGtC,GAAgB,EAAW,EAAe,CAC1C,EAAc,EAAW,EAAa,CAEtC,EAAiB,EAAW,EAAgB,CAC5C,GAAyB,EAAW,EAAwB,CAC5D,GAAiB,EAAW,EAAgB,CAG5C,EAAQ,IAAU,CAClB,EAAW,EAAa,EAAoB,CAC5C,CAAE,UAAU,IAAe,CAEjC,IAAyB,CAGzB,IAAM,GAAA,EAAA,EAAA,QAAsC,KAAK,CAC3C,GAAA,EAAA,EAAA,QAAsC,EAAS,CAC/C,GAAA,EAAA,EAAA,QAAsE,IAAI,IAAM,CAChF,GAAA,EAAA,EAAA,QAA4D,IAAI,IAAM,CACtE,IAAA,EAAA,EAAA,QAA6C,EAAkB,CAC/D,GAAA,EAAA,EAAA,QAAoC,GAAM,CAC1C,GAAA,EAAA,EAAA,QAAoD,KAAK,CACzD,GAAA,EAAA,EAAA,QAAsD,CAC1D,KAAM,WACN,YAAa,KACd,CAAC,CACI,IAAA,EAAA,EAAA,QAAmE,CACvE,MAAO,EACR,CAAC,CACI,IAAA,EAAA,EAAA,QAAiD,GAAM,EAG7D,EAAA,EAAA,eAAgB,CACd,EAAY,QAAU,GACrB,CAAC,EAAS,CAAC,CAEd,IAAM,OAAqC,CAazC,GAZI,CAAC,EAA2B,SAI5B,IAAqB,aAIrB,SAAS,kBAAoB,WAI7B,IAAqB,SACvB,OAGF,IAAM,EAAc,EACf,IAIL,EAA2B,QAAU,GACrC,EAAY,QAAmB,aAAc,CAAE,cAAa,CAAC,CAAC,KAAM,GAAW,CACzE,EAAO,IAAM,EAAO,MACtB,EAAM,IAAI,GAAmB,EAAY,CAAE,EAAO,KAAK,EAEzD,CACF,EACG,QAAoD,eAAgB,CAAE,cAAa,CAAC,CACpF,KAAM,GAAW,CACZ,EAAO,IAAM,EAAO,MACtB,EAAM,IAAI,EAAwB,EAAY,CAAE,CAC9C,QAAS,EAAO,KAAK,QACrB,SAAU,EAAO,KAAK,SACtB,QAAS,GACV,CAAC,EAEJ,CACJ,EACG,QAAuC,gBAAiB,CAAE,cAAa,CAAC,CACxE,KAAM,GAAW,CACZ,EAAO,IAAM,EAAO,MAAQ,MAAM,QAAQ,EAAO,KAAK,UAAU,EAClE,EAAM,IAAI,EAAuB,EAAY,CAAE,CAC7C,MAAO,EAAO,KAAK,UACnB,QAAS,GACT,aAAc,KAAK,KAAK,CACzB,CAAC,EAEJ,GA2uBN,OAxuBA,EAAA,EAAA,eAAgB,CACd,IAA8B,EAC7B,CAAC,EAAkB,EAAmB,EAAiB,CAAC,EAE3D,EAAA,EAAA,eAAgB,CACd,GAAI,IAAqB,YACvB,OAGF,IAAI,EAAY,GACZ,EAAyC,EAAM,IAAI,EAAwB,CAC3E,EAAmC,GACnC,EAAsC,GACtC,EAAqC,GACnC,EAAiC,EAAM,IAAI,MAA+B,CAC9E,IAAM,EAA0B,EAAM,IAAI,EAAwB,CAEhE,EAAwB,eAAiB,EAAuC,eAEhF,EAAmC,IAGnC,EAAwB,kBACxB,EAAuC,kBAEvC,EAAsC,IAGtC,EAAwB,iBACxB,EAAuC,iBAEvC,EAAqC,IAEvC,EAAyC,GACzC,CAkCF,OAFK,SA9B0C,CAC7C,IAAM,EAAS,MAAM,EAAkC,eAAgB,EAAE,CAAC,CAC1E,GAAI,GAAa,CAAC,EAAO,IAAM,CAAC,EAAO,KACrC,OAGF,IAAM,EAA6B,EAAM,IAAI,EAAwB,CAC/D,EAAuC,EACzC,EAA2B,gBAC3B,EAA+B,EAAO,KAAM,UAAU,CACpD,EAAsC,EACxC,EAA2B,eAC3B,EAA+B,EAAO,KAAM,SAAS,CACnD,EAAoB,GAAiC,EAAO,KAAK,CACjE,EAA6B,EAAmC,EAAO,KAAM,UAAU,CACvF,EAA4B,EAAmC,EAAO,KAAM,SAAS,CAY3F,GAAuB,CAVrB,aAAc,EACV,EAA2B,aAC3B,GAAmC,EAAO,KAAK,CACnD,gBAAiB,EACjB,eAAgB,EAChB,SACE,GAA8B,GAA6B,EACvD,EAA+B,EAAO,KAAM,UAAU,CACtD,EAA2B,SAEZ,CAAwB,IAGhB,KAEpB,CACX,EAAY,GACZ,GAAgC,GAEjC,CAAC,EAAkB,EAAU,GAAwB,EAAM,CAAC,EAE/D,EAAA,EAAA,eAAgB,CACd,GAAI,IAAqB,YACvB,OAGF,IAAI,EAAY,GAYhB,OAFK,SARkC,CACrC,IAAM,EAAS,MAAM,EAA0B,mBAAoB,EAAE,CAAC,CAClE,GAAa,CAAC,EAAO,IAAM,CAAC,EAAO,MAGvC,GAAe,EAAO,KAAK,IAGJ,KAEZ,CACX,EAAY,KAEb,CAAC,EAAkB,EAAU,GAAe,CAAC,EAEhD,EAAA,EAAA,eAAgB,CACd,GAAqB,QAAU,GAC9B,CAAC,EAAkB,CAAC,EAEvB,EAAA,EAAA,eAAgB,CACV,IAAqB,aAIrB,EAAM,IAAI,EAAqB,GAAK,SAInC,IAAO,EACX,CAAC,GAAO,EAAkB,EAAM,CAAC,EAGpC,EAAA,EAAA,eAAgB,CACd,GAAwC,QACtC,aAAa,QAAQ,EAAqB,GAAK,KACjD,IAAM,EAAkB,GAAmB,IAA2B,CAAC,CACvE,EAAS,EAAgB,CACzB,aAAa,QAAQ,EAAsB,KAAK,UAAU,EAAgB,CAAC,EAC1E,CAAC,EAAS,CAAC,EAEd,EAAA,EAAA,eAAgB,CACd,IAAM,EAAgB,GAAa,EAAM,CACzC,SAAS,gBAAgB,aAAa,aAAc,EAAc,kBAAkB,CACpF,aAAa,QAAQ,EAAsB,KAAK,UAAU,EAAc,GAAG,CAAC,EAC3E,CAAC,EAAM,CAAC,EAEX,EAAA,EAAA,eAAgB,CACd,GAAI,IAAqB,YACvB,OAGF,IAAI,EAAY,GAmChB,OAFK,SA/B4B,CAC/B,IAAM,EAA2C,CAC/C,GAAG,GAA8B,QAClC,CACK,EAAS,MAAM,EAAkC,eAAgB,EAAE,CAAC,CAK1E,GAJI,GAAa,CAAC,EAAO,IAAM,CAAC,EAAO,MAKrC,GAA8B,QAAQ,QACtC,EAAyC,MAEzC,OAGF,GAAI,GAAwC,QAAS,CACnD,GAAwC,QAAU,GAClD,OAGF,IAAM,EAAW,EAAO,KAOxB,EANwB,GACtB,EAAS,uBACP,EAAS,qBACT,IAA2B,CAGtB,CAAgB,IAGR,KAEN,CACX,EAAY,KAEb,CAAC,EAAkB,EAAU,EAAS,CAAC,EAE1C,EAAA,EAAA,eAAgB,CACd,IAAM,EAAmB,EAAM,IAAI,MAAiB,CAClD,GAA8B,QAAQ,OAAS,GAC/C,CAEF,UAAa,CACX,GAAkB,GAEnB,CAAC,EAAM,CAAC,EAEX,EAAA,EAAA,eAAgB,EAYT,SAX8B,CACjC,GAAI,CAEF,IAAM,EAAO,MAAM,MADI,MAAM,eAAe,EAChB,MAAM,CAClC,EAAe,EAAQ,EAAK,YAAa,CACzC,EAAM,IAAI,EAAmB,EAAQ,EAAK,eAAkB,EAAK,cAAgB,GAAM,MACjF,CACN,EAAM,IAAI,EAAmB,GAAM,KAIlB,EACpB,CAAC,EAAgB,EAAM,CAAC,EAE3B,EAAA,EAAA,eAAgB,CACd,GAAI,IAAgB,KAClB,OAGF,GAAI,IAAgB,IAAQ,CAAC,EAAe,CAC1C,AAEE,KADA,aAAa,EAAuB,CACX,MAG3B,AAEE,KADA,EAAe,WAAW,gBAAgB,CACzB,MAEnB,GAAgC,CAEhC,EAAY,QAAU,KACtB,EAAY,KAAK,CACjB,EAAoB,aAAa,CACjC,EAAmB,KAAK,CACxB,GAAc,KAAK,CACnB,EAAkB,EAAE,CACpB,EAAiB,KAAK,CACtB,EAAY,GAAM,CAClB,OAIF,IAAM,EAAsB,GAA6B,CACvD,EAAoB,EAAO,CAGvB,IAAW,iBACb,EAAmB,GAAU,EAAQ,EAAE,CACvC,EAAkB,GAAa,GAAY,KAAK,KAAK,CAAC,CACtD,EAAM,IAAI,EAAuB,GAAa,IAAY,QAAU,EAAU,OAAQ,CACtF,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACD,EAA2B,QAAU,KAInC,IAAW,gBAAkB,IAAW,cAC1C,EAAY,GAAM,CAClB,EAAM,IAAI,EAAuB,GAAa,IAAY,QAAU,EAAU,OAAQ,CACtF,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACG,IAAW,iBACb,EAA2B,QAAU,KAIrC,IAAW,cACb,EAAkB,EAAE,CACpB,EAAiB,KAAK,CACtB,EAAsB,GAAK,GAIzB,EAAmB,GAAwB,CAC/C,EACG,QAAmB,aAAc,CAAE,cAAa,CAAC,CACjD,KAAM,GAAW,CACZ,EAAO,IAAM,EAAO,MACtB,EAAM,IAAI,GAAmB,EAAY,CAAE,EAAO,KAAK,EAEzD,CACD,MAAO,GAAU,CAChB,QAAQ,MAAM,+CAAgD,EAAM,EACpE,EAGA,MAAgC,CAEpC,GADqB,EAAqB,QACzB,OAAS,WACxB,OAEF,IAAM,EAAS,EAAY,QACtB,IAGL,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACI,EAAO,YAAY,uBAAwB,EAAE,CAAC,CAAC,UAAY,GAAG,GAG/D,EAAyB,GAAwB,CACrD,GAAI,EAAM,IAAI,EAAqB,GAAK,SACtC,OAGF,IAAM,EAAe,EAAqB,QAC1C,GAAI,EAAa,OAAS,UAAY,EAAa,cAAgB,EACjE,OAEF,IAAM,EAAS,EAAY,QACtB,IAGL,EAAqB,QAAU,CAC7B,KAAM,SACN,cACD,CACI,EAAO,YAAY,qBAAsB,CAAE,cAAa,CAAC,CAAC,UAAY,GAAG,GAG1E,GAAyB,EAAQ,KAAU,CAC/C,GAAI,SAAS,kBAAoB,SAAU,CACzC,GAAyB,CACzB,OAGF,IAAM,EAAc,GAAqB,QACzC,GAAI,CAAC,EAAa,CAChB,GAAyB,CACzB,OAGE,IACF,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,EAGH,EAAsB,EAAY,EAG9B,MAAkC,CACtC,GAAI,EAAM,IAAI,EAAqB,GAAK,QACtC,OAIF,GADA,GAAuB,CACnB,SAAS,kBAAoB,UAAW,CAC1C,EAA4B,QAAU,KACtC,OAGF,IAAM,EAAM,KAAK,KAAK,CAChB,EAA2B,EAA4B,QAE3D,IAA6B,MAC7B,EAAM,EAA2B,KAKnC,EAA4B,QAAU,EACjC,GAA8B,EAC/B,aAAa,oBAAoB,CAClC,MAAO,GAAU,CAChB,GAA+B,oBAAqB,EAAM,EAC1D,GAGA,MAA+B,CACnC,GAAI,SAAS,kBAAoB,SAAU,CACzC,EAA4B,QAAU,KACtC,GAAuB,CACvB,OAGF,GAA2B,EAGvB,MAA0B,CAC9B,GAA2B,EAGvB,MAAuB,CAC3B,GAA2B,EAGvB,MAAqB,CACrB,EAAM,IAAI,EAAqB,GAAK,SAInC,GAA8B,EAC/B,aAAa,iBAAiB,CAC/B,MAAO,GAAU,CAChB,GAA+B,iBAAkB,EAAM,EACvD,EAGA,EAAsB,GAAwB,CAClD,EACG,QAAoD,eAAgB,CAAE,cAAa,CAAC,CACpF,KAAM,GAAW,CAChB,GAAI,EAAO,IAAM,EAAO,KAAM,CAC5B,EAAM,IAAI,EAAwB,EAAY,CAAE,CAC9C,QAAS,EAAO,KAAK,QACrB,SAAU,EAAO,KAAK,SACtB,QAAS,GACV,CAAC,CACF,OAGF,EAAM,IAAI,EAAwB,EAAY,CAAG,IAAU,CACzD,GAAG,EACH,QAAS,GACT,MAAO,EAAO,OAAO,SAAW,EAAK,MACtC,EAAE,EACH,CACD,MAAO,GAAU,CAChB,QAAQ,MAAM,mDAAoD,EAAM,EACxE,EAGA,EAAuB,GAAwB,CACnD,EAAM,IAAI,EAAuB,EAAY,CAAG,IAAU,CACxD,GAAG,EACH,QAAS,GACT,MAAO,IAAA,GACR,EAAE,CACH,EACG,QAAuC,gBAAiB,CAAE,cAAa,CAAC,CACxE,KAAM,GAAW,CAChB,GAAI,EAAO,IAAM,EAAO,MAAQ,MAAM,QAAQ,EAAO,KAAK,UAAU,CAAE,CACpE,EAAM,IAAI,EAAuB,EAAY,CAAE,CAC7C,MAAO,EAAO,KAAK,UACnB,QAAS,GACT,aAAc,KAAK,KAAK,CACzB,CAAC,CACF,OAGF,EAAM,IAAI,EAAuB,EAAY,CAAG,IAAU,CACxD,GAAG,EACH,QAAS,GACT,MAAO,EAAO,OAAO,SAAW,EAAK,MACtC,EAAE,EACH,CACD,MAAO,GAAU,CAChB,QAAQ,MAAM,qDAAsD,EAAM,CAC1E,EAAM,IAAI,EAAuB,EAAY,CAAG,IAAU,CACxD,GAAG,EACH,QAAS,GACT,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAC9D,EAAE,EACH,EAGA,IAAyB,EAAqB,IAAwC,CAC1F,IAAM,EAAW,GACf,EAAgB,QAAQ,IAAI,EAAY,EAAI,GAC5C,EACD,CAID,GAHA,EAAgB,QAAQ,IAAI,EAAa,EAAS,CAE5B,EAAiB,QAAQ,IAAI,EAC/C,CACF,OAGF,IAAM,EAAQ,eAAiB,CAC7B,EAAiB,QAAQ,OAAO,EAAY,CAC5C,IAAM,EAAa,EAAgB,QAAQ,IAAI,EAAY,EAAI,GAC/D,EAAgB,QAAQ,OAAO,EAAY,CAEvC,EAAW,eACb,EAAM,IAAI,EAAwB,EAAY,CAAE,GAAK,CAEnD,EAAW,sBACb,EAAM,IAAI,GAA6B,EAAY,CAAG,GAAS,EAAO,EAAE,CAEtE,EAAW,YACb,EAAgB,EAAY,CAE1B,EAAW,iBACb,EAAmB,EAAY,CAE7B,EAAW,kBACb,EAAoB,EAAY,EAEjC,GAAG,CAEN,EAAiB,QAAQ,IAAI,EAAa,EAAM,EAI5C,GAA8B,EAAe,EAAkB,IAAiB,CACpF,GAAI,IAAU,qBAAsB,CAClC,IAAM,EAAQ,GAAW,EAAE,CAK3B,EAAM,IAAI,EAAsB,QAAQ,CACxC,EAAM,IACJ,GACA,OAAO,EAAK,QAAW,UAAY,EAAK,OAAO,OAAS,EAAI,EAAK,OAAS,YAC3E,CACD,EAAM,IACJ,GACA,OAAO,EAAK,YAAe,SAAW,EAAK,WAAa,KACzD,CACD,GAA0B,EAAM,CAChC,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACD,EAA2B,QAAU,GACrC,EAAY,SAAS,WAAW,0BAA0B,CAC1D,OAGF,IAAM,EAAc,GAA0B,EAAO,EAAQ,CACzD,GACF,GAAsB,EAAY,YAAa,EAAY,KAAK,CAGlE,GAAI,CACF,GAAiB,EAAO,EAAS,EAAM,OAChC,EAAK,CACZ,QAAQ,MAAM,kCAAkC,EAAM,GAAI,EAAI,GAK5D,GAAS,CACb,eACA,eACA,WACA,cACD,CASD,GALA,AAEE,KADA,aAAa,EAAuB,CACX,MAGvB,EAAgB,CAClB,EAAY,QAAU,EACtB,EAAY,EAAe,CAC3B,IAAM,EAAS,EAAe,WAAW,CACzC,EAAoB,EAAO,CAG3B,IAAM,EAAoB,EAAe,SAAS,EAAmB,CAC/D,EAAoB,EAAe,UAAU,GAAQ,EAAY,CA0BvE,OAxBK,GAA8B,EACjC,GACE,GAA0B,CACxB,SAAU,EACV,YAAa,IAA+B,EAAI,EAAM,IACpD,EAAgB,YAAY,EAAI,EAAM,EAAQ,CAC/C,CACD,YAAa,SAAY,GACzB,cAAe,SAAY,GAC5B,CAAC,CACH,EAGC,IAAW,gBAAkB,IAAW,iBAC1C,EAAe,kBAAkB,eAAe,CAGlD,GAAuB,CAEvB,SAAS,iBAAiB,mBAAoB,EAAuB,CACrE,OAAO,iBAAiB,QAAS,EAAkB,CACnD,OAAO,iBAAiB,WAAY,EAAe,CACnD,OAAO,iBAAiB,SAAU,EAAa,KAElC,CACX,SAAS,oBAAoB,mBAAoB,EAAuB,CACxE,OAAO,oBAAoB,QAAS,EAAkB,CACtD,OAAO,oBAAoB,WAAY,EAAe,CACtD,OAAO,oBAAoB,SAAU,EAAa,CAClD,GAAmB,CACnB,GAAmB,CACnB,EAAiB,QAAQ,QAAS,GAAU,aAAa,EAAM,CAAC,CAChE,EAAiB,QAAQ,OAAO,CAChC,EAAgB,QAAQ,OAAO,CAC/B,EAAY,QAAU,KAElB,IACF,EAAyB,eAAiB,CACxC,AAEE,KADA,EAAe,WAAW,cAAc,CACvB,MAEnB,GAAgC,CAChC,EAAyB,MACxB,GAAG,GAMZ,IAAM,EAAS,IAAI,GAAS,IAAc,CAAC,CAC3C,EAAiB,EACjB,GACE,GAA0B,CACxB,SAAU,EACV,YAAa,IAA+B,EAAI,EAAM,IACpD,EAAO,YAAY,EAAI,EAAM,EAAQ,CACtC,CACD,YAAa,SAAY,GACzB,cAAe,SAAY,GAC5B,CAAC,CACH,CACD,EAAY,QAAU,EACtB,EAAY,EAAO,CAGnB,IAAM,GAAoB,EAAO,SAAS,EAAmB,CAGvD,GAAoB,EAAO,UAAU,GAAQ,EAAY,CAgB/D,OAbA,EAAO,SAAS,CAAC,MAAO,GAAQ,CAC9B,QAAQ,MAAM,+BAAgC,EAAI,CAClD,EAAmB,EAAI,SAAW,oBAAoB,EACtD,CAEF,GAAuB,CAEvB,SAAS,iBAAiB,mBAAoB,EAAuB,CACrE,OAAO,iBAAiB,QAAS,EAAkB,CACnD,OAAO,iBAAiB,WAAY,EAAe,CACnD,OAAO,iBAAiB,SAAU,EAAa,KAGlC,CACX,SAAS,oBAAoB,mBAAoB,EAAuB,CACxE,OAAO,oBAAoB,QAAS,EAAkB,CACtD,OAAO,oBAAoB,WAAY,EAAe,CACtD,OAAO,oBAAoB,SAAU,EAAa,CAClD,IAAmB,CACnB,IAAmB,CACnB,EAAiB,QAAQ,QAAS,GAAU,aAAa,EAAM,CAAC,CAChE,EAAiB,QAAQ,OAAO,CAChC,EAAgB,QAAQ,OAAO,CAC/B,EAAY,QAAU,KAEtB,EAAyB,eAAiB,CACxC,AAEE,KADA,EAAe,WAAW,cAAc,CACvB,MAEnB,GAAgC,CAChC,EAAyB,MACxB,GAAG,GAEP,CACD,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,EACD,CAAC,EAEF,EAAA,EAAA,eAAgB,CACd,GAAI,IAAgB,KAClB,OAGF,GAAI,IAAgB,IAAQ,CAAC,EAAe,CAC1C,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACD,OAOF,GAJI,IAAqB,aAIrB,IAAqB,SACvB,OAGF,GAAI,SAAS,kBAAoB,SAAU,CACzC,GAAI,EAAqB,QAAQ,OAAS,WAAY,CACpD,IAAM,EAAS,EAAY,QAC3B,GAAI,CAAC,EACH,OAEF,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACI,EAAO,YAAY,uBAAwB,EAAE,CAAC,CAAC,UAAY,GAAG,CAErE,OAGF,GAAI,CAAC,EAAmB,CACtB,GAAI,EAAqB,QAAQ,OAAS,WAAY,CACpD,IAAM,EAAS,EAAY,QAC3B,GAAI,CAAC,EACH,OAEF,EAAqB,QAAU,CAC7B,KAAM,WACN,YAAa,KACd,CACI,EAAO,YAAY,uBAAwB,EAAE,CAAC,CAAC,UAAY,GAAG,CAErE,OAGF,GACE,EAAqB,QAAQ,OAAS,UACtC,EAAqB,QAAQ,cAAgB,EAE7C,OAGF,IAAM,EAAS,EAAY,QACtB,IAIL,EAAqB,QAAU,CAC7B,KAAM,SACN,YAAa,EACd,CACI,EACF,YAAY,qBAAsB,CAAE,YAAa,EAAmB,CAAC,CACrE,UAAY,GAAG,GACjB,CAAC,EAAmB,EAAkB,EAAa,EAAe,EAAiB,CAAC,EAEhF,EAAA,EAAA,KAAA,EAAA,SAAA,CAAG,WAAY,CAAA,CAGxB,SAAS,EACP,EACA,EAMA,CACA,IAAM,EAAO,EAoBb,OAbI,OAAO,EAAK,SAAY,UAAY,OAAO,EAAK,kBAAqB,SAChE,IAGT,EAAM,IAAI,EAAgB,CACxB,QAAS,EAAK,QACd,iBAAkB,EAAK,iBACvB,YAAa,OAAO,EAAK,aAAgB,UAAY,EAAK,YAAc,IAAA,GACzE,CAAC,CACE,OAAO,EAAK,UAAa,WAC3B,EAAM,IAAI,EAAc,EAAK,SAAS,CAGjC,IAMT,SAAgB,GAAiB,EAAe,EAAkB,EAAoB,CAKpF,GAAI,IAAU,mBAAoB,CAChC,EAAoB,EAAS,EAAM,CACnC,EAAM,IAAI,EAAqB,KAAK,CACpC,OAGF,GAAI,IAAU,oBAAqB,CAEjC,IAAM,EAAO,EAQT,EAAK,SAAW,aAClB,EAAoB,EAAS,EAAM,CAEjC,EAAK,SAAW,aAAe,EAAK,cAAgB,IACtD,EAAM,IAAI,EAAmB,GAAK,CAEhC,EAAK,SAAW,SAAW,EAAK,SAClC,EAAM,IAAI,EAAqB,EAAK,QAAQ,CAE9C,OAGF,GAAI,IAAU,uBAAwB,CACpC,EAAM,IAAI,EAAiB,EAA2B,CACtD,OAIF,IAAM,EAAiB,EAAM,MAAM,6BAA6B,CAChE,GAAI,EAAgB,CAClB,IAAM,EAAc,EAAe,GAC7B,EAAW,EAAe,GAGhC,GAAI,IAAa,OAAQ,CACvB,IAAM,EAAQ,EAId,GAAI,EAHa,EAAM,IAAI,EAAe,CAAC,IACO,EAAM,MAGtD,OAGF,EAAM,IAAI,EAAiB,IAAqC,CAC9D,GAAG,GACF,GAAc,CACb,GAAG,EAAK,GACR,GAAG,EACH,GAAI,EACL,CACF,EAAE,CACH,IAAM,EAAa,EAAM,SAAS,WAC9B,GACF,EAAM,IAAI,EAAqB,EAAY,CAAE,EAAoB,EAAW,CAAC,CAE/E,EAAM,IAAI,EAAqB,GACzB,EAAK,SAAS,EAAY,CACrB,EAEF,CAAC,GAAG,EAAM,EAAY,CAC7B,CACF,EAAM,IAAI,EAAyB,QAAQ,CAC3C,EAAM,IAAI,EAAyB,KAAK,CACxC,OAIF,GAAI,IAAa,WAAY,CAE3B,GAAI,GADU,GAAW,EAAE,EACa,OAAO,CAAE,CAC/C,IAAM,EAAO,EAAwB,EAAY,CACjD,EAAM,IAAI,EAAM,GAAK,CAEvB,OAIF,GAAI,IAAa,YACf,OAIF,IAAM,EAAe,EAAS,MAAM,2BAA2B,CAC/D,GAAI,EAAc,CAChB,IAAM,EAAY,EAAa,GACzB,EAAkB,EAAa,GAErC,GAAI,IAAoB,YAAa,CAEnC,GAAI,EAAK,QAAU,UAAW,CAC5B,IAAM,EAAiB,EAAM,IAAI,EAAa,CAAC,GAC3C,GAAgB,YAClB,EAAM,IAAI,EAAuB,EAAe,WAAW,CAAE,KAAK,CAEpE,EAAM,IAAI,EAAe,GAAkC,CACzD,GAAI,EAAE,KAAa,GACjB,OAAO,EAET,IAAM,EAAO,CAAE,GAAG,EAAM,CAExB,OADA,OAAO,EAAK,GACL,GACP,CAEJ,OAIF,GAAI,IAAoB,QAAS,CAC/B,IAAM,EAAU,EAChB,EAAM,IAAI,EAAe,IAAmC,CAC1D,GAAG,GACF,EAAQ,IAAK,EACf,EAAE,CACH,OAIF,GAAI,IAAoB,WAAY,CAGlC,QAAQ,IAAI,WAAW,EAAU,YAAa,EAAQ,CACtD,OAIF,GAAI,IAAoB,mBAAoB,CAC1C,IAAM,EAAO,EACb,GAAI,EAAK,QAAU,WAAa,EAAK,aACnC,EAAM,IAAI,EAAkB,GAAkC,CAC5D,IAAM,EAAO,IAAI,IAAI,EAAK,CAE1B,IAAK,GAAM,CAAC,EAAQ,KAAQ,EAAK,SAAS,CACxC,GAAI,EAAI,KAAO,EAAK,aAAc,CAChC,EAAK,OAAO,EAAO,CACnB,MAGJ,OAAO,GACP,SACO,EAAK,WAAY,CAC1B,IAAM,EAAa,EAAK,WACxB,EAAM,IAAI,EAAkB,GAAkC,CAC5D,IAAM,EAAO,IAAI,IAAI,EAAK,CAE1B,OADA,EAAK,IAAI,EAAW,UAAW,EAAW,CACnC,GACP,CAEJ,QAKJ,IAAM,EAAgB,EAAS,MAAM,4BAA4B,CACjE,GAAI,EAAe,CACjB,IAAM,EAAa,EAAc,GAC3B,EAAmB,EAAc,GAGvC,GAAI,IAAqB,UAAW,CAClC,IAAM,EAAO,EACP,EAAO,EAAuB,EAAW,CAC/C,EAAM,IAAI,EAAM,CACd,GAAI,EAAK,GACT,cACA,KAAM,EAAK,KACX,MAAO,GACP,MAAO,EAAK,MACb,CAAC,CACF,OAMF,GAAI,IAAqB,SACvB,OAIF,GAAI,IAAqB,OAAQ,CAC/B,IAAM,EAAO,EACP,EAAO,EAAuB,EAAW,CACzC,EAAU,EAAM,IAAI,EAAK,CAC3B,GACF,EAAM,IAAI,EAAM,CACd,GAAG,EACH,SAAU,EAAK,KACf,MAAO,GACR,CAAC,CAEJ,SAMN,QAAQ,IAAI,0BAA0B,IAAS,EAAQ,CAGzD,SAAS,EAAoB,EAAsD,CACjF,MAAO,CACL,GAAI,GAAQ,IAAM,OAClB,KAAM,GAAQ,MAAQ,OACtB,UAAW,GAAQ,UACnB,UAAW,GAAQ,UACnB,SAAU,GAAQ,UAAU,IAAK,GAAU,EAAoB,EAAM,CAAC,CACvE,ICt0CmB,WAAW,SAAS,eAAe,OAAO,CAEhE,CAAK,QACH,EAAA,EAAA,KAAC,EAAD,CAAA,UACE,EAAA,EAAA,KAAC,EAAD,CAAA,UACE,EAAA,EAAA,KAAC,EAAD,EAAO,CAAA,CACM,CAAA,CACN,CAAA,CACZ"}
@@ -1,4 +1,4 @@
1
- import{r as e}from"./rolldown-runtime-CpWojdLp.js";import{$ as t,A as n,Bt as r,Ct as i,D as a,E as o,F as s,Ft as ee,G as c,H as l,It as te,J as ne,Jt as re,K as u,Lt as ie,M as ae,N as d,O as f,Pt as oe,Q as se,Qt as ce,Rt as le,S as ue,St as de,Tt as fe,U as pe,Vt as me,W as he,X as ge,Xt as _e,Y as ve,Yt as ye,Z as be,Zt as xe,_ as Se,_t as Ce,a as we,bt as Te,c as Ee,ct as De,d as Oe,dt as p,en as ke,et as Ae,f as m,ft as h,g as je,gt as Me,h as g,ht as _,i as v,in as Ne,j as Pe,jt as Fe,k as Ie,l as y,lt as Le,m as b,mt as x,n as Re,o as S,ot as ze,p as Be,pt as Ve,q as C,r as He,rn as Ue,rt as We,s as w,st as Ge,t as Ke,u as qe,ut as T,v as E,vt as Je,xt as Ye,y as D,yt as Xe,zt as O}from"./components-omWbMLvf.js";import"./xterm-BVlcrOZ1.js";var Ze=e(xe(),1),k=e(Ue(),1),A=Me();function Qe(e){return e.startsWith(`diff --git`)||e.startsWith(`index `)||e.startsWith(`--- `)||e.startsWith(`+++ `)||e.startsWith(`@@`)?`meta`:e.startsWith(`+`)?`added`:e.startsWith(`-`)?`removed`:`context`}var $e=({workspaceId:e,onClose:t,showCloseButton:n=!0})=>{let r=_(),{preview:i,closePreview:a}=je(e),o=t??a,s=(0,k.useMemo)(()=>i?.diff.split(`
1
+ import{r as e}from"./rolldown-runtime-CpWojdLp.js";import{$ as t,A as n,Bt as r,Ct as i,D as a,E as o,F as s,Ft as ee,G as c,H as l,It as te,J as ne,Jt as re,K as u,Lt as ie,M as ae,N as d,O as f,Pt as oe,Q as se,Qt as ce,Rt as le,S as ue,St as de,Tt as fe,U as pe,Vt as me,W as he,X as ge,Xt as _e,Y as ve,Yt as ye,Z as be,Zt as xe,_ as Se,_t as Ce,a as we,bt as Te,c as Ee,ct as De,d as Oe,dt as p,en as ke,et as Ae,f as m,ft as h,g as je,gt as Me,h as g,ht as _,i as v,in as Ne,j as Pe,jt as Fe,k as Ie,l as y,lt as Le,m as b,mt as x,n as Re,o as S,ot as ze,p as Be,pt as Ve,q as C,r as He,rn as Ue,rt as We,s as w,st as Ge,t as Ke,u as qe,ut as T,v as E,vt as Je,xt as Ye,y as D,yt as Xe,zt as O}from"./components-BZf_jLGv.js";import"./xterm-BVlcrOZ1.js";var Ze=e(xe(),1),k=e(Ue(),1),A=Me();function Qe(e){return e.startsWith(`diff --git`)||e.startsWith(`index `)||e.startsWith(`--- `)||e.startsWith(`+++ `)||e.startsWith(`@@`)?`meta`:e.startsWith(`+`)?`added`:e.startsWith(`-`)?`removed`:`context`}var $e=({workspaceId:e,onClose:t,showCloseButton:n=!0})=>{let r=_(),{preview:i,closePreview:a}=je(e),o=t??a,s=(0,k.useMemo)(()=>i?.diff.split(`
2
2
  `).map((e,t)=>({id:`${t}:${e}`,line:e,tone:Qe(e),lineNumber:t+1}))??[],[i]);return(0,A.jsx)(`div`,{className:`workspace-git-view`,children:(0,A.jsxs)(`div`,{className:`code-editor workspace-git-editor`,children:[(0,A.jsx)(Pe,{title:i?.title??i?.path??`Select a changed file to inspect`,actions:i&&n?(0,A.jsx)(`div`,{className:`code-mode-toggle`,children:(0,A.jsx)(De,{content:r(`action.close`),children:(0,A.jsx)(Ve,{"aria-label":r(`action.close`),className:`code-mode-btn`,icon:(0,A.jsx)(me,{size:12}),onClick:o,size:`sm`})})}):null}),(0,A.jsx)(`div`,{className:`code-editor-body`,children:i?(0,A.jsx)(`div`,{className:`code-lines git-diff-lines`,children:s.map(e=>(0,A.jsxs)(`div`,{className:`code-line git-diff-line git-diff-line-${e.tone}`,children:[(0,A.jsx)(`span`,{className:`code-line-num`,children:e.lineNumber}),(0,A.jsx)(`span`,{className:`git-diff-line-text`,children:e.line||` `})]},e.id))}):(0,A.jsx)(T,{className:`git-diff-empty`,description:(0,A.jsx)(`p`,{className:`git-diff-empty-body`,children:`Select a staged or modified file on the left to inspect its diff.`}),title:(0,A.jsx)(`p`,{className:`git-diff-empty-title`,children:r(`label.git`)})})})]})})};function j(){return[...r]}function et(){return r.filter(e=>e.endsWith(`-light`))}var tt=[{id:`welcome`,title:`Welcome`,category:`page`,source:`real-route`,description:`Welcome page on the real / route under the preview harness.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.welcome-card`}},{id:`settings-general`,title:`Settings / General`,category:`page`,source:`real-route`,description:`Settings page at /settings with deterministic settings.get data.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-page`,settingsSection:`general`}},{id:`settings-appearance`,title:`Settings / Appearance`,category:`page`,source:`real-route`,description:`Settings appearance section using route-backed production UI.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-page`,settingsSection:`appearance`}},{id:`settings-providers`,title:`Settings / Providers`,category:`page`,source:`real-route`,description:`Settings providers section with fixed provider args.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-page`,settingsSection:`providers`}},{id:`settings-shortcuts`,title:`Settings / Shortcuts`,category:`page`,source:`real-route`,description:`Settings shortcuts section with the keyboard shortcut list and category tabs.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-page`,settingsSection:`shortcuts`}},{id:`settings-mobile-root`,title:`Settings / Mobile Root`,category:`page`,source:`real-route`,description:`Mobile settings root list before drilling into any subsection.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-mobile-root`}},{id:`app-loading-shell`,title:`App Loading Shell`,category:`loading`,source:`real-route`,description:`Top-level shell shown while auth state is still unresolved before routes render.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.app-loading-shell`}},{id:`workspace-desktop`,title:`Workspace / Desktop`,category:`page`,source:`real-route`,description:`Desktop workspace shell with seeded workspace, git status, and file tree.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.workspace-page`}},{id:`workspace-mobile`,title:`Workspace / Mobile`,category:`page`,source:`real-route`,description:`Mobile workspace shell with seeded workspace and no active sessions.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`[data-testid='mobile-shell']`}},{id:`auth-preview`,title:`Auth Preview`,category:`page`,source:`real-route`,description:`Login/auth page component on the real /login route under preview harness.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.auth-card-shell`}},{id:`session-gate`,title:`Session Gate`,category:`error`,source:`real-route`,description:`Session gate shell shown when activation is displaced and the app requires re-entry.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.auth-card-shell`}},{id:`not-found`,title:`Not Found`,category:`page`,source:`real-route`,description:`Not found page for an unknown route path.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.welcome-card`}},{id:`workspace-load-error`,title:`Workspace / Load Error`,category:`error`,source:`real-route`,description:`Shared workspace route error shell when workspace list loading fails.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.workspace-resolving-card`}},{id:`workspace-launch-modal`,title:`Workspace Launch Modal`,category:`modal`,source:`showcase`,description:`Workspace open modal with fixed browse/open responses.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.launch-modal, .mobile-sheet--launch`}},{id:`command-palette`,title:`Command Palette`,category:`modal`,source:`showcase`,description:`Command palette forced open with a seeded active workspace.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.command-palette, .command-palette-sheet`}},{id:`branch-quick-pick`,title:`Branch Quick Pick`,category:`sheet`,source:`showcase`,description:`Branch picker opened via seeded branchQuickPick atom and fake git.branches data.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.mobile-select-sheet--command`}},{id:`toast-stack`,title:`Toast Stack`,category:`toast`,source:`showcase`,description:`Success and error toasts for visual review.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.toast-container`}},{id:`footer-update-rail-review`,title:`Footer Update Rail Review`,category:`page`,source:`showcase`,description:`Workspace footer review with a seeded update-available rail on desktop and mobile.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.footer-update-rail-review`}},{id:`footer-update-rail-confirm-review`,title:`Footer Update Rail Confirm Review`,category:`modal`,source:`showcase`,description:`Workspace footer review with the confirmation dialog opened after clicking Update Now.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.modal-overlay`}},{id:`workspace-icon-review`,title:`Workspace Icon Review`,category:`page`,source:`showcase`,description:`File tree, git states, terminal empty state, and mobile dock/supervisor icon surfaces for theme review.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.workspace-icon-review`}},{id:`toast-icon-review`,title:`Toast Icon Review`,category:`toast`,source:`showcase`,description:`Success, warning, error, and info toast icons rendered together for theme review.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.toast-container`}},{id:`supervisor-icon-review`,title:`Supervisor Icon Review`,category:`modal`,source:`showcase`,description:`Supervisor dialog header icon and destructive callout surface review.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.supervisor-dialog, .mobile-supervisor-sheet`}},{id:`mobile-workspace-drawer`,title:`Mobile Workspace Drawer`,category:`sheet`,source:`showcase`,description:`Opened mobile workspace drawer with two example workspaces.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.mobile-workspace-drawer`}},{id:`mobile-files-sheet`,title:`Mobile Files Sheet`,category:`sheet`,source:`showcase`,description:`Static mobile files sheet chrome for screenshot comparison.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.mobile-sheet--files`}},{id:`mobile-terminal-sheet`,title:`Mobile Terminal Sheet`,category:`sheet`,source:`showcase`,description:`Mobile terminal fullscreen sheet with compact tool chrome and status bar for screenshot comparison.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.mobile-sheet--terminal`}},{id:`mobile-supervisor-sheet`,title:`Mobile Supervisor Sheet`,category:`sheet`,source:`showcase`,description:`Mobile supervisor sheet with a seeded supervisor state.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.mobile-supervisor-sheet`}},{id:`supervisor-dialog`,title:`Supervisor Dialog`,category:`modal`,source:`showcase`,description:`Desktop supervisor objective dialog opened by atom seed.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.supervisor-dialog`}},{id:`readme-desktop-hero`,title:`README / Desktop Hero`,category:`page`,source:`showcase`,description:`README-focused desktop workspace scene with a live agent session, supervisor summary, and shell verification terminal.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.workspace-page`}},{id:`readme-desktop-review`,title:`README / Desktop Review`,category:`page`,source:`showcase`,description:`README-focused desktop scene showing git review workflow with changed files, history, and an open diff.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.workspace-page`}},{id:`readme-mobile-progress`,title:`README / Mobile Progress`,category:`page`,source:`showcase`,description:`README-focused mobile scene showing an active session with supervisor continuity and branch status.`,devices:[`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`[data-testid='mobile-shell']`}},{id:`workspace-topbar-review`,title:`Workspace / Topbar Review`,category:`page`,source:`showcase`,description:`Desktop topbar chrome review with seeded workspaces and quick actions.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--topbar`}},{id:`workspace-sidebar-files-review`,title:`Workspace / Sidebar Files Review`,category:`page`,source:`showcase`,description:`Desktop file tree sidebar review with seeded search and file hierarchy.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--sidebar`}},{id:`workspace-sidebar-git-review`,title:`Workspace / Sidebar Git Review`,category:`page`,source:`showcase`,description:`Desktop git sidebar review with seeded status, history, and worktrees.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--sidebar`}},{id:`workspace-editor-review`,title:`Workspace / Editor Review`,category:`page`,source:`showcase`,description:`Desktop editor review with code chrome, dirty state, and static content density.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--editor`}},{id:`workspace-diff-review`,title:`Workspace / Diff Review`,category:`page`,source:`showcase`,description:`Desktop diff review with populated git preview lines and editor-surface chrome.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--diff`}},{id:`workspace-terminal-empty-review`,title:`Workspace / Terminal Empty Review`,category:`empty`,source:`showcase`,description:`Desktop terminal empty state review for bottom panel density and hierarchy.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--terminal`}},{id:`settings-density-review`,title:`Settings / Density Review`,category:`page`,source:`showcase`,description:`Desktop settings page review for spacing, grouping, and information density.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-page`}},{id:`settings-light-theme-review`,title:`Settings / Light Theme Review`,category:`page`,source:`showcase`,description:`Desktop settings review constrained to light themes for surface hierarchy checks.`,devices:[`desktop`],themes:et(),locales:[`zh`,`en`],capture:{selector:`.settings-page`}},{id:`desktop-overlay-review`,title:`Desktop / Overlay Review`,category:`modal`,source:`showcase`,description:`Desktop overlay comparison for command palette, launcher, and worktree manager.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-grid`}},{id:`desktop-statusbar-review`,title:`Desktop / Status Bar Review`,category:`page`,source:`showcase`,description:`Desktop status bar review with seeded branch and file-change state.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.desktop-review-card--statusbar`}},{id:`worktree-manager`,title:`Worktree Manager`,category:`modal`,source:`showcase`,description:`Worktree manager surface with seeded worktree list, status, diff, and tree.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.worktree-manager-surface, .mobile-sheet--worktree`}},{id:`confirm-dialog-danger`,title:`Confirm Dialog / Danger`,category:`modal`,source:`showcase`,description:`Generic destructive confirm dialog for screenshot review.`,devices:[`desktop`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.modal-card`}},{id:`provider-error-state`,title:`Provider Error State`,category:`error`,source:`showcase`,description:`Inline settings error state for provider/config failures.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.settings-page__notice`}},{id:`file-tree-delete-confirm`,title:`File Tree / Delete Confirm`,category:`modal`,source:`showcase`,description:`Shared destructive confirm dialog used by the file tree when deleting a file.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.modal-card`}},{id:`empty-state`,title:`Empty State`,category:`empty`,source:`showcase`,description:`Shared empty-state shell.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.welcome-card`}},{id:`loading-state`,title:`Loading State`,category:`loading`,source:`showcase`,description:`Workspace resolving/loading shell.`,devices:[`desktop`,`mobile`],themes:j(),locales:[`zh`,`en`],capture:{selector:`.workspace-resolving-card`}}],nt=new Map(tt.map(e=>[e.id,e]));function M(e){return nt.get(e)??null}var N={id:`ws-review`,name:`coder-studio`,path:`/home/spencer/workspace/coder-studio`,targetRuntime:`native`,openedAt:1,lastActiveAt:1,uiState:{leftPanelWidth:280,bottomPanelHeight:220,focusMode:!1,activeSessionId:void 0,paneLayout:{id:`root`,type:`leaf`}}},P={branch:`main`,ahead:1,behind:0,staged:[{path:`packages/web/src/styles/tokens.css`,status:`modified`}],modified:[{path:`packages/web/src/styles/components.css`,status:`modified`},{path:`packages/web/src/ui-preview/scenes/desktop-review-scenes.tsx`,status:`modified`}],untracked:[{path:`e2e-ui/output/screenshots/page/workspace-topbar-review.png`,status:`untracked`}],deleted:[]},rt=[{sha:`8f5f7d54d9f8b7f08f483699f2f16c3c442f0a11`,shortSha:`8f5f7d5`,subject:`style: tighten workspace desktop chrome`,authorName:`Spencer`,authoredAt:17157312e5},{sha:`f1c44d42d2b8ef3c83bb8aeeb0898422bf94b31c`,shortSha:`f1c44d4`,subject:`test: add ui preview desktop review scenes`,authorName:`Spencer`,authoredAt:17156448e5}],F=[{name:`main`,path:`/home/spencer/workspace/coder-studio`,branch:`main`,commit:`8f5f7d5`,status:`clean`},{name:`feat-pc-style-polish`,path:`/home/spencer/workspace/coder-studio/.worktrees/feat-pc-style-polish`,branch:`feat/pc-style-polish`,commit:`f1c44d4`,status:`dirty`}],it={[F[1].path]:P},at={[F[1].path]:[{name:`packages`,path:`packages`,kind:`dir`},{name:`docs`,path:`docs`,kind:`dir`},{name:`README.md`,path:`README.md`,kind:`file`}]},ot=[{name:`packages`,path:`packages`,kind:`dir`},{name:`docs`,path:`docs`,kind:`dir`},{name:`README.md`,path:`README.md`,kind:`file`}],st=[{name:`web`,path:`packages/web`,kind:`dir`},{name:`core`,path:`packages/core`,kind:`dir`}],ct=[{name:`src`,path:`packages/web/src`,kind:`dir`},{name:`package.json`,path:`packages/web/package.json`,kind:`file`}],lt=[{name:`styles`,path:`packages/web/src/styles`,kind:`dir`},{name:`ui-preview`,path:`packages/web/src/ui-preview`,kind:`dir`},{name:`app.tsx`,path:`packages/web/src/app.tsx`,kind:`file`}],ut=[{name:`components.css`,path:`packages/web/src/styles/components.css`,kind:`file`},{name:`tokens.css`,path:`packages/web/src/styles/tokens.css`,kind:`file`}],dt=[`const headerTitle = isMobile`,` ? t(shouldShowMobileRoot ? "settings.title" : activeSectionMeta.labelKey)`,` : t("settings.title");`,``,`return (`,' <div className={`settings-page ${isMobile ? "settings-page--mobile" : ""}`}>',` <header className="settings-header">`,` <PageHeader`,` ...`];function I(e,t){let n=M(e);if(!n)throw Error(`Missing UI preview metadata for ${e}`);return{...n,...t}}function L(e){return{...e,workspaces:[N,{...N,id:`ws-review-2`,name:`playground`,path:`/home/spencer/workspace/playground`}],activeWorkspaceId:N.id,fileTreeByWorkspaceId:{[N.id]:new Map([[`.`,ot],[`packages`,st],[`packages/web`,ct],[`packages/web/src`,lt]])},gitStateByWorkspaceId:{[N.id]:P},gitBranchListByWorkspaceId:{[N.id]:{current:`main`,branches:[{name:`main`,isCurrent:!0,isRemote:!1},{name:`feat/pc-style-polish`,isCurrent:!1,isRemote:!1},{name:`origin/main`,isCurrent:!1,isRemote:!0}]}},worktreeListByWorkspaceId:{[N.id]:F},commands:{workspaceList:[N],fileTreeByWorkspaceId:{[N.id]:{".":ot,packages:st,"packages/web":ct,"packages/web/src":lt}},fileSearchByWorkspaceId:{[N.id]:ut},gitStatusByWorkspaceId:{[N.id]:P},gitBranchesByWorkspaceId:{[N.id]:{current:`main`,branches:[{name:`main`,isCurrent:!0,isRemote:!1},{name:`feat/pc-style-polish`,isCurrent:!1,isRemote:!1},{name:`origin/main`,isCurrent:!1,isRemote:!0}]}},gitLogByWorkspaceId:{[N.id]:{entries:rt}},gitDiffByWorkspaceId:{[N.id]:{diff:`@@ preview diff
3
3
  - background: #11181f;
4
4
  + background: var(--bg-elevated);`}},gitShowByWorkspaceId:{[N.id]:{diff:`@@ preview commit diff
@@ -14,4 +14,4 @@ import{r as e}from"./rolldown-runtime-CpWojdLp.js";import{$ as t,A as n,Bt as r,
14
14
  `)],"term-preview-2":[new TextEncoder().encode(`$ playwright test --project=mobile
15
15
  `)]},commands:{terminalListByWorkspaceId:{[U.id]:[{id:`term-preview-1`,workspaceId:U.id,kind:`shell`,title:`Workspace Shell`,cwd:U.path,argv:[`zsh`],cols:120,rows:28,alive:!0,createdAt:1},{id:`term-preview-2`,workspaceId:U.id,kind:`shell`,title:`Preview Runner`,cwd:U.path,argv:[`zsh`],cols:120,rows:28,alive:!0,createdAt:2}]}}}),render:()=>(0,A.jsx)(()=>{let[e,t]=(0,k.useState)(null);return(0,A.jsx)(x,{title:`Terminal`,kicker:null,fullscreen:!0,bodyClassName:`mobile-sheet__body--flush mobile-sheet__body--fullscreen`,contentClassName:`mobile-sheet--terminal`,headerAction:e,onClose:()=>{},body:(0,A.jsx)(`div`,{className:`mobile-terminal-sheet mobile-terminal-sheet--fullscreen`,children:(0,A.jsx)(D,{chrome:`mobile-fullscreen`,onMobileHeaderActionsChange:t})}),footer:(0,A.jsx)(m,{workspaceId:U.id,gitState:{branch:`feature/mobile-terminal`,ahead:0,behind:0,staged:[],modified:[{path:`packages/web/src/styles/components.css`,status:`modified`}],untracked:[],deleted:[]},flush:!0})})},{})}),Y(`mobile-supervisor-sheet`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>({...e,supervisorBySessionId:{"session-preview-1":W}}),render:()=>(0,A.jsx)(w,{sessionId:`session-preview-1`,workspaceId:U.id,onClose:()=>{}})}),Y(`supervisor-dialog`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>({...e,supervisorBySessionId:{"session-preview-1":W},supervisorDialog:{open:!0,sessionId:`session-preview-1`,mode:`edit`,draftObjective:W.objective,draftEvaluatorProviderId:`claude`}}),render:()=>(0,A.jsx)(f,{workspaceId:U.id,sessionId:`session-preview-1`})}),Y(`readme-desktop-hero`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>J(e),render:()=>(0,A.jsx)(Oe,{})}),Y(`readme-desktop-review`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>Ot(e),render:()=>(0,A.jsx)(kt,{})}),Y(`readme-mobile-progress`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>jt({...e,device:`mobile`}),render:()=>(0,A.jsx)(At,{})}),Y(`worktree-manager`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>({...e,workspaces:[U],activeWorkspaceId:U.id,worktreeListByWorkspaceId:{[U.id]:G},commands:{worktreeListByWorkspaceId:{[U.id]:G},worktreeStatusByPath:{[G[0].path]:vt},worktreeDiffByPath:{[G[0].path]:`diff --git a/src/app.tsx b/src/app.tsx`},worktreeTreeByPath:{[G[0].path]:yt}}}),render:()=>(0,A.jsx)(g,{workspaceId:U.id,openView:`list`,onClose:()=>{}})}),Y(`confirm-dialog-danger`,{router:()=>({initialEntries:[`/`],path:`/`}),seed:e=>({...e}),render:()=>(0,A.jsx)(p,{open:!0,onOpenChange:()=>{},tone:`danger`,title:`Delete worktree?`,description:`This removes the worktree directory from disk.`,cancelText:`Cancel`,confirmText:`Delete`,onConfirm:()=>{}})}),Y(`provider-error-state`,{router:()=>({initialEntries:[`/settings`],path:`/settings`}),seed:e=>({...e}),render:()=>(0,A.jsx)(`div`,{className:`settings-page`,children:(0,A.jsx)(Le,{tone:`error`,title:`Failed to refresh provider config`,message:`Retry after checking the provider settings.`,action:(0,A.jsx)(`button`,{className:`settings-link`,children:`Retry`})})})}),Y(`file-tree-delete-confirm`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>({...e}),render:()=>(0,A.jsx)(p,{open:!0,onOpenChange:()=>{},tone:`danger`,title:`Delete preview-file.ts?`,description:`This permanently removes the file from the current workspace.`,cancelText:`Cancel`,confirmText:`Delete`,onConfirm:()=>{}})}),Y(`empty-state`,{router:()=>({initialEntries:[`/`],path:`/`}),seed:e=>({...e}),render:()=>(0,A.jsx)(`div`,{className:`welcome-card`,children:(0,A.jsx)(T,{title:(0,A.jsx)(`p`,{children:`No results`}),description:(0,A.jsx)(`p`,{children:`Try a different filter.`})})})}),Y(`loading-state`,{router:()=>({initialEntries:[`/workspace`],path:`/workspace`}),seed:e=>({...e,workspaces:[],activeWorkspaceId:null}),render:()=>(0,A.jsx)(`div`,{className:`workspace-resolving-shell`,children:(0,A.jsx)(`div`,{className:`workspace-resolving-card`,children:(0,A.jsx)(T,{title:(0,A.jsx)(`p`,{children:`Loading workspace`}),description:(0,A.jsx)(`p`,{children:`Please wait...`})})})})})]}var Ft=[...gt(),...Pt(),...pt()];function It(e){return Ft.find(t=>t.id===e)??null}function Lt(e){let t=new URLSearchParams(e),n=t.get(`scene`)??`welcome`,r=O(t.get(`theme`)),i=t.get(`locale`)===`en`?`en`:`zh`,a=t.get(`device`)===`mobile`?`mobile`:`desktop`,o=It(n);return{sceneId:n,theme:r,locale:i,device:a,context:{theme:r,locale:i,device:a},scene:o}}function Rt({sceneId:e}){return(0,A.jsx)(`div`,{className:`welcome-container`,children:(0,A.jsx)(`div`,{className:`welcome-card`,children:(0,A.jsx)(T,{title:(0,A.jsx)(`p`,{children:`Unknown preview scene`}),description:(0,A.jsx)(`p`,{children:e})})})})}function zt({request:e}){if(document.documentElement.setAttribute(`data-theme`,le(e.theme).documentThemeAttr),document.documentElement.setAttribute(`lang`,e.locale===`zh`?`zh`:`en`),document.body.dataset.uiPreviewDevice=e.device,!e.scene)return(0,A.jsx)(Rt,{sceneId:e.sceneId});let t=e.scene.router(e.context);return(0,A.jsx)(re,{initialEntries:t.initialEntries,children:(0,A.jsx)(_e,{children:(0,A.jsx)(ye,{path:t.path,element:e.scene.render(e.context)})})})}function X(e){return{ok:!0,data:e}}function Z(e,t){let n=e.terminalOutputById?.[t]??[];if(n.length===0)return new Uint8Array;let r=n.reduce((e,t)=>e+t.byteLength,0),i=new Uint8Array(r),a=0;for(let e of n)i.set(e,a),a+=e.byteLength;return i}function Bt(e,t){return Z(e,t).byteLength}function Q(e){return{ok:!1,error:{code:`preview_missing_handler`,message:e}}}function Vt(e){return async(t,n)=>{let r=e.commands??{};if(t===`settings.get`)return X(r.settingsGet??{});if(t===`settings.update`)return X(r.settingsUpdate??{});if(t===`settings.previewCommand`){let e=n?.providerId??``;return X({preview:r.settingsPreviewCommandByProviderId?.[e]??``})}if(t===`settings.readConfigFile`)return X({exists:!0,content:`# preview config
16
16
  `});if(t===`settings.writeConfigFile`)return X({ok:!0});if(t===`workspace.list`)return X(r.workspaceList??e.workspaces??[]);if(t===`workspace.browse`)return r.workspaceBrowse?X(r.workspaceBrowse):Q(`Missing workspace.browse preview handler`);if(t===`workspace.open`)return r.workspaceOpen?X(r.workspaceOpen):Q(`Missing workspace.open preview handler`);if(t===`workspace.uiState.set`){let t=n?.workspaceId??``,i=n?.uiState;return t&&i?.paneLayout&&store.set(C(t),i.paneLayout),X(r.workspaceUiStateSet??r.workspaceOpen??e.workspaces?.[0])}if(t===`session.list`){let e=n?.workspaceId??``;return X((r.sessionListByWorkspaceId?.[e]??[]).slice())}if(t===`git.status`){let t=n?.workspaceId??``,i=r.gitStatusByWorkspaceId?.[t];return X(i||(e.gitStateByWorkspaceId?.[t]??null))}if(t===`git.branches`){let e=n?.workspaceId??``,t=r.gitBranchesByWorkspaceId?.[e];return X(t||{current:``,branches:[]})}if(t===`git.log`){let e=n?.workspaceId??``;return X(r.gitLogByWorkspaceId?.[e]??{entries:[]})}if(t===`git.diff`){let e=n?.workspaceId??``;return X(r.gitDiffByWorkspaceId?.[e]??{diff:``})}if(t===`git.show`){let e=n?.workspaceId??``;return X(r.gitShowByWorkspaceId?.[e]??{diff:``})}if(t===`git.checkout`)return X({success:!0,message:`Preview checkout`,branch:`main`});if(t===`git.fetch`||t===`git.pull`||t===`git.push`)return X({success:!0,message:`Preview sync`});if(t===`file.readTree`){let{workspaceId:e=``,subPath:t}=n??{},i=t??`.`;return X({path:i,children:r.fileTreeByWorkspaceId?.[e]?.[i]??[]})}if(t===`file.search`){let e=n?.workspaceId??``;return X({files:r.fileSearchByWorkspaceId?.[e]??[]})}if(t===`worktree.list`){let e=n?.workspaceId??``;return X({worktrees:r.worktreeListByWorkspaceId?.[e]??[]})}if(t===`worktree.status`){let e=n?.worktreePath??``,t=r.worktreeStatusByPath?.[e];return X(t?{status:t}:{status:null})}if(t===`worktree.diff`){let e=n?.worktreePath??``;return X({diff:r.worktreeDiffByPath?.[e]??``})}if(t===`worktree.tree`){let e=n?.worktreePath??``;return X({tree:r.worktreeTreeByPath?.[e]??[]})}if(t===`worktree.create`||t===`worktree.remove`)return X({ok:!0});if(t===`terminal.list`){let e=n?.workspaceId??``;return X(r.terminalListByWorkspaceId?.[e]??[])}if(t===`terminal.create`)return X({id:`terminal-preview-created`,workspaceId:n?.workspaceId??e.activeWorkspaceId??``,kind:`shell`,title:`Preview Terminal`,cwd:`/home/spencer/workspace/coder-studio`,argv:[],cols:120,rows:32,alive:!0,createdAt:1});if(t===`terminal.snapshot`){let t=n?.terminalId??``,r=Z(e,t);return X({status:`ok`,transport:`binary`,streamId:1,size:r.byteLength,seq:Bt(e,t),rows:28,cols:120,source:`headless`,bytes:r})}if(t===`terminal.replay`){let t=n?.terminalId??``,r=n?.lastSeq??0,i=Z(e,t),a=i.subarray(Math.max(0,r));return X({status:`ok`,transport:`binary`,streamId:1,size:a.byteLength,seq:i.byteLength,bytes:a})}if(t===`terminal.close`||t===`terminal.resize`||t===`terminal.input`||t===`provider.runtimeStatus`||t===`provider.install.start`||t===`provider.install.get`||t===`session.create`||t===`session.stop`||t===`session.remove`||t===`file.create`||t===`file.mkdir`||t===`file.delete`||t===`supervisor.create`||t===`supervisor.update`||t===`supervisor.delete`)return X({});if(t===`supervisor.get`){let t=n?.sessionId??``;return X({supervisor:r.supervisorBySessionId?.[t]??e.supervisorBySessionId?.[t]??null})}return Q(`Missing preview handler for ${t}`)}}function Ht(e){let r=Ne(),a=Vt(e),c=e.workspaces??[];r.set(ie,O(e.theme)),r.set(te,e.locale),r.set(i,e.authEnabled===void 0?!1:e.authEnabled),r.set(oe,e.authenticated??!0),r.set(fe,e.connectionStatus??`connected`),r.set(Te,Object.fromEntries(c.map(e=>[e.id,e]))),r.set(Xe,c.map(e=>e.id)),r.set(de,e.workspacesLoadState??`ready`),r.set(Ye,e.workspacesLoadError??null),r.set(Je,e.activeWorkspaceId===void 0?c[0]?.id??null:e.activeWorkspaceId),r.set(Ce,Object.fromEntries((e.sessions??[]).map(e=>[e.id,e]))),r.set(ee,e.commandPaletteOpen??!1),r.set(ve,e.branchQuickPick??{visible:!1,inputValue:``}),r.set(ne,e.terminalPanelVisible??!0),r.set(pe,e.toasts??[]),r.set(s,e.updateState??null),r.set(Ie,e.supervisorDialog?{draftEvaluatorModel:``,draftMaxSupervisionCount:`0`,draftScheduledAt:``,...e.supervisorDialog}:{open:!1,sessionId:null,mode:`enable`,draftObjective:``,draftEvaluatorProviderId:`claude`,draftEvaluatorModel:``,draftMaxSupervisionCount:`0`,draftScheduledAt:``}),r.set(n,new Map(Object.entries(e.supervisorBySessionId??{}))),r.set(Fe,{sendCommand:async(e,t)=>{let n=await a(e,t);if(!n.ok)throw Error(n.error?.message??`Preview command failed: ${e}`);return n.data},sendTerminalInput:async()=>{},subscribe:()=>()=>{},connect:async()=>{},disconnect:()=>{},getStatus:()=>`connected`});for(let[t,n]of Object.entries(e.paneLayoutByWorkspaceId??{}))r.set(C(t),n);for(let[t,n]of Object.entries(e.fileTreeByWorkspaceId??{}))r.set(We(t),n);for(let[t,n]of Object.entries(e.activeFilePathByWorkspaceId??{}))r.set(Ae(t),n);for(let[t,n]of Object.entries(e.gitStateByWorkspaceId??{}))r.set(se(t),n);for(let[t,n]of Object.entries(e.gitBranchListByWorkspaceId??{}))r.set(ge(t),{...n,loading:!1});for(let[t,n]of Object.entries(e.gitDiffPreviewByWorkspaceId??{}))r.set(be(t),n);for(let[n,i]of Object.entries(e.worktreeListByWorkspaceId??{}))r.set(t(n),{items:i,loading:!1,lastLoadedAt:1});for(let[t,n]of Object.entries(e.terminalMetaById??{}))r.set(o(t),n);return r}var $=Lt(window.location.search),Ut=Ht($.scene?$.scene.seed($.context):$.context);Ze.createRoot(document.getElementById(`root`)).render((0,A.jsx)(ce,{store:Ut,children:(0,A.jsx)(zt,{request:$})}));
17
- //# sourceMappingURL=ui-preview-BGZz053-.js.map
17
+ //# sourceMappingURL=ui-preview-Cd3euuid.js.map