@polderlabs/bizar 5.1.0 → 5.2.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 (50) hide show
  1. package/bizar-dash/dist/assets/{MobileChat-BVojK0n5.js → MobileChat-TCputYzr.js} +1 -1
  2. package/bizar-dash/dist/assets/{MobileChat-BVojK0n5.js.map → MobileChat-TCputYzr.js.map} +1 -1
  3. package/bizar-dash/dist/assets/{MobileSettings-C85ApWKZ.js → MobileSettings-BxcbL5XT.js} +1 -1
  4. package/bizar-dash/dist/assets/{MobileSettings-C85ApWKZ.js.map → MobileSettings-BxcbL5XT.js.map} +1 -1
  5. package/bizar-dash/dist/assets/{icons-Clz0NR6Y.js → icons-DRDXfbBP.js} +154 -134
  6. package/bizar-dash/dist/assets/icons-DRDXfbBP.js.map +1 -0
  7. package/bizar-dash/dist/assets/main-D5Ditnrd.js +19 -0
  8. package/bizar-dash/dist/assets/main-D5Ditnrd.js.map +1 -0
  9. package/bizar-dash/dist/assets/{main-DTkNlLrw.css → main-xFpWMd32.css} +1 -1
  10. package/bizar-dash/dist/assets/{mobile-D2pc-iNh.js → mobile--17fkfrl.js} +1 -1
  11. package/bizar-dash/dist/assets/{mobile-D2pc-iNh.js.map → mobile--17fkfrl.js.map} +1 -1
  12. package/bizar-dash/dist/assets/{mobile-IaZ47uKC.js → mobile-j3rOZK6v.js} +2 -2
  13. package/bizar-dash/dist/assets/{mobile-IaZ47uKC.js.map → mobile-j3rOZK6v.js.map} +1 -1
  14. package/bizar-dash/dist/assets/{useSlashCommands-DjEwHl4n.js → useSlashCommands-BG-DhEck.js} +2 -2
  15. package/bizar-dash/dist/assets/{useSlashCommands-DjEwHl4n.js.map → useSlashCommands-BG-DhEck.js.map} +1 -1
  16. package/bizar-dash/dist/index.html +5 -5
  17. package/bizar-dash/dist/mobile.html +3 -3
  18. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  19. package/bizar-dash/src/server/api.mjs +4 -0
  20. package/bizar-dash/src/server/routes/plugins.mjs +11 -3
  21. package/bizar-dash/src/server/routes/tailscale.mjs +46 -0
  22. package/bizar-dash/src/server/routes/voice.mjs +42 -6
  23. package/bizar-dash/src/server/server.mjs +13 -0
  24. package/bizar-dash/src/server/voice-store.mjs +27 -0
  25. package/bizar-dash/src/server/workers/transcription-worker.mjs +213 -0
  26. package/bizar-dash/src/web/App.tsx +9 -0
  27. package/bizar-dash/src/web/components/EvalDiff.tsx +157 -0
  28. package/bizar-dash/src/web/components/EvalRunCard.tsx +78 -0
  29. package/bizar-dash/src/web/components/PluginCard.tsx +64 -0
  30. package/bizar-dash/src/web/components/PluginPermissions.tsx +36 -0
  31. package/bizar-dash/src/web/components/TailscaleSettings.tsx +161 -0
  32. package/bizar-dash/src/web/components/Toggle.tsx +31 -0
  33. package/bizar-dash/src/web/components/Topbar.tsx +6 -0
  34. package/bizar-dash/src/web/styles/main.css +545 -0
  35. package/bizar-dash/src/web/views/Eval.tsx +172 -0
  36. package/bizar-dash/src/web/views/EvalReport.tsx +349 -0
  37. package/bizar-dash/src/web/views/Plugins.tsx +128 -0
  38. package/bizar-dash/src/web/views/Settings.tsx +2 -0
  39. package/bizar-dash/tests/cli-tailscale.test.mjs +113 -0
  40. package/bizar-dash/tests/components/plugin-permissions.test.tsx +95 -0
  41. package/bizar-dash/tests/eval-web-ui.test.tsx +220 -0
  42. package/bizar-dash/tests/voice-transcribe-worker.test.mjs +343 -0
  43. package/cli/bin.mjs +14 -0
  44. package/cli/commands/dash.mjs +19 -1
  45. package/cli/commands/service.mjs +7 -0
  46. package/cli/commands/tailscale.mjs +251 -0
  47. package/package.json +1 -1
  48. package/bizar-dash/dist/assets/icons-Clz0NR6Y.js.map +0 -1
  49. package/bizar-dash/dist/assets/main-8feQWXiF.js +0 -19
  50. package/bizar-dash/dist/assets/main-8feQWXiF.js.map +0 -1
