@openchambery/web 1.18.2-beta.11 → 1.18.2-beta.13

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.
Files changed (51) hide show
  1. package/dist/assets/{AssistantView-BDxTxI4C.js → AssistantView-Bbqfj9CK.js} +1 -1
  2. package/dist/assets/{ChatContainer-C26Rw1h2.js → ChatContainer-hDTv6UXl.js} +7 -7
  3. package/dist/assets/{DiagramView-siSsyD6n.js → DiagramView-1hFDtyEy.js} +1 -1
  4. package/dist/assets/{MarkdownRendererImpl-Crm21KO-.js → MarkdownRendererImpl-5BLw0qYH.js} +1 -1
  5. package/dist/assets/{MobileDetailNavigation-m2VCvJuL.js → MobileDetailNavigation-DIyVGM50.js} +1 -1
  6. package/dist/assets/{MobileShareBridge-B4X9T8I9.js → MobileShareBridge-BQM-WOll.js} +1 -1
  7. package/dist/assets/{MobileSurface-DUhwRQFz.js → MobileSurface-KZ-kuSM-.js} +1 -1
  8. package/dist/assets/{MultiRunWindow-DHm99eU5.js → MultiRunWindow-DPOSSmY_.js} +1 -1
  9. package/dist/assets/{OverlayScrollbar-ivKSIGWh.js → OverlayScrollbar-C2pMNVMM.js} +1 -1
  10. package/dist/assets/{SettingsView-CpM0iBkp.js → SettingsView-DxL07Iba.js} +1 -1
  11. package/dist/assets/{SettingsWindow-DW1pl40e.js → SettingsWindow-DJ2o4zvh.js} +1 -1
  12. package/dist/assets/{TerminalView-z4ek-zEW.js → TerminalView-BB3tvloy.js} +1 -1
  13. package/dist/assets/{ToolOutputDialog-BZPEjn9H.js → ToolOutputDialog-D7DqChuM.js} +1 -1
  14. package/dist/assets/{appThemeRegistry-BUHyoCKY.js → appThemeRegistry-DhaoeTus.js} +2 -2
  15. package/dist/assets/{context-menu-uy-nsYLa.js → context-menu-D88vCGyB.js} +1 -1
  16. package/dist/assets/{gitApi-BukyCDHf.js → gitApi-DVNC4iYD.js} +1 -1
  17. package/dist/assets/{insertionBoundaries-Cn--FUpW.js → insertionBoundaries-hcIB6RSd.js} +1 -1
  18. package/dist/assets/{main-DBMzIIq8.js → main-CQrMAdMF.js} +4 -4
  19. package/dist/assets/{main-B9LVDYC3.js → main-D4aa2ZJz.js} +2 -2
  20. package/dist/assets/{miniChat-nHXgh499.js → miniChat-4N2-z2vf.js} +2 -2
  21. package/dist/assets/{mobile-DheffaWK.js → mobile-C-RRGcDW.js} +2 -2
  22. package/dist/assets/{multirun-BkftDz-w.js → multirun-Co8LbTjb.js} +1 -1
  23. package/dist/assets/{projectMeta-Cn8JzItU.js → projectMeta-D-ncdr5Z.js} +1 -1
  24. package/dist/assets/{radio-C9csxweA.js → radio-CD4P-ogh.js} +1 -1
  25. package/dist/assets/{renderElectronMiniChatApp-DLaYpuy5.js → renderElectronMiniChatApp-D5QcQTL0.js} +2 -2
  26. package/dist/assets/{renderMobileApp-CxDgYCxR.js → renderMobileApp-CnZZVbHU.js} +4 -4
  27. package/dist/assets/{runtimeEndpointReset-CCpti76q.js → runtimeEndpointReset-BQ5F5VZS.js} +2 -2
  28. package/dist/assets/{sortable-tabs-strip-sSkepr7C.js → sortable-tabs-strip-DQsv96ke.js} +1 -1
  29. package/dist/assets/{src-BcPciZGI.css → src-C8jn0x69.css} +1 -1
  30. package/dist/assets/{useAppFontEffects-BSolc5HW.js → useAppFontEffects-DygV6JSW.js} +2 -2
  31. package/dist/assets/{useDesktopWindowControlsLayout-CXQ-Ublz.js → useDesktopWindowControlsLayout-Cj63sNDg.js} +1 -1
  32. package/dist/assets/{useEffectiveDirectory-Dm7djJX8.js → useEffectiveDirectory-Dc904Fjg.js} +1 -1
  33. package/dist/assets/{useMobileNavigationStore-a9a3gOnd.js → useMobileNavigationStore-DNoNQA4y.js} +2 -2
  34. package/dist/assets/{useSessionAutoCleanup-CH6_9K8S.js → useSessionAutoCleanup-bBkcz_hu.js} +1 -1
  35. package/dist/assets/{useWorkerHighlightedLines-Qg2o83Ps.js → useWorkerHighlightedLines-mhBD0Do9.js} +1 -1
  36. package/dist/index.html +2 -2
  37. package/dist/mini-chat.html +2 -2
  38. package/dist/mobile.html +2 -2
  39. package/package.json +1 -1
  40. package/server/lib/event-stream/DOCUMENTATION.md +2 -2
  41. package/server/lib/event-stream/diff-summary.js +28 -19
  42. package/server/lib/event-stream/diff-summary.test.js +37 -10
  43. package/server/lib/event-stream/protocol.test.js +66 -3
  44. package/server/lib/opencode/DOCUMENTATION.md +1 -1
  45. package/server/lib/session-turn-pages/DOCUMENTATION.md +3 -3
  46. package/server/lib/session-turn-pages/reconcile.routes.test.js +6 -2
  47. package/server/lib/session-turn-pages/reconcile.service.test.js +6 -2
  48. package/server/lib/session-turn-pages/routes.js +3 -3
  49. package/server/lib/session-turn-pages/routes.test.js +41 -13
  50. package/server/lib/session-turn-pages/service.js +4 -2
  51. package/server/lib/session-turn-pages/service.test.js +13 -3
