@spencerboucher/switchyard 0.7.0 → 0.9.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.
Files changed (149) hide show
  1. package/README.md +3 -3
  2. package/dist/bridge/lines.js +33 -0
  3. package/dist/bridge/switchyard-terminal.js +155 -23
  4. package/dist/switchyard.mjs +3879 -2658
  5. package/dist/terminal/holder.js +142 -51
  6. package/package.json +1 -1
  7. package/web-dist/apple-touch-icon.png +0 -0
  8. package/web-dist/assets/AutomationView-D7Syv1En.js +2 -0
  9. package/web-dist/assets/AutomationView-D7Syv1En.js.map +1 -0
  10. package/web-dist/assets/Checkbox-D6tRfEeI.js +2 -0
  11. package/web-dist/assets/Checkbox-D6tRfEeI.js.map +1 -0
  12. package/web-dist/assets/Copy-B6XSAIUd.js +2 -0
  13. package/web-dist/assets/Copy-B6XSAIUd.js.map +1 -0
  14. package/web-dist/assets/DangerZone-DfYlxDC1.js +2 -0
  15. package/web-dist/assets/DangerZone-DfYlxDC1.js.map +1 -0
  16. package/web-dist/assets/Field-D-Ty7fKT.js +2 -0
  17. package/web-dist/assets/Field-D-Ty7fKT.js.map +1 -0
  18. package/web-dist/assets/InteractionCard-DF1EcSpm.js +6 -0
  19. package/web-dist/assets/InteractionCard-DF1EcSpm.js.map +1 -0
  20. package/web-dist/assets/Menu-BfOszNC4.js +2 -0
  21. package/web-dist/assets/Menu-BfOszNC4.js.map +1 -0
  22. package/web-dist/assets/Overlay-DUQwh6_b.js +2 -0
  23. package/web-dist/assets/Overlay-DUQwh6_b.js.map +1 -0
  24. package/web-dist/assets/Priority-CHmzfoHg.js +2 -0
  25. package/web-dist/assets/Priority-CHmzfoHg.js.map +1 -0
  26. package/web-dist/assets/{SegmentedControl-D-2BCZzd.js → SegmentedControl-C_hEVQMB.js} +2 -2
  27. package/web-dist/assets/{SegmentedControl-D-2BCZzd.js.map → SegmentedControl-C_hEVQMB.js.map} +1 -1
  28. package/web-dist/assets/Select-Cfql4Nwu.js +2 -0
  29. package/web-dist/assets/Select-Cfql4Nwu.js.map +1 -0
  30. package/web-dist/assets/Switch-DBfzmqkm.js +2 -0
  31. package/web-dist/assets/Switch-DBfzmqkm.js.map +1 -0
  32. package/web-dist/assets/Tabs-BNuL3_Et.js +184 -0
  33. package/web-dist/assets/Tabs-BNuL3_Et.js.map +1 -0
  34. package/web-dist/assets/TextArea-CKybrQyn.js +2 -0
  35. package/web-dist/assets/TextArea-CKybrQyn.js.map +1 -0
  36. package/web-dist/assets/TextLink-OzzyP2-p.js +2 -0
  37. package/web-dist/assets/TextLink-OzzyP2-p.js.map +1 -0
  38. package/web-dist/assets/arrow-down-C-iLrN8I.js +2 -0
  39. package/web-dist/assets/arrow-down-C-iLrN8I.js.map +1 -0
  40. package/web-dist/assets/arrow-up-Dj-VTKx4.js +2 -0
  41. package/web-dist/assets/arrow-up-Dj-VTKx4.js.map +1 -0
  42. package/web-dist/assets/attention-V86Gye3I.js +2 -0
  43. package/web-dist/assets/attention-V86Gye3I.js.map +1 -0
  44. package/web-dist/assets/automations-Cw5Gacgm.js +2 -0
  45. package/web-dist/assets/automations-Cw5Gacgm.js.map +1 -0
  46. package/web-dist/assets/board-B8X7TYYR.js +10 -0
  47. package/web-dist/assets/board-B8X7TYYR.js.map +1 -0
  48. package/web-dist/assets/code-BKroYJmR.js +12 -0
  49. package/web-dist/assets/code-BKroYJmR.js.map +1 -0
  50. package/web-dist/assets/describe-D6KLGKWa.js +5 -0
  51. package/web-dist/assets/describe-D6KLGKWa.js.map +1 -0
  52. package/web-dist/assets/enroll-DwT7AcuS.js +2 -0
  53. package/web-dist/assets/enroll-DwT7AcuS.js.map +1 -0
  54. package/web-dist/assets/index-B3F7WcYf.css +2 -0
  55. package/web-dist/assets/index-hxvDvCS7.js +12 -0
  56. package/web-dist/assets/index-hxvDvCS7.js.map +1 -0
  57. package/web-dist/assets/logic-B46fwD-8.js +2 -0
  58. package/web-dist/assets/logic-B46fwD-8.js.map +1 -0
  59. package/web-dist/assets/more-DQR5uu1c.js +2 -0
  60. package/web-dist/assets/more-DQR5uu1c.js.map +1 -0
  61. package/web-dist/assets/queue-DUg1rS8t.js +2 -0
  62. package/web-dist/assets/queue-DUg1rS8t.js.map +1 -0
  63. package/web-dist/assets/repo-XzzzEI0d.js +2 -0
  64. package/web-dist/assets/repo-XzzzEI0d.js.map +1 -0
  65. package/web-dist/assets/server-BqZ-w6M8.js +2 -0
  66. package/web-dist/assets/server-BqZ-w6M8.js.map +1 -0
  67. package/web-dist/assets/settings-DyUu0tJM.js +8 -0
  68. package/web-dist/assets/settings-DyUu0tJM.js.map +1 -0
  69. package/web-dist/assets/states-ZhrxQa3K.js +56 -0
  70. package/web-dist/assets/states-ZhrxQa3K.js.map +1 -0
  71. package/web-dist/assets/terminal-BOV_MXPZ.js +2 -0
  72. package/web-dist/assets/terminal-BOV_MXPZ.js.map +1 -0
  73. package/web-dist/assets/terminal-login-S5CAd5xA.js +2 -0
  74. package/web-dist/assets/terminal-login-S5CAd5xA.js.map +1 -0
  75. package/web-dist/assets/useBackTo-BIrCq3W2.js +2 -0
  76. package/web-dist/assets/useBackTo-BIrCq3W2.js.map +1 -0
  77. package/web-dist/assets/useNow-Dj7oEiwn.js +2 -0
  78. package/web-dist/assets/useNow-Dj7oEiwn.js.map +1 -0
  79. package/web-dist/assets/useResource-CDGSq2At.js +2 -0
  80. package/web-dist/assets/useResource-CDGSq2At.js.map +1 -0
  81. package/web-dist/icon-192.png +0 -0
  82. package/web-dist/icon-512.png +0 -0
  83. package/web-dist/icon.svg +20 -8
  84. package/web-dist/index.html +3 -4
  85. package/web-dist/manifest.webmanifest +1 -1
  86. package/web-dist/maskable-512.png +0 -0
  87. package/web-dist/sw.js +1 -1
  88. package/web-dist/sw.js.map +1 -1
  89. package/web-dist/assets/AutomationView-BIW_pO0M.js +0 -2
  90. package/web-dist/assets/AutomationView-BIW_pO0M.js.map +0 -1
  91. package/web-dist/assets/Badge-BiDp7NKI.js +0 -2
  92. package/web-dist/assets/Badge-BiDp7NKI.js.map +0 -1
  93. package/web-dist/assets/InteractionCard-CWxyDv81.js +0 -6
  94. package/web-dist/assets/InteractionCard-CWxyDv81.js.map +0 -1
  95. package/web-dist/assets/Menu-BDt1bxwz.js +0 -2
  96. package/web-dist/assets/Menu-BDt1bxwz.js.map +0 -1
  97. package/web-dist/assets/Tabs-ByiPklAw.js +0 -184
  98. package/web-dist/assets/Tabs-ByiPklAw.js.map +0 -1
  99. package/web-dist/assets/TextArea-BYr88SnV.js +0 -2
  100. package/web-dist/assets/TextArea-BYr88SnV.js.map +0 -1
  101. package/web-dist/assets/arrow-left-C6YWM6y6.js +0 -2
  102. package/web-dist/assets/arrow-left-C6YWM6y6.js.map +0 -1
  103. package/web-dist/assets/attention-Bya8XHKI.js +0 -2
  104. package/web-dist/assets/attention-Bya8XHKI.js.map +0 -1
  105. package/web-dist/assets/automations-DiXKRcnE.js +0 -2
  106. package/web-dist/assets/automations-DiXKRcnE.js.map +0 -1
  107. package/web-dist/assets/board-BrLaJwLJ.js +0 -10
  108. package/web-dist/assets/board-BrLaJwLJ.js.map +0 -1
  109. package/web-dist/assets/code-DKLO8bzz.js +0 -11
  110. package/web-dist/assets/code-DKLO8bzz.js.map +0 -1
  111. package/web-dist/assets/copy-oWgGHmkS.js +0 -2
  112. package/web-dist/assets/copy-oWgGHmkS.js.map +0 -1
  113. package/web-dist/assets/describe-DnvH6_fl.js +0 -5
  114. package/web-dist/assets/describe-DnvH6_fl.js.map +0 -1
  115. package/web-dist/assets/dist-BE_V9dwJ.js +0 -56
  116. package/web-dist/assets/dist-BE_V9dwJ.js.map +0 -1
  117. package/web-dist/assets/enroll-DUDpbJoB.js +0 -2
  118. package/web-dist/assets/enroll-DUDpbJoB.js.map +0 -1
  119. package/web-dist/assets/index-DvRcMGEe.css +0 -2
  120. package/web-dist/assets/index-vIzH1m8u.js +0 -11
  121. package/web-dist/assets/index-vIzH1m8u.js.map +0 -1
  122. package/web-dist/assets/logic-xb-QF00E.js +0 -2
  123. package/web-dist/assets/logic-xb-QF00E.js.map +0 -1
  124. package/web-dist/assets/more-BP5x45cs.js +0 -2
  125. package/web-dist/assets/more-BP5x45cs.js.map +0 -1
  126. package/web-dist/assets/now--XjJC37b.js +0 -2
  127. package/web-dist/assets/now--XjJC37b.js.map +0 -1
  128. package/web-dist/assets/plus-BLP-wIYD.js +0 -2
  129. package/web-dist/assets/plus-BLP-wIYD.js.map +0 -1
  130. package/web-dist/assets/save-DEvZPWlS.js +0 -2
  131. package/web-dist/assets/save-DEvZPWlS.js.map +0 -1
  132. package/web-dist/assets/send-BKjswHxB.js +0 -2
  133. package/web-dist/assets/send-BKjswHxB.js.map +0 -1
  134. package/web-dist/assets/server-SxFxIScj.js +0 -2
  135. package/web-dist/assets/server-SxFxIScj.js.map +0 -1
  136. package/web-dist/assets/settings-D8T1esWq.js +0 -7
  137. package/web-dist/assets/settings-D8T1esWq.js.map +0 -1
  138. package/web-dist/assets/shared-CZ7fcu_B.js +0 -3
  139. package/web-dist/assets/shared-CZ7fcu_B.js.map +0 -1
  140. package/web-dist/assets/sliders-horizontal-DAoirila.js +0 -2
  141. package/web-dist/assets/sliders-horizontal-DAoirila.js.map +0 -1
  142. package/web-dist/assets/states--geW2Ntl.js +0 -2
  143. package/web-dist/assets/states--geW2Ntl.js.map +0 -1
  144. package/web-dist/assets/terminal-login-BJxV78au.js +0 -2
  145. package/web-dist/assets/terminal-login-BJxV78au.js.map +0 -1
  146. package/web-dist/assets/trash-C6X2OLrI.js +0 -2
  147. package/web-dist/assets/trash-C6X2OLrI.js.map +0 -1
  148. package/web-dist/assets/useNow-jxdoOC_1.js +0 -2
  149. package/web-dist/assets/useNow-jxdoOC_1.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ import{n as e}from"./jsx-runtime-D13aM9HY.js";var t={name:`terminal`,size:24,node:[[`path`,{d:`M12 19h8`,key:`baeox8`}],[`path`,{d:`m4 17 6-6-6-6`,key:`1yngyt`}]]};t.node;var n=e(t);export{n as t};
