@openchambery/web 1.18.2-beta.12 → 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.
- package/dist/assets/{AssistantView-De54yQXX.js → AssistantView-Bbqfj9CK.js} +1 -1
- package/dist/assets/{ChatContainer-9cw5pRwD.js → ChatContainer-hDTv6UXl.js} +4 -4
- package/dist/assets/{DiagramView-DmZ4jKmn.js → DiagramView-1hFDtyEy.js} +1 -1
- package/dist/assets/{MarkdownRendererImpl-B6zceXlX.js → MarkdownRendererImpl-5BLw0qYH.js} +1 -1
- package/dist/assets/{MobileDetailNavigation-fdO6J2xj.js → MobileDetailNavigation-DIyVGM50.js} +1 -1
- package/dist/assets/{MobileShareBridge-Czlandhf.js → MobileShareBridge-BQM-WOll.js} +1 -1
- package/dist/assets/{MobileSurface-DppgVqKs.js → MobileSurface-KZ-kuSM-.js} +1 -1
- package/dist/assets/{MultiRunWindow-CvMgGQLj.js → MultiRunWindow-DPOSSmY_.js} +1 -1
- package/dist/assets/{OverlayScrollbar-DwdKeYSb.js → OverlayScrollbar-C2pMNVMM.js} +1 -1
- package/dist/assets/{SettingsView-cfFQW5LJ.js → SettingsView-DxL07Iba.js} +1 -1
- package/dist/assets/{SettingsWindow-DebnkbG9.js → SettingsWindow-DJ2o4zvh.js} +1 -1
- package/dist/assets/{TerminalView-CWBmPQJ_.js → TerminalView-BB3tvloy.js} +1 -1
- package/dist/assets/{ToolOutputDialog-CyKqI69B.js → ToolOutputDialog-D7DqChuM.js} +1 -1
- package/dist/assets/{appThemeRegistry-CmZlBPov.js → appThemeRegistry-DhaoeTus.js} +2 -2
- package/dist/assets/{context-menu-Bbd153RL.js → context-menu-D88vCGyB.js} +1 -1
- package/dist/assets/{gitApi-BlInY34O.js → gitApi-DVNC4iYD.js} +1 -1
- package/dist/assets/{insertionBoundaries-CiTMpUdk.js → insertionBoundaries-hcIB6RSd.js} +1 -1
- package/dist/assets/{main-CUN5Brht.js → main-CQrMAdMF.js} +4 -4
- package/dist/assets/{main-DQxV4rh8.js → main-D4aa2ZJz.js} +2 -2
- package/dist/assets/{miniChat-Bx2cMtJS.js → miniChat-4N2-z2vf.js} +2 -2
- package/dist/assets/{mobile-BvWi_rq9.js → mobile-C-RRGcDW.js} +2 -2
- package/dist/assets/{multirun-DaUWpTWM.js → multirun-Co8LbTjb.js} +1 -1
- package/dist/assets/{projectMeta-DtoKE1uJ.js → projectMeta-D-ncdr5Z.js} +1 -1
- package/dist/assets/{radio-BiawVf-W.js → radio-CD4P-ogh.js} +1 -1
- package/dist/assets/{renderElectronMiniChatApp-BPvk5Kd6.js → renderElectronMiniChatApp-D5QcQTL0.js} +2 -2
- package/dist/assets/{renderMobileApp-D7V_905J.js → renderMobileApp-CnZZVbHU.js} +4 -4
- package/dist/assets/{runtimeEndpointReset-DpaiHzaP.js → runtimeEndpointReset-BQ5F5VZS.js} +2 -2
- package/dist/assets/{sortable-tabs-strip-BEalEtjO.js → sortable-tabs-strip-DQsv96ke.js} +1 -1
- package/dist/assets/{useAppFontEffects-DOb592S6.js → useAppFontEffects-DygV6JSW.js} +2 -2
- package/dist/assets/{useDesktopWindowControlsLayout-COCcsUGy.js → useDesktopWindowControlsLayout-Cj63sNDg.js} +1 -1
- package/dist/assets/{useEffectiveDirectory-DXGFGuv0.js → useEffectiveDirectory-Dc904Fjg.js} +1 -1
- package/dist/assets/{useMobileNavigationStore-D5XHlGZB.js → useMobileNavigationStore-DNoNQA4y.js} +2 -2
- package/dist/assets/{useSessionAutoCleanup-DvK0S9G6.js → useSessionAutoCleanup-bBkcz_hu.js} +1 -1
- package/dist/assets/{useWorkerHighlightedLines-BTFe-rdw.js → useWorkerHighlightedLines-mhBD0Do9.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/mini-chat.html +1 -1
- package/dist/mobile.html +1 -1
- package/package.json +1 -1
- package/server/lib/event-stream/DOCUMENTATION.md +2 -2
- package/server/lib/event-stream/diff-summary.js +28 -19
- package/server/lib/event-stream/diff-summary.test.js +37 -10
- package/server/lib/event-stream/protocol.test.js +66 -3
- package/server/lib/opencode/DOCUMENTATION.md +1 -1
- package/server/lib/session-turn-pages/DOCUMENTATION.md +3 -3
- package/server/lib/session-turn-pages/reconcile.routes.test.js +6 -2
- package/server/lib/session-turn-pages/reconcile.service.test.js +6 -2
- package/server/lib/session-turn-pages/routes.js +3 -3
- package/server/lib/session-turn-pages/routes.test.js +41 -13
- package/server/lib/session-turn-pages/service.js +4 -2
- 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-D5XHlGZB.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-BiawVf-W.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};
|
package/dist/assets/{useWorkerHighlightedLines-BTFe-rdw.js → useWorkerHighlightedLines-mhBD0Do9.js}
RENAMED
|
@@ -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-D5XHlGZB.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-CmZlBPov.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,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`),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,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`),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-
|
|
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">
|
package/dist/mini-chat.html
CHANGED
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
}
|
|
75
75
|
</style>
|
|
76
76
|
|
|
77
|
-
<script type="module" crossorigin src="/assets/miniChat-
|
|
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">
|
package/dist/mobile.html
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
})();
|
|
64
64
|
</script>
|
|
65
65
|
|
|
66
|
-
<script type="module" crossorigin src="/assets/mobile-
|
|
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">
|
package/package.json
CHANGED
|
@@ -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`
|
|
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` (
|
|
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
|
-
//
|
|
6
|
-
//
|
|
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:
|
|
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
|
|
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
|
|
93
|
-
const
|
|
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
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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:
|
|
104
|
+
summary: {
|
|
105
|
+
...summary,
|
|
106
|
+
diffs: slimDiffs,
|
|
107
|
+
diffCount,
|
|
108
|
+
hasDiffs,
|
|
109
|
+
},
|
|
104
110
|
};
|
|
105
111
|
};
|
|
106
112
|
|
|
107
|
-
/** @deprecated Prefer
|
|
108
|
-
export const
|
|
113
|
+
/** @deprecated Prefer projectMessageSummaryDiffSlim — same 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:
|
|
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 =
|
|
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 =
|
|
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('
|
|
53
|
-
it('
|
|
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 =
|
|
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.
|
|
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(
|
|
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(
|
|
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
|
|
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.
|
|
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
|
|
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('
|
|
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
|
|
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.
|
|
@@ -79,11 +79,11 @@ Every turn-page response summarizes `tool`, `reasoning`, and `file` parts plus m
|
|
|
79
79
|
|
|
80
80
|
| Layer | Surface | Payload |
|
|
81
81
|
|---|---|---|
|
|
82
|
-
| **L1** | Turn pages, reconcile response pages, message/session SSE fan-out, exact `GET /api/session/:sessionID/message/:messageID` | Any `info.summary.diffs` **array** is projected to `summary.diffCount: number`
|
|
82
|
+
| **L1** | Turn pages, reconcile response pages, message/session SSE fan-out, exact `GET /api/session/:sessionID/message/:messageID` | Any `info.summary.diffs` **array** is projected to a **slim file list** `[{ file, status?, additions, deletions }]` plus additive markers `summary.diffCount: number` and `summary.hasDiffs: boolean`. Patch/before/after/from/to and other heavy bodies are stripped. Other lightweight summary fields are preserved. `diffCount` equals the slim array length; `hasDiffs === diffCount > 0`. Consumers may use either the slim array or the markers. |
|
|
83
83
|
| **L2** | `GET /api/openchamber/sessions/:sessionID/changes?messageID=` (no `file`) | Host reads official `session.message` locally, returns only `{ files: [{ file, status?, additions, deletions }] }`. Never returns patch/before/after/from/to or the full message envelope. |
|
|
84
84
|
| **L3** | Same route with `file=` | Host calls official `session.diff({ sessionID, messageID, directory })`, returns `{ diff: SnapshotFileDiff }` for the exact `file` string match (includes that file's patch). No match → HTTP 404 `{ error: 'change file not found', code: 'change_not_found' }`. |
|
|
85
85
|
|
|
86
|
-
Exact message GET keeps the official `{ info, parts }` response shape and only applies L1 summary projection so materialize/recovery never relays
|
|
86
|
+
Exact message GET keeps the official `{ info, parts }` response shape and only applies L1 summary projection so materialize/recovery never relays raw multi-megabyte patch bodies through the generic proxy. Abort/45s timeout semantics match the turn-page routes. Global `/api` auth still applies.
|
|
87
87
|
|
|
88
88
|
Changes query guards: `sessionID` / `messageID` length `1..512`; optional `file` length `1..4096` and rejects control characters / NUL. Failures: invalid params → 400, abort → 499, upstream/malformed → 502. Logs carry only safe flags and ids — never paths, patch bodies, or tokens.
|
|
89
89
|
|
|
@@ -100,7 +100,7 @@ Rules:
|
|
|
100
100
|
- Slim tool input keeps only short locator and task-identity fields (path, pattern, query, command, `subagent_type`, `description`, skill `name` / `id`). Slim metadata keeps `sessionId`, skill `name`, plus edit `additions`/`deletions`. Projection still drops result bodies, task prompts, patches, and large write payloads.
|
|
101
101
|
- Assistant `text` stays intact. User rows are no longer wholesale pass-through: their `file` parts are projected; other user parts stay as-is.
|
|
102
102
|
- `file` projection keeps already-present size/width/height (top-level or `metadata`). `byteSize` is derived from a data URL when present. PNG/GIF/JPEG/WebP headers may fill missing `width`/`height`. Unknown dimensions omit those fields.
|
|
103
|
-
- Message `info.summary.diffs` is L1-projected to `diffCount` / `hasDiffs` (
|
|
103
|
+
- Message `info.summary.diffs` is L1-projected to a slim file list plus `diffCount` / `hasDiffs` (never patch bodies). Reconcile preserves full parts and applies this same L1 summary projection to response-page byte budgeting and serialization; raw upstream scan budgets retain raw bytes. Clients that need a dedicated file-list envelope or per-file patches use the Changes L2/L3 API.
|
|
104
104
|
- A slim `file` part is a reference, not renderable content. Clients must hydrate the full message (`session.message` by `messageID`) before painting or editing the attachment. Do not treat slim file metadata as a complete part.
|
|
105
105
|
- Records that gain nothing from projection keep their original object reference, so identity-based change detection downstream still works.
|
|
106
106
|
- Projection applies to every turn-page response, including first packet, prepend, and explicit cursors (`before` present). Reconcile routes return full parts, unchanged.
|