@rubytech/create-maxy 1.0.636 → 1.0.638
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +30 -23
- package/package.json +1 -1
- package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts +14 -0
- package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js +83 -8
- package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js.map +1 -1
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +21 -8
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +0 -2
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +5 -32
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -1
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +48 -1
- package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +10 -12
- package/payload/platform/plugins/docs/references/cloudflare.md +8 -7
- package/payload/platform/plugins/docs/references/getting-started.md +9 -0
- package/payload/platform/plugins/memory/mcp/scripts/graph/accept.sh +96 -8
- package/payload/platform/plugins/memory/references/graph-primitives.md +52 -4
- package/payload/platform/plugins/workflows/PLUGIN.md +4 -0
- package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts +25 -2
- package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js +41 -13
- package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +18 -6
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
- package/payload/platform/scripts/setup.sh +1 -1
- package/payload/server/public/assets/{admin-E3EIZIw0.js → admin-tPrH6zWV.js} +60 -60
- package/payload/server/public/assets/{public-Lwkux_Q4.js → public-DdVq1Jag.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-BNLXzSN4.css +1 -0
- package/payload/server/public/index.html +3 -3
- package/payload/server/public/public.html +3 -3
- package/payload/server/server.js +124 -9
- package/payload/server/public/assets/useVoiceRecorder-Cbo-LQPY.css +0 -1
- /package/payload/server/public/assets/{useVoiceRecorder-D4y_EM_A.js → useVoiceRecorder-3Qblv7wH.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{o as e}from"./chunk-Be6NvmcD.js";import{A as t,C as n,D as r,F as i,I as a,N as o,P as s,R as c,S as l,V as u,_ as d,a as f,b as p,c as m,g as h,h as g,i as _,j as v,n as y,o as b,r as x,s as S,t as C,u as w,v as T,w as E,y as D,z as O}from"./useVoiceRecorder-D4y_EM_A.js";var k=c(`square-plus`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M8 12h8`,key:`1wcyev`}],[`path`,{d:`M12 8v8`,key:`napkw2`}]]),A=O(),j=e(u(),1),M=`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar`,N=new Set(M.split(`,`)),P=20*1024*1024,F=typeof window<`u`&&/^(localhost|127\.0\.0\.1|[a-z0-9-]+\.local)(:|$)/.test(window.location.hostname);function I(){let e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;let t=[...e].map(e=>e.toString(16).padStart(2,`0`)).join(``);return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}function L(){let e=window.location.pathname;if(e.startsWith(`/g/`))return;let t=e.match(/^\/([a-z][a-z0-9-]{2,49})$/);return t?t[1]:void 0}function R(){let e=window.location.pathname.match(/^\/g\/([a-z0-9][a-z0-9-]{0,49})$/);return e?e[1]:void 0}function z(e){return[{key:`length`,label:`At least 8 characters`,met:e.length>=8},{key:`number`,label:`Contains a number`,met:/\d/.test(e)},{key:`special`,label:`Contains a special character`,met:/[^A-Za-z0-9]/.test(e)},{key:`whitespace`,label:`No spaces`,met:e.length>0&&!/\s/.test(e)}]}function B(e,t){if(t===`phone`)return e.length>4?e.slice(0,e.length-4).replace(/\d/g,`•`)+` `+e.slice(-4):e;let n=e.indexOf(`@`);return n<=2?e:e.slice(0,2)+`•••`+e.slice(n)}function V(e){let[t,n]=(0,j.useState)(null),[r,i]=(0,j.useState)(null),[a,o]=(0,j.useState)(`loading`),[s,c]=(0,j.useState)(``),[l,u]=(0,j.useState)(null),[d,f]=(0,j.useState)(null),[p,m]=(0,j.useState)(!1),[h,g]=(0,j.useState)(null),_=(0,j.useMemo)(()=>L(),[]),v=(0,j.useMemo)(()=>R(),[]),[y,b]=(0,j.useState)(null),x=(0,j.useRef)(_||``),S=(0,j.useRef)(null),C=(0,j.useRef)(null),w=(0,j.useRef)(!1),T=(0,j.useRef)(null),[E,D]=(0,j.useState)(`sign-in`),[O,k]=(0,j.useState)(null),A=(0,j.useRef)(null),M=(0,j.useRef)(null);(0,j.useEffect)(()=>{try{let e=sessionStorage.getItem(`maxy_session`);e&&(M.current=e)}catch{}},[]);let N=(0,j.useCallback)(t=>{S.current=t,n(t);try{sessionStorage.setItem(`maxy_session`,t)}catch{}o(`chat`),e(t)},[e]),P=(0,j.useCallback)(()=>{S.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}n(null),o(`auth-required`),D(`sign-in`)},[]),z=(0,j.useCallback)(async e=>{try{let t=x.current,n=await fetch(`/api/access/verify-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:e,agentSlug:t})}),r=await n.json();n.ok?(A.current=r.session_key,k(r.grant),D(`set-password`),window.history.replaceState({},``,window.location.pathname)):D(`link-expired`)}catch{D(`sign-in`)}},[]),B=(0,j.useCallback)(async()=>{if(S.current)return S.current;if(C.current)return C.current;let e=(async()=>{try{let e=M.current,t=await fetch(`/api/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_id:I(),..._?{agent:_}:{},...v?{group_slug:v}:{},...e?{session_key:e}:{}})});if(!t.ok){let e=await t.json().catch(()=>({error:``}));return F&&console.error(`[session] POST /api/session failed: ${t.status} ${t.statusText}`,e),t.status===404?i(e.error||`Agent not found`):t.status===503&&i(e.error||`Service unavailable`),null}let r=await t.json();if(r.auth_required){r.agent_id&&(x.current=r.agent_id),c(r.displayName||``),r.agentImage&&u(r.agentImage),r.agentImageShape&&f(r.agentImageShape),r.showAgentName&&m(r.showAgentName),r.branding&&g(r.branding),o(`auth-required`);let e=new URLSearchParams(window.location.search).get(`token`);return e?z(e):D(`sign-in`),null}S.current=r.session_key,n(r.session_key),r.displayName&&c(r.displayName),r.agentImage&&u(r.agentImage),r.agentImageShape&&f(r.agentImageShape),r.showAgentName&&m(r.showAgentName),r.branding&&g(r.branding),o(`chat`),r.resumed&&r.messages&&(w.current=!0,T.current=r.messages),r.group&&b({groupSlug:r.groupSlug,groupName:r.groupName,participants:r.participants??[]});try{sessionStorage.setItem(`maxy_session`,r.session_key)}catch{}return r.session_key}catch(e){return F&&console.error(`[session] fetch /api/session threw:`,e),i(`Unable to connect. Please check your connection and try again.`),null}finally{C.current=null}})();return C.current=e,e},[_,v,z]);return{sessionId:t,sessionKeyRef:S,sessionError:r,pageState:a,setPageState:o,agentDisplayName:s,agentImage:l,agentImageShape:d,showAgentName:p,agentSlug:_,branding:h,resolvedSlugRef:x,ensureSession:B,startNewSession:(0,j.useCallback)(async()=>{S.current=null,C.current=null,M.current=null,w.current=!1,T.current=null,n(null),i(null);try{sessionStorage.removeItem(`maxy_session`)}catch{}let t=await B();t&&e(t)},[B,e]),enterChat:N,enterGate:P,resumedRef:w,resumeMessagesRef:T,gateState:E,setGateState:D,grantInfo:O,setGrantInfo:k,gateSessionKeyRef:A,groupContext:y,groupSlug:v}}function ee({sessionKeyRef:e,ensureSession:t,sessionError:n,pageState:r,inputRef:i}){let[a,o]=(0,j.useState)([]),[s,c]=(0,j.useState)(!1),u=(0,j.useRef)(!1),d=e=>{u.current=e,c(e)},f=(0,j.useCallback)(async a=>{if(!u.current){d(!0),o([{role:`maxy`,content:``,timestamp:Date.now()}]);try{let n=await fetch(`/api/chat`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({greeting:!0,session_key:a})});if(n.status===401){e.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}F&&console.warn(`[greeting] stale session, retrying with fresh session`);let r=await t();if(!r)return;n=await fetch(`/api/chat`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({greeting:!0,session_key:r})})}if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Something went wrong`)}let r=``,i=``,s=()=>{i&&(r+=i,i=``,o(e=>{let t=[...e];return t[0]={...t[0],content:r},t}))},c=setInterval(s,60);try{for await(let e of l(n)){if(e.error)throw Object.assign(Error(e.error),{fromSSE:!0});e.text&&(i+=e.text),e.type===`component`&&(s(),o(t=>{let n=[...t],r={...n[0]},i=[...r.components||[]];return i.push({name:e.name,data:e.data,submitted:!1}),n[0]={...r,components:i},n}))}}finally{clearInterval(c),s()}}catch(e){if(F&&console.error(`[chat] greeting failed:`,e),r===`auth-required`)return;let t=e instanceof Error?e.message:String(e);o([{role:`maxy`,content:e instanceof Error&&e.fromSSE?t:n??`I'm having trouble connecting right now. Try refreshing the page.`,timestamp:Date.now()}])}finally{d(!1),r===`chat`&&i.current?.focus()}}},[e,t,n,r,i]),p=(0,j.useCallback)(async(a,s)=>{let c=s?.hidden??!1,f=s?.files??[];if(!a&&f.length===0||u.current)return;d(!0);let p=f.map(e=>({filename:e.name,mimeType:e.type})),m={role:`visitor`,content:a,attachments:p.length>0?p:void 0,timestamp:Date.now(),hidden:c},h;o(e=>{let t=[...e,m,{role:`maxy`,content:``,timestamp:Date.now()}];return h=t.length-1,t});try{let n=await t();if(!n)throw Error(`session`);let r=e=>{if(f.length>0){let t=new FormData;t.append(`message`,a),t.append(`session_key`,e);for(let e of f)t.append(`attachments`,e);return{body:t,headers:{}}}return{body:JSON.stringify({message:a,session_key:e}),headers:{"Content-Type":`application/json`}}},{body:i,headers:s}=r(n),c=await fetch(`/api/chat`,{method:`POST`,headers:s,body:i});if(c.status===401){e.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}F&&console.warn(`[session-expired] stale key cleared, retrying with fresh session`);let n=await t();if(!n)throw Error(`session`);({body:i,headers:s}=r(n)),c=await fetch(`/api/chat`,{method:`POST`,headers:s,body:i})}if(!c.ok){let e=await c.json().catch(()=>({}));throw Error(e.error||`Something went wrong`)}let u=``,d=``,p=()=>{d&&(u+=d,d=``,o(e=>{let t=[...e];return t[h]={...t[h],content:u},t}))},m=setInterval(p,60);try{for await(let e of l(c)){if(e.error)throw Object.assign(Error(e.error),{fromSSE:!0});e.text&&(d+=e.text),e.type===`component`&&(p(),o(t=>{let n=[...t],r={...n[h]},i=[...r.components||[]];return i.push({name:e.name,data:e.data,submitted:!1}),n[h]={...r,components:i},n}))}}finally{clearInterval(m),p()}}catch(e){if(F&&console.error(`[chat] sendMessage failed:`,e),r===`auth-required`)return;let t=e instanceof Error?e.message:String(e),i=e instanceof Error&&e.fromSSE;o(e=>{let r=[...e];return r[h]={...r[h],content:i?t:t===`session`?n??`I'm having trouble connecting right now. Try refreshing the page.`:`Sorry, I hit a snag. Try again in a moment.`},r})}finally{d(!1),r===`chat`&&i.current?.focus()}},[e,t,n,r,i]);return{messages:a,setMessages:o,isStreaming:s,sendMessage:p,sendGreeting:f,handleComponentSubmit:(0,j.useCallback)((e,t,n)=>{o(n=>{let r=[...n],i={...r[e]},a=[...i.components||[]];return a[t]={...a[t],submitted:!0},r[e]={...i,components:a},r}),p(n,{hidden:!0})},[p])}}function te({sessionKeyRef:e,groupSlug:t,isStreaming:n,setMessages:r}){let i=(0,j.useRef)(new Date().toISOString()),a=(0,j.useRef)(!0);(0,j.useEffect)(()=>{let e=()=>{a.current=document.visibilityState===`visible`};return document.addEventListener(`visibilitychange`,e),()=>document.removeEventListener(`visibilitychange`,e)},[]);let o=(0,j.useCallback)(async()=>{let n=e.current;if(!(!n||!t))try{let e=await fetch(`/api/group/messages?session_key=${encodeURIComponent(n)}&since=${encodeURIComponent(i.current)}`);if(!e.ok)return;let t=await e.json();if(!t.messages||t.messages.length===0)return;let a=t.messages[t.messages.length-1];a.timestamp&&(i.current=new Date(a.timestamp).toISOString()),r(e=>{let n=new Set(e.filter(e=>e.messageId).map(e=>e.messageId)),r=t.messages.filter(e=>!n.has(e.messageId)).map(e=>({role:e.role,content:e.content,timestamp:e.timestamp,senderName:e.senderName??void 0,senderVisitorId:e.senderVisitorId??void 0,messageId:e.messageId}));return r.length===0?e:[...e,...r]})}catch{}},[e,t,r]);(0,j.useEffect)(()=>{if(!t)return;let e,r=!1;function i(){if(r)return;let t=a.current?3e3:3e4;e=setTimeout(async()=>{n||await o(),i()},t)}return i(),()=>{r=!0,clearTimeout(e)}},[t,n,o])}var H=d();function U({value:e,onChange:t,onComplete:n,disabled:r}){let i=(0,j.useRef)([]);function a(n,r){r.key===`Backspace`?(r.preventDefault(),e[n]?t(e.slice(0,n)+e.slice(n+1)):n>0&&(t(e.slice(0,n-1)+e.slice(n)),i.current[n-1]?.focus())):r.key===`ArrowLeft`&&n>0?i.current[n-1]?.focus():r.key===`ArrowRight`&&n<5&&i.current[n+1]?.focus()}function o(r,a){let o=a.nativeEvent.data;if(!o||!/^\d$/.test(o))return;let s=e.split(``);for(s[r]=o;s.length<r;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);t(c),c.length===6?n(c):r<5&&i.current[r+1]?.focus()}function s(e){e.preventDefault();let r=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);r&&(t(r),r.length===6?n(r):i.current[r.length]?.focus())}return(0,H.jsx)(`div`,{className:`gate-otp-field`,children:Array.from({length:6}).map((t,n)=>(0,H.jsx)(`input`,{ref:e=>{i.current[n]=e},type:`text`,inputMode:`numeric`,className:`pin-box${e[n]?` pin-box-filled`:``}`,value:e[n]||``,onKeyDown:e=>a(n,e),onInput:e=>o(n,e),onPaste:s,onFocus:e=>e.target.select(),autoFocus:n===0,autoComplete:`off`,maxLength:1,disabled:r,"aria-label":`Code digit ${n+1}`},n))})}function ne({gateState:e,setGateState:t,grantInfo:n,setGrantInfo:r,gateSessionKeyRef:i,resolvedSlugRef:a,onAuthenticated:o}){let[s,c]=(0,j.useState)(``),[l,u]=(0,j.useState)(``),[d,f]=(0,j.useState)(``),[p,m]=(0,j.useState)(!1),[_,v]=(0,j.useState)(``),[y,b]=(0,j.useState)(``),[x,S]=(0,j.useState)(!1),[C,w]=(0,j.useState)(null),[T,E]=(0,j.useState)(null),[D,O]=(0,j.useState)(!1);async function k(e){if(e.preventDefault(),!D){w(null),O(!0);try{let e=a.current,n=await fetch(`/api/access/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contact:s,password:l,agentSlug:e})}),i=await n.json();n.ok?o(i.session_key):n.status===401?i.error?.includes(`setup not complete`)||i.error?.includes(`invitation link`)?(t(`private-agent`),w(null)):w(i.error||`Invalid credentials`):n.status===403?(t(`access-expired`),i.expiresAt&&r(e=>e?{...e,expiresAt:i.expiresAt}:{displayName:null,contactValue:s,contactMethod:`email`,expiresAt:i.expiresAt,status:`expired`})):n.status===429?w(i.error||`Too many attempts. Please try again later.`):w(i.error||`Something went wrong`)}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}async function A(e){if(!D){w(null),O(!0);try{let n=a.current,o=await fetch(`/api/access/verify-otp`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({phone:y,code:e,agentSlug:n})}),s=await o.json();o.ok?(i.current=s.session_key,r(s.grant),t(`set-password`)):o.status===429?t(`otp-failed`):(w(s.error||`Invalid code`),v(``))}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}async function M(e){if(e.preventDefault(),!D){if(w(null),l!==d){w(`Passwords do not match`);return}if(!z(l).every(e=>e.met)){w(`Password does not meet requirements`);return}O(!0);try{let e=i.current;if(!e){w(`Session expired. Please use your invitation link again.`);return}let t=await fetch(`/api/access/create-credentials`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_key:e,password:l})}),n=await t.json();t.ok?o(n.session_key):t.status===400&&n.requirements?w(n.requirements.filter(e=>!e.met).map(e=>e.label).join(`, `)):w(n.error||`Something went wrong`)}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}async function N(e){if(e.preventDefault(),!(D||!s)){w(null),O(!0);try{let e=a.current,t=await fetch(`/api/access/forgot-password`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contact:s,agentSlug:e})});t.status===429?w((await t.json()).error||`Too many attempts. Please try again later.`):(E(`If an account exists, a reset link has been sent.`),setTimeout(()=>{S(!1),E(null)},4e3))}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}switch(e){case`set-password`:{let e=z(l),t=e.every(e=>e.met),r=l===d,i=t&&r&&d.length>0;return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[n?.expiresAt&&(0,H.jsxs)(`div`,{className:`gate-expiry-badge`,children:[`Access until `,new Date(n.expiresAt).toLocaleDateString(`en-GB`,{day:`numeric`,month:`short`,year:`numeric`})]}),(0,H.jsxs)(`h2`,{className:`gate-title`,children:[`Welcome, `,n?.displayName||`there`]}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:`Create a password to access this agent in the future.`}),(0,H.jsxs)(`form`,{className:`gate-form`,onSubmit:M,children:[(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-display-name`,children:`Display name`}),(0,H.jsx)(`input`,{id:`gate-display-name`,type:`text`,value:n?.displayName||``,disabled:!0})]}),(0,H.jsxs)(`div`,{className:`gate-field gate-pw-row`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-pw`,children:`Password`}),(0,H.jsx)(`div`,{className:`gate-pw-toggle`,children:(0,H.jsx)(h,{checked:p,onChange:m,label:`Show`})}),(0,H.jsx)(`input`,{id:`gate-pw`,type:p?`text`:`password`,value:l,onChange:e=>u(e.target.value),placeholder:`Your password`,autoFocus:!0,autoComplete:`new-password`}),l.length>0&&(0,H.jsx)(`div`,{className:`gate-strength`,children:e.map(e=>(0,H.jsxs)(`span`,{className:`gate-strength-item${e.met?` met`:``}`,children:[e.met?`✓`:`○`,` `,e.label]},e.key))})]}),(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-pw-confirm`,children:`Confirm password`}),(0,H.jsx)(`input`,{id:`gate-pw-confirm`,type:p?`text`:`password`,value:d,onChange:e=>f(e.target.value),placeholder:`Confirm your password`,autoComplete:`new-password`}),d.length>0&&!r&&(0,H.jsx)(`div`,{className:`gate-error`,children:`Passwords do not match`})]}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),(0,H.jsx)(`div`,{className:`gate-submit`,children:(0,H.jsx)(g,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!i||D,loading:D,children:`Create account & enter chat`})})]})]})})}case`enter-otp`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`h2`,{className:`gate-title`,children:`Enter your code`}),(0,H.jsxs)(`p`,{className:`gate-subtitle`,children:[`Enter the 6-digit code sent to `,B(y,`phone`)]}),(0,H.jsx)(U,{value:_,onChange:v,onComplete:A,disabled:D}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),D&&(0,H.jsxs)(`div`,{className:`gate-loading`,children:[(0,H.jsx)(`span`,{className:`spinner`}),`Verifying...`]}),(0,H.jsx)(`div`,{className:`gate-resend`,children:(0,H.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{t(`sign-in`),v(``),w(null)},children:`Use a different number`})})]})});case`sign-in`:case`private-agent`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`h2`,{className:`gate-title`,children:e===`private-agent`?`Private Agent`:`Welcome back`}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:e===`private-agent`?`This agent is invitation-only. If you have an account, sign in below.`:`Sign in to continue your conversation.`}),x?(0,H.jsxs)(`form`,{className:`gate-form`,onSubmit:N,children:[(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-forgot-contact`,children:`Email or phone`}),(0,H.jsx)(`input`,{id:`gate-forgot-contact`,type:`text`,value:s,onChange:e=>c(e.target.value),placeholder:`you@example.com`,autoFocus:!0,autoComplete:`email`})]}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),T&&(0,H.jsx)(`div`,{className:`gate-success`,children:T}),(0,H.jsx)(`div`,{className:`gate-submit`,children:(0,H.jsx)(g,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!s.trim()||D,loading:D,children:`Send reset link`})}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{S(!1),w(null),E(null)},children:`Back to sign in`})})]}):(0,H.jsxs)(`form`,{className:`gate-form`,onSubmit:k,children:[(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-contact`,children:`Email or phone`}),(0,H.jsx)(`input`,{id:`gate-contact`,type:`text`,value:s,onChange:e=>c(e.target.value),placeholder:`you@example.com`,autoFocus:!0,autoComplete:`email`})]}),(0,H.jsxs)(`div`,{className:`gate-field gate-pw-row`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-login-pw`,children:`Password`}),(0,H.jsx)(`div`,{className:`gate-pw-toggle`,children:(0,H.jsx)(h,{checked:p,onChange:m,label:`Show`})}),(0,H.jsx)(`input`,{id:`gate-login-pw`,type:p?`text`:`password`,value:l,onChange:e=>u(e.target.value),placeholder:`Your password`,autoComplete:`current-password`})]}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),(0,H.jsx)(`div`,{className:`gate-submit`,children:(0,H.jsx)(g,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!s.trim()||!l||D,loading:D,children:`Sign in`})}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{S(!0),w(null)},children:`Forgot password?`})})]}),e===`private-agent`&&(0,H.jsx)(`p`,{className:`gate-hint`,children:`No account? You need an invitation from the agent owner.`})]})});case`access-expired`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`div`,{className:`gate-icon`,children:`⏰`}),(0,H.jsx)(`h2`,{className:`gate-title`,children:`Access expired`}),(0,H.jsxs)(`p`,{className:`gate-subtitle`,children:[n?.expiresAt?`Your access expired on ${new Date(n.expiresAt).toLocaleDateString(`en-GB`,{day:`numeric`,month:`long`,year:`numeric`})}.`:`Your access to this agent has expired.`,` `,`Contact the agent owner to renew.`]}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(g,{variant:`secondary`,onClick:()=>{t(`sign-in`),w(null),u(``)},children:`Sign in with a different account`})})]})});case`link-expired`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`div`,{className:`gate-icon`,children:`⚠️`}),(0,H.jsx)(`h2`,{className:`gate-title`,children:`Link expired`}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:`This invitation link has expired or has already been used. If you already set your password, sign in below. Otherwise, ask the agent owner to send a new invitation.`}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(g,{variant:`primary`,onClick:()=>{t(`sign-in`),w(null)},children:`Go to sign in`})})]})});case`otp-failed`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`div`,{className:`gate-icon`,children:`⛔`}),(0,H.jsx)(`h2`,{className:`gate-title`,children:`Too many attempts`}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:`You've entered the wrong code too many times. Ask the agent owner to send a new code.`}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(g,{variant:`secondary`,onClick:()=>{t(`sign-in`),w(null),v(``)},children:`Back to sign in`})})]})})}}var W={"single-select":m,"multi-select":S,"action-buttons":b};function G({name:e,data:t,onSubmit:n,submitted:r}){let i=W[e];return i?(0,H.jsx)(i,{data:t,onSubmit:n,submitted:r}):(console.warn(`[PublicComponentRenderer] Unknown component: "${e}". Registered: ${Object.keys(W).join(`, `)}`),(0,H.jsx)(`div`,{className:`component-card component-card--error`,children:(0,H.jsxs)(`p`,{style:{fontFamily:`var(--font-body)`,fontSize:12,color:`var(--text-secondary)`},children:[`Component “`,e,`” is not available. This may require a platform update.`]})}))}function re({messages:e,isStreaming:t,sessionError:n,selectionMode:r,selectedItems:i,toggleSelectItem:c,onComponentSubmit:l,remainingSuggestions:u,onSuggestionClick:d,isAtBottom:p,setIsAtBottom:m,isGroup:_}){let[v,y]=(0,j.useState)(new Set),[b,x]=(0,j.useState)(new Set),S=(0,j.useRef)(null),C=(0,j.useRef)(null),T=(0,j.useRef)(null),E=(0,j.useRef)(!1),D=(0,j.useRef)(!1),O=(0,j.useRef)(!1),k=(0,j.useRef)(0),A=(0,j.useRef)(!1),M=(0,j.useRef)(new Map);A.current=t,(0,j.useEffect)(()=>{t&&!E.current&&p&&(D.current=!0)},[t,p]),(0,j.useEffect)(()=>{if(!D.current&&!p){E.current=t,O.current=!1;return}if(E.current&&!t&&T.current&&C.current){let e=T.current;if(e.offsetHeight>C.current.clientHeight){D.current=!1,O.current=!0,e.scrollIntoView({behavior:`smooth`,block:`start`}),E.current=t;return}}(p||D.current)&&!O.current&&S.current?.scrollIntoView({behavior:`smooth`}),E.current&&!t&&(D.current=!1),E.current=t},[e,p,t]),(0,j.useEffect)(()=>{let e=C.current;if(!e)return;let t=()=>{let t=e.scrollTop;A.current&&t<k.current&&(D.current=!1),k.current=t,m(e.scrollHeight-e.scrollTop-e.clientHeight<80)};return e.addEventListener(`scroll`,t,{passive:!0}),t(),()=>e.removeEventListener(`scroll`,t)},[m]),(0,j.useEffect)(()=>{function e(){x(e=>{let t=new Set;return M.current.forEach((n,r)=>{n.isConnected&&(v.has(r)?e.has(r)&&t.add(r):n.scrollHeight>n.clientHeight+2&&t.add(r))}),e.size===t.size&&[...e].every(e=>t.has(e))?e:t})}e();let t=new ResizeObserver(e);return M.current.forEach(e=>t.observe(e)),()=>t.disconnect()},[e.length,v]);let N=e.reduce((e,t,n)=>t.role===`maxy`&&!t.hidden?n:e,-1);return(0,H.jsxs)(`div`,{className:`chat-messages-wrap`,children:[r&&(0,H.jsx)(`div`,{className:`selection-overlay-band`}),(0,H.jsxs)(`div`,{className:`chat-messages`,ref:C,children:[n&&e.length===0&&(0,H.jsx)(`div`,{className:`session-error`,children:(0,H.jsx)(`p`,{children:n})}),e.map((n,u)=>{if(n.hidden)return null;let d=t&&u===e.length-1,p=`${n.timestamp}_${n.role}`,m=i.has(p);return(0,H.jsxs)(`div`,{ref:u===N?T:void 0,className:`message ${n.role}${m?` selected`:``}`,children:[r&&!d&&(0,H.jsx)(`div`,{className:`message-select-check`,children:(0,H.jsx)(h,{checked:m,onChange:()=>c(p)})}),(0,H.jsxs)(`div`,{className:`bubble`,children:[_&&n.role===`visitor`&&n.senderName&&(0,H.jsx)(`span`,{className:`bubble-sender`,children:n.senderName}),n.role===`visitor`&&n.content?(()=>{let e=v.has(u),t=b.has(u);return(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{ref:e=>{e?M.current.set(u,e):M.current.delete(u)},className:e?`bubble-content`:`bubble-content clamped${t?` overflowing`:``}`,children:n.content}),t&&(0,H.jsx)(`div`,{className:`bubble-expand`,children:(0,H.jsx)(g,{variant:`icon`,className:e?`expanded`:``,onClick:()=>y(e=>{let t=new Set(e);return t.has(u)?t.delete(u):t.add(u),t}),"aria-label":e?`Collapse message`:`Expand message`,children:(0,H.jsx)(a,{size:14})})})]})})():n.content?(0,H.jsx)(w,{content:n.content,timestamp:f(n.timestamp)}):(0,H.jsxs)(`span`,{className:`typing-indicator`,children:[(0,H.jsx)(`span`,{className:`typing-dot`}),(0,H.jsx)(`span`,{className:`typing-dot`}),(0,H.jsx)(`span`,{className:`typing-dot`})]}),n.attachments&&n.attachments.length>0&&(0,H.jsx)(`div`,{className:`message-attachments`,children:n.attachments.map((e,t)=>(0,H.jsxs)(`span`,{className:`message-attachment-chip no-action`,children:[e.mimeType===`application/pdf`?(0,H.jsx)(o,{size:12}):e.mimeType.startsWith(`text/`)?(0,H.jsx)(s,{size:12}):null,(0,H.jsx)(`span`,{children:e.filename})]},t))}),n.role===`visitor`&&(0,H.jsx)(`span`,{className:`message-timestamp`,children:f(n.timestamp)})]}),n.role===`maxy`&&n.components&&n.components.length>0&&(0,H.jsx)(`div`,{className:`public-components`,children:n.components.map((e,t)=>(0,H.jsx)(`div`,{className:`public-component-enter`,children:(0,H.jsx)(G,{name:e.name,data:e.data,onSubmit:e=>l(u,t,e),submitted:e.submitted})},t))})]},u)}),!t&&u.length>0&&(0,H.jsx)(`div`,{className:`chat-suggestions`,children:u.map(e=>(0,H.jsx)(g,{variant:`suggestion`,onClick:()=>d(e),children:e},e))}),(0,H.jsx)(`div`,{ref:S})]}),!p&&(0,H.jsx)(`button`,{className:`scroll-to-bottom`,onClick:()=>S.current?.scrollIntoView({behavior:`smooth`}),"aria-label":`Scroll to bottom`,children:(0,H.jsx)(a,{size:18})})]})}function ie({selectedItems:e,messages:t,copySelected:r,exitSelection:a,showCopyToast:o}){let[s,c]=(0,j.useState)(!1),l=(0,j.useRef)(null),u=(0,j.useRef)(!1);function d(e){let n=e.lastIndexOf(`_`),r=e.slice(0,n),i=e.slice(n+1),a=parseInt(r,10);return t.find(e=>e.timestamp===a&&e.role===i)?.content??``}function f(e,t){return parseInt(e.slice(0,e.lastIndexOf(`_`)),10)-parseInt(t.slice(0,t.lastIndexOf(`_`)),10)}function p(){let e=[...t].sort((e,t)=>e.timestamp-t.timestamp),n=[];for(let t of e){if(t.hidden||!t.content)continue;let e=t.role===`visitor`?`Visitor`:`Maxy`;n.push(`${e}:\n${t.content}`)}return n.join(`
|
|
1
|
+
import{o as e}from"./chunk-Be6NvmcD.js";import{A as t,C as n,D as r,F as i,I as a,N as o,P as s,R as c,S as l,V as u,_ as d,a as f,b as p,c as m,g as h,h as g,i as _,j as v,n as y,o as b,r as x,s as S,t as C,u as w,v as T,w as E,y as D,z as O}from"./useVoiceRecorder-3Qblv7wH.js";var k=c(`square-plus`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M8 12h8`,key:`1wcyev`}],[`path`,{d:`M12 8v8`,key:`napkw2`}]]),A=O(),j=e(u(),1),M=`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar`,N=new Set(M.split(`,`)),P=20*1024*1024,F=typeof window<`u`&&/^(localhost|127\.0\.0\.1|[a-z0-9-]+\.local)(:|$)/.test(window.location.hostname);function I(){let e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;let t=[...e].map(e=>e.toString(16).padStart(2,`0`)).join(``);return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}function L(){let e=window.location.pathname;if(e.startsWith(`/g/`))return;let t=e.match(/^\/([a-z][a-z0-9-]{2,49})$/);return t?t[1]:void 0}function R(){let e=window.location.pathname.match(/^\/g\/([a-z0-9][a-z0-9-]{0,49})$/);return e?e[1]:void 0}function z(e){return[{key:`length`,label:`At least 8 characters`,met:e.length>=8},{key:`number`,label:`Contains a number`,met:/\d/.test(e)},{key:`special`,label:`Contains a special character`,met:/[^A-Za-z0-9]/.test(e)},{key:`whitespace`,label:`No spaces`,met:e.length>0&&!/\s/.test(e)}]}function B(e,t){if(t===`phone`)return e.length>4?e.slice(0,e.length-4).replace(/\d/g,`•`)+` `+e.slice(-4):e;let n=e.indexOf(`@`);return n<=2?e:e.slice(0,2)+`•••`+e.slice(n)}function V(e){let[t,n]=(0,j.useState)(null),[r,i]=(0,j.useState)(null),[a,o]=(0,j.useState)(`loading`),[s,c]=(0,j.useState)(``),[l,u]=(0,j.useState)(null),[d,f]=(0,j.useState)(null),[p,m]=(0,j.useState)(!1),[h,g]=(0,j.useState)(null),_=(0,j.useMemo)(()=>L(),[]),v=(0,j.useMemo)(()=>R(),[]),[y,b]=(0,j.useState)(null),x=(0,j.useRef)(_||``),S=(0,j.useRef)(null),C=(0,j.useRef)(null),w=(0,j.useRef)(!1),T=(0,j.useRef)(null),[E,D]=(0,j.useState)(`sign-in`),[O,k]=(0,j.useState)(null),A=(0,j.useRef)(null),M=(0,j.useRef)(null);(0,j.useEffect)(()=>{try{let e=sessionStorage.getItem(`maxy_session`);e&&(M.current=e)}catch{}},[]);let N=(0,j.useCallback)(t=>{S.current=t,n(t);try{sessionStorage.setItem(`maxy_session`,t)}catch{}o(`chat`),e(t)},[e]),P=(0,j.useCallback)(()=>{S.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}n(null),o(`auth-required`),D(`sign-in`)},[]),z=(0,j.useCallback)(async e=>{try{let t=x.current,n=await fetch(`/api/access/verify-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:e,agentSlug:t})}),r=await n.json();n.ok?(A.current=r.session_key,k(r.grant),D(`set-password`),window.history.replaceState({},``,window.location.pathname)):D(`link-expired`)}catch{D(`sign-in`)}},[]),B=(0,j.useCallback)(async()=>{if(S.current)return S.current;if(C.current)return C.current;let e=(async()=>{try{let e=M.current,t=await fetch(`/api/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_id:I(),..._?{agent:_}:{},...v?{group_slug:v}:{},...e?{session_key:e}:{}})});if(!t.ok){let e=await t.json().catch(()=>({error:``}));return F&&console.error(`[session] POST /api/session failed: ${t.status} ${t.statusText}`,e),t.status===404?i(e.error||`Agent not found`):t.status===503&&i(e.error||`Service unavailable`),null}let r=await t.json();if(r.auth_required){r.agent_id&&(x.current=r.agent_id),c(r.displayName||``),r.agentImage&&u(r.agentImage),r.agentImageShape&&f(r.agentImageShape),r.showAgentName&&m(r.showAgentName),r.branding&&g(r.branding),o(`auth-required`);let e=new URLSearchParams(window.location.search).get(`token`);return e?z(e):D(`sign-in`),null}S.current=r.session_key,n(r.session_key),r.displayName&&c(r.displayName),r.agentImage&&u(r.agentImage),r.agentImageShape&&f(r.agentImageShape),r.showAgentName&&m(r.showAgentName),r.branding&&g(r.branding),o(`chat`),r.resumed&&r.messages&&(w.current=!0,T.current=r.messages),r.group&&b({groupSlug:r.groupSlug,groupName:r.groupName,participants:r.participants??[]});try{sessionStorage.setItem(`maxy_session`,r.session_key)}catch{}return r.session_key}catch(e){return F&&console.error(`[session] fetch /api/session threw:`,e),i(`Unable to connect. Please check your connection and try again.`),null}finally{C.current=null}})();return C.current=e,e},[_,v,z]);return{sessionId:t,sessionKeyRef:S,sessionError:r,pageState:a,setPageState:o,agentDisplayName:s,agentImage:l,agentImageShape:d,showAgentName:p,agentSlug:_,branding:h,resolvedSlugRef:x,ensureSession:B,startNewSession:(0,j.useCallback)(async()=>{S.current=null,C.current=null,M.current=null,w.current=!1,T.current=null,n(null),i(null);try{sessionStorage.removeItem(`maxy_session`)}catch{}let t=await B();t&&e(t)},[B,e]),enterChat:N,enterGate:P,resumedRef:w,resumeMessagesRef:T,gateState:E,setGateState:D,grantInfo:O,setGrantInfo:k,gateSessionKeyRef:A,groupContext:y,groupSlug:v}}function ee({sessionKeyRef:e,ensureSession:t,sessionError:n,pageState:r,inputRef:i}){let[a,o]=(0,j.useState)([]),[s,c]=(0,j.useState)(!1),u=(0,j.useRef)(!1),d=e=>{u.current=e,c(e)},f=(0,j.useCallback)(async a=>{if(!u.current){d(!0),o([{role:`maxy`,content:``,timestamp:Date.now()}]);try{let n=await fetch(`/api/chat`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({greeting:!0,session_key:a})});if(n.status===401){e.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}F&&console.warn(`[greeting] stale session, retrying with fresh session`);let r=await t();if(!r)return;n=await fetch(`/api/chat`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({greeting:!0,session_key:r})})}if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Something went wrong`)}let r=``,i=``,s=()=>{i&&(r+=i,i=``,o(e=>{let t=[...e];return t[0]={...t[0],content:r},t}))},c=setInterval(s,60);try{for await(let e of l(n)){if(e.error)throw Object.assign(Error(e.error),{fromSSE:!0});e.text&&(i+=e.text),e.type===`component`&&(s(),o(t=>{let n=[...t],r={...n[0]},i=[...r.components||[]];return i.push({name:e.name,data:e.data,submitted:!1}),n[0]={...r,components:i},n}))}}finally{clearInterval(c),s()}}catch(e){if(F&&console.error(`[chat] greeting failed:`,e),r===`auth-required`)return;let t=e instanceof Error?e.message:String(e);o([{role:`maxy`,content:e instanceof Error&&e.fromSSE?t:n??`I'm having trouble connecting right now. Try refreshing the page.`,timestamp:Date.now()}])}finally{d(!1),r===`chat`&&i.current?.focus()}}},[e,t,n,r,i]),p=(0,j.useCallback)(async(a,s)=>{let c=s?.hidden??!1,f=s?.files??[];if(!a&&f.length===0||u.current)return;d(!0);let p=f.map(e=>({filename:e.name,mimeType:e.type})),m={role:`visitor`,content:a,attachments:p.length>0?p:void 0,timestamp:Date.now(),hidden:c},h;o(e=>{let t=[...e,m,{role:`maxy`,content:``,timestamp:Date.now()}];return h=t.length-1,t});try{let n=await t();if(!n)throw Error(`session`);let r=e=>{if(f.length>0){let t=new FormData;t.append(`message`,a),t.append(`session_key`,e);for(let e of f)t.append(`attachments`,e);return{body:t,headers:{}}}return{body:JSON.stringify({message:a,session_key:e}),headers:{"Content-Type":`application/json`}}},{body:i,headers:s}=r(n),c=await fetch(`/api/chat`,{method:`POST`,headers:s,body:i});if(c.status===401){e.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}F&&console.warn(`[session-expired] stale key cleared, retrying with fresh session`);let n=await t();if(!n)throw Error(`session`);({body:i,headers:s}=r(n)),c=await fetch(`/api/chat`,{method:`POST`,headers:s,body:i})}if(!c.ok){let e=await c.json().catch(()=>({}));throw Error(e.error||`Something went wrong`)}let u=``,d=``,p=()=>{d&&(u+=d,d=``,o(e=>{let t=[...e];return t[h]={...t[h],content:u},t}))},m=setInterval(p,60);try{for await(let e of l(c)){if(e.error)throw Object.assign(Error(e.error),{fromSSE:!0});e.text&&(d+=e.text),e.type===`component`&&(p(),o(t=>{let n=[...t],r={...n[h]},i=[...r.components||[]];return i.push({name:e.name,data:e.data,submitted:!1}),n[h]={...r,components:i},n}))}}finally{clearInterval(m),p()}}catch(e){if(F&&console.error(`[chat] sendMessage failed:`,e),r===`auth-required`)return;let t=e instanceof Error?e.message:String(e),i=e instanceof Error&&e.fromSSE;o(e=>{let r=[...e];return r[h]={...r[h],content:i?t:t===`session`?n??`I'm having trouble connecting right now. Try refreshing the page.`:`Sorry, I hit a snag. Try again in a moment.`},r})}finally{d(!1),r===`chat`&&i.current?.focus()}},[e,t,n,r,i]);return{messages:a,setMessages:o,isStreaming:s,sendMessage:p,sendGreeting:f,handleComponentSubmit:(0,j.useCallback)((e,t,n)=>{o(n=>{let r=[...n],i={...r[e]},a=[...i.components||[]];return a[t]={...a[t],submitted:!0},r[e]={...i,components:a},r}),p(n,{hidden:!0})},[p])}}function te({sessionKeyRef:e,groupSlug:t,isStreaming:n,setMessages:r}){let i=(0,j.useRef)(new Date().toISOString()),a=(0,j.useRef)(!0);(0,j.useEffect)(()=>{let e=()=>{a.current=document.visibilityState===`visible`};return document.addEventListener(`visibilitychange`,e),()=>document.removeEventListener(`visibilitychange`,e)},[]);let o=(0,j.useCallback)(async()=>{let n=e.current;if(!(!n||!t))try{let e=await fetch(`/api/group/messages?session_key=${encodeURIComponent(n)}&since=${encodeURIComponent(i.current)}`);if(!e.ok)return;let t=await e.json();if(!t.messages||t.messages.length===0)return;let a=t.messages[t.messages.length-1];a.timestamp&&(i.current=new Date(a.timestamp).toISOString()),r(e=>{let n=new Set(e.filter(e=>e.messageId).map(e=>e.messageId)),r=t.messages.filter(e=>!n.has(e.messageId)).map(e=>({role:e.role,content:e.content,timestamp:e.timestamp,senderName:e.senderName??void 0,senderVisitorId:e.senderVisitorId??void 0,messageId:e.messageId}));return r.length===0?e:[...e,...r]})}catch{}},[e,t,r]);(0,j.useEffect)(()=>{if(!t)return;let e,r=!1;function i(){if(r)return;let t=a.current?3e3:3e4;e=setTimeout(async()=>{n||await o(),i()},t)}return i(),()=>{r=!0,clearTimeout(e)}},[t,n,o])}var H=d();function U({value:e,onChange:t,onComplete:n,disabled:r}){let i=(0,j.useRef)([]);function a(n,r){r.key===`Backspace`?(r.preventDefault(),e[n]?t(e.slice(0,n)+e.slice(n+1)):n>0&&(t(e.slice(0,n-1)+e.slice(n)),i.current[n-1]?.focus())):r.key===`ArrowLeft`&&n>0?i.current[n-1]?.focus():r.key===`ArrowRight`&&n<5&&i.current[n+1]?.focus()}function o(r,a){let o=a.nativeEvent.data;if(!o||!/^\d$/.test(o))return;let s=e.split(``);for(s[r]=o;s.length<r;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);t(c),c.length===6?n(c):r<5&&i.current[r+1]?.focus()}function s(e){e.preventDefault();let r=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);r&&(t(r),r.length===6?n(r):i.current[r.length]?.focus())}return(0,H.jsx)(`div`,{className:`gate-otp-field`,children:Array.from({length:6}).map((t,n)=>(0,H.jsx)(`input`,{ref:e=>{i.current[n]=e},type:`text`,inputMode:`numeric`,className:`pin-box${e[n]?` pin-box-filled`:``}`,value:e[n]||``,onKeyDown:e=>a(n,e),onInput:e=>o(n,e),onPaste:s,onFocus:e=>e.target.select(),autoFocus:n===0,autoComplete:`off`,maxLength:1,disabled:r,"aria-label":`Code digit ${n+1}`},n))})}function ne({gateState:e,setGateState:t,grantInfo:n,setGrantInfo:r,gateSessionKeyRef:i,resolvedSlugRef:a,onAuthenticated:o}){let[s,c]=(0,j.useState)(``),[l,u]=(0,j.useState)(``),[d,f]=(0,j.useState)(``),[p,m]=(0,j.useState)(!1),[_,v]=(0,j.useState)(``),[y,b]=(0,j.useState)(``),[x,S]=(0,j.useState)(!1),[C,w]=(0,j.useState)(null),[T,E]=(0,j.useState)(null),[D,O]=(0,j.useState)(!1);async function k(e){if(e.preventDefault(),!D){w(null),O(!0);try{let e=a.current,n=await fetch(`/api/access/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contact:s,password:l,agentSlug:e})}),i=await n.json();n.ok?o(i.session_key):n.status===401?i.error?.includes(`setup not complete`)||i.error?.includes(`invitation link`)?(t(`private-agent`),w(null)):w(i.error||`Invalid credentials`):n.status===403?(t(`access-expired`),i.expiresAt&&r(e=>e?{...e,expiresAt:i.expiresAt}:{displayName:null,contactValue:s,contactMethod:`email`,expiresAt:i.expiresAt,status:`expired`})):n.status===429?w(i.error||`Too many attempts. Please try again later.`):w(i.error||`Something went wrong`)}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}async function A(e){if(!D){w(null),O(!0);try{let n=a.current,o=await fetch(`/api/access/verify-otp`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({phone:y,code:e,agentSlug:n})}),s=await o.json();o.ok?(i.current=s.session_key,r(s.grant),t(`set-password`)):o.status===429?t(`otp-failed`):(w(s.error||`Invalid code`),v(``))}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}async function M(e){if(e.preventDefault(),!D){if(w(null),l!==d){w(`Passwords do not match`);return}if(!z(l).every(e=>e.met)){w(`Password does not meet requirements`);return}O(!0);try{let e=i.current;if(!e){w(`Session expired. Please use your invitation link again.`);return}let t=await fetch(`/api/access/create-credentials`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_key:e,password:l})}),n=await t.json();t.ok?o(n.session_key):t.status===400&&n.requirements?w(n.requirements.filter(e=>!e.met).map(e=>e.label).join(`, `)):w(n.error||`Something went wrong`)}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}async function N(e){if(e.preventDefault(),!(D||!s)){w(null),O(!0);try{let e=a.current,t=await fetch(`/api/access/forgot-password`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contact:s,agentSlug:e})});t.status===429?w((await t.json()).error||`Too many attempts. Please try again later.`):(E(`If an account exists, a reset link has been sent.`),setTimeout(()=>{S(!1),E(null)},4e3))}catch{w(`Unable to connect. Please try again.`)}finally{O(!1)}}}switch(e){case`set-password`:{let e=z(l),t=e.every(e=>e.met),r=l===d,i=t&&r&&d.length>0;return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[n?.expiresAt&&(0,H.jsxs)(`div`,{className:`gate-expiry-badge`,children:[`Access until `,new Date(n.expiresAt).toLocaleDateString(`en-GB`,{day:`numeric`,month:`short`,year:`numeric`})]}),(0,H.jsxs)(`h2`,{className:`gate-title`,children:[`Welcome, `,n?.displayName||`there`]}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:`Create a password to access this agent in the future.`}),(0,H.jsxs)(`form`,{className:`gate-form`,onSubmit:M,children:[(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-display-name`,children:`Display name`}),(0,H.jsx)(`input`,{id:`gate-display-name`,type:`text`,value:n?.displayName||``,disabled:!0})]}),(0,H.jsxs)(`div`,{className:`gate-field gate-pw-row`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-pw`,children:`Password`}),(0,H.jsx)(`div`,{className:`gate-pw-toggle`,children:(0,H.jsx)(h,{checked:p,onChange:m,label:`Show`})}),(0,H.jsx)(`input`,{id:`gate-pw`,type:p?`text`:`password`,value:l,onChange:e=>u(e.target.value),placeholder:`Your password`,autoFocus:!0,autoComplete:`new-password`}),l.length>0&&(0,H.jsx)(`div`,{className:`gate-strength`,children:e.map(e=>(0,H.jsxs)(`span`,{className:`gate-strength-item${e.met?` met`:``}`,children:[e.met?`✓`:`○`,` `,e.label]},e.key))})]}),(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-pw-confirm`,children:`Confirm password`}),(0,H.jsx)(`input`,{id:`gate-pw-confirm`,type:p?`text`:`password`,value:d,onChange:e=>f(e.target.value),placeholder:`Confirm your password`,autoComplete:`new-password`}),d.length>0&&!r&&(0,H.jsx)(`div`,{className:`gate-error`,children:`Passwords do not match`})]}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),(0,H.jsx)(`div`,{className:`gate-submit`,children:(0,H.jsx)(g,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!i||D,loading:D,children:`Create account & enter chat`})})]})]})})}case`enter-otp`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`h2`,{className:`gate-title`,children:`Enter your code`}),(0,H.jsxs)(`p`,{className:`gate-subtitle`,children:[`Enter the 6-digit code sent to `,B(y,`phone`)]}),(0,H.jsx)(U,{value:_,onChange:v,onComplete:A,disabled:D}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),D&&(0,H.jsxs)(`div`,{className:`gate-loading`,children:[(0,H.jsx)(`span`,{className:`spinner`}),`Verifying...`]}),(0,H.jsx)(`div`,{className:`gate-resend`,children:(0,H.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{t(`sign-in`),v(``),w(null)},children:`Use a different number`})})]})});case`sign-in`:case`private-agent`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`h2`,{className:`gate-title`,children:e===`private-agent`?`Private Agent`:`Welcome back`}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:e===`private-agent`?`This agent is invitation-only. If you have an account, sign in below.`:`Sign in to continue your conversation.`}),x?(0,H.jsxs)(`form`,{className:`gate-form`,onSubmit:N,children:[(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-forgot-contact`,children:`Email or phone`}),(0,H.jsx)(`input`,{id:`gate-forgot-contact`,type:`text`,value:s,onChange:e=>c(e.target.value),placeholder:`you@example.com`,autoFocus:!0,autoComplete:`email`})]}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),T&&(0,H.jsx)(`div`,{className:`gate-success`,children:T}),(0,H.jsx)(`div`,{className:`gate-submit`,children:(0,H.jsx)(g,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!s.trim()||D,loading:D,children:`Send reset link`})}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{S(!1),w(null),E(null)},children:`Back to sign in`})})]}):(0,H.jsxs)(`form`,{className:`gate-form`,onSubmit:k,children:[(0,H.jsxs)(`div`,{className:`gate-field`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-contact`,children:`Email or phone`}),(0,H.jsx)(`input`,{id:`gate-contact`,type:`text`,value:s,onChange:e=>c(e.target.value),placeholder:`you@example.com`,autoFocus:!0,autoComplete:`email`})]}),(0,H.jsxs)(`div`,{className:`gate-field gate-pw-row`,children:[(0,H.jsx)(`label`,{htmlFor:`gate-login-pw`,children:`Password`}),(0,H.jsx)(`div`,{className:`gate-pw-toggle`,children:(0,H.jsx)(h,{checked:p,onChange:m,label:`Show`})}),(0,H.jsx)(`input`,{id:`gate-login-pw`,type:p?`text`:`password`,value:l,onChange:e=>u(e.target.value),placeholder:`Your password`,autoComplete:`current-password`})]}),C&&(0,H.jsx)(`div`,{className:`gate-error`,children:C}),(0,H.jsx)(`div`,{className:`gate-submit`,children:(0,H.jsx)(g,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!s.trim()||!l||D,loading:D,children:`Sign in`})}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{S(!0),w(null)},children:`Forgot password?`})})]}),e===`private-agent`&&(0,H.jsx)(`p`,{className:`gate-hint`,children:`No account? You need an invitation from the agent owner.`})]})});case`access-expired`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`div`,{className:`gate-icon`,children:`⏰`}),(0,H.jsx)(`h2`,{className:`gate-title`,children:`Access expired`}),(0,H.jsxs)(`p`,{className:`gate-subtitle`,children:[n?.expiresAt?`Your access expired on ${new Date(n.expiresAt).toLocaleDateString(`en-GB`,{day:`numeric`,month:`long`,year:`numeric`})}.`:`Your access to this agent has expired.`,` `,`Contact the agent owner to renew.`]}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(g,{variant:`secondary`,onClick:()=>{t(`sign-in`),w(null),u(``)},children:`Sign in with a different account`})})]})});case`link-expired`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`div`,{className:`gate-icon`,children:`⚠️`}),(0,H.jsx)(`h2`,{className:`gate-title`,children:`Link expired`}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:`This invitation link has expired or has already been used. If you already set your password, sign in below. Otherwise, ask the agent owner to send a new invitation.`}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(g,{variant:`primary`,onClick:()=>{t(`sign-in`),w(null)},children:`Go to sign in`})})]})});case`otp-failed`:return(0,H.jsx)(`div`,{className:`gate-wrap`,children:(0,H.jsxs)(`div`,{className:`gate-card`,children:[(0,H.jsx)(`div`,{className:`gate-icon`,children:`⛔`}),(0,H.jsx)(`h2`,{className:`gate-title`,children:`Too many attempts`}),(0,H.jsx)(`p`,{className:`gate-subtitle`,children:`You've entered the wrong code too many times. Ask the agent owner to send a new code.`}),(0,H.jsx)(`div`,{className:`gate-actions`,children:(0,H.jsx)(g,{variant:`secondary`,onClick:()=>{t(`sign-in`),w(null),v(``)},children:`Back to sign in`})})]})})}}var W={"single-select":m,"multi-select":S,"action-buttons":b};function G({name:e,data:t,onSubmit:n,submitted:r}){let i=W[e];return i?(0,H.jsx)(i,{data:t,onSubmit:n,submitted:r}):(console.warn(`[PublicComponentRenderer] Unknown component: "${e}". Registered: ${Object.keys(W).join(`, `)}`),(0,H.jsx)(`div`,{className:`component-card component-card--error`,children:(0,H.jsxs)(`p`,{style:{fontFamily:`var(--font-body)`,fontSize:12,color:`var(--text-secondary)`},children:[`Component “`,e,`” is not available. This may require a platform update.`]})}))}function re({messages:e,isStreaming:t,sessionError:n,selectionMode:r,selectedItems:i,toggleSelectItem:c,onComponentSubmit:l,remainingSuggestions:u,onSuggestionClick:d,isAtBottom:p,setIsAtBottom:m,isGroup:_}){let[v,y]=(0,j.useState)(new Set),[b,x]=(0,j.useState)(new Set),S=(0,j.useRef)(null),C=(0,j.useRef)(null),T=(0,j.useRef)(null),E=(0,j.useRef)(!1),D=(0,j.useRef)(!1),O=(0,j.useRef)(!1),k=(0,j.useRef)(0),A=(0,j.useRef)(!1),M=(0,j.useRef)(new Map);A.current=t,(0,j.useEffect)(()=>{t&&!E.current&&p&&(D.current=!0)},[t,p]),(0,j.useEffect)(()=>{if(!D.current&&!p){E.current=t,O.current=!1;return}if(E.current&&!t&&T.current&&C.current){let e=T.current;if(e.offsetHeight>C.current.clientHeight){D.current=!1,O.current=!0,e.scrollIntoView({behavior:`smooth`,block:`start`}),E.current=t;return}}(p||D.current)&&!O.current&&S.current?.scrollIntoView({behavior:`smooth`}),E.current&&!t&&(D.current=!1),E.current=t},[e,p,t]),(0,j.useEffect)(()=>{let e=C.current;if(!e)return;let t=()=>{let t=e.scrollTop;A.current&&t<k.current&&(D.current=!1),k.current=t,m(e.scrollHeight-e.scrollTop-e.clientHeight<80)};return e.addEventListener(`scroll`,t,{passive:!0}),t(),()=>e.removeEventListener(`scroll`,t)},[m]),(0,j.useEffect)(()=>{function e(){x(e=>{let t=new Set;return M.current.forEach((n,r)=>{n.isConnected&&(v.has(r)?e.has(r)&&t.add(r):n.scrollHeight>n.clientHeight+2&&t.add(r))}),e.size===t.size&&[...e].every(e=>t.has(e))?e:t})}e();let t=new ResizeObserver(e);return M.current.forEach(e=>t.observe(e)),()=>t.disconnect()},[e.length,v]);let N=e.reduce((e,t,n)=>t.role===`maxy`&&!t.hidden?n:e,-1);return(0,H.jsxs)(`div`,{className:`chat-messages-wrap`,children:[r&&(0,H.jsx)(`div`,{className:`selection-overlay-band`}),(0,H.jsxs)(`div`,{className:`chat-messages`,ref:C,children:[n&&e.length===0&&(0,H.jsx)(`div`,{className:`session-error`,children:(0,H.jsx)(`p`,{children:n})}),e.map((n,u)=>{if(n.hidden)return null;let d=t&&u===e.length-1,p=`${n.timestamp}_${n.role}`,m=i.has(p);return(0,H.jsxs)(`div`,{ref:u===N?T:void 0,className:`message ${n.role}${m?` selected`:``}`,children:[r&&!d&&(0,H.jsx)(`div`,{className:`message-select-check`,children:(0,H.jsx)(h,{checked:m,onChange:()=>c(p)})}),(0,H.jsxs)(`div`,{className:`bubble`,children:[_&&n.role===`visitor`&&n.senderName&&(0,H.jsx)(`span`,{className:`bubble-sender`,children:n.senderName}),n.role===`visitor`&&n.content?(()=>{let e=v.has(u),t=b.has(u);return(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{ref:e=>{e?M.current.set(u,e):M.current.delete(u)},className:e?`bubble-content`:`bubble-content clamped${t?` overflowing`:``}`,children:n.content}),t&&(0,H.jsx)(`div`,{className:`bubble-expand`,children:(0,H.jsx)(g,{variant:`icon`,className:e?`expanded`:``,onClick:()=>y(e=>{let t=new Set(e);return t.has(u)?t.delete(u):t.add(u),t}),"aria-label":e?`Collapse message`:`Expand message`,children:(0,H.jsx)(a,{size:14})})})]})})():n.content?(0,H.jsx)(w,{content:n.content,timestamp:f(n.timestamp)}):(0,H.jsxs)(`span`,{className:`typing-indicator`,children:[(0,H.jsx)(`span`,{className:`typing-dot`}),(0,H.jsx)(`span`,{className:`typing-dot`}),(0,H.jsx)(`span`,{className:`typing-dot`})]}),n.attachments&&n.attachments.length>0&&(0,H.jsx)(`div`,{className:`message-attachments`,children:n.attachments.map((e,t)=>(0,H.jsxs)(`span`,{className:`message-attachment-chip no-action`,children:[e.mimeType===`application/pdf`?(0,H.jsx)(o,{size:12}):e.mimeType.startsWith(`text/`)?(0,H.jsx)(s,{size:12}):null,(0,H.jsx)(`span`,{children:e.filename})]},t))}),n.role===`visitor`&&(0,H.jsx)(`span`,{className:`message-timestamp`,children:f(n.timestamp)})]}),n.role===`maxy`&&n.components&&n.components.length>0&&(0,H.jsx)(`div`,{className:`public-components`,children:n.components.map((e,t)=>(0,H.jsx)(`div`,{className:`public-component-enter`,children:(0,H.jsx)(G,{name:e.name,data:e.data,onSubmit:e=>l(u,t,e),submitted:e.submitted})},t))})]},u)}),!t&&u.length>0&&(0,H.jsx)(`div`,{className:`chat-suggestions`,children:u.map(e=>(0,H.jsx)(g,{variant:`suggestion`,onClick:()=>d(e),children:e},e))}),(0,H.jsx)(`div`,{ref:S})]}),!p&&(0,H.jsx)(`button`,{className:`scroll-to-bottom`,onClick:()=>S.current?.scrollIntoView({behavior:`smooth`}),"aria-label":`Scroll to bottom`,children:(0,H.jsx)(a,{size:18})})]})}function ie({selectedItems:e,messages:t,copySelected:r,exitSelection:a,showCopyToast:o}){let[s,c]=(0,j.useState)(!1),l=(0,j.useRef)(null),u=(0,j.useRef)(!1);function d(e){let n=e.lastIndexOf(`_`),r=e.slice(0,n),i=e.slice(n+1),a=parseInt(r,10);return t.find(e=>e.timestamp===a&&e.role===i)?.content??``}function f(e,t){return parseInt(e.slice(0,e.lastIndexOf(`_`)),10)-parseInt(t.slice(0,t.lastIndexOf(`_`)),10)}function p(){let e=[...t].sort((e,t)=>e.timestamp-t.timestamp),n=[];for(let t of e){if(t.hidden||!t.content)continue;let e=t.role===`visitor`?`Visitor`:`Maxy`;n.push(`${e}:\n${t.content}`)}return n.join(`
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:300;src:url(/assets/cormorant-cyrillic-ext-300-normal-BXl3lXsi.woff2)format("woff2"),url(/assets/cormorant-cyrillic-ext-300-normal-DmxSOTe3.woff)format("woff");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:300;src:url(/assets/cormorant-cyrillic-300-normal-DFUoTmrg.woff2)format("woff2"),url(/assets/cormorant-cyrillic-300-normal-CzPHYadL.woff)format("woff");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:300;src:url(/assets/cormorant-vietnamese-300-normal-BVqIp_mg.woff2)format("woff2"),url(/assets/cormorant-vietnamese-300-normal-CEMS9Pw-.woff)format("woff");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:300;src:url(/assets/cormorant-latin-ext-300-normal-De3D72RL.woff2)format("woff2"),url(/assets/cormorant-latin-ext-300-normal-CkiUx0UG.woff)format("woff");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:300;src:url(/assets/cormorant-latin-300-normal-CJ5dfen0.woff2)format("woff2"),url(/assets/cormorant-latin-300-normal-DQZObO_3.woff)format("woff");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/cormorant-cyrillic-ext-400-normal-BlcaxZtM.woff2)format("woff2"),url(/assets/cormorant-cyrillic-ext-400-normal-Bgrpe4p1.woff)format("woff");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/cormorant-cyrillic-400-normal-C8QS47vb.woff2)format("woff2"),url(/assets/cormorant-cyrillic-400-normal-D3EsxgFc.woff)format("woff");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/cormorant-vietnamese-400-normal-C-RiYxEf.woff2)format("woff2"),url(/assets/cormorant-vietnamese-400-normal-DmUuA7Y2.woff)format("woff");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/cormorant-latin-ext-400-normal-DuQ88yz3.woff2)format("woff2"),url(/assets/cormorant-latin-ext-400-normal-DuXFa1Dr.woff)format("woff");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/cormorant-latin-400-normal-BGH8Vunh.woff2)format("woff2"),url(/assets/cormorant-latin-400-normal-C3_-2Ua-.woff)format("woff");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/cormorant-cyrillic-ext-500-normal-pZw22qtS.woff2)format("woff2"),url(/assets/cormorant-cyrillic-ext-500-normal-CdQuyvtc.woff)format("woff");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/cormorant-cyrillic-500-normal-BLlg2W5x.woff2)format("woff2"),url(/assets/cormorant-cyrillic-500-normal-B7dJQtg-.woff)format("woff");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/cormorant-vietnamese-500-normal-DsPuwQHi.woff2)format("woff2"),url(/assets/cormorant-vietnamese-500-normal-tGBW_mI7.woff)format("woff");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/cormorant-latin-ext-500-normal-AH9qog1s.woff2)format("woff2"),url(/assets/cormorant-latin-ext-500-normal-DAuUCO41.woff)format("woff");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Cormorant;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/cormorant-latin-500-normal-EBdSCOD3.woff2)format("woff2"),url(/assets/cormorant-latin-500-normal-Dj3SQ6fR.woff)format("woff");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:DM Sans;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/dm-sans-latin-ext-400-normal-BtiwyxMk.woff2)format("woff2"),url(/assets/dm-sans-latin-ext-400-normal-BjWJ59Pq.woff)format("woff");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:DM Sans;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/dm-sans-latin-400-normal-CW0RaeGs.woff2)format("woff2"),url(/assets/dm-sans-latin-400-normal-BwCSEQnW.woff)format("woff");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:DM Sans;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/dm-sans-latin-ext-500-normal-BJfUCQsA.woff2)format("woff2"),url(/assets/dm-sans-latin-ext-500-normal-DR84L5F-.woff)format("woff");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:DM Sans;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/dm-sans-latin-500-normal-B9HHJjqV.woff2)format("woff2"),url(/assets/dm-sans-latin-500-normal-Dr3UlScf.woff)format("woff");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}*,:before,:after{box-sizing:border-box;margin:0;padding:0}:root{--bg:#fafaf8;--bg-chat:#fff;--surface:#f5f2ed;--surface-cool:#eef1f4;--text:#1a1a1a;--text-secondary:#6b6b6b;--text-tertiary:#9a9a9a;--border:#0000000f;--border-strong:#0000001a;--sage:#7c8c72;--sage-hover:#6a7a62;--sage-subtle:#7c8c7214;--sage-glow:#7c8c7226;--maxy-bubble:#f5f2ed;--visitor-bubble:#e8ecf0;--shadow-sm:0 1px 2px #0000000a;--shadow-md:0 2px 8px #0000000f;--shadow-lg:0 4px 16px #00000014;--radius-sm:6px;--radius-md:12px;--radius-lg:20px;--radius-full:9999px;--danger:#b44;--danger-hover:#c44;--accent:#e8e8e8;--surface-hover:#ffffff0d;--font-display:"Cormorant", Georgia, serif;--font-body:"DM Sans", -apple-system, BlinkMacSystemFont, sans-serif}html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:var(--font-body);color:var(--text);background:var(--bg);font-size:16px;line-height:1.6;overflow-x:hidden}a{color:var(--sage);text-decoration:none;transition:color .2s}a:hover{color:var(--sage-hover)}.chat-page{flex-direction:column;max-width:800px;height:100dvh;margin:0 auto;padding:0 20px;display:flex}.chat-header{text-align:center;flex-shrink:0;padding:48px 0 24px;position:relative}.chat-header-actions{gap:4px;display:flex;position:absolute;top:16px;right:16px}.chat-header-action{color:var(--text-tertiary);cursor:pointer;border-radius:var(--radius-sm);background:0 0;border:none;padding:6px;transition:color .15s,background .15s}.chat-header-action:hover:not(:disabled){color:var(--text);background:var(--hover)}.chat-header-action:disabled{opacity:.35;cursor:default}.chat-logo{object-fit:contain;width:auto;height:64px;margin-bottom:16px}.chat-logo--circle{object-fit:cover;border-radius:50%;width:64px;height:64px}.chat-logo--rounded{object-fit:cover;border-radius:12px}.chat-tagline{font-family:var(--font-display);color:var(--text);letter-spacing:-.01em;margin-bottom:12px;font-size:clamp(28px,5vw,42px);font-weight:300;line-height:1.2}.chat-intro{color:var(--text-secondary);margin:0 0 12px;font-size:15px;line-height:1.6}.chat-ai-indicator{color:var(--text-secondary);opacity:.7;margin:0;font-size:11px;line-height:1.3}.chat-trust{color:var(--text-tertiary);justify-content:center;align-items:center;gap:8px;font-size:13px;display:flex}.chat-trust-sep{opacity:.4}.chat-messages-wrap{flex:1;min-height:0;position:relative}@keyframes scrollBounce{0%,to{transform:translate(-50%)translateY(0)}40%{transform:translate(-50%)translateY(4px)}}.scroll-to-bottom{background:var(--bg);border:1px solid var(--border-strong);cursor:pointer;width:32px;height:32px;color:var(--text-secondary);opacity:.5;z-index:10;border-radius:50%;justify-content:center;align-items:center;transition:opacity .15s,color .15s,box-shadow .15s;animation:1.4s ease-in-out infinite scrollBounce;display:flex;position:absolute;bottom:12px;left:50%;transform:translate(-50%)}.scroll-to-bottom:hover{color:var(--sage);opacity:1;animation:none;box-shadow:0 2px 8px #00000014}.chat-messages{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent;flex-direction:column;gap:12px;height:100%;padding:16px 0;display:flex;overflow-y:auto}.chat-messages::-webkit-scrollbar{width:4px}.chat-messages::-webkit-scrollbar-track{background:0 0}.chat-messages::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:var(--radius-full)}.session-error{text-align:center;color:var(--text-secondary);flex:1;justify-content:center;align-items:center;padding:2rem;font-size:.95rem;line-height:1.5;display:flex}.idle-tips{flex-direction:column;justify-content:center;align-items:center;gap:16px;height:100%;padding:2rem;animation:.3s ease-out idle-tips-in;display:flex}@keyframes idle-tips-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.idle-tips-hint{color:var(--text-secondary);font-size:.95rem}.idle-tips-chips{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.idle-tip-chip{font-family:var(--font-body);border:1px solid var(--border-strong);border-radius:var(--radius-full);color:var(--text-secondary);cursor:pointer;background:0 0;padding:8px 16px;font-size:.85rem;transition:border-color .15s,color .15s,background .15s}.idle-tip-chip:hover,.idle-tip-chip:focus-visible{border-color:var(--sage);color:var(--sage);background:var(--sage-subtle)}.message-historical{opacity:.6}.resume-divider{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em;align-items:center;gap:12px;padding:12px 16px;font-size:.75rem;display:flex}.resume-divider:before,.resume-divider:after{content:"";background:var(--border-default);flex:1;height:1px}body[data-drag-popout-active] .chat-messages{outline:2px dashed var(--sage);outline-offset:-2px;border-radius:8px;transition:outline-color .15s}.message{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;touch-action:manipulation;animation:.3s ease-out messageIn;display:flex;position:relative}.admin-page .message,.chat-page .message{-webkit-user-select:text;user-select:text;-webkit-touch-callout:default}.message.maxy{flex-direction:column;align-items:flex-start}.message.visitor{justify-content:flex-end}.bubble{border-radius:var(--radius-lg);word-wrap:break-word;white-space:pre-wrap;max-width:85%;padding:12px 16px;font-size:15px;line-height:1.55;position:relative}.maxy-content-wrap{width:100%;min-width:0;position:relative}.message.maxy .bubble{background:var(--maxy-bubble);color:var(--text);border-bottom-left-radius:var(--radius-sm)}.message.visitor .bubble{background:var(--visitor-bubble);color:var(--text);border-bottom-right-radius:var(--radius-sm)}.bubble-sender{color:var(--sage);opacity:.85;margin-bottom:2px;font-size:11px;font-weight:600;display:block}.bubble-content{position:relative}.bubble-content.clamped{max-height:4.65em;overflow:hidden}.bubble-content.clamped.overflowing:after{content:"";background:linear-gradient(to bottom, transparent, var(--visitor-bubble));pointer-events:none;height:1.55em;position:absolute;bottom:0;left:0;right:0}.bubble-expand{justify-content:center;padding-top:4px;display:flex}.bubble-expand .btn{transition:background .15s,opacity .15s,color .15s,transform .2s}.bubble-expand .btn.expanded{transform:rotate(180deg)}.typing-indicator{align-items:center;gap:4px;padding:14px 18px;display:flex}.typing-dot{background:var(--text-tertiary);border-radius:50%;width:6px;height:6px;animation:1.4s ease-in-out infinite typingPulse}.typing-dot:nth-child(2){animation-delay:.2s}.typing-dot:nth-child(3){animation-delay:.4s}.chat-suggestions{flex-wrap:wrap;gap:8px;padding:4px 0 8px;animation:.3s ease-out messageIn;display:flex}.chat-input-area{flex-shrink:0;padding:16px 0 24px}.chat-actions{align-items:center;gap:16px;padding:8px 4px 0;display:flex;position:relative}.chat-action{font-family:var(--font-body);color:var(--text-tertiary);cursor:pointer;background:0 0;border:none;align-items:center;gap:6px;padding:0;font-size:12px;transition:color .15s;display:inline-flex}.chat-action:hover{color:var(--text-secondary)}.burger-trigger{color:var(--text-tertiary);cursor:pointer;background:0 0;border:none;padding:2px;transition:color .15s;display:none}.burger-trigger:hover{color:var(--text-secondary)}.actions-menu-items{display:contents}.chat-resize-handle{cursor:row-resize;touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;height:12px;display:flex}.chat-resize-handle-bar{background:var(--border-strong);opacity:0;border-radius:2px;width:36px;height:3px;transition:opacity .15s}.chat-resize-handle:hover .chat-resize-handle-bar{opacity:1}.chat-form{background:var(--bg-chat);border:1px solid var(--border-strong);border-radius:var(--radius-full);align-items:end;gap:8px;padding:6px 6px 6px 20px;transition:border-color .2s,box-shadow .2s,border-radius .2s;display:flex}.chat-form[data-expanded=true]{border-radius:var(--radius-lg)}.chat-form>.btn--icon{margin:10px 0}.chat-form:focus-within{box-shadow:0 0 0 3px var(--sage-subtle);border-color:#7c8c724d}.chat-input{min-width:0;font-family:var(--font-body);color:var(--text);resize:none;word-wrap:break-word;background:0 0;border:none;outline:none;flex:1;padding-block:8px;font-size:15px;line-height:1.4;overflow-y:hidden}.chat-input::placeholder{color:var(--text-tertiary)}.chat-footer{text-align:center;flex-shrink:0;padding:0 0 20px}.chat-footer a{color:var(--text-tertiary);font-size:13px;transition:color .2s}.chat-footer a:hover{color:var(--sage)}.auth-retry-link{font-family:var(--font-body);color:var(--text-tertiary);margin-top:12px;font-size:13px;text-decoration:none}.auth-retry-link:hover{color:var(--sage)}.gate-wrap{flex-direction:column;flex:1;justify-content:center;align-items:center;min-height:0;padding:0 20px 40px;display:flex}.gate-card{text-align:center;width:100%;max-width:400px}.gate-title{font-family:var(--font-display);color:var(--text);letter-spacing:-.01em;margin-bottom:8px;font-size:clamp(22px,4vw,30px);font-weight:300;line-height:1.3}.gate-subtitle{color:var(--text-secondary);margin-bottom:24px;font-size:15px;line-height:1.5}.gate-expiry-badge{color:var(--sage);background:var(--sage-subtle);border-radius:var(--radius-full);margin-bottom:20px;padding:4px 10px;font-size:12px;display:inline-block}.gate-form{text-align:left}.gate-field{margin-bottom:14px}.gate-field label{color:var(--text-secondary);margin-bottom:6px;font-size:13px;font-weight:500;display:block}.gate-field input{border:1px solid var(--border-strong);width:100%;font-family:var(--font-body);color:var(--text);background:var(--bg);border-radius:8px;outline:none;padding:10px 12px;font-size:15px;transition:border-color .15s,box-shadow .15s}.gate-field input:focus{border-color:var(--sage);box-shadow:0 0 0 2px var(--sage-glow)}.gate-field input::placeholder{color:var(--text-tertiary)}.gate-pw-row{position:relative}.gate-pw-toggle{position:absolute;top:0;right:0}.gate-strength{color:var(--text-tertiary);flex-direction:column;gap:4px;margin-top:8px;font-size:12px;display:flex}.gate-strength-item{align-items:center;gap:6px;display:flex}.gate-strength-item.met{color:var(--sage)}.gate-submit{margin-top:20px}.gate-submit .btn{border-radius:10px;width:100%;padding:12px;font-size:15px;font-weight:500}.gate-error{color:var(--danger);text-align:center;margin-top:8px;font-size:13px}.gate-success{color:var(--sage);text-align:center;margin-top:8px;font-size:13px}.gate-link{color:var(--text-tertiary);cursor:pointer;font-size:13px;font-family:var(--font-body);text-underline-offset:2px;background:0 0;border:none;padding:0;text-decoration:underline;display:inline}.gate-link:hover{color:var(--sage)}.gate-hint{color:var(--text-tertiary);text-align:center;margin-top:16px;font-size:13px}.gate-actions{text-align:center;margin-top:16px}.gate-actions .btn{min-width:200px}.gate-icon{margin-bottom:12px;font-size:36px}.gate-otp-field{justify-content:center;align-items:center;gap:10px;margin:20px 0;display:flex}.gate-otp-field .pin-box{border-radius:8px;width:42px;height:48px;font-size:20px}.gate-otp-field .pin-box:focus{border-color:var(--sage);box-shadow:0 0 0 2px var(--sage-glow)}.gate-otp-field .pin-box-filled{border-color:var(--border-strong)}.gate-resend{text-align:center;margin-top:4px}.gate-divider{color:var(--text-tertiary);align-items:center;gap:12px;margin:16px 0;font-size:13px;display:flex}.gate-divider:before,.gate-divider:after{content:"";background:var(--border);flex:1;height:1px}.gate-loading{color:var(--text-tertiary);justify-content:center;align-items:center;gap:8px;padding:20px 0;font-size:14px;display:flex}.gate-loading .spinner{border:2px solid var(--border);border-top-color:var(--sage);border-radius:50%;width:16px;height:16px;animation:.6s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.admin-page .chat-header{text-align:left;border-bottom:1px solid var(--border);flex-direction:row;justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.admin-page .chat-logo{flex-shrink:0;width:36px;height:36px;margin-bottom:0}.admin-page .chat-header>div:not(.chat-burger-wrap){flex-direction:column;flex:1;gap:2px;display:flex}.chat-burger-wrap{flex:none;position:relative}.chat-burger{cursor:pointer;color:var(--text-secondary);background:0 0;border:none;border-radius:6px;align-items:center;padding:6px;transition:color .15s;animation:2.4s ease-in-out 3 iconHeartbeat;display:flex}.chat-burger:hover{color:var(--sage);animation:none}.chat-menu{background:var(--bg);border:1px solid var(--border);z-index:100;border-radius:8px;min-width:160px;position:absolute;top:calc(100% + 6px);right:0;overflow:hidden;box-shadow:0 4px 12px #00000014}.chat-menu-item{width:100%;color:var(--text-secondary);cursor:pointer;text-align:left;box-sizing:border-box;background:0 0;border:none;align-items:center;gap:8px;padding:9px 12px;font-size:13px;text-decoration:none;transition:background .12s,color .12s;display:flex}.chat-menu-item:hover{background:var(--surface);color:var(--text)}.chat-menu-divider{background:var(--border);height:1px;margin:2px 0}.chat-menu-agents{border-top:1px solid var(--border);max-height:264px;padding:4px 0;overflow-y:auto}.chat-menu .chat-menu-agent-item{align-items:flex-start;padding-left:20px}.chat-menu-agent-item .agent-status-dot{background:var(--text-tertiary);border-radius:50%;flex-shrink:0;width:6px;height:6px;margin-top:6px}.chat-menu-agent-item .agent-status-dot.active{background:#22c55e}.chat-menu-agent-item .agent-text{flex-direction:column;flex:1;min-width:0;display:flex}.chat-menu-agent-item .agent-display-name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.chat-menu-agent-item .agent-slug{opacity:.5;font-size:11px}.chat-menu-agent-empty,.chat-menu-agent-error{color:var(--text-tertiary);padding:9px 20px;font-size:12px;display:block}.chat-menu-agent-error{color:var(--danger)}.agent-actions{flex-shrink:0;align-items:center;gap:2px;margin-left:auto;display:flex}.agent-action-btn{width:22px;height:22px;color:var(--text-tertiary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;text-decoration:none;display:flex}.agent-action-btn:hover{background:var(--surface);color:var(--text)}.agent-delete-btn:hover,.agent-confirm-yes{color:var(--danger)}.agent-confirm-yes:hover{background:var(--danger);color:#fff}.agent-confirm-no:hover{color:var(--text)}.chat-menu-version{width:100%;color:var(--text-tertiary);cursor:pointer;text-align:left;box-sizing:border-box;background:0 0;border:none;align-items:center;gap:8px;padding:9px 12px;font-size:12px;transition:background .12s,color .12s;display:flex}.chat-menu-version:hover{background:var(--surface);color:var(--text-secondary)}.chat-menu-version-passive{cursor:default}.chat-menu-version-passive:hover{color:var(--text-tertiary);background:0 0}.version-installed{font-variant-numeric:tabular-nums;align-items:center;gap:5px;display:inline-flex}.version-update-dot{background:var(--accent);border-radius:50%;flex-shrink:0;width:6px;height:6px}.version-uptodate-dot{background:#22c55e;border-radius:50%;flex-shrink:0;width:6px;height:6px}.claude-info-modal.update-modal{min-width:300px;max-width:min(480px,100% - 28px)}.update-modal-body{padding:12px 0}.update-modal-versions{margin-bottom:12px}.update-version-new{color:var(--sage);font-weight:500}.update-modal-btn{background:var(--sage);color:#fff;cursor:pointer;border:none;border-radius:6px;width:calc(100% - 28px);margin:0 14px;padding:8px 0;font-size:12px;font-weight:500;transition:background .12s}.update-modal-btn:hover{background:var(--sage-hover)}.update-modal-progress-wrap{flex-direction:column;gap:8px;padding:0 14px;display:flex}.update-modal-progress-bar{background:var(--surface);border-radius:2px;width:100%;height:4px;overflow:hidden}.update-modal-progress-fill{background:var(--sage);border-radius:2px;height:100%;transition:width 1s linear}.update-modal-phase{color:var(--text-secondary);align-items:center;gap:6px;font-size:11px;display:flex}.update-modal-step-detail{align-items:center;gap:5px;display:flex}.update-modal-step-count{font-variant-numeric:tabular-nums;opacity:.6;font-size:10px}.update-modal-substeps{background:var(--bg-secondary,#00000008);border:1px solid var(--border,#00000014);max-height:140px;color:var(--text-secondary);white-space:pre-wrap;word-break:break-word;border-radius:4px;margin-top:6px;padding:8px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px;line-height:1.5;overflow-y:auto}.update-modal-substep-line{font-variant-numeric:tabular-nums}.update-modal-result{align-items:center;gap:8px;padding:12px 14px;font-size:12px;display:flex}.update-success-icon{color:var(--sage);flex-shrink:0}.update-error-icon{color:var(--danger);flex-shrink:0}.admin-page .chat-tagline{margin:0;font-size:16px;line-height:1.2}.admin-page .chat-intro{margin:0;font-size:12px;line-height:1.3}.admin-activity{flex-direction:column;gap:6px;max-width:100%;display:flex}.spin{animation:1s linear infinite spin}.tl-spinner{animation:1.2s linear infinite spin}.star-loader{color:var(--text-tertiary)}.star-frame-0{opacity:.5;transform:scale(.85)}.star-frame-1{opacity:.8;transform:scale(1)}.star-frame-2{opacity:1;transform:scale(1.15)}.star-frame-3{opacity:.9;transform:scale(1.05)}.tl-loading{color:var(--text-tertiary);align-items:center;gap:6px;padding:2px 0 4px;display:flex}.tl-elapsed{color:var(--text-tertiary);font-variant-numeric:tabular-nums;font-size:12px}.tl-thinking-typewriter{min-width:8.5em;font-size:12px;display:inline-block}.tl-steps{flex-direction:column;display:flex}.tl-step{align-items:stretch;gap:0;display:flex;position:relative}.tl-col{flex-direction:column;flex-shrink:0;align-items:center;width:20px;display:flex}.tl-line{background:var(--border-strong);flex-shrink:0;width:1px;min-height:6px}.tl-line-grow{flex:1}.tl-icon{flex-shrink:0;justify-content:center;align-items:center;width:20px;height:20px;display:flex}.tl-icon.tl-pending{color:var(--sage)}.tl-icon.tl-done{color:var(--text-tertiary)}.tl-icon.tl-success{color:#4d8c63}.tl-icon.tl-error{color:#c44}.tl-icon.tl-dim{color:#c87533;opacity:.8}.tl-body{flex:1;min-width:0;padding:0 0 0 6px}.tl-row{align-items:center;gap:6px;min-height:22px;padding:2px 0;display:flex}.tl-summary{color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:12px;line-height:1.4;overflow:hidden}.tl-thinking-label{color:var(--text-tertiary);font-style:italic}.tl-step-tokens{color:var(--text-tertiary);font-variant-numeric:tabular-nums;opacity:.7;flex-shrink:0;align-items:center;gap:2px;font-size:11px;display:inline-flex}.tl-step-elapsed{color:var(--text-tertiary);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:11px}.tl-chevron{color:var(--text-tertiary);flex-shrink:0;align-items:center;display:flex}.tl-summary-row{cursor:pointer}.tl-summary-row .tl-summary{color:var(--text-tertiary);font-size:11px}.tl-summary-row .tl-icon{color:var(--text-tertiary)}.tl-detail{white-space:pre-wrap;word-break:break-word;color:var(--text-secondary);background:#00000008;border-radius:4px;margin:2px 0 6px;padding:7px 9px;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:11.5px;line-height:1.5;overflow-x:auto}.tl-row.tl-row-top{align-items:flex-start}.tl-thinking-col{flex-direction:column;flex:1;min-width:0;display:flex}.tl-thinking-body{color:var(--text-tertiary);word-break:break-word;border:1px solid #7c8c7240;border-radius:6px;max-height:90px;margin:0 0 4px;padding:4px 8px;font-size:12px;font-style:italic;line-height:1.5;overflow-y:auto}.tl-status{color:var(--text-tertiary);text-align:center;padding:2px 0 2px 4px;font-size:11px;font-style:italic}.tl-script-stream{color:var(--text-secondary);flex-direction:column;gap:4px;padding:2px 0 2px 4px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;font-size:11px;line-height:1.5;display:flex}.tl-script-stream-line{overflow-wrap:anywhere;align-items:baseline;gap:6px;display:flex}.tl-script-stream-source{color:var(--text-tertiary);letter-spacing:.02em;opacity:.85;flex-shrink:0;font-size:10px}.tl-script-stream-content{white-space:pre-wrap;flex:auto}.tl-post-components{flex-direction:column;gap:12px;margin-top:12px;display:flex}.tl-footer{color:var(--text-tertiary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:center;gap:6px;padding:6px 0 2px;font-size:11px;display:flex}.tl-footer-sep{opacity:.5}.tl-footer-icon-stat{align-items:center;gap:3px;display:inline-flex}.tl-footer-est{opacity:.6}.tl-ctx-pct{font-variant-numeric:tabular-nums}.tl-ctx-pct.tl-ctx-mid{color:var(--warning,#b8860b)}.tl-ctx-pct.tl-ctx-high{color:var(--error,#c33)}.tl-ctx-compacted{opacity:.45;font-style:italic}.tl-footer-status{align-items:center;gap:4px;margin-left:6px;display:inline-flex}.expand-toggle{cursor:pointer;-webkit-backdrop-filter:blur(8px);border:1px solid var(--border-strong);z-index:10;background:#fafaf8bf;border-radius:50%;justify-content:center;align-items:center;width:32px;height:32px;transition:background .15s;animation:2.4s ease-in-out .4s 3 iconHeartbeat;display:flex;position:absolute;bottom:12px;right:12px;box-shadow:0 2px 8px #00000014}.expand-toggle-default{color:#c87533}.expand-toggle-default:hover{color:#a05e22;background:#c8753314;animation:none}.expand-toggle-all{color:#4a8fc4}.expand-toggle-all:hover{color:#2e6fa0;background:#4a8fc414;animation:none}.expand-toggle-off{color:var(--text-tertiary)}.expand-toggle-off:hover{color:var(--text-secondary);background:var(--surface);animation:none}.select-toggle{color:var(--text-tertiary);animation:none;right:52px}.select-toggle:hover{color:var(--text-secondary);background:var(--surface)}.markdown-message{color:var(--text);word-wrap:break-word;background:var(--maxy-bubble);border-radius:var(--radius-lg);border-bottom-left-radius:var(--radius-sm);max-width:85%;padding:12px 16px;font-size:15px;line-height:1.65;position:relative}.bubble>.markdown-message{white-space:normal;background:0 0;border-radius:0;max-width:none;padding:0}.markdown-message .md-p{margin:0 0 10px}.markdown-message .md-p:last-child{margin-bottom:0}.markdown-message .md-heading{font-family:var(--font-body);color:var(--text);margin:14px 0 5px;font-weight:500;line-height:1.3}.markdown-message h1.md-heading{font-size:17px}.markdown-message h2.md-heading{font-size:15.5px}.markdown-message h3.md-heading{font-size:14.5px}.markdown-message .md-pre{border:1px solid var(--border);background:#0000000a;border-radius:5px;margin:8px 0;padding:10px 12px;overflow-x:auto}.markdown-message .md-pre code{white-space:pre;color:var(--text-secondary);background:0 0;border:none;border-radius:0;padding:0;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:12px;line-height:1.5;display:block}.markdown-message .md-code{background:#0000000f;border-radius:3px;padding:1px 5px;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:13px}.markdown-message .md-list{margin:4px 0 10px;padding-left:20px}.markdown-message .md-list-ordered{list-style-type:decimal}.markdown-message .md-list-item{margin-bottom:3px;font-size:15px;line-height:1.6}.markdown-message .md-list-item .md-p{margin:0}.markdown-message .md-hr{border:none;border-top:1px solid var(--border-strong);margin:12px 0}.markdown-message .md-strong{font-weight:500}.markdown-message .md-link{color:var(--sage);text-underline-offset:2px;-webkit-text-decoration:underline #7c8c7266;text-decoration:underline #7c8c7266}.markdown-message .md-img{object-fit:contain;cursor:pointer;border-radius:6px;max-width:100%;max-height:400px;margin:8px 0;display:block}.markdown-message .md-video{border-radius:6px;max-width:100%;margin:8px 0;display:block}.markdown-message .md-video-iframe{border-radius:6px;width:100%;margin:8px 0;padding-bottom:56.25%;position:relative;overflow:hidden}.markdown-message .md-video-iframe iframe{border:0;width:100%;height:100%;position:absolute;top:0;left:0}.markdown-message .md-mermaid{margin:8px 0;overflow-x:auto}.md-device-url{font-family:var(--font-body);flex-direction:column;gap:8px;margin:10px 0;display:flex}.md-device-url-button{border:1px solid var(--sage);background:var(--sage-subtle);color:var(--sage);border-radius:var(--radius-sm);font-family:var(--font-body);cursor:pointer;text-align:left;align-items:center;gap:8px;width:fit-content;max-width:100%;padding:10px 14px;font-size:14px;font-weight:500;line-height:1.2;transition:background .12s,transform .12s;display:inline-flex}.md-device-url-button:hover:not(:disabled){background:var(--sage-glow)}.md-device-url-button:active:not(:disabled){transform:translateY(1px)}.md-device-url-button:disabled{opacity:.65;cursor:progress}.md-device-url-icon{color:var(--sage);flex-shrink:0}.md-device-url-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.md-device-url-fallback{border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:var(--surface);font-family:var(--font-body);color:var(--text);flex-direction:column;gap:8px;padding:10px 12px;font-size:13px;display:flex}.md-device-url-fallback-message{align-items:flex-start;gap:8px;line-height:1.4;display:flex}.md-device-url-fallback-url{background:var(--bg);border-radius:4px;align-items:center;gap:8px;padding:6px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;font-size:12px;display:flex;overflow-x:auto}.md-device-url-fallback-url code{white-space:nowrap;flex:1;overflow-x:auto}.md-device-url-fallback-copy{border:1px solid var(--border-strong);background:var(--bg-chat);font-family:var(--font-body);color:var(--text);cursor:pointer;border-radius:4px;flex-shrink:0;align-items:center;gap:4px;padding:4px 8px;font-size:12px;display:inline-flex}.md-device-url-fallback-copy:hover{background:var(--surface)}.md-device-url-fallback-copy-failed{color:var(--danger);padding:2px 2px 0;font-size:11px}.md-device-url-malformed{border-left:3px solid var(--danger)}.md-device-url-malformed-label{color:var(--danger);align-items:center;gap:4px;margin-bottom:4px;font-size:11px;display:inline-flex}.markdown-message .md-mermaid svg{max-width:100%;height:auto}.markdown-message .md-mermaid-error .md-mermaid-error-label{color:var(--text-error,#c33);margin-bottom:4px;font-size:12px}.markdown-message .md-table{border-collapse:collapse;width:100%;margin:10px 0;font-size:13px}.markdown-message .md-th,.markdown-message .md-td{border:1px solid var(--border-strong);text-align:left;padding:6px 10px}.markdown-message .md-thead .md-th{background:var(--sage-subtle);color:var(--text-secondary);font-size:12px;font-weight:600}.markdown-message .md-tr:nth-child(2n) td{background:#00000005}.message-meta{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-top:6px;font-size:11px}@keyframes iconHeartbeat{0%,to{opacity:.55}50%{opacity:1}}@keyframes iconHeartbeatSubtle{0%,to{opacity:.7}50%{opacity:1}}.powered-by{color:var(--text-tertiary);cursor:pointer;-webkit-user-select:none;user-select:none;opacity:.7;align-items:center;gap:5px;margin-left:auto;font-size:10px;transition:opacity .15s;animation:2.4s ease-in-out .8s 3 iconHeartbeatSubtle;display:flex}.powered-by:hover{opacity:1;animation:none}.powered-by-icon{object-fit:contain;width:14px;height:14px}.claude-info-overlay{z-index:200;background:#00000073;justify-content:flex-end;align-items:flex-end;padding:0 0 56px;display:flex;position:fixed;inset:0}.claude-info-modal{background:var(--surface);border:1px solid var(--border);border-radius:10px;width:300px;max-width:calc(100% - 28px);margin-right:max(14px,50vw - 386px);overflow:hidden;box-shadow:0 8px 32px #0006}.claude-info-header{border-bottom:1px solid var(--border);color:var(--text-secondary);align-items:center;gap:8px;padding:12px 14px;font-size:12px;font-weight:500;display:flex}.claude-info-header img{object-fit:contain;width:14px;height:14px}.claude-info-close{color:var(--text-tertiary);cursor:pointer;background:0 0;border:none;margin-left:auto;padding:2px 4px;font-size:11px;line-height:1}.claude-info-close:hover{color:var(--text)}.claude-info-section{border-bottom:1px solid var(--border);padding:8px 0}.claude-info-section:last-child{border-bottom:none}.claude-info-row{justify-content:space-between;align-items:baseline;gap:12px;padding:4px 14px;font-size:11px;display:flex}.claude-info-label{color:var(--text-tertiary);flex-shrink:0}.claude-info-value{color:var(--text-secondary);font-family:var(--font-mono,monospace);text-align:right;text-overflow:ellipsis;white-space:nowrap;font-size:10.5px;overflow:hidden}.claude-info-toggle{cursor:pointer;transition:color .15s}.claude-info-toggle:hover,.claude-info-toggle:focus-visible{color:var(--text);text-decoration:underline}.claude-info-icon{object-fit:contain;width:14px;height:14px}.conversations-modal{flex-direction:column;width:min(480px,100vw - 28px);max-height:calc(100dvh - 72px);display:flex}.conversations-list{flex:1;overflow-y:auto}.conversations-empty{color:var(--text-tertiary);justify-content:center;align-items:center;gap:6px;padding:24px 14px;font-size:12px;display:flex}.conversations-error{color:var(--error,#e55)}.conversations-row{border-bottom:1px solid var(--border);justify-content:space-between;align-items:center;gap:8px;padding:8px 14px;transition:background .12s;display:flex}.conversations-row:last-child{border-bottom:none}.conversations-row:hover{background:var(--surface)}.conversations-row-info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.conversations-row-name{color:var(--text);white-space:nowrap;text-overflow:ellipsis;font-size:12px;overflow:hidden}.conversations-row-meta{align-items:center;gap:6px;display:flex}.conversations-row-id{color:var(--text-tertiary);opacity:.7;font-family:monospace;font-size:10px}.conversations-row-time{color:var(--text-tertiary);align-items:center;gap:4px;font-size:10px;display:flex}.conversations-row-actions{flex-shrink:0;align-items:center;gap:4px;display:flex}.conversations-action{width:28px;height:28px;color:var(--text-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;transition:background .12s,color .12s;display:flex}.conversations-play:hover{background:var(--sage-faint,#88b0941f);color:var(--sage)}.conversations-rename:hover{background:var(--sage-faint,#88b0941f);color:var(--text)}.conversations-delete:hover{color:var(--error,#e55);background:#e555551a}.conversations-edit-loading{color:var(--text-tertiary);align-items:center;gap:6px;font-style:italic;display:flex}.conversations-edit-inline{flex:1;align-items:center;gap:4px;min-width:0;display:flex}.conversations-edit-input{min-width:0;color:var(--text);background:var(--surface);border:1px solid var(--border);border-radius:4px;outline:none;flex:1;padding:3px 8px;font-family:inherit;font-size:12px;transition:border-color .12s}.conversations-edit-input:focus{border-color:var(--sage,#88b094)}.conversations-edit-error{color:var(--error,#e55);white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;font-size:11px;overflow:hidden}.conversations-confirm:not(:disabled):hover{background:var(--sage-faint,#88b0941f);color:var(--sage)}.conversations-confirm:disabled{opacity:.3;cursor:default}.conversations-cancel:hover{color:var(--error,#e55);background:#e555551a}.conversations-retry:hover{background:var(--sage-faint,#88b0941f);color:var(--text)}.pin-input-row{align-items:center;gap:8px;display:flex}.pin-field{border:1px solid var(--border-strong);background:var(--bg);border-radius:26px;flex:1;align-items:center;gap:8px;height:52px;padding:0 16px;transition:border-color .15s;display:flex}.pin-field:focus-within{border-color:var(--sage)}.pin-box{border:1.5px solid var(--border);text-align:center;width:28px;height:32px;color:var(--text-primary);caret-color:#0000;background:0 0;border-radius:6px;outline:none;flex-shrink:0;padding:0;font-size:10px;transition:border-color .15s,box-shadow .15s}.pin-box:focus{border-color:var(--sage);box-shadow:0 0 0 2px var(--sage-glow)}.pin-box-filled{border-color:var(--border-strong)}.pin-options{justify-content:space-between;align-items:center;display:flex}.admin-pin-error{color:#c44;white-space:pre-wrap;word-break:break-word;font-size:13px;font-family:var(--font-body);text-align:left;max-height:200px;overflow-y:auto}.account-picker-list{flex-direction:column;gap:8px;width:100%;max-width:340px;display:flex}.account-picker-card{background:var(--bg-secondary);border:1px solid var(--border);cursor:pointer;text-align:left;font-family:var(--font-body);border-radius:10px;align-items:center;gap:12px;padding:14px 16px;transition:border-color .15s,background .15s;display:flex}.account-picker-card:hover:not(:disabled){border-color:var(--text-tertiary);background:var(--bg-hover)}.account-picker-card:disabled{opacity:.6;cursor:default}.account-picker-name{color:var(--text);flex:1;font-size:15px;font-weight:500}.account-picker-role{color:var(--text-tertiary);text-transform:capitalize;font-size:12px}.account-picker-spinner{color:var(--text-tertiary);animation:1s linear infinite spin}.connect-page{background:var(--bg);justify-content:center;align-items:center;min-height:100dvh;padding:40px 20px;display:flex}.connect-content{flex-direction:column;align-items:center;gap:24px;width:100%;max-width:420px;display:flex}.connect-logos{align-items:center;gap:28px;display:flex}.connect-logo-wrap{flex-direction:column;align-items:center;gap:10px;display:flex}.connect-logo{object-fit:contain;width:88px;height:88px}.connect-logo--maxy{width:110px;height:110px;margin:-11px}.connect-logo-label{font-family:var(--font-body);color:var(--text-secondary);letter-spacing:.02em;font-size:13px}.connect-arrow{width:48px;height:24px;color:var(--text-tertiary);flex-shrink:0;margin-bottom:22px}.connect-title{font-family:var(--font-display);color:var(--text);text-align:center;letter-spacing:-.01em;font-size:clamp(22px,4vw,28px);font-weight:300;line-height:1.3}.connect-subtitle{color:var(--text-secondary);text-align:center;margin-top:-8px;font-size:15px;line-height:1.5}.connect-content .btn--primary{min-width:200px}.connect-pin-form{flex-direction:column;gap:8px;width:100%;max-width:300px;display:flex}@keyframes messageIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes typingPulse{0%,60%,to{opacity:.3;transform:scale(.8)}30%{opacity:1;transform:scale(1)}}.attachment-strip{flex-wrap:wrap;gap:6px;padding:0 0 8px;display:flex}.attachment-chip{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-full);color:var(--text-secondary);align-items:center;gap:5px;max-width:200px;padding:4px 8px;font-size:12px;display:inline-flex}.attachment-chip-thumb{object-fit:cover;border-radius:3px;flex-shrink:0;width:20px;height:20px}.attachment-chip-name{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.attachment-chip-remove{cursor:pointer;color:var(--text-tertiary);background:0 0;border:none;flex-shrink:0;align-items:center;padding:0 0 0 2px;font-size:13px;line-height:1;display:flex}.attachment-chip-remove:hover{color:var(--text)}.message-attachments{flex-wrap:wrap;gap:5px;margin-top:8px;display:flex}.message-attachment-chip{border-radius:var(--radius-full);color:var(--text-secondary);cursor:pointer;background:#0000000f;border:none;align-items:center;gap:4px;padding:3px 10px;font-family:inherit;font-size:11px;display:inline-flex}.message-attachment-chip:hover{color:var(--text);background:#0000001a}.message-attachment-chip.no-action{cursor:default}.message-attachment-chip.no-action:hover{color:var(--text-secondary);background:#0000000f}.chat-form.drag-over{outline:2px dashed var(--sage);outline-offset:6px;border-radius:var(--radius-sm)}.attachment-lightbox{z-index:1000;background:#000000d9;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.attachment-lightbox img{object-fit:contain;border-radius:var(--radius-md);max-width:90vw;max-height:90vh}.attachment-lightbox-close{color:#ffffffb3;cursor:pointer;background:0 0;border:none;padding:4px;font-size:20px;line-height:1;position:absolute;top:20px;right:20px}.attachment-lightbox-close:hover{color:#fff}.attach-error{color:#e05252;margin:0 0 4px;padding:0 4px;font-size:12px}.voice-error{color:#e05252;align-items:center;gap:6px;margin:0 0 4px;padding:0 4px;font-size:12px;display:flex}.chat-form.voice-active{padding:6px 6px 6px 12px}.voice-recorder{align-items:center;gap:8px;width:100%;min-height:30px;display:flex}.voice-trash{border-radius:var(--radius-full);color:#e05252;cursor:pointer;background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;width:30px;height:30px;transition:background .15s;display:flex}.voice-trash:hover{background:#e052521a}.voice-trash:disabled{opacity:.4;cursor:default}.voice-timer{font-variant-numeric:tabular-nums;color:var(--text-secondary);flex-shrink:0;min-width:32px;font-size:13px}.voice-waveform{flex:1;align-items:center;gap:2px;min-width:0;height:24px;display:flex}.voice-waveform-bar{background:#7c8c7299;border-radius:1px;flex:1;min-width:2px;max-width:4px;transition:height .1s ease-out}.voice-pause{border-radius:var(--radius-full);width:30px;height:30px;color:var(--text-secondary);cursor:pointer;background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;transition:background .15s;display:flex}.voice-pause:hover{background:var(--sage-subtle)}.voice-pause:disabled{opacity:.4;cursor:default}@media (width<=640px){.chat-header{padding:32px 0 16px}.chat-page:not(.admin-page) .chat-header{text-align:left;border-bottom:1px solid var(--border);flex-direction:row;align-items:center;gap:12px;padding:12px 0;display:flex}.chat-page:not(.admin-page) .chat-logo{flex-shrink:0;width:40px;height:40px;margin-bottom:0}.chat-page:not(.admin-page) .chat-logo--circle{width:40px;height:40px}.chat-page:not(.admin-page) .chat-tagline{margin-bottom:0;font-size:16px;font-weight:400;line-height:1.3}.chat-page:not(.admin-page) .chat-intro{margin:0;font-size:12px;line-height:1.3}.chat-page:not(.admin-page) .chat-header-text{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.chat-page:not(.admin-page) .chat-header-actions{flex-shrink:0;margin-left:auto;position:static}.bubble,.public-components{max-width:90%}.burger-trigger{align-items:center;display:flex}.actions-menu-items{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-sm,6px);opacity:0;visibility:hidden;pointer-events:none;flex-direction:column;gap:2px;min-width:170px;padding:4px 0;transition:opacity .15s,transform .15s,visibility .15s;display:flex;position:absolute;bottom:calc(100% + 6px);left:0;transform:translateY(4px);box-shadow:0 2px 8px #00000026}.actions-menu-items.actions-menu-open{opacity:1;visibility:visible;pointer-events:auto;transform:translateY(0)}.actions-menu-items .chat-action{width:100%;padding:8px 12px;font-size:13px}.actions-menu-items .chat-action:hover{background:var(--hover)}.actions-menu-items .action-label{display:inline}}.message-queue-list{flex-direction:column;gap:2px;padding:0 0 6px;display:flex}.queued-message-row{color:var(--text-secondary);background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-sm,4px);justify-content:space-between;align-items:center;padding:3px 8px;font-size:12px;display:flex}.queued-message-text{text-overflow:ellipsis;white-space:nowrap;max-width:calc(100% - 24px);overflow:hidden}.queued-message-row button{cursor:pointer;color:var(--text-secondary);background:0 0;border:none;flex-shrink:0;padding:0 4px;font-size:1rem;line-height:1}.queued-message-row button:hover{color:var(--text-primary,#fff)}.message-timestamp{color:var(--text-tertiary,#555);text-align:right;-webkit-user-select:none;user-select:none;margin-top:4px;font-size:10px;display:block}.tl-msg-timestamp{color:var(--text-tertiary,#555);text-align:right;-webkit-user-select:none;user-select:none;margin-top:4px;padding-right:2px;font-size:10px;display:block}.bubble-queued{padding-right:28px;position:relative}.queued-bubble-delete{cursor:pointer;color:var(--text-secondary,#888);background:0 0;border:none;padding:0 2px;font-size:1rem;line-height:1;position:absolute;top:6px;right:6px}.queued-bubble-delete:hover{color:var(--danger)}.maxy-checkbox{cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:6px;display:flex;position:relative}.maxy-checkbox--disabled{opacity:.4;pointer-events:none}.maxy-checkbox input{opacity:0;pointer-events:none;width:0;height:0;position:absolute}.maxy-checkbox__box{border:1px solid var(--border-strong);color:#0000;border-radius:3px;flex-shrink:0;justify-content:center;align-items:center;width:14px;height:14px;font-size:10px;transition:border-color .15s,color .15s;display:flex}.maxy-checkbox input:checked+.maxy-checkbox__box{border-color:var(--sage);color:var(--sage)}.maxy-checkbox__label{font-family:var(--font-body);color:var(--text-secondary);font-size:13px}.selection-overlay-band{background:color-mix(in srgb, var(--bg) 85%, transparent);-webkit-backdrop-filter:blur(4px);border-left:1px solid var(--border-strong);z-index:10;pointer-events:none;width:64px;position:absolute;top:0;bottom:0;right:0}.tl-text-block{position:relative}.message-select-check,.tl-select-check{z-index:11;position:absolute;top:50%;right:10px;transform:translateY(-50%)}.message.selected .bubble,.message.selected .admin-activity{background:#7c8c7214}.selection-bar{justify-content:space-between;align-items:center;gap:12px;padding:12px 16px;display:flex}.selection-cancel{font-family:var(--font-body);color:var(--text-secondary);cursor:pointer;background:0 0;border:none;font-size:14px}.selection-count{font-family:var(--font-body);color:var(--text);font-size:14px;font-weight:500}.selection-copy-wrap{position:relative}.selection-copy{color:var(--sage);font-family:var(--font-body);cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;touch-action:manipulation;background:0 0;border:none;flex-direction:column;align-items:center;gap:2px;padding:0;font-size:11px;display:flex}.copy-menu{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);box-shadow:var(--shadow-md);z-index:20;white-space:nowrap;animation:.15s ease-out messageIn;position:absolute;bottom:calc(100% + 8px);right:50%;overflow:hidden;transform:translate(50%)}.copy-menu-item{width:100%;font-family:var(--font-body);color:var(--text);text-align:left;cursor:pointer;background:0 0;border:none;padding:10px 16px;font-size:13px;display:block}.copy-menu-item:not(:last-child){border-bottom:1px solid var(--border)}.copy-menu-item:active{background:var(--hover)}.copy-toast{background:var(--text);color:var(--bg);font-family:var(--font-body);border-radius:var(--radius-full);z-index:100;pointer-events:none;padding:6px 16px;font-size:13px;animation:.2s ease-out messageIn;position:fixed;bottom:80px;left:50%;transform:translate(-50%)}.copy-toast-failed{background:var(--error,#c00);color:#fff}.component-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);box-shadow:var(--shadow-sm);width:fit-content;max-width:100%;padding:14px 16px}.component-card--submitted{opacity:.6;pointer-events:none}.component-card__actions{justify-content:flex-end;align-items:center;gap:8px;padding-top:10px;display:flex}.component-card__done-label{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;font-style:italic}.output-style-selector{flex-direction:column;gap:0;max-width:320px;display:flex}.output-style-selector__row{border-radius:var(--radius-sm);cursor:pointer;-webkit-user-select:none;user-select:none;align-items:flex-start;gap:10px;padding:10px 8px;transition:background .15s;display:flex}.output-style-selector__row:hover,.output-style-selector__row--selected{background:var(--sage-subtle)}.output-style-selector__radio{border:2px solid var(--text-secondary);border-radius:50%;flex-shrink:0;width:16px;height:16px;margin-top:1px;transition:border-color .15s,box-shadow .15s}.output-style-selector__radio--checked{border-color:var(--text);box-shadow:inset 0 0 0 3px var(--surface), inset 0 0 0 8px var(--text)}.output-style-selector__info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.output-style-selector__label{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500;line-height:1.3}.output-style-selector__desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.thinking-view-selector{flex-direction:column;gap:0;max-width:320px;display:flex}.thinking-view-selector__row{border-radius:var(--radius-sm);cursor:pointer;-webkit-user-select:none;user-select:none;align-items:flex-start;gap:10px;padding:10px 8px;transition:background .15s;display:flex}.thinking-view-selector__row:hover,.thinking-view-selector__row--selected{background:var(--sage-subtle)}.thinking-view-selector__radio{border:2px solid var(--text-secondary);border-radius:50%;flex-shrink:0;width:16px;height:16px;margin-top:1px;transition:border-color .15s,box-shadow .15s}.thinking-view-selector__radio--checked{border-color:var(--text);box-shadow:inset 0 0 0 3px var(--surface), inset 0 0 0 8px var(--text)}.thinking-view-selector__info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.thinking-view-selector__label{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500;line-height:1.3}.thinking-view-selector__desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.plugin-selector{flex-direction:column;gap:10px;max-width:420px;display:flex}.plugin-selector__header{border-bottom:1px solid var(--border);padding-bottom:6px}.plugin-selector__list{flex-direction:column;gap:0;max-height:400px;display:flex;overflow-y:auto}.plugin-selector__row{border-radius:var(--radius-sm);cursor:pointer;-webkit-user-select:none;user-select:none;align-items:flex-start;gap:10px;padding:8px 6px;transition:background .15s;display:flex}.plugin-selector__row:hover{background:var(--sage-subtle)}.plugin-selector__info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.plugin-selector__name{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500;line-height:1.3}.plugin-selector__recommended{font-family:var(--font-body);color:var(--sage);margin-left:6px;font-size:10px;font-weight:500}.plugin-selector__desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.single-select{flex-direction:column;gap:0;display:flex}.single-select__title{font-family:var(--font-body);color:var(--text);padding:0 8px 6px;font-size:13px;font-weight:600}.single-select__row{border-radius:var(--radius-sm);cursor:pointer;-webkit-user-select:none;user-select:none;align-items:flex-start;gap:10px;padding:10px 8px;transition:background .15s;display:flex}.single-select__row:hover,.single-select__row--selected{background:var(--sage-subtle)}.single-select__radio{border:2px solid var(--text-secondary);border-radius:50%;flex-shrink:0;width:16px;height:16px;margin-top:1px;transition:border-color .15s,box-shadow .15s}.single-select__radio--checked{border-color:var(--text);box-shadow:inset 0 0 0 3px var(--surface), inset 0 0 0 8px var(--text)}.single-select__info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.single-select__icon{margin-right:6px}.single-select__label{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500;line-height:1.3}.single-select__desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.multi-select{flex-direction:column;gap:10px;display:flex}.multi-select__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:600}.multi-select__header{border-bottom:1px solid var(--border);padding-bottom:6px}.multi-select__list{flex-direction:column;gap:4px;max-height:400px;display:flex;overflow-y:auto}.multi-select__row{border-radius:var(--radius-sm);cursor:pointer;-webkit-user-select:none;user-select:none;flex-shrink:0;align-items:flex-start;gap:10px;padding:10px 8px;transition:background .15s;display:flex}.multi-select__row:hover{background:var(--sage-subtle)}.multi-select__row>.maxy-checkbox{margin-top:1px}.multi-select__info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.multi-select__label{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500;line-height:1.3}.multi-select__badge{font-family:var(--font-body);color:var(--sage);margin-left:6px;font-size:10px;font-weight:500}.multi-select__desc{font-family:var(--font-body);color:var(--text-secondary);overflow-wrap:anywhere;font-size:12px;line-height:1.4}.multi-select__group-header{font-family:var(--font-body);color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em;padding:10px 6px 4px;font-size:11px;font-weight:600}.multi-select__group-header:first-child{padding-top:0}.multi-select__row--locked{opacity:.6;cursor:default}.multi-select__row--locked:hover,.multi-select__row--locked:focus{background:0 0;outline:none}.public-components{flex-direction:column;gap:12px;max-width:85%;margin-top:8px;display:flex}@keyframes component-enter{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.public-component-enter{animation:.2s ease-out both component-enter}.single-select__row{min-height:44px}.single-select__row:focus,.multi-select__row:focus{outline:2px solid var(--accent,#7c9a82);outline-offset:-2px;border-radius:8px}@media (width<=480px){.component-card{border-radius:12px;width:100%}.multi-select__list{max-height:60vh}.browser-viewer__iframe{aspect-ratio:4/3;min-height:300px}}.confirm{flex-direction:column;gap:8px;max-width:380px;display:flex}.confirm__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:600;line-height:1.3}.confirm__desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.confirm__items{border-top:1px solid var(--border);flex-direction:column;gap:4px;padding:8px 0;display:flex}.confirm__item{justify-content:space-between;align-items:baseline;gap:12px;padding:2px 0;display:flex}.confirm__item-label{font-family:var(--font-body);color:var(--text-secondary);font-size:12px}.confirm__item-value{font-family:var(--font-body);color:var(--text);text-align:right;font-size:12px;font-weight:500}.info-card{flex-direction:column;gap:10px;max-width:380px;display:flex}.info-card__header{flex-direction:column;gap:2px;display:flex}.info-card__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:600;line-height:1.3}.info-card__subtitle{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.info-card__fields{flex-direction:column;gap:6px;display:flex}.info-card__field{border-bottom:1px solid var(--border);justify-content:space-between;align-items:baseline;gap:12px;padding:3px 0;display:flex}.info-card__field:last-child{border-bottom:none}.info-card__field-label{font-family:var(--font-body);color:var(--text-secondary);flex-shrink:0;font-size:12px}.info-card__field-value{font-family:var(--font-body);color:var(--text);text-align:right;font-size:12px;font-weight:500}.info-card__field-value--status{color:var(--sage)}.info-card__field-value a{color:var(--sage);text-decoration:none}.info-card__field-value a:hover{text-decoration:underline}.qr-code{flex-direction:column;align-items:center;gap:12px;padding:8px 0;display:flex}.qr-code--error{font-family:var(--font-body);color:var(--text-secondary);text-align:center;font-size:12px}.qr-code__canvas{color:#000;background:#fff;border-radius:12px;padding:16px}.qr-code__label{font-family:var(--font-body);color:var(--text-secondary);text-align:center;max-width:280px;font-size:12px;line-height:1.4}.action-list{flex-direction:column;gap:8px;max-width:460px;display:flex}.action-list__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:600}.action-list__items{flex-direction:column;gap:0;display:flex}.action-list__item{border-radius:var(--radius-sm);justify-content:space-between;align-items:center;gap:12px;padding:8px 6px;transition:background .15s;display:flex}.action-list__item:hover{background:var(--sage-subtle)}.action-list__item--acted{opacity:.5}.action-list__item-info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.action-list__item-label{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500;line-height:1.3}.action-list__item-desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.action-list__item-right{flex-shrink:0;align-items:center;gap:8px;display:flex}.action-list__item-status{font-family:var(--font-body);color:var(--sage);white-space:nowrap;font-size:10px;font-weight:500}.action-list__item-actions{gap:4px;display:flex}.form-input{flex-direction:column;gap:10px;max-width:360px;display:flex}.form-input__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:600}.form-input__desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.form-input__fields{flex-direction:column;gap:12px;display:flex}.form-input__field{flex-direction:column;gap:4px;display:flex}.form-input__label{font-family:var(--font-body);color:var(--text);font-size:12px;font-weight:500}.form-input__required{color:var(--sage);margin-left:2px}.form-input__input,.form-input__textarea,.form-input__select{font-family:var(--font-body);color:var(--text);background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);outline:none;padding:8px 10px;font-size:13px;transition:border-color .15s}.form-input__input:focus,.form-input__textarea:focus,.form-input__select:focus{border-color:var(--sage)}.form-input__input:disabled,.form-input__textarea:disabled,.form-input__select:disabled{opacity:.6;cursor:not-allowed}.form-input__textarea{resize:vertical;min-height:60px}.form-input__select{cursor:pointer}.form-input__field-desc{font-family:var(--font-body);color:var(--text-secondary);margin-top:-1px;font-size:11px;line-height:1.4}.form-input__list{flex-direction:column;gap:4px;display:flex}.form-input__list-item{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;display:flex}.form-input__list-item-text{font-family:var(--font-body);color:var(--text);text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:13px;overflow:hidden}.form-input__list-item-remove{color:var(--text-secondary);cursor:pointer;border-radius:var(--radius-sm);background:0 0;border:none;flex-shrink:0;padding:0 4px;font-size:16px;line-height:1;transition:color .15s}.form-input__list-item-remove:hover:not(:disabled){color:var(--text)}.form-input__list-item-remove:disabled{opacity:.6;cursor:not-allowed}.form-input__list-add{gap:6px;margin-top:2px;display:flex}.form-input__list-add .form-input__input{flex:1;min-width:0}.form-input__list-add-btn{font-family:var(--font-body);color:var(--text);background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;flex-shrink:0;padding:8px 12px;font-size:12px;font-weight:500;transition:border-color .15s}.form-input__list-add-btn:hover:not(:disabled){border-color:var(--sage)}.form-input__list-add-btn:disabled{opacity:.6;cursor:not-allowed}.tunnel-route__row{border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface);align-items:stretch;transition:border-color .15s;display:flex;overflow:hidden}.tunnel-route__row:focus-within{border-color:var(--sage)}.tunnel-route__input{background:0 0;border:none;border-radius:0;flex:1;min-width:0}.tunnel-route__input:focus{border:none;outline:none}.tunnel-route__suffix{font-family:var(--font-body);color:var(--text-secondary);background:color-mix(in srgb, var(--border) 35%, transparent);border-left:1px solid var(--border);white-space:nowrap;-webkit-user-select:none;user-select:none;align-items:center;padding:0 10px;font-size:13px;display:inline-flex}.tunnel-route__optional{font-family:var(--font-body);color:var(--text-secondary);margin-left:8px;font-size:11px;font-weight:400}.tunnel-route__preview{font-family:var(--font-mono,ui-monospace, monospace);color:var(--text)}.tunnel-route__error{font-family:var(--font-body);color:var(--danger,#c0392b);font-size:11px;line-height:1.4}.progress-tracker{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);max-width:380px;box-shadow:var(--shadow-sm);width:fit-content;padding:14px 16px}.progress-tracker--submitted{opacity:.6;pointer-events:none}.progress-tracker__title{font-family:var(--font-body);color:var(--text);padding-bottom:10px;font-size:13px;font-weight:600}.progress-tracker__steps{flex-direction:column;gap:2px;display:flex}.progress-tracker__step{border-radius:var(--radius-sm);align-items:flex-start;gap:10px;padding:6px 4px;display:flex}.progress-tracker__icon{text-align:center;flex-shrink:0;width:18px;font-size:13px;line-height:1.3}.progress-tracker__step--completed .progress-tracker__icon{color:var(--sage)}.progress-tracker__step--failed .progress-tracker__icon{color:#c44}.progress-tracker__step--active .progress-tracker__icon{color:var(--text);font-weight:700}.progress-tracker__step--pending .progress-tracker__icon,.progress-tracker__step--skipped .progress-tracker__icon{color:var(--text-tertiary)}.progress-tracker__step-info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.progress-tracker__step-label{font-family:var(--font-body);color:var(--text);font-size:13px;line-height:1.3}.progress-tracker__step--pending .progress-tracker__step-label{color:var(--text-tertiary)}.progress-tracker__step--skipped .progress-tracker__step-label{color:var(--text-tertiary);text-decoration:line-through}.progress-tracker__step-desc{font-family:var(--font-body);color:var(--text-secondary);font-size:12px;line-height:1.4}.editor-base{background:var(--surface);border:1px solid var(--border);border-radius:10px;flex-direction:column;gap:10px;padding:12px;display:flex}.editor-base__bar{justify-content:space-between;align-items:center;padding:0 0 4px;display:flex}.editor-base__bar[draggable=true]{cursor:grab}.editor-base__bar[draggable=true] .editor-base__actions{cursor:default}.editor-base__icon{width:14px;height:14px;color:var(--text-secondary);flex-shrink:0;margin-right:6px}.editor-base__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500}.editor-base__actions{align-items:center;gap:4px;margin-left:auto;display:flex}.editor-base__status{font-family:var(--font-body);color:var(--text-tertiary);padding:2px 6px;font-size:12px}.editor-base--minimised{cursor:pointer;gap:0;padding:10px 14px}.editor-base--popout{padding:10px 14px}.editor-base-fullscreen{z-index:1000;background:var(--bg-chat);flex-direction:column;display:flex;position:fixed;inset:0}.editor-base-fullscreen__bar{border-bottom:1px solid var(--border);background:var(--surface);flex-shrink:0;justify-content:space-between;align-items:center;padding:8px 16px;display:flex}.editor-base-fullscreen__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500}.editor-base-fullscreen__body{flex:1;width:100%;max-width:800px;margin:0 auto;padding:24px;position:relative;overflow-y:auto}.doc-editor__body{background:var(--bg-chat);border:1px solid var(--border);border-radius:6px;max-height:500px;position:relative;overflow-y:auto}.doc-editor__content{font-family:var(--font-body);color:var(--text);outline:none;min-height:60px;padding:12px;font-size:15px;line-height:1.6}.doc-editor__content h1,.doc-editor__content h2,.doc-editor__content h3{margin-top:1.2em;margin-bottom:.4em;font-weight:600}.doc-editor__content h1{font-size:1.5em}.doc-editor__content h2{font-size:1.25em}.doc-editor__content h3{font-size:1.1em}.doc-editor__content p{margin:.4em 0}.doc-editor__content ul,.doc-editor__content ol{margin:.4em 0;padding-left:1.5em}.doc-editor__content code{background:var(--surface);border-radius:3px;padding:1px 4px;font-size:.9em}.doc-editor__content pre{background:var(--surface);border-radius:6px;margin:.6em 0;padding:12px;overflow-x:auto}.doc-editor__content pre code{background:0 0;padding:0}.doc-editor__content blockquote{border-left:3px solid var(--border-strong);color:var(--text-secondary);margin:.6em 0;padding-left:12px}.doc-editor__content a{color:var(--sage);text-decoration:underline}.doc-editor__content hr{border:none;border-top:1px solid var(--border);margin:1em 0}.doc-editor__content p.is-editor-empty:first-child:before{content:"Start typing or wait for content...";color:var(--text-tertiary);float:left;pointer-events:none;height:0;font-style:italic}.doc-editor__bubble-menu{background:var(--surface);border:1px solid var(--border);box-shadow:var(--shadow-sm);border-radius:8px;align-items:center;gap:4px;padding:6px;display:flex}.doc-editor__bubble-divider{background:var(--border-strong);width:1px;height:20px;margin:0 2px}.doc-editor__comment-highlight{background:var(--sage-glow);cursor:help;border-radius:2px}.doc-editor__comment-popover{z-index:10;background:var(--bg-chat);border:1px solid var(--border-strong);box-shadow:var(--shadow-md);border-radius:8px;flex-direction:column;gap:6px;max-width:280px;padding:8px;display:flex;position:absolute;top:8px;right:8px}.doc-editor__comment-input{font-family:var(--font-body);border:1px solid var(--border);background:var(--bg);color:var(--text);border-radius:6px;outline:none;width:100%;padding:6px 8px;font-size:13px}.doc-editor__comment-input:focus{border-color:var(--sage)}.doc-editor__comment-actions{justify-content:flex-end;gap:4px;display:flex}.doc-editor__fallback,.rich-editor__fallback{font-family:var(--font-body);color:var(--text);padding:12px;font-size:15px;line-height:1.6}.doc-editor__fallback ul,.doc-editor__fallback ol{margin:.4em 0;padding-left:1.5em}.doc-editor__preview{cursor:text;border-radius:6px;transition:background .15s}.doc-editor__preview:hover{background:#00000005}.rich-editor__body{background:var(--bg-chat);border:1px solid var(--border);border-radius:6px;max-height:500px;position:relative;overflow-y:auto}.rich-editor__content{font-family:var(--font-body);color:var(--text);outline:none;min-height:60px;padding:12px;font-size:15px;line-height:1.6}.rich-editor__content h1,.rich-editor__content h2,.rich-editor__content h3{margin-top:1.2em;margin-bottom:.4em;font-weight:600}.rich-editor__content h1{font-size:1.5em}.rich-editor__content h2{font-size:1.25em}.rich-editor__content h3{font-size:1.1em}.rich-editor__content p{margin:.4em 0}.rich-editor__content ul,.rich-editor__content ol{margin:.4em 0;padding-left:1.5em}.rich-editor__content img{cursor:pointer;border-radius:6px;max-width:100%;height:auto;transition:opacity .15s}.rich-editor__content img:hover{opacity:.85}.rich-editor__content a{color:var(--sage);text-decoration:underline}.rich-editor__content blockquote{border-left:3px solid var(--border-strong);color:var(--text-secondary);margin:.6em 0;padding-left:12px}.rich-editor__content p.is-editor-empty:first-child:before{content:"Start typing or wait for content...";color:var(--text-tertiary);float:left;pointer-events:none;height:0;font-style:italic}.grid-editor__body{background:var(--bg-chat);border:1px solid var(--border);border-radius:6px;max-height:500px;position:relative;overflow:auto}.grid-editor__table-wrap{min-width:100%;position:relative}.grid-editor__table{border-collapse:collapse;width:100%;font-family:var(--font-body);color:var(--text);font-size:13px}.grid-editor__col-header{background:var(--surface);text-align:left;border:1px solid var(--border);white-space:nowrap;-webkit-user-select:none;user-select:none;padding:6px 10px;font-size:12px;font-weight:600;position:relative}.grid-editor__row-header{background:var(--surface);border:1px solid var(--border);text-align:center;width:40px;min-width:40px;padding:4px;position:relative}.grid-editor__row-num{color:var(--text-tertiary);font-size:11px}.grid-editor__row-delete{color:var(--text-tertiary);cursor:pointer;background:0 0;border:none;border-radius:3px;padding:2px;display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.grid-editor__row-header:hover .grid-editor__row-num{display:none}.grid-editor__row-header:hover .grid-editor__row-delete{display:block}.grid-editor__row-delete:hover{color:var(--text);background:var(--sage-subtle)}.grid-editor__cell{border:1px solid var(--border);cursor:text;padding:0;position:relative}.grid-editor__cell--active{outline:2px solid var(--sage);outline-offset:-1px;z-index:1}.grid-editor__cell-text{white-space:nowrap;text-overflow:ellipsis;min-height:28px;padding:4px 8px;display:block;overflow:hidden}.grid-editor__cell-input{background:var(--bg-chat);width:100%;height:100%;min-height:28px;font-family:var(--font-body);color:var(--text);border:none;outline:none;padding:4px 8px;font-size:13px}.grid-editor__resize-handle{cursor:col-resize;z-index:2;width:5px;height:100%;position:absolute;top:0;right:-2px}.grid-editor__resize-handle:hover{background:var(--sage-glow)}.grid-editor__add-row{color:var(--text-tertiary);font-family:var(--font-body);cursor:pointer;background:0 0;border:none;align-items:center;gap:6px;width:100%;padding:6px 10px;font-size:12px;display:flex}.grid-editor__add-row:hover{background:var(--sage-subtle);color:var(--sage)}.grid-editor__comment-popover{z-index:10;background:var(--bg-chat);border:1px solid var(--border-strong);box-shadow:var(--shadow-md);border-radius:8px;flex-direction:column;gap:6px;max-width:280px;padding:8px;display:flex;position:absolute;top:8px;right:8px}.browser-viewer{background:var(--surface);border:1px solid var(--border);border-radius:10px;flex-direction:column;gap:10px;padding:12px;display:flex}.browser-viewer--submitted{opacity:.6;pointer-events:none;padding:10px 14px}.browser-viewer__bar{justify-content:space-between;align-items:center;padding:0 0 4px;display:flex}.browser-viewer__bar[draggable=true]{cursor:grab}.browser-viewer__bar[draggable=true] .browser-viewer__actions{cursor:default}.browser-viewer__icon{width:14px;height:14px;color:var(--text-secondary);flex-shrink:0;margin-right:6px}.browser-viewer__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500}.browser-viewer__actions{gap:4px;margin-left:auto;display:flex}.browser-viewer__iframe{border:1px solid var(--border);background:#111;border-radius:6px;width:100%;min-height:500px;display:block}.browser-viewer--minimised{cursor:pointer;border-left:3px solid var(--sage);background:var(--sage-subtle);gap:0;padding:10px 14px}.browser-viewer--minimised .browser-viewer__iframe{display:none}.browser-viewer--popout{border-left:3px solid var(--sage);background:var(--sage-subtle);padding:10px 14px}.browser-viewer__popout-label{font-family:var(--font-body);color:var(--text-tertiary);padding:2px 0;font-size:12px}.browser-viewer-fullscreen{z-index:1000;background:var(--surface,#111);flex-direction:column;display:flex;position:fixed;inset:0}.browser-viewer-fullscreen__bar{border-bottom:1px solid var(--border);background:var(--surface);flex-shrink:0;justify-content:space-between;align-items:center;padding:8px 12px;display:flex}.browser-viewer-fullscreen__title{font-family:var(--font-body);color:var(--text);font-size:13px;font-weight:500}.browser-viewer-fullscreen__actions{gap:4px;display:flex}.browser-viewer-fullscreen__iframe{background:#111;border:none;flex:1;width:100%}.browser-overlay-popout{z-index:1000;background:var(--surface);border:1px solid var(--border);border-radius:10px;align-items:center;gap:8px;padding:8px 14px;display:flex;position:fixed;bottom:16px;left:50%;transform:translate(-50%);box-shadow:0 2px 12px #00000026}.btn{font-family:var(--font-body);white-space:nowrap;cursor:pointer;-webkit-font-smoothing:antialiased;background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:10px 16px;font-size:14px;font-weight:400;line-height:1;transition:background .15s,opacity .15s,color .15s;display:inline-flex;position:relative}.btn:disabled{opacity:.4;cursor:not-allowed}.btn__content{align-items:center;gap:6px;display:flex}.btn__spinner{justify-content:center;align-items:center;font-size:14px;animation:1.2s linear infinite spin;display:flex;position:absolute;inset:0}.btn--sm .btn__spinner{font-size:11px}.btn--lg .btn__spinner{font-size:17px}.btn--primary{background:var(--sage);color:#fff;border-radius:var(--radius-full)}.btn--primary:hover:not(:disabled){background:var(--sage-hover)}.btn--secondary{color:var(--text-secondary);border:1px solid var(--border-strong);border-radius:var(--radius-full);background:0 0}.btn--secondary:hover:not(:disabled){border-color:var(--sage)}.btn--ghost{color:var(--text-secondary);background:0 0;border:none;padding:0 2px}.btn--ghost:hover:not(:disabled){color:var(--sage)}.btn--danger{background:var(--danger);color:#fff;border-radius:var(--radius-full)}.btn--danger:hover:not(:disabled){background:var(--danger-hover)}.btn--send{background:var(--sage);color:#fff;border-radius:50%}.btn--send:hover:not(:disabled){background:var(--sage-hover)}.btn--send:active:not(:disabled){transform:scale(.95)}.btn--send svg{width:16px;height:16px}.btn--icon{color:var(--text-tertiary);background:0 0;border:none;padding:2px}.btn--icon:hover:not(:disabled){color:var(--text-secondary)}.btn--suggestion{color:var(--text-secondary);border:1px solid var(--border-strong);border-radius:var(--radius-full);background:0 0;font-size:13px}.btn--suggestion:hover:not(:disabled){border-color:var(--sage)}.btn--sm{padding:6px 10px;font-size:12px}.btn--lg{padding:12px 24px;font-size:15px}.btn--full{width:100%}.file-attachment{align-items:center;gap:10px;max-width:380px;display:flex}.file-attachment__icon{color:var(--text-secondary);flex-shrink:0}.file-attachment__info{flex:1;min-width:0}.file-attachment__name{font-family:var(--font-body);color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:1.3;overflow:hidden}.file-attachment__meta{font-family:var(--font-body);color:var(--text-secondary);font-size:11px;line-height:1.4}.file-attachment__download{border:1px solid var(--border);width:32px;height:32px;color:var(--text-secondary);cursor:pointer;background:0 0;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;transition:background .15s,color .15s;display:flex}.file-attachment__download:hover:not(:disabled){background:var(--bg-hover);color:var(--text)}.file-attachment__download:disabled{opacity:.4;cursor:not-allowed}.topic-change-bar{border-top:1px solid var(--border);background:var(--bg);align-items:center;gap:12px;padding:10px 16px;display:flex}.topic-change-bar__icon{color:var(--text-secondary);flex-shrink:0;align-items:center;display:flex}.topic-change-bar__actions{gap:8px;margin-left:auto;display:flex}.data-page{background:var(--chat-bg,#fff);min-height:100vh;color:var(--chat-fg,#111);flex-direction:column;display:flex}.data-header{border-bottom:1px solid #00000014;align-items:center;gap:12px;padding:16px 24px;display:flex}.data-header .chat-logo{width:28px;height:28px}.data-title{align-items:center;gap:8px;margin:0;font-size:18px;font-weight:600;display:inline-flex}.data-back{color:inherit;opacity:.7;align-items:center;gap:4px;margin-left:auto;font-size:13px;text-decoration:none;display:inline-flex}.data-back:hover{opacity:1}.data-main{flex-direction:column;gap:24px;width:100%;max-width:960px;margin:0 auto;padding:24px;display:flex}.data-panel{background:#ffffff80;border:1px solid #00000014;border-radius:10px;padding:20px}.data-panel-heading{align-items:center;gap:12px;margin-bottom:4px;display:flex}.data-panel-title{margin:0 0 4px;font-size:15px;font-weight:600}.data-panel-subtitle{opacity:.7;margin:0 0 16px;font-size:13px}.data-panel-subtitle code{background:#0000000f;border-radius:4px;padding:1px 5px;font-family:ui-monospace,Menlo,monospace;font-size:12px}.data-file-actions{gap:8px;margin-left:auto;display:flex}.data-btn{cursor:pointer;color:inherit;background:#fff;border:1px solid #0000001f;border-radius:6px;align-items:center;gap:6px;padding:6px 12px;font-size:13px;display:inline-flex}.data-btn:hover:not(:disabled){background:#0000000a}.data-btn:disabled{opacity:.5;cursor:not-allowed}.data-btn-ghost{opacity:.7;background:0 0;border-color:#0000}.data-btn-ghost:hover:not(:disabled){opacity:1;background:#0000000a}.data-search-input{background:#fff;border:1px solid #0000001f;border-radius:8px;align-items:center;gap:8px;padding:8px 12px;display:flex}.data-search-input input{color:inherit;background:0 0;border:none;outline:none;flex:1;font-family:inherit;font-size:14px}.data-results-meta{opacity:.6;margin-top:12px;font-size:12px}.data-empty-results,.data-loading,.data-empty{opacity:.7;text-align:center;padding:16px;font-size:13px}.data-empty{padding:48px 16px}.data-error{color:#a33;background:#c8282814;border:1px solid #c828284d;border-radius:6px;margin-top:12px;padding:8px 12px;font-size:13px}.data-results{flex-direction:column;gap:8px;margin:16px 0 0;padding:0;list-style:none;display:flex}.data-result{background:#fff;border:1px solid #00000014;border-radius:8px;padding:12px 14px}.data-result-header{opacity:.6;justify-content:space-between;align-items:center;margin-bottom:4px;font-family:ui-monospace,Menlo,monospace;font-size:11px;display:flex}.data-result-title{margin-bottom:6px;font-size:14px;font-weight:600}.data-result-body{white-space:pre-wrap;word-break:break-word;margin:0;font-family:inherit;font-size:13px;line-height:1.45}.data-result-toggle{color:inherit;opacity:.7;cursor:pointer;background:0 0;border:none;margin-top:6px;padding:0;font-size:12px}.data-result-toggle:hover{opacity:1}.data-breadcrumbs{flex-wrap:wrap;align-items:center;gap:4px;margin-bottom:12px;font-size:13px;display:flex}.data-crumb{color:inherit;cursor:pointer;background:0 0;border:none;border-radius:4px;padding:2px 4px;font-size:13px}.data-crumb:hover{background:#0000000d}.data-crumb-sep{opacity:.4}.data-crumb-wrap{align-items:center;gap:4px;display:inline-flex}.data-up-btn{margin-left:auto}.data-entries{background:#fff;border:1px solid #00000014;border-radius:8px;flex-direction:column;margin:0;padding:0;list-style:none;display:flex;overflow:hidden}.data-entry+.data-entry{border-top:1px solid #0000000f}.data-entry-btn{cursor:pointer;text-align:left;width:100%;color:inherit;background:0 0;border:none;align-items:center;gap:10px;padding:10px 14px;font-size:13px;display:flex}.data-entry-btn:hover:not(.data-entry-disabled){background:#0000000a}.data-entry-disabled{opacity:.5;cursor:default}.data-entry-name{text-overflow:ellipsis;white-space:nowrap;flex:1;font-family:inherit;overflow:hidden}.data-entry-meta{opacity:.55;white-space:nowrap;font-size:11px}.data-entry-download-icon{opacity:.5}.data-link{color:inherit;text-decoration:underline}
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/admin-
|
|
8
|
+
<script type="module" crossorigin src="/assets/admin-tPrH6zWV.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-Be6NvmcD.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-rov5CBGT.js">
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/useVoiceRecorder-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/useVoiceRecorder-
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/useVoiceRecorder-3Qblv7wH.js">
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/useVoiceRecorder-BNLXzSN4.css">
|
|
13
13
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/public-
|
|
8
|
+
<script type="module" crossorigin src="/assets/public-DdVq1Jag.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-Be6NvmcD.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-rov5CBGT.js">
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/useVoiceRecorder-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/useVoiceRecorder-
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/useVoiceRecorder-3Qblv7wH.js">
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/useVoiceRecorder-BNLXzSN4.css">
|
|
13
13
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
package/payload/server/server.js
CHANGED
|
@@ -4336,7 +4336,7 @@ import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
|
4336
4336
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4337
4337
|
import { resolve as resolve6, join as join4 } from "path";
|
|
4338
4338
|
import { platform as osPlatform } from "os";
|
|
4339
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, readdirSync as readdirSync2, existsSync as existsSync6, mkdirSync as mkdirSync4, createWriteStream, statSync as statSync3, unlinkSync as unlinkSync2, cpSync, rmSync, appendFileSync as appendFileSync2, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
|
|
4339
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, readdirSync as readdirSync2, existsSync as existsSync6, mkdirSync as mkdirSync4, createWriteStream, statSync as statSync3, unlinkSync as unlinkSync2, cpSync, rmSync as rmSync2, appendFileSync as appendFileSync2, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
|
|
4340
4340
|
import { lookup as dnsLookup } from "dns/promises";
|
|
4341
4341
|
import { createConnection as netConnect } from "net";
|
|
4342
4342
|
import { StringDecoder } from "string_decoder";
|
|
@@ -4639,7 +4639,7 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4639
4639
|
import neo4j from "neo4j-driver";
|
|
4640
4640
|
import { randomUUID } from "crypto";
|
|
4641
4641
|
import { spawn } from "child_process";
|
|
4642
|
-
import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync5, openSync, readSync, closeSync, statSync as statSync2 } from "fs";
|
|
4642
|
+
import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync5, openSync, readSync, closeSync, statSync as statSync2, rmSync } from "fs";
|
|
4643
4643
|
import { resolve as resolve5 } from "path";
|
|
4644
4644
|
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "..");
|
|
4645
4645
|
var driver = null;
|
|
@@ -5864,9 +5864,53 @@ ${sections.join("\n\n")}
|
|
|
5864
5864
|
await session.close();
|
|
5865
5865
|
}
|
|
5866
5866
|
}
|
|
5867
|
+
async function consumeStep7FlagUI(session, accountId) {
|
|
5868
|
+
const accountDir = resolve5(PLATFORM_ROOT3, "..", "data/accounts", accountId);
|
|
5869
|
+
const flagPath = resolve5(accountDir, "onboarding", "step7-complete");
|
|
5870
|
+
if (!existsSync5(flagPath)) return false;
|
|
5871
|
+
let completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5872
|
+
try {
|
|
5873
|
+
const raw2 = readFileSync6(flagPath, "utf-8").trim();
|
|
5874
|
+
if (raw2) {
|
|
5875
|
+
const parsed = JSON.parse(raw2);
|
|
5876
|
+
if (typeof parsed.completedAt === "string") {
|
|
5877
|
+
completedAt = parsed.completedAt;
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
} catch {
|
|
5881
|
+
}
|
|
5882
|
+
const result = await session.run(
|
|
5883
|
+
`MATCH (o:OnboardingState {accountId: $accountId})
|
|
5884
|
+
SET o.step7CompletedAt = CASE WHEN o.step7CompletedAt IS NULL THEN $completedAt ELSE o.step7CompletedAt END,
|
|
5885
|
+
o.currentStep = CASE WHEN 7 > o.currentStep THEN 7 ELSE o.currentStep END,
|
|
5886
|
+
o.updatedAt = $completedAt
|
|
5887
|
+
RETURN count(o) AS updated`,
|
|
5888
|
+
{ accountId, completedAt }
|
|
5889
|
+
);
|
|
5890
|
+
const updatedRaw = result.records[0]?.get("updated");
|
|
5891
|
+
const updated = typeof updatedRaw === "number" ? updatedRaw : updatedRaw && typeof updatedRaw === "object" && "toNumber" in updatedRaw ? updatedRaw.toNumber() : 0;
|
|
5892
|
+
if (updated === 0) {
|
|
5893
|
+
console.log(
|
|
5894
|
+
`[onboarding-flag-consumed] accountId=${accountId.slice(0, 8)}\u2026 step=7 source=filesystem flagPath=${flagPath} skipped=no-node`
|
|
5895
|
+
);
|
|
5896
|
+
return false;
|
|
5897
|
+
}
|
|
5898
|
+
console.log(
|
|
5899
|
+
`[onboarding-flag-consumed] accountId=${accountId.slice(0, 8)}\u2026 step=7 source=filesystem flagPath=${flagPath} completedAt=${completedAt}`
|
|
5900
|
+
);
|
|
5901
|
+
try {
|
|
5902
|
+
rmSync(flagPath);
|
|
5903
|
+
} catch (err) {
|
|
5904
|
+
console.error(
|
|
5905
|
+
`[onboarding-flag-consumed] warn: failed to delete ${flagPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
5906
|
+
);
|
|
5907
|
+
}
|
|
5908
|
+
return true;
|
|
5909
|
+
}
|
|
5867
5910
|
async function loadOnboardingStep(accountId) {
|
|
5868
5911
|
const session = getSession();
|
|
5869
5912
|
try {
|
|
5913
|
+
await consumeStep7FlagUI(session, accountId);
|
|
5870
5914
|
const result = await session.run(
|
|
5871
5915
|
`MATCH (o:OnboardingState {accountId: $accountId})
|
|
5872
5916
|
RETURN o.currentStep AS currentStep`,
|
|
@@ -6911,7 +6955,7 @@ function migratePluginRenames(accountDir, config2) {
|
|
|
6911
6955
|
const orphan = resolve6(pluginsDir, oldName);
|
|
6912
6956
|
if (existsSync6(orphan)) {
|
|
6913
6957
|
try {
|
|
6914
|
-
|
|
6958
|
+
rmSync2(orphan, { recursive: true });
|
|
6915
6959
|
console.log(`${TAG18} removed orphan: ${oldName}`);
|
|
6916
6960
|
} catch (err) {
|
|
6917
6961
|
console.log(`${TAG18} orphan removal failed: ${oldName} \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -7781,6 +7825,17 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
|
|
|
7781
7825
|
args: [resolve6(PLATFORM_ROOT4, "plugins/email/mcp/dist/index.js")],
|
|
7782
7826
|
env: { ...baseEnv }
|
|
7783
7827
|
},
|
|
7828
|
+
// Workflows MCP — persistent admin-session server for list/get/update/delete/
|
|
7829
|
+
// validate/runs (the "manage" verbs). The same binary also spawns ad-hoc from
|
|
7830
|
+
// the heartbeat cron for `workflow-execute` via plugins/workflows/.mcp.json;
|
|
7831
|
+
// the two paths are independent. Without this entry the permission allowlist
|
|
7832
|
+
// at ADMIN_CORE_TOOLS grants tools the session never registers, and the model
|
|
7833
|
+
// ToolSearches fruitlessly before degrading to a task-create stand-in (Task 571).
|
|
7834
|
+
"workflows": {
|
|
7835
|
+
command: "node",
|
|
7836
|
+
args: [resolve6(PLATFORM_ROOT4, "plugins/workflows/mcp/dist/index.js")],
|
|
7837
|
+
env: { ...baseEnv }
|
|
7838
|
+
},
|
|
7784
7839
|
// Playwright MCP server — browser automation for browser-specialist.
|
|
7785
7840
|
// Key matches Claude Code's plugin naming: plugin_{plugin}_{server} so tools
|
|
7786
7841
|
// appear as mcp__plugin_playwright_playwright__browser_navigate etc.
|
|
@@ -7873,12 +7928,15 @@ var ADMIN_CORE_TOOLS = [
|
|
|
7873
7928
|
"Glob",
|
|
7874
7929
|
"Grep",
|
|
7875
7930
|
"Agent",
|
|
7876
|
-
//
|
|
7877
|
-
//
|
|
7931
|
+
// Upstream mcp-neo4j-cypher (namespaced maxy-graph, read-only).
|
|
7932
|
+
// FastMCP joins NEO4J_NAMESPACE to each upstream tool name with a hyphen,
|
|
7933
|
+
// and allowedTools matching is string-exact under --permission-mode dontAsk —
|
|
7934
|
+
// these names must equal the init-message tool list byte-for-byte.
|
|
7935
|
+
// maxy-graph-write_neo4j_cypher is intentionally absent: writes go through
|
|
7878
7936
|
// the schema-aware memory-write tool, which validates labels, properties,
|
|
7879
7937
|
// and embeddings. Admin-only by virtue of not being in the public allow list.
|
|
7880
|
-
"mcp__graph__maxy-
|
|
7881
|
-
"mcp__graph__maxy-
|
|
7938
|
+
"mcp__graph__maxy-graph-read_neo4j_cypher",
|
|
7939
|
+
"mcp__graph__maxy-graph-get_neo4j_schema",
|
|
7882
7940
|
"mcp__memory__memory-search",
|
|
7883
7941
|
"mcp__memory__memory-rank",
|
|
7884
7942
|
"mcp__memory__memory-write",
|
|
@@ -11009,6 +11067,63 @@ function defaultRules() {
|
|
|
11009
11067
|
thresholdCount: 0,
|
|
11010
11068
|
thresholdWindowMinutes: 0,
|
|
11011
11069
|
suggestedAction: "The stored Anthropic API key was rejected by console.anthropic.com (invalid, revoked, or expired) and `anthropic-setup` auto-deleted it. On the next operator interaction, explain that the key was cleared and walk them through sign-in again via the onboarding skill \u2014 the tool already returned `awaiting_signin` with the correct `browser_evaluate` action on the same call."
|
|
11070
|
+
},
|
|
11071
|
+
{
|
|
11072
|
+
// Task 562: setup-tunnel.sh persists step-7 completion to a filesystem
|
|
11073
|
+
// flag before arming the service restart. The flag is consumed by the
|
|
11074
|
+
// next session's `loadOnboardingStep` and `getOnboardingState` calls,
|
|
11075
|
+
// so any runtime failure to write it means the next admin session
|
|
11076
|
+
// will re-ask the Cloudflare question the user just answered. Every
|
|
11077
|
+
// occurrence is loud-surface-worthy: the cause is either a permission
|
|
11078
|
+
// issue on the onboarding directory or a filesystem problem on the
|
|
11079
|
+
// device, and the recovery is deterministic (the operator can re-run
|
|
11080
|
+
// setup-tunnel.sh or call `onboarding-complete-step` explicitly).
|
|
11081
|
+
id: "setup-tunnel-onboarding-persist-failed",
|
|
11082
|
+
name: "setup-tunnel.sh failed to persist step-7 completion",
|
|
11083
|
+
type: "silent-catch",
|
|
11084
|
+
logSource: "any",
|
|
11085
|
+
pattern: "\\[setup-tunnel\\] step=onboarding-persist result=error",
|
|
11086
|
+
thresholdCount: 0,
|
|
11087
|
+
thresholdWindowMinutes: 0,
|
|
11088
|
+
suggestedAction: "[Task 562] setup-tunnel.sh could not persist step-7 completion before arming the service restart. Read the `reason` field on the failing phase line: `fs-flag-dir-failed` means `${ACCOUNT_DIR}/onboarding/` is not writable (chmod issue or disk full); `fs-flag-write-failed` means the flag file itself could not be written. Without the flag, the next admin session will re-ask the Cloudflare question the user just answered. Recovery: fix the permission/disk issue, then either re-run `~/setup-tunnel.sh` (the flag-write is idempotent) or call `onboarding-complete-step` with step 7 from the admin chat to mark step 7 complete explicitly."
|
|
11089
|
+
},
|
|
11090
|
+
{
|
|
11091
|
+
// Task 570: every `[llm-call] adminModel resolution FAILED:` line
|
|
11092
|
+
// is a workflow LLM step that could not resolve a model because
|
|
11093
|
+
// readAdminModel returned null. The stderr line carries `reason=`
|
|
11094
|
+
// (enoent/eacces/fs_error/parse_error/field_missing/
|
|
11095
|
+
// field_wrong_type/field_empty) so the admin agent can act on the
|
|
11096
|
+
// specific failure mode rather than reading the generic persisted
|
|
11097
|
+
// error and misdiagnosing. Every occurrence is worth surfacing —
|
|
11098
|
+
// the workflow already failed when this line was emitted.
|
|
11099
|
+
id: "workflow-admin-model-resolution-failed",
|
|
11100
|
+
name: "Workflow readAdminModel returned null (reason code in log)",
|
|
11101
|
+
type: "silent-catch",
|
|
11102
|
+
logSource: "any",
|
|
11103
|
+
pattern: "\\[llm-call\\] adminModel resolution FAILED:",
|
|
11104
|
+
thresholdCount: 0,
|
|
11105
|
+
thresholdWindowMinutes: 0,
|
|
11106
|
+
suggestedAction: "A workflow LLM step could not resolve the account's adminModel. Read the log line's `reason=` field: `enoent` means the account.json path is wrong or the account is unprovisioned \u2014 inspect `path=` and confirm it exists. `eacces` means permission drift \u2014 check file ownership. `parse_error` means the file is malformed, likely mid-write or truncated \u2014 read the file and repair. `field_missing` / `field_wrong_type` / `field_empty` mean the `adminModel` field needs to be set to a valid model ID. Never edit the persisted WorkflowRun.error string; fix the underlying file or permissions and re-run the workflow."
|
|
11107
|
+
},
|
|
11108
|
+
{
|
|
11109
|
+
// Task 561: fires when an admin-agent Bash tool call installs
|
|
11110
|
+
// `bind9-dnsutils` at runtime. Post-Task-561 the Maxy installer
|
|
11111
|
+
// (platform/scripts/setup.sh) provisions the package on every fresh
|
|
11112
|
+
// and upgrade install, so `dig` is always in PATH before
|
|
11113
|
+
// setup-tunnel.sh runs. An admin apt-install of bind9-dnsutils is
|
|
11114
|
+
// therefore evidence the installer regressed (or the host is on a
|
|
11115
|
+
// pre-Task-561 image); in either case the fix is to re-run the
|
|
11116
|
+
// installer, not to patch apt-state from chat. Session scope so a
|
|
11117
|
+
// single offending turn fires exactly once.
|
|
11118
|
+
id: "admin-agent-apt-bind9-install",
|
|
11119
|
+
name: "Admin agent installed bind9-dnsutils at runtime (installer regression)",
|
|
11120
|
+
type: "repeated-error",
|
|
11121
|
+
logSource: "any",
|
|
11122
|
+
pattern: "\\[tool-use\\][^\\n]*name=Bash[^\\n]*apt-get install[^\\n]*bind9-dnsutils",
|
|
11123
|
+
thresholdCount: 1,
|
|
11124
|
+
thresholdWindowMinutes: 60,
|
|
11125
|
+
scope: "session",
|
|
11126
|
+
suggestedAction: "[Task 561 regression] The admin agent ran `apt-get install bind9-dnsutils` \u2014 the exact workaround Task 561 eliminated. The Maxy installer provisions `bind9-dnsutils` in `platform/scripts/setup.sh` so `dig` is always in PATH before `setup-tunnel.sh` runs. Do not patch apt-state from chat \u2014 re-run the installer (`npx -y @rubytech/create-maxy`) and verify the installer's apt-get line still includes `bind9-dnsutils`. If the package is present in setup.sh but missing on the device, the installer did not re-run step 1 on the current image."
|
|
11012
11127
|
}
|
|
11013
11128
|
];
|
|
11014
11129
|
}
|
|
@@ -32192,7 +32307,7 @@ async function GET12() {
|
|
|
32192
32307
|
|
|
32193
32308
|
// app/api/admin/agents/[slug]/route.ts
|
|
32194
32309
|
import { resolve as resolve24 } from "path";
|
|
32195
|
-
import { existsSync as existsSync22, rmSync as
|
|
32310
|
+
import { existsSync as existsSync22, rmSync as rmSync3 } from "fs";
|
|
32196
32311
|
async function DELETE2(_req, { params }) {
|
|
32197
32312
|
const { slug } = await params;
|
|
32198
32313
|
const account = resolveAccount();
|
|
@@ -32210,7 +32325,7 @@ async function DELETE2(_req, { params }) {
|
|
|
32210
32325
|
return Response.json({ error: "Agent not found" }, { status: 404 });
|
|
32211
32326
|
}
|
|
32212
32327
|
try {
|
|
32213
|
-
|
|
32328
|
+
rmSync3(agentDir, { recursive: true, force: true });
|
|
32214
32329
|
console.log(`[admin/agents] deleted agent "${slug}"`);
|
|
32215
32330
|
return Response.json({ ok: true });
|
|
32216
32331
|
} catch (err) {
|