@spencerboucher/switchyard 0.0.0-stage → 0.3.0
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/LICENSE +21 -0
- package/README.md +161 -2
- package/dist/bridge/switchyard-bridge.js +105 -0
- package/dist/switchyard.mjs +18207 -0
- package/package.json +52 -4
- package/web-dist/apple-touch-icon.png +0 -0
- package/web-dist/assets/AutomationView-Bt_v8JDx.js +2 -0
- package/web-dist/assets/AutomationView-Bt_v8JDx.js.map +1 -0
- package/web-dist/assets/InteractionCard-BRI9KgrO.js +4 -0
- package/web-dist/assets/InteractionCard-BRI9KgrO.js.map +1 -0
- package/web-dist/assets/Markdown-jXkvZeRp.js +31 -0
- package/web-dist/assets/Markdown-jXkvZeRp.js.map +1 -0
- package/web-dist/assets/Menu-Cqil5qVF.js +2 -0
- package/web-dist/assets/Menu-Cqil5qVF.js.map +1 -0
- package/web-dist/assets/Overlay-B9h5oAe6.js +2 -0
- package/web-dist/assets/Overlay-B9h5oAe6.js.map +1 -0
- package/web-dist/assets/SegmentedControl-ChdVilXb.js +2 -0
- package/web-dist/assets/SegmentedControl-ChdVilXb.js.map +1 -0
- package/web-dist/assets/TextArea-BsQHOQMe.js +2 -0
- package/web-dist/assets/TextArea-BsQHOQMe.js.map +1 -0
- package/web-dist/assets/arrow-left-C6YWM6y6.js +2 -0
- package/web-dist/assets/arrow-left-C6YWM6y6.js.map +1 -0
- package/web-dist/assets/attention-VkuGuoSf.js +2 -0
- package/web-dist/assets/attention-VkuGuoSf.js.map +1 -0
- package/web-dist/assets/automations-BY88rXFv.js +2 -0
- package/web-dist/assets/automations-BY88rXFv.js.map +1 -0
- package/web-dist/assets/board-OzxtnPgh.js +10 -0
- package/web-dist/assets/board-OzxtnPgh.js.map +1 -0
- package/web-dist/assets/calendar-clock-B8zE4JsX.js +2 -0
- package/web-dist/assets/calendar-clock-B8zE4JsX.js.map +1 -0
- package/web-dist/assets/chevron-right-evVLS6hq.js +2 -0
- package/web-dist/assets/chevron-right-evVLS6hq.js.map +1 -0
- package/web-dist/assets/code-BR4PKt8F.js +8 -0
- package/web-dist/assets/code-BR4PKt8F.js.map +1 -0
- package/web-dist/assets/copy-oWgGHmkS.js +2 -0
- package/web-dist/assets/copy-oWgGHmkS.js.map +1 -0
- package/web-dist/assets/describe-CRXLn3O6.js +5 -0
- package/web-dist/assets/describe-CRXLn3O6.js.map +1 -0
- package/web-dist/assets/dist-C4YmDHPG.js +56 -0
- package/web-dist/assets/dist-C4YmDHPG.js.map +1 -0
- package/web-dist/assets/enroll-C9-fBIKO.js +2 -0
- package/web-dist/assets/enroll-C9-fBIKO.js.map +1 -0
- package/web-dist/assets/external-link-3jjTxo92.js +2 -0
- package/web-dist/assets/external-link-3jjTxo92.js.map +1 -0
- package/web-dist/assets/hand-UPoHamrn.js +2 -0
- package/web-dist/assets/hand-UPoHamrn.js.map +1 -0
- package/web-dist/assets/index-B11DJFHW.js +11 -0
- package/web-dist/assets/index-B11DJFHW.js.map +1 -0
- package/web-dist/assets/index-DGGOgcLZ.css +2 -0
- package/web-dist/assets/jsx-runtime-D13aM9HY.js +2 -0
- package/web-dist/assets/jsx-runtime-D13aM9HY.js.map +1 -0
- package/web-dist/assets/key-round-VDbE9E4X.js +2 -0
- package/web-dist/assets/key-round-VDbE9E4X.js.map +1 -0
- package/web-dist/assets/link-2-CaMlUDRG.js +2 -0
- package/web-dist/assets/link-2-CaMlUDRG.js.map +1 -0
- package/web-dist/assets/logic-D_Eq9DMW.js +2 -0
- package/web-dist/assets/logic-D_Eq9DMW.js.map +1 -0
- package/web-dist/assets/more-BUvq82hI.js +2 -0
- package/web-dist/assets/more-BUvq82hI.js.map +1 -0
- package/web-dist/assets/now-DR2wt1DG.js +2 -0
- package/web-dist/assets/now-DR2wt1DG.js.map +1 -0
- package/web-dist/assets/pencil-DI8QbCN8.js +2 -0
- package/web-dist/assets/pencil-DI8QbCN8.js.map +1 -0
- package/web-dist/assets/play-CjoDg3ws.js +2 -0
- package/web-dist/assets/play-CjoDg3ws.js.map +1 -0
- package/web-dist/assets/plus-BLP-wIYD.js +2 -0
- package/web-dist/assets/plus-BLP-wIYD.js.map +1 -0
- package/web-dist/assets/presence-05bJD5G3.js +2 -0
- package/web-dist/assets/presence-05bJD5G3.js.map +1 -0
- package/web-dist/assets/save-DEvZPWlS.js +2 -0
- package/web-dist/assets/save-DEvZPWlS.js.map +1 -0
- package/web-dist/assets/search-C6cn5WOo.js +2 -0
- package/web-dist/assets/search-C6cn5WOo.js.map +1 -0
- package/web-dist/assets/send-CFwekPNi.js +2 -0
- package/web-dist/assets/send-CFwekPNi.js.map +1 -0
- package/web-dist/assets/server-SxFxIScj.js +2 -0
- package/web-dist/assets/server-SxFxIScj.js.map +1 -0
- package/web-dist/assets/settings-C4tDpSCU.js +7 -0
- package/web-dist/assets/settings-C4tDpSCU.js.map +1 -0
- package/web-dist/assets/states-DrTQuYXw.js +2 -0
- package/web-dist/assets/states-DrTQuYXw.js.map +1 -0
- package/web-dist/assets/trash-C6X2OLrI.js +2 -0
- package/web-dist/assets/trash-C6X2OLrI.js.map +1 -0
- package/web-dist/assets/useNow-ChB9z-N6.js +2 -0
- package/web-dist/assets/useNow-ChB9z-N6.js.map +1 -0
- package/web-dist/icon-192.png +0 -0
- package/web-dist/icon-512.png +0 -0
- package/web-dist/icon.svg +12 -0
- package/web-dist/index.html +25 -0
- package/web-dist/manifest.webmanifest +1 -0
- package/web-dist/maskable-512.png +0 -0
- package/web-dist/registerSW.js +1 -0
- package/web-dist/sw.js +2 -0
- package/web-dist/sw.js.map +1 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{_ as e,i as t,m as n,n as r,t as i}from"./jsx-runtime-D13aM9HY.js";var a=e(n(),1),o=e=>{let t,n=new Set,r=(e,r)=>{let i=typeof e==`function`?e(t):e;if(!Object.is(i,t)){let e=t;t=r??(typeof i!=`object`||!i)?i:Object.assign({},t,i),n.forEach(n=>n(t,e))}},i=()=>t,a={setState:r,getState:i,getInitialState:()=>o,subscribe:e=>(n.add(e),()=>n.delete(e))},o=t=e(r,i,a);return a},s=(e=>e?o(e):o),c=e=>e;function ee(e,t=c){let n=a.useSyncExternalStore(e.subscribe,a.useCallback(()=>t(e.getState()),[e,t]),()=>t(e.getInitialState()));return a.useDebugValue(n),n}var l=e=>{let t=s(e),n=e=>ee(t,e);return Object.assign(n,t),n},u=(e=>e?l(e):l),d=class extends Error{code;status;details;constructor(e,t,n,r){super(t),this.name=`ApiClientError`,this.code=e,this.status=n,this.details=r}};function te(e,t){return e instanceof d&&(t===void 0||e.code===t)}function f(e){return e instanceof Error?e.message:String(e)}var p=new Set;function ne(e){return p.add(e),()=>p.delete(e)}function re(e,t){if(!t)return e;let n=new URLSearchParams;for(let[e,r]of Object.entries(t))r!=null&&n.set(e,String(r));let r=n.toString();return r?`${e}${e.includes(`?`)?`&`:`?`}${r}`:e}async function m(e,t={}){let n=t.method??(t.body===void 0?`GET`:`POST`),r={Accept:`application/json`,"X-Switchyard-Request":`1`,...t.headers},i;t.body!==void 0&&(r[`Content-Type`]=`application/json`,i=JSON.stringify(t.body));let a;try{a=await fetch(re(e,t.query),{method:n,headers:r,body:i,credentials:`include`,signal:t.signal})}catch(e){throw e instanceof DOMException&&e.name===`AbortError`?e:new d(`network`,`Could not reach the coordinator`,0)}let o=await a.text(),s;if(o)try{s=JSON.parse(o)}catch{s=void 0}if(!a.ok){let e=ie(s),t=e?new d(e.code,e.message,a.status,e.details):new d(a.status===401?`unauthorized`:`http`,`Request failed (${a.status}${a.statusText?` ${a.statusText}`:``})`,a.status);if(a.status===401)for(let e of p)e(t.code);throw t}return s}function ie(e){if(!e||typeof e!=`object`)return null;let t=e.error;if(!t||typeof t!=`object`)return null;let{code:n,message:r,details:i}=t;return typeof n==`string`?{code:n,message:typeof r==`string`?r:n,details:i}:null}var h=(e,t,n)=>m(e,{method:`GET`,query:t,signal:n}),ae=(e,t)=>m(e,{method:`POST`,body:t??{}}),oe=(e,t)=>m(e,{method:`PATCH`,body:t}),se=(e,t)=>m(e,{method:`DELETE`,body:t}),ce=new Set([`starting`,`running`,`waiting_input`]);function g(e,t,n){return`${e}:${t}:${n}`}function _(e){return e.node!==null||e.webRenderer}function le(){return{seq:null,hosts:{},projects:{},checkouts:{},workspaces:{},profiles:{},sessions:{},tasks:{},runs:{},automations:{},attention:{},interactions:{},panels:{},devices:{},adapters:{},occurrences:{},diagnostics:[],dispatchPaused:!1}}function ue(){return{...le(),transcripts:{},streaming:{}}}function v(){return{items:[],loaded:!1,loading:!1,hasMore:!1,stale:!1,error:null}}function y(e){let t={};for(let n of e)t[n.id]=n;return t}function b(e,t,n){return{...e,[t]:n}}function x(e,t){if(!(t in e))return e;let n={...e};return delete n[t],n}function S(e,t,n){let r={};for(let e of n.panels)_(e)&&(r[g(e.sessionId,e.adapterId,e.slot)]=e);let i={};for(let[t,n]of Object.entries(e.transcripts))i[t]={...n,stale:!0};return{...e,seq:t,hosts:y(n.hosts),projects:y(n.projects),checkouts:y(n.checkouts),workspaces:y(n.workspaces),profiles:y(n.profiles),sessions:y(n.sessions),tasks:y(n.tasks),runs:y(n.runs),automations:y(n.automations),attention:y(n.attention.filter(e=>e.resolvedAt===null)),interactions:y(n.interactions),panels:r,devices:y(n.devices),adapters:{...n.adapters},dispatchPaused:n.dispatchPaused,transcripts:i,streaming:{}}}function de(e){return{hosts:Object.values(e.hosts),projects:Object.values(e.projects),checkouts:Object.values(e.checkouts),workspaces:Object.values(e.workspaces),profiles:Object.values(e.profiles),sessions:Object.values(e.sessions),tasks:Object.values(e.tasks),runs:Object.values(e.runs),automations:Object.values(e.automations),attention:Object.values(e.attention),interactions:Object.values(e.interactions),panels:Object.values(e.panels),devices:Object.values(e.devices),adapters:e.adapters,dispatchPaused:e.dispatchPaused}}function C(e,t){if(t.length===0)return e;let n=new Map;for(let t of e)n.set(t.id,t);for(let e of t)n.set(e.id,e);return[...n.values()].sort((e,t)=>e.order-t.order||e.id.localeCompare(t.id))}function w(e,t,n,r){let i=e.transcripts[t]??v(),a=!r.older&&i.stale?[]:i.items,o={...i,items:C(a,n),loaded:!0,loading:!1,stale:r.older?i.stale:!1,error:null,hasMore:r.older||!i.loaded||i.stale?r.hasMore:i.hasMore};return{...e,transcripts:{...e.transcripts,[t]:o}}}function fe(e,t){let n=e.transcripts[t.sessionId]??v(),r={...e.transcripts,[t.sessionId]:{...n,items:C(n.items,[t])}},i=x(e.streaming,t.id);return{...e,transcripts:r,streaming:i}}function T(e,t){return e.seq!==null&&t.seq<=e.seq?e:{...me(e,t.type,t.data),seq:t.seq}}function pe(e,t){let n=e;for(let e of[...t].sort((e,t)=>e.seq-t.seq))n=T(n,e);return n}function me(e,t,n){switch(t){case`host.updated`:{let t=n;return{...e,hosts:b(e.hosts,t.id,t)}}case`project.updated`:{let t=n;return{...e,projects:b(e.projects,t.id,t)}}case`project.deleted`:{let t=n;return{...e,projects:x(e.projects,t.id)}}case`checkout.updated`:{let t=n;return{...e,checkouts:b(e.checkouts,t.id,t)}}case`workspace.updated`:{let t=n;return{...e,workspaces:t.archivedAt?x(e.workspaces,t.id):b(e.workspaces,t.id,t)}}case`workspace.removed`:{let t=n;return{...e,workspaces:x(e.workspaces,t.id)}}case`profile.updated`:{let t=n;return{...e,profiles:b(e.profiles,t.id,t)}}case`session.updated`:{let t=n,r={...e,sessions:b(e.sessions,t.id,t)};return ce.has(t.runtime)?r:ge(r,t.id)}case`transcript.item`:return fe(e,n);case`interaction.updated`:{let t=n,r=e.interactions[t.id];return r&&r.revision>t.revision?e:{...e,interactions:b(e.interactions,t.id,t)}}case`panel.updated`:{let t=n,r=g(t.sessionId,t.adapterId,t.slot);return{...e,panels:_(t)?b(e.panels,r,t):x(e.panels,r)}}case`adapters.updated`:{let t=n;return{...e,adapters:{...e.adapters,[t.hostId]:t.adapters}}}case`diagnostic`:{let t=n;return{...e,diagnostics:[...e.diagnostics,t].slice(-100)}}case`task.updated`:{let t=n;return{...e,tasks:b(e.tasks,t.id,t)}}case`task.deleted`:{let t=n;return{...e,tasks:x(e.tasks,t.id)}}case`run.updated`:{let t=n;return{...e,runs:b(e.runs,t.id,t)}}case`automation.updated`:{let t=n;return{...e,automations:b(e.automations,t.id,t)}}case`automation.deleted`:{let t=n,r={...e.occurrences};return delete r[t.id],{...e,automations:x(e.automations,t.id),occurrences:r}}case`occurrence.created`:{let t=n,r=(e.occurrences[t.automationId]??[]).filter(e=>e.id!==t.id);return{...e,occurrences:{...e.occurrences,[t.automationId]:[t,...r].slice(0,50)}}}case`attention.updated`:{let t=n;return{...e,attention:t.resolvedAt?x(e.attention,t.id):b(e.attention,t.id,t)}}case`device.updated`:{let t=n;return{...e,devices:t.revokedAt?x(e.devices,t.id):b(e.devices,t.id,t)}}case`settings.updated`:{let t=n;return{...e,dispatchPaused:t.dispatchPaused}}default:return e}}function he(e,t){let n=e.streaming[t.itemId]??{sessionId:t.sessionId,itemId:t.itemId,order:t.order??null,text:``,thinking:``,toolArgs:``,toolOutput:``},r=t.kind===`text`?`text`:t.kind===`thinking`?`thinking`:t.kind===`tool_args`?`toolArgs`:`toolOutput`,i={...n,order:n.order??t.order??null,[r]:n[r]+t.delta};return{...e,streaming:{...e.streaming,[t.itemId]:i}}}function ge(e,t){let n={},r=!1;for(let[i,a]of Object.entries(e.streaming))a.sessionId===t?r=!0:n[i]=a;return r?{...e,streaming:n}:e}function E(e,t){let n=Array.isArray(e)?e:e.items??[];return{items:n,hasMore:(Array.isArray(e)?void 0:e.hasMore)??n.length>=t}}var D=new Map,O=u()((e,t)=>({...ue(),hydrated:!1,synced:!1,connection:{state:`connecting`,lastSyncedAt:null,attempts:0},hydrateFromCache(n,r,i){t().synced||e(e=>({...S(e,n,r),hydrated:!0,connection:{...e.connection,lastSyncedAt:e.connection.lastSyncedAt??i}}))},applySnapshot(t,n){e(e=>({...S(e,t,n),hydrated:!0,synced:!0,connection:{...e.connection,lastSyncedAt:new Date().toISOString()}}))},applyReplay(t,n){e(e=>{let r=pe(e,n);return{...r,seq:Math.max(r.seq??0,t),hydrated:!0,synced:!0,connection:{...e.connection,lastSyncedAt:new Date().toISOString()}}})},applyEvent(t){e(e=>({...T(e,t),connection:{...e.connection,lastSyncedAt:new Date().toISOString()}}))},applyStream(t){e(e=>he(e,t))},setConnection(t){e(e=>({connection:{...e.connection,...t}}))},upsertInteraction(t){e(e=>{let n=e.interactions[t.id];return n&&n.revision>t.revision?{}:{interactions:{...e.interactions,[t.id]:t}}})},loadTranscript(n,r){let i=t().transcripts[n];if(i?.loaded&&!i.stale&&!r?.force)return Promise.resolve();let a=`${n}:newest`,o=D.get(a);if(o)return o;k(e,n,{loading:!0,error:null});let s=h(`/api/sessions/${encodeURIComponent(n)}/transcript`,{limit:200}).then(t=>{let r=E(t,200);e(e=>w(e,n,r.items,{hasMore:r.hasMore??!1,older:!1}))}).catch(t=>k(e,n,{loading:!1,error:f(t)})).finally(()=>D.delete(a));return D.set(a,s),s},loadOlderTranscript(n){let r=t().transcripts[n];if(!r?.loaded||!r.hasMore||r.items.length===0)return Promise.resolve();let i=r.items[0].order,a=`${n}:before:${i}`,o=D.get(a);if(o)return o;k(e,n,{loading:!0,error:null});let s=h(`/api/sessions/${encodeURIComponent(n)}/transcript`,{before:i,limit:200}).then(t=>{let r=E(t,200);e(e=>w(e,n,r.items,{hasMore:r.hasMore??!1,older:!0}))}).catch(t=>k(e,n,{loading:!1,error:f(t)})).finally(()=>D.delete(a));return D.set(a,s),s},reset(){e({...ue(),hydrated:!1,synced:!1,connection:{state:`connecting`,lastSyncedAt:null,attempts:0}})}}));function k(e,t,n){e(e=>({transcripts:{...e.transcripts,[t]:{...e.transcripts[t]??v(),...n}}}))}var _e=O;function ve(e){return Object.values(e).filter(e=>e.resolvedAt===null).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}function ye(e){let t=0;for(let n of Object.values(e))!n.resolvedAt&&!n.acknowledgedAt&&t++;return t}function be(e,t){return Object.values(e).filter(e=>e.sessionId===t&&e.state===`pending`).sort((e,t)=>e.createdAt.localeCompare(t.createdAt))}function A(e,t){return Object.values(e).filter(e=>e.taskId===t).sort((e,t)=>t.attempt-e.attempt||t.createdAt.localeCompare(e.createdAt))}function xe(e,t){return Object.values(e).filter(e=>e.sessionId===t).sort((e,t)=>e.adapterId.localeCompare(t.adapterId)||e.slot.localeCompare(t.slot))}function Se(e,t){return Object.values(e).filter(e=>e.sessionId===t)}var Ce=()=>O(e=>e.connection),we=e=>O(t=>e?t.sessions[e]:void 0),Te=e=>O(t=>e?t.tasks[e]:void 0);function Ee(){let e=O(e=>e.projects);return(0,a.useMemo)(()=>Object.values(e).sort((e,t)=>e.name.localeCompare(t.name)),[e])}function De(){let e=O(e=>e.hosts);return(0,a.useMemo)(()=>Object.values(e).filter(e=>e.revokedAt===null).sort((e,t)=>e.name.localeCompare(t.name)),[e])}function Oe(){let e=O(e=>e.attention);return(0,a.useMemo)(()=>ve(e),[e])}function ke(){return O(e=>ye(e.attention))}function Ae(e){let t=O(e=>e.interactions);return(0,a.useMemo)(()=>e?be(t,e):[],[t,e])}function je(e){let t=O(e=>e.runs);return(0,a.useMemo)(()=>e?A(t,e):[],[t,e])}function Me(e){let t=O(e=>e.panels);return(0,a.useMemo)(()=>e?xe(t,e):[],[t,e])}function Ne(e){let t=O(e=>e.streaming);return(0,a.useMemo)(()=>e?Se(t,e):[],[t,e])}var Pe=v();function Fe(e){let t=O(t=>e?t.transcripts[e]:void 0),n=O(e=>e.loadTranscript),r=!!e&&(!t||(!t.loaded||t.stale)&&!t.loading&&!t.error);return(0,a.useEffect)(()=>{r&&e&&n(e)},[r,e,n]),t??Pe}var j={name:`circle-alert`,size:24,node:[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`12`,x2:`12`,y1:`8`,y2:`12`,key:`1pkeuh`}],[`line`,{x1:`12`,x2:`12.01`,y1:`16`,y2:`16`,key:`4dfq90`}]],aliases:[`alert-circle`]};j.node;var M=r(j),N={name:`inbox`,size:24,node:[[`polyline`,{points:`22 12 16 12 14 15 10 15 8 12 2 12`,key:`o97t9d`}],[`path`,{d:`M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z`,key:`oot6mr`}]]};N.node;var P=r(N),F={name:`message-circle-question-mark`,size:24,node:[[`path`,{d:`M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719`,key:`1sd12s`}],[`path`,{d:`M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3`,key:`1u773s`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]],aliases:[`message-circle-question`]};F.node;var I=r(F),L={name:`puzzle`,size:24,node:[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]};L.node;var R=r(L),z={name:`refresh-cw`,size:24,node:[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]};z.node;var B=r(z),V={name:`server-off`,size:24,node:[[`path`,{d:`M7 2h13a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-5`,key:`bt2siv`}],[`path`,{d:`M10 10 2.5 2.5C2 2 2 2.5 2 5v3a2 2 0 0 0 2 2h6z`,key:`1hjrv1`}],[`path`,{d:`M22 17v-1a2 2 0 0 0-2-2h-1`,key:`1iynyr`}],[`path`,{d:`M4 14a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16.5l1-.5.5.5-8-8H4z`,key:`161ggg`}],[`path`,{d:`M6 18h.01`,key:`uhywen`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]};V.node;var H=r(V),U={name:`triangle-alert`,size:24,node:[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]],aliases:[`alert-triangle`]};U.node;var W=r(U);function G(...e){return e.filter(Boolean).join(` `)}var K=typeof Intl<`u`&&`RelativeTimeFormat`in Intl?new Intl.RelativeTimeFormat(void 0,{numeric:`auto`}):null;function q(e,t=Date.now()){if(!e)return`never`;let n=Date.parse(e);if(Number.isNaN(n))return e;let r=Math.round((n-t)/1e3),i=Math.abs(r);return i<30?`just now`:K?i<3600?K.format(Math.round(r/60),`minute`):i<86400?K.format(Math.round(r/3600),`hour`):i<2592e3?K.format(Math.round(r/86400),`day`):new Date(n).toLocaleDateString():new Date(n).toLocaleString()}function J(e){if(e==null)return`unknown`;let t=new Date(e);return Number.isNaN(t.getTime())?String(e):t.toDateString()===new Date().toDateString()?t.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`}):t.toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function Ie(e){if(e==null||Number.isNaN(e))return``;if(e<1e3)return`${Math.round(e)} ms`;let t=Math.round(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60);return n<60?`${n}m ${String(t%60).padStart(2,`0`)}s`:`${Math.floor(n/60)}h ${String(n%60).padStart(2,`0`)}m`}var Y=i(),Le={primary:`bg-accent text-accent-fg border-accent hover:bg-accent-hover hover:border-accent-hover`,secondary:`bg-surface text-text border-border hover:bg-surface-2`,ghost:`bg-transparent text-text border-transparent hover:bg-surface-2`,danger:`bg-danger text-danger-fg border-danger hover:bg-danger-hover hover:border-danger-hover`},Re={sm:`h-8 px-2.5 text-sm gap-1.5`,md:`h-9 px-3.5 text-sm gap-2`};function X(e=`secondary`,t=`md`,n){return G(`tap inline-flex items-center justify-center rounded-md border font-medium whitespace-nowrap select-none`,`transition-colors disabled:opacity-55 disabled:pointer-events-none`,Le[e],Re[t],n)}var Z=(0,a.forwardRef)(function({variant:e=`secondary`,size:t=`md`,icon:n,busy:r,block:i,className:a,children:o,disabled:s,type:c,...ee},l){return(0,Y.jsxs)(`button`,{ref:l,type:c??`button`,disabled:s||r,"aria-busy":r||void 0,className:X(e,t,G(i&&`w-full`,a)),...ee,children:[r?(0,Y.jsx)(Q,{}):n,o]})});function Q({className:e,label:t}){return(0,Y.jsxs)(`svg`,{className:G(`size-4 animate-spin`,e),viewBox:`0 0 24 24`,fill:`none`,role:t?`img`:void 0,"aria-label":t,"aria-hidden":!t||void 0,children:[(0,Y.jsx)(`circle`,{cx:`12`,cy:`12`,r:`9`,stroke:`currentColor`,strokeOpacity:`0.25`,strokeWidth:`3`}),(0,Y.jsx)(`path`,{d:`M21 12a9 9 0 0 0-9-9`,stroke:`currentColor`,strokeWidth:`3`,strokeLinecap:`round`})]})}function ze({action:e,primary:n=!0}){return`to`in e?(0,Y.jsxs)(t,{to:e.to,className:X(n?`primary`:`secondary`),children:[e.icon,e.label]}):(0,Y.jsx)(Z,{variant:n?`primary`:`secondary`,icon:e.icon,onClick:e.onClick,children:e.label})}function $({icon:e,title:t,children:n,actions:r,className:i,role:a}){return(0,Y.jsxs)(`div`,{role:a,className:G(`mx-auto flex w-full max-w-md flex-col items-center gap-3 px-4 py-10 text-center`,i),children:[(0,Y.jsx)(`div`,{className:`text-muted`,"aria-hidden":!0,children:e}),(0,Y.jsx)(`h2`,{className:`text-base font-semibold`,children:t}),n&&(0,Y.jsx)(`div`,{className:`text-sm text-muted`,children:n}),r&&(0,Y.jsx)(`div`,{className:`flex flex-wrap justify-center gap-2`,children:r})]})}function Be({label:e=`Loading…`,className:t}){return(0,Y.jsxs)(`div`,{role:`status`,"aria-live":`polite`,className:G(`flex items-center justify-center gap-2 px-4 py-10 text-sm text-muted`,t),children:[(0,Y.jsx)(Q,{}),(0,Y.jsx)(`span`,{children:e})]})}function Ve({title:e,description:t,action:n,secondaryAction:r,icon:i,className:a}){return(0,Y.jsx)($,{icon:i??(0,Y.jsx)(P,{className:`size-8`}),title:e,className:a,actions:(n||r)&&(0,Y.jsxs)(Y.Fragment,{children:[n&&(0,Y.jsx)(ze,{action:n}),r&&(0,Y.jsx)(ze,{action:r,primary:!1})]}),children:t})}function He({state:e,lastSyncedAt:t,onRetry:n,className:r}){if(e===`live`||e===`connecting`&&!t)return null;let i=e===`offline`,a=t?J(t):`an earlier session`;return(0,Y.jsxs)(`div`,{role:`status`,"aria-live":`polite`,className:G(`flex items-center gap-2 border-b border-border bg-warning-soft px-3 py-1.5 text-sm text-text`,r),children:[i?(0,Y.jsx)(H,{"aria-hidden":!0,className:`size-4 shrink-0 text-warning`}):(0,Y.jsx)(B,{"aria-hidden":!0,className:`size-4 shrink-0 animate-spin text-warning`}),(0,Y.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[i?`Offline`:`Reconnecting…`,` showing last known data from`,` `,(0,Y.jsx)(`time`,{dateTime:t??void 0,children:a})]}),n&&(0,Y.jsx)(`button`,{type:`button`,onClick:n,className:`tap shrink-0 rounded px-2 py-0.5 font-medium text-accent hover:bg-surface-2`,children:`Retry now`})]})}function Ue({hostName:e,connectivity:t=`unreachable`,lastSeenAt:n,detail:r,compact:i,className:a}){let o=t===`reconnecting`?`Host ${e} is reconnecting`:`Host ${e} is unreachable`,s=(0,Y.jsxs)(Y.Fragment,{children:[n?`Last seen ${q(n)}. `:``,r??`Work on this host keeps its last known state; nothing is restarted elsewhere.`]});return i?(0,Y.jsxs)(`div`,{role:`status`,className:G(`flex items-start gap-2 rounded-md border border-border bg-danger-soft px-3 py-2 text-sm`,a),children:[(0,Y.jsx)(H,{"aria-hidden":!0,className:`mt-0.5 size-4 shrink-0 text-danger`}),(0,Y.jsxs)(`div`,{className:`min-w-0`,children:[(0,Y.jsx)(`div`,{className:`font-medium`,children:o}),(0,Y.jsx)(`div`,{className:`text-muted`,children:s})]})]}):(0,Y.jsx)($,{role:`status`,icon:(0,Y.jsx)(H,{className:`size-8`}),title:o,className:a,children:s})}function We({count:e,to:n,onOpen:r,label:i,className:a}){if(e<=0)return null;let o=i??(e===1?`Needs your answer`:`${e} questions need your answer`),s=(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(I,{"aria-hidden":!0,className:`size-4 shrink-0 text-warning`}),(0,Y.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-medium`,children:o}),(0,Y.jsx)(`span`,{className:`shrink-0 text-accent`,children:`Answer`})]}),c=G(`tap flex w-full items-center gap-2 border border-border bg-warning-soft px-3 py-2 text-left text-sm rounded-md`,a);return n?(0,Y.jsx)(t,{to:n,className:c,role:`status`,children:s}):(0,Y.jsx)(`button`,{type:`button`,onClick:r,className:c,children:s})}function Ge({capability:e,reason:t,fallback:n,className:r}){return(0,Y.jsxs)(`div`,{role:`note`,className:G(`flex items-start gap-2 rounded-md border border-border bg-surface-2 px-3 py-2 text-sm`,r),children:[(0,Y.jsx)(R,{"aria-hidden":!0,className:`mt-0.5 size-4 shrink-0 text-muted`}),(0,Y.jsxs)(`div`,{className:`min-w-0`,children:[(0,Y.jsxs)(`div`,{className:`font-medium`,children:[e,` is not available here`]}),(0,Y.jsx)(`div`,{className:`text-muted`,children:t}),n&&(0,Y.jsx)(`div`,{className:`mt-1`,children:n})]})]})}function Ke({title:e=`Something went wrong`,error:t,onRetry:n,compact:r,className:i}){let a=t instanceof Error?t.message:String(t??``);return r?(0,Y.jsxs)(`div`,{role:`alert`,className:G(`flex items-start gap-2 rounded-md border border-border bg-danger-soft px-3 py-2 text-sm`,i),children:[(0,Y.jsx)(W,{"aria-hidden":!0,className:`mt-0.5 size-4 shrink-0 text-danger`}),(0,Y.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,Y.jsx)(`div`,{className:`font-medium`,children:e}),a&&(0,Y.jsx)(`div`,{className:`break-words text-muted`,children:a})]}),n&&(0,Y.jsx)(Z,{size:`sm`,onClick:n,icon:(0,Y.jsx)(B,{className:`size-3.5`}),children:`Retry`})]}):(0,Y.jsx)($,{role:`alert`,icon:(0,Y.jsx)(W,{className:`size-8 text-danger`}),title:e,className:i,actions:n&&(0,Y.jsx)(Z,{variant:`primary`,onClick:n,icon:(0,Y.jsx)(B,{className:`size-4`}),children:`Retry`}),children:(0,Y.jsx)(`span`,{className:`break-words`,children:a})})}function qe({title:e=`Switchyard cannot show this view`,error:t,diagnosticsHref:n=`/settings/diagnostics`,className:r}){let i=t instanceof Error?t.message:String(t??``);return(0,Y.jsx)($,{role:`alert`,icon:(0,Y.jsx)(M,{className:`size-8 text-danger`}),title:e,className:r,actions:(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(`a`,{href:n,className:X(`primary`),children:`Open diagnostics`}),(0,Y.jsx)(Z,{onClick:()=>location.reload(),children:`Reload`})]}),children:(0,Y.jsx)(`span`,{className:`break-words`,children:i})})}export{Ee as A,se as B,_e as C,Oe as D,De as E,Te as F,te as G,oe as H,Fe as I,ne as K,de as L,we as M,Ne as N,Me as O,O as P,d as R,A as S,Ce as T,ae as U,h as V,f as W,B as _,We as a,P as b,Ge as c,X as d,Ie as f,W as g,G as h,Ue as i,je as j,Ae as k,Z as l,J as m,Ke as n,Be as o,q as p,u as q,qe as r,He as s,Ve as t,Q as u,R as v,ke as w,M as x,I as y,m as z};
|
|
2
|
+
//# sourceMappingURL=states-DrTQuYXw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"states-DrTQuYXw.js","names":["useMemo","__iconData","__iconData","__iconData","__iconData","__iconData","__iconData","forwardRef","_Fragment","MessageCircleQuestion","__toESM","Link","require_react","createLucideIcon","require_jsx_runtime","import_react","createStoreImpl","state","listeners","setState","nextState","partial","previousState","replace","listener","getState","api","initialState","createState","createStore","identity","arg","useStore","slice","selector","createImpl","useBoundStore","create","ApiClientError","message","code","status","details","isApiError","errorMessage","unauthorizedListeners","onUnauthorized","fn","buildUrl","query","path","params","k","v","qs","method","opts","headers","body","res","text","json","err","parseErrorBody","e","apiGet","apiPost","apiPatch","apiDelete","LIVE_RUNTIMES","panelKey","sessionId","adapterId","slot","keepPanel","p","emptyEntities","emptySyncData","emptyTranscript","byId","out","x","list","put","map","id","value","drop","next","applySnapshot","panels","snap","transcripts","t","a","toSyncState","mergeTranscriptItems","incoming","existing","it","b","applyTranscriptPage","prev","base","items","upsertTranscriptItem","item","streaming","applyEvent","event","reduceEvent","applyEvents","s","events","type","d","data","clearSessionStreams","key","occurrences","o","applyStream","delta","field","changed","normalizePage","limit","inflight","useSyncStore","get","set","seq","savedAt","patch","interaction","setTranscript","page","before","syncStore","sortAttention","attention","countAttention","n","pendingInteractionsFor","interactions","i","runsForTask","runs","r","taskId","panelsForSession","streamsForSession","useConnection","useSession","useTask","useProjects","projects","useHosts","hosts","h","useOpenAttention","useAttentionCount","usePendingInteractions","useRunsForTask","usePanels","useStreams","EMPTY_TRANSCRIPT","useTranscript","load","needsLoad","__iconData$6","CircleAlert","__iconData$5","Inbox","__iconData$4","MessageCircleQuestionMark","__iconData$3","Puzzle","__iconData$2","RefreshCw","__iconData$1","ServerOff","__iconData","TriangleAlert","cn","parts","rtf","formatRelative","iso","diff","now","abs","formatTime","formatDuration","ms","m","import_jsx_runtime","VARIANTS","SIZES","buttonClasses","variant","size","extra","Button","rest","disabled","busy","block","className","Spinner","icon","children","label","ActionButton","action","primary","Panel","title","actions","LoadingState","EmptyState","secondaryAction","description","ReconnectingBanner","lastSyncedAt","offline","when","onRetry","HostUnavailable","connectivity","hostName","lastSeenAt","detail","compact","InteractionPending","count","inner","cls","to","onOpen","UnsupportedCapability","capability","reason","fallback","ErrorState","error","FatalError","diagnosticsHref"],"sources":["../../../../node_modules/.pnpm/zustand@5.0.16_@types+react@19.3.0_react@19.3.1/node_modules/zustand/esm/vanilla.mjs","../../../../node_modules/.pnpm/zustand@5.0.16_@types+react@19.3.0_react@19.3.1/node_modules/zustand/esm/react.mjs","../../src/sync/api.ts","../../src/sync/reduce.ts","../../src/sync/store.ts","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/circle-alert.mjs","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/inbox.mjs","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/message-circle-question-mark.mjs","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/puzzle.mjs","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/server-off.mjs","../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/triangle-alert.mjs","../../src/lib/cn.ts","../../src/lib/time.ts","../../src/components/ui/Button.tsx","../../src/components/ui/states.tsx"],"sourcesContent":["const createStoreImpl = (createState) => {\n let state;\n const listeners = /* @__PURE__ */ new Set();\n const setState = (partial, replace) => {\n const nextState = typeof partial === \"function\" ? partial(state) : partial;\n if (!Object.is(nextState, state)) {\n const previousState = state;\n state = (replace != null ? replace : typeof nextState !== \"object\" || nextState === null) ? nextState : Object.assign({}, state, nextState);\n listeners.forEach((listener) => listener(state, previousState));\n }\n };\n const getState = () => state;\n const getInitialState = () => initialState;\n const subscribe = (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n const api = { setState, getState, getInitialState, subscribe };\n const initialState = state = createState(setState, getState, api);\n return api;\n};\nconst createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);\n\nexport { createStore };\n","import React from 'react';\nimport { createStore } from 'zustand/vanilla';\n\nconst identity = (arg) => arg;\nfunction useStore(api, selector = identity) {\n const slice = React.useSyncExternalStore(\n api.subscribe,\n React.useCallback(() => selector(api.getState()), [api, selector]),\n () => selector(api.getInitialState())\n );\n React.useDebugValue(slice);\n return slice;\n}\nconst createImpl = (createState) => {\n const api = createStore(createState);\n const useBoundStore = (selector) => useStore(api, selector);\n Object.assign(useBoundStore, api);\n return useBoundStore;\n};\nconst create = ((createState) => createState ? createImpl(createState) : createImpl);\n\nexport { create, useStore };\n","import type { ErrorCode } from \"@switchyard/protocol\";\n\n/** Client-side error codes in addition to the protocol's shared codes. */\nexport type ApiClientErrorCode = ErrorCode | \"network\" | \"http\";\n\n/** Every failed REST call rejects with this. `code` is the protocol `ApiError` code. */\nexport class ApiClientError extends Error {\n readonly code: ApiClientErrorCode;\n readonly status: number;\n readonly details?: unknown;\n constructor(code: ApiClientErrorCode, message: string, status: number, details?: unknown) {\n super(message);\n this.name = \"ApiClientError\";\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport function isApiError(e: unknown, code?: ApiClientErrorCode): e is ApiClientError {\n return e instanceof ApiClientError && (code === undefined || e.code === code);\n}\n\n/** Human-readable message for any thrown value. */\nexport function errorMessage(e: unknown): string {\n if (e instanceof Error) return e.message;\n return String(e);\n}\n\ntype Query = Record<string, string | number | boolean | null | undefined>;\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n body?: unknown;\n query?: Query;\n signal?: AbortSignal;\n headers?: Record<string, string>;\n}\n\ntype UnauthorizedListener = (code: ApiClientErrorCode) => void;\nconst unauthorizedListeners = new Set<UnauthorizedListener>();\n\n/** Called when any request comes back 401 (the auth gate redirects to /enroll). */\nexport function onUnauthorized(fn: UnauthorizedListener): () => void {\n unauthorizedListeners.add(fn);\n return () => unauthorizedListeners.delete(fn);\n}\n\nexport function buildUrl(path: string, query?: Query): string {\n if (!query) return path;\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null) continue;\n params.set(k, String(v));\n }\n const qs = params.toString();\n return qs ? `${path}${path.includes(\"?\") ? \"&\" : \"?\"}${qs}` : path;\n}\n\n/**\n * fetch wrapper for the coordinator REST API. Sends cookies, the CSRF header\n * `X-Switchyard-Request: 1`, and JSON bodies; maps `ApiError` bodies to\n * `ApiClientError`.\n */\nexport async function api<T = unknown>(path: string, opts: RequestOptions = {}): Promise<T> {\n const method = opts.method ?? (opts.body === undefined ? \"GET\" : \"POST\");\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"X-Switchyard-Request\": \"1\",\n ...opts.headers,\n };\n let body: string | undefined;\n if (opts.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n body = JSON.stringify(opts.body);\n }\n let res: Response;\n try {\n res = await fetch(buildUrl(path, opts.query), {\n method,\n headers,\n body,\n credentials: \"include\",\n signal: opts.signal,\n });\n } catch (e) {\n if (e instanceof DOMException && e.name === \"AbortError\") throw e;\n throw new ApiClientError(\"network\", \"Could not reach the coordinator\", 0);\n }\n const text = await res.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n }\n if (!res.ok) {\n const err = parseErrorBody(json);\n const e = err\n ? new ApiClientError(err.code, err.message, res.status, err.details)\n : new ApiClientError(\n res.status === 401 ? \"unauthorized\" : \"http\",\n `Request failed (${res.status}${res.statusText ? ` ${res.statusText}` : \"\"})`,\n res.status,\n );\n if (res.status === 401) for (const fn of unauthorizedListeners) fn(e.code);\n throw e;\n }\n return json as T;\n}\n\nfunction parseErrorBody(\n json: unknown,\n): { code: ErrorCode; message: string; details?: unknown } | null {\n if (!json || typeof json !== \"object\") return null;\n const err = (json as { error?: unknown }).error;\n if (!err || typeof err !== \"object\") return null;\n const { code, message, details } = err as {\n code?: unknown;\n message?: unknown;\n details?: unknown;\n };\n if (typeof code !== \"string\") return null;\n return {\n code: code as ErrorCode,\n message: typeof message === \"string\" ? message : code,\n details,\n };\n}\n\nexport const apiGet = <T>(path: string, query?: Query, signal?: AbortSignal) =>\n api<T>(path, { method: \"GET\", query, signal });\nexport const apiPost = <T>(path: string, body?: unknown) =>\n api<T>(path, { method: \"POST\", body: body ?? {} });\nexport const apiPatch = <T>(path: string, body: unknown) => api<T>(path, { method: \"PATCH\", body });\nexport const apiPut = <T>(path: string, body: unknown) => api<T>(path, { method: \"PUT\", body });\nexport const apiDelete = <T>(path: string, body?: unknown) =>\n api<T>(path, { method: \"DELETE\", body });\n","import type {\n AdapterInfo,\n AttentionItem,\n Automation,\n Checkout,\n Device,\n Diagnostic,\n EventData,\n EventEnvelope,\n EventType,\n Host,\n Interaction,\n Occurrence,\n Panel,\n Profile,\n Project,\n Run,\n Session,\n StreamDelta,\n SyncState,\n Task,\n TranscriptItem,\n Workspace,\n} from \"@switchyard/protocol\";\n\n/**\n * Pure reducers for the normalized client state. The zustand store in\n * `store.ts` wraps these; tests exercise them directly.\n */\n\nexport type ById<T> = Record<string, T>;\n\nexport interface EntityState {\n /** Last applied durable event seq (the WS cursor), null before any sync. */\n seq: number | null;\n hosts: ById<Host>;\n projects: ById<Project>;\n checkouts: ById<Checkout>;\n workspaces: ById<Workspace>;\n profiles: ById<Profile>;\n sessions: ById<Session>;\n tasks: ById<Task>;\n runs: ById<Run>;\n automations: ById<Automation>;\n /** Open (unresolved) attention items. Resolved items are dropped. */\n attention: ById<AttentionItem>;\n /** Interactions of any state, so resolution summaries stay visible inline. */\n interactions: ById<Interaction>;\n /** Keyed by `panelKey(sessionId, adapterId, slot)`. */\n panels: ById<Panel>;\n devices: ById<Device>;\n /** Adapters per host id. */\n adapters: Record<string, AdapterInfo[]>;\n /** Occurrences seen live (newest first) per automation id; history loads over REST. */\n occurrences: Record<string, Occurrence[]>;\n /** The latest diagnostics, newest last, bounded. */\n diagnostics: Diagnostic[];\n dispatchPaused: boolean;\n}\n\nexport interface TranscriptState {\n /** Items sorted by `order` ascending, unique by id. */\n items: TranscriptItem[];\n /** True once the newest page has been fetched over REST. */\n loaded: boolean;\n loading: boolean;\n /** Whether older items exist before `items[0]`. */\n hasMore: boolean;\n /** Set after a snapshot resync; the next view reloads the newest page. */\n stale: boolean;\n error: string | null;\n}\n\nexport interface StreamBuffer {\n sessionId: string;\n itemId: string;\n order: number | null;\n text: string;\n thinking: string;\n toolArgs: string;\n toolOutput: string;\n}\n\nexport interface SyncData extends EntityState {\n transcripts: Record<string, TranscriptState>;\n /** Ephemeral stream deltas keyed by item id, appended to the durable item text. */\n streaming: Record<string, StreamBuffer>;\n}\n\nexport const MAX_DIAGNOSTICS = 100;\nconst LIVE_RUNTIMES = new Set<string>([\"starting\", \"running\", \"waiting_input\"]);\nexport const MAX_OCCURRENCES_PER_AUTOMATION = 50;\n\nexport function panelKey(sessionId: string, adapterId: string, slot: string): string {\n return `${sessionId}:${adapterId}:${slot}`;\n}\n\n/** A panel with no node and no web renderer has been removed by its adapter. */\nfunction keepPanel(p: Panel): boolean {\n return p.node !== null || p.webRenderer;\n}\n\nexport function emptyEntities(): EntityState {\n return {\n seq: null,\n hosts: {},\n projects: {},\n checkouts: {},\n workspaces: {},\n profiles: {},\n sessions: {},\n tasks: {},\n runs: {},\n automations: {},\n attention: {},\n interactions: {},\n panels: {},\n devices: {},\n adapters: {},\n occurrences: {},\n diagnostics: [],\n dispatchPaused: false,\n };\n}\n\nexport function emptySyncData(): SyncData {\n return { ...emptyEntities(), transcripts: {}, streaming: {} };\n}\n\nexport function emptyTranscript(): TranscriptState {\n return { items: [], loaded: false, loading: false, hasMore: false, stale: false, error: null };\n}\n\nfunction byId<T extends { id: string }>(list: T[]): ById<T> {\n const out: ById<T> = {};\n for (const x of list) out[x.id] = x;\n return out;\n}\n\nfunction put<T>(map: ById<T>, id: string, value: T): ById<T> {\n return { ...map, [id]: value };\n}\n\nfunction drop<T>(map: ById<T>, id: string): ById<T> {\n if (!(id in map)) return map;\n const next = { ...map };\n delete next[id];\n return next;\n}\n\n/** Replace every entity with a server snapshot. Loaded transcripts are kept but marked stale. */\nexport function applySnapshot<S extends SyncData>(state: S, seq: number, snap: SyncState): S {\n const panels: ById<Panel> = {};\n for (const p of snap.panels)\n if (keepPanel(p)) panels[panelKey(p.sessionId, p.adapterId, p.slot)] = p;\n const transcripts: Record<string, TranscriptState> = {};\n for (const [id, t] of Object.entries(state.transcripts)) transcripts[id] = { ...t, stale: true };\n return {\n ...state,\n seq,\n hosts: byId(snap.hosts),\n projects: byId(snap.projects),\n checkouts: byId(snap.checkouts),\n workspaces: byId(snap.workspaces),\n profiles: byId(snap.profiles),\n sessions: byId(snap.sessions),\n tasks: byId(snap.tasks),\n runs: byId(snap.runs),\n automations: byId(snap.automations),\n attention: byId(snap.attention.filter((a) => a.resolvedAt === null)),\n interactions: byId(snap.interactions),\n panels,\n devices: byId(snap.devices),\n adapters: { ...snap.adapters },\n dispatchPaused: snap.dispatchPaused,\n transcripts,\n streaming: {},\n };\n}\n\n/** Rebuild a SyncState from the entities (used for the offline cache). */\nexport function toSyncState(state: EntityState): SyncState {\n return {\n hosts: Object.values(state.hosts),\n projects: Object.values(state.projects),\n checkouts: Object.values(state.checkouts),\n workspaces: Object.values(state.workspaces),\n profiles: Object.values(state.profiles),\n sessions: Object.values(state.sessions),\n tasks: Object.values(state.tasks),\n runs: Object.values(state.runs),\n automations: Object.values(state.automations),\n attention: Object.values(state.attention),\n interactions: Object.values(state.interactions),\n panels: Object.values(state.panels),\n devices: Object.values(state.devices),\n adapters: state.adapters,\n dispatchPaused: state.dispatchPaused,\n };\n}\n\n/** Insert or replace transcript items by id, keeping `order` ascending. */\nexport function mergeTranscriptItems(\n existing: TranscriptItem[],\n incoming: TranscriptItem[],\n): TranscriptItem[] {\n if (incoming.length === 0) return existing;\n const map = new Map<string, TranscriptItem>();\n for (const it of existing) map.set(it.id, it);\n for (const it of incoming) map.set(it.id, it);\n return [...map.values()].sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));\n}\n\n/** Merge a fetched page into a session transcript. `older` pages only set `hasMore`. */\nexport function applyTranscriptPage<S extends SyncData>(\n state: S,\n sessionId: string,\n items: TranscriptItem[],\n opts: { hasMore: boolean; older: boolean },\n): S {\n const prev = state.transcripts[sessionId] ?? emptyTranscript();\n // A fresh newest page after a resync replaces items, so nothing stale lingers.\n const base = !opts.older && prev.stale ? [] : prev.items;\n const next: TranscriptState = {\n ...prev,\n items: mergeTranscriptItems(base, items),\n loaded: true,\n loading: false,\n stale: opts.older ? prev.stale : false,\n error: null,\n hasMore: opts.older || !prev.loaded || prev.stale ? opts.hasMore : prev.hasMore,\n };\n return { ...state, transcripts: { ...state.transcripts, [sessionId]: next } };\n}\n\nfunction upsertTranscriptItem<S extends SyncData>(state: S, item: TranscriptItem): S {\n const prev = state.transcripts[item.sessionId] ?? emptyTranscript();\n const transcripts = {\n ...state.transcripts,\n [item.sessionId]: { ...prev, items: mergeTranscriptItems(prev.items, [item]) },\n };\n // The durable item is authoritative up to now: drop any buffered deltas for it.\n const streaming = drop(state.streaming, item.id);\n return { ...state, transcripts, streaming };\n}\n\n/**\n * Apply one durable event. Events at or below the current cursor are ignored\n * (replay and live delivery may overlap).\n */\nexport function applyEvent<S extends SyncData>(state: S, event: EventEnvelope): S {\n if (state.seq !== null && event.seq <= state.seq) return state;\n const next = reduceEvent(state, event.type, event.data as never);\n return { ...next, seq: event.seq };\n}\n\nexport function applyEvents<S extends SyncData>(state: S, events: EventEnvelope[]): S {\n let s = state;\n for (const e of [...events].sort((a, b) => a.seq - b.seq)) s = applyEvent(s, e);\n return s;\n}\n\nfunction reduceEvent<S extends SyncData, T extends EventType>(\n state: S,\n type: T,\n data: EventData<T>,\n): S {\n switch (type) {\n case \"host.updated\": {\n const d = data as EventData<\"host.updated\">;\n return { ...state, hosts: put(state.hosts, d.id, d) };\n }\n case \"project.updated\": {\n const d = data as EventData<\"project.updated\">;\n return { ...state, projects: put(state.projects, d.id, d) };\n }\n case \"project.deleted\": {\n const d = data as EventData<\"project.deleted\">;\n return { ...state, projects: drop(state.projects, d.id) };\n }\n case \"checkout.updated\": {\n const d = data as EventData<\"checkout.updated\">;\n return { ...state, checkouts: put(state.checkouts, d.id, d) };\n }\n case \"workspace.updated\": {\n const d = data as EventData<\"workspace.updated\">;\n return {\n ...state,\n workspaces: d.archivedAt ? drop(state.workspaces, d.id) : put(state.workspaces, d.id, d),\n };\n }\n case \"workspace.removed\": {\n const d = data as EventData<\"workspace.removed\">;\n return { ...state, workspaces: drop(state.workspaces, d.id) };\n }\n case \"profile.updated\": {\n const d = data as EventData<\"profile.updated\">;\n return { ...state, profiles: put(state.profiles, d.id, d) };\n }\n case \"session.updated\": {\n const d = data as EventData<\"session.updated\">;\n const next = { ...state, sessions: put(state.sessions, d.id, d) };\n return LIVE_RUNTIMES.has(d.runtime) ? next : clearSessionStreams(next, d.id);\n }\n case \"transcript.item\":\n return upsertTranscriptItem(state, data as EventData<\"transcript.item\">);\n case \"interaction.updated\": {\n const d = data as EventData<\"interaction.updated\">;\n const prev = state.interactions[d.id];\n if (prev && prev.revision > d.revision) return state;\n return { ...state, interactions: put(state.interactions, d.id, d) };\n }\n case \"panel.updated\": {\n const d = data as EventData<\"panel.updated\">;\n const key = panelKey(d.sessionId, d.adapterId, d.slot);\n return {\n ...state,\n panels: keepPanel(d) ? put(state.panels, key, d) : drop(state.panels, key),\n };\n }\n case \"adapters.updated\": {\n const d = data as EventData<\"adapters.updated\">;\n return { ...state, adapters: { ...state.adapters, [d.hostId]: d.adapters } };\n }\n case \"diagnostic\": {\n const d = data as EventData<\"diagnostic\">;\n return { ...state, diagnostics: [...state.diagnostics, d].slice(-MAX_DIAGNOSTICS) };\n }\n case \"task.updated\": {\n const d = data as EventData<\"task.updated\">;\n return { ...state, tasks: put(state.tasks, d.id, d) };\n }\n case \"task.deleted\": {\n const d = data as EventData<\"task.deleted\">;\n return { ...state, tasks: drop(state.tasks, d.id) };\n }\n case \"run.updated\": {\n const d = data as EventData<\"run.updated\">;\n return { ...state, runs: put(state.runs, d.id, d) };\n }\n case \"automation.updated\": {\n const d = data as EventData<\"automation.updated\">;\n return { ...state, automations: put(state.automations, d.id, d) };\n }\n case \"automation.deleted\": {\n const d = data as EventData<\"automation.deleted\">;\n const occurrences = { ...state.occurrences };\n delete occurrences[d.id];\n return { ...state, automations: drop(state.automations, d.id), occurrences };\n }\n case \"occurrence.created\": {\n const d = data as EventData<\"occurrence.created\">;\n const list = (state.occurrences[d.automationId] ?? []).filter((o) => o.id !== d.id);\n return {\n ...state,\n occurrences: {\n ...state.occurrences,\n [d.automationId]: [d, ...list].slice(0, MAX_OCCURRENCES_PER_AUTOMATION),\n },\n };\n }\n case \"attention.updated\": {\n const d = data as EventData<\"attention.updated\">;\n return {\n ...state,\n attention: d.resolvedAt ? drop(state.attention, d.id) : put(state.attention, d.id, d),\n };\n }\n case \"device.updated\": {\n const d = data as EventData<\"device.updated\">;\n return {\n ...state,\n devices: d.revokedAt ? drop(state.devices, d.id) : put(state.devices, d.id, d),\n };\n }\n case \"settings.updated\": {\n const d = data as EventData<\"settings.updated\">;\n return { ...state, dispatchPaused: d.dispatchPaused };\n }\n default:\n return state;\n }\n}\n\n/** Append an ephemeral stream delta to the per-item buffer. */\nexport function applyStream<S extends SyncData>(state: S, delta: StreamDelta): S {\n const prev: StreamBuffer = state.streaming[delta.itemId] ?? {\n sessionId: delta.sessionId,\n itemId: delta.itemId,\n order: delta.order ?? null,\n text: \"\",\n thinking: \"\",\n toolArgs: \"\",\n toolOutput: \"\",\n };\n const field =\n delta.kind === \"text\"\n ? \"text\"\n : delta.kind === \"thinking\"\n ? \"thinking\"\n : delta.kind === \"tool_args\"\n ? \"toolArgs\"\n : \"toolOutput\";\n const next: StreamBuffer = {\n ...prev,\n order: prev.order ?? delta.order ?? null,\n [field]: prev[field] + delta.delta,\n };\n return { ...state, streaming: { ...state.streaming, [delta.itemId]: next } };\n}\n\n/** Drop all stream buffers of a session (for example when it settles). */\nexport function clearSessionStreams<S extends SyncData>(state: S, sessionId: string): S {\n const streaming: Record<string, StreamBuffer> = {};\n let changed = false;\n for (const [id, b] of Object.entries(state.streaming)) {\n if (b.sessionId === sessionId) changed = true;\n else streaming[id] = b;\n }\n return changed ? { ...state, streaming } : state;\n}\n","import type {\n AttentionItem,\n EventEnvelope,\n Interaction,\n Panel,\n Run,\n Session,\n StreamDelta,\n SyncState,\n Task,\n TaskState,\n TranscriptItem,\n} from \"@switchyard/protocol\";\nimport { useEffect, useMemo } from \"react\";\nimport { create } from \"zustand\";\nimport { apiGet, errorMessage } from \"./api\";\nimport {\n applyEvent,\n applyEvents,\n applySnapshot,\n applyStream,\n applyTranscriptPage,\n emptySyncData,\n emptyTranscript,\n type StreamBuffer,\n type SyncData,\n type TranscriptState,\n} from \"./reduce\";\n\nexport type { StreamBuffer, SyncData, TranscriptState } from \"./reduce\";\nexport { panelKey } from \"./reduce\";\n\nexport type ConnectionState = \"connecting\" | \"live\" | \"reconnecting\" | \"offline\";\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n /** When the client last received data from the coordinator (ISO). */\n lastSyncedAt: string | null;\n /** Consecutive failed connection attempts. */\n attempts: number;\n}\n\nexport interface SyncStore extends SyncData {\n /** Some data is present (from the offline cache or the server). */\n hydrated: boolean;\n /** Server data was received during this page load. */\n synced: boolean;\n connection: ConnectionInfo;\n\n hydrateFromCache(seq: number, state: SyncState, savedAt: string): void;\n applySnapshot(seq: number, state: SyncState): void;\n applyReplay(seq: number, events: EventEnvelope[]): void;\n applyEvent(event: EventEnvelope): void;\n applyStream(delta: StreamDelta): void;\n setConnection(patch: Partial<ConnectionInfo>): void;\n /** Store an interaction returned by a REST acknowledgement (answer, 409 already_answered). */\n upsertInteraction(interaction: Interaction): void;\n /** Fetch the newest transcript page (or reload it after a resync). */\n loadTranscript(sessionId: string, opts?: { force?: boolean }): Promise<void>;\n /** Fetch the page before the oldest loaded item. */\n loadOlderTranscript(sessionId: string): Promise<void>;\n /** Clear all data (logout). */\n reset(): void;\n}\n\nexport const TRANSCRIPT_PAGE = 200;\n\ninterface TranscriptPage {\n items: TranscriptItem[];\n hasMore?: boolean;\n}\n\nfunction normalizePage(res: TranscriptPage | TranscriptItem[], limit: number): TranscriptPage {\n const items = Array.isArray(res) ? res : (res.items ?? []);\n const hasMore = Array.isArray(res) ? undefined : res.hasMore;\n return { items, hasMore: hasMore ?? items.length >= limit };\n}\n\nconst inflight = new Map<string, Promise<void>>();\n\nexport const useSyncStore = create<SyncStore>()((set, get) => ({\n ...emptySyncData(),\n hydrated: false,\n synced: false,\n connection: { state: \"connecting\", lastSyncedAt: null, attempts: 0 },\n\n hydrateFromCache(seq, state, savedAt) {\n if (get().synced) return;\n set((s) => ({\n ...applySnapshot(s, seq, state),\n hydrated: true,\n connection: { ...s.connection, lastSyncedAt: s.connection.lastSyncedAt ?? savedAt },\n }));\n },\n applySnapshot(seq, state) {\n set((s) => ({\n ...applySnapshot(s, seq, state),\n hydrated: true,\n synced: true,\n connection: { ...s.connection, lastSyncedAt: new Date().toISOString() },\n }));\n },\n applyReplay(seq, events) {\n set((s) => {\n const next = applyEvents(s, events);\n return {\n ...next,\n seq: Math.max(next.seq ?? 0, seq),\n hydrated: true,\n synced: true,\n connection: { ...s.connection, lastSyncedAt: new Date().toISOString() },\n };\n });\n },\n applyEvent(event) {\n set((s) => ({\n ...applyEvent(s, event),\n connection: { ...s.connection, lastSyncedAt: new Date().toISOString() },\n }));\n },\n applyStream(delta) {\n set((s) => applyStream(s, delta));\n },\n setConnection(patch) {\n set((s) => ({ connection: { ...s.connection, ...patch } }));\n },\n upsertInteraction(interaction) {\n set((s) => {\n const prev = s.interactions[interaction.id];\n if (prev && prev.revision > interaction.revision) return {};\n return { interactions: { ...s.interactions, [interaction.id]: interaction } };\n });\n },\n loadTranscript(sessionId, opts) {\n const t = get().transcripts[sessionId];\n if (t?.loaded && !t.stale && !opts?.force) return Promise.resolve();\n const key = `${sessionId}:newest`;\n const existing = inflight.get(key);\n if (existing) return existing;\n setTranscript(set, sessionId, { loading: true, error: null });\n const p = apiGet<TranscriptPage | TranscriptItem[]>(\n `/api/sessions/${encodeURIComponent(sessionId)}/transcript`,\n { limit: TRANSCRIPT_PAGE },\n )\n .then((res) => {\n const page = normalizePage(res, TRANSCRIPT_PAGE);\n set((s) =>\n applyTranscriptPage(s, sessionId, page.items, {\n hasMore: page.hasMore ?? false,\n older: false,\n }),\n );\n })\n .catch((e) => setTranscript(set, sessionId, { loading: false, error: errorMessage(e) }))\n .finally(() => inflight.delete(key));\n inflight.set(key, p);\n return p;\n },\n loadOlderTranscript(sessionId) {\n const t = get().transcripts[sessionId];\n if (!t?.loaded || !t.hasMore || t.items.length === 0) return Promise.resolve();\n const before = t.items[0]!.order;\n const key = `${sessionId}:before:${before}`;\n const existing = inflight.get(key);\n if (existing) return existing;\n setTranscript(set, sessionId, { loading: true, error: null });\n const p = apiGet<TranscriptPage | TranscriptItem[]>(\n `/api/sessions/${encodeURIComponent(sessionId)}/transcript`,\n { before, limit: TRANSCRIPT_PAGE },\n )\n .then((res) => {\n const page = normalizePage(res, TRANSCRIPT_PAGE);\n set((s) =>\n applyTranscriptPage(s, sessionId, page.items, {\n hasMore: page.hasMore ?? false,\n older: true,\n }),\n );\n })\n .catch((e) => setTranscript(set, sessionId, { loading: false, error: errorMessage(e) }))\n .finally(() => inflight.delete(key));\n inflight.set(key, p);\n return p;\n },\n reset() {\n set({\n ...emptySyncData(),\n hydrated: false,\n synced: false,\n connection: { state: \"connecting\", lastSyncedAt: null, attempts: 0 },\n });\n },\n}));\n\nfunction setTranscript(\n set: (fn: (s: SyncStore) => Partial<SyncStore>) => void,\n sessionId: string,\n patch: Partial<TranscriptState>,\n) {\n set((s) => ({\n transcripts: {\n ...s.transcripts,\n [sessionId]: { ...(s.transcripts[sessionId] ?? emptyTranscript()), ...patch },\n },\n }));\n}\n\nexport const syncStore = useSyncStore;\n\n/* ------------------------------------------------------------------ */\n/* Pure selectors (take entity maps; safe to use in useMemo or tests). */\n/* ------------------------------------------------------------------ */\n\nexport const TASK_COLUMNS: TaskState[] = [\"backlog\", \"ready\", \"in_progress\", \"review\", \"done\"];\n\nexport function compareTasks(a: Task, b: Task): number {\n return (\n a.priority - b.priority || a.position - b.position || a.createdAt.localeCompare(b.createdAt)\n );\n}\n\n/** Tasks grouped by state, sorted by (priority, position, createdAt). Hidden routine tasks are omitted. */\nexport function groupTasksByState(\n tasks: Record<string, Task>,\n opts: { projectId?: string | null; includeHidden?: boolean } = {},\n): Record<TaskState, Task[]> {\n const out: Record<TaskState, Task[]> = {\n backlog: [],\n ready: [],\n in_progress: [],\n review: [],\n done: [],\n canceled: [],\n };\n for (const t of Object.values(tasks)) {\n if (opts.projectId && t.projectId !== opts.projectId) continue;\n if (t.hiddenFromBoard && !opts.includeHidden) continue;\n out[t.state].push(t);\n }\n for (const k of Object.keys(out) as TaskState[]) out[k].sort(compareTasks);\n return out;\n}\n\n/** Non-archived sessions, most recent activity first. */\nexport function sortSessions(sessions: Record<string, Session>): Session[] {\n return Object.values(sessions)\n .filter((s) => s.archivedAt === null)\n .sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt));\n}\n\n/** Open attention, newest first. */\nexport function sortAttention(attention: Record<string, AttentionItem>): AttentionItem[] {\n return Object.values(attention)\n .filter((a) => a.resolvedAt === null)\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n}\n\n/** Count shown on the Attention badge: open and not yet acknowledged. */\nexport function countAttention(attention: Record<string, AttentionItem>): number {\n let n = 0;\n for (const a of Object.values(attention)) if (!a.resolvedAt && !a.acknowledgedAt) n++;\n return n;\n}\n\nexport function pendingInteractionsFor(\n interactions: Record<string, Interaction>,\n sessionId: string,\n): Interaction[] {\n return Object.values(interactions)\n .filter((i) => i.sessionId === sessionId && i.state === \"pending\")\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n}\n\nexport function runsForTask(runs: Record<string, Run>, taskId: string): Run[] {\n return Object.values(runs)\n .filter((r) => r.taskId === taskId)\n .sort((a, b) => b.attempt - a.attempt || b.createdAt.localeCompare(a.createdAt));\n}\n\nexport function panelsForSession(panels: Record<string, Panel>, sessionId: string): Panel[] {\n return Object.values(panels)\n .filter((p) => p.sessionId === sessionId)\n .sort((a, b) => a.adapterId.localeCompare(b.adapterId) || a.slot.localeCompare(b.slot));\n}\n\nexport function streamsForSession(\n streaming: Record<string, StreamBuffer>,\n sessionId: string,\n): StreamBuffer[] {\n return Object.values(streaming).filter((b) => b.sessionId === sessionId);\n}\n\n/* ------------------------------------------------------------------ */\n/* Hooks. Each selects stable maps and derives with useMemo. */\n/* ------------------------------------------------------------------ */\n\nexport const useConnection = () => useSyncStore((s) => s.connection);\nexport const useHost = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.hosts[id] : undefined));\nexport const useProject = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.projects[id] : undefined));\nexport const useWorkspace = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.workspaces[id] : undefined));\nexport const useSession = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.sessions[id] : undefined));\nexport const useTask = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.tasks[id] : undefined));\nexport const useRun = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.runs[id] : undefined));\nexport const useAutomation = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.automations[id] : undefined));\nexport const useInteraction = (id: string | null | undefined) =>\n useSyncStore((s) => (id ? s.interactions[id] : undefined));\n\nexport function useProjects() {\n const projects = useSyncStore((s) => s.projects);\n return useMemo(\n () => Object.values(projects).sort((a, b) => a.name.localeCompare(b.name)),\n [projects],\n );\n}\n\nexport function useHosts() {\n const hosts = useSyncStore((s) => s.hosts);\n return useMemo(\n () =>\n Object.values(hosts)\n .filter((h) => h.revokedAt === null)\n .sort((a, b) => a.name.localeCompare(b.name)),\n [hosts],\n );\n}\n\nexport function useSessions() {\n const sessions = useSyncStore((s) => s.sessions);\n return useMemo(() => sortSessions(sessions), [sessions]);\n}\n\nexport function useTasksByState(opts: { projectId?: string | null; includeHidden?: boolean } = {}) {\n const tasks = useSyncStore((s) => s.tasks);\n const { projectId, includeHidden } = opts;\n return useMemo(\n () => groupTasksByState(tasks, { projectId, includeHidden }),\n [tasks, projectId, includeHidden],\n );\n}\n\nexport function useOpenAttention() {\n const attention = useSyncStore((s) => s.attention);\n return useMemo(() => sortAttention(attention), [attention]);\n}\n\nexport function useAttentionCount() {\n return useSyncStore((s) => countAttention(s.attention));\n}\n\nexport function usePendingInteractions(sessionId: string | null | undefined) {\n const interactions = useSyncStore((s) => s.interactions);\n return useMemo(\n () => (sessionId ? pendingInteractionsFor(interactions, sessionId) : []),\n [interactions, sessionId],\n );\n}\n\nexport function useRunsForTask(taskId: string | null | undefined) {\n const runs = useSyncStore((s) => s.runs);\n return useMemo(() => (taskId ? runsForTask(runs, taskId) : []), [runs, taskId]);\n}\n\nexport function usePanels(sessionId: string | null | undefined) {\n const panels = useSyncStore((s) => s.panels);\n return useMemo(() => (sessionId ? panelsForSession(panels, sessionId) : []), [panels, sessionId]);\n}\n\nexport function useStreams(sessionId: string | null | undefined) {\n const streaming = useSyncStore((s) => s.streaming);\n return useMemo(\n () => (sessionId ? streamsForSession(streaming, sessionId) : []),\n [streaming, sessionId],\n );\n}\n\nconst EMPTY_TRANSCRIPT = emptyTranscript();\n\n/** Transcript for a session; loads the newest page on mount (and after a resync). */\nexport function useTranscript(sessionId: string | null | undefined): TranscriptState {\n const t = useSyncStore((s) => (sessionId ? s.transcripts[sessionId] : undefined));\n const load = useSyncStore((s) => s.loadTranscript);\n const needsLoad = !!sessionId && (!t || ((!t.loaded || t.stale) && !t.loading && !t.error));\n useEffect(() => {\n if (needsLoad && sessionId) void load(sessionId);\n }, [needsLoad, sessionId, load]);\n return t ?? EMPTY_TRANSCRIPT;\n}\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"circle-alert\",\n size: 24,\n node: [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n ],\n aliases: [\"alert-circle\"]\n};\n__iconData.node;\nconst CircleAlert = createLucideIcon(__iconData);\n\nexport { __iconData, CircleAlert as default };\n//# sourceMappingURL=circle-alert.mjs.map\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"inbox\",\n size: 24,\n node: [\n [\"polyline\", { points: \"22 12 16 12 14 15 10 15 8 12 2 12\", key: \"o97t9d\" }],\n [\n \"path\",\n {\n d: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n key: \"oot6mr\"\n }\n ]\n ]\n};\n__iconData.node;\nconst Inbox = createLucideIcon(__iconData);\n\nexport { __iconData, Inbox as default };\n//# sourceMappingURL=inbox.mjs.map\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"message-circle-question-mark\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719\",\n key: \"1sd12s\"\n }\n ],\n [\"path\", { d: \"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\", key: \"1u773s\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n ],\n aliases: [\"message-circle-question\"]\n};\n__iconData.node;\nconst MessageCircleQuestionMark = createLucideIcon(__iconData);\n\nexport { __iconData, MessageCircleQuestionMark as default };\n//# sourceMappingURL=message-circle-question-mark.mjs.map\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"puzzle\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z\",\n key: \"w46dr5\"\n }\n ]\n ]\n};\n__iconData.node;\nconst Puzzle = createLucideIcon(__iconData);\n\nexport { __iconData, Puzzle as default };\n//# sourceMappingURL=puzzle.mjs.map\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"refresh-cw\",\n size: 24,\n node: [\n [\"path\", { d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\", key: \"v9h5vc\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }],\n [\"path\", { d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\", key: \"3uifl3\" }],\n [\"path\", { d: \"M8 16H3v5\", key: \"1cv678\" }]\n ]\n};\n__iconData.node;\nconst RefreshCw = createLucideIcon(__iconData);\n\nexport { __iconData, RefreshCw as default };\n//# sourceMappingURL=refresh-cw.mjs.map\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"server-off\",\n size: 24,\n node: [\n [\"path\", { d: \"M7 2h13a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-5\", key: \"bt2siv\" }],\n [\"path\", { d: \"M10 10 2.5 2.5C2 2 2 2.5 2 5v3a2 2 0 0 0 2 2h6z\", key: \"1hjrv1\" }],\n [\"path\", { d: \"M22 17v-1a2 2 0 0 0-2-2h-1\", key: \"1iynyr\" }],\n [\"path\", { d: \"M4 14a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16.5l1-.5.5.5-8-8H4z\", key: \"161ggg\" }],\n [\"path\", { d: \"M6 18h.01\", key: \"uhywen\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n ]\n};\n__iconData.node;\nconst ServerOff = createLucideIcon(__iconData);\n\nexport { __iconData, ServerOff as default };\n//# sourceMappingURL=server-off.mjs.map\n","/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"triangle-alert\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\",\n key: \"wmoenq\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n ],\n aliases: [\"alert-triangle\"]\n};\n__iconData.node;\nconst TriangleAlert = createLucideIcon(__iconData);\n\nexport { __iconData, TriangleAlert as default };\n//# sourceMappingURL=triangle-alert.mjs.map\n","/** Join class names, skipping falsy values. */\nexport function cn(...parts: (string | false | null | undefined)[]): string {\n return parts.filter(Boolean).join(\" \");\n}\n","const rtf =\n typeof Intl !== \"undefined\" && \"RelativeTimeFormat\" in Intl\n ? new Intl.RelativeTimeFormat(undefined, { numeric: \"auto\" })\n : null;\n\n/** \"3 min ago\", \"in 2 h\", \"just now\". */\nexport function formatRelative(iso: string | null | undefined, now = Date.now()): string {\n if (!iso) return \"never\";\n const t = Date.parse(iso);\n if (Number.isNaN(t)) return iso;\n const diff = Math.round((t - now) / 1000);\n const abs = Math.abs(diff);\n if (abs < 30) return \"just now\";\n if (!rtf) return new Date(t).toLocaleString();\n if (abs < 3600) return rtf.format(Math.round(diff / 60), \"minute\");\n if (abs < 86400) return rtf.format(Math.round(diff / 3600), \"hour\");\n if (abs < 86400 * 30) return rtf.format(Math.round(diff / 86400), \"day\");\n return new Date(t).toLocaleDateString();\n}\n\n/** Short local time, with the date when it is not today. */\nexport function formatTime(iso: string | number | null | undefined): string {\n if (iso === null || iso === undefined) return \"unknown\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return String(iso);\n const sameDay = d.toDateString() === new Date().toDateString();\n return sameDay\n ? d.toLocaleTimeString(undefined, { hour: \"2-digit\", minute: \"2-digit\" })\n : d.toLocaleString(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/** \"1m 05s\" style duration. */\nexport function formatDuration(ms: number | null | undefined): string {\n if (ms === null || ms === undefined || Number.isNaN(ms)) return \"\";\n if (ms < 1000) return `${Math.round(ms)} ms`;\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${String(s % 60).padStart(2, \"0\")}s`;\n return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, \"0\")}m`;\n}\n","import { type ButtonHTMLAttributes, forwardRef, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/cn\";\n\nexport type ButtonVariant = \"primary\" | \"secondary\" | \"ghost\" | \"danger\";\nexport type ButtonSize = \"sm\" | \"md\";\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n /** Icon shown before the label. */\n icon?: ReactNode;\n /** Shows a spinner and sets aria-busy; the button is disabled while busy. */\n busy?: boolean;\n block?: boolean;\n}\n\nconst VARIANTS: Record<ButtonVariant, string> = {\n primary: \"bg-accent text-accent-fg border-accent hover:bg-accent-hover hover:border-accent-hover\",\n secondary: \"bg-surface text-text border-border hover:bg-surface-2\",\n ghost: \"bg-transparent text-text border-transparent hover:bg-surface-2\",\n danger: \"bg-danger text-danger-fg border-danger hover:bg-danger-hover hover:border-danger-hover\",\n};\n\nconst SIZES: Record<ButtonSize, string> = {\n sm: \"h-8 px-2.5 text-sm gap-1.5\",\n md: \"h-9 px-3.5 text-sm gap-2\",\n};\n\nexport function buttonClasses(\n variant: ButtonVariant = \"secondary\",\n size: ButtonSize = \"md\",\n extra?: string,\n): string {\n return cn(\n \"tap inline-flex items-center justify-center rounded-md border font-medium whitespace-nowrap select-none\",\n \"transition-colors disabled:opacity-55 disabled:pointer-events-none\",\n VARIANTS[variant],\n SIZES[size],\n extra,\n );\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n variant = \"secondary\",\n size = \"md\",\n icon,\n busy,\n block,\n className,\n children,\n disabled,\n type,\n ...rest\n },\n ref,\n) {\n return (\n <button\n ref={ref}\n type={type ?? \"button\"}\n disabled={disabled || busy}\n aria-busy={busy || undefined}\n className={buttonClasses(variant, size, cn(block && \"w-full\", className))}\n {...rest}\n >\n {busy ? <Spinner /> : icon}\n {children}\n </button>\n );\n});\n\nexport function Spinner({ className, label }: { className?: string; label?: string }) {\n return (\n <svg\n className={cn(\"size-4 animate-spin\", className)}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n role={label ? \"img\" : undefined}\n aria-label={label}\n aria-hidden={label ? undefined : true}\n >\n <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"currentColor\" strokeOpacity=\"0.25\" strokeWidth=\"3\" />\n <path d=\"M21 12a9 9 0 0 0-9-9\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n","import {\n CircleAlert,\n Inbox,\n MessageCircleQuestion,\n Puzzle,\n RefreshCw,\n ServerOff,\n TriangleAlert,\n} from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { Link } from \"react-router\";\nimport { cn } from \"../../lib/cn\";\nimport { formatRelative, formatTime } from \"../../lib/time\";\nimport type { ConnectionState } from \"../../sync/store\";\nimport { Button, buttonClasses, Spinner } from \"./Button\";\n\n/*\n * The nine UI states every primary view implements (spec 18):\n * LoadingState, EmptyState, ReconnectingBanner, HostUnavailable,\n * InteractionPending, UnsupportedCapability, ErrorState, FatalError, and\n * toast() for successful mutations (see Toast.tsx).\n */\n\nexport type StateAction =\n | { label: string; onClick: () => void; icon?: ReactNode }\n | { label: string; to: string; icon?: ReactNode };\n\nfunction ActionButton({ action, primary = true }: { action: StateAction; primary?: boolean }) {\n if (\"to\" in action) {\n return (\n <Link to={action.to} className={buttonClasses(primary ? \"primary\" : \"secondary\")}>\n {action.icon}\n {action.label}\n </Link>\n );\n }\n return (\n <Button variant={primary ? \"primary\" : \"secondary\"} icon={action.icon} onClick={action.onClick}>\n {action.label}\n </Button>\n );\n}\n\nfunction Panel({\n icon,\n title,\n children,\n actions,\n className,\n role,\n}: {\n icon: ReactNode;\n title: ReactNode;\n children?: ReactNode;\n actions?: ReactNode;\n className?: string;\n role?: string;\n}) {\n return (\n <div\n role={role}\n className={cn(\n \"mx-auto flex w-full max-w-md flex-col items-center gap-3 px-4 py-10 text-center\",\n className,\n )}\n >\n <div className=\"text-muted\" aria-hidden>\n {icon}\n </div>\n <h2 className=\"text-base font-semibold\">{title}</h2>\n {children && <div className=\"text-sm text-muted\">{children}</div>}\n {actions && <div className=\"flex flex-wrap justify-center gap-2\">{actions}</div>}\n </div>\n );\n}\n\n/** 1. Initial loading. */\nexport function LoadingState({\n label = \"Loading…\",\n className,\n}: {\n label?: string;\n className?: string;\n}) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"flex items-center justify-center gap-2 px-4 py-10 text-sm text-muted\",\n className,\n )}\n >\n <Spinner />\n <span>{label}</span>\n </div>\n );\n}\n\n/** 2. Empty state with a next action. */\nexport function EmptyState({\n title,\n description,\n action,\n secondaryAction,\n icon,\n className,\n}: {\n title: string;\n description?: ReactNode;\n action?: StateAction;\n secondaryAction?: StateAction;\n icon?: ReactNode;\n className?: string;\n}) {\n return (\n <Panel\n icon={icon ?? <Inbox className=\"size-8\" />}\n title={title}\n className={className}\n actions={\n (action || secondaryAction) && (\n <>\n {action && <ActionButton action={action} />}\n {secondaryAction && <ActionButton action={secondaryAction} primary={false} />}\n </>\n )\n }\n >\n {description}\n </Panel>\n );\n}\n\n/** 3. Reconnecting with last-known-data indication. Renders nothing while live. */\nexport function ReconnectingBanner({\n state,\n lastSyncedAt,\n onRetry,\n className,\n}: {\n state: ConnectionState;\n lastSyncedAt: string | null;\n onRetry?: () => void;\n className?: string;\n}) {\n if (state === \"live\" || (state === \"connecting\" && !lastSyncedAt)) return null;\n const offline = state === \"offline\";\n const when = lastSyncedAt ? formatTime(lastSyncedAt) : \"an earlier session\";\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"flex items-center gap-2 border-b border-border bg-warning-soft px-3 py-1.5 text-sm text-text\",\n className,\n )}\n >\n {offline ? (\n <ServerOff aria-hidden className=\"size-4 shrink-0 text-warning\" />\n ) : (\n <RefreshCw aria-hidden className=\"size-4 shrink-0 animate-spin text-warning\" />\n )}\n <span className=\"min-w-0 flex-1\">\n {offline ? \"Offline\" : \"Reconnecting…\"} showing last known data from{\" \"}\n <time dateTime={lastSyncedAt ?? undefined}>{when}</time>\n </span>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"tap shrink-0 rounded px-2 py-0.5 font-medium text-accent hover:bg-surface-2\"\n >\n Retry now\n </button>\n )}\n </div>\n );\n}\n\n/** 4. Host unavailable (unreachable or reconnecting). Never claims completion. */\nexport function HostUnavailable({\n hostName,\n connectivity = \"unreachable\",\n lastSeenAt,\n detail,\n compact,\n className,\n}: {\n hostName: string;\n connectivity?: \"reconnecting\" | \"unreachable\";\n lastSeenAt?: string | null;\n detail?: ReactNode;\n /** Inline banner instead of a full panel. */\n compact?: boolean;\n className?: string;\n}) {\n const title =\n connectivity === \"reconnecting\"\n ? `Host ${hostName} is reconnecting`\n : `Host ${hostName} is unreachable`;\n const body = (\n <>\n {lastSeenAt ? `Last seen ${formatRelative(lastSeenAt)}. ` : \"\"}\n {detail ?? \"Work on this host keeps its last known state; nothing is restarted elsewhere.\"}\n </>\n );\n if (compact) {\n return (\n <div\n role=\"status\"\n className={cn(\n \"flex items-start gap-2 rounded-md border border-border bg-danger-soft px-3 py-2 text-sm\",\n className,\n )}\n >\n <ServerOff aria-hidden className=\"mt-0.5 size-4 shrink-0 text-danger\" />\n <div className=\"min-w-0\">\n <div className=\"font-medium\">{title}</div>\n <div className=\"text-muted\">{body}</div>\n </div>\n </div>\n );\n }\n return (\n <Panel\n role=\"status\"\n icon={<ServerOff className=\"size-8\" />}\n title={title}\n className={className}\n >\n {body}\n </Panel>\n );\n}\n\n/** 5. Permission/interaction pending: a strip linking to the first unanswered item. */\nexport function InteractionPending({\n count,\n to,\n onOpen,\n label,\n className,\n}: {\n count: number;\n to?: string;\n onOpen?: () => void;\n label?: string;\n className?: string;\n}) {\n if (count <= 0) return null;\n const text = label ?? (count === 1 ? \"Needs your answer\" : `${count} questions need your answer`);\n const inner = (\n <>\n <MessageCircleQuestion aria-hidden className=\"size-4 shrink-0 text-warning\" />\n <span className=\"min-w-0 flex-1 truncate font-medium\">{text}</span>\n <span className=\"shrink-0 text-accent\">Answer</span>\n </>\n );\n const cls = cn(\n \"tap flex w-full items-center gap-2 border border-border bg-warning-soft px-3 py-2 text-left text-sm rounded-md\",\n className,\n );\n if (to)\n return (\n <Link to={to} className={cls} role=\"status\">\n {inner}\n </Link>\n );\n return (\n <button type=\"button\" onClick={onOpen} className={cls}>\n {inner}\n </button>\n );\n}\n\n/** 6. Unsupported capability: says exactly what is not available and what to do instead. */\nexport function UnsupportedCapability({\n capability,\n reason,\n fallback,\n className,\n}: {\n capability: string;\n reason: ReactNode;\n fallback?: ReactNode;\n className?: string;\n}) {\n return (\n <div\n role=\"note\"\n className={cn(\n \"flex items-start gap-2 rounded-md border border-border bg-surface-2 px-3 py-2 text-sm\",\n className,\n )}\n >\n <Puzzle aria-hidden className=\"mt-0.5 size-4 shrink-0 text-muted\" />\n <div className=\"min-w-0\">\n <div className=\"font-medium\">{capability} is not available here</div>\n <div className=\"text-muted\">{reason}</div>\n {fallback && <div className=\"mt-1\">{fallback}</div>}\n </div>\n </div>\n );\n}\n\n/** 7. Recoverable error with retry. */\nexport function ErrorState({\n title = \"Something went wrong\",\n error,\n onRetry,\n compact,\n className,\n}: {\n title?: string;\n error: unknown;\n onRetry?: () => void;\n compact?: boolean;\n className?: string;\n}) {\n const message = error instanceof Error ? error.message : String(error ?? \"\");\n if (compact) {\n return (\n <div\n role=\"alert\"\n className={cn(\n \"flex items-start gap-2 rounded-md border border-border bg-danger-soft px-3 py-2 text-sm\",\n className,\n )}\n >\n <TriangleAlert aria-hidden className=\"mt-0.5 size-4 shrink-0 text-danger\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-medium\">{title}</div>\n {message && <div className=\"break-words text-muted\">{message}</div>}\n </div>\n {onRetry && (\n <Button size=\"sm\" onClick={onRetry} icon={<RefreshCw className=\"size-3.5\" />}>\n Retry\n </Button>\n )}\n </div>\n );\n }\n return (\n <Panel\n role=\"alert\"\n icon={<TriangleAlert className=\"size-8 text-danger\" />}\n title={title}\n className={className}\n actions={\n onRetry && (\n <Button variant=\"primary\" onClick={onRetry} icon={<RefreshCw className=\"size-4\" />}>\n Retry\n </Button>\n )\n }\n >\n <span className=\"break-words\">{message}</span>\n </Panel>\n );\n}\n\n/** 8. Irrecoverable error with a diagnostics link. */\nexport function FatalError({\n title = \"Switchyard cannot show this view\",\n error,\n diagnosticsHref = \"/settings/diagnostics\",\n className,\n}: {\n title?: string;\n error: unknown;\n diagnosticsHref?: string;\n className?: string;\n}) {\n const message = error instanceof Error ? error.message : String(error ?? \"\");\n return (\n <Panel\n role=\"alert\"\n icon={<CircleAlert className=\"size-8 text-danger\" />}\n title={title}\n className={className}\n actions={\n <>\n <a href={diagnosticsHref} className={buttonClasses(\"primary\")}>\n Open diagnostics\n </a>\n <Button onClick={() => location.reload()}>Reload</Button>\n </>\n }\n >\n <span className=\"break-words\">{message}</span>\n </Panel>\n );\n}\n"],"ignoreList":[0,1,5,6,7,8,9,10,11],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{n as e}from"./jsx-runtime-D13aM9HY.js";var t={name:`trash`,size:24,node:[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]],aliases:[`trash-2`]};t.node;var n=e(t);export{n as t};
|
|
2
|
+
//# sourceMappingURL=trash-C6X2OLrI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trash-C6X2OLrI.js","names":["createLucideIcon","__iconData","Trash"],"sources":["../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/trash.mjs"],"sourcesContent":["/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"trash\",\n size: 24,\n node: [\n [\"path\", { d: \"M10 11v6\", key: \"nco0om\" }],\n [\"path\", { d: \"M14 11v6\", key: \"outv1u\" }],\n [\"path\", { d: \"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\", key: \"miytrc\" }],\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\", key: \"e791ji\" }]\n ],\n aliases: [\"trash-2\"]\n};\n__iconData.node;\nconst Trash = createLucideIcon(__iconData);\n\nexport { __iconData, Trash as default };\n//# sourceMappingURL=trash.mjs.map\n"],"ignoreList":[0],"mappings":"A,8CASA,IAAMC,EAAa,CACjB,KAAM,QACN,KAAM,GACN,KAAM,CACJ,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,2CAA4C,IAAK,QAAS,CAAC,EACzE,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAS,CAAC,EACxC,CAAC,OAAQ,CAAE,EAAG,yCAA0C,IAAK,QAAS,CAAC,CACzE,EACA,QAAS,CAAC,SAAS,CACrB,EACAA,EAAW,KACX,IAAMC,EAAQF,EAAiBC,CAAU,E"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{_ as e,m as t,n,t as r}from"./jsx-runtime-D13aM9HY.js";import{A as i,B as a,E as o,G as s,H as c,P as l,U as u,V as d,W as f,a as p,c as ee,h as m,i as te,l as h,n as g}from"./states-DrTQuYXw.js";import{t as _}from"./search-C6cn5WOo.js";import{M as v,N as y,c as b,g as x,p as S,t as ne}from"./index-B11DJFHW.js";import{n as re}from"./TextArea-BsQHOQMe.js";import{s as C}from"./dist-C4YmDHPG.js";import{r as ie,t as ae}from"./Overlay-B9h5oAe6.js";var w={name:`funnel`,size:24,node:[[`path`,{d:`M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z`,key:`sc7q7i`}]],aliases:[`filter`]};w.node;var oe=n(w),T=e(t(),1),E=e=>`/api/tasks/${encodeURIComponent(e)}`;function D(e){if(!e||typeof e!=`object`)return null;let t=e;return t.task&&typeof t.task==`object`?t.task:typeof t.id==`string`&&typeof t.state==`string`?t:null}function O(e){let t=D(e);return t?(l.setState(e=>{let n=e.tasks[t.id];return n&&n.updatedAt>t.updatedAt?{}:{tasks:{...e.tasks,[t.id]:t}}}),t):null}async function k(e){let t=O(await u(`/api/tasks`,e));if(!t)throw Error(`The coordinator returned an unexpected response`);return t}async function A(e,t){return O(await c(E(e),t))}async function j(e){await a(E(e)),l.setState(t=>{if(!t.tasks[e])return{};let{[e]:n,...r}=t.tasks;return{tasks:r}})}async function M(e,t){return O(await u(`${E(e)}/move`,t))}async function N(e,t,n,r){return O(await u(`${E(e)}/${t}${r??``}`,n))}async function P(e,t){return O(await u(`${E(e)}/request-changes`,{feedback:t}))}function F(e,t){return d(`${E(e)}/eligibility`,void 0,t)}async function I(e,t){let n=await d(`${E(e)}/runs`,void 0,t);return Array.isArray(n)?n:n.runs??[]}async function L(e){await u(`/api/dispatch/pause`,{paused:e}),l.setState({dispatchPaused:e})}function R(e){return!s(e)||e.status!==409&&e.code!==`invalid_transition`?!1:e.details?.needsConfirm===!0||/confirm/i.test(e.message)}function z(e){if(!s(e))return!1;let t=e.details;return Array.isArray(t?.choices)||t?.needsChoice===!0||t?.onRunning===!0||/pause automation or stop execution/i.test(e.message)}var B=[`backlog`,`ready`,`in_progress`,`review`,`done`],V={backlog:`Backlog`,ready:`Ready`,in_progress:`In progress`,review:`Review`,done:`Done`,canceled:`Canceled`},H={search:``,priorities:[],hostId:null,attentionOnly:!1,blockedOnly:!1,showCanceled:!1,showCompleted:!0,sort:`priority`};function U(e){let t=e&&typeof e==`object`?e:{};return{search:typeof t.search==`string`?t.search:``,priorities:Array.isArray(t.priorities)?t.priorities.filter(e=>[0,1,2,3].includes(e)):[],hostId:typeof t.hostId==`string`?t.hostId:null,attentionOnly:t.attentionOnly===!0,blockedOnly:t.blockedOnly===!0,showCanceled:t.showCanceled===!0,showCompleted:t.showCompleted!==!1,sort:t.sort===`updated`||t.sort===`created`?t.sort:`priority`}}function W(e,t){let n=[];e.search.trim()&&n.push({key:`search`,label:`Search: ${e.search.trim()}`,clear:e=>({...e,search:``})});for(let t of e.priorities)n.push({key:`priority-${t}`,label:`Priority: ${C[t]}`,clear:e=>({...e,priorities:e.priorities.filter(e=>e!==t)})});return e.hostId&&n.push({key:`host`,label:`Host: ${t(e.hostId)}`,clear:e=>({...e,hostId:null})}),e.attentionOnly&&n.push({key:`attention`,label:`Needs attention`,clear:e=>({...e,attentionOnly:!1})}),e.blockedOnly&&n.push({key:`blocked`,label:`Blocked`,clear:e=>({...e,blockedOnly:!1})}),e.showCanceled&&n.push({key:`canceled`,label:`Including canceled`,clear:e=>({...e,showCanceled:!1})}),n}function G(e,t){return(e.currentRunId?t[e.currentRunId]:void 0)?.hostId??e.policy.hostId??null}function K(e,t,n){if(e.hiddenFromBoard||n.projectId&&e.projectId!==n.projectId||e.state===`canceled`&&!t.showCanceled)return!1;let r=t.search.trim().toLowerCase();return!(r&&!`${e.title}\n${e.objective}`.toLowerCase().includes(r)||t.priorities.length>0&&!t.priorities.includes(e.priority)||t.hostId&&G(e,n.runs)!==t.hostId||t.attentionOnly&&!n.attentionTaskIds.has(e.id)||t.blockedOnly&&!e.blocked)}function q(e,t){let n=[...e];return t===`updated`?n.sort((e,t)=>t.lastActivityAt.localeCompare(e.lastActivityAt)):t===`created`?n.sort((e,t)=>t.createdAt.localeCompare(e.createdAt)):n.sort((e,t)=>e.priority-t.priority||e.position-t.position||e.createdAt.localeCompare(t.createdAt)),n}function se(e,t,n){let r={backlog:[],ready:[],in_progress:[],review:[],done:[],canceled:[]};for(let i of Object.values(e))K(i,t,n)&&r[i.state].push(i);for(let e of Object.keys(r))r[e]=q(r[e],t.sort);return r}function ce(e){return e.showCanceled?[...B,`canceled`]:B}var J={backlog:[`ready`,`canceled`],ready:[`backlog`,`in_progress`,`canceled`],in_progress:[`review`,`ready`,`backlog`,`canceled`,`done`],review:[`in_progress`,`done`,`ready`,`canceled`],done:[`ready`,`backlog`],canceled:[`backlog`]};function le(e){return!!e&&[`queued`,`dispatching`,`uncertain`,`running`,`waiting_input`,`checking`].includes(e.state)}function ue(e,t){let n=[];e.state!==`review`&&n.push(`The task has not been through review.`),e.acceptanceCriteria.length>0&&n.push(`${e.acceptanceCriteria.length} acceptance ${e.acceptanceCriteria.length===1?`criterion has`:`criteria have`} not been confirmed.`);let r=(e.policy.completion.checks?.length??0)>0,i=t?.checks.filter(e=>e.exitCode!==0)??[];return i.length>0?n.push(`Checks failing: ${i.map(e=>e.command).join(`, `)}.`):r&&(!t||t.checks.length===0)&&n.push(`Required checks have not run.`),e.policy.completion.requireHumanReview&&e.state===`review`&&n.push(`Human review is required: moving to Done accepts the work.`),n}function de(e,t,n){if(e.state===t)return{kind:`noop`};let r=e.state;if(!J[r].includes(t))return{kind:`invalid`,reason:fe(r,t)};if(r===`ready`&&t===`in_progress`)return{kind:`run_now`};if(r===`review`&&t===`in_progress`)return{kind:`new_attempt`};if(r===`in_progress`&&(t===`ready`||t===`backlog`))return{kind:`choose_running`};if(t===`done`){let t=ue(e,n);if(t.length>0)return{kind:`confirm_done`,reasons:t}}return{kind:`move`}}function fe(e,t){let n=V[e],r=V[t];return t===`in_progress`?e===`backlog`?`A Backlog task cannot start directly. Move it to Ready first; the dispatcher starts it when it is eligible.`:`${n} tasks cannot be moved to In progress. Only the dispatcher starts work (Run now from Ready).`:t===`review`?`Only a finished run moves a task to Review. Run the task, or use Done to accept it.`:e===`canceled`?`A canceled task can only be restored to Backlog.`:e===`done`&&t===`canceled`?`A Done task cannot be canceled. Reopen it first.`:e===`backlog`&&t===`done`?`A Backlog task cannot be marked Done. Make it ready and review its work first.`:e===`ready`&&t===`done`?`A task that has not run cannot be marked Done. Run it, or cancel it.`:`Moving from ${n} to ${r} is not allowed.`}function pe(e){return J[e.state]}function me(e,t,n){let r=e.filter(e=>e.id!==n);if(r.length===0)return 1;if(t===null)return r[r.length-1].position+1;let i=r.findIndex(e=>e.id===t);if(i<0)return r[r.length-1].position+1;let a=r[i].position;return((i>0?r[i-1].position:a-2)+a)/2}var Y={dependency:`Waiting on dependencies`,host_offline:`Host offline`,project_limit:`Project run limit reached`,workspace_occupied:`Workspace occupied`,scheduled_time:`Scheduled for later`,invalid_configuration:`Invalid configuration`,dispatch_paused:`Dispatch paused`,project_automation_disabled:`Project automation is off`,not_ready:`Not ready`,already_dispatched:`Already dispatched`,retry_backoff:`Retrying after a failure`};function he(e){return e.eligible?`Will start automatically on ${e.hostName}`:`Will wait: ${e.message||Y[e.wait]}`}function ge(e,t){let{project:n}=e;if(!n)return{eligible:!1,wait:`invalid_configuration`,message:`Choose a project`};if(t.dispatchPaused)return{eligible:!1,wait:`dispatch_paused`,message:`Dispatch is paused; resume it to start new work`};if(!n.automationEnabled)return{eligible:!1,wait:`project_automation_disabled`,message:`Automation is off for ${n.name}`};let r=e.dependencies.map(e=>t.tasks[e]).filter(e=>!!e&&e.state!==`done`);if(r.length>0)return{eligible:!1,wait:`dependency`,message:`Waiting on ${r.map(e=>e.title).join(`, `)}`};if(e.notBefore&&Date.parse(e.notBefore)>Date.now())return{eligible:!1,wait:`scheduled_time`,message:`Scheduled for ${new Date(e.notBefore).toLocaleString()}`};let i=e.hostId??n.defaultHostId,a=i?t.hosts[i]:void 0;return!a||a.revokedAt?{eligible:!1,wait:`invalid_configuration`,message:`No host is configured for this project`}:a.piCompatible?a.connectivity===`connected`?(t.runningByProject[n.id]??0)>=n.maxConcurrentRuns?{eligible:!1,wait:`project_limit`,message:`${n.name} already runs ${n.maxConcurrentRuns} of ${n.maxConcurrentRuns} allowed tasks`}:{eligible:!0,hostId:a.id,hostName:a.name}:{eligible:!1,wait:`host_offline`,message:`${a.name} is offline`}:{eligible:!1,wait:`invalid_configuration`,message:`Pi on ${a.name} is not compatible`}}function _e(e){let t=new Map;for(let n of Object.values(e)){if(n.resolvedAt||!n.taskId)continue;let e=t.get(n.taskId)??[];e.push(n),t.set(n.taskId,e)}return t}function ve(e,t){let n=e.dependencies.length;if(n===0)return null;let r=e.dependencies.filter(e=>t[e]?.state!==`done`).length,i=`${n} ${n===1?`dependency`:`dependencies`}`;return r>0?`${i} (${r} open)`:`${i} (all done)`}var X=r(),Z=`tap h-9 min-w-0 rounded-md border border-border bg-surface px-2 text-base text-text md:text-sm`;function ye({board:e,className:t}){let n=i(),r=(0,T.useId)();return(0,X.jsxs)(`div`,{className:m(`flex min-w-0 items-center gap-2`,t),children:[(0,X.jsx)(`label`,{htmlFor:r,className:`sr-only`,children:`Project`}),(0,X.jsxs)(`select`,{id:r,className:m(Z,`w-full max-w-56`),value:e.projectId??``,onChange:t=>e.setProjectId(t.target.value||null),children:[(0,X.jsx)(`option`,{value:``,children:`All projects`}),n.map(e=>(0,X.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]})}function be({board:e,className:t}){let n=(0,T.useId)();return(0,X.jsxs)(`div`,{className:m(`relative min-w-0`,t),children:[(0,X.jsx)(`label`,{htmlFor:n,className:`sr-only`,children:`Search tasks`}),(0,X.jsx)(_,{"aria-hidden":!0,className:`pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-subtle`}),(0,X.jsx)(re,{id:n,type:`search`,placeholder:`Search tasks`,className:`pl-8`,value:e.filters.search,onChange:t=>e.setFilters({...e.filters,search:t.target.value})})]})}function xe({board:e}){let t=(0,T.useId)();return(0,X.jsxs)(`div`,{className:`flex items-center gap-1.5 text-sm`,children:[(0,X.jsx)(`label`,{htmlFor:t,className:`text-muted`,children:`Sort`}),(0,X.jsxs)(`select`,{id:t,className:Z,value:e.filters.sort,onChange:t=>e.setFilters({...e.filters,sort:t.target.value}),children:[(0,X.jsx)(`option`,{value:`priority`,children:`Priority`}),(0,X.jsx)(`option`,{value:`updated`,children:`Recently updated`}),(0,X.jsx)(`option`,{value:`created`,children:`Newest`})]})]})}function Se({board:e}){return(0,X.jsxs)(`label`,{className:`tap inline-flex items-center gap-2 text-sm`,children:[(0,X.jsx)(`input`,{type:`checkbox`,checked:e.filters.showCompleted,onChange:t=>e.setFilters({...e.filters,showCompleted:t.target.checked})}),`Show completed`]})}function Ce({compact:e}){let t=l(e=>e.dispatchPaused),[n,r]=(0,T.useState)(!1),i=t?y:v;return(0,X.jsxs)(`div`,{className:`flex min-w-0 flex-wrap items-center gap-2 text-sm`,children:[(0,X.jsxs)(`span`,{role:`status`,className:m(`inline-flex items-center gap-1.5 font-medium`,t?`text-warning`:`text-success`),children:[(0,X.jsx)(i,{"aria-hidden":!0,className:`size-4`}),(0,X.jsx)(`span`,{className:`text-text`,children:t?`Automation paused`:`Automation enabled`})]}),(0,X.jsx)(h,{size:`sm`,busy:n,onClick:async()=>{r(!0);try{await L(!t),b.success(t?`Dispatch resumed. Ready tasks start when eligible.`:`Dispatch paused. Running work continues; nothing new starts.`)}catch(e){b.error(`Could not ${t?`resume`:`pause`} dispatch: ${f(e)}`)}finally{r(!1)}},children:t?`Resume dispatch`:e?`Pause`:`Pause dispatch`})]})}function we({value:e,onChange:t,withSort:n}){let r=o(),i=(0,T.useId)(),a=(n,r)=>t({...e,priorities:r?[...e.priorities,n]:e.priorities.filter(e=>e!==n)});return(0,X.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,X.jsxs)(`fieldset`,{className:`flex flex-col gap-1`,children:[(0,X.jsx)(`legend`,{className:`mb-1 text-sm font-medium`,children:`Priority`}),(0,X.jsx)(`div`,{className:`flex flex-wrap gap-x-4`,children:C.map((t,n)=>(0,X.jsxs)(`label`,{className:`tap inline-flex items-center gap-2 text-sm`,children:[(0,X.jsx)(`input`,{type:`checkbox`,checked:e.priorities.includes(n),onChange:e=>a(n,e.target.checked)}),t]},t))})]}),(0,X.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,X.jsx)(`label`,{htmlFor:`${i}-host`,className:`text-sm font-medium`,children:`Host`}),(0,X.jsxs)(`select`,{id:`${i}-host`,className:Z,value:e.hostId??``,onChange:n=>t({...e,hostId:n.target.value||null}),children:[(0,X.jsx)(`option`,{value:``,children:`Any host`}),r.map(e=>(0,X.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]}),(0,X.jsxs)(`fieldset`,{className:`flex flex-col gap-1`,children:[(0,X.jsx)(`legend`,{className:`mb-1 text-sm font-medium`,children:`Show`}),(0,X.jsxs)(`label`,{className:`tap inline-flex items-center gap-2 text-sm`,children:[(0,X.jsx)(`input`,{type:`checkbox`,checked:e.attentionOnly,onChange:n=>t({...e,attentionOnly:n.target.checked})}),`Only tasks that need attention`]}),(0,X.jsxs)(`label`,{className:`tap inline-flex items-center gap-2 text-sm`,children:[(0,X.jsx)(`input`,{type:`checkbox`,checked:e.blockedOnly,onChange:n=>t({...e,blockedOnly:n.target.checked})}),`Only blocked tasks`]}),(0,X.jsxs)(`label`,{className:`tap inline-flex items-center gap-2 text-sm`,children:[(0,X.jsx)(`input`,{type:`checkbox`,checked:e.showCanceled,onChange:n=>t({...e,showCanceled:n.target.checked})}),`Canceled tasks`]}),(0,X.jsxs)(`label`,{className:`tap inline-flex items-center gap-2 text-sm`,children:[(0,X.jsx)(`input`,{type:`checkbox`,checked:e.showCompleted,onChange:n=>t({...e,showCompleted:n.target.checked})}),`Completed tasks`]})]}),n&&(0,X.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,X.jsx)(`label`,{htmlFor:`${i}-sort`,className:`text-sm font-medium`,children:`Sort`}),(0,X.jsxs)(`select`,{id:`${i}-sort`,className:Z,value:e.sort,onChange:n=>t({...e,sort:n.target.value}),children:[(0,X.jsx)(`option`,{value:`priority`,children:`Priority`}),(0,X.jsx)(`option`,{value:`updated`,children:`Recently updated`}),(0,X.jsx)(`option`,{value:`created`,children:`Newest`})]})]})]})}function Q({board:e,mobile:t}){let[n,r]=(0,T.useState)(!1),[i,a]=(0,T.useState)(e.filters),o=l(e=>e.hosts),s=W(e.filters,e=>o[e]?.name??`host`).filter(e=>e.key!==`search`).length,c=t?ie:ae;return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsxs)(h,{icon:(0,X.jsx)(oe,{className:`size-4`}),onClick:()=>{a(e.filters),r(!0)},"aria-label":s?`Filters, ${s} active`:`Filters`,children:[`Filters`,s>0&&(0,X.jsx)(S,{tone:`accent`,children:s})]}),(0,X.jsx)(c,{open:n,onClose:()=>r(!1),title:`Filter tasks`,footer:(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(h,{variant:`ghost`,onClick:()=>a({...H,search:i.search}),children:`Reset`}),(0,X.jsx)(h,{variant:`primary`,onClick:()=>{e.setFilters(i),r(!1)},children:`Show results`})]}),children:(0,X.jsx)(we,{value:i,onChange:a,withSort:t})})]})}function Te({board:e,includeSearch:t}){let n=l(e=>e.hosts),r=W(e.filters,e=>n[e]?.name??`Unknown host`).filter(e=>t||e.key!==`search`);return r.length===0?null:(0,X.jsxs)(`ul`,{"data-testid":`filter-chips`,"aria-label":`Active filters`,className:`flex min-w-0 flex-wrap gap-1.5`,children:[r.map(t=>(0,X.jsx)(`li`,{className:`min-w-0`,children:(0,X.jsxs)(`button`,{type:`button`,onClick:()=>e.setFilters(t.clear(e.filters)),"aria-label":`Remove filter ${t.label}`,className:`tap inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-surface-2 px-2.5 py-0.5 text-xs font-medium`,children:[(0,X.jsx)(`span`,{className:`truncate`,children:t.label}),(0,X.jsx)(x,{"aria-hidden":!0,className:`size-3.5 shrink-0`})]})},t.key)),r.length>1&&(0,X.jsx)(`li`,{children:(0,X.jsx)(`button`,{type:`button`,className:`tap rounded px-2 py-0.5 text-xs font-medium text-accent`,onClick:()=>e.setFilters({...H,sort:e.filters.sort}),children:`Clear all`})})]})}function Ee({board:e}){let t=l(e=>e.tasks),n=l(e=>e.runs),r=l(e=>e.hosts),i=l(e=>e.interactions),{offline:a,pending:o}=(0,T.useMemo)(()=>{let a=new Set,o=new Set;for(let i of Object.values(t)){if(e.projectId&&i.projectId!==e.projectId)continue;i.sessionId&&o.add(i.sessionId);let t=i.currentRunId?n[i.currentRunId]:void 0;if(i.state===`in_progress`&&t?.hostId){let e=r[t.hostId];e&&e.connectivity!==`connected`&&a.add(e.id)}}let s=Object.values(i).filter(e=>e.state===`pending`&&o.has(e.sessionId)).sort((e,t)=>e.createdAt.localeCompare(t.createdAt));return{offline:[...a].map(e=>r[e]),pending:s}},[t,n,r,i,e.projectId]),c=e.now.error,u=[];for(let e of a)u.push((0,X.jsx)(te,{compact:!0,hostName:e.name,connectivity:e.connectivity===`reconnecting`?`reconnecting`:`unreachable`,lastSeenAt:e.lastSeenAt,detail:`Its In progress tasks keep their last known state; nothing is restarted elsewhere.`},`host-${e.id}`));return o.length>0&&u.push((0,X.jsx)(p,{count:o.length,to:ne.interaction(o[0].sessionId,o[0].id),label:o.length===1?`A task needs your answer`:`${o.length} questions need your answer`},`pending`)),c!=null&&(s(c)&&c.status===404?u.push((0,X.jsx)(ee,{capability:`Queue details`,reason:`This coordinator does not report why Ready tasks are waiting.`},`now`)):u.push((0,X.jsx)(g,{compact:!0,title:`Could not load the dispatch queue`,error:f(c),onRetry:e.now.reload},`now`))),u.length===0?null:(0,X.jsx)(`div`,{className:`flex flex-col gap-2 px-4 pt-2`,children:u})}function $(e,t,n={}){let[r,i]=(0,T.useState)(void 0),[a,o]=(0,T.useState)(null),[s,c]=(0,T.useState)(e!==null),[l,u]=(0,T.useState)(0),d=(0,T.useRef)(t);return d.current=t,(0,T.useEffect)(()=>{if(e===null){c(!1);return}let t=new AbortController;return c(!0),d.current(t.signal).then(e=>{t.signal.aborted||(i(e),o(null))}).catch(e=>{t.signal.aborted||e instanceof DOMException&&e.name===`AbortError`||o(e)}).finally(()=>{t.signal.aborted||c(!1)}),()=>t.abort()},[e,l]),(0,T.useEffect)(()=>{if(!n.refreshMs||e===null)return;let t=setInterval(()=>{document.visibilityState===`visible`&&u(e=>e+1)},n.refreshMs);return()=>clearInterval(t)},[n.refreshMs,e]),{data:r,error:a,loading:s,reload:(0,T.useCallback)(()=>u(e=>e+1),[])}}function De(e=!0){let t=$(e?`now`:null,e=>d(`/api/now`,void 0,e),{refreshMs:15e3}),n=l(e=>e.tasks),r=l(e=>e.runs),i=l(e=>e.dispatchPaused),a=(0,T.useRef)(!0),{reload:o}=t;return(0,T.useEffect)(()=>{if(a.current){a.current=!1;return}if(!e)return;let t=setTimeout(o,500);return()=>clearTimeout(t)},[n,r,i,e,o]),t}export{R as A,ge as C,F as D,j as E,P as M,N,I as O,A as P,me as S,k as T,le as _,Ce as a,_e as b,ye as c,H as d,V as f,he as g,ve as h,Se as i,z as j,M as k,be as l,se as m,$ as n,Q as o,Y as p,Ee as r,Te as s,De as t,xe as u,pe as v,ce as w,de as x,U as y};
|
|
2
|
+
//# sourceMappingURL=useNow-ChB9z-N6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNow-ChB9z-N6.js","names":["useId","useState","_Fragment","Filter","useMemo","useState","useRef","useCallback","useRef","__toESM","require_react","require_jsx_runtime","useProjects","apiDelete","useHosts","isApiError","apiPatch","useSyncStore","apiPost","apiGet","errorMessage","InteractionPending","UnsupportedCapability","cn","HostUnavailable","Button","ErrorState","Search","CirclePlay","CirclePause","toast","X","Badge","ROUTES","TextInput","PRIORITY_LABELS","Sheet","Dialog","__iconData","Funnel","createLucideIcon","import_react","base","id","asTask","res","r","upsertTask","task","prev","s","createTask","body","updateTask","patch","deleteTask","_gone","rest","moveTask","taskAction","action","query","requestChanges","fetchEligibility","signal","fetchRuns","setDispatchPaused","paused","needsConfirmation","needsRunningChoice","d","BOARD_COLUMNS","STATE_LABELS","DEFAULT_FILTERS","normalizeFilters","v","raw","p","activeFilterChips","chips","f","x","q","hostName","taskHostId","runs","matchesFilters","ctx","sortTasks","out","tasks","sort","b","a","buildColumns","t","k","visibleColumns","TRANSITIONS","isRunActive","run","unresolvedForDone","reasons","checksRequired","failing","c","planMove","to","from","invalidReason","moveTargets","positionFor","list","column","movingId","beforeId","idx","next","WAIT_LABELS","eligibilityText","previewEligibility","input","project","state","unmet","hostId","host","openAttentionByTask","m","attention","dependencySummary","open","import_jsx_runtime","selectCls","ProjectSelect","projects","className","board","e","SearchBox","SortSelect","CompletedToggle","DispatchToggle","busy","setBusy","Icon","compact","FilterFields","hosts","togglePriority","onChange","value","on","i","l","h","withSort","FilterButton","setOpen","draft","setDraft","count","Surface","mobile","FilterChips","includeSearch","BoardNotices","interactions","offlineIds","sessionIds","pend","nowErr","notices","offline","pending","useResource","data","setData","error","setError","loading","setLoading","key","nonce","setNonce","fetcherRef","fetcher","ctrl","opts","n","useNow","enabled","first","reload"],"sources":["../../../../node_modules/.pnpm/lucide-react@1.61.0_@types+react@19.3.0_react@19.3.1/node_modules/lucide-react/dist/esm/icons/funnel.mjs","../../src/features/board/api.ts","../../src/features/board/logic.ts","../../src/features/board/BoardChrome.tsx","../../src/features/board/useResource.ts","../../src/features/now/useNow.ts"],"sourcesContent":["/**\n * @license lucide-react v1.61.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"funnel\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\",\n key: \"sc7q7i\"\n }\n ]\n ],\n aliases: [\"filter\"]\n};\n__iconData.node;\nconst Funnel = createLucideIcon(__iconData);\n\nexport { __iconData, Funnel as default };\n//# sourceMappingURL=funnel.mjs.map\n","import type { Eligibility, Run, Task, TaskState } from \"@switchyard/protocol\";\nimport { apiDelete, apiGet, apiPatch, apiPost, isApiError } from \"../../sync/api\";\nimport { useSyncStore } from \"../../sync/store\";\n\n/** REST helpers for tasks. Results are written to the store once acknowledged (no optimistic success). */\n\nconst base = (id: string) => `/api/tasks/${encodeURIComponent(id)}`;\n\nfunction asTask(res: unknown): Task | null {\n if (!res || typeof res !== \"object\") return null;\n const r = res as { task?: Task; id?: string; state?: string };\n if (r.task && typeof r.task === \"object\") return r.task;\n if (typeof r.id === \"string\" && typeof r.state === \"string\") return r as Task;\n return null;\n}\n\n/** Store the acknowledged task unless a newer version already arrived over the socket. */\nexport function upsertTask(res: unknown): Task | null {\n const task = asTask(res);\n if (!task) return null;\n useSyncStore.setState((s) => {\n const prev = s.tasks[task.id];\n if (prev && prev.updatedAt > task.updatedAt) return {};\n return { tasks: { ...s.tasks, [task.id]: task } };\n });\n return task;\n}\n\nexport interface CreateTaskBody {\n projectId: string;\n title: string;\n objective: string;\n acceptanceCriteria: string[];\n dependencies: string[];\n priority: 0 | 1 | 2 | 3;\n state: \"backlog\" | \"ready\";\n notBefore?: string | null;\n policy?: Partial<Task[\"policy\"]>;\n}\n\nexport async function createTask(body: CreateTaskBody): Promise<Task> {\n const res = await apiPost<unknown>(\"/api/tasks\", body);\n const t = upsertTask(res);\n if (!t) throw new Error(\"The coordinator returned an unexpected response\");\n return t;\n}\n\nexport async function updateTask(id: string, patch: Record<string, unknown>): Promise<Task | null> {\n return upsertTask(await apiPatch<unknown>(base(id), patch));\n}\n\nexport async function deleteTask(id: string): Promise<void> {\n await apiDelete(base(id));\n useSyncStore.setState((s) => {\n if (!s.tasks[id]) return {};\n const { [id]: _gone, ...rest } = s.tasks;\n return { tasks: rest };\n });\n}\n\nexport interface MoveBody {\n to: TaskState;\n confirm?: boolean;\n onRunning?: \"pause\" | \"stop\";\n position?: number;\n}\n\nexport async function moveTask(id: string, body: MoveBody): Promise<Task | null> {\n return upsertTask(await apiPost<unknown>(`${base(id)}/move`, body));\n}\n\nexport type TaskAction = \"run-now\" | \"accept\" | \"new-attempt\" | \"reopen\" | \"cancel\";\n\nexport async function taskAction(\n id: string,\n action: TaskAction,\n body?: unknown,\n query?: string,\n): Promise<Task | null> {\n return upsertTask(await apiPost<unknown>(`${base(id)}/${action}${query ?? \"\"}`, body));\n}\n\nexport async function requestChanges(id: string, feedback: string[]): Promise<Task | null> {\n return upsertTask(await apiPost<unknown>(`${base(id)}/request-changes`, { feedback }));\n}\n\nexport function fetchEligibility(id: string, signal?: AbortSignal): Promise<Eligibility> {\n return apiGet<Eligibility>(`${base(id)}/eligibility`, undefined, signal);\n}\n\nexport async function fetchRuns(id: string, signal?: AbortSignal): Promise<Run[]> {\n const res = await apiGet<Run[] | { runs: Run[] }>(`${base(id)}/runs`, undefined, signal);\n return Array.isArray(res) ? res : (res.runs ?? []);\n}\n\nexport async function setDispatchPaused(paused: boolean): Promise<void> {\n await apiPost(\"/api/dispatch/pause\", { paused });\n useSyncStore.setState({ dispatchPaused: paused });\n}\n\n/** A 409 that asks the user to confirm (e.g. Done with unresolved checks). */\nexport function needsConfirmation(e: unknown): boolean {\n if (!isApiError(e)) return false;\n if (e.status !== 409 && e.code !== \"invalid_transition\") return false;\n const d = e.details as { needsConfirm?: boolean; needsChoice?: boolean } | undefined;\n return d?.needsConfirm === true || /confirm/i.test(e.message);\n}\n\n/** A 409 that asks for the running-work choice (pause automation or stop execution). */\nexport function needsRunningChoice(e: unknown): boolean {\n if (!isApiError(e)) return false;\n const d = e.details as\n | { needsChoice?: boolean; onRunning?: boolean; choices?: unknown }\n | undefined;\n return (\n Array.isArray(d?.choices) ||\n d?.needsChoice === true ||\n d?.onRunning === true ||\n /pause automation or stop execution/i.test(e.message)\n );\n}\n","import type {\n AttentionItem,\n Eligibility,\n Host,\n Priority,\n Project,\n Run,\n Task,\n TaskState,\n} from \"@switchyard/protocol\";\nimport { PRIORITY_LABELS } from \"@switchyard/protocol\";\n\n/**\n * Pure board helpers (filters, sorting, move planning, eligibility wording).\n * Kept free of React so they are unit-testable.\n */\n\nexport const BOARD_COLUMNS: TaskState[] = [\"backlog\", \"ready\", \"in_progress\", \"review\", \"done\"];\n\nexport const STATE_LABELS: Record<TaskState, string> = {\n backlog: \"Backlog\",\n ready: \"Ready\",\n in_progress: \"In progress\",\n review: \"Review\",\n done: \"Done\",\n canceled: \"Canceled\",\n};\n\nexport type BoardSort = \"priority\" | \"updated\" | \"created\";\n\nexport interface BoardFilters {\n search: string;\n priorities: Priority[];\n hostId: string | null;\n attentionOnly: boolean;\n blockedOnly: boolean;\n showCanceled: boolean;\n showCompleted: boolean;\n sort: BoardSort;\n}\n\nexport const DEFAULT_FILTERS: BoardFilters = {\n search: \"\",\n priorities: [],\n hostId: null,\n attentionOnly: false,\n blockedOnly: false,\n showCanceled: false,\n showCompleted: true,\n sort: \"priority\",\n};\n\nexport function normalizeFilters(raw: unknown): BoardFilters {\n const v = (raw && typeof raw === \"object\" ? raw : {}) as Partial<BoardFilters>;\n return {\n search: typeof v.search === \"string\" ? v.search : \"\",\n priorities: Array.isArray(v.priorities)\n ? (v.priorities.filter((p) => [0, 1, 2, 3].includes(p as number)) as Priority[])\n : [],\n hostId: typeof v.hostId === \"string\" ? v.hostId : null,\n attentionOnly: v.attentionOnly === true,\n blockedOnly: v.blockedOnly === true,\n showCanceled: v.showCanceled === true,\n showCompleted: v.showCompleted !== false,\n sort: v.sort === \"updated\" || v.sort === \"created\" ? v.sort : \"priority\",\n };\n}\n\nexport interface ActiveFilterChip {\n key: string;\n label: string;\n clear: (f: BoardFilters) => BoardFilters;\n}\n\n/** Removable chips for every non-default filter (search shown separately on desktop). */\nexport function activeFilterChips(\n f: BoardFilters,\n hostName: (id: string) => string,\n): ActiveFilterChip[] {\n const chips: ActiveFilterChip[] = [];\n if (f.search.trim())\n chips.push({\n key: \"search\",\n label: `Search: ${f.search.trim()}`,\n clear: (x) => ({ ...x, search: \"\" }),\n });\n for (const p of f.priorities)\n chips.push({\n key: `priority-${p}`,\n label: `Priority: ${PRIORITY_LABELS[p]}`,\n clear: (x) => ({ ...x, priorities: x.priorities.filter((q) => q !== p) }),\n });\n if (f.hostId)\n chips.push({\n key: \"host\",\n label: `Host: ${hostName(f.hostId)}`,\n clear: (x) => ({ ...x, hostId: null }),\n });\n if (f.attentionOnly)\n chips.push({\n key: \"attention\",\n label: \"Needs attention\",\n clear: (x) => ({ ...x, attentionOnly: false }),\n });\n if (f.blockedOnly)\n chips.push({ key: \"blocked\", label: \"Blocked\", clear: (x) => ({ ...x, blockedOnly: false }) });\n if (f.showCanceled)\n chips.push({\n key: \"canceled\",\n label: \"Including canceled\",\n clear: (x) => ({ ...x, showCanceled: false }),\n });\n return chips;\n}\n\nexport interface FilterContext {\n projectId: string | null;\n runs: Record<string, Run>;\n /** Task ids with open attention. */\n attentionTaskIds: Set<string>;\n}\n\n/** The host a task runs (or will run) on: current run, explicit policy, or nothing. */\nexport function taskHostId(task: Task, runs: Record<string, Run>): string | null {\n const run = task.currentRunId ? runs[task.currentRunId] : undefined;\n return run?.hostId ?? task.policy.hostId ?? null;\n}\n\nexport function matchesFilters(task: Task, f: BoardFilters, ctx: FilterContext): boolean {\n if (task.hiddenFromBoard) return false;\n if (ctx.projectId && task.projectId !== ctx.projectId) return false;\n if (task.state === \"canceled\" && !f.showCanceled) return false;\n const q = f.search.trim().toLowerCase();\n if (q && !`${task.title}\\n${task.objective}`.toLowerCase().includes(q)) return false;\n if (f.priorities.length > 0 && !f.priorities.includes(task.priority)) return false;\n if (f.hostId && taskHostId(task, ctx.runs) !== f.hostId) return false;\n if (f.attentionOnly && !ctx.attentionTaskIds.has(task.id)) return false;\n if (f.blockedOnly && !task.blocked) return false;\n return true;\n}\n\nexport function sortTasks(tasks: Task[], sort: BoardSort): Task[] {\n const out = [...tasks];\n if (sort === \"updated\") out.sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt));\n else if (sort === \"created\") out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n else\n out.sort(\n (a, b) =>\n a.priority - b.priority ||\n a.position - b.position ||\n a.createdAt.localeCompare(b.createdAt),\n );\n return out;\n}\n\nexport type Columns = Record<TaskState, Task[]>;\n\nexport function buildColumns(\n tasks: Record<string, Task>,\n f: BoardFilters,\n ctx: FilterContext,\n): Columns {\n const out: Columns = {\n backlog: [],\n ready: [],\n in_progress: [],\n review: [],\n done: [],\n canceled: [],\n };\n for (const t of Object.values(tasks)) if (matchesFilters(t, f, ctx)) out[t.state].push(t);\n for (const k of Object.keys(out) as TaskState[]) out[k] = sortTasks(out[k], f.sort);\n return out;\n}\n\nexport function visibleColumns(f: BoardFilters): TaskState[] {\n return f.showCanceled ? [...BOARD_COLUMNS, \"canceled\"] : BOARD_COLUMNS;\n}\n\n/* ------------------------------------------------------------------ */\n/* Move planning */\n/* ------------------------------------------------------------------ */\n\n/** Client mirror of the coordinator's transition table (plans: tasks/state.ts). */\nexport const TRANSITIONS: Record<TaskState, TaskState[]> = {\n backlog: [\"ready\", \"canceled\"],\n ready: [\"backlog\", \"in_progress\", \"canceled\"],\n in_progress: [\"review\", \"ready\", \"backlog\", \"canceled\", \"done\"],\n review: [\"in_progress\", \"done\", \"ready\", \"canceled\"],\n done: [\"ready\", \"backlog\"],\n canceled: [\"backlog\"],\n};\n\nexport type MovePlan =\n | { kind: \"noop\" }\n | { kind: \"invalid\"; reason: string }\n /** Plain move (POST /move). */\n | { kind: \"move\" }\n /** Ready to In progress means \"Run now\" (dispatcher only). */\n | { kind: \"run_now\" }\n /** Review to In progress starts a new attempt. */\n | { kind: \"new_attempt\" }\n /** Running work moved backward: the user chooses pause automation or stop execution. */\n | { kind: \"choose_running\" }\n /** Moving to Done with unresolved criteria/checks: confirm acceptance. */\n | { kind: \"confirm_done\"; reasons: string[] };\n\n/** True while a run is live (dispatching, running, waiting, checking). */\nexport function isRunActive(run: Run | undefined | null): boolean {\n return (\n !!run &&\n [\"queued\", \"dispatching\", \"uncertain\", \"running\", \"waiting_input\", \"checking\"].includes(\n run.state,\n )\n );\n}\n\n/** Why moving to Done needs explicit acceptance; empty when nothing is unresolved. */\nexport function unresolvedForDone(task: Task, run: Run | undefined | null): string[] {\n const reasons: string[] = [];\n if (task.state !== \"review\") reasons.push(\"The task has not been through review.\");\n if (task.acceptanceCriteria.length > 0)\n reasons.push(\n `${task.acceptanceCriteria.length} acceptance ${\n task.acceptanceCriteria.length === 1 ? \"criterion has\" : \"criteria have\"\n } not been confirmed.`,\n );\n const checksRequired = (task.policy.completion.checks?.length ?? 0) > 0;\n const failing = run?.checks.filter((c) => c.exitCode !== 0) ?? [];\n if (failing.length > 0)\n reasons.push(`Checks failing: ${failing.map((c) => c.command).join(\", \")}.`);\n else if (checksRequired && (!run || run.checks.length === 0))\n reasons.push(\"Required checks have not run.\");\n if (task.policy.completion.requireHumanReview && task.state === \"review\")\n reasons.push(\"Human review is required: moving to Done accepts the work.\");\n return reasons;\n}\n\nexport function planMove(task: Task, to: TaskState, run?: Run | null): MovePlan {\n if (task.state === to) return { kind: \"noop\" };\n const from = task.state;\n if (!TRANSITIONS[from].includes(to)) {\n return { kind: \"invalid\", reason: invalidReason(from, to) };\n }\n if (from === \"ready\" && to === \"in_progress\") return { kind: \"run_now\" };\n if (from === \"review\" && to === \"in_progress\") return { kind: \"new_attempt\" };\n if (from === \"in_progress\" && (to === \"ready\" || to === \"backlog\")) {\n return { kind: \"choose_running\" };\n }\n if (to === \"done\") {\n const reasons = unresolvedForDone(task, run);\n if (reasons.length > 0) return { kind: \"confirm_done\", reasons };\n }\n return { kind: \"move\" };\n}\n\nfunction invalidReason(from: TaskState, to: TaskState): string {\n const f = STATE_LABELS[from];\n const t = STATE_LABELS[to];\n if (to === \"in_progress\")\n return from === \"backlog\"\n ? \"A Backlog task cannot start directly. Move it to Ready first; the dispatcher starts it when it is eligible.\"\n : `${f} tasks cannot be moved to In progress. Only the dispatcher starts work (Run now from Ready).`;\n if (to === \"review\")\n return \"Only a finished run moves a task to Review. Run the task, or use Done to accept it.\";\n if (from === \"canceled\") return \"A canceled task can only be restored to Backlog.\";\n if (from === \"done\" && to === \"canceled\")\n return \"A Done task cannot be canceled. Reopen it first.\";\n if (from === \"backlog\" && to === \"done\")\n return \"A Backlog task cannot be marked Done. Make it ready and review its work first.\";\n if (from === \"ready\" && to === \"done\")\n return \"A task that has not run cannot be marked Done. Run it, or cancel it.\";\n return `Moving from ${f} to ${t} is not allowed.`;\n}\n\n/** Valid targets for \"Move to…\" menus, excluding the current state. */\nexport function moveTargets(task: Task): TaskState[] {\n return TRANSITIONS[task.state];\n}\n\n/* ------------------------------------------------------------------ */\n/* Positions */\n/* ------------------------------------------------------------------ */\n\n/** Position that places a card before `beforeId` (or at the end) in a sorted column. */\nexport function positionFor(column: Task[], beforeId: string | null, movingId: string): number {\n const list = column.filter((t) => t.id !== movingId);\n if (list.length === 0) return 1;\n if (beforeId === null) return list[list.length - 1]!.position + 1;\n const idx = list.findIndex((t) => t.id === beforeId);\n if (idx < 0) return list[list.length - 1]!.position + 1;\n const next = list[idx]!.position;\n const prev = idx > 0 ? list[idx - 1]!.position : next - 2;\n return (prev + next) / 2;\n}\n\n/* ------------------------------------------------------------------ */\n/* Eligibility */\n/* ------------------------------------------------------------------ */\n\nexport type WaitReason = Extract<Eligibility, { eligible: false }>[\"wait\"];\n\nexport const WAIT_LABELS: Record<WaitReason, string> = {\n dependency: \"Waiting on dependencies\",\n host_offline: \"Host offline\",\n project_limit: \"Project run limit reached\",\n workspace_occupied: \"Workspace occupied\",\n scheduled_time: \"Scheduled for later\",\n invalid_configuration: \"Invalid configuration\",\n dispatch_paused: \"Dispatch paused\",\n project_automation_disabled: \"Project automation is off\",\n not_ready: \"Not ready\",\n already_dispatched: \"Already dispatched\",\n retry_backoff: \"Retrying after a failure\",\n};\n\nexport function eligibilityText(e: Eligibility): string {\n if (e.eligible) return `Will start automatically on ${e.hostName}`;\n return `Will wait: ${e.message || WAIT_LABELS[e.wait]}`;\n}\n\nexport interface PreviewInput {\n project: Project | undefined;\n hostId: string | null;\n dependencies: string[];\n notBefore?: string | null;\n}\n\nexport interface PreviewState {\n hosts: Record<string, Host>;\n tasks: Record<string, Task>;\n dispatchPaused: boolean;\n /** Tasks currently running per project (for the project limit). */\n runningByProject: Record<string, number>;\n}\n\n/**\n * Client-side eligibility estimate for a task that does not exist yet (or\n * when the coordinator returns `not_ready` for a Backlog task). The\n * coordinator's dispatcher stays authoritative.\n */\nexport function previewEligibility(input: PreviewInput, state: PreviewState): Eligibility {\n const { project } = input;\n if (!project)\n return { eligible: false, wait: \"invalid_configuration\", message: \"Choose a project\" };\n if (state.dispatchPaused)\n return {\n eligible: false,\n wait: \"dispatch_paused\",\n message: \"Dispatch is paused; resume it to start new work\",\n };\n if (!project.automationEnabled)\n return {\n eligible: false,\n wait: \"project_automation_disabled\",\n message: `Automation is off for ${project.name}`,\n };\n const unmet = input.dependencies\n .map((id) => state.tasks[id])\n .filter((t): t is Task => !!t && t.state !== \"done\");\n if (unmet.length > 0)\n return {\n eligible: false,\n wait: \"dependency\",\n message: `Waiting on ${unmet.map((t) => t.title).join(\", \")}`,\n };\n if (input.notBefore && Date.parse(input.notBefore) > Date.now())\n return {\n eligible: false,\n wait: \"scheduled_time\",\n message: `Scheduled for ${new Date(input.notBefore).toLocaleString()}`,\n };\n const hostId = input.hostId ?? project.defaultHostId;\n const host = hostId ? state.hosts[hostId] : undefined;\n if (!host || host.revokedAt)\n return {\n eligible: false,\n wait: \"invalid_configuration\",\n message: \"No host is configured for this project\",\n };\n if (!host.piCompatible)\n return {\n eligible: false,\n wait: \"invalid_configuration\",\n message: `Pi on ${host.name} is not compatible`,\n };\n if (host.connectivity !== \"connected\")\n return { eligible: false, wait: \"host_offline\", message: `${host.name} is offline` };\n if ((state.runningByProject[project.id] ?? 0) >= project.maxConcurrentRuns)\n return {\n eligible: false,\n wait: \"project_limit\",\n message: `${project.name} already runs ${project.maxConcurrentRuns} of ${project.maxConcurrentRuns} allowed tasks`,\n };\n return { eligible: true, hostId: host.id, hostName: host.name };\n}\n\n/* ------------------------------------------------------------------ */\n/* Card text */\n/* ------------------------------------------------------------------ */\n\nexport function openAttentionByTask(\n attention: Record<string, AttentionItem>,\n): Map<string, AttentionItem[]> {\n const m = new Map<string, AttentionItem[]>();\n for (const a of Object.values(attention)) {\n if (a.resolvedAt || !a.taskId) continue;\n const list = m.get(a.taskId) ?? [];\n list.push(a);\n m.set(a.taskId, list);\n }\n return m;\n}\n\nexport function dependencySummary(task: Task, tasks: Record<string, Task>): string | null {\n const n = task.dependencies.length;\n if (n === 0) return null;\n const open = task.dependencies.filter((id) => tasks[id]?.state !== \"done\").length;\n const base = `${n} ${n === 1 ? \"dependency\" : \"dependencies\"}`;\n return open > 0 ? `${base} (${open} open)` : `${base} (all done)`;\n}\n","import type { Priority } from \"@switchyard/protocol\";\nimport { PRIORITY_LABELS } from \"@switchyard/protocol\";\nimport { CirclePause, CirclePlay, Filter, Search, X } from \"lucide-react\";\nimport { type ReactNode, useId, useMemo, useState } from \"react\";\nimport { ROUTES } from \"../../app/routes\";\nimport { Badge } from \"../../components/ui/Badge\";\nimport { Button } from \"../../components/ui/Button\";\nimport { Dialog, Sheet } from \"../../components/ui/Overlay\";\nimport {\n ErrorState,\n HostUnavailable,\n InteractionPending,\n UnsupportedCapability,\n} from \"../../components/ui/states\";\nimport { TextInput } from \"../../components/ui/TextArea\";\nimport { toast } from \"../../components/ui/Toast\";\nimport { cn } from \"../../lib/cn\";\nimport { errorMessage, isApiError } from \"../../sync/api\";\nimport { useHosts, useProjects, useSyncStore } from \"../../sync/store\";\nimport { setDispatchPaused } from \"./api\";\nimport { activeFilterChips, type BoardFilters, type BoardSort, DEFAULT_FILTERS } from \"./logic\";\nimport type { BoardState } from \"./useBoard\";\n\nconst selectCls =\n \"tap h-9 min-w-0 rounded-md border border-border bg-surface px-2 text-base text-text md:text-sm\";\n\nexport function ProjectSelect({ board, className }: { board: BoardState; className?: string }) {\n const projects = useProjects();\n const id = useId();\n return (\n <div className={cn(\"flex min-w-0 items-center gap-2\", className)}>\n <label htmlFor={id} className=\"sr-only\">\n Project\n </label>\n <select\n id={id}\n className={cn(selectCls, \"w-full max-w-56\")}\n value={board.projectId ?? \"\"}\n onChange={(e) => board.setProjectId(e.target.value || null)}\n >\n <option value=\"\">All projects</option>\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n );\n}\n\nexport function SearchBox({ board, className }: { board: BoardState; className?: string }) {\n const id = useId();\n return (\n <div className={cn(\"relative min-w-0\", className)}>\n <label htmlFor={id} className=\"sr-only\">\n Search tasks\n </label>\n <Search\n aria-hidden\n className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-subtle\"\n />\n <TextInput\n id={id}\n type=\"search\"\n placeholder=\"Search tasks\"\n className=\"pl-8\"\n value={board.filters.search}\n onChange={(e) => board.setFilters({ ...board.filters, search: e.target.value })}\n />\n </div>\n );\n}\n\nexport function SortSelect({ board }: { board: BoardState }) {\n const id = useId();\n return (\n <div className=\"flex items-center gap-1.5 text-sm\">\n <label htmlFor={id} className=\"text-muted\">\n Sort\n </label>\n <select\n id={id}\n className={selectCls}\n value={board.filters.sort}\n onChange={(e) => board.setFilters({ ...board.filters, sort: e.target.value as BoardSort })}\n >\n <option value=\"priority\">Priority</option>\n <option value=\"updated\">Recently updated</option>\n <option value=\"created\">Newest</option>\n </select>\n </div>\n );\n}\n\nexport function CompletedToggle({ board }: { board: BoardState }) {\n return (\n <label className=\"tap inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={board.filters.showCompleted}\n onChange={(e) => board.setFilters({ ...board.filters, showCompleted: e.target.checked })}\n />\n Show completed\n </label>\n );\n}\n\n/** Automation enabled/paused status and the pause/resume toggle (never terminates active runs). */\nexport function DispatchToggle({ compact }: { compact?: boolean }) {\n const paused = useSyncStore((s) => s.dispatchPaused);\n const [busy, setBusy] = useState(false);\n const Icon = paused ? CirclePause : CirclePlay;\n return (\n <div className=\"flex min-w-0 flex-wrap items-center gap-2 text-sm\">\n <span\n role=\"status\"\n className={cn(\n \"inline-flex items-center gap-1.5 font-medium\",\n paused ? \"text-warning\" : \"text-success\",\n )}\n >\n <Icon aria-hidden className=\"size-4\" />\n <span className=\"text-text\">{paused ? \"Automation paused\" : \"Automation enabled\"}</span>\n </span>\n <Button\n size=\"sm\"\n busy={busy}\n onClick={async () => {\n setBusy(true);\n try {\n await setDispatchPaused(!paused);\n toast.success(\n paused\n ? \"Dispatch resumed. Ready tasks start when eligible.\"\n : \"Dispatch paused. Running work continues; nothing new starts.\",\n );\n } catch (e) {\n toast.error(`Could not ${paused ? \"resume\" : \"pause\"} dispatch: ${errorMessage(e)}`);\n } finally {\n setBusy(false);\n }\n }}\n >\n {paused ? \"Resume dispatch\" : compact ? \"Pause\" : \"Pause dispatch\"}\n </Button>\n </div>\n );\n}\n\nfunction FilterFields({\n value,\n onChange,\n withSort,\n}: {\n value: BoardFilters;\n onChange: (f: BoardFilters) => void;\n withSort?: boolean;\n}) {\n const hosts = useHosts();\n const id = useId();\n const togglePriority = (p: Priority, on: boolean) =>\n onChange({\n ...value,\n priorities: on ? [...value.priorities, p] : value.priorities.filter((x) => x !== p),\n });\n return (\n <div className=\"flex flex-col gap-4\">\n <fieldset className=\"flex flex-col gap-1\">\n <legend className=\"mb-1 text-sm font-medium\">Priority</legend>\n <div className=\"flex flex-wrap gap-x-4\">\n {PRIORITY_LABELS.map((l, i) => (\n <label key={l} className=\"tap inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={value.priorities.includes(i as Priority)}\n onChange={(e) => togglePriority(i as Priority, e.target.checked)}\n />\n {l}\n </label>\n ))}\n </div>\n </fieldset>\n <div className=\"flex flex-col gap-1\">\n <label htmlFor={`${id}-host`} className=\"text-sm font-medium\">\n Host\n </label>\n <select\n id={`${id}-host`}\n className={selectCls}\n value={value.hostId ?? \"\"}\n onChange={(e) => onChange({ ...value, hostId: e.target.value || null })}\n >\n <option value=\"\">Any host</option>\n {hosts.map((h) => (\n <option key={h.id} value={h.id}>\n {h.name}\n </option>\n ))}\n </select>\n </div>\n <fieldset className=\"flex flex-col gap-1\">\n <legend className=\"mb-1 text-sm font-medium\">Show</legend>\n <label className=\"tap inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={value.attentionOnly}\n onChange={(e) => onChange({ ...value, attentionOnly: e.target.checked })}\n />\n Only tasks that need attention\n </label>\n <label className=\"tap inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={value.blockedOnly}\n onChange={(e) => onChange({ ...value, blockedOnly: e.target.checked })}\n />\n Only blocked tasks\n </label>\n <label className=\"tap inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={value.showCanceled}\n onChange={(e) => onChange({ ...value, showCanceled: e.target.checked })}\n />\n Canceled tasks\n </label>\n <label className=\"tap inline-flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={value.showCompleted}\n onChange={(e) => onChange({ ...value, showCompleted: e.target.checked })}\n />\n Completed tasks\n </label>\n </fieldset>\n {withSort && (\n <div className=\"flex flex-col gap-1\">\n <label htmlFor={`${id}-sort`} className=\"text-sm font-medium\">\n Sort\n </label>\n <select\n id={`${id}-sort`}\n className={selectCls}\n value={value.sort}\n onChange={(e) => onChange({ ...value, sort: e.target.value as BoardSort })}\n >\n <option value=\"priority\">Priority</option>\n <option value=\"updated\">Recently updated</option>\n <option value=\"created\">Newest</option>\n </select>\n </div>\n )}\n </div>\n );\n}\n\n/** Filters button: a dialog on desktop, a sheet on mobile. Applies on \"Show results\". */\nexport function FilterButton({ board, mobile }: { board: BoardState; mobile?: boolean }) {\n const [open, setOpen] = useState(false);\n const [draft, setDraft] = useState(board.filters);\n const hosts = useSyncStore((s) => s.hosts);\n const count = activeFilterChips(board.filters, (id) => hosts[id]?.name ?? \"host\").filter(\n (c) => c.key !== \"search\",\n ).length;\n const Surface = mobile ? Sheet : Dialog;\n return (\n <>\n <Button\n icon={<Filter className=\"size-4\" />}\n onClick={() => {\n setDraft(board.filters);\n setOpen(true);\n }}\n aria-label={count ? `Filters, ${count} active` : \"Filters\"}\n >\n Filters\n {count > 0 && <Badge tone=\"accent\">{count}</Badge>}\n </Button>\n <Surface\n open={open}\n onClose={() => setOpen(false)}\n title=\"Filter tasks\"\n footer={\n <>\n <Button\n variant=\"ghost\"\n onClick={() => setDraft({ ...DEFAULT_FILTERS, search: draft.search })}\n >\n Reset\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => {\n board.setFilters(draft);\n setOpen(false);\n }}\n >\n Show results\n </Button>\n </>\n }\n >\n <FilterFields value={draft} onChange={setDraft} withSort={mobile} />\n </Surface>\n </>\n );\n}\n\n/** Active filters as removable chips. */\nexport function FilterChips({\n board,\n includeSearch,\n}: {\n board: BoardState;\n includeSearch?: boolean;\n}) {\n const hosts = useSyncStore((s) => s.hosts);\n const chips = activeFilterChips(board.filters, (id) => hosts[id]?.name ?? \"Unknown host\").filter(\n (c) => includeSearch || c.key !== \"search\",\n );\n if (chips.length === 0) return null;\n return (\n <ul\n data-testid=\"filter-chips\"\n aria-label=\"Active filters\"\n className=\"flex min-w-0 flex-wrap gap-1.5\"\n >\n {chips.map((c) => (\n <li key={c.key} className=\"min-w-0\">\n <button\n type=\"button\"\n onClick={() => board.setFilters(c.clear(board.filters))}\n aria-label={`Remove filter ${c.label}`}\n className=\"tap inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-surface-2 px-2.5 py-0.5 text-xs font-medium\"\n >\n <span className=\"truncate\">{c.label}</span>\n <X aria-hidden className=\"size-3.5 shrink-0\" />\n </button>\n </li>\n ))}\n {chips.length > 1 && (\n <li>\n <button\n type=\"button\"\n className=\"tap rounded px-2 py-0.5 text-xs font-medium text-accent\"\n onClick={() => board.setFilters({ ...DEFAULT_FILTERS, sort: board.filters.sort })}\n >\n Clear all\n </button>\n </li>\n )}\n </ul>\n );\n}\n\n/** Host unavailable, pending interactions and queue-detail problems above the board (spec 18). */\nexport function BoardNotices({ board }: { board: BoardState }) {\n const tasks = useSyncStore((s) => s.tasks);\n const runs = useSyncStore((s) => s.runs);\n const hosts = useSyncStore((s) => s.hosts);\n const interactions = useSyncStore((s) => s.interactions);\n const { offline, pending } = useMemo(() => {\n const offlineIds = new Set<string>();\n const sessionIds = new Set<string>();\n for (const t of Object.values(tasks)) {\n if (board.projectId && t.projectId !== board.projectId) continue;\n if (t.sessionId) sessionIds.add(t.sessionId);\n const run = t.currentRunId ? runs[t.currentRunId] : undefined;\n if (t.state === \"in_progress\" && run?.hostId) {\n const h = hosts[run.hostId];\n if (h && h.connectivity !== \"connected\") offlineIds.add(h.id);\n }\n }\n const pend = Object.values(interactions)\n .filter((i) => i.state === \"pending\" && sessionIds.has(i.sessionId))\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n return { offline: [...offlineIds].map((id) => hosts[id]!), pending: pend };\n }, [tasks, runs, hosts, interactions, board.projectId]);\n\n const nowErr = board.now.error;\n const notices: ReactNode[] = [];\n for (const h of offline)\n notices.push(\n <HostUnavailable\n key={`host-${h.id}`}\n compact\n hostName={h.name}\n connectivity={h.connectivity === \"reconnecting\" ? \"reconnecting\" : \"unreachable\"}\n lastSeenAt={h.lastSeenAt}\n detail=\"Its In progress tasks keep their last known state; nothing is restarted elsewhere.\"\n />,\n );\n if (pending.length > 0)\n notices.push(\n <InteractionPending\n key=\"pending\"\n count={pending.length}\n to={ROUTES.interaction(pending[0]!.sessionId, pending[0]!.id)}\n label={\n pending.length === 1\n ? \"A task needs your answer\"\n : `${pending.length} questions need your answer`\n }\n />,\n );\n if (nowErr !== null && nowErr !== undefined) {\n if (isApiError(nowErr) && nowErr.status === 404)\n notices.push(\n <UnsupportedCapability\n key=\"now\"\n capability=\"Queue details\"\n reason=\"This coordinator does not report why Ready tasks are waiting.\"\n />,\n );\n else\n notices.push(\n <ErrorState\n key=\"now\"\n compact\n title=\"Could not load the dispatch queue\"\n error={errorMessage(nowErr)}\n onRetry={board.now.reload}\n />,\n );\n }\n if (notices.length === 0) return null;\n return <div className=\"flex flex-col gap-2 px-4 pt-2\">{notices}</div>;\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface Resource<T> {\n data: T | undefined;\n error: unknown;\n loading: boolean;\n /** Refetch; keeps the last data while loading. */\n reload: () => void;\n}\n\n/**\n * Fetch a REST resource. `key` changes trigger a refetch; null skips fetching.\n * Errors keep the last good data so views can show last-known state.\n */\nexport function useResource<T>(\n key: string | null,\n fetcher: (signal: AbortSignal) => Promise<T>,\n opts: { refreshMs?: number } = {},\n): Resource<T> {\n const [data, setData] = useState<T | undefined>(undefined);\n const [error, setError] = useState<unknown>(null);\n const [loading, setLoading] = useState(key !== null);\n const [nonce, setNonce] = useState(0);\n const fetcherRef = useRef(fetcher);\n fetcherRef.current = fetcher;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: nonce forces a reload\n useEffect(() => {\n if (key === null) {\n setLoading(false);\n return;\n }\n const ctrl = new AbortController();\n setLoading(true);\n fetcherRef\n .current(ctrl.signal)\n .then((d) => {\n if (ctrl.signal.aborted) return;\n setData(d);\n setError(null);\n })\n .catch((e) => {\n if (ctrl.signal.aborted || (e instanceof DOMException && e.name === \"AbortError\")) return;\n setError(e);\n })\n .finally(() => {\n if (!ctrl.signal.aborted) setLoading(false);\n });\n return () => ctrl.abort();\n }, [key, nonce]);\n\n useEffect(() => {\n if (!opts.refreshMs || key === null) return;\n const t = setInterval(() => {\n if (document.visibilityState === \"visible\") setNonce((n) => n + 1);\n }, opts.refreshMs);\n return () => clearInterval(t);\n }, [opts.refreshMs, key]);\n\n const reload = useCallback(() => setNonce((n) => n + 1), []);\n return { data, error, loading, reload };\n}\n","import type { NowResponse } from \"@switchyard/protocol\";\nimport { useEffect, useRef } from \"react\";\nimport { apiGet } from \"../../sync/api\";\nimport { useSyncStore } from \"../../sync/store\";\nimport { type Resource, useResource } from \"../board/useResource\";\n\n/**\n * GET /api/now: running runs, queued Ready tasks with their wait reason and\n * the dispatch-paused flag. Refetches when tasks/runs change (debounced) and\n * every 15 s while visible.\n */\nexport function useNow(enabled = true): Resource<NowResponse> {\n const res = useResource<NowResponse>(\n enabled ? \"now\" : null,\n (signal) => apiGet<NowResponse>(\"/api/now\", undefined, signal),\n { refreshMs: 15_000 },\n );\n const tasks = useSyncStore((s) => s.tasks);\n const runs = useSyncStore((s) => s.runs);\n const paused = useSyncStore((s) => s.dispatchPaused);\n const first = useRef(true);\n const { reload } = res;\n // biome-ignore lint/correctness/useExhaustiveDependencies: refetch on entity changes\n useEffect(() => {\n if (first.current) {\n first.current = false;\n return;\n }\n if (!enabled) return;\n const t = setTimeout(reload, 500);\n return () => clearTimeout(t);\n }, [tasks, runs, paused, enabled, reload]);\n return res;\n}\n"],"ignoreList":[0],"mappings":"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"}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<title>Switchyard</title>
|
|
3
|
+
<rect width="512" height="512" rx="96" fill="#1f2937"/>
|
|
4
|
+
<g fill="none" stroke="#f9fafb" stroke-width="28" stroke-linecap="round" stroke-linejoin="round">
|
|
5
|
+
<path d="M136 120v272"/>
|
|
6
|
+
<path d="M376 120v272"/>
|
|
7
|
+
<path d="M136 176c0 80 240 80 240 160"/>
|
|
8
|
+
<path d="M136 336c0-40 60-60 100-70"/>
|
|
9
|
+
</g>
|
|
10
|
+
<circle cx="136" cy="120" r="26" fill="#60a5fa"/>
|
|
11
|
+
<circle cx="376" cy="392" r="26" fill="#34d399"/>
|
|
12
|
+
</svg>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
|
|
6
|
+
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f8fafc" />
|
|
7
|
+
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0f1115" />
|
|
8
|
+
<meta name="color-scheme" content="light dark" />
|
|
9
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
10
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
11
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
12
|
+
<meta name="apple-mobile-web-app-title" content="Switchyard" />
|
|
13
|
+
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
|
14
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
15
|
+
<title>Switchyard</title>
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-B11DJFHW.js"></script>
|
|
17
|
+
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-D13aM9HY.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/states-DrTQuYXw.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/presence-05bJD5G3.js">
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DGGOgcLZ.css">
|
|
21
|
+
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js" defer></script></head>
|
|
22
|
+
<body>
|
|
23
|
+
<div id="root"></div>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"Switchyard","short_name":"Switchyard","description":"Pi coding sessions, tasks and automations across your hosts","start_url":"/","display":"standalone","background_color":"#111827","theme_color":"#111827","lang":"en","scope":"/","icons":[{"src":"/icon-192.png","sizes":"192x192","type":"image/png"},{"src":"/icon-512.png","sizes":"512x512","type":"image/png"},{"src":"/maskable-512.png","sizes":"512x512","type":"image/png","purpose":"maskable"},{"src":"/icon.svg","sizes":"any","type":"image/svg+xml"}]}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|