2
+ //# sourceMappingURL=terminal-BOV_MXPZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-BOV_MXPZ.js","names":["createLucideIcon","__iconData","Terminal"],"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/terminal.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: \"terminal\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 19h8\", key: \"baeox8\" }],\n [\"path\", { d: \"m4 17 6-6-6-6\", key: \"1yngyt\" }]\n ]\n};\n__iconData.node;\nconst Terminal = createLucideIcon(__iconData);\n\nexport { __iconData, Terminal as default };\n//# sourceMappingURL=terminal.mjs.map\n"],"ignoreList":[0],"mappings":"A,8CASA,IAAMC,EAAa,CACjB,KAAM,WACN,KAAM,GACN,KAAM,CACJ,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,gBAAiB,IAAK,QAAS,CAAC,CAChD,CACF,EACAA,EAAW,KACX,IAAMC,EAAWF,EAAiBC,CAAU,E"}
@@ -0,0 +1,2 @@
1
+ import{_ as e,a as t,f as n,m as r,t as i}from"./jsx-runtime-D13aM9HY.js";import{a,bt as o,c as s,d as c,gt as l,h as u,v as d,vt as f,yt as p}from"./states-ZhrxQa3K.js";import{t as m}from"./terminal-BOV_MXPZ.js";import{r as h}from"./TextArea-CKybrQyn.js";import{t as g}from"./TextLink-OzzyP2-p.js";var _=e(r(),1),v=i();function y(){let[e]=t(),r=n(),i=e.get(`code`)?.trim()??``,[y,b]=(0,_.useState)(``),[x,S]=(0,_.useState)(null),[C,w]=(0,_.useState)(null),[T,E]=(0,_.useState)(null),[D,O]=(0,_.useState)(!1),[k,A]=(0,_.useState)(null);(0,_.useEffect)(()=>{if(!i)return;let e=new AbortController;return S(null),w(null),E(null),l(`/api/auth/terminal/requests/${encodeURIComponent(i)}`,void 0,e.signal).then(t=>!e.signal.aborted&&S(t)).catch(t=>{e.signal.aborted||(o(t)&&t.code===`not_found`?w(p(t)):E(t))}),()=>e.abort()},[i]);let j=async e=>{O(!0),A(null);try{S(await f(`/api/auth/terminal/requests/${encodeURIComponent(i)}/${e}`))}catch(e){A(e)}finally{O(!1)}},M;return M=i?C?(0,v.jsxs)(`div`,{role:`alert`,className:`rounded-md border border-border bg-danger-soft px-3 py-2 text-sm`,children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium`,children:[(0,v.jsx)(d,{"aria-hidden":!0,className:`size-4 shrink-0`}),`Sign-in request not found`]}),(0,v.jsx)(`div`,{className:`text-muted`,children:C})]}):T?(0,v.jsx)(a,{error:T}):x?x.status===`approved`?(0,v.jsxs)(`div`,{role:`status`,className:`flex flex-col gap-3 text-sm`,children:[(0,v.jsx)(`p`,{className:`font-medium`,children:`Terminal signed in. You can close this tab and return to your terminal.`}),(0,v.jsx)(g,{to:`/`,children:`Back to Switchyard`})]}):x.status===`denied`?(0,v.jsx)(`p`,{role:`status`,className:`text-sm font-medium`,children:`Sign-in denied. The terminal was not signed in.`}):(0,v.jsxs)(`div`,{className:`flex flex-col gap-4 text-sm`,children:[(0,v.jsx)(`p`,{className:`text-base font-medium`,children:`Sign in a terminal?`}),(0,v.jsxs)(`dl`,{className:`grid grid-cols-[auto_1fr] gap-x-4 gap-y-2`,children:[(0,v.jsx)(`dt`,{className:`text-muted`,children:`Terminal`}),(0,v.jsx)(`dd`,{className:`break-words`,children:x.name}),(0,v.jsx)(`dt`,{className:`text-muted`,children:`Code`}),(0,v.jsx)(`dd`,{"data-testid":`terminal-login-code`,className:`font-mono text-lg tracking-widest`,children:x.userCode}),(0,v.jsx)(`dt`,{className:`text-muted`,children:`From`}),(0,v.jsx)(`dd`,{children:x.requestedFrom}),(0,v.jsx)(`dt`,{className:`text-muted`,children:`Requested`}),(0,v.jsx)(`dd`,{children:u(x.createdAt)})]}),(0,v.jsx)(`p`,{className:`text-muted`,children:`Approve only if you just ran switchyard login and your terminal shows this code.`}),(0,v.jsx)(a,{error:k}),(0,v.jsxs)(`div`,{className:`flex gap-2`,children:[(0,v.jsx)(c,{variant:`primary`,"data-testid":`terminal-login-approve`,busy:D,onClick:()=>void j(`approve`),children:`Approve`}),(0,v.jsx)(c,{"data-testid":`terminal-login-deny`,disabled:D,onClick:()=>void j(`deny`),children:`Deny`})]})]}):(0,v.jsx)(s,{label:`Loading the sign-in request…`}):(0,v.jsxs)(`form`,{className:`flex flex-col gap-3`,onSubmit:e=>{e.preventDefault(),y.trim()&&r(`?code=${encodeURIComponent(y.trim())}`)},children:[(0,v.jsx)(`label`,{htmlFor:`tl-code`,className:`text-sm font-medium`,children:`Code from your terminal`}),(0,v.jsx)(h,{id:`tl-code`,value:y,autoComplete:`off`,onChange:e=>b(e.target.value)}),(0,v.jsx)(c,{type:`submit`,variant:`primary`,disabled:!y.trim(),children:`Continue`})]}),(0,v.jsx)(`div`,{className:`flex min-h-dvh items-start justify-center px-4 safe-pt-10 safe-pb-10 sm:items-center`,children:(0,v.jsxs)(`div`,{className:`w-full max-w-sm rounded-xl border border-border bg-surface p-5 shadow-sm`,children:[(0,v.jsxs)(`div`,{className:`mb-4 flex items-center gap-3`,children:[(0,v.jsx)(`img`,{src:`/icon.svg`,alt:``,className:`size-10 rounded-lg`}),(0,v.jsxs)(`div`,{children:[(0,v.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Switchyard`}),(0,v.jsxs)(`p`,{className:`flex items-center gap-1 text-sm text-muted`,children:[(0,v.jsx)(m,{"aria-hidden":!0,className:`size-3.5`}),` Terminal sign-in`]})]})]}),M]})})}export{y as default};
2
+ //# sourceMappingURL=terminal-login-S5CAd5xA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-login-S5CAd5xA.js","names":["useState","__toESM","useSearchParams","useNavigate","require_react","require_jsx_runtime","isApiError","LoadingState","Button","apiGet","formatRelative","TriangleAlert","apiPost","errorMessage","Terminal","TextInput","TextLink","import_react","import_jsx_runtime","TerminalLoginView","params","navigate","code","typed","setTyped","request","setRequest","notFound","setNotFound","loadError","setLoadError","busy","setBusy","actionError","setActionError","ac","r","e","act","action","body","InlineError"],"sources":["../../src/features/terminal-login/index.tsx"],"sourcesContent":["import type { TerminalLoginRequest } from \"@switchyard/protocol\";\nimport { Terminal, TriangleAlert } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { Button } from \"../../components/ui/Button\";\nimport { InlineError, LoadingState } from \"../../components/ui/states\";\nimport { TextInput } from \"../../components/ui/TextArea\";\nimport { TextLink } from \"../../components/ui/TextLink\";\nimport { formatRelative } from \"../../lib/time\";\nimport { apiGet, apiPost, errorMessage, isApiError } from \"../../sync/api\";\n\n/** /terminal-login?code=XXXX-XXXX: approve or deny a terminal's `switchyard login`. */\nexport default function TerminalLoginView() {\n const [params] = useSearchParams();\n const navigate = useNavigate();\n const code = params.get(\"code\")?.trim() ?? \"\";\n const [typed, setTyped] = useState(\"\");\n const [request, setRequest] = useState<TerminalLoginRequest | null>(null);\n const [notFound, setNotFound] = useState<string | null>(null);\n const [loadError, setLoadError] = useState<unknown>(null);\n const [busy, setBusy] = useState(false);\n const [actionError, setActionError] = useState<unknown>(null);\n\n useEffect(() => {\n if (!code) return;\n const ac = new AbortController();\n setRequest(null);\n setNotFound(null);\n setLoadError(null);\n apiGet<TerminalLoginRequest>(\n `/api/auth/terminal/requests/${encodeURIComponent(code)}`,\n undefined,\n ac.signal,\n )\n .then((r) => !ac.signal.aborted && setRequest(r))\n .catch((e: unknown) => {\n if (ac.signal.aborted) return;\n if (isApiError(e) && e.code === \"not_found\") setNotFound(errorMessage(e));\n else setLoadError(e);\n });\n return () => ac.abort();\n }, [code]);\n\n const act = async (action: \"approve\" | \"deny\") => {\n setBusy(true);\n setActionError(null);\n try {\n setRequest(\n await apiPost<TerminalLoginRequest>(\n `/api/auth/terminal/requests/${encodeURIComponent(code)}/${action}`,\n ),\n );\n } catch (e) {\n setActionError(e);\n } finally {\n setBusy(false);\n }\n };\n\n let body: React.ReactNode;\n if (!code) {\n body = (\n <form\n className=\"flex flex-col gap-3\"\n onSubmit={(e) => {\n e.preventDefault();\n if (typed.trim()) navigate(`?code=${encodeURIComponent(typed.trim())}`);\n }}\n >\n <label htmlFor=\"tl-code\" className=\"text-sm font-medium\">\n Code from your terminal\n </label>\n <TextInput\n id=\"tl-code\"\n value={typed}\n autoComplete=\"off\"\n onChange={(e) => setTyped(e.target.value)}\n />\n <Button type=\"submit\" variant=\"primary\" disabled={!typed.trim()}>\n Continue\n </Button>\n </form>\n );\n } else if (notFound) {\n body = (\n <div\n role=\"alert\"\n className=\"rounded-md border border-border bg-danger-soft px-3 py-2 text-sm\"\n >\n <div className=\"flex items-center gap-1.5 font-medium\">\n <TriangleAlert aria-hidden className=\"size-4 shrink-0\" />\n Sign-in request not found\n </div>\n <div className=\"text-muted\">{notFound}</div>\n </div>\n );\n } else if (loadError) {\n body = <InlineError error={loadError} />;\n } else if (!request) {\n body = <LoadingState label=\"Loading the sign-in request…\" />;\n } else if (request.status === \"approved\") {\n body = (\n <div role=\"status\" className=\"flex flex-col gap-3 text-sm\">\n <p className=\"font-medium\">\n Terminal signed in. You can close this tab and return to your terminal.\n </p>\n <TextLink to=\"/\">Back to Switchyard</TextLink>\n </div>\n );\n } else if (request.status === \"denied\") {\n body = (\n <p role=\"status\" className=\"text-sm font-medium\">\n Sign-in denied. The terminal was not signed in.\n </p>\n );\n } else {\n body = (\n <div className=\"flex flex-col gap-4 text-sm\">\n <p className=\"text-base font-medium\">Sign in a terminal?</p>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2\">\n <dt className=\"text-muted\">Terminal</dt>\n <dd className=\"break-words\">{request.name}</dd>\n <dt className=\"text-muted\">Code</dt>\n <dd data-testid=\"terminal-login-code\" className=\"font-mono text-lg tracking-widest\">\n {request.userCode}\n </dd>\n <dt className=\"text-muted\">From</dt>\n <dd>{request.requestedFrom}</dd>\n <dt className=\"text-muted\">Requested</dt>\n <dd>{formatRelative(request.createdAt)}</dd>\n </dl>\n <p className=\"text-muted\">\n Approve only if you just ran switchyard login and your terminal shows this code.\n </p>\n <InlineError error={actionError} />\n <div className=\"flex gap-2\">\n <Button\n variant=\"primary\"\n data-testid=\"terminal-login-approve\"\n busy={busy}\n onClick={() => void act(\"approve\")}\n >\n Approve\n </Button>\n <Button\n data-testid=\"terminal-login-deny\"\n disabled={busy}\n onClick={() => void act(\"deny\")}\n >\n Deny\n </Button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-dvh items-start justify-center px-4 safe-pt-10 safe-pb-10 sm:items-center\">\n <div className=\"w-full max-w-sm rounded-xl border border-border bg-surface p-5 shadow-sm\">\n <div className=\"mb-4 flex items-center gap-3\">\n <img src=\"/icon.svg\" alt=\"\" className=\"size-10 rounded-lg\" />\n <div>\n <h1 className=\"text-lg font-semibold\">Switchyard</h1>\n <p className=\"flex items-center gap-1 text-sm text-muted\">\n <Terminal aria-hidden className=\"size-3.5\" /> Terminal sign-in\n </p>\n </div>\n </div>\n {body}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{_ as e,f as t,m as n,n as r,u as i}from"./jsx-runtime-D13aM9HY.js";var a={name:`plus`,size:24,node:[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]};a.node;var o=r(a),s=e(n(),1),c={syBack:!0};function l(e){return typeof e==`object`&&!!e&&e.syBack===!0}function u(e){let n=t(),{state:r}=i();return(0,s.useCallback)(()=>{l(r)?n(-1):n(e,{replace:!0})},[n,r,e])}function d(e){return t=>{t.defaultPrevented||t.button!==0||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||(t.preventDefault(),e())}}export{o as i,d as n,u as r,c as t};
2
+ //# sourceMappingURL=useBackTo-BIrCq3W2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBackTo-BIrCq3W2.js","names":["useCallback","__toESM","useNavigate","require_react","createLucideIcon","useLocation","__iconData","Plus","import_react","BACK_STATE","hasBackState","state","useBackTo","navigate","fallback","backLinkClick","e","back"],"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/plus.mjs","../../src/app/useBackTo.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: \"plus\",\n size: 24,\n node: [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n ]\n};\n__iconData.node;\nconst Plus = createLucideIcon(__iconData);\n\nexport { __iconData, Plus as default };\n//# sourceMappingURL=plus.mjs.map\n","import { type MouseEvent, useCallback } from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\n/** Location state set by in-app links whose page is the natural Back target of the page they open. */\nexport const BACK_STATE = { syBack: true } as const;\n\nexport function hasBackState(state: unknown): boolean {\n return (\n typeof state === \"object\" && state !== null && (state as { syBack?: unknown }).syBack === true\n );\n}\n\n/** Pop history when opened from the in-app parent; otherwise replace with `fallback` (never push). */\nexport function useBackTo(fallback: string): () => void {\n const navigate = useNavigate();\n const { state } = useLocation();\n return useCallback(() => {\n if (hasBackState(state)) navigate(-1);\n else navigate(fallback, { replace: true });\n }, [navigate, state, fallback]);\n}\n\n/** onClick for a `<Link to={fallback}>` Back link; modified clicks stay native. */\nexport function backLinkClick(back: () => void) {\n return (e: MouseEvent) => {\n if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {\n return;\n }\n e.preventDefault();\n back();\n };\n}\n"],"ignoreList":[0],"mappings":"A,0EASA,IAAMM,EAAa,CACjB,KAAM,OACN,KAAM,GACN,KAAM,CACJ,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,CAC3C,CACF,EACAA,EAAW,KACX,IAAMC,EAAOH,EAAiBE,CAAU,E,WCd3BG,EAAa,CAAE,OAAQ,EAAK,EAEzC,SAAgBC,EAAa,EAAyB,CACpD,OACE,OAAOC,GAAU,YAAYA,GAAmBA,EAA+B,SAAW,EAE9F,CAGA,SAAgBC,EAAU,EAA8B,CACtD,IAAMC,EAAWX,EAAY,EACvB,CAAE,SAAUG,EAAY,EAC9B,OAAA,EAAOL,EAAAA,YAAAA,KAAkB,CACnBU,EAAaC,CAAK,EAAGE,EAAS,EAAE,EAC/BA,EAASC,EAAU,CAAE,QAAS,EAAK,CAAC,CAC3C,EAAG,CAACD,EAAUF,EAAOG,CAAQ,CAAC,CAChC,CAGA,SAAgBC,EAAc,EAAkB,CAC9C,MAAQ,IAAkB,CACpBC,EAAE,kBAAoBA,EAAE,SAAW,GAAKA,EAAE,SAAWA,EAAE,SAAWA,EAAE,UAAYA,EAAE,SAGtFA,EAAE,eAAe,EACjBC,EAAK,EACP,CACF,C"}
@@ -0,0 +1,2 @@
1
+ import{_ as e,m as t,n,t as r}from"./jsx-runtime-D13aM9HY.js";import{A as i,J as a,P as o,_ as s,_t as c,bt as l,d as u,gt as d,ht as f,i as p,lt as m,n as ee,o as te,u as h,vt as g,yt as _,z as v}from"./states-ZhrxQa3K.js";import{t as ne}from"./search-C6cn5WOo.js";import{D as re,K as y,b,c as x,j as S,k as C,q as w}from"./index-hxvDvCS7.js";import{i as T,n as ie}from"./Overlay-DUQwh6_b.js";import{r as ae}from"./TextArea-CKybrQyn.js";import{t as oe}from"./TextLink-OzzyP2-p.js";import{r as se}from"./useResource-CDGSq2At.js";import{t as E}from"./Select-Cfql4Nwu.js";import{t as D}from"./Checkbox-D6tRfEeI.js";var O={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`]};O.node;var k=n(O),A=e(t(),1),j=e=>`/api/tasks/${encodeURIComponent(e)}`;function M(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 N(e){let t=M(e);return t?(v.setState(e=>{let n=e.tasks[t.id];return n&&n.updatedAt>t.updatedAt?{}:{tasks:{...e.tasks,[t.id]:t}}}),t):null}async function P(e){let t=N(await g(`/api/tasks`,e));if(!t)throw Error(`The coordinator returned an unexpected response`);return t}async function F(e,t){return N(await c(j(e),t))}async function I(e){await f(j(e)),v.setState(t=>{if(!t.tasks[e])return{};let{[e]:n,...r}=t.tasks;return{tasks:r}})}async function L(e,t){return N(await g(`${j(e)}/move`,t))}async function R(e,t,n,r){return N(await g(`${j(e)}/${t}${r??``}`,n))}async function z(e,t){return N(await g(`${j(e)}/request-changes`,{feedback:t}))}function B(e,t){return d(`${j(e)}/eligibility`,void 0,t)}async function V(e,t){let n=await d(`${j(e)}/runs`,void 0,t);return Array.isArray(n)?n:n.runs??[]}async function H(e){await g(`/api/dispatch/pause`,{paused:e}),v.setState({dispatchPaused:e})}function U(e){return!l(e)||e.status!==409&&e.code!==`invalid_transition`?!1:e.details?.needsConfirm===!0||/confirm/i.test(e.message)}function W(e){if(!l(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 G=[`backlog`,`ready`,`in_progress`,`review`,`done`],K={backlog:`Backlog`,ready:`Ready`,in_progress:`In progress`,review:`Review`,done:`Done`,canceled:`Canceled`},q={search:``,priorities:[],hostId:null,attentionOnly:!1,blockedOnly:!1,showCanceled:!1,showCompleted:!0,sort:`priority`};function ce(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 J(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: ${m[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 le(e,t){return(e.currentRunId?t[e.currentRunId]:void 0)?.hostId??e.policy.hostId??null}function ue(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&&le(e,n.runs)!==t.hostId||t.attentionOnly&&!n.attentionTaskIds.has(e.id)||t.blockedOnly&&!e.blocked)}function de(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 fe(e,t,n){let r={backlog:[],ready:[],in_progress:[],review:[],done:[],canceled:[]};for(let i of Object.values(e))ue(i,t,n)&&r[i.state].push(i);for(let e of Object.keys(r))r[e]=de(r[e],t.sort);return r}function pe(e){return e.showCanceled?[...G,`canceled`]:G}var Y={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 me(e){return!!e&&[`queued`,`dispatching`,`uncertain`,`running`,`waiting_input`,`checking`].includes(e.state)}function he(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}var ge=[`backlog`,`ready`,`in_progress`,`review`,`done`,`canceled`];function _e(e){switch(e.kind){case`invalid`:return e.reason;case`choose_running`:return`Asks whether to pause automation or stop execution.`;case`confirm_done`:return`Asks you to confirm acceptance.`;case`run_now`:return`Starts now if the task is eligible.`;default:return null}}function ve(e,t,n){if(e.state===t)return{kind:`noop`};let r=e.state;if(!Y[r].includes(t))return{kind:`invalid`,reason:ye(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=he(e,n);if(t.length>0)return{kind:`confirm_done`,reasons:t}}return{kind:`move`}}function ye(e,t){let n=K[e],r=K[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 be(e){return Y[e.state]}function xe(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 X={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:`Auto-start is off for this project`,not_ready:`Not ready`,already_dispatched:`Already dispatched`,retry_backoff:`Retrying after a failure`};function Se(e){return e.eligible?`Will start automatically on ${e.hostName}`:`Will wait: ${e.message||X[e.wait]}`}function Ce(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:`Auto-start 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 we(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 Te(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 Z=r();function Ee({board:e,className:t,labelVisible:n}){let r=o(),i=(0,A.useId)();return(0,Z.jsxs)(`div`,{className:s(n?`flex min-w-0 flex-col gap-1`:`flex min-w-0 items-center gap-2`,t),children:[(0,Z.jsx)(`label`,{htmlFor:i,className:n?`text-sm font-medium`:`sr-only`,children:`Project`}),(0,Z.jsxs)(E,{id:i,className:n?`w-full`:`max-w-56`,value:e.projectId??``,onChange:t=>e.setProjectId(t.target.value||null),children:[(0,Z.jsx)(`option`,{value:``,children:`All projects`}),r.map(e=>(0,Z.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]})}function De({board:e,className:t,autoFocus:n}){let r=(0,A.useId)();return(0,Z.jsxs)(`div`,{className:s(`relative min-w-0`,t),children:[(0,Z.jsx)(`label`,{htmlFor:r,className:`sr-only`,children:`Search tasks`}),(0,Z.jsx)(ne,{"aria-hidden":!0,className:`pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-subtle`}),(0,Z.jsx)(ae,{id:r,type:`search`,placeholder:`Search tasks`,autoFocus:n,className:`pl-8`,value:e.filters.search,onChange:t=>e.setFilters({...e.filters,search:t.target.value})})]})}function Oe({board:e}){let t=(0,A.useId)();return(0,Z.jsxs)(`div`,{className:`flex items-center gap-1.5 text-sm`,children:[(0,Z.jsx)(`label`,{htmlFor:t,className:`text-muted`,children:`Sort`}),(0,Z.jsxs)(E,{id:t,width:`auto`,value:e.filters.sort,onChange:t=>e.setFilters({...e.filters,sort:t.target.value}),children:[(0,Z.jsx)(`option`,{value:`priority`,children:`Priority`}),(0,Z.jsx)(`option`,{value:`updated`,children:`Recently updated`}),(0,Z.jsx)(`option`,{value:`created`,children:`Newest`})]})]})}function ke({board:e}){return(0,Z.jsx)(D,{label:`Show completed`,checked:e.filters.showCompleted,onChange:t=>e.setFilters({...e.filters,showCompleted:t})})}function Ae(){let e=v(e=>e.dispatchPaused),[t,n]=(0,A.useState)(!1);return{paused:e,busy:t,toggle:async()=>{n(!0);try{await H(!e),b.success(e?`Dispatch resumed. Ready tasks start when eligible.`:`Dispatch paused. Running work continues; nothing new starts.`)}catch(t){b.error(`Could not ${e?`resume`:`pause`} dispatch: ${_(t)}`)}finally{n(!1)}}}}function Q(){let{paused:e,busy:t,toggle:n}=Ae(),r=e?w:y;return(0,Z.jsxs)(`div`,{className:`flex min-w-0 flex-wrap items-center gap-2 text-sm`,children:[(0,Z.jsxs)(`span`,{role:`status`,className:s(`inline-flex items-center gap-1.5 font-medium`,e?`text-warning`:`text-success`),children:[(0,Z.jsx)(r,{"aria-hidden":!0,className:`size-4`}),(0,Z.jsx)(`span`,{className:`text-text`,children:e?`Dispatch paused`:`Dispatch on`})]}),(0,Z.jsx)(u,{size:`sm`,busy:t,onClick:()=>void n(),children:e?`Resume dispatch`:`Pause dispatch`})]})}function $({queueCount:e}){let t=v(e=>e.dispatchPaused),[n,r]=(0,A.useState)(!1),i=t?w:y;return(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsxs)(`button`,{type:`button`,"aria-haspopup":`dialog`,onClick:()=>r(!0),className:s(`tap inline-flex items-center gap-1 rounded-full border px-2.5 text-xs leading-6 font-medium`,t?C.warning:C.neutral),children:[(0,Z.jsx)(i,{"aria-hidden":!0,className:s(`size-3.5`,t?`text-warning`:`text-success`)}),(0,Z.jsx)(`span`,{className:`text-text`,children:t?`Dispatch paused`:`Dispatch on`}),(0,Z.jsxs)(`span`,{children:[`· `,e,` queued`]})]}),(0,Z.jsx)(T,{open:n,onClose:()=>r(!1),title:`Dispatch`,description:`Pausing stops new work from starting. Runs already in progress keep going.`,children:(0,Z.jsx)(Q,{})})]})}function je({value:e,onChange:t,withSort:n}){let r=i(),a=(0,A.useId)(),o=(n,r)=>t({...e,priorities:r?[...e.priorities,n]:e.priorities.filter(e=>e!==n)});return(0,Z.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,Z.jsxs)(`fieldset`,{className:`flex flex-col gap-1`,children:[(0,Z.jsx)(`legend`,{className:`mb-1 text-sm font-medium`,children:`Priority`}),(0,Z.jsx)(`div`,{className:`flex flex-wrap gap-x-4`,children:m.map((t,n)=>(0,Z.jsx)(D,{label:t,checked:e.priorities.includes(n),onChange:e=>o(n,e)},t))})]}),(0,Z.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,Z.jsx)(`label`,{htmlFor:`${a}-host`,className:`text-sm font-medium`,children:`Host`}),(0,Z.jsxs)(E,{id:`${a}-host`,value:e.hostId??``,onChange:n=>t({...e,hostId:n.target.value||null}),children:[(0,Z.jsx)(`option`,{value:``,children:`Any host`}),r.map(e=>(0,Z.jsx)(`option`,{value:e.id,children:e.name},e.id))]})]}),(0,Z.jsxs)(`fieldset`,{className:`flex flex-col gap-1`,children:[(0,Z.jsx)(`legend`,{className:`mb-1 text-sm font-medium`,children:`Show`}),(0,Z.jsx)(D,{label:`Only tasks that need attention`,checked:e.attentionOnly,onChange:n=>t({...e,attentionOnly:n})}),(0,Z.jsx)(D,{label:`Only blocked tasks`,checked:e.blockedOnly,onChange:n=>t({...e,blockedOnly:n})}),(0,Z.jsx)(D,{label:`Canceled tasks`,checked:e.showCanceled,onChange:n=>t({...e,showCanceled:n})}),(0,Z.jsx)(D,{label:`Completed tasks`,checked:e.showCompleted,onChange:n=>t({...e,showCompleted:n})})]}),n&&(0,Z.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,Z.jsx)(`label`,{htmlFor:`${a}-sort`,className:`text-sm font-medium`,children:`Sort`}),(0,Z.jsxs)(E,{id:`${a}-sort`,value:e.sort,onChange:n=>t({...e,sort:n.target.value}),children:[(0,Z.jsx)(`option`,{value:`priority`,children:`Priority`}),(0,Z.jsx)(`option`,{value:`updated`,children:`Recently updated`}),(0,Z.jsx)(`option`,{value:`created`,children:`Newest`})]})]})]})}function Me({board:e,mobile:t,extra:n,extraCount:r=0}){let[i,a]=(0,A.useState)(!1),[o,s]=(0,A.useState)(e.filters),c=v(e=>e.hosts),l=J(e.filters,e=>c[e]?.name??`host`).filter(e=>e.key!==`search`).length+r,d=t?T:ie;return(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsxs)(u,{size:t?`sm`:`md`,icon:(0,Z.jsx)(k,{className:`size-4`}),onClick:()=>{s(e.filters),a(!0)},"aria-label":l?`Filters, ${l} active`:`Filters`,children:[`Filters`,l>0&&(0,Z.jsx)(re,{tone:`accent`,children:l})]}),(0,Z.jsx)(d,{open:i,onClose:()=>a(!1),title:`Filter tasks`,footer:(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(u,{variant:`ghost`,onClick:()=>s({...q,search:o.search}),children:`Reset`}),(0,Z.jsx)(u,{variant:`primary`,onClick:()=>{e.setFilters(o),a(!1)},children:`Show results`})]}),children:(0,Z.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[n&&(0,Z.jsx)(`div`,{className:`flex flex-col gap-4 border-b border-border pb-4`,children:n}),(0,Z.jsx)(je,{value:o,onChange:s,withSort:t})]})})]})}function Ne({board:e,includeSearch:t}){let n=v(e=>e.hosts),r=J(e.filters,e=>n[e]?.name??`Unknown host`).filter(e=>t||e.key!==`search`);return r.length===0?null:(0,Z.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,Z.jsx)(`li`,{className:`min-w-0`,children:(0,Z.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,Z.jsx)(`span`,{className:`truncate`,children:t.label}),(0,Z.jsx)(S,{"aria-hidden":!0,className:`size-3.5 shrink-0`})]})},t.key)),r.length>1&&(0,Z.jsx)(`li`,{children:(0,Z.jsx)(oe,{size:`xs`,onClick:()=>e.setFilters({...q,sort:e.filters.sort}),children:`Clear all`})})]})}function Pe({board:e}){let t=v(e=>e.tasks),n=v(e=>e.runs),r=v(e=>e.hosts),i=v(e=>e.interactions),{offline:o,pending:s}=(0,A.useMemo)(()=>{let o=new Set,s=new Set;for(let i of Object.values(t)){if(e.projectId&&i.projectId!==e.projectId)continue;i.sessionId&&s.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`&&o.add(e.id)}}let c=a(i,s);return{offline:[...o].map(e=>r[e]),pending:c}},[t,n,r,i,e.projectId]),c=e.now.error,u=[];for(let e of o)u.push((0,Z.jsx)(p,{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 s.length>0&&u.push((0,Z.jsx)(te,{count:s.length,to:x.interaction(s[0].sessionId,s[0].id),label:s.length===1?`A task needs input`:`${s.length} questions need input`},`pending`)),c!=null&&(l(c)&&c.status===404?u.push((0,Z.jsx)(h,{capability:`Queue details`,reason:`This coordinator does not report why Ready tasks are waiting.`},`now`)):u.push((0,Z.jsx)(ee,{compact:!0,title:`Could not load the dispatch queue`,error:_(c),onRetry:e.now.reload},`now`))),u.length===0?null:(0,Z.jsx)(`div`,{className:`flex flex-col gap-2 px-4 pt-2`,children:u})}function Fe(e=!0){let t=se(e?`now`:null,e=>d(`/api/now`,void 0,e),{refreshMs:15e3}),n=v(e=>e.tasks),r=v(e=>e.runs),i=v(e=>e.dispatchPaused),a=(0,A.useRef)(!0),{reload:o}=t;return(0,A.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{V as A,ve as C,P as D,pe as E,R as F,F as I,U as M,W as N,I as O,z as P,we as S,Ce as T,Se as _,Q as a,be as b,Ee as c,ge as d,q as f,Te as g,fe as h,$ as i,L as j,B as k,De as l,X as m,Pe as n,Me as o,K as p,ke as r,Ne as s,Fe as t,Oe as u,me as v,xe as w,ce as x,_e as y};
2
+ //# sourceMappingURL=useNow-Dj7oEiwn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useNow-Dj7oEiwn.js","names":["useId","useState","_Fragment","Filter","useMemo","useRef","__toESM","require_react","require_jsx_runtime","useHosts","pendingInteractionsForSessions","useProjects","cn","apiPatch","isApiError","Button","apiGet","apiDelete","HostUnavailable","PRIORITY_LABELS","ErrorState","InteractionPending","UnsupportedCapability","apiPost","errorMessage","useSyncStore","Search","Badge","CirclePlay","ROUTES","X","TONE_CLASSES","CirclePause","Sheet","Dialog","TextInput","TextLink","useResource","Select","Checkbox","__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","ALL_STATES","moveHint","plan","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","ProjectSelect","projects","labelVisible","className","board","e","SearchBox","SortSelect","CompletedToggle","on","useDispatchControl","busy","setBusy","toast","DispatchToggle","Icon","toggle","DispatchChip","setOpen","queueCount","FilterFields","hosts","togglePriority","onChange","value","l","i","h","withSort","FilterButton","draft","setDraft","count","extraCount","Surface","mobile","extra","FilterChips","includeSearch","BoardNotices","interactions","offlineIds","sessionIds","pend","nowErr","notices","offline","pending","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/queue/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, TaskPolicyPatch, 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?: TaskPolicyPatch;\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 const ALL_STATES: TaskState[] = [\n \"backlog\",\n \"ready\",\n \"in_progress\",\n \"review\",\n \"done\",\n \"canceled\",\n];\n\n/** Short explanation under a move target: why it is blocked, or what choice it asks for. */\nexport function moveHint(plan: MovePlan): string | null {\n switch (plan.kind) {\n case \"invalid\":\n return plan.reason;\n case \"choose_running\":\n return \"Asks whether to pause automation or stop execution.\";\n case \"confirm_done\":\n return \"Asks you to confirm acceptance.\";\n case \"run_now\":\n return \"Starts now if the task is eligible.\";\n default:\n return null;\n }\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: \"Auto-start is off for this project\",\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: `Auto-start 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, TONE_CLASSES } from \"../../components/ui/Badge\";\nimport { Button } from \"../../components/ui/Button\";\nimport { Checkbox } from \"../../components/ui/Checkbox\";\nimport { Dialog, Sheet } from \"../../components/ui/Overlay\";\nimport { Select } from \"../../components/ui/Select\";\nimport {\n ErrorState,\n HostUnavailable,\n InteractionPending,\n UnsupportedCapability,\n} from \"../../components/ui/states\";\nimport { TextInput } from \"../../components/ui/TextArea\";\nimport { TextLink } from \"../../components/ui/TextLink\";\nimport { toast } from \"../../components/ui/Toast\";\nimport { cn } from \"../../lib/cn\";\nimport { errorMessage, isApiError } from \"../../sync/api\";\nimport { pendingInteractionsForSessions } from \"../../sync/selectors\";\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\nexport function ProjectSelect({\n board,\n className,\n labelVisible,\n}: {\n board: BoardState;\n className?: string;\n labelVisible?: boolean;\n}) {\n const projects = useProjects();\n const id = useId();\n return (\n <div\n className={cn(\n labelVisible ? \"flex min-w-0 flex-col gap-1\" : \"flex min-w-0 items-center gap-2\",\n className,\n )}\n >\n <label htmlFor={id} className={labelVisible ? \"text-sm font-medium\" : \"sr-only\"}>\n Project\n </label>\n <Select\n id={id}\n className={labelVisible ? \"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({\n board,\n className,\n autoFocus,\n}: {\n board: BoardState;\n className?: string;\n autoFocus?: boolean;\n}) {\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 autoFocus={autoFocus}\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 width=\"auto\"\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 <Checkbox\n label=\"Show completed\"\n checked={board.filters.showCompleted}\n onChange={(on) => board.setFilters({ ...board.filters, showCompleted: on })}\n />\n );\n}\n\nfunction useDispatchControl() {\n const paused = useSyncStore((s) => s.dispatchPaused);\n const [busy, setBusy] = useState(false);\n const toggle = 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 return { paused, busy, toggle };\n}\n\n/** Dispatch status and the pause/resume button (never terminates active runs). Board and Queue. */\nexport function DispatchToggle() {\n const { paused, busy, toggle } = useDispatchControl();\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 ? \"Dispatch paused\" : \"Dispatch on\"}</span>\n </span>\n <Button size=\"sm\" busy={busy} onClick={() => void toggle()}>\n {paused ? \"Resume dispatch\" : \"Pause dispatch\"}\n </Button>\n </div>\n );\n}\n\n/** Mobile board: compact dispatch status that opens a sheet with the toggle. */\nexport function DispatchChip({ queueCount }: { queueCount: number }) {\n const paused = useSyncStore((s) => s.dispatchPaused);\n const [open, setOpen] = useState(false);\n const Icon = paused ? CirclePause : CirclePlay;\n return (\n <>\n <button\n type=\"button\"\n aria-haspopup=\"dialog\"\n onClick={() => setOpen(true)}\n className={cn(\n \"tap inline-flex items-center gap-1 rounded-full border px-2.5 text-xs leading-6 font-medium\",\n paused ? TONE_CLASSES.warning : TONE_CLASSES.neutral,\n )}\n >\n <Icon aria-hidden className={cn(\"size-3.5\", paused ? \"text-warning\" : \"text-success\")} />\n <span className=\"text-text\">{paused ? \"Dispatch paused\" : \"Dispatch on\"}</span>\n <span>· {queueCount} queued</span>\n </button>\n <Sheet\n open={open}\n onClose={() => setOpen(false)}\n title=\"Dispatch\"\n description=\"Pausing stops new work from starting. Runs already in progress keep going.\"\n >\n <DispatchToggle />\n </Sheet>\n </>\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 <Checkbox\n key={l}\n label={l}\n checked={value.priorities.includes(i as Priority)}\n onChange={(on) => togglePriority(i as Priority, on)}\n />\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 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 <Checkbox\n label=\"Only tasks that need attention\"\n checked={value.attentionOnly}\n onChange={(on) => onChange({ ...value, attentionOnly: on })}\n />\n <Checkbox\n label=\"Only blocked tasks\"\n checked={value.blockedOnly}\n onChange={(on) => onChange({ ...value, blockedOnly: on })}\n />\n <Checkbox\n label=\"Canceled tasks\"\n checked={value.showCanceled}\n onChange={(on) => onChange({ ...value, showCanceled: on })}\n />\n <Checkbox\n label=\"Completed tasks\"\n checked={value.showCompleted}\n onChange={(on) => onChange({ ...value, showCompleted: on })}\n />\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 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({\n board,\n mobile,\n extra,\n extraCount = 0,\n}: {\n board: BoardState;\n mobile?: boolean;\n /** Controls above the filter fields that apply at once (mobile board: project and layout). */\n extra?: ReactNode;\n extraCount?: number;\n}) {\n const [open, setOpen] = useState(false);\n const [draft, setDraft] = useState(board.filters);\n const hosts = useSyncStore((s) => s.hosts);\n const count =\n activeFilterChips(board.filters, (id) => hosts[id]?.name ?? \"host\").filter(\n (c) => c.key !== \"search\",\n ).length + extraCount;\n const Surface = mobile ? Sheet : Dialog;\n return (\n <>\n <Button\n size={mobile ? \"sm\" : \"md\"}\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 <div className=\"flex flex-col gap-4\">\n {extra && <div className=\"flex flex-col gap-4 border-b border-border pb-4\">{extra}</div>}\n <FilterFields value={draft} onChange={setDraft} withSort={mobile} />\n </div>\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 <TextLink\n size=\"xs\"\n onClick={() => board.setFilters({ ...DEFAULT_FILTERS, sort: board.filters.sort })}\n >\n Clear all\n </TextLink>\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 = pendingInteractionsForSessions(interactions, sessionIds);\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 ? \"A task needs input\" : `${pending.length} questions need input`\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 type { NowResponse } from \"@switchyard/protocol\";\nimport { useEffect, useRef } from \"react\";\nimport { type Resource, useResource } from \"../../lib/useResource\";\nimport { apiGet } from \"../../sync/api\";\nimport { useSyncStore } from \"../../sync/store\";\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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"}
@@ -0,0 +1,2 @@
1
+ import{_ as e,m as t}from"./jsx-runtime-D13aM9HY.js";import{gt as n}from"./states-ZhrxQa3K.js";var r=e(t(),1),i=class extends Error{constructor(e){super(`Unexpected response from ${e}. The coordinator and this app may be out of sync.`),this.name=`UnexpectedResponseError`}};function a(e,t,n={}){let[a,o]=(0,r.useState)(void 0),[s,c]=(0,r.useState)(null),[l,u]=(0,r.useState)(!1),[d,f]=(0,r.useState)(e!==null),[p,m]=(0,r.useState)(0),h=(0,r.useRef)(t);h.current=t;let g=(0,r.useRef)(n.check);return g.current=n.check,(0,r.useEffect)(()=>{if(e===null){f(!1);return}let t=new AbortController;return f(!0),h.current(t.signal).then(n=>{if(t.signal.aborted)return;let r=g.current;r&&!r(n)?(c(new i(e)),u(!0)):(o(n),c(null),u(!1))}).catch(e=>{t.signal.aborted||e instanceof DOMException&&e.name===`AbortError`||(c(e),u(!1))}).finally(()=>{t.signal.aborted||f(!1)}),()=>t.abort()},[e,p]),(0,r.useEffect)(()=>{if(!n.refreshMs||e===null)return;let t=setInterval(()=>{document.visibilityState===`visible`&&m(e=>e+1)},n.refreshMs);return()=>clearInterval(t)},[n.refreshMs,e]),{data:a,error:s,loading:d,fatal:l,reload:(0,r.useCallback)(()=>m(e=>e+1),[]),setData:(0,r.useCallback)(e=>{o(e),c(null),u(!1),f(!1)},[])}}function o(e,t){return a(e,t=>n(e,void 0,t),t?{check:t}:void 0)}function s(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{o as n,a as r,s as t};
2
+ //# sourceMappingURL=useResource-CDGSq2At.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useResource-CDGSq2At.js","names":["useState","useRef","useCallback","__toESM","require_react","apiGet","import_react","UnexpectedResponseError","path","useResource","data","setDataState","error","setError","fatal","setFatal","loading","setLoading","key","nonce","setNonce","fetcherRef","fetcher","checkRef","opts","ctrl","check","d","n","useApiResource","signal","isObject","v"],"sources":["../../src/lib/useResource.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { apiGet } from \"../sync/api\";\n\n/** Thrown when a response does not have the expected shape (render FatalError). */\nexport class UnexpectedResponseError extends Error {\n constructor(path: string) {\n super(`Unexpected response from ${path}. The coordinator and this app may be out of sync.`);\n this.name = \"UnexpectedResponseError\";\n }\n}\n\nexport interface Resource<T> {\n data: T | undefined;\n /** The last error; kept until the next result arrives. */\n error: unknown;\n /** True while a request is in flight (initial fetch, reload or refresh). */\n loading: boolean;\n /** True when the response had an unexpected shape (irrecoverable). */\n fatal: boolean;\n /** Refetch; keeps the last data while loading. */\n reload: () => void;\n /** Replace the data locally (e.g. with a mutation response). */\n setData: (data: T) => void;\n}\n\nexport interface ResourceOptions {\n /** Refetch on this interval while the page is visible. */\n refreshMs?: number;\n /** Validates the response shape; a failure makes the resource `fatal`. */\n check?: (data: unknown) => boolean;\n}\n\n/**\n * Fetch a resource. `key` changes trigger a refetch; null skips fetching. Errors\n * 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: ResourceOptions = {},\n): Resource<T> {\n const [data, setDataState] = useState<T | undefined>(undefined);\n const [error, setError] = useState<unknown>(null);\n const [fatal, setFatal] = useState(false);\n const [loading, setLoading] = useState(key !== null);\n const [nonce, setNonce] = useState(0);\n const fetcherRef = useRef(fetcher);\n fetcherRef.current = fetcher;\n const checkRef = useRef(opts.check);\n checkRef.current = opts.check;\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 const check = checkRef.current;\n if (check && !check(d)) {\n setError(new UnexpectedResponseError(key));\n setFatal(true);\n return;\n }\n setDataState(d);\n setError(null);\n setFatal(false);\n })\n .catch((e) => {\n if (ctrl.signal.aborted || (e instanceof DOMException && e.name === \"AbortError\")) return;\n setError(e);\n setFatal(false);\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 const setData = useCallback((d: T) => {\n setDataState(d);\n setError(null);\n setFatal(false);\n setLoading(false);\n }, []);\n return { data, error, loading, fatal, reload, setData };\n}\n\n/** GET an API path as a resource. `check` validates the response shape. */\nexport function useApiResource<T>(\n path: string | null,\n check?: (data: unknown) => boolean,\n): Resource<T> {\n return useResource<T>(\n path,\n (signal) => apiGet<T>(path as string, undefined, signal),\n check ? { check } : undefined,\n );\n}\n\n/** True for a plain JSON object. */\nexport function isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n"],"mappings":"A,8GAIaO,EAAb,cAA6C,KAAM,CACjD,YAAY,EAAc,CACxB,MAAM,4BAA4BC,EAAK,mDAAmD,EAC1F,KAAK,KAAO,yBACd,CACF,EA2BA,SAAgBC,EACd,EACA,EACA,EAAwB,CAAC,EACZ,CACb,GAAM,CAACC,EAAMC,IAAA,EAAgBX,EAAAA,SAAAA,CAAwB,IAAA,EAAS,EACxD,CAACY,EAAOC,IAAA,EAAYb,EAAAA,SAAAA,CAAkB,IAAI,EAC1C,CAACc,EAAOC,IAAA,EAAYf,EAAAA,SAAAA,CAAS,EAAK,EAClC,CAACgB,EAASC,IAAA,EAAcjB,EAAAA,SAAAA,CAASkB,IAAQ,IAAI,EAC7C,CAACC,EAAOC,IAAA,EAAYpB,EAAAA,SAAAA,CAAS,CAAC,EAC9BqB,GAAA,EAAapB,EAAAA,OAAAA,CAAOqB,CAAO,EACjC,EAAW,QAAUA,EACrB,IAAMC,GAAA,EAAWtB,EAAAA,OAAAA,CAAOuB,EAAK,KAAK,EAmDlC,MAlDA,GAAS,QAAUA,EAAK,OAGxB,EAAAlB,EAAA,UAAA,KAAgB,CACd,GAAIY,IAAQ,KAAM,CAChBD,EAAW,EAAK,EAChB,MACF,CACA,IAAMQ,EAAO,IAAI,gBAwBjB,OAvBAR,EAAW,EAAI,EACfI,EACG,QAAQI,EAAK,MAAM,CAAC,CACpB,KAAM,GAAM,CACX,GAAIA,EAAK,OAAO,QAAS,OACzB,IAAMC,EAAQH,EAAS,QACnBG,GAAS,CAACA,EAAMC,CAAC,GACnBd,EAAS,IAAIN,EAAwBW,CAAG,CAAC,EACzCH,EAAS,EAAI,IAGfJ,EAAagB,CAAC,EACdd,EAAS,IAAI,EACbE,EAAS,EAAK,EAChB,CAAC,CAAC,CACD,MAAO,GAAM,CACRU,EAAK,OAAO,SAAY,aAAa,cAAgB,EAAE,OAAS,eACpEZ,EAAS,CAAC,EACVE,EAAS,EAAK,EAChB,CAAC,CAAC,CACD,YAAc,CACRU,EAAK,OAAO,SAASR,EAAW,EAAK,CAC5C,CAAC,MACUQ,EAAK,MAAM,CAC1B,EAAG,CAACP,EAAKC,CAAK,CAAC,GAEf,EAAAb,EAAA,UAAA,KAAgB,CACd,GAAI,CAACkB,EAAK,WAAaN,IAAQ,KAAM,OACrC,IAAM,EAAI,gBAAkB,CACtB,SAAS,kBAAoB,WAAWE,EAAU,GAAMQ,EAAI,CAAC,CACnE,EAAGJ,EAAK,SAAS,EACjB,UAAa,cAAc,CAAC,CAC9B,EAAG,CAACA,EAAK,UAAWN,CAAG,CAAC,EASjB,CAAE,OAAM,QAAO,UAAS,QAAO,QAAA,EAPvBhB,EAAAA,YAAAA,KAAkBkB,EAAU,GAAMQ,EAAI,CAAC,EAAG,CAAC,CAOpB,EAAQ,SAAA,EAN9B1B,EAAAA,YAAAA,CAAa,GAAS,CACpCS,EAAagB,CAAC,EACdd,EAAS,IAAI,EACbE,EAAS,EAAK,EACdE,EAAW,EAAK,CAClB,EAAG,CAAC,CAC0C,CAAQ,CACxD,CAGA,SAAgBY,EACd,EACA,EACa,CACb,OAAOpB,EACLD,EACC,GAAWH,EAAUG,EAAgB,IAAA,GAAWsB,CAAM,EACvDJ,EAAQ,CAAE,OAAM,EAAI,IAAA,EACtB,CACF,CAGA,SAAgBK,EAAS,EAA0C,CACjE,OAAO,OAAOC,GAAM,YAAYA,GAAc,CAAC,MAAM,QAAQA,CAAC,CAChE,C"}
Binary file
Binary file
package/web-dist/icon.svg CHANGED
@@ -1,12 +1,24 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
2
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"/>
3
+ <rect id="bg" width="512" height="512" rx="96" fill="#1f2937"/>
4
+ <g id="mark">
5
+ <path d="M100 102h156v102H100a10 10 0 0 1-10-10v-82a10 10 0 0 1 10-10z" fill="#60a5fa"/>
6
+ <path d="M256 102h156a10 10 0 0 1 10 10v82a10 10 0 0 1-10 10H256z" fill="#34d399"/>
7
+ <g fill="#1f2937">
8
+ <circle cx="192" cy="190" r="40"/>
9
+ <circle cx="320" cy="190" r="40"/>
10
+ </g>
11
+ <g stroke="#f9fafb" stroke-linecap="round" fill="none">
12
+ <path d="M192 190 L120 384" stroke-width="56"/>
13
+ <path d="M320 190 L392 384" stroke-width="56"/>
14
+ </g>
15
+ <g fill="#f9fafb">
16
+ <circle cx="192" cy="190" r="26"/>
17
+ <circle cx="320" cy="190" r="26"/>
18
+ </g>
19
+ <g fill="#1f2937">
20
+ <circle cx="192" cy="190" r="12"/>
21
+ <circle cx="320" cy="190" r="12"/>
22
+ </g>
9
23
  </g>
10
- <circle cx="136" cy="120" r="26" fill="#60a5fa"/>
11
- <circle cx="376" cy="392" r="26" fill="#34d399"/>
12
24
  </svg>
@@ -13,12 +13,11 @@
13
13
  <link rel="icon" type="image/svg+xml" href="/icon.svg" />
14
14
  <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
15
15
  <title>Switchyard</title>
16
- <script type="module" crossorigin src="/assets/index-vIzH1m8u.js"></script>
16
+ <script type="module" crossorigin src="/assets/index-hxvDvCS7.js"></script>
17
17
  <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-D13aM9HY.js">
18
- <link rel="modulepreload" crossorigin href="/assets/states--geW2Ntl.js">
19
- <link rel="modulepreload" crossorigin href="/assets/Badge-BiDp7NKI.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/states-ZhrxQa3K.js">
20
19
  <link rel="modulepreload" crossorigin href="/assets/presence-05bJD5G3.js">
21
- <link rel="stylesheet" crossorigin href="/assets/index-DvRcMGEe.css">
20
+ <link rel="stylesheet" crossorigin href="/assets/index-B3F7WcYf.css">
22
21
  <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js" defer></script></head>
23
22
  <body>
24
23
  <div id="root"></div>
@@ -1 +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"}]}
1
+ {"name":"Switchyard","short_name":"Switchyard","description":"Pi coding sessions, tasks and automations across your hosts","start_url":"/","display":"standalone","background_color":"#f8fafc","theme_color":"#f8fafc","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
package/web-dist/sw.js CHANGED
@@ -1,2 +1,2 @@
1
- try{self[`workbox:core:7.4.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.4.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.4.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.4.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&(t.origin===location.origin||n.index===0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}var B=`-precache-`,V=async(e,t=B)=>{let n=(await self.caches.keys()).filter(n=>n.includes(t)&&n.includes(self.registration.scope)&&n!==e);return await Promise.all(n.map(e=>self.caches.delete(e))),n};function H(){self.addEventListener(`activate`,(e=>{let t=a.getPrecacheName();e.waitUntil(V(t).then(e=>{}))}))}function U(e){return O().matchPrecache(e)}function W(e){O().precache(e)}function G(e,t){W(e),z(t)}G([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"77a2d561f8d777b2552c56aaedbab45b","url":"maskable-512.png"},{"revision":"bf5a5dabd14b016541f46bda39e0a1b0","url":"index.html"},{"revision":"aff1fd110f9bbf5840024b47c6362287","url":"icon.svg"},{"revision":"4e7e82ba69994d6ce779099a3a2a9c7d","url":"icon-512.png"},{"revision":"617108ed0f4b0f50b45ce588f8345d88","url":"icon-192.png"},{"revision":"54e99eab9f6b4d2889ec047a1d9ccabc","url":"apple-touch-icon.png"},{"revision":null,"url":"assets/yaml-DijMHRDA.js"},{"revision":null,"url":"assets/yaml-DDA_XMNu.js"},{"revision":null,"url":"assets/xml-WY0zc4PG.js"},{"revision":null,"url":"assets/xml-DuKfbPI6.js"},{"revision":null,"url":"assets/useNow-jxdoOC_1.js"},{"revision":null,"url":"assets/typescript-j_1H8WHN.js"},{"revision":null,"url":"assets/typescript-Bb1J8qyy.js"},{"revision":null,"url":"assets/tsx-CGosfAUg.js"},{"revision":null,"url":"assets/tsx-BOvsFOI6.js"},{"revision":null,"url":"assets/trash-C6X2OLrI.js"},{"revision":null,"url":"assets/toml-CcmNWLt0.js"},{"revision":null,"url":"assets/terminal-login-BJxV78au.js"},{"revision":null,"url":"assets/swift-CyEgAFGc.js"},{"revision":null,"url":"assets/states--geW2Ntl.js"},{"revision":null,"url":"assets/sql-CfM2IJm3.js"},{"revision":null,"url":"assets/sql-CNu3Or2W.js"},{"revision":null,"url":"assets/sliders-horizontal-DAoirila.js"},{"revision":null,"url":"assets/shellscript-CqHdAlCp.js"},{"revision":null,"url":"assets/shellscript-CVTB3cr6.js"},{"revision":null,"url":"assets/shared-CZ7fcu_B.js"},{"revision":null,"url":"assets/settings-D8T1esWq.js"},{"revision":null,"url":"assets/server-SxFxIScj.js"},{"revision":null,"url":"assets/send-BKjswHxB.js"},{"revision":null,"url":"assets/search-C6cn5WOo.js"},{"revision":null,"url":"assets/scss-8bKmll0B.js"},{"revision":null,"url":"assets/save-DEvZPWlS.js"},{"revision":null,"url":"assets/rust-DpiIf5JO.js"},{"revision":null,"url":"assets/ruby-Bx-U2qjP.js"},{"revision":null,"url":"assets/python-gzcpVVnB.js"},{"revision":null,"url":"assets/presence-05bJD5G3.js"},{"revision":null,"url":"assets/plus-BLP-wIYD.js"},{"revision":null,"url":"assets/play-CjoDg3ws.js"},{"revision":null,"url":"assets/pencil-DI8QbCN8.js"},{"revision":null,"url":"assets/now--XjJC37b.js"},{"revision":null,"url":"assets/more-BP5x45cs.js"},{"revision":null,"url":"assets/lua-fPRBWD-V.js"},{"revision":null,"url":"assets/lua-DjuecEsk.js"},{"revision":null,"url":"assets/logic-xb-QF00E.js"},{"revision":null,"url":"assets/link-2-CaMlUDRG.js"},{"revision":null,"url":"assets/key-round-VDbE9E4X.js"},{"revision":null,"url":"assets/jsx-runtime-D13aM9HY.js"},{"revision":null,"url":"assets/jsx-D3KKoC5L.js"},{"revision":null,"url":"assets/jsx-C4yDKi0A.js"},{"revision":null,"url":"assets/jsonc-CYpm1nAK.js"},{"revision":null,"url":"assets/json-qhed-kSA.js"},{"revision":null,"url":"assets/javascript-CpIGwZ_Y.js"},{"revision":null,"url":"assets/javascript-BzbQS41l.js"},{"revision":null,"url":"assets/java-_ATy9zCa.js"},{"revision":null,"url":"assets/java-BtIQNnN0.js"},{"revision":null,"url":"assets/index-vIzH1m8u.js"},{"revision":null,"url":"assets/index-DvRcMGEe.css"},{"revision":null,"url":"assets/html-BWDvXlHg.js"},{"revision":null,"url":"assets/html-BMn1ogTm.js"},{"revision":null,"url":"assets/hand-UPoHamrn.js"},{"revision":null,"url":"assets/go-rLFTqkRN.js"},{"revision":null,"url":"assets/github-light-EUqPIrTm.js"},{"revision":null,"url":"assets/github-dark-C-LZuMrd.js"},{"revision":null,"url":"assets/external-link-3jjTxo92.js"},{"revision":null,"url":"assets/enroll-DUDpbJoB.js"},{"revision":null,"url":"assets/dockerfile-IyjqRm3v.js"},{"revision":null,"url":"assets/dist-BE_V9dwJ.js"},{"revision":null,"url":"assets/diff-woXpYk--.js"},{"revision":null,"url":"assets/describe-DnvH6_fl.js"},{"revision":null,"url":"assets/css-DgaLhXQH.js"},{"revision":null,"url":"assets/css-BGIxQoYs.js"},{"revision":null,"url":"assets/cpp-DzjeI0uH.js"},{"revision":null,"url":"assets/cpp-Cts1PyIS.js"},{"revision":null,"url":"assets/copy-oWgGHmkS.js"},{"revision":null,"url":"assets/code-DKLO8bzz.js"},{"revision":null,"url":"assets/chevron-right-evVLS6hq.js"},{"revision":null,"url":"assets/calendar-clock-B8zE4JsX.js"},{"revision":null,"url":"assets/c-SSSlmE39.js"},{"revision":null,"url":"assets/c-Cz4nF6n_.js"},{"revision":null,"url":"assets/board-BrLaJwLJ.js"},{"revision":null,"url":"assets/automations-DiXKRcnE.js"},{"revision":null,"url":"assets/attention-Bya8XHKI.js"},{"revision":null,"url":"assets/arrow-left-C6YWM6y6.js"},{"revision":null,"url":"assets/TextArea-BYr88SnV.js"},{"revision":null,"url":"assets/Tabs-ByiPklAw.js"},{"revision":null,"url":"assets/SegmentedControl-D-2BCZzd.js"},{"revision":null,"url":"assets/Menu-BDt1bxwz.js"},{"revision":null,"url":"assets/InteractionCard-CWxyDv81.js"},{"revision":null,"url":"assets/Badge-BiDp7NKI.js"},{"revision":null,"url":"assets/AutomationView-BIW_pO0M.js"},{"revision":"fdc04d15259be148613cba0a9a8ee216","url":"manifest.webmanifest"}]),H(),self.addEventListener(`install`,()=>{self.skipWaiting()}),self.addEventListener(`activate`,e=>{e.waitUntil(self.clients.claim())});var K=/^\/(api|ws|adapter-frames|healthz|readyz)(\/|$)/;self.addEventListener(`fetch`,e=>{let t=e.request;if(t.mode!==`navigate`)return;let n=new URL(t.url);n.origin!==self.location.origin||K.test(n.pathname)||e.respondWith(fetch(t).catch(async()=>await U(`/index.html`)??Response.error()))});function q(e){if(!e.data)return null;try{let t=e.data.json();if(t&&(t.type===`show`||t.type===`clear`))return t}catch{return{type:`show`,title:`Switchyard`,body:e.data.text(),tag:`switchyard`,url:`/attention`,renotify:!1}}return null}self.addEventListener(`push`,e=>{let t=q(e);if(!t)return;if(t.type===`clear`){e.waitUntil(self.registration.getNotifications({tag:t.tag}).then(e=>{for(let t of e)t.close()}));return}let n={body:t.body,tag:t.tag,data:{url:t.url},renotify:t.renotify,icon:`/icon-192.png`,badge:`/icon-192.png`};e.waitUntil(self.registration.showNotification(t.title,n))}),self.addEventListener(`notificationclick`,e=>{e.notification.close();let t=e.notification.data?.url??`/`,n=new URL(t,self.location.origin).href;e.waitUntil((async()=>{let e=(await self.clients.matchAll({type:`window`,includeUncontrolled:!0})).filter(e=>new URL(e.url).origin===self.location.origin),t=e.find(e=>e.url===n)??e[0];if(t){let e=await t.focus();e.url!==n&&e.postMessage({type:`navigate`,url:n})}else await self.clients.openWindow(n)})())});
1
+ try{self[`workbox:core:7.4.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.4.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.4.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.4.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&(t.origin===location.origin||n.index===0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}var B=`-precache-`,V=async(e,t=B)=>{let n=(await self.caches.keys()).filter(n=>n.includes(t)&&n.includes(self.registration.scope)&&n!==e);return await Promise.all(n.map(e=>self.caches.delete(e))),n};function H(){self.addEventListener(`activate`,(e=>{let t=a.getPrecacheName();e.waitUntil(V(t).then(e=>{}))}))}function U(e){return O().matchPrecache(e)}function W(e){O().precache(e)}function G(e,t){W(e),z(t)}var K={type:`show`,title:`Switchyard`,body:`Something changed. Open Switchyard to see it.`,tag:`switchyard`,url:`/attention`,renotify:!1},q=e=>typeof e==`string`;function J(e){if(!e)return K;let t;try{t=e.json()}catch{let t=``;try{t=e.text()}catch{}return t?{...K,body:t}:K}return t?.type===`clear`&&q(t.tag)?{type:`clear`,tag:t.tag}:t?.type===`show`&&q(t.title)&&q(t.body)&&q(t.tag)&&q(t.url)?{type:`show`,title:t.title,body:t.body,tag:t.tag,url:t.url,renotify:t.renotify===!0}:K}function Y(e,t){let n=t?.data?.url;return{title:`Resolved`,options:{body:t?.title?`${t.title} no longer needs you.`:`A Switchyard item no longer needs you.`,tag:e,silent:!0,renotify:!1,data:{url:q(n)?n:`/attention`,resolved:!0}}}}G([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"13547519d4d57ed00992ea3ce674898f","url":"maskable-512.png"},{"revision":"4308fa8f2d00e6136f766b0c602ed347","url":"index.html"},{"revision":"a2ab6346edf4afa0d3e92efa4eaffda0","url":"icon.svg"},{"revision":"5f6750eb3eac94f14e2c13ebc966b744","url":"icon-512.png"},{"revision":"1d18b7c0ba74b49ffa7c388dd59f33cf","url":"icon-192.png"},{"revision":"d35ba918f4293158ea83e9628573689a","url":"apple-touch-icon.png"},{"revision":null,"url":"assets/yaml-DijMHRDA.js"},{"revision":null,"url":"assets/yaml-DDA_XMNu.js"},{"revision":null,"url":"assets/xml-WY0zc4PG.js"},{"revision":null,"url":"assets/xml-DuKfbPI6.js"},{"revision":null,"url":"assets/useResource-CDGSq2At.js"},{"revision":null,"url":"assets/useNow-Dj7oEiwn.js"},{"revision":null,"url":"assets/useBackTo-BIrCq3W2.js"},{"revision":null,"url":"assets/typescript-j_1H8WHN.js"},{"revision":null,"url":"assets/typescript-Bb1J8qyy.js"},{"revision":null,"url":"assets/tsx-CGosfAUg.js"},{"revision":null,"url":"assets/tsx-BOvsFOI6.js"},{"revision":null,"url":"assets/toml-CcmNWLt0.js"},{"revision":null,"url":"assets/terminal-login-S5CAd5xA.js"},{"revision":null,"url":"assets/terminal-BOV_MXPZ.js"},{"revision":null,"url":"assets/swift-CyEgAFGc.js"},{"revision":null,"url":"assets/states-ZhrxQa3K.js"},{"revision":null,"url":"assets/sql-CfM2IJm3.js"},{"revision":null,"url":"assets/sql-CNu3Or2W.js"},{"revision":null,"url":"assets/shellscript-CqHdAlCp.js"},{"revision":null,"url":"assets/shellscript-CVTB3cr6.js"},{"revision":null,"url":"assets/settings-DyUu0tJM.js"},{"revision":null,"url":"assets/server-BqZ-w6M8.js"},{"revision":null,"url":"assets/search-C6cn5WOo.js"},{"revision":null,"url":"assets/scss-8bKmll0B.js"},{"revision":null,"url":"assets/rust-DpiIf5JO.js"},{"revision":null,"url":"assets/ruby-Bx-U2qjP.js"},{"revision":null,"url":"assets/repo-XzzzEI0d.js"},{"revision":null,"url":"assets/queue-DUg1rS8t.js"},{"revision":null,"url":"assets/python-gzcpVVnB.js"},{"revision":null,"url":"assets/presence-05bJD5G3.js"},{"revision":null,"url":"assets/play-CjoDg3ws.js"},{"revision":null,"url":"assets/pencil-DI8QbCN8.js"},{"revision":null,"url":"assets/more-DQR5uu1c.js"},{"revision":null,"url":"assets/lua-fPRBWD-V.js"},{"revision":null,"url":"assets/lua-DjuecEsk.js"},{"revision":null,"url":"assets/logic-B46fwD-8.js"},{"revision":null,"url":"assets/link-2-CaMlUDRG.js"},{"revision":null,"url":"assets/key-round-VDbE9E4X.js"},{"revision":null,"url":"assets/jsx-runtime-D13aM9HY.js"},{"revision":null,"url":"assets/jsx-D3KKoC5L.js"},{"revision":null,"url":"assets/jsx-C4yDKi0A.js"},{"revision":null,"url":"assets/jsonc-CYpm1nAK.js"},{"revision":null,"url":"assets/json-qhed-kSA.js"},{"revision":null,"url":"assets/javascript-CpIGwZ_Y.js"},{"revision":null,"url":"assets/javascript-BzbQS41l.js"},{"revision":null,"url":"assets/java-_ATy9zCa.js"},{"revision":null,"url":"assets/java-BtIQNnN0.js"},{"revision":null,"url":"assets/index-hxvDvCS7.js"},{"revision":null,"url":"assets/index-B3F7WcYf.css"},{"revision":null,"url":"assets/html-BWDvXlHg.js"},{"revision":null,"url":"assets/html-BMn1ogTm.js"},{"revision":null,"url":"assets/hand-UPoHamrn.js"},{"revision":null,"url":"assets/go-rLFTqkRN.js"},{"revision":null,"url":"assets/github-light-EUqPIrTm.js"},{"revision":null,"url":"assets/github-dark-C-LZuMrd.js"},{"revision":null,"url":"assets/external-link-3jjTxo92.js"},{"revision":null,"url":"assets/enroll-DwT7AcuS.js"},{"revision":null,"url":"assets/dockerfile-IyjqRm3v.js"},{"revision":null,"url":"assets/diff-woXpYk--.js"},{"revision":null,"url":"assets/describe-D6KLGKWa.js"},{"revision":null,"url":"assets/css-DgaLhXQH.js"},{"revision":null,"url":"assets/css-BGIxQoYs.js"},{"revision":null,"url":"assets/cpp-DzjeI0uH.js"},{"revision":null,"url":"assets/cpp-Cts1PyIS.js"},{"revision":null,"url":"assets/code-BKroYJmR.js"},{"revision":null,"url":"assets/chevron-right-evVLS6hq.js"},{"revision":null,"url":"assets/calendar-clock-B8zE4JsX.js"},{"revision":null,"url":"assets/c-SSSlmE39.js"},{"revision":null,"url":"assets/c-Cz4nF6n_.js"},{"revision":null,"url":"assets/board-B8X7TYYR.js"},{"revision":null,"url":"assets/automations-Cw5Gacgm.js"},{"revision":null,"url":"assets/attention-V86Gye3I.js"},{"revision":null,"url":"assets/arrow-up-Dj-VTKx4.js"},{"revision":null,"url":"assets/arrow-down-C-iLrN8I.js"},{"revision":null,"url":"assets/TextLink-OzzyP2-p.js"},{"revision":null,"url":"assets/TextArea-CKybrQyn.js"},{"revision":null,"url":"assets/Tabs-BNuL3_Et.js"},{"revision":null,"url":"assets/Switch-DBfzmqkm.js"},{"revision":null,"url":"assets/Select-Cfql4Nwu.js"},{"revision":null,"url":"assets/SegmentedControl-C_hEVQMB.js"},{"revision":null,"url":"assets/Priority-CHmzfoHg.js"},{"revision":null,"url":"assets/Overlay-DUQwh6_b.js"},{"revision":null,"url":"assets/Menu-BfOszNC4.js"},{"revision":null,"url":"assets/InteractionCard-DF1EcSpm.js"},{"revision":null,"url":"assets/Field-D-Ty7fKT.js"},{"revision":null,"url":"assets/DangerZone-DfYlxDC1.js"},{"revision":null,"url":"assets/Copy-B6XSAIUd.js"},{"revision":null,"url":"assets/Checkbox-D6tRfEeI.js"},{"revision":null,"url":"assets/AutomationView-D7Syv1En.js"},{"revision":"a3eb00302b8325cfe5c4836ff54f4b4a","url":"manifest.webmanifest"}]),H(),self.addEventListener(`install`,()=>{self.skipWaiting()}),self.addEventListener(`activate`,e=>{e.waitUntil(self.clients.claim())});var X=/^\/(api|ws|adapter-frames|healthz|readyz)(\/|$)/;self.addEventListener(`fetch`,e=>{let t=e.request;if(t.mode!==`navigate`)return;let n=new URL(t.url);n.origin!==self.location.origin||X.test(n.pathname)||e.respondWith(fetch(t).catch(async()=>await U(`/index.html`)??Response.error()))});var Z=`/icon-192.png`;self.addEventListener(`push`,e=>{let t=J(e.data);e.waitUntil(t.type===`clear`?Q(t.tag):self.registration.showNotification(t.title,{body:t.body,tag:t.tag,data:{url:t.url},renotify:t.renotify,icon:Z,badge:Z}))});async function Q(e){let t=await self.registration.getNotifications({tag:e});if((await self.clients.matchAll({type:`window`,includeUncontrolled:!0})).some(e=>e.visibilityState===`visible`)){for(let e of t)e.close();return}let n=Y(e,t[0]?{title:t[0].title,data:t[0].data}:null);await self.registration.showNotification(n.title,{...n.options,icon:Z,badge:Z})}self.addEventListener(`notificationclick`,e=>{e.notification.close();let t=e.notification.data?.url??`/`,n=new URL(t,self.location.origin).href;e.waitUntil((async()=>{let e=(await self.clients.matchAll({type:`window`,includeUncontrolled:!0})).filter(e=>new URL(e.url).origin===self.location.origin),t=e.find(e=>e.url===n)??e[0];if(t)try{let e=await t.focus()??t;e.url!==n&&e.postMessage({type:`navigate`,url:n});return}catch{}await self.clients.openWindow(n)})())});
2
2
  //# sourceMappingURL=sw.js.map