@rubytech/create-maxy 1.0.472 → 1.0.474
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/package.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +2 -2
- package/payload/platform/plugins/admin/skills/public-agent-manager/skill.md +3 -3
- package/payload/platform/plugins/docs/references/migration-guide.md +29 -21
- package/payload/platform/plugins/memory/PLUGIN.md +6 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +58 -22
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +35 -23
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +40 -7
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/scripts/migrate-import.sh +17 -11
- package/payload/platform/scripts/seed-neo4j.sh +15 -61
- package/payload/platform/templates/account.json +1 -1
- package/payload/server/public/assets/ChatInput-BZayQkAS.css +1 -0
- package/payload/server/public/assets/{admin-B1CMS86q.js → admin-CW4uB1GJ.js} +2 -2
- package/payload/server/public/assets/public-DEZaIlO-.js +5 -0
- package/payload/server/public/index.html +3 -3
- package/payload/server/public/public.html +3 -3
- package/payload/server/server.js +46 -102
- package/payload/platform/plugins/admin/hooks/agent-creation-approval.sh +0 -161
- package/payload/platform/plugins/admin/hooks/agent-creation-gate.sh +0 -317
- package/payload/platform/plugins/admin/hooks/agent-creation-post.sh +0 -165
- package/payload/platform/plugins/admin/hooks/session-start.sh +0 -104
- package/payload/platform/plugins/admin/hooks/test-agent-creation-gate.sh +0 -926
- package/payload/server/public/assets/ChatInput-BEwQxFL9.css +0 -1
- package/payload/server/public/assets/public-ojODTkXT.js +0 -5
- /package/payload/server/public/assets/{ChatInput-Dnp1FLis.js → ChatInput-DgjefIvo.js} +0 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{C as e,D as t,S as n,T as r,_ as i,a,b as o,d as s,f as c,h as l,i as u,j as d,k as f,m as p,n as m,p as h,r as g,s as _,t as v,u as y,v as b,w as x,x as S,y as C}from"./ChatInput-DgjefIvo.js";var w=t(),T=d(f(),1),E=`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html`,D=new Set(E.split(`,`)),O=20*1024*1024,k=typeof window<`u`&&/^(localhost|127\.0\.0\.1|[a-z0-9-]+\.local)(:|$)/.test(window.location.hostname);function A(){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 j(){let e=window.location.pathname.match(/^\/([a-z][a-z0-9-]{2,49})$/);return e?e[1]:void 0}function M(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 leading or trailing spaces`,met:e.length>0&&e===e.trim()}]}function N(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 P(e){let[t,n]=(0,T.useState)(null),[r,i]=(0,T.useState)(null),[a,o]=(0,T.useState)(`loading`),[s,c]=(0,T.useState)(``),[l,u]=(0,T.useState)(null),[d,f]=(0,T.useState)(null),[p,m]=(0,T.useState)(!1),[h,g]=(0,T.useState)(null),_=(0,T.useMemo)(()=>j(),[]),v=(0,T.useRef)(_||``),y=(0,T.useRef)(null),b=(0,T.useRef)(null),x=(0,T.useRef)(!1),S=(0,T.useRef)(null),[C,w]=(0,T.useState)(`sign-in`),[E,D]=(0,T.useState)(null),O=(0,T.useRef)(null),M=(0,T.useRef)(null);(0,T.useEffect)(()=>{try{let e=sessionStorage.getItem(`maxy_session`);e&&(M.current=e)}catch{}},[]);let N=(0,T.useCallback)(t=>{y.current=t,n(t);try{sessionStorage.setItem(`maxy_session`,t)}catch{}o(`chat`),e(t)},[e]),P=(0,T.useCallback)(()=>{y.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}n(null),o(`auth-required`),w(`sign-in`)},[]),F=(0,T.useCallback)(async e=>{try{let t=v.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?(O.current=r.session_key,D(r.grant),w(`set-password`),window.history.replaceState({},``,window.location.pathname)):w(`link-expired`)}catch{w(`sign-in`)}},[]);return{sessionId:t,sessionKeyRef:y,sessionError:r,pageState:a,setPageState:o,agentDisplayName:s,agentImage:l,agentImageShape:d,showAgentName:p,agentSlug:_,branding:h,resolvedSlugRef:v,ensureSession:(0,T.useCallback)(async()=>{if(y.current)return y.current;if(b.current)return b.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:A(),..._?{agent:_}:{},...e?{session_key:e}:{}})});if(!t.ok){let e=await t.json().catch(()=>({error:``}));return k&&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&&(v.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?F(e):w(`sign-in`),null}y.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&&(x.current=!0,S.current=r.messages);try{sessionStorage.setItem(`maxy_session`,r.session_key)}catch{}return r.session_key}catch(e){return k&&console.error(`[session] fetch /api/session threw:`,e),i(`Unable to connect. Please check your connection and try again.`),null}finally{b.current=null}})();return b.current=e,e},[_,F]),enterChat:N,enterGate:P,resumedRef:x,resumeMessagesRef:S,gateState:C,setGateState:w,grantInfo:E,setGrantInfo:D,gateSessionKeyRef:O}}function F({sessionKeyRef:e,ensureSession:t,sessionError:n,pageState:r,inputRef:a}){let[o,s]=(0,T.useState)([]),[c,l]=(0,T.useState)(!1),u=(0,T.useRef)(!1),d=e=>{u.current=e,l(e)},f=(0,T.useCallback)(async o=>{if(!u.current){d(!0),s([{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:o})});if(n.status===401){e.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}k&&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=``,a=``,c=()=>{a&&(r+=a,a=``,s(e=>{let t=[...e];return t[0]={...t[0],content:r},t}))},l=setInterval(c,60);try{for await(let e of i(n)){if(e.error)throw Object.assign(Error(e.error),{fromSSE:!0});e.text&&(a+=e.text),e.type===`component`&&(c(),s(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(l),c()}}catch(e){if(k&&console.error(`[chat] greeting failed:`,e),r===`auth-required`)return;let t=e instanceof Error?e.message:String(e);s([{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`&&a.current?.focus()}}},[e,t,n,r,a]),p=(0,T.useCallback)(async(o,c)=>{let l=c?.hidden??!1,f=c?.files??[];if(!o&&f.length===0||u.current)return;d(!0);let p=f.map(e=>({filename:e.name,mimeType:e.type})),m={role:`visitor`,content:o,attachments:p.length>0?p:void 0,timestamp:Date.now(),hidden:l},h;s(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`,o),t.append(`session_key`,e);for(let e of f)t.append(`attachments`,e);return{body:t,headers:{}}}return{body:JSON.stringify({message:o,session_key:e}),headers:{"Content-Type":`application/json`}}},{body:a,headers:c}=r(n),l=await fetch(`/api/chat`,{method:`POST`,headers:c,body:a});if(l.status===401){e.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}k&&console.warn(`[session-expired] stale key cleared, retrying with fresh session`);let n=await t();if(!n)throw Error(`session`);({body:a,headers:c}=r(n)),l=await fetch(`/api/chat`,{method:`POST`,headers:c,body:a})}if(!l.ok){let e=await l.json().catch(()=>({}));throw Error(e.error||`Something went wrong`)}let u=``,d=``,p=()=>{d&&(u+=d,d=``,s(e=>{let t=[...e];return t[h]={...t[h],content:u},t}))},m=setInterval(p,60);try{for await(let e of i(l)){if(e.error)throw Object.assign(Error(e.error),{fromSSE:!0});e.text&&(d+=e.text),e.type===`component`&&(p(),s(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(k&&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;s(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`&&a.current?.focus()}},[e,t,n,r,a]);return{messages:o,setMessages:s,isStreaming:c,sendMessage:p,sendGreeting:f,handleComponentSubmit:(0,T.useCallback)((e,t,n)=>{s(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])}}var I=c();function L({value:e,onChange:t,onComplete:n,disabled:r}){let i=(0,T.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,I.jsx)(`div`,{className:`gate-otp-field`,children:Array.from({length:6}).map((t,n)=>(0,I.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 R({gateState:e,setGateState:t,grantInfo:n,setGrantInfo:r,gateSessionKeyRef:i,resolvedSlugRef:a,onAuthenticated:o}){let[c,l]=(0,T.useState)(``),[u,d]=(0,T.useState)(``),[f,p]=(0,T.useState)(``),[m,h]=(0,T.useState)(!1),[g,_]=(0,T.useState)(``),[v,b]=(0,T.useState)(``),[x,S]=(0,T.useState)(!1),[C,w]=(0,T.useState)(null),[E,D]=(0,T.useState)(null),[O,k]=(0,T.useState)(!1);async function A(e){if(e.preventDefault(),!O){w(null),k(!0);try{let e=a.current,n=await fetch(`/api/access/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contact:c,password:u,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:c,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{k(!1)}}}async function j(e){if(!O){w(null),k(!0);try{let n=a.current,o=await fetch(`/api/access/verify-otp`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({phone:v,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`),_(``))}catch{w(`Unable to connect. Please try again.`)}finally{k(!1)}}}async function P(e){if(e.preventDefault(),!O){if(w(null),u!==f){w(`Passwords do not match`);return}if(!M(u).every(e=>e.met)){w(`Password does not meet requirements`);return}k(!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:u})}),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{k(!1)}}}async function F(e){if(e.preventDefault(),!(O||!c)){w(null),k(!0);try{let e=a.current,t=await fetch(`/api/access/forgot-password`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contact:c,agentSlug:e})});t.status===429?w((await t.json()).error||`Too many attempts. Please try again later.`):(D(`If an account exists, a reset link has been sent.`),setTimeout(()=>{S(!1),D(null)},4e3))}catch{w(`Unable to connect. Please try again.`)}finally{k(!1)}}}switch(e){case`set-password`:{let e=M(u),t=e.every(e=>e.met),r=u===f,i=t&&r&&f.length>0;return(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsxs)(`div`,{className:`gate-card`,children:[n?.expiresAt&&(0,I.jsxs)(`div`,{className:`gate-expiry-badge`,children:[`Access until `,new Date(n.expiresAt).toLocaleDateString(`en-GB`,{day:`numeric`,month:`short`,year:`numeric`})]}),(0,I.jsxs)(`h2`,{className:`gate-title`,children:[`Welcome, `,n?.displayName||`there`]}),(0,I.jsx)(`p`,{className:`gate-subtitle`,children:`Create a password to access this agent in the future.`}),(0,I.jsxs)(`form`,{className:`gate-form`,onSubmit:P,children:[(0,I.jsxs)(`div`,{className:`gate-field`,children:[(0,I.jsx)(`label`,{htmlFor:`gate-display-name`,children:`Display name`}),(0,I.jsx)(`input`,{id:`gate-display-name`,type:`text`,value:n?.displayName||``,disabled:!0})]}),(0,I.jsxs)(`div`,{className:`gate-field gate-pw-row`,children:[(0,I.jsx)(`label`,{htmlFor:`gate-pw`,children:`Password`}),(0,I.jsx)(`div`,{className:`gate-pw-toggle`,children:(0,I.jsx)(s,{checked:m,onChange:h,label:`Show`})}),(0,I.jsx)(`input`,{id:`gate-pw`,type:m?`text`:`password`,value:u,onChange:e=>d(e.target.value),placeholder:`Your password`,autoFocus:!0,autoComplete:`new-password`}),u.length>0&&(0,I.jsx)(`div`,{className:`gate-strength`,children:e.map(e=>(0,I.jsxs)(`span`,{className:`gate-strength-item${e.met?` met`:``}`,children:[e.met?`✓`:`○`,` `,e.label]},e.key))})]}),(0,I.jsxs)(`div`,{className:`gate-field`,children:[(0,I.jsx)(`label`,{htmlFor:`gate-pw-confirm`,children:`Confirm password`}),(0,I.jsx)(`input`,{id:`gate-pw-confirm`,type:m?`text`:`password`,value:f,onChange:e=>p(e.target.value),placeholder:`Confirm your password`,autoComplete:`new-password`}),f.length>0&&!r&&(0,I.jsx)(`div`,{className:`gate-error`,children:`Passwords do not match`})]}),C&&(0,I.jsx)(`div`,{className:`gate-error`,children:C}),(0,I.jsx)(`div`,{className:`gate-submit`,children:(0,I.jsx)(y,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!i||O,loading:O,children:`Create account & enter chat`})})]})]})})}case`enter-otp`:return(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsxs)(`div`,{className:`gate-card`,children:[(0,I.jsx)(`h2`,{className:`gate-title`,children:`Enter your code`}),(0,I.jsxs)(`p`,{className:`gate-subtitle`,children:[`Enter the 6-digit code sent to `,N(v,`phone`)]}),(0,I.jsx)(L,{value:g,onChange:_,onComplete:j,disabled:O}),C&&(0,I.jsx)(`div`,{className:`gate-error`,children:C}),O&&(0,I.jsxs)(`div`,{className:`gate-loading`,children:[(0,I.jsx)(`span`,{className:`spinner`}),`Verifying...`]}),(0,I.jsx)(`div`,{className:`gate-resend`,children:(0,I.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{t(`sign-in`),_(``),w(null)},children:`Use a different number`})})]})});case`sign-in`:case`private-agent`:return(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsxs)(`div`,{className:`gate-card`,children:[(0,I.jsx)(`h2`,{className:`gate-title`,children:e===`private-agent`?`Private Agent`:`Welcome back`}),(0,I.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,I.jsxs)(`form`,{className:`gate-form`,onSubmit:F,children:[(0,I.jsxs)(`div`,{className:`gate-field`,children:[(0,I.jsx)(`label`,{htmlFor:`gate-forgot-contact`,children:`Email or phone`}),(0,I.jsx)(`input`,{id:`gate-forgot-contact`,type:`text`,value:c,onChange:e=>l(e.target.value),placeholder:`you@example.com`,autoFocus:!0,autoComplete:`email`})]}),C&&(0,I.jsx)(`div`,{className:`gate-error`,children:C}),E&&(0,I.jsx)(`div`,{className:`gate-success`,children:E}),(0,I.jsx)(`div`,{className:`gate-submit`,children:(0,I.jsx)(y,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!c.trim()||O,loading:O,children:`Send reset link`})}),(0,I.jsx)(`div`,{className:`gate-actions`,children:(0,I.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{S(!1),w(null),D(null)},children:`Back to sign in`})})]}):(0,I.jsxs)(`form`,{className:`gate-form`,onSubmit:A,children:[(0,I.jsxs)(`div`,{className:`gate-field`,children:[(0,I.jsx)(`label`,{htmlFor:`gate-contact`,children:`Email or phone`}),(0,I.jsx)(`input`,{id:`gate-contact`,type:`text`,value:c,onChange:e=>l(e.target.value),placeholder:`you@example.com`,autoFocus:!0,autoComplete:`email`})]}),(0,I.jsxs)(`div`,{className:`gate-field gate-pw-row`,children:[(0,I.jsx)(`label`,{htmlFor:`gate-login-pw`,children:`Password`}),(0,I.jsx)(`div`,{className:`gate-pw-toggle`,children:(0,I.jsx)(s,{checked:m,onChange:h,label:`Show`})}),(0,I.jsx)(`input`,{id:`gate-login-pw`,type:m?`text`:`password`,value:u,onChange:e=>d(e.target.value),placeholder:`Your password`,autoComplete:`current-password`})]}),C&&(0,I.jsx)(`div`,{className:`gate-error`,children:C}),(0,I.jsx)(`div`,{className:`gate-submit`,children:(0,I.jsx)(y,{variant:`primary`,type:`submit`,fullWidth:!0,disabled:!c.trim()||!u||O,loading:O,children:`Sign in`})}),(0,I.jsx)(`div`,{className:`gate-actions`,children:(0,I.jsx)(`button`,{type:`button`,className:`gate-link`,onClick:()=>{S(!0),w(null)},children:`Forgot password?`})})]}),e===`private-agent`&&(0,I.jsx)(`p`,{className:`gate-hint`,children:`No account? You need an invitation from the agent owner.`})]})});case`access-expired`:return(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsxs)(`div`,{className:`gate-card`,children:[(0,I.jsx)(`div`,{className:`gate-icon`,children:`⏰`}),(0,I.jsx)(`h2`,{className:`gate-title`,children:`Access expired`}),(0,I.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,I.jsx)(`div`,{className:`gate-actions`,children:(0,I.jsx)(y,{variant:`secondary`,onClick:()=>{t(`sign-in`),w(null),d(``)},children:`Sign in with a different account`})})]})});case`link-expired`:return(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsxs)(`div`,{className:`gate-card`,children:[(0,I.jsx)(`div`,{className:`gate-icon`,children:`⚠️`}),(0,I.jsx)(`h2`,{className:`gate-title`,children:`Link expired`}),(0,I.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,I.jsx)(`div`,{className:`gate-actions`,children:(0,I.jsx)(y,{variant:`primary`,onClick:()=>{t(`sign-in`),w(null)},children:`Go to sign in`})})]})});case`otp-failed`:return(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsxs)(`div`,{className:`gate-card`,children:[(0,I.jsx)(`div`,{className:`gate-icon`,children:`⛔`}),(0,I.jsx)(`h2`,{className:`gate-title`,children:`Too many attempts`}),(0,I.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,I.jsx)(`div`,{className:`gate-actions`,children:(0,I.jsx)(y,{variant:`secondary`,onClick:()=>{t(`sign-in`),w(null),_(``)},children:`Back to sign in`})})]})})}}var z={"single-select":a,"multi-select":u};function B({name:e,data:t,onSubmit:n,submitted:r}){let i=z[e];return i?(0,I.jsx)(i,{data:t,onSubmit:n,submitted:r}):(console.warn(`[PublicComponentRenderer] Unknown component: "${e}". Registered: ${Object.keys(z).join(`, `)}`),(0,I.jsx)(`div`,{className:`component-card component-card--error`,children:(0,I.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 V({messages:t,isStreaming:i,sessionError:a,selectionMode:o,selectedItems:c,toggleSelectItem:l,onComponentSubmit:u,remainingSuggestions:d,onSuggestionClick:f,isAtBottom:p,setIsAtBottom:m}){let[h,v]=(0,T.useState)(new Set),[b,x]=(0,T.useState)(new Set),S=(0,T.useRef)(null),C=(0,T.useRef)(null),w=(0,T.useRef)(null),E=(0,T.useRef)(!1),D=(0,T.useRef)(!1),O=(0,T.useRef)(!1),k=(0,T.useRef)(0),A=(0,T.useRef)(!1),j=(0,T.useRef)(new Map);A.current=i,(0,T.useEffect)(()=>{i&&!E.current&&p&&(D.current=!0)},[i,p]),(0,T.useEffect)(()=>{if(!D.current&&!p){E.current=i,O.current=!1;return}if(E.current&&!i&&w.current&&C.current){let e=w.current;if(e.offsetHeight>C.current.clientHeight){D.current=!1,O.current=!0,e.scrollIntoView({behavior:`smooth`,block:`start`}),E.current=i;return}}(p||D.current)&&!O.current&&S.current?.scrollIntoView({behavior:`smooth`}),E.current=i},[t,p,i]),(0,T.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,T.useEffect)(()=>{function e(){x(e=>{let t=new Set;return j.current.forEach((n,r)=>{n.isConnected&&(h.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 j.current.forEach(e=>t.observe(e)),()=>t.disconnect()},[t.length,h]);let M=t.reduce((e,t,n)=>t.role===`maxy`&&!t.hidden?n:e,-1);return(0,I.jsxs)(`div`,{className:`chat-messages-wrap`,children:[o&&(0,I.jsx)(`div`,{className:`selection-overlay-band`}),(0,I.jsxs)(`div`,{className:`chat-messages`,ref:C,children:[a&&t.length===0&&(0,I.jsx)(`div`,{className:`session-error`,children:(0,I.jsx)(`p`,{children:a})}),t.map((a,d)=>{if(a.hidden)return null;let f=i&&d===t.length-1,p=`${a.timestamp}_${a.role}`,m=c.has(p);return(0,I.jsxs)(`div`,{ref:d===M?w:void 0,className:`message ${a.role}${m?` selected`:``}`,children:[o&&!f&&(0,I.jsx)(`div`,{className:`message-select-check`,children:(0,I.jsx)(s,{checked:m,onChange:()=>l(p)})}),(0,I.jsxs)(`div`,{className:`bubble`,children:[a.role===`visitor`&&a.content?(()=>{let e=h.has(d),t=b.has(d);return(0,I.jsxs)(I.Fragment,{children:[(0,I.jsx)(`div`,{ref:e=>{e?j.current.set(d,e):j.current.delete(d)},className:e?`bubble-content`:`bubble-content clamped${t?` overflowing`:``}`,children:a.content}),t&&(0,I.jsx)(`div`,{className:`bubble-expand`,children:(0,I.jsx)(y,{variant:`icon`,className:e?`expanded`:``,onClick:()=>v(e=>{let t=new Set(e);return t.has(d)?t.delete(d):t.add(d),t}),"aria-label":e?`Collapse message`:`Expand message`,children:(0,I.jsx)(r,{size:14})})})]})})():a.content?(0,I.jsx)(_,{content:a.content,timestamp:g(a.timestamp)}):(0,I.jsxs)(`span`,{className:`typing-indicator`,children:[(0,I.jsx)(`span`,{className:`typing-dot`}),(0,I.jsx)(`span`,{className:`typing-dot`}),(0,I.jsx)(`span`,{className:`typing-dot`})]}),a.attachments&&a.attachments.length>0&&(0,I.jsx)(`div`,{className:`message-attachments`,children:a.attachments.map((t,r)=>(0,I.jsxs)(`span`,{className:`message-attachment-chip no-action`,children:[t.mimeType===`application/pdf`?(0,I.jsx)(n,{size:12}):t.mimeType.startsWith(`text/`)?(0,I.jsx)(e,{size:12}):null,(0,I.jsx)(`span`,{children:t.filename})]},r))}),a.role===`visitor`&&(0,I.jsx)(`span`,{className:`message-timestamp`,children:g(a.timestamp)})]}),a.role===`maxy`&&a.components&&a.components.length>0&&(0,I.jsx)(`div`,{className:`public-components`,children:a.components.map((e,t)=>(0,I.jsx)(`div`,{className:`public-component-enter`,children:(0,I.jsx)(B,{name:e.name,data:e.data,onSubmit:e=>u(d,t,e),submitted:e.submitted})},t))})]},d)}),!i&&d.length>0&&(0,I.jsx)(`div`,{className:`chat-suggestions`,children:d.map(e=>(0,I.jsx)(y,{variant:`suggestion`,onClick:()=>f(e),children:e},e))}),(0,I.jsx)(`div`,{ref:S})]}),!p&&(0,I.jsx)(`button`,{className:`scroll-to-bottom`,onClick:()=>S.current?.scrollIntoView({behavior:`smooth`}),"aria-label":`Scroll to bottom`,children:(0,I.jsx)(r,{size:18})})]})}function H({selectedItems:e,messages:t,copySelected:n,exitSelection:r,showCopyToast:i}){let[a,o]=(0,T.useState)(!1),s=(0,T.useRef)(null),c=(0,T.useRef)(!1);function l(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 u(e,t){return parseInt(e.slice(0,e.lastIndexOf(`_`)),10)-parseInt(t.slice(0,t.lastIndexOf(`_`)),10)}function d(){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
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`)}T.useEffect(()=>{if(!a)return;let e=e=>{e.target.closest(`.selection-copy-wrap`)||o(!1)};return document.addEventListener(`pointerdown`,e),()=>document.removeEventListener(`pointerdown`,e)},[a]);function f(){s.current!==null&&(clearTimeout(s.current),s.current=null)}return(0,I.jsx)(`div`,{className:`chat-input-area`,children:(0,I.jsxs)(`div`,{className:`selection-bar`,children:[(0,I.jsxs)(`span`,{className:`selection-count`,children:[e.size,` Selected`]}),(0,I.jsxs)(`div`,{className:`selection-copy-wrap`,children:[(0,I.jsxs)(`button`,{type:`button`,className:`selection-copy`,onPointerDown:()=>{if(a){o(!1);return}c.current=!1,s.current=setTimeout(()=>{c.current=!0,o(!0),s.current=null},500)},onPointerUp:f,onPointerLeave:f,onPointerCancel:f,onClick:async()=>{c.current||await n(l,u)},children:[(0,I.jsx)(x,{size:18}),(0,I.jsx)(`span`,{children:`Copy`})]}),a&&(0,I.jsx)(`div`,{className:`copy-menu`,children:(0,I.jsx)(`button`,{type:`button`,className:`copy-menu-item`,onClick:async()=>{let e=d();e&&i(await b(e)),r()},children:`Copy all`})})]}),(0,I.jsx)(`button`,{type:`button`,className:`selection-cancel`,onClick:r,children:`Cancel`})]})})}function U({input:t,setInput:r,isStreaming:i,pendingFiles:a,setPendingFiles:o,attachError:s,setAttachError:c,isDragOver:l,setIsDragOver:u,inputRef:d,onSubmit:f}){let p=(0,T.useRef)(null);function h(e){c(null);let t=e.find(e=>!D.has(e.type));if(t){c(`Unsupported file type: "${t.type}". Supported: images, PDF, plain text, markdown, CSV.`);return}let n=e.find(e=>e.size>O);if(n){c(`"${n.name}" exceeds the 20 MB limit.`);return}o(t=>[...t,...e].slice(0,5))}function g(e){e.preventDefault(),u(!0)}function _(){u(!1)}function b(e){e.preventDefault(),u(!1),h([...e.dataTransfer.files])}return(0,I.jsxs)(`div`,{className:`chat-input-area`,children:[(0,I.jsx)(`input`,{ref:p,type:`file`,multiple:!0,accept:E,style:{display:`none`},onChange:e=>{e.target.files&&h([...e.target.files]),e.target.value=``}}),a.length>0&&(0,I.jsx)(`div`,{className:`attachment-strip`,children:a.map((t,r)=>(0,I.jsxs)(`div`,{className:`attachment-chip`,children:[t.type.startsWith(`image/`)?(0,I.jsx)(`img`,{src:URL.createObjectURL(t),alt:t.name,className:`attachment-chip-thumb`}):t.type===`application/pdf`?(0,I.jsx)(n,{size:14}):(0,I.jsx)(e,{size:14}),(0,I.jsx)(`span`,{className:`attachment-chip-name`,children:t.name}),(0,I.jsx)(`button`,{type:`button`,className:`attachment-chip-remove`,onClick:()=>o(e=>e.filter((e,t)=>t!==r)),"aria-label":`Remove ${t.name}`,children:`×`})]},r))}),s&&(0,I.jsx)(`p`,{className:`attach-error`,children:s}),(0,I.jsx)(m,{inputRef:d}),(0,I.jsxs)(`form`,{className:`chat-form${l?` drag-over`:``}`,onSubmit:f,onDragOver:g,onDragLeave:_,onDrop:b,onPaste:e=>{let t=e.clipboardData?.items;if(!t)return;let n=[];for(let e of t){if(e.kind!==`file`)continue;let t=e.getAsFile();if(!t)continue;let r=t.type.split(`/`)[1]?.replace(`jpeg`,`jpg`)||`png`;n.push(new File([t],`pasted-image-${Date.now()}.${r}`,{type:t.type}))}n.length>0&&h(n)},children:[(0,I.jsx)(y,{variant:`icon`,type:`button`,onClick:()=>p.current?.click(),disabled:i,"aria-label":`Attach file`,children:(0,I.jsx)(S,{size:14})}),(0,I.jsx)(v,{ref:d,value:t,onChange:r,placeholder:`Type a message...`}),(0,I.jsx)(y,{variant:`send`,type:`submit`,disabled:i||!t.trim()&&a.length===0,"aria-label":`Send message`,children:(0,I.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,I.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,I.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]})]})}var W=[];function G(){let[e,t]=(0,T.useState)(``),[n,r]=(0,T.useState)([]),[i,a]=(0,T.useState)(!1),[s,c]=(0,T.useState)(null),[u,d]=(0,T.useState)(W),[f,m]=(0,T.useState)(!0),g=(0,T.useRef)(null),{selectionMode:_,selectedItems:v,copyToast:y,exitSelection:b,enterSelection:x,toggleSelectItem:S,copySelected:w,showCopyToast:E}=C(),D=(0,T.useRef)(()=>{}),O=P((0,T.useCallback)(e=>{D.current(e)},[])),{sessionId:k,sessionKeyRef:A,sessionError:j,pageState:M,agentDisplayName:N,agentImage:L,agentImageShape:z,showAgentName:B,branding:G,ensureSession:K,resumedRef:q,resumeMessagesRef:J}=O,{messages:Y,setMessages:X,isStreaming:Z,sendMessage:ee,sendGreeting:Q,handleComponentSubmit:te}=F({sessionKeyRef:A,ensureSession:K,sessionError:j,pageState:M,inputRef:g});(0,T.useEffect)(()=>{D.current=Q},[Q]),(0,T.useEffect)(()=>{let e=!1;return(async()=>{let t=await K();if(!e&&t){if(q.current&&J.current&&J.current.length>0){X(J.current.map(e=>({role:e.role,content:e.content,timestamp:e.timestamp}))),J.current=null;return}Q(t)}})(),()=>{e=!0}},[]),(0,T.useEffect)(()=>{M===`chat`&&g.current?.focus()},[M]),(0,T.useEffect)(()=>{if(!G)return;let e=document.documentElement;if(G.primaryColor&&(e.style.setProperty(`--sage`,G.primaryColor),e.style.setProperty(`--sage-hover`,G.primaryColor),e.style.setProperty(`--sage-subtle`,G.primaryColor+`14`),e.style.setProperty(`--sage-glow`,G.primaryColor+`26`)),G.accentColor&&e.style.setProperty(`--visitor-bubble`,G.accentColor),G.backgroundColor&&e.style.setProperty(`--bg`,G.backgroundColor),document.title=G.name,G.primaryColor){let e=document.querySelector(`meta[name="theme-color"]`);e||(e=document.createElement(`meta`),e.name=`theme-color`,document.head.appendChild(e)),e.content=G.primaryColor}if(G.faviconUrl){let e=document.querySelector(`link[rel="icon"]`);e||(e=document.createElement(`link`),e.rel=`icon`,document.head.appendChild(e)),e.href=G.faviconUrl}},[G]),(0,T.useEffect)(()=>{function e(e){e.key===`Escape`&&_&&b()}return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[_,b]);function $(e){if(!e&&n.length===0||Z)return;X(e=>e.map(e=>e.components?.some(e=>!e.submitted)?{...e,components:e.components.map(e=>e.submitted?e:{...e,submitted:!0})}:e)),d(t=>t.filter(t=>t!==e)),m(!0);let i=[...n];t(``),r([]),c(null),ee(e,{files:i})}function ne(t){t.preventDefault(),$(e.trim()),g.current?.resetHeight()}return(0,I.jsxs)(`div`,{className:`chat-page`,children:[(0,I.jsxs)(`header`,{className:`chat-header`,children:[(0,I.jsx)(`img`,{src:L||G?.logoUrl||l,alt:G?.name||h.productName,className:`chat-logo${L&&z===`circle`?` chat-logo--circle`:``}${L&&z===`rounded`?` chat-logo--rounded`:``}`,onError:e=>{e.target.src=G?.logoUrl||l}}),(0,I.jsxs)(`div`,{className:`chat-header-text`,children:[B!==`none`&&(0,I.jsx)(`h1`,{className:`chat-tagline`,children:B&&N||G?.name||h.productName}),(0,I.jsx)(`p`,{className:`chat-intro`,children:G?.tagline||``})]}),M===`chat`&&!_&&(0,I.jsx)(`button`,{className:`chat-header-select`,onClick:x,title:`Select messages`,"aria-label":`Select messages`,children:(0,I.jsx)(o,{size:16})})]}),M===`loading`&&(0,I.jsx)(`div`,{className:`gate-wrap`,children:(0,I.jsx)(`div`,{className:`gate-loading`,children:(0,I.jsx)(`span`,{className:`spinner`})})}),M===`auth-required`&&(0,I.jsx)(R,{gateState:O.gateState,setGateState:O.setGateState,grantInfo:O.grantInfo,setGrantInfo:O.setGrantInfo,gateSessionKeyRef:O.gateSessionKeyRef,resolvedSlugRef:O.resolvedSlugRef,onAuthenticated:O.enterChat}),M===`chat`&&(0,I.jsxs)(I.Fragment,{children:[(0,I.jsx)(V,{messages:Y,isStreaming:Z,sessionError:j,selectionMode:_,selectedItems:v,toggleSelectItem:S,onComponentSubmit:te,remainingSuggestions:u,onSuggestionClick:$,isAtBottom:f,setIsAtBottom:m}),_?(0,I.jsx)(H,{selectedItems:v,messages:Y,copySelected:w,exitSelection:b,showCopyToast:E}):(0,I.jsx)(U,{input:e,setInput:t,isStreaming:Z,pendingFiles:n,setPendingFiles:r,attachError:s,setAttachError:c,isDragOver:i,setIsDragOver:a,inputRef:g,onSubmit:ne})]}),y&&(0,I.jsx)(`span`,{className:`copy-toast${y===`failed`?` copy-toast-failed`:``}`,children:y===`copied`?`Copied`:`Copy failed`}),(0,I.jsxs)(`footer`,{className:`chat-footer`,children:[(0,I.jsxs)(`a`,{href:p,children:[h.domain,` `,`↗`]}),k&&(0,I.jsxs)(`span`,{style:{opacity:.35,fontSize:`10px`,fontFamily:`monospace`,marginLeft:`1rem`},children:[`Session · `,k.slice(0,8)]})]})]})}(0,w.createRoot)(document.getElementById(`root`)).render((0,I.jsx)(G,{}));
|
|
@@ -5,9 +5,9 @@
|
|
|
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-
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/assets/ChatInput-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/ChatInput-
|
|
8
|
+
<script type="module" crossorigin src="/assets/admin-CW4uB1GJ.js"></script>
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/assets/ChatInput-DgjefIvo.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/ChatInput-BZayQkAS.css">
|
|
11
11
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
@@ -5,9 +5,9 @@
|
|
|
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-
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/assets/ChatInput-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/ChatInput-
|
|
8
|
+
<script type="module" crossorigin src="/assets/public-DEZaIlO-.js"></script>
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/assets/ChatInput-DgjefIvo.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/ChatInput-BZayQkAS.css">
|
|
11
11
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
package/payload/server/server.js
CHANGED
|
@@ -2851,7 +2851,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2851
2851
|
};
|
|
2852
2852
|
|
|
2853
2853
|
// server/index.ts
|
|
2854
|
-
import { readFileSync as
|
|
2854
|
+
import { readFileSync as readFileSync19, existsSync as existsSync19, watchFile } from "fs";
|
|
2855
2855
|
import { resolve as resolve18, join as join9, basename as basename4 } from "path";
|
|
2856
2856
|
import { homedir as homedir3 } from "os";
|
|
2857
2857
|
|
|
@@ -4379,6 +4379,8 @@ function resolveAgentConfig(accountDir, agentName) {
|
|
|
4379
4379
|
}
|
|
4380
4380
|
if (parsed.showAgentName === true) {
|
|
4381
4381
|
showAgentName = true;
|
|
4382
|
+
} else if (parsed.showAgentName === "none") {
|
|
4383
|
+
showAgentName = "none";
|
|
4382
4384
|
}
|
|
4383
4385
|
if (image || imageShape || showAgentName) {
|
|
4384
4386
|
console.log(`[agent-config] ${agentName}: image=${image || "(none)"} imageShape=${imageShape || "(none)"} showAgentName=${showAgentName}`);
|
|
@@ -7610,7 +7612,8 @@ var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
7610
7612
|
"application/pdf",
|
|
7611
7613
|
"text/plain",
|
|
7612
7614
|
"text/markdown",
|
|
7613
|
-
"text/csv"
|
|
7615
|
+
"text/csv",
|
|
7616
|
+
"text/html"
|
|
7614
7617
|
]);
|
|
7615
7618
|
var MAX_FILE_SIZE_BYTES = 20 * 1024 * 1024;
|
|
7616
7619
|
var MAX_FILES_PER_MESSAGE = 5;
|
|
@@ -25597,8 +25600,6 @@ async function POST19(req) {
|
|
|
25597
25600
|
}
|
|
25598
25601
|
|
|
25599
25602
|
// app/api/admin/chat/route.ts
|
|
25600
|
-
import { existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync6 } from "fs";
|
|
25601
|
-
import { dirname as dirname2 } from "path";
|
|
25602
25603
|
function isComponentDone(parsed) {
|
|
25603
25604
|
return typeof parsed === "object" && parsed !== null && parsed._componentDone === true && typeof parsed.component === "string" && typeof parsed.payload === "string";
|
|
25604
25605
|
}
|
|
@@ -25623,60 +25624,6 @@ ${inner.content}`;
|
|
|
25623
25624
|
}
|
|
25624
25625
|
return payload;
|
|
25625
25626
|
}
|
|
25626
|
-
var VOLATILE_STATE_FILE = "/tmp/maxy-agent-create-state.json";
|
|
25627
|
-
function advanceGateIfNeeded(envelope, accountDir, logFn) {
|
|
25628
|
-
if (!existsSync14(VOLATILE_STATE_FILE)) return;
|
|
25629
|
-
const { component, payload } = envelope;
|
|
25630
|
-
let gateFlag = null;
|
|
25631
|
-
let agentSlug = "";
|
|
25632
|
-
if (component === "document-editor") {
|
|
25633
|
-
try {
|
|
25634
|
-
const inner = typeof payload === "string" ? JSON.parse(payload) : payload;
|
|
25635
|
-
if (typeof inner === "object" && inner !== null && typeof inner.filePath === "string") {
|
|
25636
|
-
const match2 = inner.filePath.match(/agents\/([^/]+)\/(SOUL\.md|KNOWLEDGE\.md)$/);
|
|
25637
|
-
if (match2 && match2[1] !== "admin") {
|
|
25638
|
-
agentSlug = match2[1];
|
|
25639
|
-
gateFlag = match2[2] === "SOUL.md" ? "soul" : "knowledge";
|
|
25640
|
-
}
|
|
25641
|
-
}
|
|
25642
|
-
} catch {
|
|
25643
|
-
}
|
|
25644
|
-
} else if (component === "form") {
|
|
25645
|
-
gateFlag = "config";
|
|
25646
|
-
}
|
|
25647
|
-
if (!gateFlag) return;
|
|
25648
|
-
let state;
|
|
25649
|
-
try {
|
|
25650
|
-
state = JSON.parse(readFileSync14(VOLATILE_STATE_FILE, "utf-8"));
|
|
25651
|
-
} catch (err) {
|
|
25652
|
-
logFn(`ERROR \u2014 failed to read state file for advancement: ${err instanceof Error ? err.message : String(err)}`);
|
|
25653
|
-
return;
|
|
25654
|
-
}
|
|
25655
|
-
const gates = state.gates;
|
|
25656
|
-
if (!gates || typeof gates !== "object") {
|
|
25657
|
-
logFn("WARNING \u2014 state file has unexpected structure, skipping advancement");
|
|
25658
|
-
return;
|
|
25659
|
-
}
|
|
25660
|
-
if (!state.slug && agentSlug) {
|
|
25661
|
-
state.slug = agentSlug;
|
|
25662
|
-
}
|
|
25663
|
-
if (gates[gateFlag] === true) return;
|
|
25664
|
-
gates[gateFlag] = true;
|
|
25665
|
-
try {
|
|
25666
|
-
writeFileSync9(VOLATILE_STATE_FILE, JSON.stringify(state));
|
|
25667
|
-
} catch (err) {
|
|
25668
|
-
logFn(`ERROR \u2014 failed to write volatile state after advancement: ${err instanceof Error ? err.message : String(err)}`);
|
|
25669
|
-
}
|
|
25670
|
-
const durablePath = `${accountDir}/.claude/agent-create-state.json`;
|
|
25671
|
-
try {
|
|
25672
|
-
mkdirSync6(dirname2(durablePath), { recursive: true });
|
|
25673
|
-
writeFileSync9(durablePath, JSON.stringify(state));
|
|
25674
|
-
} catch (err) {
|
|
25675
|
-
logFn(`WARNING \u2014 failed to write durable state after advancement: ${err instanceof Error ? err.message : String(err)}`);
|
|
25676
|
-
}
|
|
25677
|
-
const pending = Object.entries(gates).filter(([, v]) => !v).map(([k]) => k);
|
|
25678
|
-
logFn(`${gateFlag} gate advanced (route-level). Pending: ${pending.length > 0 ? pending.join(", ") : "none"}`);
|
|
25679
|
-
}
|
|
25680
25627
|
async function POST20(req) {
|
|
25681
25628
|
const contentType = req.headers.get("content-type") ?? "";
|
|
25682
25629
|
let message;
|
|
@@ -25820,9 +25767,6 @@ async function POST20(req) {
|
|
|
25820
25767
|
if (isComponentDone(parsed)) {
|
|
25821
25768
|
const componentLog = agentLogStream("component-lifecycle", account.accountDir);
|
|
25822
25769
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
25823
|
-
const logFn = (msg) => componentLog.write(`[${ts}] [agent-creation-approval:route] ${msg}
|
|
25824
|
-
`);
|
|
25825
|
-
advanceGateIfNeeded(parsed, account.accountDir, logFn);
|
|
25826
25770
|
message = transformComponentDone(parsed);
|
|
25827
25771
|
componentLog.write(`[${ts}] [component:${parsed.component}] componentDone \u2192 transformed
|
|
25828
25772
|
`);
|
|
@@ -25940,7 +25884,7 @@ async function POST21(req) {
|
|
|
25940
25884
|
}
|
|
25941
25885
|
|
|
25942
25886
|
// app/api/admin/logs/route.ts
|
|
25943
|
-
import { existsSync as
|
|
25887
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync14, statSync as statSync3 } from "fs";
|
|
25944
25888
|
import { resolve as resolve12, basename as basename3 } from "path";
|
|
25945
25889
|
var TAIL_BYTES = 8192;
|
|
25946
25890
|
async function GET4(request) {
|
|
@@ -25956,7 +25900,7 @@ async function GET4(request) {
|
|
|
25956
25900
|
if (!dir) continue;
|
|
25957
25901
|
const filePath = resolve12(dir, safe);
|
|
25958
25902
|
try {
|
|
25959
|
-
const content =
|
|
25903
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
25960
25904
|
const headers = { "Content-Type": "text/plain; charset=utf-8" };
|
|
25961
25905
|
if (download) headers["Content-Disposition"] = `attachment; filename="${safe}"`;
|
|
25962
25906
|
return new Response(content, { headers });
|
|
@@ -25982,7 +25926,7 @@ async function GET4(request) {
|
|
|
25982
25926
|
if (!dir) continue;
|
|
25983
25927
|
const filePath = resolve12(dir, fileName);
|
|
25984
25928
|
try {
|
|
25985
|
-
const content =
|
|
25929
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
25986
25930
|
const headers = { "Content-Type": "text/plain; charset=utf-8" };
|
|
25987
25931
|
if (download) headers["Content-Disposition"] = `attachment; filename="${fileName}"`;
|
|
25988
25932
|
return new Response(content, { headers });
|
|
@@ -25994,7 +25938,7 @@ async function GET4(request) {
|
|
|
25994
25938
|
const seen = /* @__PURE__ */ new Set();
|
|
25995
25939
|
const logs = {};
|
|
25996
25940
|
for (const dir of [accountLogDir, LOG_DIR]) {
|
|
25997
|
-
if (!dir || !
|
|
25941
|
+
if (!dir || !existsSync14(dir)) continue;
|
|
25998
25942
|
let files;
|
|
25999
25943
|
try {
|
|
26000
25944
|
files = readdirSync3(dir).filter((f) => f.endsWith(".log"));
|
|
@@ -26004,7 +25948,7 @@ async function GET4(request) {
|
|
|
26004
25948
|
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync3(resolve12(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
26005
25949
|
seen.add(name);
|
|
26006
25950
|
try {
|
|
26007
|
-
const content =
|
|
25951
|
+
const content = readFileSync14(resolve12(dir, name));
|
|
26008
25952
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
26009
25953
|
logs[name] = tail.trim() || "(empty)";
|
|
26010
25954
|
} catch {
|
|
@@ -26039,7 +25983,7 @@ async function GET5() {
|
|
|
26039
25983
|
|
|
26040
25984
|
// app/api/admin/attachment/[attachmentId]/route.ts
|
|
26041
25985
|
import { readFile as readFile3, readdir } from "fs/promises";
|
|
26042
|
-
import { existsSync as
|
|
25986
|
+
import { existsSync as existsSync15 } from "fs";
|
|
26043
25987
|
import { resolve as resolve13 } from "path";
|
|
26044
25988
|
async function GET6(req, attachmentId) {
|
|
26045
25989
|
const sessionKey = new URL(req.url).searchParams.get("session_key") ?? "";
|
|
@@ -26054,11 +25998,11 @@ async function GET6(req, attachmentId) {
|
|
|
26054
25998
|
return new Response("Not found", { status: 404 });
|
|
26055
25999
|
}
|
|
26056
26000
|
const dir = resolve13(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
26057
|
-
if (!
|
|
26001
|
+
if (!existsSync15(dir)) {
|
|
26058
26002
|
return new Response("Not found", { status: 404 });
|
|
26059
26003
|
}
|
|
26060
26004
|
const metaPath = resolve13(dir, `${attachmentId}.meta.json`);
|
|
26061
|
-
if (!
|
|
26005
|
+
if (!existsSync15(metaPath)) {
|
|
26062
26006
|
return new Response("Not found", { status: 404 });
|
|
26063
26007
|
}
|
|
26064
26008
|
let meta3;
|
|
@@ -26084,7 +26028,7 @@ async function GET6(req, attachmentId) {
|
|
|
26084
26028
|
}
|
|
26085
26029
|
|
|
26086
26030
|
// app/api/admin/account/route.ts
|
|
26087
|
-
import { readFileSync as
|
|
26031
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "fs";
|
|
26088
26032
|
import { resolve as resolve14 } from "path";
|
|
26089
26033
|
var VALID_CONTEXT_MODES = ["managed", "claude-code"];
|
|
26090
26034
|
async function PATCH(req) {
|
|
@@ -26110,10 +26054,10 @@ async function PATCH(req) {
|
|
|
26110
26054
|
}
|
|
26111
26055
|
const configPath2 = resolve14(account.accountDir, "account.json");
|
|
26112
26056
|
try {
|
|
26113
|
-
const raw2 =
|
|
26057
|
+
const raw2 = readFileSync15(configPath2, "utf-8");
|
|
26114
26058
|
const config2 = JSON.parse(raw2);
|
|
26115
26059
|
config2.contextMode = contextMode;
|
|
26116
|
-
|
|
26060
|
+
writeFileSync9(configPath2, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
26117
26061
|
console.error(`[account-update] contextMode=${contextMode}`);
|
|
26118
26062
|
return Response.json({ ok: true, contextMode });
|
|
26119
26063
|
} catch (err) {
|
|
@@ -26124,14 +26068,14 @@ async function PATCH(req) {
|
|
|
26124
26068
|
|
|
26125
26069
|
// app/api/admin/agents/route.ts
|
|
26126
26070
|
import { resolve as resolve15 } from "path";
|
|
26127
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
26071
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync16, existsSync as existsSync16 } from "fs";
|
|
26128
26072
|
async function GET7() {
|
|
26129
26073
|
const account = resolveAccount();
|
|
26130
26074
|
if (!account) {
|
|
26131
26075
|
return Response.json({ agents: [] });
|
|
26132
26076
|
}
|
|
26133
26077
|
const agentsDir = resolve15(account.accountDir, "agents");
|
|
26134
|
-
if (!
|
|
26078
|
+
if (!existsSync16(agentsDir)) {
|
|
26135
26079
|
return Response.json({ agents: [] });
|
|
26136
26080
|
}
|
|
26137
26081
|
const agents = [];
|
|
@@ -26141,9 +26085,9 @@ async function GET7() {
|
|
|
26141
26085
|
if (!entry.isDirectory()) continue;
|
|
26142
26086
|
if (entry.name === "admin") continue;
|
|
26143
26087
|
const configPath2 = resolve15(agentsDir, entry.name, "config.json");
|
|
26144
|
-
if (!
|
|
26088
|
+
if (!existsSync16(configPath2)) continue;
|
|
26145
26089
|
try {
|
|
26146
|
-
const config2 = JSON.parse(
|
|
26090
|
+
const config2 = JSON.parse(readFileSync16(configPath2, "utf-8"));
|
|
26147
26091
|
agents.push({
|
|
26148
26092
|
slug: entry.name,
|
|
26149
26093
|
displayName: config2.displayName ?? entry.name,
|
|
@@ -26161,15 +26105,15 @@ async function GET7() {
|
|
|
26161
26105
|
}
|
|
26162
26106
|
|
|
26163
26107
|
// app/api/admin/version/route.ts
|
|
26164
|
-
import { readFileSync as
|
|
26108
|
+
import { readFileSync as readFileSync17, existsSync as existsSync17 } from "fs";
|
|
26165
26109
|
import { resolve as resolve16, join as join7 } from "path";
|
|
26166
26110
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve16(process.cwd(), "..");
|
|
26167
26111
|
var brandHostname = "maxy";
|
|
26168
26112
|
var brandNpmPackage = "@rubytech/create-maxy";
|
|
26169
26113
|
var brandJsonPath = join7(PLATFORM_ROOT7, "config", "brand.json");
|
|
26170
|
-
if (
|
|
26114
|
+
if (existsSync17(brandJsonPath)) {
|
|
26171
26115
|
try {
|
|
26172
|
-
const brand = JSON.parse(
|
|
26116
|
+
const brand = JSON.parse(readFileSync17(brandJsonPath, "utf-8"));
|
|
26173
26117
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
26174
26118
|
if (brand.npm?.packageName) brandNpmPackage = brand.npm.packageName;
|
|
26175
26119
|
} catch {
|
|
@@ -26182,8 +26126,8 @@ var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
|
26182
26126
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
26183
26127
|
var latestCache = null;
|
|
26184
26128
|
function readInstalled() {
|
|
26185
|
-
if (!
|
|
26186
|
-
const content =
|
|
26129
|
+
if (!existsSync17(VERSION_FILE)) return "unknown";
|
|
26130
|
+
const content = readFileSync17(VERSION_FILE, "utf-8").trim();
|
|
26187
26131
|
return content || "unknown";
|
|
26188
26132
|
}
|
|
26189
26133
|
async function fetchLatest() {
|
|
@@ -26237,15 +26181,15 @@ async function GET8() {
|
|
|
26237
26181
|
|
|
26238
26182
|
// app/api/admin/version/upgrade/route.ts
|
|
26239
26183
|
import { spawn as spawn4 } from "child_process";
|
|
26240
|
-
import { existsSync as
|
|
26184
|
+
import { existsSync as existsSync18, statSync as statSync4, writeFileSync as writeFileSync10, readFileSync as readFileSync18, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
26241
26185
|
import { resolve as resolve17, join as join8 } from "path";
|
|
26242
26186
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
26243
26187
|
var upgradePkg = "@rubytech/create-maxy";
|
|
26244
26188
|
var upgradeHostname = "maxy";
|
|
26245
26189
|
var brandPath = join8(PLATFORM_ROOT8, "config", "brand.json");
|
|
26246
|
-
if (
|
|
26190
|
+
if (existsSync18(brandPath)) {
|
|
26247
26191
|
try {
|
|
26248
|
-
const brand = JSON.parse(
|
|
26192
|
+
const brand = JSON.parse(readFileSync18(brandPath, "utf-8"));
|
|
26249
26193
|
if (brand.npm?.packageName) upgradePkg = brand.npm.packageName;
|
|
26250
26194
|
if (brand.hostname) upgradeHostname = brand.hostname;
|
|
26251
26195
|
} catch {
|
|
@@ -26255,7 +26199,7 @@ var LOCK_FILE = `/tmp/${upgradeHostname}-upgrade.lock`;
|
|
|
26255
26199
|
var LOG_FILE = `/tmp/${upgradeHostname}-upgrade.log`;
|
|
26256
26200
|
var LOCK_MAX_AGE_MS = 3 * 60 * 1e3;
|
|
26257
26201
|
function isLockFresh() {
|
|
26258
|
-
if (!
|
|
26202
|
+
if (!existsSync18(LOCK_FILE)) return false;
|
|
26259
26203
|
try {
|
|
26260
26204
|
const stat3 = statSync4(LOCK_FILE);
|
|
26261
26205
|
return Date.now() - stat3.mtimeMs < LOCK_MAX_AGE_MS;
|
|
@@ -26281,7 +26225,7 @@ async function POST22(req) {
|
|
|
26281
26225
|
return Response.json({ ok: false, error: "upgrade already in progress" }, { status: 409 });
|
|
26282
26226
|
}
|
|
26283
26227
|
try {
|
|
26284
|
-
|
|
26228
|
+
writeFileSync10(LOCK_FILE, String(Date.now()));
|
|
26285
26229
|
} catch (err) {
|
|
26286
26230
|
console.error("[admin/version/upgrade] failed to write lock file:", err);
|
|
26287
26231
|
}
|
|
@@ -26411,12 +26355,12 @@ async function POST23() {
|
|
|
26411
26355
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
26412
26356
|
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join9(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
26413
26357
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
|
|
26414
|
-
if (BRAND_JSON_PATH && !
|
|
26358
|
+
if (BRAND_JSON_PATH && !existsSync19(BRAND_JSON_PATH)) {
|
|
26415
26359
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
26416
26360
|
}
|
|
26417
|
-
if (BRAND_JSON_PATH &&
|
|
26361
|
+
if (BRAND_JSON_PATH && existsSync19(BRAND_JSON_PATH)) {
|
|
26418
26362
|
try {
|
|
26419
|
-
const parsed = JSON.parse(
|
|
26363
|
+
const parsed = JSON.parse(readFileSync19(BRAND_JSON_PATH, "utf-8"));
|
|
26420
26364
|
BRAND = { ...BRAND, ...parsed };
|
|
26421
26365
|
} catch (err) {
|
|
26422
26366
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -26431,8 +26375,8 @@ var brandLoginOpts = {
|
|
|
26431
26375
|
var ALIAS_DOMAINS_PATH = join9(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
26432
26376
|
function loadAliasDomains() {
|
|
26433
26377
|
try {
|
|
26434
|
-
if (!
|
|
26435
|
-
const parsed = JSON.parse(
|
|
26378
|
+
if (!existsSync19(ALIAS_DOMAINS_PATH)) return null;
|
|
26379
|
+
const parsed = JSON.parse(readFileSync19(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
26436
26380
|
if (!Array.isArray(parsed)) {
|
|
26437
26381
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
26438
26382
|
return null;
|
|
@@ -26803,14 +26747,14 @@ app.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
26803
26747
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
26804
26748
|
return c.text("Forbidden", 403);
|
|
26805
26749
|
}
|
|
26806
|
-
if (!
|
|
26750
|
+
if (!existsSync19(filePath)) {
|
|
26807
26751
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
26808
26752
|
return c.text("Not found", 404);
|
|
26809
26753
|
}
|
|
26810
26754
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
26811
26755
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
26812
26756
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
26813
|
-
const body =
|
|
26757
|
+
const body = readFileSync19(filePath);
|
|
26814
26758
|
return c.body(body, 200, {
|
|
26815
26759
|
"Content-Type": contentType,
|
|
26816
26760
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -26819,9 +26763,9 @@ app.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
26819
26763
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
26820
26764
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
26821
26765
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
26822
|
-
if (BRAND_JSON_PATH &&
|
|
26766
|
+
if (BRAND_JSON_PATH && existsSync19(BRAND_JSON_PATH)) {
|
|
26823
26767
|
try {
|
|
26824
|
-
const fullBrand = JSON.parse(
|
|
26768
|
+
const fullBrand = JSON.parse(readFileSync19(BRAND_JSON_PATH, "utf-8"));
|
|
26825
26769
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
26826
26770
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
26827
26771
|
} catch {
|
|
@@ -26838,7 +26782,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
26838
26782
|
function cachedHtml(file2) {
|
|
26839
26783
|
let html = htmlCache.get(file2);
|
|
26840
26784
|
if (!html) {
|
|
26841
|
-
html =
|
|
26785
|
+
html = readFileSync19(resolve18(process.cwd(), "public", file2), "utf-8");
|
|
26842
26786
|
html = html.replace("</head>", `${brandScript}
|
|
26843
26787
|
</head>`);
|
|
26844
26788
|
htmlCache.set(file2, html);
|
|
@@ -26850,13 +26794,13 @@ function loadBrandingCache(agentSlug) {
|
|
|
26850
26794
|
const configDir2 = join9(homedir3(), BRAND.configDir);
|
|
26851
26795
|
try {
|
|
26852
26796
|
const accountJsonPath = join9(configDir2, "account.json");
|
|
26853
|
-
if (!
|
|
26854
|
-
const account = JSON.parse(
|
|
26797
|
+
if (!existsSync19(accountJsonPath)) return null;
|
|
26798
|
+
const account = JSON.parse(readFileSync19(accountJsonPath, "utf-8"));
|
|
26855
26799
|
const accountId = account.accountId;
|
|
26856
26800
|
if (!accountId) return null;
|
|
26857
26801
|
const cachePath = join9(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
26858
|
-
if (!
|
|
26859
|
-
return JSON.parse(
|
|
26802
|
+
if (!existsSync19(cachePath)) return null;
|
|
26803
|
+
return JSON.parse(readFileSync19(cachePath, "utf-8"));
|
|
26860
26804
|
} catch {
|
|
26861
26805
|
return null;
|
|
26862
26806
|
}
|
|
@@ -26865,8 +26809,8 @@ function resolveDefaultSlug() {
|
|
|
26865
26809
|
try {
|
|
26866
26810
|
const configDir2 = join9(homedir3(), BRAND.configDir);
|
|
26867
26811
|
const accountJsonPath = join9(configDir2, "account.json");
|
|
26868
|
-
if (!
|
|
26869
|
-
const account = JSON.parse(
|
|
26812
|
+
if (!existsSync19(accountJsonPath)) return null;
|
|
26813
|
+
const account = JSON.parse(readFileSync19(accountJsonPath, "utf-8"));
|
|
26870
26814
|
return account.defaultAgent || null;
|
|
26871
26815
|
} catch {
|
|
26872
26816
|
return null;
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# UserPromptSubmit hook — agent creation gate advancement.
|
|
3
|
-
#
|
|
4
|
-
# Advances gates when the user approves a component during agent creation.
|
|
5
|
-
# The UI wraps all component completions in a _componentDone envelope:
|
|
6
|
-
#
|
|
7
|
-
# {"_componentDone": true, "component": "<name>", "payload": "<original msg>"}
|
|
8
|
-
#
|
|
9
|
-
# Gate advancement rules:
|
|
10
|
-
# _componentDone + component="document-editor" + payload.filePath matching
|
|
11
|
-
# agents/{non-admin}/SOUL.md → gates.soul = true
|
|
12
|
-
# _componentDone + component="document-editor" + payload.filePath matching
|
|
13
|
-
# agents/{non-admin}/KNOWLEDGE.md → gates.knowledge = true
|
|
14
|
-
# _componentDone + component="form" (during active creation) → gates.config = true
|
|
15
|
-
#
|
|
16
|
-
# This hook fires on the user's response (after they click Approve or Submit),
|
|
17
|
-
# not when the agent renders a component. Gate enforcement (blocking writes)
|
|
18
|
-
# is handled by agent-creation-gate.sh (PreToolUse).
|
|
19
|
-
#
|
|
20
|
-
# Exit 0 always — UserPromptSubmit hooks must never block user messages
|
|
21
|
-
# for gate advancement purposes.
|
|
22
|
-
# Env: AGENT_CREATE_STATE_FILE (override volatile path, for testing)
|
|
23
|
-
# ACCOUNT_DIR (account directory for durable state)
|
|
24
|
-
# GATE_LOG_FILE (override log path, for testing)
|
|
25
|
-
|
|
26
|
-
if [ -n "$GATE_LOG_FILE" ]; then
|
|
27
|
-
GATE_LOG="$GATE_LOG_FILE"
|
|
28
|
-
elif [ -n "$ACCOUNT_DIR" ]; then
|
|
29
|
-
mkdir -p "$ACCOUNT_DIR/logs"
|
|
30
|
-
GATE_LOG="$ACCOUNT_DIR/logs/maxy-gate.log"
|
|
31
|
-
else
|
|
32
|
-
# UserPromptSubmit hooks must never block — exit 0 on misconfiguration
|
|
33
|
-
exit 0
|
|
34
|
-
fi
|
|
35
|
-
STATE_FILE="${AGENT_CREATE_STATE_FILE:-/tmp/maxy-agent-create-state.json}"
|
|
36
|
-
ACCOUNT_DIR="${ACCOUNT_DIR:-}"
|
|
37
|
-
DURABLE_STATE="${ACCOUNT_DIR:+$ACCOUNT_DIR/.claude/agent-create-state.json}"
|
|
38
|
-
|
|
39
|
-
# Fast path: no state file → no agent creation in progress, skip stdin read entirely
|
|
40
|
-
[[ -f "$STATE_FILE" ]] || exit 0
|
|
41
|
-
|
|
42
|
-
# Read stdin (user prompt JSON from Claude Code hook protocol)
|
|
43
|
-
INPUT=$(cat)
|
|
44
|
-
|
|
45
|
-
export _HOOK_INPUT="$INPUT"
|
|
46
|
-
export _STATE_FILE="$STATE_FILE"
|
|
47
|
-
export _DURABLE_STATE="${DURABLE_STATE:-}"
|
|
48
|
-
export _GATE_LOG="$GATE_LOG"
|
|
49
|
-
|
|
50
|
-
python3 -c '
|
|
51
|
-
import os, sys, json, re
|
|
52
|
-
|
|
53
|
-
hook_input_raw = os.environ.get("_HOOK_INPUT", "")
|
|
54
|
-
state_file = os.environ.get("_STATE_FILE", "/tmp/maxy-agent-create-state.json")
|
|
55
|
-
durable_file = os.environ.get("_DURABLE_STATE", "")
|
|
56
|
-
log_file = os.environ.get("_GATE_LOG", "/tmp/maxy-gate.log")
|
|
57
|
-
|
|
58
|
-
def log(msg):
|
|
59
|
-
try:
|
|
60
|
-
with open(log_file, "a") as lf:
|
|
61
|
-
lf.write("agent-creation-approval: %s\n" % msg)
|
|
62
|
-
except OSError:
|
|
63
|
-
pass
|
|
64
|
-
|
|
65
|
-
# Parse hook input — UserPromptSubmit provides {"prompt": "..."} on stdin
|
|
66
|
-
try:
|
|
67
|
-
hook_input = json.loads(hook_input_raw)
|
|
68
|
-
except Exception as e:
|
|
69
|
-
log("ERROR — failed to parse UserPromptSubmit input: %s" % e)
|
|
70
|
-
sys.exit(0)
|
|
71
|
-
|
|
72
|
-
if not isinstance(hook_input, dict):
|
|
73
|
-
sys.exit(0)
|
|
74
|
-
|
|
75
|
-
prompt = hook_input.get("prompt", "")
|
|
76
|
-
if not isinstance(prompt, str) or not prompt:
|
|
77
|
-
sys.exit(0)
|
|
78
|
-
|
|
79
|
-
# --- Detect _componentDone wrapper ---
|
|
80
|
-
try:
|
|
81
|
-
msg = json.loads(prompt)
|
|
82
|
-
except (json.JSONDecodeError, TypeError):
|
|
83
|
-
# Not JSON — not a wrapped component message, nothing to advance
|
|
84
|
-
sys.exit(0)
|
|
85
|
-
|
|
86
|
-
if not isinstance(msg, dict) or not msg.get("_componentDone"):
|
|
87
|
-
sys.exit(0)
|
|
88
|
-
|
|
89
|
-
component = msg.get("component", "")
|
|
90
|
-
payload_raw = msg.get("payload", "")
|
|
91
|
-
|
|
92
|
-
# --- Determine which gate to advance ---
|
|
93
|
-
gate_flag = ""
|
|
94
|
-
agent_slug = ""
|
|
95
|
-
|
|
96
|
-
if component == "document-editor":
|
|
97
|
-
# Parse payload for filePath
|
|
98
|
-
try:
|
|
99
|
-
payload = json.loads(payload_raw) if isinstance(payload_raw, str) else payload_raw
|
|
100
|
-
except (json.JSONDecodeError, TypeError):
|
|
101
|
-
payload = {}
|
|
102
|
-
if isinstance(payload, dict):
|
|
103
|
-
file_path = payload.get("filePath", "")
|
|
104
|
-
if isinstance(file_path, str):
|
|
105
|
-
m = re.search(r"agents/([^/]+)/(SOUL\.md|KNOWLEDGE\.md)$", file_path)
|
|
106
|
-
if m and m.group(1) != "admin":
|
|
107
|
-
agent_slug = m.group(1)
|
|
108
|
-
gate_flag = "soul" if m.group(2) == "SOUL.md" else "knowledge"
|
|
109
|
-
|
|
110
|
-
elif component == "form":
|
|
111
|
-
# Any form submission during active creation advances the config gate.
|
|
112
|
-
# The state file existing is sufficient context — the workflow presents
|
|
113
|
-
# exactly one form (the agent config form) during creation.
|
|
114
|
-
gate_flag = "config"
|
|
115
|
-
|
|
116
|
-
if not gate_flag:
|
|
117
|
-
sys.exit(0)
|
|
118
|
-
|
|
119
|
-
# --- Read and advance the gate ---
|
|
120
|
-
try:
|
|
121
|
-
with open(state_file) as f:
|
|
122
|
-
state = json.load(f)
|
|
123
|
-
except Exception as e:
|
|
124
|
-
log("ERROR — failed to read state file for advancement: %s" % e)
|
|
125
|
-
sys.exit(0)
|
|
126
|
-
|
|
127
|
-
if not isinstance(state, dict) or not isinstance(state.get("gates"), dict):
|
|
128
|
-
log("WARNING — state file has unexpected structure, skipping advancement")
|
|
129
|
-
sys.exit(0)
|
|
130
|
-
|
|
131
|
-
# Populate slug from document-editor filePath if empty
|
|
132
|
-
if not state.get("slug") and agent_slug:
|
|
133
|
-
state["slug"] = agent_slug
|
|
134
|
-
|
|
135
|
-
# Already advanced — idempotent
|
|
136
|
-
if state["gates"].get(gate_flag) is True:
|
|
137
|
-
sys.exit(0)
|
|
138
|
-
|
|
139
|
-
state["gates"][gate_flag] = True
|
|
140
|
-
|
|
141
|
-
# Write updated state
|
|
142
|
-
try:
|
|
143
|
-
with open(state_file, "w") as f:
|
|
144
|
-
json.dump(state, f)
|
|
145
|
-
except OSError as e:
|
|
146
|
-
log("ERROR — failed to write volatile state after advancement: %s" % e)
|
|
147
|
-
|
|
148
|
-
if durable_file:
|
|
149
|
-
try:
|
|
150
|
-
durable_dir = os.path.dirname(durable_file)
|
|
151
|
-
os.makedirs(durable_dir, exist_ok=True)
|
|
152
|
-
with open(durable_file, "w") as f:
|
|
153
|
-
json.dump(state, f)
|
|
154
|
-
except OSError as e:
|
|
155
|
-
log("WARNING — failed to write durable state after advancement: %s" % e)
|
|
156
|
-
|
|
157
|
-
pending = [k for k, v in state.get("gates", {}).items() if not v]
|
|
158
|
-
log("%s gate advanced (user approval detected). Pending: %s" % (gate_flag, ", ".join(pending) if pending else "none"))
|
|
159
|
-
' 2>>"$GATE_LOG" || true
|
|
160
|
-
|
|
161
|
-
exit 0
|