@@ -1 +1 @@
1
- import{j as n,r as t}from"./react-vendor-Dn4wqh4Z.js";import{C as N,u as T,a as k,b as R,c as E,d as F}from"./useSlashCommands-DjEwHl4n.js";import"./icons-Clz0NR6Y.js";import"./mobile-IaZ47uKC.js";import"./markdown-C6mXtQxD.js";import"./vendor-CeHGtduv.js";function $(o){const{activeSource:c}=o;return n.jsx("div",{className:`chat-composer-wrap chat-composer-source-${c??"none"} legacy`,children:n.jsx("div",{className:"chat-composer-pill",children:n.jsx(N,{...o})})})}function A({snapshot:o,settings:c,setActiveTab:g,initialTaskId:j,onClearTaskId:z}){const i=T(),s=k(o,c,j??"");t.useEffect(()=>{s.setToast({error:e=>i.error(e),success:e=>i.success(e),info:e=>i.info(e),warning:e=>i.warning(e)})},[s,i]);const[r,l]=t.useState(""),[f,x]=t.useState(c.defaultAgent||"odin"),[p,C]=t.useState(c.defaultModel||""),[h,v]=t.useState([]),u=t.useRef(null),{suggestions:y,setQuery:m}=R(o);t.useEffect(()=>{m(r)},[r,m]);const P=()=>{var e;return(e=u.current)==null?void 0:e.click()},w=e=>{const d=e.target.files;if(!d)return;const S=[];for(let a=0;a<d.length;a++)S.push(d[a].name);v(a=>{const O=S.filter(M=>!a.includes(M));return[...a,...O]}),u.current&&(u.current.value="")},I=async()=>{const e=r.trim();if(!e)return;l(""),m(""),(await s.onSend(e,f,p,h)).ok&&s.jumpToLatest()};return n.jsxs("div",{className:"chat-shell",children:[n.jsx(E,{activeProject:o.activeProject,sessionCount:s.sessions.length,sessionsOpen:!1,infoOpen:!1,onToggleSessions:()=>{},onToggleInfo:()=>{},onOpenOverview:()=>g==null?void 0:g("overview")}),n.jsx("div",{className:"chat-body",children:n.jsxs("main",{className:"chat-main",children:[n.jsx(F,{messages:s.activeSource==="opencode"?s.opencodeMessages:s.bizarMessages,loading:s.loading,activeProject:o.activeProject,sessionId:s.activeSource==="opencode"?s.activeOpencodeSessionId??s.sessionId:s.sessionId,pinned:s.pinned,activeSource:s.activeSource,onPickSuggestion:e=>l(e),onCopy:e=>s.copyMessage(e),onDelete:()=>{},onTogglePin:s.togglePin,onRegenerate:s.onRegenerate}),n.jsx($,{agent:f,setAgent:x,model:p,setModel:C,text:r,setText:l,sending:s.sending,activeSource:s.activeSource,onSend:I,attachments:h,setAttachments:v,suggestions:y,onPickSuggestion:e=>l(`${e.split(" ")[0]} `),agents:o.agents||[],onAttach:P,sessionsOpen:!1,infoOpen:!1}),n.jsx("input",{ref:u,type:"file",multiple:!0,style:{display:"none"},onChange:w})]})})]})}export{A as MobileChat};
1
+ import{j as n,r as t}from"./react-vendor-Dn4wqh4Z.js";import{C as N,u as T,a as k,b as R,c as E,d as F}from"./useSlashCommands-BG-DhEck.js";import"./icons-DRDXfbBP.js";import"./mobile-j3rOZK6v.js";import"./markdown-C6mXtQxD.js";import"./vendor-CeHGtduv.js";function $(o){const{activeSource:c}=o;return n.jsx("div",{className:`chat-composer-wrap chat-composer-source-${c??"none"} legacy`,children:n.jsx("div",{className:"chat-composer-pill",children:n.jsx(N,{...o})})})}function A({snapshot:o,settings:c,setActiveTab:g,initialTaskId:j,onClearTaskId:z}){const i=T(),s=k(o,c,j??"");t.useEffect(()=>{s.setToast({error:e=>i.error(e),success:e=>i.success(e),info:e=>i.info(e),warning:e=>i.warning(e)})},[s,i]);const[r,l]=t.useState(""),[f,x]=t.useState(c.defaultAgent||"odin"),[p,C]=t.useState(c.defaultModel||""),[h,v]=t.useState([]),u=t.useRef(null),{suggestions:y,setQuery:m}=R(o);t.useEffect(()=>{m(r)},[r,m]);const P=()=>{var e;return(e=u.current)==null?void 0:e.click()},w=e=>{const d=e.target.files;if(!d)return;const S=[];for(let a=0;a<d.length;a++)S.push(d[a].name);v(a=>{const O=S.filter(M=>!a.includes(M));return[...a,...O]}),u.current&&(u.current.value="")},I=async()=>{const e=r.trim();if(!e)return;l(""),m(""),(await s.onSend(e,f,p,h)).ok&&s.jumpToLatest()};return n.jsxs("div",{className:"chat-shell",children:[n.jsx(E,{activeProject:o.activeProject,sessionCount:s.sessions.length,sessionsOpen:!1,infoOpen:!1,onToggleSessions:()=>{},onToggleInfo:()=>{},onOpenOverview:()=>g==null?void 0:g("overview")}),n.jsx("div",{className:"chat-body",children:n.jsxs("main",{className:"chat-main",children:[n.jsx(F,{messages:s.activeSource==="opencode"?s.opencodeMessages:s.bizarMessages,loading:s.loading,activeProject:o.activeProject,sessionId:s.activeSource==="opencode"?s.activeOpencodeSessionId??s.sessionId:s.sessionId,pinned:s.pinned,activeSource:s.activeSource,onPickSuggestion:e=>l(e),onCopy:e=>s.copyMessage(e),onDelete:()=>{},onTogglePin:s.togglePin,onRegenerate:s.onRegenerate}),n.jsx($,{agent:f,setAgent:x,model:p,setModel:C,text:r,setText:l,sending:s.sending,activeSource:s.activeSource,onSend:I,attachments:h,setAttachments:v,suggestions:y,onPickSuggestion:e=>l(`${e.split(" ")[0]} `),agents:o.agents||[],onAttach:P,sessionsOpen:!1,infoOpen:!1}),n.jsx("input",{ref:u,type:"file",multiple:!0,style:{display:"none"},onChange:w})]})})]})}export{A as MobileChat};
@@ -1 +1 @@
1
- {"version":3,"file":"MobileChat-BVojK0n5.js","sources":["../../src/web/components/chat/FloatingComposer.tsx","../../src/web/mobile/MobileChat.tsx"],"sourcesContent":["// src/components/chat/FloatingComposer.tsx — sticky bottom wrapper for the composer pill.\n\nimport { Composer } from './Composer';\n\ninterface Props {\n agent: string;\n setAgent: (a: string) => void;\n model: string;\n setModel: (m: string) => void;\n text: string;\n setText: (t: string) => void;\n sending: boolean;\n onSend: () => void;\n attachments: string[];\n setAttachments: (a: string[] | ((prev: string[]) => string[])) => void;\n suggestions: Array<{ cmd: string; desc: string }>;\n onPickSuggestion: (cmd: string) => void;\n agents: Array<{ name: string }>;\n onAttach: () => void;\n sessionsOpen: boolean;\n infoOpen: boolean;\n /** Which stream will receive the next message — propagates the\n * pill border color and a small \"→ opencode\" hint. */\n activeSource?: 'bizar' | 'opencode' | null;\n}\n\nexport function FloatingComposer(props: Props) {\n const { activeSource } = props;\n return (\n <div\n className={`chat-composer-wrap chat-composer-source-${activeSource ?? 'none'} legacy`}\n >\n <div className=\"chat-composer-pill\">\n <Composer {...props} />\n </div>\n </div>\n );\n}","// src/web/mobile/MobileChat.tsx — mobile chat UI without info/sessions sidebars.\n// No OCR capture, no clipper, no sessions panel — pure chat thread.\nimport { useEffect, useRef, useState } from 'react';\nimport { ChatTopBar } from '../components/chat/ChatTopBar';\nimport { ChatThread } from '../components/chat/ChatThread';\nimport { FloatingComposer } from '../components/chat/FloatingComposer';\nimport { useChat } from '../components/chat/useChat';\nimport { useSlashCommands } from '../components/chat/useSlashCommands';\nimport { useToast } from '../components/Toast';\nimport type { Snapshot, Settings } from '../lib/types';\n\ninterface Props {\n snapshot: Snapshot;\n settings: Settings;\n setActiveTab?: (id: string) => void;\n initialTaskId?: string | null;\n onClearTaskId?: () => void;\n}\n\nexport function MobileChat({\n snapshot,\n settings,\n setActiveTab,\n initialTaskId,\n onClearTaskId,\n}: Props) {\n const toast = useToast();\n const chat = useChat(snapshot, settings, initialTaskId ?? '');\n useEffect(() => {\n chat.setToast({\n error: (msg: string) => toast.error(msg),\n success: (msg: string) => toast.success(msg),\n info: (msg: string) => toast.info(msg),\n warning: (msg: string) => toast.warning(msg),\n });\n }, [chat, toast]);\n\n const [text, setText] = useState('');\n const [agent, setAgent] = useState(settings.defaultAgent || 'odin');\n const [model, setModel] = useState(settings.defaultModel || '');\n const [attachments, setAttachments] = useState<string[]>([]);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const { suggestions, setQuery } = useSlashCommands(snapshot);\n useEffect(() => {\n setQuery(text);\n }, [text, setQuery]);\n\n const onAttach = () => fileInputRef.current?.click();\n const onFiles = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n if (!files) return;\n const next: string[] = [];\n for (let i = 0; i < files.length; i++) next.push(files[i].name);\n setAttachments((cur) => {\n const newNames = next.filter((n) => !cur.includes(n));\n return [...cur, ...newNames];\n });\n if (fileInputRef.current) fileInputRef.current.value = '';\n };\n\n const handleSend = async () => {\n const msg = text.trim();\n if (!msg) return;\n setText('');\n setQuery('');\n const result = await chat.onSend(msg, agent, model, attachments);\n if (result.ok) chat.jumpToLatest();\n };\n\n return (\n <div className=\"chat-shell\">\n <ChatTopBar\n activeProject={snapshot.activeProject}\n sessionCount={chat.sessions.length}\n sessionsOpen={false}\n infoOpen={false}\n onToggleSessions={() => undefined}\n onToggleInfo={() => undefined}\n onOpenOverview={() => setActiveTab?.('overview')}\n />\n <div className=\"chat-body\">\n <main className=\"chat-main\">\n <ChatThread\n messages={\n chat.activeSource === 'opencode'\n ? chat.opencodeMessages\n : chat.bizarMessages\n }\n loading={chat.loading}\n activeProject={snapshot.activeProject}\n sessionId={\n chat.activeSource === 'opencode'\n ? chat.activeOpencodeSessionId ?? chat.sessionId\n : chat.sessionId\n }\n pinned={chat.pinned}\n activeSource={chat.activeSource}\n onPickSuggestion={(t) => setText(t)}\n onCopy={(m) =>\n chat.copyMessage(m as Parameters<typeof chat.copyMessage>[0])\n }\n onDelete={() => undefined}\n onTogglePin={chat.togglePin}\n onRegenerate={chat.onRegenerate}\n />\n <FloatingComposer\n agent={agent}\n setAgent={setAgent}\n model={model}\n setModel={setModel}\n text={text}\n setText={setText}\n sending={chat.sending}\n activeSource={chat.activeSource}\n onSend={handleSend}\n attachments={attachments}\n setAttachments={setAttachments}\n suggestions={suggestions}\n onPickSuggestion={(cmd) => setText(`${cmd.split(' ')[0]} `)}\n agents={snapshot.agents || []}\n onAttach={onAttach}\n sessionsOpen={false}\n infoOpen={false}\n />\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n style={{ display: 'none' }}\n onChange={onFiles}\n />\n </main>\n </div>\n </div>\n );\n}\n"],"names":["FloatingComposer","props","activeSource","jsx","Composer","MobileChat","snapshot","settings","setActiveTab","initialTaskId","onClearTaskId","toast","useToast","chat","useChat","useEffect","msg","text","setText","useState","agent","setAgent","model","setModel","attachments","setAttachments","fileInputRef","useRef","suggestions","setQuery","useSlashCommands","onAttach","_a","onFiles","files","next","i","cur","newNames","n","handleSend","jsxs","ChatTopBar","ChatThread","t","m","cmd"],"mappings":"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"}
1
+ {"version":3,"file":"MobileChat-TCputYzr.js","sources":["../../src/web/components/chat/FloatingComposer.tsx","../../src/web/mobile/MobileChat.tsx"],"sourcesContent":["// src/components/chat/FloatingComposer.tsx — sticky bottom wrapper for the composer pill.\n\nimport { Composer } from './Composer';\n\ninterface Props {\n agent: string;\n setAgent: (a: string) => void;\n model: string;\n setModel: (m: string) => void;\n text: string;\n setText: (t: string) => void;\n sending: boolean;\n onSend: () => void;\n attachments: string[];\n setAttachments: (a: string[] | ((prev: string[]) => string[])) => void;\n suggestions: Array<{ cmd: string; desc: string }>;\n onPickSuggestion: (cmd: string) => void;\n agents: Array<{ name: string }>;\n onAttach: () => void;\n sessionsOpen: boolean;\n infoOpen: boolean;\n /** Which stream will receive the next message — propagates the\n * pill border color and a small \"→ opencode\" hint. */\n activeSource?: 'bizar' | 'opencode' | null;\n}\n\nexport function FloatingComposer(props: Props) {\n const { activeSource } = props;\n return (\n <div\n className={`chat-composer-wrap chat-composer-source-${activeSource ?? 'none'} legacy`}\n >\n <div className=\"chat-composer-pill\">\n <Composer {...props} />\n </div>\n </div>\n );\n}","// src/web/mobile/MobileChat.tsx — mobile chat UI without info/sessions sidebars.\n// No OCR capture, no clipper, no sessions panel — pure chat thread.\nimport { useEffect, useRef, useState } from 'react';\nimport { ChatTopBar } from '../components/chat/ChatTopBar';\nimport { ChatThread } from '../components/chat/ChatThread';\nimport { FloatingComposer } from '../components/chat/FloatingComposer';\nimport { useChat } from '../components/chat/useChat';\nimport { useSlashCommands } from '../components/chat/useSlashCommands';\nimport { useToast } from '../components/Toast';\nimport type { Snapshot, Settings } from '../lib/types';\n\ninterface Props {\n snapshot: Snapshot;\n settings: Settings;\n setActiveTab?: (id: string) => void;\n initialTaskId?: string | null;\n onClearTaskId?: () => void;\n}\n\nexport function MobileChat({\n snapshot,\n settings,\n setActiveTab,\n initialTaskId,\n onClearTaskId,\n}: Props) {\n const toast = useToast();\n const chat = useChat(snapshot, settings, initialTaskId ?? '');\n useEffect(() => {\n chat.setToast({\n error: (msg: string) => toast.error(msg),\n success: (msg: string) => toast.success(msg),\n info: (msg: string) => toast.info(msg),\n warning: (msg: string) => toast.warning(msg),\n });\n }, [chat, toast]);\n\n const [text, setText] = useState('');\n const [agent, setAgent] = useState(settings.defaultAgent || 'odin');\n const [model, setModel] = useState(settings.defaultModel || '');\n const [attachments, setAttachments] = useState<string[]>([]);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const { suggestions, setQuery } = useSlashCommands(snapshot);\n useEffect(() => {\n setQuery(text);\n }, [text, setQuery]);\n\n const onAttach = () => fileInputRef.current?.click();\n const onFiles = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n if (!files) return;\n const next: string[] = [];\n for (let i = 0; i < files.length; i++) next.push(files[i].name);\n setAttachments((cur) => {\n const newNames = next.filter((n) => !cur.includes(n));\n return [...cur, ...newNames];\n });\n if (fileInputRef.current) fileInputRef.current.value = '';\n };\n\n const handleSend = async () => {\n const msg = text.trim();\n if (!msg) return;\n setText('');\n setQuery('');\n const result = await chat.onSend(msg, agent, model, attachments);\n if (result.ok) chat.jumpToLatest();\n };\n\n return (\n <div className=\"chat-shell\">\n <ChatTopBar\n activeProject={snapshot.activeProject}\n sessionCount={chat.sessions.length}\n sessionsOpen={false}\n infoOpen={false}\n onToggleSessions={() => undefined}\n onToggleInfo={() => undefined}\n onOpenOverview={() => setActiveTab?.('overview')}\n />\n <div className=\"chat-body\">\n <main className=\"chat-main\">\n <ChatThread\n messages={\n chat.activeSource === 'opencode'\n ? chat.opencodeMessages\n : chat.bizarMessages\n }\n loading={chat.loading}\n activeProject={snapshot.activeProject}\n sessionId={\n chat.activeSource === 'opencode'\n ? chat.activeOpencodeSessionId ?? chat.sessionId\n : chat.sessionId\n }\n pinned={chat.pinned}\n activeSource={chat.activeSource}\n onPickSuggestion={(t) => setText(t)}\n onCopy={(m) =>\n chat.copyMessage(m as Parameters<typeof chat.copyMessage>[0])\n }\n onDelete={() => undefined}\n onTogglePin={chat.togglePin}\n onRegenerate={chat.onRegenerate}\n />\n <FloatingComposer\n agent={agent}\n setAgent={setAgent}\n model={model}\n setModel={setModel}\n text={text}\n setText={setText}\n sending={chat.sending}\n activeSource={chat.activeSource}\n onSend={handleSend}\n attachments={attachments}\n setAttachments={setAttachments}\n suggestions={suggestions}\n onPickSuggestion={(cmd) => setText(`${cmd.split(' ')[0]} `)}\n agents={snapshot.agents || []}\n onAttach={onAttach}\n sessionsOpen={false}\n infoOpen={false}\n />\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n style={{ display: 'none' }}\n onChange={onFiles}\n />\n </main>\n </div>\n </div>\n );\n}\n"],"names":["FloatingComposer","props","activeSource","jsx","Composer","MobileChat","snapshot","settings","setActiveTab","initialTaskId","onClearTaskId","toast","useToast","chat","useChat","useEffect","msg","text","setText","useState","agent","setAgent","model","setModel","attachments","setAttachments","fileInputRef","useRef","suggestions","setQuery","useSlashCommands","onAttach","_a","onFiles","files","next","i","cur","newNames","n","handleSend","jsxs","ChatTopBar","ChatThread","t","m","cmd"],"mappings":"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"}
@@ -1 +1 @@
1
- import{r as o,j as e}from"./react-vendor-Dn4wqh4Z.js";import{d,a as f,g as N}from"./mobile-IaZ47uKC.js";import{au as y,av as k,aw as S}from"./icons-Clz0NR6Y.js";const w=[{id:"dark",label:"Dark",Icon:y},{id:"light",label:"Light",Icon:k},{id:"system",label:"System",Icon:S}],C=[{name:"Purple",accent:"#8b5cf6"},{name:"Blue",accent:"#3b82f6"},{name:"Green",accent:"#10b981"},{name:"Orange",accent:"#f97316"},{name:"Red",accent:"#ef4444"},{name:"Pink",accent:"#ec4899"},{name:"Cyan",accent:"#06b6d4"},{name:"Mono",accent:"#6b7280"}];function D({settings:n,snapshot:a,onRefresh:u}){var g,x,j;const[t,m]=o.useState(n),[v,r]=o.useState(!1),[b,h]=o.useState(!1);o.useEffect(()=>{m(n),r(!1),n.theme&&d(n.theme)},[n]);const i=s=>{m(l=>{const c={...l,theme:{...l.theme,...s}};return N(c.theme),d(c.theme),c}),r(!0)},p=async()=>{h(!0);try{const s=await f.put("/settings",t);m(s.data),r(!1),N(s.data.theme),d(s.data.theme),u()}catch{}finally{h(!1)}};return e.jsxs("div",{className:"mobile-view",children:[v&&e.jsxs("div",{className:"mobile-settings-save-bar",children:[e.jsx("span",{children:"Unsaved changes"}),e.jsx("button",{type:"button",className:"mobile-btn",disabled:b,onClick:p,children:b?"Saving…":"Save"})]}),e.jsxs("section",{className:"mobile-section",children:[e.jsx("h3",{className:"mobile-section-title",children:"Appearance"}),e.jsxs("div",{className:"mobile-card",children:[e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Theme"}),e.jsx("div",{className:"mobile-theme-btns",children:w.map(({id:s,label:l,Icon:c})=>e.jsxs("button",{type:"button",className:`mobile-theme-btn ${t.theme.mode===s?"active":""}`,onClick:()=>i({mode:s}),children:[e.jsx(c,{size:14})," ",l]},s))})]}),e.jsxs("div",{className:"mobile-setting-row",style:{flexDirection:"column",alignItems:"flex-start",gap:8},children:[e.jsx("span",{className:"mobile-setting-label",children:"Accent color"}),e.jsx("div",{className:"mobile-accent-swatches",children:C.map(s=>e.jsx("button",{type:"button",className:`mobile-accent-swatch ${t.theme.accent===s.accent?"active":""}`,style:{background:s.accent},onClick:()=>i({accent:s.accent}),title:s.name},s.name))})]}),e.jsxs("div",{className:"mobile-setting-row",style:{flexDirection:"column",alignItems:"flex-start",gap:8},children:[e.jsxs("span",{className:"mobile-setting-label",children:["Font size: ",t.theme.fontSize,"px"]}),e.jsx("input",{type:"range",min:12,max:20,value:t.theme.fontSize,onChange:s=>i({fontSize:Number(s.target.value)}),style:{width:"100%"}})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Compact mode"}),e.jsxs("label",{className:"mobile-toggle",children:[e.jsx("input",{type:"checkbox",checked:t.theme.compactMode,onChange:s=>i({compactMode:s.target.checked})}),e.jsx("span",{className:"mobile-toggle-slider"})]})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Animations"}),e.jsxs("label",{className:"mobile-toggle",children:[e.jsx("input",{type:"checkbox",checked:t.theme.animations,onChange:s=>i({animations:s.target.checked})}),e.jsx("span",{className:"mobile-toggle-slider"})]})]})]})]}),e.jsxs("section",{className:"mobile-section",children:[e.jsx("h3",{className:"mobile-section-title",children:"Chat Defaults"}),e.jsxs("div",{className:"mobile-card",children:[e.jsx("label",{className:"mobile-field-label",children:"Default Agent"}),e.jsx("select",{className:"mobile-input",value:t.defaultAgent||"odin",onChange:s=>m(l=>({...l,defaultAgent:s.target.value})),children:((a==null?void 0:a.agents)||[]).map(s=>e.jsxs("option",{value:s.name,children:["@",s.name]},s.name))})]})]}),e.jsxs("section",{className:"mobile-section",children:[e.jsx("h3",{className:"mobile-section-title",children:"About"}),e.jsxs("div",{className:"mobile-card",children:[e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Version"}),e.jsx("span",{className:"mobile-setting-value mono",children:((g=t.about)==null?void 0:g.version)||"—"})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Agents"}),e.jsx("span",{className:"mobile-setting-value",children:((x=a==null?void 0:a.agents)==null?void 0:x.length)||0})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Tasks"}),e.jsx("span",{className:"mobile-setting-value",children:((j=a==null?void 0:a.tasks)==null?void 0:j.length)||0})]})]})]}),e.jsx("div",{className:"mobile-view-footer",children:e.jsx("a",{href:"/?desktop=1",className:"mobile-btn mobile-btn-secondary",children:"Switch to Desktop"})})]})}export{D as MobileSettings};
1
+ import{r as o,j as e}from"./react-vendor-Dn4wqh4Z.js";import{d,a as f,g as N}from"./mobile-j3rOZK6v.js";import{av as y,aw as k,ax as S}from"./icons-DRDXfbBP.js";const w=[{id:"dark",label:"Dark",Icon:y},{id:"light",label:"Light",Icon:k},{id:"system",label:"System",Icon:S}],C=[{name:"Purple",accent:"#8b5cf6"},{name:"Blue",accent:"#3b82f6"},{name:"Green",accent:"#10b981"},{name:"Orange",accent:"#f97316"},{name:"Red",accent:"#ef4444"},{name:"Pink",accent:"#ec4899"},{name:"Cyan",accent:"#06b6d4"},{name:"Mono",accent:"#6b7280"}];function D({settings:n,snapshot:a,onRefresh:u}){var g,x,j;const[t,m]=o.useState(n),[v,r]=o.useState(!1),[b,h]=o.useState(!1);o.useEffect(()=>{m(n),r(!1),n.theme&&d(n.theme)},[n]);const i=s=>{m(l=>{const c={...l,theme:{...l.theme,...s}};return N(c.theme),d(c.theme),c}),r(!0)},p=async()=>{h(!0);try{const s=await f.put("/settings",t);m(s.data),r(!1),N(s.data.theme),d(s.data.theme),u()}catch{}finally{h(!1)}};return e.jsxs("div",{className:"mobile-view",children:[v&&e.jsxs("div",{className:"mobile-settings-save-bar",children:[e.jsx("span",{children:"Unsaved changes"}),e.jsx("button",{type:"button",className:"mobile-btn",disabled:b,onClick:p,children:b?"Saving…":"Save"})]}),e.jsxs("section",{className:"mobile-section",children:[e.jsx("h3",{className:"mobile-section-title",children:"Appearance"}),e.jsxs("div",{className:"mobile-card",children:[e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Theme"}),e.jsx("div",{className:"mobile-theme-btns",children:w.map(({id:s,label:l,Icon:c})=>e.jsxs("button",{type:"button",className:`mobile-theme-btn ${t.theme.mode===s?"active":""}`,onClick:()=>i({mode:s}),children:[e.jsx(c,{size:14})," ",l]},s))})]}),e.jsxs("div",{className:"mobile-setting-row",style:{flexDirection:"column",alignItems:"flex-start",gap:8},children:[e.jsx("span",{className:"mobile-setting-label",children:"Accent color"}),e.jsx("div",{className:"mobile-accent-swatches",children:C.map(s=>e.jsx("button",{type:"button",className:`mobile-accent-swatch ${t.theme.accent===s.accent?"active":""}`,style:{background:s.accent},onClick:()=>i({accent:s.accent}),title:s.name},s.name))})]}),e.jsxs("div",{className:"mobile-setting-row",style:{flexDirection:"column",alignItems:"flex-start",gap:8},children:[e.jsxs("span",{className:"mobile-setting-label",children:["Font size: ",t.theme.fontSize,"px"]}),e.jsx("input",{type:"range",min:12,max:20,value:t.theme.fontSize,onChange:s=>i({fontSize:Number(s.target.value)}),style:{width:"100%"}})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Compact mode"}),e.jsxs("label",{className:"mobile-toggle",children:[e.jsx("input",{type:"checkbox",checked:t.theme.compactMode,onChange:s=>i({compactMode:s.target.checked})}),e.jsx("span",{className:"mobile-toggle-slider"})]})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Animations"}),e.jsxs("label",{className:"mobile-toggle",children:[e.jsx("input",{type:"checkbox",checked:t.theme.animations,onChange:s=>i({animations:s.target.checked})}),e.jsx("span",{className:"mobile-toggle-slider"})]})]})]})]}),e.jsxs("section",{className:"mobile-section",children:[e.jsx("h3",{className:"mobile-section-title",children:"Chat Defaults"}),e.jsxs("div",{className:"mobile-card",children:[e.jsx("label",{className:"mobile-field-label",children:"Default Agent"}),e.jsx("select",{className:"mobile-input",value:t.defaultAgent||"odin",onChange:s=>m(l=>({...l,defaultAgent:s.target.value})),children:((a==null?void 0:a.agents)||[]).map(s=>e.jsxs("option",{value:s.name,children:["@",s.name]},s.name))})]})]}),e.jsxs("section",{className:"mobile-section",children:[e.jsx("h3",{className:"mobile-section-title",children:"About"}),e.jsxs("div",{className:"mobile-card",children:[e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Version"}),e.jsx("span",{className:"mobile-setting-value mono",children:((g=t.about)==null?void 0:g.version)||"—"})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Agents"}),e.jsx("span",{className:"mobile-setting-value",children:((x=a==null?void 0:a.agents)==null?void 0:x.length)||0})]}),e.jsxs("div",{className:"mobile-setting-row",children:[e.jsx("span",{className:"mobile-setting-label",children:"Tasks"}),e.jsx("span",{className:"mobile-setting-value",children:((j=a==null?void 0:a.tasks)==null?void 0:j.length)||0})]})]})]}),e.jsx("div",{className:"mobile-view-footer",children:e.jsx("a",{href:"/?desktop=1",className:"mobile-btn mobile-btn-secondary",children:"Switch to Desktop"})})]})}export{D as MobileSettings};
@@ -1 +1 @@
1
- {"version":3,"file":"MobileSettings-C85ApWKZ.js","sources":["../../src/web/mobile/MobileSettings.tsx"],"sourcesContent":["// src/web/mobile/MobileSettings.tsx — minimal mobile settings (no companion app, no agent config).\n// Drops: Companion App (qrcode.react chunk), Tailscale Serve, Agent Behavior, Notifications toggles.\nimport { useEffect, useState } from 'react';\nimport { Sun, Moon, Monitor } from 'lucide-react';\nimport { api } from '../lib/api';\nimport { applyTheme, applyThemeTokens, type Settings, type Snapshot, type ThemeName } from '../lib/types';\n\ntype Props = {\n settings: Settings;\n snapshot: Snapshot | null;\n onRefresh: () => Promise<void>;\n};\n\nconst THEMES: { id: ThemeName; label: string; Icon: typeof Sun }[] = [\n { id: 'dark', label: 'Dark', Icon: Moon },\n { id: 'light', label: 'Light', Icon: Sun },\n { id: 'system', label: 'System', Icon: Monitor },\n];\n\nconst PRESET_ACCENTS = [\n { name: 'Purple', accent: '#8b5cf6' },\n { name: 'Blue', accent: '#3b82f6' },\n { name: 'Green', accent: '#10b981' },\n { name: 'Orange', accent: '#f97316' },\n { name: 'Red', accent: '#ef4444' },\n { name: 'Pink', accent: '#ec4899' },\n { name: 'Cyan', accent: '#06b6d4' },\n { name: 'Mono', accent: '#6b7280' },\n];\n\nexport function MobileSettings({ settings: initial, snapshot, onRefresh }: Props) {\n const [settings, setSettings] = useState<Settings>(initial);\n const [dirty, setDirty] = useState(false);\n const [saving, setSaving] = useState(false);\n\n useEffect(() => {\n setSettings(initial);\n setDirty(false);\n if (initial.theme) applyThemeTokens(initial.theme);\n }, [initial]);\n\n const patchTheme = (patch: Partial<Settings['theme']>) => {\n setSettings((cur) => {\n const next = { ...cur, theme: { ...cur.theme, ...patch } };\n applyTheme(next.theme);\n applyThemeTokens(next.theme);\n return next;\n });\n setDirty(true);\n };\n\n const onSave = async () => {\n setSaving(true);\n try {\n const r = await api.put<{ data: Settings }>('/settings', settings);\n setSettings(r.data);\n setDirty(false);\n applyTheme(r.data.theme);\n applyThemeTokens(r.data.theme);\n onRefresh();\n } catch {\n // best-effort\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"mobile-view\">\n {dirty && (\n <div className=\"mobile-settings-save-bar\">\n <span>Unsaved changes</span>\n <button type=\"button\" className=\"mobile-btn\" disabled={saving} onClick={onSave}>\n {saving ? 'Saving…' : 'Save'}\n </button>\n </div>\n )}\n\n {/* Theme */}\n <section className=\"mobile-section\">\n <h3 className=\"mobile-section-title\">Appearance</h3>\n <div className=\"mobile-card\">\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Theme</span>\n <div className=\"mobile-theme-btns\">\n {THEMES.map(({ id, label, Icon }) => (\n <button\n key={id}\n type=\"button\"\n className={`mobile-theme-btn ${settings.theme.mode === id ? 'active' : ''}`}\n onClick={() => patchTheme({ mode: id })}\n >\n <Icon size={14} /> {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"mobile-setting-row\" style={{ flexDirection: 'column', alignItems: 'flex-start', gap: 8 }}>\n <span className=\"mobile-setting-label\">Accent color</span>\n <div className=\"mobile-accent-swatches\">\n {PRESET_ACCENTS.map((p) => (\n <button\n key={p.name}\n type=\"button\"\n className={`mobile-accent-swatch ${settings.theme.accent === p.accent ? 'active' : ''}`}\n style={{ background: p.accent }}\n onClick={() => patchTheme({ accent: p.accent })}\n title={p.name}\n />\n ))}\n </div>\n </div>\n\n <div className=\"mobile-setting-row\" style={{ flexDirection: 'column', alignItems: 'flex-start', gap: 8 }}>\n <span className=\"mobile-setting-label\">Font size: {settings.theme.fontSize}px</span>\n <input\n type=\"range\"\n min={12}\n max={20}\n value={settings.theme.fontSize}\n onChange={(e) => patchTheme({ fontSize: Number(e.target.value) })}\n style={{ width: '100%' }}\n />\n </div>\n\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Compact mode</span>\n <label className=\"mobile-toggle\">\n <input\n type=\"checkbox\"\n checked={settings.theme.compactMode}\n onChange={(e) => patchTheme({ compactMode: e.target.checked })}\n />\n <span className=\"mobile-toggle-slider\" />\n </label>\n </div>\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Animations</span>\n <label className=\"mobile-toggle\">\n <input\n type=\"checkbox\"\n checked={settings.theme.animations}\n onChange={(e) => patchTheme({ animations: e.target.checked })}\n />\n <span className=\"mobile-toggle-slider\" />\n </label>\n </div>\n </div>\n </section>\n\n {/* Chat defaults */}\n <section className=\"mobile-section\">\n <h3 className=\"mobile-section-title\">Chat Defaults</h3>\n <div className=\"mobile-card\">\n <label className=\"mobile-field-label\">Default Agent</label>\n <select\n className=\"mobile-input\"\n value={settings.defaultAgent || 'odin'}\n onChange={(e) => setSettings((cur) => ({ ...cur, defaultAgent: e.target.value }))}\n >\n {(snapshot?.agents || []).map((a) => (\n <option key={a.name} value={a.name}>@{a.name}</option>\n ))}\n </select>\n </div>\n </section>\n\n {/* About */}\n <section className=\"mobile-section\">\n <h3 className=\"mobile-section-title\">About</h3>\n <div className=\"mobile-card\">\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Version</span>\n <span className=\"mobile-setting-value mono\">{settings.about?.version || '—'}</span>\n </div>\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Agents</span>\n <span className=\"mobile-setting-value\">{snapshot?.agents?.length || 0}</span>\n </div>\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Tasks</span>\n <span className=\"mobile-setting-value\">{snapshot?.tasks?.length || 0}</span>\n </div>\n </div>\n </section>\n\n {/* Switch to desktop */}\n <div className=\"mobile-view-footer\">\n <a href=\"/?desktop=1\" className=\"mobile-btn mobile-btn-secondary\">\n Switch to Desktop\n </a>\n </div>\n </div>\n );\n}\n"],"names":["THEMES","Moon","Sun","Monitor","PRESET_ACCENTS","MobileSettings","initial","snapshot","onRefresh","settings","setSettings","useState","dirty","setDirty","saving","setSaving","useEffect","applyThemeTokens","patchTheme","patch","cur","next","applyTheme","onSave","r","api","jsxs","jsx","id","label","Icon","p","e","a","_a","_b","_c"],"mappings":"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"}
1
+ {"version":3,"file":"MobileSettings-BxcbL5XT.js","sources":["../../src/web/mobile/MobileSettings.tsx"],"sourcesContent":["// src/web/mobile/MobileSettings.tsx — minimal mobile settings (no companion app, no agent config).\n// Drops: Companion App (qrcode.react chunk), Tailscale Serve, Agent Behavior, Notifications toggles.\nimport { useEffect, useState } from 'react';\nimport { Sun, Moon, Monitor } from 'lucide-react';\nimport { api } from '../lib/api';\nimport { applyTheme, applyThemeTokens, type Settings, type Snapshot, type ThemeName } from '../lib/types';\n\ntype Props = {\n settings: Settings;\n snapshot: Snapshot | null;\n onRefresh: () => Promise<void>;\n};\n\nconst THEMES: { id: ThemeName; label: string; Icon: typeof Sun }[] = [\n { id: 'dark', label: 'Dark', Icon: Moon },\n { id: 'light', label: 'Light', Icon: Sun },\n { id: 'system', label: 'System', Icon: Monitor },\n];\n\nconst PRESET_ACCENTS = [\n { name: 'Purple', accent: '#8b5cf6' },\n { name: 'Blue', accent: '#3b82f6' },\n { name: 'Green', accent: '#10b981' },\n { name: 'Orange', accent: '#f97316' },\n { name: 'Red', accent: '#ef4444' },\n { name: 'Pink', accent: '#ec4899' },\n { name: 'Cyan', accent: '#06b6d4' },\n { name: 'Mono', accent: '#6b7280' },\n];\n\nexport function MobileSettings({ settings: initial, snapshot, onRefresh }: Props) {\n const [settings, setSettings] = useState<Settings>(initial);\n const [dirty, setDirty] = useState(false);\n const [saving, setSaving] = useState(false);\n\n useEffect(() => {\n setSettings(initial);\n setDirty(false);\n if (initial.theme) applyThemeTokens(initial.theme);\n }, [initial]);\n\n const patchTheme = (patch: Partial<Settings['theme']>) => {\n setSettings((cur) => {\n const next = { ...cur, theme: { ...cur.theme, ...patch } };\n applyTheme(next.theme);\n applyThemeTokens(next.theme);\n return next;\n });\n setDirty(true);\n };\n\n const onSave = async () => {\n setSaving(true);\n try {\n const r = await api.put<{ data: Settings }>('/settings', settings);\n setSettings(r.data);\n setDirty(false);\n applyTheme(r.data.theme);\n applyThemeTokens(r.data.theme);\n onRefresh();\n } catch {\n // best-effort\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"mobile-view\">\n {dirty && (\n <div className=\"mobile-settings-save-bar\">\n <span>Unsaved changes</span>\n <button type=\"button\" className=\"mobile-btn\" disabled={saving} onClick={onSave}>\n {saving ? 'Saving…' : 'Save'}\n </button>\n </div>\n )}\n\n {/* Theme */}\n <section className=\"mobile-section\">\n <h3 className=\"mobile-section-title\">Appearance</h3>\n <div className=\"mobile-card\">\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Theme</span>\n <div className=\"mobile-theme-btns\">\n {THEMES.map(({ id, label, Icon }) => (\n <button\n key={id}\n type=\"button\"\n className={`mobile-theme-btn ${settings.theme.mode === id ? 'active' : ''}`}\n onClick={() => patchTheme({ mode: id })}\n >\n <Icon size={14} /> {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"mobile-setting-row\" style={{ flexDirection: 'column', alignItems: 'flex-start', gap: 8 }}>\n <span className=\"mobile-setting-label\">Accent color</span>\n <div className=\"mobile-accent-swatches\">\n {PRESET_ACCENTS.map((p) => (\n <button\n key={p.name}\n type=\"button\"\n className={`mobile-accent-swatch ${settings.theme.accent === p.accent ? 'active' : ''}`}\n style={{ background: p.accent }}\n onClick={() => patchTheme({ accent: p.accent })}\n title={p.name}\n />\n ))}\n </div>\n </div>\n\n <div className=\"mobile-setting-row\" style={{ flexDirection: 'column', alignItems: 'flex-start', gap: 8 }}>\n <span className=\"mobile-setting-label\">Font size: {settings.theme.fontSize}px</span>\n <input\n type=\"range\"\n min={12}\n max={20}\n value={settings.theme.fontSize}\n onChange={(e) => patchTheme({ fontSize: Number(e.target.value) })}\n style={{ width: '100%' }}\n />\n </div>\n\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Compact mode</span>\n <label className=\"mobile-toggle\">\n <input\n type=\"checkbox\"\n checked={settings.theme.compactMode}\n onChange={(e) => patchTheme({ compactMode: e.target.checked })}\n />\n <span className=\"mobile-toggle-slider\" />\n </label>\n </div>\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Animations</span>\n <label className=\"mobile-toggle\">\n <input\n type=\"checkbox\"\n checked={settings.theme.animations}\n onChange={(e) => patchTheme({ animations: e.target.checked })}\n />\n <span className=\"mobile-toggle-slider\" />\n </label>\n </div>\n </div>\n </section>\n\n {/* Chat defaults */}\n <section className=\"mobile-section\">\n <h3 className=\"mobile-section-title\">Chat Defaults</h3>\n <div className=\"mobile-card\">\n <label className=\"mobile-field-label\">Default Agent</label>\n <select\n className=\"mobile-input\"\n value={settings.defaultAgent || 'odin'}\n onChange={(e) => setSettings((cur) => ({ ...cur, defaultAgent: e.target.value }))}\n >\n {(snapshot?.agents || []).map((a) => (\n <option key={a.name} value={a.name}>@{a.name}</option>\n ))}\n </select>\n </div>\n </section>\n\n {/* About */}\n <section className=\"mobile-section\">\n <h3 className=\"mobile-section-title\">About</h3>\n <div className=\"mobile-card\">\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Version</span>\n <span className=\"mobile-setting-value mono\">{settings.about?.version || '—'}</span>\n </div>\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Agents</span>\n <span className=\"mobile-setting-value\">{snapshot?.agents?.length || 0}</span>\n </div>\n <div className=\"mobile-setting-row\">\n <span className=\"mobile-setting-label\">Tasks</span>\n <span className=\"mobile-setting-value\">{snapshot?.tasks?.length || 0}</span>\n </div>\n </div>\n </section>\n\n {/* Switch to desktop */}\n <div className=\"mobile-view-footer\">\n <a href=\"/?desktop=1\" className=\"mobile-btn mobile-btn-secondary\">\n Switch to Desktop\n </a>\n </div>\n </div>\n );\n}\n"],"names":["THEMES","Moon","Sun","Monitor","PRESET_ACCENTS","MobileSettings","initial","snapshot","onRefresh","settings","setSettings","useState","dirty","setDirty","saving","setSaving","useEffect","applyThemeTokens","patchTheme","patch","cur","next","applyTheme","onSave","r","api","jsxs","jsx","id","label","Icon","p","e","a","_a","_b","_c"],"mappings":"iKAaA,MAAMA,EAA+D,CACnE,CAAE,GAAI,OAAQ,MAAO,OAAQ,KAAMC,CAAA,EACnC,CAAE,GAAI,QAAS,MAAO,QAAS,KAAMC,CAAA,EACrC,CAAE,GAAI,SAAU,MAAO,SAAU,KAAMC,CAAA,CACzC,EAEMC,EAAiB,CACrB,CAAE,KAAM,SAAU,OAAQ,SAAA,EAC1B,CAAE,KAAM,OAAQ,OAAQ,SAAA,EACxB,CAAE,KAAM,QAAS,OAAQ,SAAA,EACzB,CAAE,KAAM,SAAU,OAAQ,SAAA,EAC1B,CAAE,KAAM,MAAO,OAAQ,SAAA,EACvB,CAAE,KAAM,OAAQ,OAAQ,SAAA,EACxB,CAAE,KAAM,OAAQ,OAAQ,SAAA,EACxB,CAAE,KAAM,OAAQ,OAAQ,SAAA,CAC1B,EAEO,SAASC,EAAe,CAAE,SAAUC,EAAS,SAAAC,EAAU,UAAAC,GAAoB,WAChF,KAAM,CAACC,EAAUC,CAAW,EAAIC,EAAAA,SAAmBL,CAAO,EACpD,CAACM,EAAOC,CAAQ,EAAIF,EAAAA,SAAS,EAAK,EAClC,CAACG,EAAQC,CAAS,EAAIJ,EAAAA,SAAS,EAAK,EAE1CK,EAAAA,UAAU,IAAM,CACdN,EAAYJ,CAAO,EACnBO,EAAS,EAAK,EACVP,EAAQ,OAAOW,EAAiBX,EAAQ,KAAK,CACnD,EAAG,CAACA,CAAO,CAAC,EAEZ,MAAMY,EAAcC,GAAsC,CACxDT,EAAaU,GAAQ,CACnB,MAAMC,EAAO,CAAE,GAAGD,EAAK,MAAO,CAAE,GAAGA,EAAI,MAAO,GAAGD,EAAM,EACvD,OAAAG,EAAWD,EAAK,KAAK,EACrBJ,EAAiBI,EAAK,KAAK,EACpBA,CACT,CAAC,EACDR,EAAS,EAAI,CACf,EAEMU,EAAS,SAAY,CACzBR,EAAU,EAAI,EACd,GAAI,CACF,MAAMS,EAAI,MAAMC,EAAI,IAAwB,YAAahB,CAAQ,EACjEC,EAAYc,EAAE,IAAI,EAClBX,EAAS,EAAK,EACdS,EAAWE,EAAE,KAAK,KAAK,EACvBP,EAAiBO,EAAE,KAAK,KAAK,EAC7BhB,EAAA,CACF,MAAQ,CAER,QAAA,CACEO,EAAU,EAAK,CACjB,CACF,EAEA,OACEW,EAAAA,KAAC,MAAA,CAAI,UAAU,cACZ,SAAA,CAAAd,GACCc,EAAAA,KAAC,MAAA,CAAI,UAAU,2BACb,SAAA,CAAAC,EAAAA,IAAC,QAAK,SAAA,iBAAA,CAAe,EACrBA,EAAAA,IAAC,SAAA,CAAO,KAAK,SAAS,UAAU,aAAa,SAAUb,EAAQ,QAASS,EACrE,SAAAT,EAAS,UAAY,MAAA,CACxB,CAAA,EACF,EAIFY,EAAAA,KAAC,UAAA,CAAQ,UAAU,iBACjB,SAAA,CAAAC,EAAAA,IAAC,KAAA,CAAG,UAAU,uBAAuB,SAAA,aAAU,EAC/CD,EAAAA,KAAC,MAAA,CAAI,UAAU,cACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,QAAK,EAC5CA,EAAAA,IAAC,MAAA,CAAI,UAAU,oBACZ,SAAA3B,EAAO,IAAI,CAAC,CAAE,GAAA4B,EAAI,MAAAC,EAAO,KAAAC,CAAA,IACxBJ,EAAAA,KAAC,SAAA,CAEC,KAAK,SACL,UAAW,oBAAoBjB,EAAS,MAAM,OAASmB,EAAK,SAAW,EAAE,GACzE,QAAS,IAAMV,EAAW,CAAE,KAAMU,EAAI,EAEtC,SAAA,CAAAD,EAAAA,IAACG,EAAA,CAAK,KAAM,EAAA,CAAI,EAAE,IAAED,CAAA,CAAA,EALfD,CAAA,CAOR,CAAA,CACH,CAAA,EACF,EAEAF,EAAAA,KAAC,MAAA,CAAI,UAAU,qBAAqB,MAAO,CAAE,cAAe,SAAU,WAAY,aAAc,IAAK,CAAA,EACnG,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,eAAY,QAClD,MAAA,CAAI,UAAU,yBACZ,SAAAvB,EAAe,IAAK2B,GACnBJ,EAAAA,IAAC,SAAA,CAEC,KAAK,SACL,UAAW,wBAAwBlB,EAAS,MAAM,SAAWsB,EAAE,OAAS,SAAW,EAAE,GACrF,MAAO,CAAE,WAAYA,EAAE,MAAA,EACvB,QAAS,IAAMb,EAAW,CAAE,OAAQa,EAAE,OAAQ,EAC9C,MAAOA,EAAE,IAAA,EALJA,EAAE,IAAA,CAOV,CAAA,CACH,CAAA,EACF,EAEAL,EAAAA,KAAC,MAAA,CAAI,UAAU,qBAAqB,MAAO,CAAE,cAAe,SAAU,WAAY,aAAc,IAAK,CAAA,EACnG,SAAA,CAAAA,EAAAA,KAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,CAAA,cAAYjB,EAAS,MAAM,SAAS,IAAA,EAAE,EAC7EkB,EAAAA,IAAC,QAAA,CACC,KAAK,QACL,IAAK,GACL,IAAK,GACL,MAAOlB,EAAS,MAAM,SACtB,SAAWuB,GAAMd,EAAW,CAAE,SAAU,OAAOc,EAAE,OAAO,KAAK,EAAG,EAChE,MAAO,CAAE,MAAO,MAAA,CAAO,CAAA,CACzB,EACF,EAEAN,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,eAAY,EACnDD,EAAAA,KAAC,QAAA,CAAM,UAAU,gBACf,SAAA,CAAAC,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,QAASlB,EAAS,MAAM,YACxB,SAAWuB,GAAMd,EAAW,CAAE,YAAac,EAAE,OAAO,OAAA,CAAS,CAAA,CAAA,EAE/DL,EAAAA,IAAC,OAAA,CAAK,UAAU,sBAAA,CAAuB,CAAA,CAAA,CACzC,CAAA,EACF,EACAD,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,aAAU,EACjDD,EAAAA,KAAC,QAAA,CAAM,UAAU,gBACf,SAAA,CAAAC,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,QAASlB,EAAS,MAAM,WACxB,SAAWuB,GAAMd,EAAW,CAAE,WAAYc,EAAE,OAAO,OAAA,CAAS,CAAA,CAAA,EAE9DL,EAAAA,IAAC,OAAA,CAAK,UAAU,sBAAA,CAAuB,CAAA,CAAA,CACzC,CAAA,CAAA,CACF,CAAA,CAAA,CACF,CAAA,EACF,EAGAD,EAAAA,KAAC,UAAA,CAAQ,UAAU,iBACjB,SAAA,CAAAC,EAAAA,IAAC,KAAA,CAAG,UAAU,uBAAuB,SAAA,gBAAa,EAClDD,EAAAA,KAAC,MAAA,CAAI,UAAU,cACb,SAAA,CAAAC,EAAAA,IAAC,QAAA,CAAM,UAAU,qBAAqB,SAAA,gBAAa,EACnDA,EAAAA,IAAC,SAAA,CACC,UAAU,eACV,MAAOlB,EAAS,cAAgB,OAChC,SAAWuB,GAAMtB,EAAaU,IAAS,CAAE,GAAGA,EAAK,aAAcY,EAAE,OAAO,OAAQ,EAE9E,WAAAzB,GAAA,YAAAA,EAAU,SAAU,CAAA,GAAI,IAAK0B,GAC7BP,EAAAA,KAAC,SAAA,CAAoB,MAAOO,EAAE,KAAM,SAAA,CAAA,IAAEA,EAAE,IAAA,CAAA,EAA3BA,EAAE,IAA8B,CAC9C,CAAA,CAAA,CACH,CAAA,CACF,CAAA,EACF,EAGAP,EAAAA,KAAC,UAAA,CAAQ,UAAU,iBACjB,SAAA,CAAAC,EAAAA,IAAC,KAAA,CAAG,UAAU,uBAAuB,SAAA,QAAK,EAC1CD,EAAAA,KAAC,MAAA,CAAI,UAAU,cACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,UAAO,QAC7C,OAAA,CAAK,UAAU,4BAA6B,WAAAO,EAAAzB,EAAS,QAAT,YAAAyB,EAAgB,UAAW,GAAA,CAAI,CAAA,EAC9E,EACAR,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,SAAM,QAC5C,OAAA,CAAK,UAAU,uBAAwB,WAAAQ,EAAA5B,GAAA,YAAAA,EAAU,SAAV,YAAA4B,EAAkB,SAAU,CAAA,CAAE,CAAA,EACxE,EACAT,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAuB,SAAA,QAAK,QAC3C,OAAA,CAAK,UAAU,uBAAwB,WAAAS,EAAA7B,GAAA,YAAAA,EAAU,QAAV,YAAA6B,EAAiB,SAAU,CAAA,CAAE,CAAA,CAAA,CACvE,CAAA,CAAA,CACF,CAAA,EACF,EAGAT,EAAAA,IAAC,MAAA,CAAI,UAAU,qBACb,SAAAA,EAAAA,IAAC,IAAA,CAAE,KAAK,cAAc,UAAU,kCAAkC,SAAA,mBAAA,CAElE,CAAA,CACF,CAAA,EACF,CAEJ"}