@@ -1 +1 @@
1
- import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{M as t,t as n}from"./useUIStore-5agS8bsW.js";import{Kt as r,kn as i,qt as a,u as o}from"./persistence-oSFWyKgV.js";import{h as s}from"./desktopHosts-DSgGxDpI.js";import{a as c,i as l,o as u,r as d}from"./desktopRelayRestore-DVIx7jsz.js";import{nt as f,rt as p}from"./vendor-base-ui-CnHfUmDN.js";import{kt as m}from"./gitApiHttp-SLrnr8a5.js";import{n as h}from"./vendor-react-DLPElpoQ.js";import{n as g}from"./vendor-tanstack-query-core-BWz0ose6.js";import{i as _,r as v}from"./vendor-tanstack-react-query-D7pys_c9.js";import{n as y,t as b}from"./clipboard-DF5tFLDb.js";import{i as x,t as S}from"./store-OURVnLSN.js";import{Xi as C,hr as w,l as T,tr as ee,wr as E,xr as te}from"./useMobileNavigationStore-a9a3gOnd.js";import{t as D}from"./utils-Dxsi3J3l.js";import{n as ne}from"./Icon-DHaR0peD.js";import{t as re}from"./button-DCUMIXDC.js";import{i as ie,n as ae,r as oe,t as se}from"./vendor-simplewebauthn-browser-Dwhcdg_5.js";import{n as ce,r as le}from"./radio-C9csxweA.js";var O=h(),k=[`desktopHostSwitch`],A=class extends Error{result;host;constructor(e,t){super(e.reason),this.name=`DesktopHostSwitchError`,this.result=e,this.host=t}},ue=(e,t)=>S(x.getState().dictionary,e,t),de=async e=>{let{host:n}=e;if(n.id===`local`){let r=(e.localApiOrigin||``).trim();if(!r)throw new A({ok:!1,status:{status:`unreachable`,latencyMs:0},reason:`unreachable`},n);return t({apiBaseUrl:r,clientToken:e.localClientToken||null,runtimeKey:l(n)}),{ok:!0,via:`direct`,status:{status:`ok`,latencyMs:0}}}if(n.viaSshRelay){let e=await u(n);if(!e.ok)throw new A(e,n);return e}let r=await c(n,{cachedProbe:e.cachedProbe});if(!r.ok)throw new A(r,n);return r},j=null,fe=()=>j||(j=new g(o,{mutationKey:k,mutationFn:de,onError:(e,t)=>{e instanceof A&&e.result.reason!==`unsupported`&&ee.error(ue(`desktopHostSwitcher.toast.instanceUnreachable`,{host:s(t.host.label)}))}}),j.subscribe(()=>void 0),j),pe=async e=>{if(d(e.host))return{ok:!0,via:`direct`,status:e.cachedProbe?.status===`ok`?e.cachedProbe:{status:`ok`,latencyMs:0}};if(o.isMutating({mutationKey:k})>0)return{ok:!1,status:{status:`unreachable`,latencyMs:0},reason:`unsupported`};try{return await fe().mutate(e)}catch(e){if(e instanceof A)return e.result;throw e}},me=()=>{let e=(0,O.c)(1),t;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={mutationKey:k},e[0]=t):t=e[0],v(t)>0},he=()=>{let e=(0,O.c)(1),t;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={filters:{mutationKey:k,status:`pending`},select:ge},e[0]=t):t=e[0],_(t)[0]?.host.id??null};function ge(e){return e.state.variables}var M=e=>typeof e==`object`&&!!e,N=(e,t)=>{let n=e[t];return typeof n==`string`?n:null},P=(e,t)=>{let n=e[t];return typeof n==`number`&&Number.isFinite(n)?n:null},F=(e,t)=>{let n=e[t];return typeof n==`boolean`?n:null},I=e=>Array.isArray(e)?e.filter(e=>typeof e==`string`):[],L=()=>r()?(e,t)=>a(e,t):null,R=e=>{if(!M(e))return;let t=F(e,`enabled`)??!1,n=N(e,`store`)?.toLowerCase()===`settings`?`settings`:`never`,r=N(e,`value`);return{enabled:t,store:n,...r?{value:r}:{}}},_e=e=>e===`remote`||e===`dynamic`?e:`local`,ve=e=>{if(!M(e))return null;let t=N(e,`id`);if(!t)return null;let n=F(e,`enabled`)??!0,r=_e(N(e,`type`)),i=N(e,`localHost`)||N(e,`local_host`)||void 0,a=P(e,`localPort`)??P(e,`local_port`)??void 0,o=N(e,`remoteHost`)||N(e,`remote_host`)||void 0,s=P(e,`remotePort`)??P(e,`remote_port`)??void 0;return{id:t,enabled:n,type:r,...i?{localHost:i}:{},...typeof a==`number`?{localPort:a}:{},...o?{remoteHost:o}:{},...typeof s==`number`?{remotePort:s}:{}}},ye=e=>{if(!M(e))return null;let t=N(e,`id`),n=N(e,`sshCommand`)||N(e,`ssh_command`);if(!t||!n)return null;let r=N(e,`nickname`),i=e.sshParsed,a=M(i)?{destination:N(i,`destination`)||``,args:I(i.args)}:void 0,o=M(e.remoteOpenchamber)?e.remoteOpenchamber:M(e.remote_openchamber)?e.remote_openchamber:{},s=M(e.localForward)?e.localForward:M(e.local_forward)?e.local_forward:{},c=M(e.auth)?e.auth:{},l=N(o,`mode`)?.toLowerCase()===`external`?`external`:`managed`,u=N(o,`installMethod`)||N(o,`install_method`),d=u===`npm`||u===`download_release`||u===`upload_bundle`?u:`bun`,f=N(s,`bindHost`)||N(s,`bind_host`)||`127.0.0.1`,p=f===`localhost`||f===`0.0.0.0`?f:`127.0.0.1`,m=(Array.isArray(e.portForwards)?e.portForwards:Array.isArray(e.port_forwards)?e.port_forwards:[]).map(e=>ve(e)).filter(e=>!!e),h=P(o,`preferredPort`)??P(o,`preferred_port`),g=P(s,`preferredLocalPort`)??P(s,`preferred_local_port`),_=R(c.sshPassword||c.ssh_password),v=R(c.openchamberPassword||c.openchamber_password);return{id:t,...r?{nickname:r}:{},sshCommand:n,...a&&a.destination?{sshParsed:a}:{},connectionTimeoutSec:P(e,`connectionTimeoutSec`)??P(e,`connection_timeout_sec`)??60,remoteOpenchamber:{mode:l,keepRunning:F(o,`keepRunning`)??F(o,`keep_running`)??!0,...h?{preferredPort:h}:{},installMethod:d,uploadBundleOverSsh:F(o,`uploadBundleOverSsh`)??F(o,`upload_bundle_over_ssh`)??!1},localForward:{...g?{preferredLocalPort:g}:{},bindHost:p},auth:{..._?{sshPassword:_}:{},...v?{openchamberPassword:v}:{}},portForwards:m}},be=e=>{switch(e){case`config_resolved`:case`auth_check`:case`master_connecting`:case`remote_probe`:case`installing`:case`updating`:case`server_detecting`:case`server_starting`:case`forwarding`:case`ready`:case`degraded`:case`error`:return e;default:return`idle`}},z=e=>{if(!M(e))return null;let t=N(e,`id`);return t?{id:t,phase:be(N(e,`phase`)),...N(e,`detail`)?{detail:N(e,`detail`)||void 0}:{},...N(e,`localUrl`)||N(e,`local_url`)?{localUrl:N(e,`localUrl`)||N(e,`local_url`)||void 0}:{},...typeof(P(e,`localPort`)??P(e,`local_port`))==`number`?{localPort:P(e,`localPort`)??P(e,`local_port`)??void 0}:{},...typeof(P(e,`remotePort`)??P(e,`remote_port`))==`number`?{remotePort:P(e,`remotePort`)??P(e,`remote_port`)??void 0}:{},startedByUs:F(e,`startedByUs`)??F(e,`started_by_us`)??!1,retryAttempt:P(e,`retryAttempt`)??P(e,`retry_attempt`)??0,requiresUserAction:F(e,`requiresUserAction`)??F(e,`requires_user_action`)??!1,updatedAtMs:P(e,`updatedAtMs`)??P(e,`updated_at_ms`)??Date.now()}:null},xe=e=>{if(!M(e))return null;let t=N(e,`host`),n=N(e,`source`),r=N(e,`sshCommand`)||N(e,`ssh_command`);return!t||!n||!r?null:{host:t,source:n,sshCommand:r,pattern:F(e,`pattern`)??!1}},Se=(e,t)=>({id:e,sshCommand:t,connectionTimeoutSec:60,remoteOpenchamber:{mode:`managed`,keepRunning:!0,installMethod:`bun`,uploadBundleOverSsh:!1},localForward:{bindHost:`127.0.0.1`},auth:{},portForwards:[]}),Ce=async()=>{let e=L();if(!e)return{instances:[]};let t=await e(`desktop_ssh_instances_get`);return M(t)?{instances:(Array.isArray(t.instances)?t.instances:Array.isArray(t.desktopSshInstances)?t.desktopSshInstances:[]).map(e=>ye(e)).filter(e=>!!e)}:{instances:[]}},we=async e=>{let t=L();t&&await t(`desktop_ssh_instances_set`,{config:{instances:e.instances}})},Te=async()=>{let e=L();if(!e)return[];let t=await e(`desktop_ssh_import_hosts`);return Array.isArray(t)?t.map(e=>xe(e)).filter(e=>!!e):[]},Ee=async e=>{let t=L();t&&await t(`desktop_ssh_connect`,{id:e})},De=async e=>{let t=L();t&&await t(`desktop_ssh_disconnect`,{id:e})},Oe=async e=>{let t=L();if(!t)return[];let n=await t(`desktop_ssh_status`,{...e?{id:e}:{}});return Array.isArray(n)?n.map(e=>z(e)).filter(e=>!!e):[]},ke=async(e,t)=>{let n=L();if(!n)return[];let r=await n(`desktop_ssh_logs`,{id:e,...typeof t==`number`?{limit:t}:{}});return Array.isArray(r)?r.filter(e=>typeof e==`string`):[]},Ae=async e=>{let t=L();t&&await t(`desktop_ssh_logs_clear`,{id:e})},je=(e,t)=>{let n=Math.max(0,Math.trunc(Number(e.fileGroups)||0)),r=Math.max(0,Math.trunc(Number(e.singleFiles)||0)),i=Math.max(0,Math.trunc(Number(e.directories)||0));return{fileGroups:Array.from({length:n},()=>!0),singleFiles:Array.from({length:r},()=>!0),directories:Array.from({length:i},()=>!0),agentsRoot:!0,authFile:t?.includeAuthFile===!0}},Me=e=>{if(!M(e))return null;let t=N(e,`path`),n=P(e,`bytes`);return!t||n===null?null:{path:t,bytes:n}},Ne=e=>{if(!M(e))return null;let t=N(e,`path`),n=P(e,`fileCount`)??P(e,`file_count`),r=P(e,`bytes`);return!t||n===null||r===null?null:{path:t,fileCount:n,bytes:r}},Pe=e=>{if(e==null||!M(e))return null;let t=P(e,`fileCount`)??P(e,`file_count`),n=P(e,`bytes`);return t===null||n===null?null:{fileCount:t,bytes:n}},B=e=>{if(e==null||!M(e))return null;let t=P(e,`bytes`);return t===null?null:{bytes:t}},V=e=>{if(!M(e))return null;let t=Array.isArray(e.files)?e.files:null,n=Array.isArray(e.directories)?e.directories:null,r=I(e.deletes),i=P(e,`totalBytes`)??P(e,`total_bytes`);if(!t||!n||i===null||!(`agentsRoot`in e)&&!(`agents_root`in e))return null;let a=t.map(e=>Me(e)).filter(e=>!!e),o=n.map(e=>Ne(e)).filter(e=>!!e);if(a.length!==t.length||o.length!==n.length)return null;let s=e.agentsRoot??e.agents_root,c=s==null?null:Pe(s);if(s!=null&&c===null)return null;let l=e.authFile??e.auth_file,u=l==null?null:B(l),d=e.direction===`pull`||e.direction===`push`?e.direction:void 0,f=e.selections,p=M(f)?{fileGroups:Array.isArray(f.fileGroups)?f.fileGroups.map(e=>e!==!1):[],singleFiles:Array.isArray(f.singleFiles)?f.singleFiles.map(e=>e!==!1):[],directories:Array.isArray(f.directories)?f.directories.map(e=>e!==!1):[],agentsRoot:f.agentsRoot!==!1,authFile:f.authFile===!0}:void 0,m=H(e.selectionShape??e.selection_shape);return{files:a,directories:o,agentsRoot:c,authFile:u,deletes:r,totalBytes:i,...d?{direction:d}:{},...p?{selections:p}:{},...m?{selectionShape:m}:{}}},H=e=>{if(!M(e))return null;let t=P(e,`fileGroups`)??P(e,`file_groups`),n=P(e,`singleFiles`)??P(e,`single_files`),r=P(e,`directories`);return t===null||n===null||r===null||t<0||n<0||r<0?null:{fileGroups:t,singleFiles:n,directories:r}},Fe=e=>{if(!M(e))return null;let t=V(e.plan);if(!t)return null;let n=H(e.selectionShape??e.selection_shape)??t.selectionShape??null;return{plan:t,remoteExisting:I(e.remoteExisting??e.remote_existing),remoteAgentsRootExists:F(e,`remoteAgentsRootExists`)??F(e,`remote_agents_root_exists`)??!1,remoteAuthFileExists:F(e,`remoteAuthFileExists`)??F(e,`remote_auth_file_exists`)??!1,...typeof e.credentialAuthorized==`boolean`?{credentialAuthorized:e.credentialAuthorized}:{},...n?{selectionShape:n}:{}}},Ie=e=>{if(!M(e)||F(e,`ok`)!==!0)return null;let t=P(e,`files`),n=P(e,`directories`),r=P(e,`deletes`),i=P(e,`totalBytes`)??P(e,`total_bytes`);if(t===null||n===null||r===null||i===null||!(`agentsRoot`in e)&&!(`agents_root`in e))return null;let a=e.agentsRoot??e.agents_root,o=null;if(a!=null){if(!M(a))return null;let e=P(a,`fileCount`)??P(a,`file_count`);if(e===null)return null;o={fileCount:e}}let s=e.authFile??e.auth_file,c=s==null?null:B(s);return{ok:!0,files:t,directories:n,deletes:r,totalBytes:i,agentsRoot:o,authFile:c}},Le=async(e={})=>{let t=L();if(!t)return null;let n=await t(`desktop_ssh_sync_opencode_config`,{stage:`local`,...e.direction?{direction:e.direction}:{},...e.selections?{selections:e.selections}:{}});if(!M(n))return null;let r=V(n.plan);if(!r)return null;let i=H(n.selectionShape??n.selection_shape)??r.selectionShape??null;return i?{...r,selectionShape:i}:r},Re=async(e,t={})=>{let n=L();return n?Fe(await n(`desktop_ssh_sync_opencode_config`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{},...t.direction?{direction:t.direction}:{},...t.selections?{selections:t.selections}:{}})):null},ze=async(e,t={})=>{let n=L();return n?Ie(await n(`desktop_ssh_sync_opencode_config`,{id:e,apply:!0,...t.targetKind?{targetKind:t.targetKind}:{},...t.direction?{direction:t.direction}:{},...t.selections?{selections:t.selections}:{}})):null},Be=async(e,t={})=>{let n=L();if(!n)return[];let r=await n(`desktop_ssh_sync_runs_list`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}});return Array.isArray(r)?r.filter(e=>M(e)&&typeof e.syncRunId==`string`&&typeof e.targetId==`string`):[]},U=e=>{if(!M(e))return null;let t=typeof e.targetId==`string`?e.targetId.trim():``;if(!t)return null;let n=e.authorized===!0,r=typeof e.grantedAt==`string`&&e.grantedAt.trim()?e.grantedAt.trim():void 0,i=typeof e.channel==`string`&&e.channel.trim()?e.channel.trim():void 0;return{targetId:t,authorized:n,...r?{grantedAt:r}:{},...i?{channel:i}:{}}},Ve=async(e,t={})=>{let n=L();return n?U(await n(`desktop_ssh_credential_sync_get`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}})):null},He=async(e,t={})=>{let n=L();return n?U(await n(`desktop_ssh_credential_sync_grant`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}})):null},Ue=async(e,t={})=>{let n=L();return n?U(await n(`desktop_ssh_credential_sync_revoke`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}})):null},We=async e=>{if(!r())return async()=>{};let t=window.__OPENCHAMBER_DESKTOP__?.listen;if(typeof t!=`function`)return async()=>{};let n=await t(`openchamber:ssh-instance-status`,t=>{let n=z(t?.payload);n&&e(n)});return async()=>{await n()}},Ge=`/auth/passkey/authenticate/options`,Ke=`/auth/passkey/authenticate/verify`,qe=`/auth/passkey/register/options`,Je=`/auth/passkey/register/verify`,W=`/api/passkeys`,Ye=`/auth/passkey/status`,Xe=`/api/auth/reset`,G={enabled:!1,hasPasskeys:!1,passkeyCount:0,rpID:null},K=async(e,t)=>i(e,{method:`POST`,credentials:`include`,headers:{"Content-Type":`application/json`,Accept:`application/json`},body:t===void 0?void 0:JSON.stringify(t)}),q=async(e,t)=>{try{let t=await e.json();if(t&&typeof t.error==`string`&&t.error.trim())return t.error}catch{}return t},Ze=e=>e instanceof ie&&e.code===`ERROR_CEREMONY_ABORTED`,Qe=()=>{oe.cancelCeremony()},J=()=>typeof window>`u`?{supported:!1,reason:`Passkeys are unavailable outside the browser.`}:window.isSecureContext?{supported:!0,reason:``}:{supported:!1,reason:`Passkeys require HTTPS or localhost.`},$e=async()=>{let e=J();if(!e.supported)throw Error(e.reason);let t=await K(qe,{label:typeof navigator.userAgent==`string`&&navigator.userAgent.trim()?navigator.userAgent:`This device`});if(!t.ok)throw Error(await q(t,`Could not start passkey setup.`));let{requestId:n,optionsJSON:r}=await t.json(),i=await K(Je,{requestId:n,response:await ae({optionsJSON:r})});if(!i.ok)throw Error(await q(i,`Could not finish passkey setup.`));return i.json().catch(()=>null)},et=async(e,t={})=>{let n=J();if(!n.supported)throw Error(n.reason);let r=await K(Ge);if(!r.ok)throw Error(await q(r,`Passkey sign-in is not available right now.`));let{requestId:i,optionsJSON:a}=await r.json(),o=await K(Ke,{requestId:i,response:await se({optionsJSON:a}),trustDevice:e,issueClientToken:t.issueClientToken===!0,clientLabel:t.clientLabel,clientKind:t.clientKind,dedupeKey:t.dedupeKey});if(!o.ok)throw Error(await q(o,`Passkey sign-in failed.`));return o.json().catch(()=>null)},tt=async()=>{let e=await i(Ye,{method:`GET`,credentials:`include`,headers:{Accept:`application/json`}});if(!e.ok)return G;let t=await e.json().catch(()=>null);return{enabled:t?.enabled===!0,hasPasskeys:t?.hasPasskeys===!0,passkeyCount:typeof t?.passkeyCount==`number`?t.passkeyCount:0,rpID:typeof t?.rpID==`string`&&t.rpID?t.rpID:null}},nt=async()=>{let e=await i(W,{method:`GET`,credentials:`include`,headers:{Accept:`application/json`}});if(!e.ok)throw Error(await q(e,`Could not load passkeys.`));let t=await e.json().catch(()=>null);return Array.isArray(t?.passkeys)?t.passkeys:[]},rt=async e=>{let t=await i(`${W}/${encodeURIComponent(e)}`,{method:`DELETE`,credentials:`include`,headers:{Accept:`application/json`}});if(!t.ok)throw Error(await q(t,`Could not remove passkey.`));return t.json().catch(()=>null)},it=async()=>{let e=await K(Xe);if(!e.ok)throw Error(await q(e,`Could not clear saved authentication.`));return e.json().catch(()=>null)},Y=e(p(),1),X=f();function Z(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-none`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function at(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card-header`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function ot(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`leading-none font-semibold`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card-title`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function st(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`px-6`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card-content`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}var ct=class extends Y.Component{constructor(e){super(e),this.state={hasError:!1}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){this.setState({error:e,errorInfo:t,copied:!1}),console.error(`Error caught by boundary:`,e,t)}handleReset=()=>{this.setState({hasError:!1,error:void 0,errorInfo:void 0})};handleCopy=async()=>{let{strings:e}=this.props,t=`${this.state.error?String(this.state.error):e.unknownError}${this.state.error?.stack?`\n\nStack:\n${this.state.error.stack}`:``}${this.state.errorInfo?.componentStack?`\n\n${e.componentStackLabel}${this.state.errorInfo.componentStack}`:``}`;(await b(t)).ok&&(this.setState({copied:!0}),window.setTimeout(()=>{this.setState(e=>e.copied?{copied:!1}:null)},1500))};render(){let{strings:e}=this.props;return this.state.hasError?this.props.fallback?this.props.fallback:(0,X.jsx)(`div`,{className:`p-4 flex items-center justify-center min-h-screen`,children:(0,X.jsxs)(Z,{className:`w-full max-w-md`,children:[(0,X.jsx)(at,{className:`text-center`,children:(0,X.jsxs)(ot,{className:`flex items-center justify-center gap-2 text-destructive`,children:[(0,X.jsx)(ne,{name:`error-warning`,className:`h-5 w-5`}),e.title]})}),(0,X.jsxs)(st,{className:`space-y-4`,children:[(0,X.jsx)(`p`,{className:`text-sm text-muted-foreground text-center`,children:e.description}),this.state.error&&(0,X.jsxs)(`details`,{className:`text-xs font-mono bg-muted p-3 rounded`,children:[(0,X.jsx)(`summary`,{className:`cursor-pointer hover:bg-interactive-hover/80`,children:e.detailsSummary}),(0,X.jsxs)(`pre`,{className:`mt-2 max-h-48 overflow-auto`,children:[this.state.error.toString(),this.state.errorInfo?.componentStack?`\n\n${e.componentStackLabel}${this.state.errorInfo.componentStack}`:``]})]}),(0,X.jsxs)(`div`,{className:`flex gap-2`,children:[(0,X.jsxs)(re,{onClick:this.handleReset,variant:`outline`,className:`flex-1`,children:[(0,X.jsx)(ne,{name:`restart`,className:`h-4 w-4 mr-2`}),e.tryAgain]}),(0,X.jsx)(re,{onClick:this.handleCopy,variant:`outline`,className:`flex-1`,children:this.state.copied?e.copied:e.copy})]})]})]})}):this.props.children}},lt=e=>{let t=(0,O.c)(29),{children:n,fallback:r}=e,{t:i}=y(),a;t[0]===i?a=t[1]:(a=i(`errorBoundary.state.unknownError`),t[0]=i,t[1]=a);let o;t[2]===i?o=t[3]:(o=i(`errorBoundary.title`),t[2]=i,t[3]=o);let s;t[4]===i?s=t[5]:(s=i(`errorBoundary.description`),t[4]=i,t[5]=s);let c;t[6]===i?c=t[7]:(c=i(`errorBoundary.actions.errorDetails`),t[6]=i,t[7]=c);let l;t[8]===i?l=t[9]:(l=i(`errorBoundary.state.componentStackLabel`),t[8]=i,t[9]=l);let u;t[10]===i?u=t[11]:(u=i(`errorBoundary.actions.tryAgain`),t[10]=i,t[11]=u);let d;t[12]===i?d=t[13]:(d=i(`errorBoundary.actions.copied`),t[12]=i,t[13]=d);let f;t[14]===i?f=t[15]:(f=i(`errorBoundary.actions.copy`),t[14]=i,t[15]=f);let p;t[16]!==a||t[17]!==o||t[18]!==s||t[19]!==c||t[20]!==l||t[21]!==u||t[22]!==d||t[23]!==f?(p={unknownError:a,title:o,description:s,detailsSummary:c,componentStackLabel:l,tryAgain:u,copied:d,copy:f},t[16]=a,t[17]=o,t[18]=s,t[19]=c,t[20]=l,t[21]=u,t[22]=d,t[23]=f,t[24]=p):p=t[24];let m=p,h;return t[25]!==n||t[26]!==r||t[27]!==m?(h=(0,X.jsx)(ct,{fallback:r,strings:m,children:n}),t[25]=n,t[26]=r,t[27]=m,t[28]=h):h=t[28],h},Q=e=>S(x.getState().dictionary,e),ut=e=>typeof e!=`number`||!Number.isFinite(e)?null:Math.max(0,Math.min(100,Math.round(e))),dt=e=>typeof e!=`number`||!Number.isFinite(e)?`-`:`${Math.round(e)}%`,ft=(e,t)=>e??dt(t),pt=(e,t,n=`auto`)=>{if(!e)return t??``;try{let r=new Date(e);if(!Number.isFinite(r.getTime()))return t??``;let i=new Date;return r.toDateString()===i.toDateString()?le(r,n,{fallback:t??``}):ce(r,n,{month:`short`,day:`numeric`,weekday:`short`,hour:`numeric`,minute:`2-digit`})}catch{return t??``}},mt=e=>e===null?`safe`:e>=80?`critical`:e>=50?`warn`:`safe`,ht=e=>e===`5h`?Q(`quota.window.5h`):e===`7d`?Q(`quota.window.7d`):e===`7d-sonnet`?Q(`quota.window.7dSonnet`):e===`7d-opus`?Q(`quota.window.7dOpus`):e===`weekly`?Q(`quota.window.weekly`):e===`daily`?Q(`quota.window.daily`):e===`monthly`?Q(`quota.window.monthly`):e===`credits`?Q(`quota.window.credits`):e===`credits_balance`?Q(`quota.window.creditsBalance`):e===`billing_cycle`?Q(`quota.window.billingCycle`):e===`auto`?Q(`quota.window.auto`):e===`api`?Q(`quota.window.api`):e===`plan_limit`?Q(`quota.window.planLimit`):e===`on_demand`?Q(`quota.window.onDemand`):e===`session`?Q(`quota.window.session`):e===`premium`?Q(`quota.window.premium`):e===`chat`?Q(`quota.window.chat`):e===`completions`?Q(`quota.window.completions`):e===`premium_interactions`?Q(`quota.window.premiumInteractions`):e,gt=e=>{let t=e.toLowerCase().trim();if(t===`5h`)return 18e3;if(t===`7d`||t===`weekly`||t===`7d-sonnet`||t===`7d-opus`)return 604800;if(t===`monthly`)return 2592e3;if(t===`24h`||t===`daily`)return 86400;if(t===`1h`)return 3600;let n=t.match(/^(\d+)h$/);if(n)return parseInt(n[1],10)*3600;let r=t.match(/^(\d+)d$/);return r?parseInt(r[1],10)*86400:null},_t=(e,t,n,r)=>{let i=n;if(i===null&&r&&(i=gt(r)),e===null||t===null||i===null||i<=0)return null;let a=Math.max(0,(t-Date.now())/1e3),o=Math.max(0,Math.min(i,i-a)),s=Math.max(0,Math.min(1,o/i)),c=e/100,l=e>=100&&a>0,u;u=s>.01?Math.min(999,c/s*100):e;let d;d=l?`exhausted`:c<=s?`on-track`:u<=130?`slightly-fast`:`too-fast`;let f=i>=432e3,p=f?86400:3600,m=f?`d`:`h`,h=i/p,g=e/Math.max(o/p,h*.01),_=Number.isFinite(g)?`${Math.min(999.9,Math.max(0,g)).toFixed(1)}%/${m}`:`-`,v=u>100?`+${Math.round(u)}%`:`${Math.round(u)}%`,y=null,b=i/86400;return b>=7&&(y=100/b),{elapsedRatio:s,usageRatio:c,predictedFinalPercent:u,remainingSeconds:a,isExhausted:l,elapsedSeconds:o,totalSeconds:i,status:d,paceRateText:_,predictText:v,dailyAllocationPercent:y}},vt=e=>{switch(e){case`exhausted`:case`too-fast`:return`var(--status-error)`;case`slightly-fast`:return`var(--status-warning)`;case`on-track`:return`var(--status-success)`}},yt=e=>{let t=Math.floor(Math.max(0,Math.floor(e))/60),n=Math.floor(t/60),r=Math.floor(n/24),i=n%24,a=t%60;return r>0?`${r}d ${i}h`:n>0?`${n}h`:t===0?`<1m`:`${a}m`},bt=e=>Math.min(100,Math.max(0,e*100)),xt=[`standalone`,`minimal-ui`,`fullscreen`,`window-controls-overlay`],St=`openchamber.pwaRecentSessions`,Ct=e=>typeof window>`u`||typeof window.matchMedia!=`function`?!1:window.matchMedia(`(display-mode: ${e})`).matches,wt=()=>typeof window>`u`?`browser`:typeof document<`u`&&document.referrer.startsWith(`android-app://`)?`twa`:window.navigator.standalone?`standalone`:xt.find(e=>Ct(e))??`browser`,Tt=864e5,Et=5,Dt=864e5,$=e=>e.time?.updated??e.time?.created??0,Ot=({sessions:e,currentSessionId:t,cutoffDays:n,keepRecent:r=Et,now:i=Date.now()})=>{if(!Array.isArray(e)||n<=0)return[];let a=i-n*Tt,o=[...e].sort((e,t)=>$(t)-$(e)),s=new Set(o.slice(0,r).map(e=>e.id));return o.filter(e=>{if(!e?.id||s.has(e.id)||e.id===t||e.share)return!1;let n=$(e);return n?n<a:!1}).map(e=>e.id)},kt=e=>{let t=typeof e==`object`?e:void 0,r=t?.autoRun!==!1,i=typeof e==`boolean`?e:t?.enabled??!0,a=T(e=>e.currentSessionId),o=T(e=>e.isLoading),s=E(e=>e.activeSessions),c=E(e=>e.hasLoadedFullCatalog),l=n(e=>e.autoDeleteEnabled),u=n(e=>e.autoDeleteAfterDays),d=n(e=>e.sessionRetentionAction),f=n(e=>e.autoDeleteLastRunAt),p=n(e=>e.setAutoDeleteLastRunAt),[h,g]=Y.useState(!1),_=Y.useRef(!1);Y.useEffect(()=>{if(!i||!r||!l||u<=0)return;let e=window.setTimeout(()=>{w(C())},8e3);return()=>window.clearTimeout(e)},[u,l,r,i]);let v=Y.useMemo(()=>u<=0?[]:Ot({sessions:s,currentSessionId:a,cutoffDays:u}),[u,a,s]),y=Y.useCallback(async({force:e=!1}={})=>{if(_.current)return{completedIds:[],failedIds:[],action:d,skippedReason:`running`};if((!l||u<=0)&&!e)return{completedIds:[],failedIds:[],action:d,skippedReason:`disabled`};if(o)return{completedIds:[],failedIds:[],action:d,skippedReason:`loading`};let t=Date.now();if(!e&&f&&t-f<Dt)return{completedIds:[],failedIds:[],action:d,skippedReason:`cooldown`};let{activeSessions:n}=await w(C());if(n.length===0)return{completedIds:[],failedIds:[],action:d,skippedReason:`no-candidates`};let r=Ot({sessions:n,currentSessionId:a,cutoffDays:u,now:t});if(r.length===0)return p(t),{completedIds:[],failedIds:[],action:d,skippedReason:`no-candidates`};_.current=!0,g(!0);try{let e=new Map(n.map(e=>[e.id,e])),t=[],i=[];for(let n of r){let r=e.get(n),a=r?te(r):null;if(!a){i.push(n);continue}try{d===`archive`?await m.updateSession(n,{time:{archived:Date.now()}},a):await m.deleteSession(n,a),t.push(n)}catch{i.push(n)}}return d===`archive`?E.getState().archiveSessions(t):E.getState().removeSessions(t),{completedIds:t,failedIds:i,action:d}}finally{_.current=!1,g(!1),p(Date.now())}},[u,l,f,a,o,d,p]);return Y.useEffect(()=>{i&&r&&(!l||u<=0||o||!c||s.length===0||f&&Date.now()-f<Dt||y())},[u,l,f,r,i,c,s.length,o,y]),{candidates:v,isRunning:h,runCleanup:y,keepRecentCount:Et,action:d}};export{Ee as A,Oe as B,J as C,rt as D,it as E,Te as F,We as G,Le as H,Ce as I,he as J,pe as K,we as L,He as M,Ue as N,je as O,De as P,ke as R,nt as S,$e as T,Re as U,ze as V,Be as W,ot as _,_t as a,G as b,ft as c,vt as d,mt as f,at as g,st as h,bt as i,Ve as j,Se as k,yt as l,Z as m,St as n,ut as o,lt as p,me as q,wt as r,pt as s,kt as t,ht as u,et as v,Ze as w,tt as x,Qe as y,Ae as z};
1
+ import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{M as t,t as n}from"./useUIStore-5agS8bsW.js";import{Kt as r,kn as i,qt as a,u as o}from"./persistence-oSFWyKgV.js";import{h as s}from"./desktopHosts-DSgGxDpI.js";import{a as c,i as l,o as u,r as d}from"./desktopRelayRestore-DVIx7jsz.js";import{nt as f,rt as p}from"./vendor-base-ui-CnHfUmDN.js";import{kt as m}from"./gitApiHttp-SLrnr8a5.js";import{n as h}from"./vendor-react-DLPElpoQ.js";import{n as g}from"./vendor-tanstack-query-core-BWz0ose6.js";import{i as _,r as v}from"./vendor-tanstack-react-query-D7pys_c9.js";import{n as y,t as b}from"./clipboard-DF5tFLDb.js";import{i as x,t as S}from"./store-OURVnLSN.js";import{Xi as C,hr as w,l as T,tr as ee,wr as E,xr as te}from"./useMobileNavigationStore-DNoNQA4y.js";import{t as D}from"./utils-Dxsi3J3l.js";import{n as ne}from"./Icon-DHaR0peD.js";import{t as re}from"./button-DCUMIXDC.js";import{i as ie,n as ae,r as oe,t as se}from"./vendor-simplewebauthn-browser-Dwhcdg_5.js";import{n as ce,r as le}from"./radio-CD4P-ogh.js";var O=h(),k=[`desktopHostSwitch`],A=class extends Error{result;host;constructor(e,t){super(e.reason),this.name=`DesktopHostSwitchError`,this.result=e,this.host=t}},ue=(e,t)=>S(x.getState().dictionary,e,t),de=async e=>{let{host:n}=e;if(n.id===`local`){let r=(e.localApiOrigin||``).trim();if(!r)throw new A({ok:!1,status:{status:`unreachable`,latencyMs:0},reason:`unreachable`},n);return t({apiBaseUrl:r,clientToken:e.localClientToken||null,runtimeKey:l(n)}),{ok:!0,via:`direct`,status:{status:`ok`,latencyMs:0}}}if(n.viaSshRelay){let e=await u(n);if(!e.ok)throw new A(e,n);return e}let r=await c(n,{cachedProbe:e.cachedProbe});if(!r.ok)throw new A(r,n);return r},j=null,fe=()=>j||(j=new g(o,{mutationKey:k,mutationFn:de,onError:(e,t)=>{e instanceof A&&e.result.reason!==`unsupported`&&ee.error(ue(`desktopHostSwitcher.toast.instanceUnreachable`,{host:s(t.host.label)}))}}),j.subscribe(()=>void 0),j),pe=async e=>{if(d(e.host))return{ok:!0,via:`direct`,status:e.cachedProbe?.status===`ok`?e.cachedProbe:{status:`ok`,latencyMs:0}};if(o.isMutating({mutationKey:k})>0)return{ok:!1,status:{status:`unreachable`,latencyMs:0},reason:`unsupported`};try{return await fe().mutate(e)}catch(e){if(e instanceof A)return e.result;throw e}},me=()=>{let e=(0,O.c)(1),t;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={mutationKey:k},e[0]=t):t=e[0],v(t)>0},he=()=>{let e=(0,O.c)(1),t;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={filters:{mutationKey:k,status:`pending`},select:ge},e[0]=t):t=e[0],_(t)[0]?.host.id??null};function ge(e){return e.state.variables}var M=e=>typeof e==`object`&&!!e,N=(e,t)=>{let n=e[t];return typeof n==`string`?n:null},P=(e,t)=>{let n=e[t];return typeof n==`number`&&Number.isFinite(n)?n:null},F=(e,t)=>{let n=e[t];return typeof n==`boolean`?n:null},I=e=>Array.isArray(e)?e.filter(e=>typeof e==`string`):[],L=()=>r()?(e,t)=>a(e,t):null,R=e=>{if(!M(e))return;let t=F(e,`enabled`)??!1,n=N(e,`store`)?.toLowerCase()===`settings`?`settings`:`never`,r=N(e,`value`);return{enabled:t,store:n,...r?{value:r}:{}}},_e=e=>e===`remote`||e===`dynamic`?e:`local`,ve=e=>{if(!M(e))return null;let t=N(e,`id`);if(!t)return null;let n=F(e,`enabled`)??!0,r=_e(N(e,`type`)),i=N(e,`localHost`)||N(e,`local_host`)||void 0,a=P(e,`localPort`)??P(e,`local_port`)??void 0,o=N(e,`remoteHost`)||N(e,`remote_host`)||void 0,s=P(e,`remotePort`)??P(e,`remote_port`)??void 0;return{id:t,enabled:n,type:r,...i?{localHost:i}:{},...typeof a==`number`?{localPort:a}:{},...o?{remoteHost:o}:{},...typeof s==`number`?{remotePort:s}:{}}},ye=e=>{if(!M(e))return null;let t=N(e,`id`),n=N(e,`sshCommand`)||N(e,`ssh_command`);if(!t||!n)return null;let r=N(e,`nickname`),i=e.sshParsed,a=M(i)?{destination:N(i,`destination`)||``,args:I(i.args)}:void 0,o=M(e.remoteOpenchamber)?e.remoteOpenchamber:M(e.remote_openchamber)?e.remote_openchamber:{},s=M(e.localForward)?e.localForward:M(e.local_forward)?e.local_forward:{},c=M(e.auth)?e.auth:{},l=N(o,`mode`)?.toLowerCase()===`external`?`external`:`managed`,u=N(o,`installMethod`)||N(o,`install_method`),d=u===`npm`||u===`download_release`||u===`upload_bundle`?u:`bun`,f=N(s,`bindHost`)||N(s,`bind_host`)||`127.0.0.1`,p=f===`localhost`||f===`0.0.0.0`?f:`127.0.0.1`,m=(Array.isArray(e.portForwards)?e.portForwards:Array.isArray(e.port_forwards)?e.port_forwards:[]).map(e=>ve(e)).filter(e=>!!e),h=P(o,`preferredPort`)??P(o,`preferred_port`),g=P(s,`preferredLocalPort`)??P(s,`preferred_local_port`),_=R(c.sshPassword||c.ssh_password),v=R(c.openchamberPassword||c.openchamber_password);return{id:t,...r?{nickname:r}:{},sshCommand:n,...a&&a.destination?{sshParsed:a}:{},connectionTimeoutSec:P(e,`connectionTimeoutSec`)??P(e,`connection_timeout_sec`)??60,remoteOpenchamber:{mode:l,keepRunning:F(o,`keepRunning`)??F(o,`keep_running`)??!0,...h?{preferredPort:h}:{},installMethod:d,uploadBundleOverSsh:F(o,`uploadBundleOverSsh`)??F(o,`upload_bundle_over_ssh`)??!1},localForward:{...g?{preferredLocalPort:g}:{},bindHost:p},auth:{..._?{sshPassword:_}:{},...v?{openchamberPassword:v}:{}},portForwards:m}},be=e=>{switch(e){case`config_resolved`:case`auth_check`:case`master_connecting`:case`remote_probe`:case`installing`:case`updating`:case`server_detecting`:case`server_starting`:case`forwarding`:case`ready`:case`degraded`:case`error`:return e;default:return`idle`}},z=e=>{if(!M(e))return null;let t=N(e,`id`);return t?{id:t,phase:be(N(e,`phase`)),...N(e,`detail`)?{detail:N(e,`detail`)||void 0}:{},...N(e,`localUrl`)||N(e,`local_url`)?{localUrl:N(e,`localUrl`)||N(e,`local_url`)||void 0}:{},...typeof(P(e,`localPort`)??P(e,`local_port`))==`number`?{localPort:P(e,`localPort`)??P(e,`local_port`)??void 0}:{},...typeof(P(e,`remotePort`)??P(e,`remote_port`))==`number`?{remotePort:P(e,`remotePort`)??P(e,`remote_port`)??void 0}:{},startedByUs:F(e,`startedByUs`)??F(e,`started_by_us`)??!1,retryAttempt:P(e,`retryAttempt`)??P(e,`retry_attempt`)??0,requiresUserAction:F(e,`requiresUserAction`)??F(e,`requires_user_action`)??!1,updatedAtMs:P(e,`updatedAtMs`)??P(e,`updated_at_ms`)??Date.now()}:null},xe=e=>{if(!M(e))return null;let t=N(e,`host`),n=N(e,`source`),r=N(e,`sshCommand`)||N(e,`ssh_command`);return!t||!n||!r?null:{host:t,source:n,sshCommand:r,pattern:F(e,`pattern`)??!1}},Se=(e,t)=>({id:e,sshCommand:t,connectionTimeoutSec:60,remoteOpenchamber:{mode:`managed`,keepRunning:!0,installMethod:`bun`,uploadBundleOverSsh:!1},localForward:{bindHost:`127.0.0.1`},auth:{},portForwards:[]}),Ce=async()=>{let e=L();if(!e)return{instances:[]};let t=await e(`desktop_ssh_instances_get`);return M(t)?{instances:(Array.isArray(t.instances)?t.instances:Array.isArray(t.desktopSshInstances)?t.desktopSshInstances:[]).map(e=>ye(e)).filter(e=>!!e)}:{instances:[]}},we=async e=>{let t=L();t&&await t(`desktop_ssh_instances_set`,{config:{instances:e.instances}})},Te=async()=>{let e=L();if(!e)return[];let t=await e(`desktop_ssh_import_hosts`);return Array.isArray(t)?t.map(e=>xe(e)).filter(e=>!!e):[]},Ee=async e=>{let t=L();t&&await t(`desktop_ssh_connect`,{id:e})},De=async e=>{let t=L();t&&await t(`desktop_ssh_disconnect`,{id:e})},Oe=async e=>{let t=L();if(!t)return[];let n=await t(`desktop_ssh_status`,{...e?{id:e}:{}});return Array.isArray(n)?n.map(e=>z(e)).filter(e=>!!e):[]},ke=async(e,t)=>{let n=L();if(!n)return[];let r=await n(`desktop_ssh_logs`,{id:e,...typeof t==`number`?{limit:t}:{}});return Array.isArray(r)?r.filter(e=>typeof e==`string`):[]},Ae=async e=>{let t=L();t&&await t(`desktop_ssh_logs_clear`,{id:e})},je=(e,t)=>{let n=Math.max(0,Math.trunc(Number(e.fileGroups)||0)),r=Math.max(0,Math.trunc(Number(e.singleFiles)||0)),i=Math.max(0,Math.trunc(Number(e.directories)||0));return{fileGroups:Array.from({length:n},()=>!0),singleFiles:Array.from({length:r},()=>!0),directories:Array.from({length:i},()=>!0),agentsRoot:!0,authFile:t?.includeAuthFile===!0}},Me=e=>{if(!M(e))return null;let t=N(e,`path`),n=P(e,`bytes`);return!t||n===null?null:{path:t,bytes:n}},Ne=e=>{if(!M(e))return null;let t=N(e,`path`),n=P(e,`fileCount`)??P(e,`file_count`),r=P(e,`bytes`);return!t||n===null||r===null?null:{path:t,fileCount:n,bytes:r}},Pe=e=>{if(e==null||!M(e))return null;let t=P(e,`fileCount`)??P(e,`file_count`),n=P(e,`bytes`);return t===null||n===null?null:{fileCount:t,bytes:n}},B=e=>{if(e==null||!M(e))return null;let t=P(e,`bytes`);return t===null?null:{bytes:t}},V=e=>{if(!M(e))return null;let t=Array.isArray(e.files)?e.files:null,n=Array.isArray(e.directories)?e.directories:null,r=I(e.deletes),i=P(e,`totalBytes`)??P(e,`total_bytes`);if(!t||!n||i===null||!(`agentsRoot`in e)&&!(`agents_root`in e))return null;let a=t.map(e=>Me(e)).filter(e=>!!e),o=n.map(e=>Ne(e)).filter(e=>!!e);if(a.length!==t.length||o.length!==n.length)return null;let s=e.agentsRoot??e.agents_root,c=s==null?null:Pe(s);if(s!=null&&c===null)return null;let l=e.authFile??e.auth_file,u=l==null?null:B(l),d=e.direction===`pull`||e.direction===`push`?e.direction:void 0,f=e.selections,p=M(f)?{fileGroups:Array.isArray(f.fileGroups)?f.fileGroups.map(e=>e!==!1):[],singleFiles:Array.isArray(f.singleFiles)?f.singleFiles.map(e=>e!==!1):[],directories:Array.isArray(f.directories)?f.directories.map(e=>e!==!1):[],agentsRoot:f.agentsRoot!==!1,authFile:f.authFile===!0}:void 0,m=H(e.selectionShape??e.selection_shape);return{files:a,directories:o,agentsRoot:c,authFile:u,deletes:r,totalBytes:i,...d?{direction:d}:{},...p?{selections:p}:{},...m?{selectionShape:m}:{}}},H=e=>{if(!M(e))return null;let t=P(e,`fileGroups`)??P(e,`file_groups`),n=P(e,`singleFiles`)??P(e,`single_files`),r=P(e,`directories`);return t===null||n===null||r===null||t<0||n<0||r<0?null:{fileGroups:t,singleFiles:n,directories:r}},Fe=e=>{if(!M(e))return null;let t=V(e.plan);if(!t)return null;let n=H(e.selectionShape??e.selection_shape)??t.selectionShape??null;return{plan:t,remoteExisting:I(e.remoteExisting??e.remote_existing),remoteAgentsRootExists:F(e,`remoteAgentsRootExists`)??F(e,`remote_agents_root_exists`)??!1,remoteAuthFileExists:F(e,`remoteAuthFileExists`)??F(e,`remote_auth_file_exists`)??!1,...typeof e.credentialAuthorized==`boolean`?{credentialAuthorized:e.credentialAuthorized}:{},...n?{selectionShape:n}:{}}},Ie=e=>{if(!M(e)||F(e,`ok`)!==!0)return null;let t=P(e,`files`),n=P(e,`directories`),r=P(e,`deletes`),i=P(e,`totalBytes`)??P(e,`total_bytes`);if(t===null||n===null||r===null||i===null||!(`agentsRoot`in e)&&!(`agents_root`in e))return null;let a=e.agentsRoot??e.agents_root,o=null;if(a!=null){if(!M(a))return null;let e=P(a,`fileCount`)??P(a,`file_count`);if(e===null)return null;o={fileCount:e}}let s=e.authFile??e.auth_file,c=s==null?null:B(s);return{ok:!0,files:t,directories:n,deletes:r,totalBytes:i,agentsRoot:o,authFile:c}},Le=async(e={})=>{let t=L();if(!t)return null;let n=await t(`desktop_ssh_sync_opencode_config`,{stage:`local`,...e.direction?{direction:e.direction}:{},...e.selections?{selections:e.selections}:{}});if(!M(n))return null;let r=V(n.plan);if(!r)return null;let i=H(n.selectionShape??n.selection_shape)??r.selectionShape??null;return i?{...r,selectionShape:i}:r},Re=async(e,t={})=>{let n=L();return n?Fe(await n(`desktop_ssh_sync_opencode_config`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{},...t.direction?{direction:t.direction}:{},...t.selections?{selections:t.selections}:{}})):null},ze=async(e,t={})=>{let n=L();return n?Ie(await n(`desktop_ssh_sync_opencode_config`,{id:e,apply:!0,...t.targetKind?{targetKind:t.targetKind}:{},...t.direction?{direction:t.direction}:{},...t.selections?{selections:t.selections}:{}})):null},Be=async(e,t={})=>{let n=L();if(!n)return[];let r=await n(`desktop_ssh_sync_runs_list`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}});return Array.isArray(r)?r.filter(e=>M(e)&&typeof e.syncRunId==`string`&&typeof e.targetId==`string`):[]},U=e=>{if(!M(e))return null;let t=typeof e.targetId==`string`?e.targetId.trim():``;if(!t)return null;let n=e.authorized===!0,r=typeof e.grantedAt==`string`&&e.grantedAt.trim()?e.grantedAt.trim():void 0,i=typeof e.channel==`string`&&e.channel.trim()?e.channel.trim():void 0;return{targetId:t,authorized:n,...r?{grantedAt:r}:{},...i?{channel:i}:{}}},Ve=async(e,t={})=>{let n=L();return n?U(await n(`desktop_ssh_credential_sync_get`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}})):null},He=async(e,t={})=>{let n=L();return n?U(await n(`desktop_ssh_credential_sync_grant`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}})):null},Ue=async(e,t={})=>{let n=L();return n?U(await n(`desktop_ssh_credential_sync_revoke`,{id:e,...t.targetKind?{targetKind:t.targetKind}:{}})):null},We=async e=>{if(!r())return async()=>{};let t=window.__OPENCHAMBER_DESKTOP__?.listen;if(typeof t!=`function`)return async()=>{};let n=await t(`openchamber:ssh-instance-status`,t=>{let n=z(t?.payload);n&&e(n)});return async()=>{await n()}},Ge=`/auth/passkey/authenticate/options`,Ke=`/auth/passkey/authenticate/verify`,qe=`/auth/passkey/register/options`,Je=`/auth/passkey/register/verify`,W=`/api/passkeys`,Ye=`/auth/passkey/status`,Xe=`/api/auth/reset`,G={enabled:!1,hasPasskeys:!1,passkeyCount:0,rpID:null},K=async(e,t)=>i(e,{method:`POST`,credentials:`include`,headers:{"Content-Type":`application/json`,Accept:`application/json`},body:t===void 0?void 0:JSON.stringify(t)}),q=async(e,t)=>{try{let t=await e.json();if(t&&typeof t.error==`string`&&t.error.trim())return t.error}catch{}return t},Ze=e=>e instanceof ie&&e.code===`ERROR_CEREMONY_ABORTED`,Qe=()=>{oe.cancelCeremony()},J=()=>typeof window>`u`?{supported:!1,reason:`Passkeys are unavailable outside the browser.`}:window.isSecureContext?{supported:!0,reason:``}:{supported:!1,reason:`Passkeys require HTTPS or localhost.`},$e=async()=>{let e=J();if(!e.supported)throw Error(e.reason);let t=await K(qe,{label:typeof navigator.userAgent==`string`&&navigator.userAgent.trim()?navigator.userAgent:`This device`});if(!t.ok)throw Error(await q(t,`Could not start passkey setup.`));let{requestId:n,optionsJSON:r}=await t.json(),i=await K(Je,{requestId:n,response:await ae({optionsJSON:r})});if(!i.ok)throw Error(await q(i,`Could not finish passkey setup.`));return i.json().catch(()=>null)},et=async(e,t={})=>{let n=J();if(!n.supported)throw Error(n.reason);let r=await K(Ge);if(!r.ok)throw Error(await q(r,`Passkey sign-in is not available right now.`));let{requestId:i,optionsJSON:a}=await r.json(),o=await K(Ke,{requestId:i,response:await se({optionsJSON:a}),trustDevice:e,issueClientToken:t.issueClientToken===!0,clientLabel:t.clientLabel,clientKind:t.clientKind,dedupeKey:t.dedupeKey});if(!o.ok)throw Error(await q(o,`Passkey sign-in failed.`));return o.json().catch(()=>null)},tt=async()=>{let e=await i(Ye,{method:`GET`,credentials:`include`,headers:{Accept:`application/json`}});if(!e.ok)return G;let t=await e.json().catch(()=>null);return{enabled:t?.enabled===!0,hasPasskeys:t?.hasPasskeys===!0,passkeyCount:typeof t?.passkeyCount==`number`?t.passkeyCount:0,rpID:typeof t?.rpID==`string`&&t.rpID?t.rpID:null}},nt=async()=>{let e=await i(W,{method:`GET`,credentials:`include`,headers:{Accept:`application/json`}});if(!e.ok)throw Error(await q(e,`Could not load passkeys.`));let t=await e.json().catch(()=>null);return Array.isArray(t?.passkeys)?t.passkeys:[]},rt=async e=>{let t=await i(`${W}/${encodeURIComponent(e)}`,{method:`DELETE`,credentials:`include`,headers:{Accept:`application/json`}});if(!t.ok)throw Error(await q(t,`Could not remove passkey.`));return t.json().catch(()=>null)},it=async()=>{let e=await K(Xe);if(!e.ok)throw Error(await q(e,`Could not clear saved authentication.`));return e.json().catch(()=>null)},Y=e(p(),1),X=f();function Z(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-none`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function at(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card-header`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function ot(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`leading-none font-semibold`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card-title`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function st(e){let t=(0,O.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=D(`px-6`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,X.jsx)(`div`,{"data-slot":`card-content`,className:i,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}var ct=class extends Y.Component{constructor(e){super(e),this.state={hasError:!1}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){this.setState({error:e,errorInfo:t,copied:!1}),console.error(`Error caught by boundary:`,e,t)}handleReset=()=>{this.setState({hasError:!1,error:void 0,errorInfo:void 0})};handleCopy=async()=>{let{strings:e}=this.props,t=`${this.state.error?String(this.state.error):e.unknownError}${this.state.error?.stack?`\n\nStack:\n${this.state.error.stack}`:``}${this.state.errorInfo?.componentStack?`\n\n${e.componentStackLabel}${this.state.errorInfo.componentStack}`:``}`;(await b(t)).ok&&(this.setState({copied:!0}),window.setTimeout(()=>{this.setState(e=>e.copied?{copied:!1}:null)},1500))};render(){let{strings:e}=this.props;return this.state.hasError?this.props.fallback?this.props.fallback:(0,X.jsx)(`div`,{className:`p-4 flex items-center justify-center min-h-screen`,children:(0,X.jsxs)(Z,{className:`w-full max-w-md`,children:[(0,X.jsx)(at,{className:`text-center`,children:(0,X.jsxs)(ot,{className:`flex items-center justify-center gap-2 text-destructive`,children:[(0,X.jsx)(ne,{name:`error-warning`,className:`h-5 w-5`}),e.title]})}),(0,X.jsxs)(st,{className:`space-y-4`,children:[(0,X.jsx)(`p`,{className:`text-sm text-muted-foreground text-center`,children:e.description}),this.state.error&&(0,X.jsxs)(`details`,{className:`text-xs font-mono bg-muted p-3 rounded`,children:[(0,X.jsx)(`summary`,{className:`cursor-pointer hover:bg-interactive-hover/80`,children:e.detailsSummary}),(0,X.jsxs)(`pre`,{className:`mt-2 max-h-48 overflow-auto`,children:[this.state.error.toString(),this.state.errorInfo?.componentStack?`\n\n${e.componentStackLabel}${this.state.errorInfo.componentStack}`:``]})]}),(0,X.jsxs)(`div`,{className:`flex gap-2`,children:[(0,X.jsxs)(re,{onClick:this.handleReset,variant:`outline`,className:`flex-1`,children:[(0,X.jsx)(ne,{name:`restart`,className:`h-4 w-4 mr-2`}),e.tryAgain]}),(0,X.jsx)(re,{onClick:this.handleCopy,variant:`outline`,className:`flex-1`,children:this.state.copied?e.copied:e.copy})]})]})]})}):this.props.children}},lt=e=>{let t=(0,O.c)(29),{children:n,fallback:r}=e,{t:i}=y(),a;t[0]===i?a=t[1]:(a=i(`errorBoundary.state.unknownError`),t[0]=i,t[1]=a);let o;t[2]===i?o=t[3]:(o=i(`errorBoundary.title`),t[2]=i,t[3]=o);let s;t[4]===i?s=t[5]:(s=i(`errorBoundary.description`),t[4]=i,t[5]=s);let c;t[6]===i?c=t[7]:(c=i(`errorBoundary.actions.errorDetails`),t[6]=i,t[7]=c);let l;t[8]===i?l=t[9]:(l=i(`errorBoundary.state.componentStackLabel`),t[8]=i,t[9]=l);let u;t[10]===i?u=t[11]:(u=i(`errorBoundary.actions.tryAgain`),t[10]=i,t[11]=u);let d;t[12]===i?d=t[13]:(d=i(`errorBoundary.actions.copied`),t[12]=i,t[13]=d);let f;t[14]===i?f=t[15]:(f=i(`errorBoundary.actions.copy`),t[14]=i,t[15]=f);let p;t[16]!==a||t[17]!==o||t[18]!==s||t[19]!==c||t[20]!==l||t[21]!==u||t[22]!==d||t[23]!==f?(p={unknownError:a,title:o,description:s,detailsSummary:c,componentStackLabel:l,tryAgain:u,copied:d,copy:f},t[16]=a,t[17]=o,t[18]=s,t[19]=c,t[20]=l,t[21]=u,t[22]=d,t[23]=f,t[24]=p):p=t[24];let m=p,h;return t[25]!==n||t[26]!==r||t[27]!==m?(h=(0,X.jsx)(ct,{fallback:r,strings:m,children:n}),t[25]=n,t[26]=r,t[27]=m,t[28]=h):h=t[28],h},Q=e=>S(x.getState().dictionary,e),ut=e=>typeof e!=`number`||!Number.isFinite(e)?null:Math.max(0,Math.min(100,Math.round(e))),dt=e=>typeof e!=`number`||!Number.isFinite(e)?`-`:`${Math.round(e)}%`,ft=(e,t)=>e??dt(t),pt=(e,t,n=`auto`)=>{if(!e)return t??``;try{let r=new Date(e);if(!Number.isFinite(r.getTime()))return t??``;let i=new Date;return r.toDateString()===i.toDateString()?le(r,n,{fallback:t??``}):ce(r,n,{month:`short`,day:`numeric`,weekday:`short`,hour:`numeric`,minute:`2-digit`})}catch{return t??``}},mt=e=>e===null?`safe`:e>=80?`critical`:e>=50?`warn`:`safe`,ht=e=>e===`5h`?Q(`quota.window.5h`):e===`7d`?Q(`quota.window.7d`):e===`7d-sonnet`?Q(`quota.window.7dSonnet`):e===`7d-opus`?Q(`quota.window.7dOpus`):e===`weekly`?Q(`quota.window.weekly`):e===`daily`?Q(`quota.window.daily`):e===`monthly`?Q(`quota.window.monthly`):e===`credits`?Q(`quota.window.credits`):e===`credits_balance`?Q(`quota.window.creditsBalance`):e===`billing_cycle`?Q(`quota.window.billingCycle`):e===`auto`?Q(`quota.window.auto`):e===`api`?Q(`quota.window.api`):e===`plan_limit`?Q(`quota.window.planLimit`):e===`on_demand`?Q(`quota.window.onDemand`):e===`session`?Q(`quota.window.session`):e===`premium`?Q(`quota.window.premium`):e===`chat`?Q(`quota.window.chat`):e===`completions`?Q(`quota.window.completions`):e===`premium_interactions`?Q(`quota.window.premiumInteractions`):e,gt=e=>{let t=e.toLowerCase().trim();if(t===`5h`)return 18e3;if(t===`7d`||t===`weekly`||t===`7d-sonnet`||t===`7d-opus`)return 604800;if(t===`monthly`)return 2592e3;if(t===`24h`||t===`daily`)return 86400;if(t===`1h`)return 3600;let n=t.match(/^(\d+)h$/);if(n)return parseInt(n[1],10)*3600;let r=t.match(/^(\d+)d$/);return r?parseInt(r[1],10)*86400:null},_t=(e,t,n,r)=>{let i=n;if(i===null&&r&&(i=gt(r)),e===null||t===null||i===null||i<=0)return null;let a=Math.max(0,(t-Date.now())/1e3),o=Math.max(0,Math.min(i,i-a)),s=Math.max(0,Math.min(1,o/i)),c=e/100,l=e>=100&&a>0,u;u=s>.01?Math.min(999,c/s*100):e;let d;d=l?`exhausted`:c<=s?`on-track`:u<=130?`slightly-fast`:`too-fast`;let f=i>=432e3,p=f?86400:3600,m=f?`d`:`h`,h=i/p,g=e/Math.max(o/p,h*.01),_=Number.isFinite(g)?`${Math.min(999.9,Math.max(0,g)).toFixed(1)}%/${m}`:`-`,v=u>100?`+${Math.round(u)}%`:`${Math.round(u)}%`,y=null,b=i/86400;return b>=7&&(y=100/b),{elapsedRatio:s,usageRatio:c,predictedFinalPercent:u,remainingSeconds:a,isExhausted:l,elapsedSeconds:o,totalSeconds:i,status:d,paceRateText:_,predictText:v,dailyAllocationPercent:y}},vt=e=>{switch(e){case`exhausted`:case`too-fast`:return`var(--status-error)`;case`slightly-fast`:return`var(--status-warning)`;case`on-track`:return`var(--status-success)`}},yt=e=>{let t=Math.floor(Math.max(0,Math.floor(e))/60),n=Math.floor(t/60),r=Math.floor(n/24),i=n%24,a=t%60;return r>0?`${r}d ${i}h`:n>0?`${n}h`:t===0?`<1m`:`${a}m`},bt=e=>Math.min(100,Math.max(0,e*100)),xt=[`standalone`,`minimal-ui`,`fullscreen`,`window-controls-overlay`],St=`openchamber.pwaRecentSessions`,Ct=e=>typeof window>`u`||typeof window.matchMedia!=`function`?!1:window.matchMedia(`(display-mode: ${e})`).matches,wt=()=>typeof window>`u`?`browser`:typeof document<`u`&&document.referrer.startsWith(`android-app://`)?`twa`:window.navigator.standalone?`standalone`:xt.find(e=>Ct(e))??`browser`,Tt=864e5,Et=5,Dt=864e5,$=e=>e.time?.updated??e.time?.created??0,Ot=({sessions:e,currentSessionId:t,cutoffDays:n,keepRecent:r=Et,now:i=Date.now()})=>{if(!Array.isArray(e)||n<=0)return[];let a=i-n*Tt,o=[...e].sort((e,t)=>$(t)-$(e)),s=new Set(o.slice(0,r).map(e=>e.id));return o.filter(e=>{if(!e?.id||s.has(e.id)||e.id===t||e.share)return!1;let n=$(e);return n?n<a:!1}).map(e=>e.id)},kt=e=>{let t=typeof e==`object`?e:void 0,r=t?.autoRun!==!1,i=typeof e==`boolean`?e:t?.enabled??!0,a=T(e=>e.currentSessionId),o=T(e=>e.isLoading),s=E(e=>e.activeSessions),c=E(e=>e.hasLoadedFullCatalog),l=n(e=>e.autoDeleteEnabled),u=n(e=>e.autoDeleteAfterDays),d=n(e=>e.sessionRetentionAction),f=n(e=>e.autoDeleteLastRunAt),p=n(e=>e.setAutoDeleteLastRunAt),[h,g]=Y.useState(!1),_=Y.useRef(!1);Y.useEffect(()=>{if(!i||!r||!l||u<=0)return;let e=window.setTimeout(()=>{w(C())},8e3);return()=>window.clearTimeout(e)},[u,l,r,i]);let v=Y.useMemo(()=>u<=0?[]:Ot({sessions:s,currentSessionId:a,cutoffDays:u}),[u,a,s]),y=Y.useCallback(async({force:e=!1}={})=>{if(_.current)return{completedIds:[],failedIds:[],action:d,skippedReason:`running`};if((!l||u<=0)&&!e)return{completedIds:[],failedIds:[],action:d,skippedReason:`disabled`};if(o)return{completedIds:[],failedIds:[],action:d,skippedReason:`loading`};let t=Date.now();if(!e&&f&&t-f<Dt)return{completedIds:[],failedIds:[],action:d,skippedReason:`cooldown`};let{activeSessions:n}=await w(C());if(n.length===0)return{completedIds:[],failedIds:[],action:d,skippedReason:`no-candidates`};let r=Ot({sessions:n,currentSessionId:a,cutoffDays:u,now:t});if(r.length===0)return p(t),{completedIds:[],failedIds:[],action:d,skippedReason:`no-candidates`};_.current=!0,g(!0);try{let e=new Map(n.map(e=>[e.id,e])),t=[],i=[];for(let n of r){let r=e.get(n),a=r?te(r):null;if(!a){i.push(n);continue}try{d===`archive`?await m.updateSession(n,{time:{archived:Date.now()}},a):await m.deleteSession(n,a),t.push(n)}catch{i.push(n)}}return d===`archive`?E.getState().archiveSessions(t):E.getState().removeSessions(t),{completedIds:t,failedIds:i,action:d}}finally{_.current=!1,g(!1),p(Date.now())}},[u,l,f,a,o,d,p]);return Y.useEffect(()=>{i&&r&&(!l||u<=0||o||!c||s.length===0||f&&Date.now()-f<Dt||y())},[u,l,f,r,i,c,s.length,o,y]),{candidates:v,isRunning:h,runCleanup:y,keepRecentCount:Et,action:d}};export{Ee as A,Oe as B,J as C,rt as D,it as E,Te as F,We as G,Le as H,Ce as I,he as J,pe as K,we as L,He as M,Ue as N,je as O,De as P,ke as R,nt as S,$e as T,Re as U,ze as V,Be as W,ot as _,_t as a,G as b,ft as c,vt as d,mt as f,at as g,st as h,bt as i,Ve as j,Se as k,yt as l,Z as m,St as n,ut as o,lt as p,me as q,wt as r,pt as s,kt as t,ht as u,et as v,Ze as w,tt as x,Qe as y,Ae as z};
@@ -1,4 +1,4 @@
1
- import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{_ as t}from"./useUIStore-5agS8bsW.js";import{$t as n,kn as r,xn as i}from"./persistence-oSFWyKgV.js";import{nt as a,rt as o}from"./vendor-base-ui-CnHfUmDN.js";import{a as s,n as c}from"./vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js";import{n as l}from"./vendor-react-DLPElpoQ.js";import{n as u}from"./clipboard-DF5tFLDb.js";import{ko as d}from"./useMobileNavigationStore-a9a3gOnd.js";import{t as f}from"./utils-Dxsi3J3l.js";import{n as p}from"./Icon-DHaR0peD.js";import{t as m}from"./button-DCUMIXDC.js";import{i as h,n as g,t as _}from"./tooltip-xEnco9xY.js";import{n as v}from"./useThemeSystem-DMzWVJaW.js";import{c as y,n as b,o as x,r as S,s as C}from"./markdownTheme-y_Rf6mLa.js";import{i as w}from"./appThemeRegistry-BUHyoCKY.js";import{d as T,n as E,t as D,u as ee}from"./markdown-worker-D-OR2e_G.js";import{t as te}from"./vendor-tanstack-react-virtual-tlDgH6PG.js";var O=e(o(),1),k=l(),A=a(),ne=`w-[min(30rem,calc(100cqw-1rem))] min-w-[280px] max-w-full overflow-hidden rounded-xl shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]`,j={maxWidth:`min(28rem, calc(100cqw - 4ch))`,backgroundColor:`var(--surface-elevated)`,color:`var(--surface-elevated-foreground)`},M=`flex items-center justify-between gap-3 border-b border-[var(--surface-subtle)] px-3 py-2.5`,N=`text-xs font-medium leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,re=`text-xs tabular-nums leading-4 text-muted-foreground md:text-[0.8125rem] md:leading-5`,P=`m-0 list-none divide-y divide-[var(--surface-subtle)] p-0`,F=`${P} max-h-[min(22rem,50vh)] overflow-y-auto`,ie=`${P} w-full`,ae={className:`p-0 rounded-none`,maxHeightClass:`max-h-[46vh]`,disableHorizontal:!0},I=`px-2.5 py-1.5 text-xs leading-4 md:py-2 md:text-[0.8125rem] md:leading-5`,oe=`flex min-w-0 items-center gap-1 text-xs leading-4 text-muted-foreground md:gap-1.5 md:text-[0.8125rem] md:leading-5`,se=`min-w-0 truncate text-xs leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,ce=`inline-flex shrink-0 items-center gap-1 text-xs leading-4 tabular-nums text-muted-foreground md:text-[0.8125rem] md:leading-5`,le=`h-3 w-3 shrink-0 md:h-3.5 md:w-3.5`,ue={in_progress:`text-foreground`,pending:`text-foreground`,completed:`text-muted-foreground line-through`,cancelled:`text-muted-foreground line-through`},L={in_progress:`chat.statusRow.todo.status.inProgress`,pending:`chat.statusRow.todo.status.pending`,completed:`chat.statusRow.todo.status.completed`,cancelled:`chat.statusRow.todo.status.cancelled`},R=e=>{let t=(0,k.c)(26),{todo:n,isActive:r,activeRef:i}=e,{t:a}=u(),o=z.has(n.status)?n.status:`pending`,s=L[o],c;t[0]!==a||t[1]!==s?(c=a(s),t[0]=a,t[1]=s,t[2]=c):c=t[2];let l=c,d;t[3]===o?d=t[4]:(d=o===`in_progress`?(0,A.jsx)(p,{name:`record-circle`,className:`h-3.5 w-3.5 text-[var(--status-info)]`,"aria-hidden":`true`}):o===`completed`?(0,A.jsx)(p,{name:`checkbox-circle`,className:`h-3.5 w-3.5 text-[var(--status-success)]`,"aria-hidden":`true`}):(0,A.jsx)(p,{name:`time`,className:`h-3.5 w-3.5 text-muted-foreground`,"aria-hidden":`true`}),t[3]=o,t[4]=d);let m=d,v=r?`step`:void 0,y=r&&`bg-[var(--surface-muted)] before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-[var(--status-info)]`,b;t[5]===y?b=t[6]:(b=f(`group relative grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] items-start gap-2.5`,I,y),t[5]=y,t[6]=b);let x;t[7]!==m||t[8]!==l?(x=(0,A.jsx)(h,{asChild:!0,children:(0,A.jsx)(`span`,{className:`flex size-4 items-center justify-center`,"aria-label":l,children:m})}),t[7]=m,t[8]=l,t[9]=x):x=t[9];let S;t[10]===l?S=t[11]:(S=(0,A.jsx)(g,{side:`left`,sideOffset:6,children:l}),t[10]=l,t[11]=S);let C;t[12]!==x||t[13]!==S?(C=(0,A.jsxs)(_,{children:[x,S]}),t[12]=x,t[13]=S,t[14]=C):C=t[14];let w=ue[o],T;t[15]===w?T=t[16]:(T=f(`block whitespace-normal break-words`,w),t[15]=w,t[16]=T);let E;t[17]!==T||t[18]!==n.content?(E=(0,A.jsx)(`span`,{className:`min-w-0 flex-1`,children:(0,A.jsx)(`span`,{className:T,children:n.content})}),t[17]=T,t[18]=n.content,t[19]=E):E=t[19];let D;return t[20]!==i||t[21]!==E||t[22]!==v||t[23]!==b||t[24]!==C?(D=(0,A.jsxs)(`li`,{ref:i,"aria-current":v,className:b,children:[C,E]}),t[20]=i,t[21]=E,t[22]=v,t[23]=b,t[24]=C,t[25]=D):D=t[25],D},z=new Set([`in_progress`,`pending`,`completed`,`cancelled`]),B=`image/png`,V=s(`OpenChamberMedia`),H=e=>{let t=e.toLowerCase().split(`;`)[0]?.trim()||B;if(t===`image/jpeg`||t===`image/jpg`)return`jpg`;if(t===`image/webp`)return`webp`;if(t===`image/gif`)return`gif`;if(t===`image/svg+xml`)return`svg`;if(t===`image/png`)return`png`;let n=t.split(`/`)[1];return n&&/^[a-z0-9.+-]+$/i.test(n)?n:`png`},U=(e,t)=>{let n=`image.${H(t)}`,r=(((e||``).trim()||n).split(/[\\/]/).pop()||n).replace(/[^\w.\- ()[\]]+/g,`_`).replace(/^\.+/,``);return r?/\.[a-z0-9]{1,8}$/i.test(r)?r:`${r}.${H(t)}`:n},W=e=>new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{if(typeof r.result==`string`){t(r.result);return}n(Error(`Failed to encode image`))},r.onerror=()=>n(r.error??Error(`Failed to encode image`)),r.readAsDataURL(e)}),de=async e=>{let t=await W(e),n=t.indexOf(`,`);return n>=0?t.slice(n+1):t},fe=(e,t)=>{let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,document.body.appendChild(r),r.click(),document.body.removeChild(r),window.setTimeout(()=>URL.revokeObjectURL(n),1e3)},G=async(e,t)=>{let n=await fetch(e,{signal:t,cache:`no-store`});if(!n.ok)throw Error(`Image fetch failed (${n.status})`);return n.blob()},pe=async(e,t=B)=>{if(!e.naturalWidth||!e.naturalHeight)return null;let n=e.currentSrc||e.src;if(n&&(/^(?:blob:|data:|openchamber-asset:)/i.test(n)||/^https?:/i.test(n)||/^\/api(?=\/|[?#]|$)/.test(n)))try{let e=await G(n);if(e.size>0)return e}catch{}try{let n=document.createElement(`canvas`);n.width=e.naturalWidth,n.height=e.naturalHeight;let r=n.getContext(`2d`);if(!r)return null;r.drawImage(e,0,0);let i=t.startsWith(`image/`)?t:B,a=await new Promise(e=>{n.toBlob(t=>e(t),i===`image/jpg`?`image/jpeg`:i)});return a&&a.size>0?a:null}catch{return null}},me=async(e,t)=>{let n=``;try{return n=await S(e,t??new AbortController().signal),await G(n,t)}finally{n&&C(n)}},he=async(e,t)=>{let n=e.effectiveDirectory??``,i=null;e.prefetchedBlob&&e.prefetchedBlob.size>0&&(i=e.prefetchedBlob);let a=e.displayUrl?.trim();if(!i&&a)try{i=await G(a,t)}catch{i=null}if(!i){let a=e.sourceUrl.trim();if(!a)throw Error(`Image source is empty`);if(/^(?:data|blob):/i.test(a)||/^https?:/i.test(a)||/^\/api(?=\/|[?#]|$)/.test(a))i=await G(a,t);else{let e=y(a,n);if(x(e))try{i=await me(e.path,t)}catch{let n=await r(`/api/fs/raw`,{method:`GET`,cache:`no-store`,query:{path:e.path},signal:t});if(!n.ok)throw Error(`Image source request failed with status ${n.status}`);i=await n.blob()}else i=await G(e.source,t)}}if(!i||i.size<=0)throw Error(`Image is empty`);let o=(e.mimeType||(i.type&&i.type.startsWith(`image/`)?i.type:``)||B).split(`;`)[0].trim()||B;return{blob:i,filename:U(e.filename,o),mimeType:o}},ge=()=>!d()||c===void 0?!1:c.isPluginAvailable(`OpenChamberMedia`),_e=async(e,t)=>{let{blob:r,filename:a,mimeType:o}=await he(e,t);if(ge()){let e=await de(r);return await V.saveImage({dataBase64:e,mimeType:o,filename:a}),`saved`}if(n()){let e=i()?.vscode;if(e?.saveImage){let t=await W(r);return await e.saveImage({fileName:a,dataUrl:t}),`saved`}}return fe(r,a),`downloaded`},ve=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`),ye=e=>e?Object.entries(e).map(([e,t])=>t==null?``:`${e.startsWith(`--`)?e:e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}:${typeof t==`number`?`${t}px`:t};`).join(``):``,K=(e,t,n)=>{let r=e.querySelector(`pre`);r&&(r.style.margin=`0`,r.style.background=`transparent`,r.style.whiteSpace=t?`pre-wrap`:`pre`,t&&(r.style.wordBreak=`break-word`,r.style.overflowWrap=`break-word`));let i=e.querySelector(`code`);if(i){let e=ye(n);e&&i.setAttribute(`style`,`${i.getAttribute(`style`)??``}${e}`)}},be=e=>`<pre><code>${ve(e)}</code></pre>`,xe=e=>{let t=(0,k.c)(21),{code:n,language:r,className:i,style:a,codeStyle:o,wrap:s}=e,c=s!==void 0&&s,{currentTheme:l}=v(),u=O.useRef(null),d;t[0]===l?d=t[1]:(d=b(l),t[0]=l,t[1]=d);let p=d,m,h;t[2]!==n||t[3]!==o||t[4]!==c?(m=()=>{let e=u.current;e&&(e.innerHTML=be(n),K(e,c,o))},h=[n,c,o],t[2]=n,t[3]=o,t[4]=c,t[5]=m,t[6]=h):(m=t[5],h=t[6]),O.useLayoutEffect(m,h);let g,_;t[7]!==n||t[8]!==o||t[9]!==r||t[10]!==c?(g=()=>{let e=u.current;if(!e)return;let t=!0,i=new AbortController;return D(n,(r||`text`).toLowerCase(),{signal:i.signal,priority:`visible`}).then(n=>{!t||!e||!n||(e.innerHTML=n,K(e,c,o))}),()=>{t=!1,i.abort()}},_=[n,r,c,o],t[7]=n,t[8]=o,t[9]=r,t[10]=c,t[11]=g,t[12]=_):(g=t[11],_=t[12]),O.useEffect(g,_);let y;t[13]===i?y=t[14]:(y=f(`typography-code`,i),t[13]=i,t[14]=y);let x=p,S;t[15]!==a||t[16]!==x?(S={...x,...a},t[15]=a,t[16]=x,t[17]=S):S=t[17];let C;return t[18]!==y||t[19]!==S?(C=(0,A.jsx)(`div`,{ref:u,className:y,style:S}),t[18]=y,t[19]=S,t[20]=C):C=t[20],C},Se=e=>{let t=e.replace(/^<file>\s*\n?/,``).replace(/\n?<\/file>\s*$/,``);return t=t.replace(/^\s*\d{5}\|\s?/gm,``),t.trim()},Ce=(e,t=``)=>{if(typeof e==`string`)return e;if(e==null)return t;if(typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`)return String(e);try{return JSON.stringify(e)}catch{return t}},we=e=>e?e.includes(`<diagnostics`)||e.includes(`<file_diagnostics>`)||e.includes(`LSP errors detected`)||e.includes(`This file has errors`):!1,Te=e=>e?e.replace(/\n{0,2}LSP errors detected[\s\S]*?<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/\n{0,2}This file has errors[\s\S]*?<\/file_diagnostics>/g,``).replace(/<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/<file_diagnostics>[\s\S]*?<\/file_diagnostics>/g,``).trim():``,Ee=(e,t)=>!e||typeof e!=`object`?String(e):T(e,t||``),q=e=>{if(typeof e==`string`){let t=e.trim();return t.length>0?t:void 0}if(e&&typeof e==`object`){let t=e.patch;if(typeof t==`string`){let e=t.trim();return e.length>0?e:void 0}}},De=e=>{if(!e||typeof e!=`object`)return;let t=q(e.patch)??q(e.diff);if(t)return t;let n=Array.isArray(e.files)?e.files:[];for(let e of n){if(!e||typeof e!=`object`)continue;let t=q(e.patch)??q(e.diff);if(t)return t}},Oe=e=>{if(!e||typeof e!=`string`)return{data:null,isJson:!1};let t=e.trim();if(!t.startsWith(`{`)&&!t.startsWith(`[`)||!t.endsWith(`}`)&&!t.endsWith(`]`)||t.length<2)return{data:null,isJson:!1};try{let e=JSON.parse(t);return typeof e==`object`&&e?{data:e,isJson:!0}:{data:null,isJson:!1}}catch{return{data:null,isJson:!1}}},ke=(e,t,n)=>{let r=Se(e);if((t===`edit`||t===`multiedit`||t===`write`||t===`apply_patch`)&&we(r)&&(r=Te(r)),(t===`edit`||t===`multiedit`||t===`apply_patch`)&&r.trim().length===0){let e=De(n);if(e)return e}return r},Ae=e=>{let t=e.match(/<type>(file|directory)<\/type>/i)?.[1]?.toLowerCase()??`unknown`,n=(e.match(/<content>([\s\S]*?)<\/content>/i)?.[1]??e).replace(/\r\n/g,`
1
+ import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{_ as t}from"./useUIStore-5agS8bsW.js";import{$t as n,kn as r,xn as i}from"./persistence-oSFWyKgV.js";import{nt as a,rt as o}from"./vendor-base-ui-CnHfUmDN.js";import{a as s,n as c}from"./vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js";import{n as l}from"./vendor-react-DLPElpoQ.js";import{n as u}from"./clipboard-DF5tFLDb.js";import{ko as d}from"./useMobileNavigationStore-DNoNQA4y.js";import{t as f}from"./utils-Dxsi3J3l.js";import{n as p}from"./Icon-DHaR0peD.js";import{t as m}from"./button-DCUMIXDC.js";import{i as h,n as g,t as _}from"./tooltip-xEnco9xY.js";import{n as v}from"./useThemeSystem-DMzWVJaW.js";import{c as y,n as b,o as x,r as S,s as C}from"./markdownTheme-y_Rf6mLa.js";import{i as w}from"./appThemeRegistry-DhaoeTus.js";import{d as T,n as E,t as D,u as ee}from"./markdown-worker-D-OR2e_G.js";import{t as te}from"./vendor-tanstack-react-virtual-tlDgH6PG.js";var O=e(o(),1),k=l(),A=a(),ne=`w-[min(30rem,calc(100cqw-1rem))] min-w-[280px] max-w-full overflow-hidden rounded-xl shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]`,j={maxWidth:`min(28rem, calc(100cqw - 4ch))`,backgroundColor:`var(--surface-elevated)`,color:`var(--surface-elevated-foreground)`},M=`flex items-center justify-between gap-3 border-b border-[var(--surface-subtle)] px-3 py-2.5`,N=`text-xs font-medium leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,re=`text-xs tabular-nums leading-4 text-muted-foreground md:text-[0.8125rem] md:leading-5`,P=`m-0 list-none divide-y divide-[var(--surface-subtle)] p-0`,F=`${P} max-h-[min(22rem,50vh)] overflow-y-auto`,ie=`${P} w-full`,ae={className:`p-0 rounded-none`,maxHeightClass:`max-h-[46vh]`,disableHorizontal:!0},I=`px-2.5 py-1.5 text-xs leading-4 md:py-2 md:text-[0.8125rem] md:leading-5`,oe=`flex min-w-0 items-center gap-1 text-xs leading-4 text-muted-foreground md:gap-1.5 md:text-[0.8125rem] md:leading-5`,se=`min-w-0 truncate text-xs leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,ce=`inline-flex shrink-0 items-center gap-1 text-xs leading-4 tabular-nums text-muted-foreground md:text-[0.8125rem] md:leading-5`,le=`h-3 w-3 shrink-0 md:h-3.5 md:w-3.5`,ue={in_progress:`text-foreground`,pending:`text-foreground`,completed:`text-muted-foreground line-through`,cancelled:`text-muted-foreground line-through`},L={in_progress:`chat.statusRow.todo.status.inProgress`,pending:`chat.statusRow.todo.status.pending`,completed:`chat.statusRow.todo.status.completed`,cancelled:`chat.statusRow.todo.status.cancelled`},R=e=>{let t=(0,k.c)(26),{todo:n,isActive:r,activeRef:i}=e,{t:a}=u(),o=z.has(n.status)?n.status:`pending`,s=L[o],c;t[0]!==a||t[1]!==s?(c=a(s),t[0]=a,t[1]=s,t[2]=c):c=t[2];let l=c,d;t[3]===o?d=t[4]:(d=o===`in_progress`?(0,A.jsx)(p,{name:`record-circle`,className:`h-3.5 w-3.5 text-[var(--status-info)]`,"aria-hidden":`true`}):o===`completed`?(0,A.jsx)(p,{name:`checkbox-circle`,className:`h-3.5 w-3.5 text-[var(--status-success)]`,"aria-hidden":`true`}):(0,A.jsx)(p,{name:`time`,className:`h-3.5 w-3.5 text-muted-foreground`,"aria-hidden":`true`}),t[3]=o,t[4]=d);let m=d,v=r?`step`:void 0,y=r&&`bg-[var(--surface-muted)] before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-[var(--status-info)]`,b;t[5]===y?b=t[6]:(b=f(`group relative grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] items-start gap-2.5`,I,y),t[5]=y,t[6]=b);let x;t[7]!==m||t[8]!==l?(x=(0,A.jsx)(h,{asChild:!0,children:(0,A.jsx)(`span`,{className:`flex size-4 items-center justify-center`,"aria-label":l,children:m})}),t[7]=m,t[8]=l,t[9]=x):x=t[9];let S;t[10]===l?S=t[11]:(S=(0,A.jsx)(g,{side:`left`,sideOffset:6,children:l}),t[10]=l,t[11]=S);let C;t[12]!==x||t[13]!==S?(C=(0,A.jsxs)(_,{children:[x,S]}),t[12]=x,t[13]=S,t[14]=C):C=t[14];let w=ue[o],T;t[15]===w?T=t[16]:(T=f(`block whitespace-normal break-words`,w),t[15]=w,t[16]=T);let E;t[17]!==T||t[18]!==n.content?(E=(0,A.jsx)(`span`,{className:`min-w-0 flex-1`,children:(0,A.jsx)(`span`,{className:T,children:n.content})}),t[17]=T,t[18]=n.content,t[19]=E):E=t[19];let D;return t[20]!==i||t[21]!==E||t[22]!==v||t[23]!==b||t[24]!==C?(D=(0,A.jsxs)(`li`,{ref:i,"aria-current":v,className:b,children:[C,E]}),t[20]=i,t[21]=E,t[22]=v,t[23]=b,t[24]=C,t[25]=D):D=t[25],D},z=new Set([`in_progress`,`pending`,`completed`,`cancelled`]),B=`image/png`,V=s(`OpenChamberMedia`),H=e=>{let t=e.toLowerCase().split(`;`)[0]?.trim()||B;if(t===`image/jpeg`||t===`image/jpg`)return`jpg`;if(t===`image/webp`)return`webp`;if(t===`image/gif`)return`gif`;if(t===`image/svg+xml`)return`svg`;if(t===`image/png`)return`png`;let n=t.split(`/`)[1];return n&&/^[a-z0-9.+-]+$/i.test(n)?n:`png`},U=(e,t)=>{let n=`image.${H(t)}`,r=(((e||``).trim()||n).split(/[\\/]/).pop()||n).replace(/[^\w.\- ()[\]]+/g,`_`).replace(/^\.+/,``);return r?/\.[a-z0-9]{1,8}$/i.test(r)?r:`${r}.${H(t)}`:n},W=e=>new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{if(typeof r.result==`string`){t(r.result);return}n(Error(`Failed to encode image`))},r.onerror=()=>n(r.error??Error(`Failed to encode image`)),r.readAsDataURL(e)}),de=async e=>{let t=await W(e),n=t.indexOf(`,`);return n>=0?t.slice(n+1):t},fe=(e,t)=>{let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,document.body.appendChild(r),r.click(),document.body.removeChild(r),window.setTimeout(()=>URL.revokeObjectURL(n),1e3)},G=async(e,t)=>{let n=await fetch(e,{signal:t,cache:`no-store`});if(!n.ok)throw Error(`Image fetch failed (${n.status})`);return n.blob()},pe=async(e,t=B)=>{if(!e.naturalWidth||!e.naturalHeight)return null;let n=e.currentSrc||e.src;if(n&&(/^(?:blob:|data:|openchamber-asset:)/i.test(n)||/^https?:/i.test(n)||/^\/api(?=\/|[?#]|$)/.test(n)))try{let e=await G(n);if(e.size>0)return e}catch{}try{let n=document.createElement(`canvas`);n.width=e.naturalWidth,n.height=e.naturalHeight;let r=n.getContext(`2d`);if(!r)return null;r.drawImage(e,0,0);let i=t.startsWith(`image/`)?t:B,a=await new Promise(e=>{n.toBlob(t=>e(t),i===`image/jpg`?`image/jpeg`:i)});return a&&a.size>0?a:null}catch{return null}},me=async(e,t)=>{let n=``;try{return n=await S(e,t??new AbortController().signal),await G(n,t)}finally{n&&C(n)}},he=async(e,t)=>{let n=e.effectiveDirectory??``,i=null;e.prefetchedBlob&&e.prefetchedBlob.size>0&&(i=e.prefetchedBlob);let a=e.displayUrl?.trim();if(!i&&a)try{i=await G(a,t)}catch{i=null}if(!i){let a=e.sourceUrl.trim();if(!a)throw Error(`Image source is empty`);if(/^(?:data|blob):/i.test(a)||/^https?:/i.test(a)||/^\/api(?=\/|[?#]|$)/.test(a))i=await G(a,t);else{let e=y(a,n);if(x(e))try{i=await me(e.path,t)}catch{let n=await r(`/api/fs/raw`,{method:`GET`,cache:`no-store`,query:{path:e.path},signal:t});if(!n.ok)throw Error(`Image source request failed with status ${n.status}`);i=await n.blob()}else i=await G(e.source,t)}}if(!i||i.size<=0)throw Error(`Image is empty`);let o=(e.mimeType||(i.type&&i.type.startsWith(`image/`)?i.type:``)||B).split(`;`)[0].trim()||B;return{blob:i,filename:U(e.filename,o),mimeType:o}},ge=()=>!d()||c===void 0?!1:c.isPluginAvailable(`OpenChamberMedia`),_e=async(e,t)=>{let{blob:r,filename:a,mimeType:o}=await he(e,t);if(ge()){let e=await de(r);return await V.saveImage({dataBase64:e,mimeType:o,filename:a}),`saved`}if(n()){let e=i()?.vscode;if(e?.saveImage){let t=await W(r);return await e.saveImage({fileName:a,dataUrl:t}),`saved`}}return fe(r,a),`downloaded`},ve=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`),ye=e=>e?Object.entries(e).map(([e,t])=>t==null?``:`${e.startsWith(`--`)?e:e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}:${typeof t==`number`?`${t}px`:t};`).join(``):``,K=(e,t,n)=>{let r=e.querySelector(`pre`);r&&(r.style.margin=`0`,r.style.background=`transparent`,r.style.whiteSpace=t?`pre-wrap`:`pre`,t&&(r.style.wordBreak=`break-word`,r.style.overflowWrap=`break-word`));let i=e.querySelector(`code`);if(i){let e=ye(n);e&&i.setAttribute(`style`,`${i.getAttribute(`style`)??``}${e}`)}},be=e=>`<pre><code>${ve(e)}</code></pre>`,xe=e=>{let t=(0,k.c)(21),{code:n,language:r,className:i,style:a,codeStyle:o,wrap:s}=e,c=s!==void 0&&s,{currentTheme:l}=v(),u=O.useRef(null),d;t[0]===l?d=t[1]:(d=b(l),t[0]=l,t[1]=d);let p=d,m,h;t[2]!==n||t[3]!==o||t[4]!==c?(m=()=>{let e=u.current;e&&(e.innerHTML=be(n),K(e,c,o))},h=[n,c,o],t[2]=n,t[3]=o,t[4]=c,t[5]=m,t[6]=h):(m=t[5],h=t[6]),O.useLayoutEffect(m,h);let g,_;t[7]!==n||t[8]!==o||t[9]!==r||t[10]!==c?(g=()=>{let e=u.current;if(!e)return;let t=!0,i=new AbortController;return D(n,(r||`text`).toLowerCase(),{signal:i.signal,priority:`visible`}).then(n=>{!t||!e||!n||(e.innerHTML=n,K(e,c,o))}),()=>{t=!1,i.abort()}},_=[n,r,c,o],t[7]=n,t[8]=o,t[9]=r,t[10]=c,t[11]=g,t[12]=_):(g=t[11],_=t[12]),O.useEffect(g,_);let y;t[13]===i?y=t[14]:(y=f(`typography-code`,i),t[13]=i,t[14]=y);let x=p,S;t[15]!==a||t[16]!==x?(S={...x,...a},t[15]=a,t[16]=x,t[17]=S):S=t[17];let C;return t[18]!==y||t[19]!==S?(C=(0,A.jsx)(`div`,{ref:u,className:y,style:S}),t[18]=y,t[19]=S,t[20]=C):C=t[20],C},Se=e=>{let t=e.replace(/^<file>\s*\n?/,``).replace(/\n?<\/file>\s*$/,``);return t=t.replace(/^\s*\d{5}\|\s?/gm,``),t.trim()},Ce=(e,t=``)=>{if(typeof e==`string`)return e;if(e==null)return t;if(typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`)return String(e);try{return JSON.stringify(e)}catch{return t}},we=e=>e?e.includes(`<diagnostics`)||e.includes(`<file_diagnostics>`)||e.includes(`LSP errors detected`)||e.includes(`This file has errors`):!1,Te=e=>e?e.replace(/\n{0,2}LSP errors detected[\s\S]*?<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/\n{0,2}This file has errors[\s\S]*?<\/file_diagnostics>/g,``).replace(/<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/<file_diagnostics>[\s\S]*?<\/file_diagnostics>/g,``).trim():``,Ee=(e,t)=>!e||typeof e!=`object`?String(e):T(e,t||``),q=e=>{if(typeof e==`string`){let t=e.trim();return t.length>0?t:void 0}if(e&&typeof e==`object`){let t=e.patch;if(typeof t==`string`){let e=t.trim();return e.length>0?e:void 0}}},De=e=>{if(!e||typeof e!=`object`)return;let t=q(e.patch)??q(e.diff);if(t)return t;let n=Array.isArray(e.files)?e.files:[];for(let e of n){if(!e||typeof e!=`object`)continue;let t=q(e.patch)??q(e.diff);if(t)return t}},Oe=e=>{if(!e||typeof e!=`string`)return{data:null,isJson:!1};let t=e.trim();if(!t.startsWith(`{`)&&!t.startsWith(`[`)||!t.endsWith(`}`)&&!t.endsWith(`]`)||t.length<2)return{data:null,isJson:!1};try{let e=JSON.parse(t);return typeof e==`object`&&e?{data:e,isJson:!0}:{data:null,isJson:!1}}catch{return{data:null,isJson:!1}}},ke=(e,t,n)=>{let r=Se(e);if((t===`edit`||t===`multiedit`||t===`write`||t===`apply_patch`)&&we(r)&&(r=Te(r)),(t===`edit`||t===`multiedit`||t===`apply_patch`)&&r.trim().length===0){let e=De(n);if(e)return e}return r},Ae=e=>{let t=e.match(/<type>(file|directory)<\/type>/i)?.[1]?.toLowerCase()??`unknown`,n=(e.match(/<content>([\s\S]*?)<\/content>/i)?.[1]??e).replace(/\r\n/g,`
2
2
  `).split(`
3
3
  `),r=e=>/\(\s*File has more lines\..*offset.*\)/i.test(e.trim());return{type:t,lines:n.map(e=>{let n=e.trim(),i=n.startsWith(`(`)&&n.endsWith(`)`)||r(n);if(t!==`directory`){let t=e.match(/^(\d+):\s?(.*)$/);if(t){let e=t[2],n=e.trim(),i=n.startsWith(`(`)&&n.endsWith(`)`)||r(n);return{lineNumber:i?null:Number(t[1]),text:e,isInfo:i}}}return{lineNumber:null,text:e,isInfo:i}}).filter((e,t,n)=>{if(e.text.trim().length>0)return!0;let r=n[t-1],i=n[t+1],a=!!(r?.isInfo||i?.isInfo),o=e.lineNumber!==null;return!(a&&o)})}},je=(e,n)=>{try{let r=e.trim().split(`
4
4
  `).filter(Boolean);if(r.length===0)return null;let i=[];return r.forEach(e=>{let t=e.match(/^(\s*)(.+)$/);if(t){let[,e,n]=t,r=Math.floor(e.length/2),a=!n.endsWith(`/`);i.push({name:n.replace(/\/$/,``),depth:r,isFile:a})}}),(0,A.jsx)(`div`,{className:f(`w-full min-w-0 font-mono space-y-0.5`,n?.unstyled?null:`p-3 bg-muted/20 rounded-xl border border-border/30`),style:t.tool.popup,children:i.map((e,t)=>(0,A.jsx)(`div`,{className:`min-w-0`,style:{paddingLeft:`${e.depth*20}px`},children:e.isFile?(0,A.jsx)(`span`,{className:`text-foreground/90 block truncate`,children:e.name}):(0,A.jsxs)(`span`,{className:`font-semibold text-foreground block truncate`,children:[e.name,`/`]})},t))})}catch{return null}},Me={backgroundColor:`var(--status-info)`,opacity:.6},Ne=(e,n,r)=>{try{let i=e.trim().split(`
package/dist/index.html CHANGED
@@ -552,7 +552,7 @@
552
552
  opacity: 0.72;
553
553
  }
554
554
  </style>
555
- <script type="module" crossorigin src="/assets/main-B9LVDYC3.js"></script>
555
+ <script type="module" crossorigin src="/assets/main-D4aa2ZJz.js"></script>
556
556
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
557
557
  <link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
558
558
  <link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
@@ -568,7 +568,7 @@
568
568
  <link rel="modulepreload" crossorigin href="/assets/gitApiHttp-SLrnr8a5.js">
569
569
  <link rel="modulepreload" crossorigin href="/assets/terminalApi-_NnfkxgP.js">
570
570
  <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-n4QAk1lU.js">
571
- <link rel="stylesheet" crossorigin href="/assets/src-BcPciZGI.css">
571
+ <link rel="stylesheet" crossorigin href="/assets/src-C8jn0x69.css">
572
572
  </head>
573
573
  <body class="h-full bg-background text-foreground">
574
574
  <!-- Keep the startup layer outside #root. React replaces every child of
@@ -74,7 +74,7 @@
74
74
  }
75
75
  </style>
76
76
 
77
- <script type="module" crossorigin src="/assets/miniChat-nHXgh499.js"></script>
77
+ <script type="module" crossorigin src="/assets/miniChat-4N2-z2vf.js"></script>
78
78
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
79
79
  <link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
80
80
  <link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
@@ -90,7 +90,7 @@
90
90
  <link rel="modulepreload" crossorigin href="/assets/gitApiHttp-SLrnr8a5.js">
91
91
  <link rel="modulepreload" crossorigin href="/assets/terminalApi-_NnfkxgP.js">
92
92
  <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-n4QAk1lU.js">
93
- <link rel="stylesheet" crossorigin href="/assets/src-BcPciZGI.css">
93
+ <link rel="stylesheet" crossorigin href="/assets/src-C8jn0x69.css">
94
94
  </head>
95
95
  <body class="h-full bg-background text-foreground">
96
96
  <div id="root" class="h-full">
package/dist/mobile.html CHANGED
@@ -63,7 +63,7 @@
63
63
  })();
64
64
  </script>
65
65
 
66
- <script type="module" crossorigin src="/assets/mobile-DheffaWK.js"></script>
66
+ <script type="module" crossorigin src="/assets/mobile-C-RRGcDW.js"></script>
67
67
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
68
68
  <link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
69
69
  <link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
@@ -79,7 +79,7 @@
79
79
  <link rel="modulepreload" crossorigin href="/assets/gitApiHttp-SLrnr8a5.js">
80
80
  <link rel="modulepreload" crossorigin href="/assets/terminalApi-_NnfkxgP.js">
81
81
  <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-n4QAk1lU.js">
82
- <link rel="stylesheet" crossorigin href="/assets/src-BcPciZGI.css">
82
+ <link rel="stylesheet" crossorigin href="/assets/src-C8jn0x69.css">
83
83
  </head>
84
84
  <body class="h-full bg-background text-foreground">
85
85
  <div id="root" class="h-full"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openchambery/web",
3
- "version": "1.18.2-beta.11",
3
+ "version": "1.18.2-beta.13",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./server/index.js",
@@ -9,7 +9,7 @@ This module contains the OpenChamber message-stream WebSocket protocol and runti
9
9
  - `packages/web/server/lib/event-stream/global-ws-bridge.js`: browser-facing global WS bridge that subscribes clients to the shared global hub.
10
10
  - `packages/web/server/lib/event-stream/directory-ws-bridge.js`: browser-facing per-directory WS bridge that owns one scoped upstream reader per connection.
11
11
  - `packages/web/server/lib/event-stream/protocol.js`: path constants, SSE envelope parsing, and WebSocket frame serialization helpers.
12
- - `packages/web/server/lib/event-stream/diff-summary.js`: pure outbound FileDiff helpers. L1 message/session `summary.diffs` project to `diffCount`/`hasDiffs` (array removed). `session.diff` event frames still keep file/status/additions/deletions and drop patch bodies. `summarizeFileDiff(s)` remains for explicit L2-style file lists.
12
+ - `packages/web/server/lib/event-stream/diff-summary.js`: pure outbound FileDiff helpers. L1 message/session `summary.diffs` keep a slim file list `{ file, status?, additions, deletions }` plus additive `diffCount`/`hasDiffs` (never patch/before/after/from/to). `session.diff` event frames still keep file/status/additions/deletions and drop patch bodies. `summarizeFileDiff(s)` remains for explicit L2-style file lists.
13
13
  - `packages/web/server/lib/event-stream/upstream-reader.js`: reusable upstream SSE reader with event-id tracking, stall recovery, and reconnect handling.
14
14
  - `packages/web/server/lib/event-stream/runtime.js`: thin WebSocket server runtime for upgrade handling and path dispatch to the global/directory bridges.
15
15
  - `packages/web/server/lib/event-stream/protocol.test.js`: unit tests for protocol helpers.
@@ -26,7 +26,7 @@ The following APIs are exported by their owning modules. `event-stream/index.js`
26
26
  - `MESSAGE_STREAM_WS_HEARTBEAT_INTERVAL_MS`: heartbeat interval for browser-facing WS connections.
27
27
  - `parseSseEventEnvelope(block)`: parses an SSE block into `{ eventId, directory, payload }`.
28
28
  - `sendMessageStreamWsFrame(socket, payload)`: serializes and sends a JSON WS frame.
29
- - `sendMessageStreamWsEvent(socket, payload, options)`: sends an event frame with optional `eventId` and `directory`. Outbound `session.diff` keeps file/status/additions/deletions only (no full patch bodies). Message/session `summary.diffs` are L1-projected to `diffCount`/`hasDiffs` (file array removed).
29
+ - `sendMessageStreamWsEvent(socket, payload, options)`: sends an event frame with optional `eventId` and `directory`. Outbound `session.diff` keeps file/status/additions/deletions only (no full patch bodies). Message/session `summary.diffs` are L1-projected to a slim file list plus additive `diffCount`/`hasDiffs` (patch bodies never leave the host).
30
30
 
31
31
  ### Runtime helpers
32
32
  - `createGlobalMessageStreamHub(...)`: creates a shared `/global/event` upstream SSE hub with event/status subscribers and bounded event-id replay.
@@ -2,8 +2,9 @@
2
2
  // Outbound FileDiff summarization for message-stream fan-out and Host L1.
3
3
  //
4
4
  // L1 (ordinary first-packet / SSE / exact message GET):
5
- // project `info.summary.diffs` arrays to `{ diffCount, hasDiffs }` and remove
6
- // the file array entirely. Never ship patch bodies on these paths.
5
+ // keep `info.summary.diffs` as a slim file list
6
+ // `{ file, status?, additions, deletions }` plus additive
7
+ // `diffCount` / `hasDiffs` markers. Never ship patch bodies on these paths.
7
8
  //
8
9
  // Explicit L2/L3 APIs may still use summarizeFileDiff(s) for file-list / patch
9
10
  // responses. Pure JS — do not import UI TypeScript from the server package.
@@ -28,9 +29,6 @@ const hasHeavyDiffBody = (diff) => {
28
29
  * Reduce a FileDiff / SnapshotFileDiff to preview-safe scalars only.
29
30
  * Drops patch / before / after / from / to and any other large body fields.
30
31
  * Already-summary objects keep identity.
31
- *
32
- * Retained for explicit L2 file-list APIs; L1 message paths must use
33
- * `projectMessageSummaryDiffCounts` instead and never keep a file array.
34
32
  */
35
33
  export function summarizeFileDiff(diff) {
36
34
  if (!diff || typeof diff !== 'object' || Array.isArray(diff)) {
@@ -69,13 +67,14 @@ export function summarizeFileDiffs(diffs) {
69
67
  }
70
68
 
71
69
  /**
72
- * L1 projection: replace `summary.diffs` with count/marker scalars.
70
+ * L1 projection: keep `summary.diffs` as a slim file-list array and set
71
+ * additive `diffCount` / `hasDiffs` markers. Drops patch/before/after/from/to.
73
72
  * Keeps every other lightweight summary field. Identity when unchanged.
74
73
  *
75
74
  * @param {unknown} owner message info / session info / summary-bearing object
76
75
  * @returns {unknown}
77
76
  */
78
- export const projectMessageSummaryDiffCounts = (owner) => {
77
+ export const projectMessageSummaryDiffSlim = (owner) => {
79
78
  if (!owner || typeof owner !== 'object' || Array.isArray(owner)) {
80
79
  return owner;
81
80
  }
@@ -89,23 +88,33 @@ export const projectMessageSummaryDiffCounts = (owner) => {
89
88
  return owner;
90
89
  }
91
90
 
92
- const diffs = summary.diffs;
93
- const diffCount = Array.isArray(diffs) ? diffs.length : 0;
91
+ const rawDiffs = summary.diffs;
92
+ const slimDiffs = Array.isArray(rawDiffs) ? summarizeFileDiffs(rawDiffs) : [];
93
+ const diffCount = slimDiffs.length;
94
94
  const hasDiffs = diffCount > 0;
95
95
 
96
- const nextSummary = { ...summary };
97
- delete nextSummary.diffs;
98
- nextSummary.diffCount = diffCount;
99
- nextSummary.hasDiffs = hasDiffs;
96
+ const diffsUnchanged = slimDiffs === rawDiffs;
97
+ const markersMatch = summary.diffCount === diffCount && summary.hasDiffs === hasDiffs;
98
+ if (diffsUnchanged && markersMatch) {
99
+ return owner;
100
+ }
100
101
 
101
102
  return {
102
103
  ...owner,
103
- summary: nextSummary,
104
+ summary: {
105
+ ...summary,
106
+ diffs: slimDiffs,
107
+ diffCount,
108
+ hasDiffs,
109
+ },
104
110
  };
105
111
  };
106
112
 
107
- /** @deprecated Prefer projectMessageSummaryDiffCounts — L1 removes the file array. */
108
- export const summarizeMessageDiffSnapshots = projectMessageSummaryDiffCounts;
113
+ /** @deprecated Prefer projectMessageSummaryDiffSlimsame L1 slim-list behavior. */
114
+ export const projectMessageSummaryDiffCounts = projectMessageSummaryDiffSlim;
115
+
116
+ /** @deprecated Prefer projectMessageSummaryDiffSlim — L1 keeps slim file list + markers. */
117
+ export const summarizeMessageDiffSnapshots = projectMessageSummaryDiffSlim;
109
118
 
110
119
  /**
111
120
  * Summarize FileDiff bodies on outbound event payloads.
@@ -114,7 +123,7 @@ export const summarizeMessageDiffSnapshots = projectMessageSummaryDiffCounts;
114
123
  * - `session.diff` with legacy `properties.diff` or current `data.diff`
115
124
  * (keeps file/status/additions/deletions; drops patch bodies)
116
125
  * - message/session objects carrying `summary.diffs` under properties/data info
117
- * (L1: projects to diffCount/hasDiffs and removes the array)
126
+ * (L1: slim file list + diffCount/hasDiffs; never patch bodies)
118
127
  *
119
128
  * Non-diff events keep identity.
120
129
  */
@@ -173,7 +182,7 @@ export function summarizeOutboundEventPayload(payload) {
173
182
 
174
183
  // Common shape: properties.info.summary.diffs
175
184
  if (body.info && typeof body.info === 'object' && !Array.isArray(body.info)) {
176
- const nextInfo = projectMessageSummaryDiffCounts(body.info);
185
+ const nextInfo = projectMessageSummaryDiffSlim(body.info);
177
186
  if (nextInfo !== body.info) {
178
187
  next = {
179
188
  ...next,
@@ -188,7 +197,7 @@ export function summarizeOutboundEventPayload(payload) {
188
197
  }
189
198
 
190
199
  // Rare: properties.summary.diffs directly on the properties/data body
191
- const nextBody = projectMessageSummaryDiffCounts(body);
200
+ const nextBody = projectMessageSummaryDiffSlim(body);
192
201
  if (nextBody !== body) {
193
202
  next = {
194
203
  ...next,
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest';
2
2
 
3
3
  import {
4
4
  projectMessageSummaryDiffCounts,
5
+ projectMessageSummaryDiffSlim,
5
6
  summarizeFileDiff,
6
7
  summarizeFileDiffs,
7
8
  summarizeOutboundEventPayload,
@@ -49,34 +50,41 @@ describe('summarizeFileDiffs', () => {
49
50
  });
50
51
  });
51
52
 
52
- describe('projectMessageSummaryDiffCounts', () => {
53
- it('replaces summary.diffs with diffCount/hasDiffs and drops the array', () => {
53
+ describe('projectMessageSummaryDiffSlim', () => {
54
+ it('keeps slim summary.diffs and sets diffCount/hasDiffs', () => {
54
55
  const owner = {
55
56
  id: 'msg_1',
56
57
  summary: {
57
58
  title: 'turn',
58
59
  diffs: [
59
60
  { file: 'a.ts', additions: 1, deletions: 0, patch: '@@' },
60
- { file: 'b.ts', additions: 2, deletions: 1 },
61
+ { file: 'b.ts', additions: 2, deletions: 1, before: 'x', after: 'y' },
61
62
  ],
62
63
  },
63
64
  };
64
65
 
65
- const next = projectMessageSummaryDiffCounts(owner);
66
+ const next = projectMessageSummaryDiffSlim(owner);
66
67
  expect(next).not.toBe(owner);
67
68
  expect(next.summary).toEqual({
68
69
  title: 'turn',
70
+ diffs: [
71
+ { file: 'a.ts', additions: 1, deletions: 0 },
72
+ { file: 'b.ts', additions: 2, deletions: 1 },
73
+ ],
69
74
  diffCount: 2,
70
75
  hasDiffs: true,
71
76
  });
72
- expect(next.summary.diffs).toBeUndefined();
77
+ expect(JSON.stringify(next)).not.toContain('patch');
78
+ expect(JSON.stringify(next)).not.toContain('"before"');
79
+ expect(JSON.stringify(next)).not.toContain('"after"');
73
80
  });
74
81
 
75
- it('projects empty arrays to diffCount 0 / hasDiffs false', () => {
82
+ it('projects empty arrays to slim list + diffCount 0 / hasDiffs false', () => {
76
83
  const owner = {
77
84
  summary: { diffs: [] },
78
85
  };
79
- expect(projectMessageSummaryDiffCounts(owner).summary).toEqual({
86
+ expect(projectMessageSummaryDiffSlim(owner).summary).toEqual({
87
+ diffs: [],
80
88
  diffCount: 0,
81
89
  hasDiffs: false,
82
90
  });
@@ -84,7 +92,22 @@ describe('projectMessageSummaryDiffCounts', () => {
84
92
 
85
93
  it('keeps identity when summary has no diffs key', () => {
86
94
  const owner = { summary: { title: 'x', diffCount: 3, hasDiffs: true } };
87
- expect(projectMessageSummaryDiffCounts(owner)).toBe(owner);
95
+ expect(projectMessageSummaryDiffSlim(owner)).toBe(owner);
96
+ });
97
+
98
+ it('keeps identity when diffs already slim and markers match', () => {
99
+ const owner = {
100
+ summary: {
101
+ diffs: [{ file: 'a.ts', additions: 1, deletions: 0 }],
102
+ diffCount: 1,
103
+ hasDiffs: true,
104
+ },
105
+ };
106
+ expect(projectMessageSummaryDiffSlim(owner)).toBe(owner);
107
+ });
108
+
109
+ it('exports projectMessageSummaryDiffCounts as a compatible alias', () => {
110
+ expect(projectMessageSummaryDiffCounts).toBe(projectMessageSummaryDiffSlim);
88
111
  });
89
112
  });
90
113
 
@@ -137,7 +160,7 @@ describe('summarizeOutboundEventPayload', () => {
137
160
  }]);
138
161
  });
139
162
 
140
- it('projects message.updated info.summary.diffs to L1 count/marker', () => {
163
+ it('projects message.updated info.summary.diffs to L1 slim list + markers', () => {
141
164
  const payload = {
142
165
  type: 'message.updated',
143
166
  properties: {
@@ -149,6 +172,8 @@ describe('summarizeOutboundEventPayload', () => {
149
172
  additions: 1,
150
173
  deletions: 0,
151
174
  patch: '@@',
175
+ from: 'blob-a',
176
+ to: 'blob-b',
152
177
  }],
153
178
  },
154
179
  },
@@ -157,10 +182,12 @@ describe('summarizeOutboundEventPayload', () => {
157
182
 
158
183
  const next = summarizeOutboundEventPayload(payload);
159
184
  expect(next.properties.info.summary).toEqual({
185
+ diffs: [{ file: 'a.ts', additions: 1, deletions: 0 }],
160
186
  diffCount: 1,
161
187
  hasDiffs: true,
162
188
  });
163
- expect(next.properties.info.summary.diffs).toBeUndefined();
189
+ expect(JSON.stringify(next)).not.toContain('patch');
190
+ expect(JSON.stringify(next)).not.toContain('blob-a');
164
191
  });
165
192
 
166
193
  it('returns identity for session.status', () => {
@@ -223,7 +223,7 @@ describe('event stream protocol helpers', () => {
223
223
  expect(rawPayload.length).toBeLessThan(64 * 1024);
224
224
  });
225
225
 
226
- it('projects message.updated summary.diffs to L1 count/marker on outbound frames', () => {
226
+ it('projects message.updated summary.diffs to L1 slim list + markers on outbound frames', () => {
227
227
  let rawPayload = null;
228
228
  const socket = {
229
229
  readyState: 1,
@@ -246,6 +246,8 @@ describe('event stream protocol helpers', () => {
246
246
  additions: 2,
247
247
  deletions: 1,
248
248
  patch: '@@ heavy patch body @@\n' + 'y'.repeat(1000),
249
+ before: 'old',
250
+ after: 'new',
249
251
  }],
250
252
  },
251
253
  },
@@ -255,12 +257,73 @@ describe('event stream protocol helpers', () => {
255
257
  expect(sent).toBe(true);
256
258
  const frame = JSON.parse(rawPayload);
257
259
  expect(frame.payload.properties.info.summary).toEqual({
260
+ diffs: [{
261
+ file: 'a.ts',
262
+ status: 'modified',
263
+ additions: 2,
264
+ deletions: 1,
265
+ }],
258
266
  diffCount: 1,
259
267
  hasDiffs: true,
260
268
  });
261
- expect(frame.payload.properties.info.summary.diffs).toBeUndefined();
262
269
  expect(JSON.stringify(frame)).not.toContain('patch');
263
- expect(JSON.stringify(frame)).not.toContain('a.ts');
270
+ expect(JSON.stringify(frame)).not.toContain('"before"');
271
+ expect(JSON.stringify(frame)).not.toContain('"after"');
272
+ });
273
+
274
+ it('keeps L1 message.updated serialization under 256KiB for a 463-file / ~14MB patch summary', () => {
275
+ let rawPayload = null;
276
+ const socket = {
277
+ readyState: 1,
278
+ send(payload) {
279
+ rawPayload = payload;
280
+ },
281
+ };
282
+
283
+ const patchBody = 'P'.repeat(Math.floor((14 * 1024 * 1024) / 463));
284
+ const diffs = Array.from({ length: 463 }, (_, i) => ({
285
+ file: `src/generated/file-${i}.ts`,
286
+ status: 'modified',
287
+ additions: i % 7,
288
+ deletions: i % 3,
289
+ patch: `${patchBody}-${i}`,
290
+ before: `before-${i}`,
291
+ after: `after-${i}`,
292
+ from: `from-${i}`,
293
+ to: `to-${i}`,
294
+ }));
295
+
296
+ const sent = sendMessageStreamWsEvent(socket, {
297
+ type: 'message.updated',
298
+ properties: {
299
+ info: {
300
+ id: 'msg_huge',
301
+ sessionID: 'ses_huge',
302
+ role: 'assistant',
303
+ summary: { title: 'huge', diffs },
304
+ },
305
+ },
306
+ });
307
+
308
+ expect(sent).toBe(true);
309
+ const frame = JSON.parse(rawPayload);
310
+ const summary = frame.payload.properties.info.summary;
311
+ expect(summary.diffCount).toBe(463);
312
+ expect(summary.hasDiffs).toBe(true);
313
+ expect(summary.diffs).toHaveLength(463);
314
+ expect(summary.diffs[0]).toEqual({
315
+ file: 'src/generated/file-0.ts',
316
+ status: 'modified',
317
+ additions: 0,
318
+ deletions: 0,
319
+ });
320
+ expect(rawPayload).not.toContain(patchBody.slice(0, 64));
321
+ expect(rawPayload).not.toContain('"patch"');
322
+ expect(rawPayload).not.toContain('"before"');
323
+ expect(rawPayload).not.toContain('"after"');
324
+ expect(rawPayload).not.toContain('"from"');
325
+ expect(rawPayload).not.toContain('"to"');
326
+ expect(Buffer.byteLength(rawPayload, 'utf8')).toBeLessThan(256 * 1024);
264
327
  });
265
328
 
266
329
  it('leaves ordinary session.status events unchanged', () => {
@@ -28,7 +28,7 @@ This module provides OpenCode server integration utilities for the web server ru
28
28
  - `packages/web/server/lib/opencode/static-routes-runtime.js`: static asset/SPA fallback route registration and manifest route wiring.
29
29
  - `packages/web/server/lib/opencode/feature-routes-runtime.js`: feature route composition runtime for dynamic import-backed config/skill/provider route registration.
30
30
  - `packages/web/server/lib/conversations/`: combined create-session-and-prompt orchestration (OpenChamber-owned, registered before generic proxy).
31
- - `packages/web/server/lib/session-turn-pages/`: turn-window session message pagination (`GET /api/openchamber/sessions/:sessionID/messages`), anchor reconcile (`GET .../messages/reconcile`), Changes L2/L3 (`GET .../changes`), and exact message L1 projection (`GET /api/session/:sessionID/message/:messageID`); loops official OpenCode `session.messages` for turn pages and head→anchor gap recovery with continuation/budgets/`resetRequired`; all registered before generic proxy. L1 first-packet / SSE / exact-message paths project `summary.diffs` to `diffCount`/`hasDiffs` only. See `session-turn-pages/DOCUMENTATION.md`.
31
+ - `packages/web/server/lib/session-turn-pages/`: turn-window session message pagination (`GET /api/openchamber/sessions/:sessionID/messages`), anchor reconcile (`GET .../messages/reconcile`), Changes L2/L3 (`GET .../changes`), and exact message L1 projection (`GET /api/session/:sessionID/message/:messageID`); loops official OpenCode `session.messages` for turn pages and head→anchor gap recovery with continuation/budgets/`resetRequired`; all registered before generic proxy. L1 first-packet / SSE / exact-message paths keep `summary.diffs` as a slim `{ file, status?, additions, deletions }` list plus additive `diffCount`/`hasDiffs` (patch bodies stay on L3). See `session-turn-pages/DOCUMENTATION.md`.
32
32
  - `packages/web/server/lib/opencode/opencode-resolution-runtime.js`: OpenCode binary resolution snapshot runtime for settings routes and diagnostics.
33
33
  - `packages/web/server/lib/opencode/tunnel-wiring-runtime.js`: active loopback-port wiring shared by pairing/LAN URLs and the private relay host.
34
34
  - `packages/web/server/lib/opencode/startup-pipeline-runtime.js`: server startup tail orchestration runtime for terminal/proxy/static/start-listen flow.