omnish 1.6.4 → 1.6.6

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.
@@ -15,4 +15,4 @@ Minimum version required to store current data is: `+J+`.
15
15
  `);const G=k(B,X,tt),W=s.getSymbolSize(B),lt=new f(W);return Y(lt,B),P(lt),$(lt,B),I(lt,X,0),B>=7&&vt(lt,B),nt(lt,G),isNaN(L)&&(L=A.getBestMask(lt,I.bind(null,lt,X))),A.applyMask(L,lt),I(lt,X,L),{modules:lt,version:B,errorCorrectionLevel:X,maskPattern:L,segments:tt}}return Nf.create=function(B,X){if(typeof B>"u"||B==="")throw new Error("No input text");let L=y.M,tt,J;return typeof X<"u"&&(L=y.from(X.errorCorrectionLevel,y.M),tt=S.from(X.version),J=A.from(X.maskPattern),X.toSJISFunc&&s.setToSJISFunction(X.toSJISFunc)),pt(B,tt,L,J)},Nf}var Vf={},Kf={},Oh;function qh(){return Oh||(Oh=1,(function(s){function y(v){if(typeof v=="number"&&(v=v.toString()),typeof v!="string")throw new Error("Color should be defined as hex string");let f=v.slice().replace("#","").split("");if(f.length<3||f.length===5||f.length>8)throw new Error("Invalid hex color: "+v);(f.length===3||f.length===4)&&(f=Array.prototype.concat.apply([],f.map(function(d){return[d,d]}))),f.length===6&&f.push("F","F");const o=parseInt(f.join(""),16);return{r:o>>24&255,g:o>>16&255,b:o>>8&255,a:o&255,hex:"#"+f.slice(0,6).join("")}}s.getOptions=function(f){f||(f={}),f.color||(f.color={});const o=typeof f.margin>"u"||f.margin===null||f.margin<0?4:f.margin,d=f.width&&f.width>=21?f.width:void 0,A=f.scale||4;return{width:d,scale:d?4:A,margin:o,color:{dark:y(f.color.dark||"#000000ff"),light:y(f.color.light||"#ffffffff")},type:f.type,rendererOpts:f.rendererOpts||{}}},s.getScale=function(f,o){return o.width&&o.width>=f+o.margin*2?o.width/(f+o.margin*2):o.scale},s.getImageWidth=function(f,o){const d=s.getScale(f,o);return Math.floor((f+o.margin*2)*d)},s.qrToImageData=function(f,o,d){const A=o.modules.size,z=o.modules.data,g=s.getScale(A,d),S=Math.floor((A+d.margin*2)*g),U=d.margin*g,R=[d.color.light,d.color.dark];for(let j=0;j<S;j++)for(let Y=0;Y<S;Y++){let P=(j*S+Y)*4,$=d.color.light;if(j>=U&&Y>=U&&j<S-U&&Y<S-U){const vt=Math.floor((j-U)/g),I=Math.floor((Y-U)/g);$=R[z[vt*A+I]?1:0]}f[P++]=$.r,f[P++]=$.g,f[P++]=$.b,f[P]=$.a}}})(Kf)),Kf}var Dh;function wg(){return Dh||(Dh=1,(function(s){const y=qh();function v(o,d,A){o.clearRect(0,0,d.width,d.height),d.style||(d.style={}),d.height=A,d.width=A,d.style.height=A+"px",d.style.width=A+"px"}function f(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}s.render=function(d,A,z){let g=z,S=A;typeof g>"u"&&(!A||!A.getContext)&&(g=A,A=void 0),A||(S=f()),g=y.getOptions(g);const U=y.getImageWidth(d.modules.size,g),R=S.getContext("2d"),j=R.createImageData(U,U);return y.qrToImageData(j.data,d,g),v(R,S,U),R.putImageData(j,0,0),S},s.renderToDataURL=function(d,A,z){let g=z;typeof g>"u"&&(!A||!A.getContext)&&(g=A,A=void 0),g||(g={});const S=s.render(d,A,g),U=g.type||"image/png",R=g.rendererOpts||{};return S.toDataURL(U,R.quality)}})(Vf)),Vf}var Jf={},Uh;function Hg(){if(Uh)return Jf;Uh=1;const s=qh();function y(o,d){const A=o.a/255,z=d+'="'+o.hex+'"';return A<1?z+" "+d+'-opacity="'+A.toFixed(2).slice(1)+'"':z}function v(o,d,A){let z=o+d;return typeof A<"u"&&(z+=" "+A),z}function f(o,d,A){let z="",g=0,S=!1,U=0;for(let R=0;R<o.length;R++){const j=Math.floor(R%d),Y=Math.floor(R/d);!j&&!S&&(S=!0),o[R]?(U++,R>0&&j>0&&o[R-1]||(z+=S?v("M",j+A,.5+Y+A):v("m",g,0),g=0,S=!1),j+1<d&&o[R+1]||(z+=v("h",U),U=0)):g++}return z}return Jf.render=function(d,A,z){const g=s.getOptions(A),S=d.modules.size,U=d.modules.data,R=S+g.margin*2,j=g.color.light.a?"<path "+y(g.color.light,"fill")+' d="M0 0h'+R+"v"+R+'H0z"/>':"",Y="<path "+y(g.color.dark,"stroke")+' d="'+f(U,S,g.margin)+'"/>',P='viewBox="0 0 '+R+" "+R+'"',vt='<svg xmlns="http://www.w3.org/2000/svg" '+(g.width?'width="'+g.width+'" height="'+g.width+'" ':"")+P+' shape-rendering="crispEdges">'+j+Y+`</svg>
16
16
  `;return typeof z=="function"&&z(null,vt),vt},Jf}var Rh;function qg(){if(Rh)return Ga;Rh=1;const s=bg(),y=jg(),v=wg(),f=Hg();function o(d,A,z,g,S){const U=[].slice.call(arguments,1),R=U.length,j=typeof U[R-1]=="function";if(!j&&!s())throw new Error("Callback required as last argument");if(j){if(R<2)throw new Error("Too few arguments provided");R===2?(S=z,z=A,A=g=void 0):R===3&&(A.getContext&&typeof S>"u"?(S=g,g=void 0):(S=g,g=z,z=A,A=void 0))}else{if(R<1)throw new Error("Too few arguments provided");return R===1?(z=A,A=g=void 0):R===2&&!A.getContext&&(g=z,z=A,A=void 0),new Promise(function(Y,P){try{const $=y.create(z,g);Y(d($,A,g))}catch($){P($)}})}try{const Y=y.create(z,g);S(null,d(Y,A,g))}catch(Y){S(Y)}}return Ga.create=y.create,Ga.toCanvas=o.bind(null,v.render),Ga.toDataURL=o.bind(null,v.renderToDataURL),Ga.toString=o.bind(null,function(d,A,z){return f.render(d,z)}),Ga}var Yg=qg();const Lg=cg(Yg);async function ta(s,y){const v=await fetch(s,{credentials:"include",...y,headers:{"Content-Type":"application/json",...y?.headers??{}}}),f=await v.text();let o;try{o=f?JSON.parse(f):void 0}catch{o={raw:f}}if(!v.ok){const d=o?.error??v.statusText;throw new Error(d||`HTTP ${v.status}`)}return o}async function Gg(s){const y=Date.now();for(;Date.now()-y<s;)try{await(await fetch("/api/me",{method:"GET",credentials:"include",cache:"no-store",signal:AbortSignal.timeout(1500)})).arrayBuffer(),await new Promise(f=>setTimeout(f,300))}catch(v){if(v instanceof DOMException&&v.name==="AbortError"||v instanceof Error&&v.name==="AbortError"){await new Promise(o=>setTimeout(o,300));continue}return{ok:!0}}return{ok:!1,reason:"timeout"}}function ai({children:s}){return T.jsx("p",{className:"text-[0.65rem] font-semibold uppercase tracking-[0.22em] text-[color-mix(in_oklab,var(--color-omnish-lime)_82%,transparent)]",children:s})}function Bh({active:s,activeLabel:y,inactiveLabel:v}){return T.jsx("span",{className:s?"inline-flex shrink-0 items-center rounded-full border border-[color-mix(in_oklab,var(--color-omnish-lime)_42%,transparent)] bg-[color-mix(in_oklab,var(--color-omnish-lime)_12%,transparent)] px-2.5 py-0.5 text-[0.7rem] font-semibold text-[var(--color-omnish-lime)]":"inline-flex shrink-0 items-center rounded-full border border-[var(--color-omnish-border)] bg-black/30 px-2.5 py-0.5 text-[0.7rem] font-medium text-[var(--color-omnish-muted)]",children:s?y:v})}function pl({children:s}){return T.jsx("code",{className:"kbd",children:s})}function Qg(){const s=[{step:1,title:"Snapshot",desc:"Host, gateway, paths"},{step:2,title:"Link",desc:"WhatsApp QR if needed"},{step:3,title:"Configure",desc:"Save to config.json"}];return T.jsx("nav",{"aria-label":"Setup flow",className:"mb-1 w-full",children:T.jsx("ol",{className:"flex flex-col overflow-hidden rounded-2xl border border-white/[0.08] bg-black/25 sm:flex-row sm:divide-x sm:divide-white/10",children:s.map((y,v)=>T.jsxs("li",{className:`flex flex-1 items-center gap-3 px-4 py-3.5 lg:px-5 ${v===2?"bg-[color-mix(in_oklab,var(--color-omnish-lime)_6%,transparent)] sm:ring-1 sm:ring-[color-mix(in_oklab,var(--color-omnish-lime)_22%,transparent)]":""}`,children:[T.jsx("span",{className:"font-display flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_oklab,var(--color-omnish-lime)_38%,transparent)] bg-[color-mix(in_oklab,var(--color-omnish-lime)_10%,transparent)] text-sm font-semibold text-[var(--color-omnish-lime)]",children:y.step}),T.jsxs("div",{className:"min-w-0",children:[T.jsx("p",{className:"font-display text-sm font-semibold tracking-tight text-[var(--color-omnish-fg)]",children:y.title}),T.jsx("p",{className:"text-xs leading-snug text-[var(--color-omnish-muted)]",children:y.desc})]})]},y.step))})})}const qn="rounded-xl bg-[var(--color-omnish-lime)] px-4 py-3 text-sm font-semibold text-[var(--color-omnish-bg)] transition duration-150 active:scale-[0.98] active:opacity-90 disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100";function Xg(){const[s,y]=Dt.useState("check"),[v,f]=Dt.useState(""),[o,d]=Dt.useState(!1),[A,z]=Dt.useState(null),[g,S]=Dt.useState(null),[U,R]=Dt.useState(null),j=Dt.useRef(null),[Y,P]=Dt.useState(!1),[$,vt]=Dt.useState(!1),[I,nt]=Dt.useState(!1),[k,K]=Dt.useState(null),[pt,q]=Dt.useState(null),[B,X]=Dt.useState(!1),[L,tt]=Dt.useState(!1),[J,G]=Dt.useState(null),[W,lt]=Dt.useState(!1),[Ht,_]=Dt.useState(null),w=Dt.useMemo(()=>(U?.allowFrom??[]).join(`
17
17
  `),[U]),at=Dt.useMemo(()=>(U?.telegramAllowFrom??[]).join(`
18
- `),[U]),rt=Dt.useCallback(async()=>{const[V,Et]=await Promise.all([ta("/api/status"),ta("/api/config")]);S(V),R(Et.config)},[]),St=Dt.useCallback(async()=>{z(null),lt(!0);try{const V=await ta("/api/gateway/start",{method:"POST",body:"{}"});V.ok&&typeof V.pid=="number"&&typeof V.logFile=="string"&&_({pid:V.pid,logFile:V.logFile}),await rt()}catch(V){z(V instanceof Error?V.message:String(V))}finally{lt(!1)}},[rt]),m=Dt.useCallback(async()=>{if(window.confirm("Stop the background gateway? Chat commands will not work until you start it again (here, omnish run -d, or your service).")){z(null),lt(!0);try{await ta("/api/gateway/stop",{method:"POST",body:"{}"}),_(null),await rt()}catch(V){z(V instanceof Error?V.message:String(V))}finally{lt(!1)}}},[rt]),O=Dt.useCallback(()=>{j.current?.close(),j.current=null,fetch("/api/wa/link/cancel",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:"{}"}),vt(!1),nt(!1),K(null),q(null)},[]),H=Dt.useCallback(async()=>{if(!g)return;const V=g.whatsappLinked===!0&&Y;if(V&&!window.confirm("Replace the saved WhatsApp session on this host? You will need to scan a new QR code."))return;z(null),nt(!0),K(null),q("Opening event stream…"),vt(!0);const Et=new EventSource("/api/wa/link/events");j.current=Et;const ol=Tl=>{(async()=>{let Bl;try{Bl=JSON.parse(Tl.data)}catch{return}const Zl=Bl.type;if(Zl==="qr"&&typeof Bl.payload=="string"){try{const Al=await Lg.toDataURL(Bl.payload,{width:280,margin:2});K(Al),q("Scan with WhatsApp → Linked devices → Link a device.")}catch{z("Could not render QR code.")}return}if(Zl==="restart"){q("WhatsApp requested a reconnect — a new QR may appear."),K(null);return}if(Zl==="open"){q("Linked. Session saved on this host."),P(!1);return}if(Zl==="error"){const Al=typeof Bl.message=="string"?Bl.message:"Pairing error";z(Al);return}if(Zl==="done"){const Al=Bl.ok===!0;Et.close(),j.current=null,vt(!1),nt(!1),Al&&(K(null),await rt())}})()};Et.addEventListener("message",ol);try{await new Promise((Tl,Bl)=>{const Al=window.setTimeout(()=>Bl(new Error("Event stream timed out.")),15e3);if(Et.readyState===EventSource.OPEN){window.clearTimeout(Al),Tl();return}Et.addEventListener("open",()=>{window.clearTimeout(Al),Tl()},{once:!0})})}catch(Tl){z(String(Tl)),Et.removeEventListener("message",ol),Et.close(),j.current=null,nt(!1),vt(!1),q(null);return}q("Starting pairing…");const ql=await fetch("/api/wa/link/start",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({force:V})}),El=await ql.text();let je;try{je=El?JSON.parse(El):void 0}catch{je={raw:El}}if(!ql.ok){const Tl=je?.error??El??ql.statusText;z(Tl),Et.removeEventListener("message",ol),Et.close(),j.current=null,nt(!1),vt(!1),q(null);return}nt(!1)},[rt,g,Y]);Dt.useEffect(()=>()=>{j.current?.close(),j.current=null},[]),Dt.useEffect(()=>{let V=!1;return(async()=>{try{const Et=await fetch("/api/me",{credentials:"include"});if(V)return;if(Et.status===401){y("gate");return}(await Et.json()).ok?(await rt(),y("app")):y("gate")}catch{V||y("gate")}})().catch(()=>{V||y("gate")}),()=>{V=!0}},[rt]);function Q(){z(null),G(null),tt(!0)}function ut(){B||(tt(!1),G(null))}Dt.useEffect(()=>{if(!L)return;const V=Et=>{Et.key==="Escape"&&!B&&(Et.preventDefault(),tt(!1),G(null))};return window.addEventListener("keydown",V),()=>window.removeEventListener("keydown",V)},[L,B]);async function ft(){X(!0),G(null),z(null);try{try{fetch("/api/shutdown",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:"{}"})}catch{}(await Gg(14e3)).ok?G("success"):G("timeout")}finally{X(!1)}}async function ot(){d(!0),z(null);try{await ta("/api/session",{method:"POST",body:JSON.stringify({token:v.trim()})}),await rt(),y("app");const V=new URL(window.location.href);V.searchParams.delete("token"),window.history.replaceState({},"",V.toString())}catch(V){z(String(V))}finally{d(!1)}}async function Ut(V){d(!0),z(null);try{const Et={...V};V.allowFromText!==void 0&&(Et.allowFrom=V.allowFromText.split(/\r?\n/).map(ql=>ql.trim()).filter(Boolean),delete Et.allowFromText),V.telegramAllowFromText!==void 0&&(Et.telegramAllowFrom=V.telegramAllowFromText.split(/\r?\n/).map(ql=>ql.trim()).filter(Boolean),delete Et.telegramAllowFromText);const ol=await ta("/api/config",{method:"PUT",body:JSON.stringify(Et)});R(ol.config),await rt()}catch(Et){z(String(Et))}finally{d(!1)}}async function zt(){O(),tt(!1),G(null),await ta("/api/logout",{method:"POST",body:"{}"}),y("gate"),R(null),S(null)}return T.jsxs("div",{className:"mesh-bg min-h-dvh",children:[T.jsxs("div",{className:"relative z-[1] mx-auto flex w-full max-w-lg flex-col gap-8 px-4 py-10 pb-16 lg:max-w-6xl",children:[T.jsxs("header",{className:`flex flex-col gap-2 pb-1 ${s==="app"&&g&&U?"lg:flex-row lg:items-start lg:justify-between lg:gap-6":""}`,children:[T.jsxs("div",{className:"flex min-w-0 flex-1 items-start gap-4 lg:gap-5",children:[T.jsx("img",{src:"/media/logo-Icon.png",alt:"",width:64,height:64,className:"h-14 w-14 shrink-0 rounded-2xl ring-1 ring-[color-mix(in_oklab,var(--color-omnish-lime)_38%,transparent)] shadow-[0_12px_40px_rgba(0,0,0,0.35)] lg:h-16 lg:w-16"}),T.jsxs("div",{className:"min-w-0 flex-1 space-y-3",children:[T.jsx("p",{className:"text-xs font-semibold tracking-[0.22em] text-[var(--color-omnish-lime)] uppercase",children:"omnish"}),T.jsx("h1",{className:"font-display text-3xl font-semibold tracking-tight text-[var(--color-omnish-fg)] lg:text-4xl",children:"Local setup"}),T.jsxs("p",{className:"max-w-2xl text-base leading-relaxed text-[var(--color-omnish-muted)]",children:["Finish configuring this machine before you use chat. Everything here writes the same"," ",T.jsx(pl,{children:"config.json"})," as the CLI."]})]})]}),s==="app"&&g&&U?T.jsx("div",{className:"shrink-0 lg:pt-1",children:T.jsx("button",{type:"button",disabled:B||o||$,className:"hidden w-full rounded-xl border border-rose-500/45 bg-rose-500/5 px-4 py-2.5 text-sm text-rose-100/90 transition duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100 lg:inline-flex lg:w-auto lg:justify-center",onClick:Q,children:"Stop setup server"})}):null]}),s==="check"?T.jsxs("div",{className:"glass rounded-2xl px-5 py-8 text-center",children:[T.jsx(ai,{children:"Session"}),T.jsx("p",{className:"font-display mt-3 text-base font-medium text-[var(--color-omnish-fg)]",children:"Checking session…"}),T.jsx("p",{className:"mt-2 text-sm text-[var(--color-omnish-muted)]",children:"Verifying your browser with this host."})]}):null,s==="gate"?T.jsxs("section",{className:"glass rounded-2xl px-5 py-6 lg:px-7 lg:py-7",children:[T.jsx(ai,{children:"Access"}),T.jsx("h2",{className:"font-display mt-2 text-xl font-semibold tracking-tight lg:text-2xl",children:"Enter setup token"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["The token was printed when you ran ",T.jsx(pl,{children:"omnish ui"})," and is stored on this host. Anyone on your network with this token can change gateway settings — use a trusted Wi‑Fi."]}),T.jsx("label",{className:"mt-6 block text-sm font-medium text-[var(--color-omnish-fg)]",htmlFor:"token",children:"Token"}),T.jsx("input",{id:"token",autoComplete:"off",className:"mt-2 w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 text-base",placeholder:"paste setup token",value:v,onChange:V=>f(V.target.value)}),A?T.jsx("p",{className:"mt-3 text-sm text-red-400",children:A}):null,T.jsx("button",{type:"button",disabled:o||!v.trim(),onClick:()=>{ot()},className:`mt-5 w-full text-center ${qn}`,children:o?"Opening…":"Unlock"})]}):null,s==="app"&&g&&U?T.jsxs(T.Fragment,{children:[T.jsx(Qg,{}),T.jsxs("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 lg:items-start lg:gap-8",children:[T.jsxs("section",{className:"glass rounded-2xl px-5 py-5 lg:min-w-0 lg:px-6 lg:py-6",children:[T.jsxs("header",{className:"border-b border-[color-mix(in_oklab,var(--color-omnish-border)_70%,transparent)] pb-4",children:[T.jsx(ai,{children:"Status"}),T.jsx("h2",{className:"font-display mt-1 text-lg font-semibold tracking-tight lg:text-xl",children:"Host snapshot"})]}),T.jsxs("div",{className:"mt-4 space-y-4",children:[T.jsxs("div",{className:"inset-module p-4",children:[T.jsxs("dl",{className:"space-y-3 text-sm",children:[T.jsxs("div",{className:"flex items-center justify-between gap-4",children:[T.jsx("dt",{className:"text-[var(--color-omnish-muted)]",children:"Version"}),T.jsx("dd",{className:"font-mono text-xs text-[var(--color-omnish-fg)]",children:g.version})]}),T.jsxs("div",{className:"flex items-start justify-between gap-4",children:[T.jsx("dt",{className:"shrink-0 text-[var(--color-omnish-muted)]",children:"Data dir"}),T.jsx("dd",{className:"break-all text-right font-mono text-xs text-[var(--color-omnish-fg)]",children:g.dataDir})]}),T.jsxs("div",{className:"flex items-center justify-between gap-4",children:[T.jsx("dt",{className:"text-[var(--color-omnish-muted)]",children:"WhatsApp session"}),T.jsx("dd",{className:"flex justify-end",children:T.jsx(Bh,{active:g.whatsappLinked,activeLabel:"Linked",inactiveLabel:"Not linked"})})]}),T.jsxs("div",{className:"flex items-center justify-between gap-4",children:[T.jsx("dt",{className:"text-[var(--color-omnish-muted)]",children:"Background gateway"}),T.jsx("dd",{className:"flex justify-end",children:T.jsx(Bh,{active:g.gatewayRunning,activeLabel:"Running",inactiveLabel:"Stopped"})})]}),T.jsxs("div",{className:"flex items-start justify-between gap-4",children:[T.jsx("dt",{className:"shrink-0 text-[var(--color-omnish-muted)]",children:"Gateway log (default)"}),T.jsx("dd",{className:"break-all text-right font-mono text-xs text-[var(--color-omnish-fg)]",children:g.gatewayLogFile})]})]}),g.gatewayRunning?T.jsxs("p",{className:"mt-4 rounded-xl border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-xs leading-relaxed text-amber-100/90",children:["Gateway is running — stop it in the module below, with ",T.jsx(pl,{children:"omnish stop"}),", or your service before QR pairing, or browser pairing will be rejected."]}):null]}),T.jsxs("div",{className:"inset-module space-y-3 p-4",children:[T.jsx("h3",{className:"font-display text-sm font-semibold tracking-tight text-[var(--color-omnish-fg)]",children:"Gateway"}),T.jsxs("p",{className:"text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:["Start or stop the chat gateway in the background (same as ",T.jsx(pl,{children:"omnish run -d"})," /"," ",T.jsx(pl,{children:"omnish stop"}),"). Logs append to the path above. You can close this UI after starting; the gateway keeps running."]}),Ht?T.jsxs("p",{className:"text-xs text-[var(--color-omnish-muted)]",children:["Last start: pid ",T.jsx("span",{className:"font-mono text-[var(--color-omnish-fg)]",children:Ht.pid})]}):null,T.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row",children:[T.jsx("button",{type:"button",disabled:W||o||g.gatewayRunning||$,onClick:()=>{St()},className:`w-full sm:flex-1 ${qn}`,children:W&&!g.gatewayRunning?"Starting…":"Start gateway"}),T.jsx("button",{type:"button",disabled:W||o||!g.gatewayRunning||$,onClick:()=>{m()},className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/20 px-4 py-3 text-sm text-[var(--color-omnish-muted)] transition duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100 sm:flex-1",children:W&&g.gatewayRunning?"Stopping…":"Stop gateway"})]})]}),T.jsxs("div",{className:"inset-module space-y-3 p-4",children:[T.jsx("h3",{className:"font-display text-sm font-semibold tracking-tight text-[var(--color-omnish-fg)]",children:"WhatsApp pairing (QR)"}),T.jsxs("p",{className:"text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:["Link this host like WhatsApp Web. Scan with your phone here, or run ",T.jsx(pl,{children:"omnish link"})," on this machine. When you are done, use ",T.jsx("strong",{className:"text-[var(--color-omnish-fg)]",children:"Start gateway"})," ","above (or ",T.jsx(pl,{children:"omnish run"})," / your service)."]}),g.whatsappLinked?T.jsxs("label",{className:"flex cursor-pointer items-center gap-2 text-sm",children:[T.jsx("input",{type:"checkbox",checked:Y,onChange:V=>P(V.target.checked),className:"rounded border-[var(--color-omnish-border)]"}),"Replace session (clear saved WhatsApp login and show a new QR)"]}):null,$?T.jsxs("div",{className:"space-y-3",children:[k?T.jsx("div",{className:"flex flex-col items-center gap-2",children:T.jsx("img",{src:k,alt:"WhatsApp QR code",className:"rounded-xl bg-white p-2",width:280,height:280})}):T.jsx("p",{className:"text-center text-sm text-[var(--color-omnish-muted)]",children:"Waiting for QR…"}),pt?T.jsx("p",{className:"text-center text-xs text-[var(--color-omnish-muted)]",children:pt}):null,T.jsx("button",{type:"button",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/20 px-4 py-3 text-sm text-[var(--color-omnish-muted)] transition duration-150 active:scale-[0.98]",onClick:()=>O(),children:"Cancel pairing"})]}):T.jsx("button",{type:"button",disabled:I||o||g.whatsappLinked&&!Y||g.gatewayRunning,onClick:()=>{H()},className:`w-full ${qn}`,children:g.whatsappLinked&&!Y?"Already linked":I?"Starting…":"Start QR pairing"})]})]})]}),T.jsxs("section",{className:"glass rounded-2xl px-5 py-5 lg:min-w-0 lg:px-6 lg:py-6",children:[T.jsxs("header",{className:"border-b border-[color-mix(in_oklab,var(--color-omnish-border)_70%,transparent)] pb-4",children:[T.jsx(ai,{children:"Configuration"}),T.jsx("h2",{className:"font-display mt-1 text-lg font-semibold tracking-tight lg:text-xl",children:"Core settings"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["Edits apply to the same ",T.jsx(pl,{children:"config.json"})," as the CLI and ",T.jsx(pl,{children:"/config"})," commands in chat."]})]}),A?T.jsx("p",{className:"mt-4 text-sm text-red-400",children:A}):null,T.jsxs("div",{className:A?"mt-4 space-y-5":"mt-5 space-y-5",children:[T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"gatewayMode",children:"Gateway mode"}),T.jsxs("select",{id:"gatewayMode",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-3 py-3 text-base",value:U.gatewayMode,onChange:V=>R({...U,gatewayMode:V.target.value}),children:[T.jsx("option",{value:"whatsapp",children:"whatsapp"}),T.jsx("option",{value:"telegram",children:"telegram"}),T.jsx("option",{value:"both",children:"both"})]})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"prefix",children:"Command prefix"}),T.jsx("input",{id:"prefix",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 font-mono text-base",value:U.commandPrefix,onChange:V=>R({...U,commandPrefix:V.target.value})})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"shell",children:"Shell"}),T.jsx("input",{id:"shell",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 font-mono text-sm",value:U.shell,onChange:V=>R({...U,shell:V.target.value})})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"tgtoken",children:"Telegram bot token"}),T.jsxs("p",{className:"text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:["Stored in config unless ",T.jsx(pl,{children:"TELEGRAM_BOT_TOKEN"})," overrides (",U.telegramBotTokenEnvOverride?"env is set on this host":"env not set",")."]}),T.jsx("input",{id:"tgtoken",autoComplete:"off",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 font-mono text-sm",placeholder:U.telegramBotTokenConfigured?"(leave blank to keep current)":"digits:secret from @BotFather",value:U.telegramBotToken.includes("…")?"":U.telegramBotToken,onChange:V=>R({...U,telegramBotToken:V.target.value})})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"waallow",children:"WhatsApp allowlist (one E.164 per line)"}),T.jsx("textarea",{id:"waallow",rows:4,className:"w-full resize-y rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-3 py-2 font-mono text-sm",defaultValue:w},w)]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"tgallow",children:"Telegram allowlist (numeric ids, optional tg: prefix — one per line)"}),T.jsx("textarea",{id:"tgallow",rows:3,className:"w-full resize-y rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-3 py-2 font-mono text-sm",defaultValue:at},at)]})]}),T.jsxs("div",{className:"mt-6 space-y-3 border-t border-[color-mix(in_oklab,var(--color-omnish-border)_70%,transparent)] pt-5",children:[T.jsx("button",{type:"button",disabled:o,className:`w-full ${qn}`,onClick:()=>{const V=document.getElementById("waallow"),Et=document.getElementById("tgallow"),ol=U.telegramBotToken.trim();Ut({gatewayMode:U.gatewayMode,commandPrefix:U.commandPrefix,shell:U.shell,...ol?{telegramBotToken:ol}:{},allowFromText:V?.value??"",telegramAllowFromText:Et?.value??""})},children:o?"Saving…":"Save configuration"}),T.jsx("button",{type:"button",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/20 px-4 py-3 text-sm text-[var(--color-omnish-muted)] transition duration-150 active:scale-[0.98]",onClick:()=>{zt()},children:"Lock session"}),T.jsx("button",{type:"button",disabled:B||o||$,className:"w-full rounded-xl border border-rose-500/45 bg-rose-500/5 px-4 py-3 text-sm text-rose-100/90 transition duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100 lg:hidden",onClick:Q,children:"Stop setup server"})]})]})]}),T.jsx("section",{className:"rounded-2xl border border-dashed border-[color-mix(in_oklab,var(--color-omnish-border)_80%,transparent)] bg-black/15 px-4 py-4 text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:"This panel binds to your LAN — treat the setup token like a password. Prefer a trusted network and isolate guest Wi‑Fi where possible."})]}):null]}),L?T.jsx("div",{className:"fixed inset-0 z-50 flex min-h-dvh items-center justify-center overflow-y-auto bg-black/55 backdrop-blur-sm [padding:max(1rem,env(safe-area-inset-top))_max(1rem,env(safe-area-inset-right))_max(1rem,env(safe-area-inset-bottom))_max(1rem,env(safe-area-inset-left))] overscroll-contain",role:"presentation",onClick:()=>{B||ut()},children:T.jsx("div",{role:"dialog","aria-modal":"true","aria-labelledby":"shutdown-dialog-title","aria-live":"polite",className:"glass my-auto w-full max-h-[min(90dvh,calc(100dvh-2rem))] max-w-md overflow-y-auto rounded-2xl border border-[var(--color-omnish-border)] p-6 shadow-2xl",onClick:V=>V.stopPropagation(),children:J==="success"?T.jsxs(T.Fragment,{children:[T.jsx("h2",{id:"shutdown-dialog-title",className:"font-display text-lg font-semibold tracking-tight text-white",children:"Setup server shut down"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["The setup server on this machine has stopped. You can close this tab. When you need this panel again, run ",T.jsx(pl,{children:"omnish ui"})," on the host."]}),T.jsx("div",{className:"mt-6",children:T.jsx("button",{type:"button",className:`w-full sm:w-auto ${qn}`,onClick:ut,children:"Done"})})]}):J==="timeout"?T.jsxs(T.Fragment,{children:[T.jsx("h2",{id:"shutdown-dialog-title",className:"font-display text-lg font-semibold tracking-tight text-white",children:"Couldn't confirm shutdown"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["We couldn't tell if the setup server fully stopped. Try ",T.jsx("strong",{children:"Stop setup server"})," again, or run ",T.jsx(pl,{children:"omnish ui"})," on the host — if the panel opens, it may still be running."]}),T.jsx("div",{className:"mt-6",children:T.jsx("button",{type:"button",className:"w-full rounded-xl border border-[var(--color-omnish-border)] px-4 py-3 text-sm text-[var(--color-omnish-muted)] sm:w-auto",onClick:ut,children:"Close"})})]}):T.jsxs(T.Fragment,{children:[T.jsx("h2",{id:"shutdown-dialog-title",className:"font-display text-lg font-semibold tracking-tight text-white",children:"Stop setup server?"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["This closes the setup server on this machine and this tab will stop working. Run ",T.jsx(pl,{children:"omnish ui"})," on the host whenever you want to open the panel again."]}),T.jsxs("div",{className:"mt-6 flex flex-col gap-3 sm:flex-row-reverse sm:justify-end",children:[T.jsx("button",{type:"button",disabled:B,className:"w-full rounded-xl bg-rose-500/90 px-4 py-3 text-sm font-semibold text-white shadow-lg shadow-rose-900/25 disabled:opacity-50 sm:w-auto",onClick:()=>{ft()},children:B?"Stopping…":"Stop server"}),T.jsx("button",{type:"button",disabled:B,className:"w-full rounded-xl border border-[var(--color-omnish-border)] px-4 py-3 text-sm text-[var(--color-omnish-muted)] disabled:opacity-40 sm:w-auto",onClick:ut,children:"Cancel"})]})]})})}):null]})}vg.createRoot(document.getElementById("root")).render(T.jsx(Dt.StrictMode,{children:T.jsx(Xg,{})}));
18
+ `),[U]),rt=Dt.useCallback(async()=>{const[V,Et]=await Promise.all([ta("/api/status"),ta("/api/config")]);S(V),R(Et.config)},[]),St=Dt.useCallback(async()=>{z(null),lt(!0);try{const V=await ta("/api/gateway/start",{method:"POST",body:"{}"});V.ok&&typeof V.pid=="number"&&typeof V.logFile=="string"&&_({pid:V.pid,logFile:V.logFile}),await rt()}catch(V){z(V instanceof Error?V.message:String(V))}finally{lt(!1)}},[rt]),m=Dt.useCallback(async()=>{if(window.confirm("Stop the background gateway? Chat commands will not work until you start it again (here, omnish start, or your service).")){z(null),lt(!0);try{await ta("/api/gateway/stop",{method:"POST",body:"{}"}),_(null),await rt()}catch(V){z(V instanceof Error?V.message:String(V))}finally{lt(!1)}}},[rt]),O=Dt.useCallback(()=>{j.current?.close(),j.current=null,fetch("/api/wa/link/cancel",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:"{}"}),vt(!1),nt(!1),K(null),q(null)},[]),H=Dt.useCallback(async()=>{if(!g)return;const V=g.whatsappLinked===!0&&Y;if(V&&!window.confirm("Replace the saved WhatsApp session on this host? You will need to scan a new QR code."))return;z(null),nt(!0),K(null),q("Opening event stream…"),vt(!0);const Et=new EventSource("/api/wa/link/events");j.current=Et;const ol=Tl=>{(async()=>{let Bl;try{Bl=JSON.parse(Tl.data)}catch{return}const Zl=Bl.type;if(Zl==="qr"&&typeof Bl.payload=="string"){try{const Al=await Lg.toDataURL(Bl.payload,{width:280,margin:2});K(Al),q("Scan with WhatsApp → Linked devices → Link a device.")}catch{z("Could not render QR code.")}return}if(Zl==="restart"){q("WhatsApp requested a reconnect — a new QR may appear."),K(null);return}if(Zl==="open"){q("Linked. Session saved on this host."),P(!1);return}if(Zl==="error"){const Al=typeof Bl.message=="string"?Bl.message:"Pairing error";z(Al);return}if(Zl==="done"){const Al=Bl.ok===!0;Et.close(),j.current=null,vt(!1),nt(!1),Al&&(K(null),await rt())}})()};Et.addEventListener("message",ol);try{await new Promise((Tl,Bl)=>{const Al=window.setTimeout(()=>Bl(new Error("Event stream timed out.")),15e3);if(Et.readyState===EventSource.OPEN){window.clearTimeout(Al),Tl();return}Et.addEventListener("open",()=>{window.clearTimeout(Al),Tl()},{once:!0})})}catch(Tl){z(String(Tl)),Et.removeEventListener("message",ol),Et.close(),j.current=null,nt(!1),vt(!1),q(null);return}q("Starting pairing…");const ql=await fetch("/api/wa/link/start",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({force:V})}),El=await ql.text();let je;try{je=El?JSON.parse(El):void 0}catch{je={raw:El}}if(!ql.ok){const Tl=je?.error??El??ql.statusText;z(Tl),Et.removeEventListener("message",ol),Et.close(),j.current=null,nt(!1),vt(!1),q(null);return}nt(!1)},[rt,g,Y]);Dt.useEffect(()=>()=>{j.current?.close(),j.current=null},[]),Dt.useEffect(()=>{let V=!1;return(async()=>{try{const Et=await fetch("/api/me",{credentials:"include"});if(V)return;if(Et.status===401){y("gate");return}(await Et.json()).ok?(await rt(),y("app")):y("gate")}catch{V||y("gate")}})().catch(()=>{V||y("gate")}),()=>{V=!0}},[rt]);function Q(){z(null),G(null),tt(!0)}function ut(){B||(tt(!1),G(null))}Dt.useEffect(()=>{if(!L)return;const V=Et=>{Et.key==="Escape"&&!B&&(Et.preventDefault(),tt(!1),G(null))};return window.addEventListener("keydown",V),()=>window.removeEventListener("keydown",V)},[L,B]);async function ft(){X(!0),G(null),z(null);try{try{fetch("/api/shutdown",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:"{}"})}catch{}(await Gg(14e3)).ok?G("success"):G("timeout")}finally{X(!1)}}async function ot(){d(!0),z(null);try{await ta("/api/session",{method:"POST",body:JSON.stringify({token:v.trim()})}),await rt(),y("app");const V=new URL(window.location.href);V.searchParams.delete("token"),window.history.replaceState({},"",V.toString())}catch(V){z(String(V))}finally{d(!1)}}async function Ut(V){d(!0),z(null);try{const Et={...V};V.allowFromText!==void 0&&(Et.allowFrom=V.allowFromText.split(/\r?\n/).map(ql=>ql.trim()).filter(Boolean),delete Et.allowFromText),V.telegramAllowFromText!==void 0&&(Et.telegramAllowFrom=V.telegramAllowFromText.split(/\r?\n/).map(ql=>ql.trim()).filter(Boolean),delete Et.telegramAllowFromText);const ol=await ta("/api/config",{method:"PUT",body:JSON.stringify(Et)});R(ol.config),await rt()}catch(Et){z(String(Et))}finally{d(!1)}}async function zt(){O(),tt(!1),G(null),await ta("/api/logout",{method:"POST",body:"{}"}),y("gate"),R(null),S(null)}return T.jsxs("div",{className:"mesh-bg min-h-dvh",children:[T.jsxs("div",{className:"relative z-[1] mx-auto flex w-full max-w-lg flex-col gap-8 px-4 py-10 pb-16 lg:max-w-6xl",children:[T.jsxs("header",{className:`flex flex-col gap-2 pb-1 ${s==="app"&&g&&U?"lg:flex-row lg:items-start lg:justify-between lg:gap-6":""}`,children:[T.jsxs("div",{className:"flex min-w-0 flex-1 items-start gap-4 lg:gap-5",children:[T.jsx("img",{src:"/media/logo-Icon.png",alt:"",width:64,height:64,className:"h-14 w-14 shrink-0 rounded-2xl ring-1 ring-[color-mix(in_oklab,var(--color-omnish-lime)_38%,transparent)] shadow-[0_12px_40px_rgba(0,0,0,0.35)] lg:h-16 lg:w-16"}),T.jsxs("div",{className:"min-w-0 flex-1 space-y-3",children:[T.jsx("p",{className:"text-xs font-semibold tracking-[0.22em] text-[var(--color-omnish-lime)] uppercase",children:"omnish"}),T.jsx("h1",{className:"font-display text-3xl font-semibold tracking-tight text-[var(--color-omnish-fg)] lg:text-4xl",children:"Local setup"}),T.jsxs("p",{className:"max-w-2xl text-base leading-relaxed text-[var(--color-omnish-muted)]",children:["Finish configuring this machine before you use chat. Everything here writes the same"," ",T.jsx(pl,{children:"config.json"})," as the CLI."]})]})]}),s==="app"&&g&&U?T.jsx("div",{className:"shrink-0 lg:pt-1",children:T.jsx("button",{type:"button",disabled:B||o||$,className:"hidden w-full rounded-xl border border-rose-500/45 bg-rose-500/5 px-4 py-2.5 text-sm text-rose-100/90 transition duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100 lg:inline-flex lg:w-auto lg:justify-center",onClick:Q,children:"Stop setup server"})}):null]}),s==="check"?T.jsxs("div",{className:"glass rounded-2xl px-5 py-8 text-center",children:[T.jsx(ai,{children:"Session"}),T.jsx("p",{className:"font-display mt-3 text-base font-medium text-[var(--color-omnish-fg)]",children:"Checking session…"}),T.jsx("p",{className:"mt-2 text-sm text-[var(--color-omnish-muted)]",children:"Verifying your browser with this host."})]}):null,s==="gate"?T.jsxs("section",{className:"glass rounded-2xl px-5 py-6 lg:px-7 lg:py-7",children:[T.jsx(ai,{children:"Access"}),T.jsx("h2",{className:"font-display mt-2 text-xl font-semibold tracking-tight lg:text-2xl",children:"Enter setup token"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["The token was printed when you ran ",T.jsx(pl,{children:"omnish ui"})," and is stored on this host. Anyone on your network with this token can change gateway settings — use a trusted Wi‑Fi."]}),T.jsx("label",{className:"mt-6 block text-sm font-medium text-[var(--color-omnish-fg)]",htmlFor:"token",children:"Token"}),T.jsx("input",{id:"token",autoComplete:"off",className:"mt-2 w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 text-base",placeholder:"paste setup token",value:v,onChange:V=>f(V.target.value)}),A?T.jsx("p",{className:"mt-3 text-sm text-red-400",children:A}):null,T.jsx("button",{type:"button",disabled:o||!v.trim(),onClick:()=>{ot()},className:`mt-5 w-full text-center ${qn}`,children:o?"Opening…":"Unlock"})]}):null,s==="app"&&g&&U?T.jsxs(T.Fragment,{children:[T.jsx(Qg,{}),T.jsxs("div",{className:"grid grid-cols-1 gap-6 lg:grid-cols-2 lg:items-start lg:gap-8",children:[T.jsxs("section",{className:"glass rounded-2xl px-5 py-5 lg:min-w-0 lg:px-6 lg:py-6",children:[T.jsxs("header",{className:"border-b border-[color-mix(in_oklab,var(--color-omnish-border)_70%,transparent)] pb-4",children:[T.jsx(ai,{children:"Status"}),T.jsx("h2",{className:"font-display mt-1 text-lg font-semibold tracking-tight lg:text-xl",children:"Host snapshot"})]}),T.jsxs("div",{className:"mt-4 space-y-4",children:[T.jsxs("div",{className:"inset-module p-4",children:[T.jsxs("dl",{className:"space-y-3 text-sm",children:[T.jsxs("div",{className:"flex items-center justify-between gap-4",children:[T.jsx("dt",{className:"text-[var(--color-omnish-muted)]",children:"Version"}),T.jsx("dd",{className:"font-mono text-xs text-[var(--color-omnish-fg)]",children:g.version})]}),T.jsxs("div",{className:"flex items-start justify-between gap-4",children:[T.jsx("dt",{className:"shrink-0 text-[var(--color-omnish-muted)]",children:"Data dir"}),T.jsx("dd",{className:"break-all text-right font-mono text-xs text-[var(--color-omnish-fg)]",children:g.dataDir})]}),T.jsxs("div",{className:"flex items-center justify-between gap-4",children:[T.jsx("dt",{className:"text-[var(--color-omnish-muted)]",children:"WhatsApp session"}),T.jsx("dd",{className:"flex justify-end",children:T.jsx(Bh,{active:g.whatsappLinked,activeLabel:"Linked",inactiveLabel:"Not linked"})})]}),T.jsxs("div",{className:"flex items-center justify-between gap-4",children:[T.jsx("dt",{className:"text-[var(--color-omnish-muted)]",children:"Background gateway"}),T.jsx("dd",{className:"flex justify-end",children:T.jsx(Bh,{active:g.gatewayRunning,activeLabel:"Running",inactiveLabel:"Stopped"})})]}),T.jsxs("div",{className:"flex items-start justify-between gap-4",children:[T.jsx("dt",{className:"shrink-0 text-[var(--color-omnish-muted)]",children:"Gateway log (default)"}),T.jsx("dd",{className:"break-all text-right font-mono text-xs text-[var(--color-omnish-fg)]",children:g.gatewayLogFile})]})]}),g.gatewayRunning?T.jsxs("p",{className:"mt-4 rounded-xl border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-xs leading-relaxed text-amber-100/90",children:["Gateway is running — stop it in the module below, with"," ",T.jsx(pl,{children:"omnish stop"}),", or your service before QR pairing, or browser pairing will be rejected."]}):null]}),T.jsxs("div",{className:"inset-module space-y-3 p-4",children:[T.jsx("h3",{className:"font-display text-sm font-semibold tracking-tight text-[var(--color-omnish-fg)]",children:"Gateway"}),T.jsxs("p",{className:"text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:["Start or stop the chat gateway in the background (same as"," ",T.jsx(pl,{children:"omnish start"})," / ",T.jsx(pl,{children:"omnish stop"}),"). Logs append to the path above. You can close this UI after starting; the gateway keeps running."]}),Ht?T.jsxs("p",{className:"text-xs text-[var(--color-omnish-muted)]",children:["Last start: pid"," ",T.jsx("span",{className:"font-mono text-[var(--color-omnish-fg)]",children:Ht.pid})]}):null,T.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row",children:[T.jsx("button",{type:"button",disabled:W||o||g.gatewayRunning||$,onClick:()=>{St()},className:`w-full sm:flex-1 ${qn}`,children:W&&!g.gatewayRunning?"Starting…":"Start gateway"}),T.jsx("button",{type:"button",disabled:W||o||!g.gatewayRunning||$,onClick:()=>{m()},className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/20 px-4 py-3 text-sm text-[var(--color-omnish-muted)] transition duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100 sm:flex-1",children:W&&g.gatewayRunning?"Stopping…":"Stop gateway"})]})]}),T.jsxs("div",{className:"inset-module space-y-3 p-4",children:[T.jsx("h3",{className:"font-display text-sm font-semibold tracking-tight text-[var(--color-omnish-fg)]",children:"WhatsApp pairing (QR)"}),T.jsxs("p",{className:"text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:["Link this host like WhatsApp Web. Scan with your phone here, or run"," ",T.jsx(pl,{children:"omnish link"})," on this machine. When you are done, use"," ",T.jsx("strong",{className:"text-[var(--color-omnish-fg)]",children:"Start gateway"})," above (or ",T.jsx(pl,{children:"omnish run"})," / your service)."]}),g.whatsappLinked?T.jsxs("label",{className:"flex cursor-pointer items-center gap-2 text-sm",children:[T.jsx("input",{type:"checkbox",checked:Y,onChange:V=>P(V.target.checked),className:"rounded border-[var(--color-omnish-border)]"}),"Replace session (clear saved WhatsApp login and show a new QR)"]}):null,$?T.jsxs("div",{className:"space-y-3",children:[k?T.jsx("div",{className:"flex flex-col items-center gap-2",children:T.jsx("img",{src:k,alt:"WhatsApp QR code",className:"rounded-xl bg-white p-2",width:280,height:280})}):T.jsx("p",{className:"text-center text-sm text-[var(--color-omnish-muted)]",children:"Waiting for QR…"}),pt?T.jsx("p",{className:"text-center text-xs text-[var(--color-omnish-muted)]",children:pt}):null,T.jsx("button",{type:"button",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/20 px-4 py-3 text-sm text-[var(--color-omnish-muted)] transition duration-150 active:scale-[0.98]",onClick:()=>O(),children:"Cancel pairing"})]}):T.jsx("button",{type:"button",disabled:I||o||g.whatsappLinked&&!Y||g.gatewayRunning,onClick:()=>{H()},className:`w-full ${qn}`,children:g.whatsappLinked&&!Y?"Already linked":I?"Starting…":"Start QR pairing"})]})]})]}),T.jsxs("section",{className:"glass rounded-2xl px-5 py-5 lg:min-w-0 lg:px-6 lg:py-6",children:[T.jsxs("header",{className:"border-b border-[color-mix(in_oklab,var(--color-omnish-border)_70%,transparent)] pb-4",children:[T.jsx(ai,{children:"Configuration"}),T.jsx("h2",{className:"font-display mt-1 text-lg font-semibold tracking-tight lg:text-xl",children:"Core settings"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["Edits apply to the same ",T.jsx(pl,{children:"config.json"})," as the CLI and ",T.jsx(pl,{children:"/config"})," ","commands in chat."]})]}),A?T.jsx("p",{className:"mt-4 text-sm text-red-400",children:A}):null,T.jsxs("div",{className:A?"mt-4 space-y-5":"mt-5 space-y-5",children:[T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"gatewayMode",children:"Gateway mode"}),T.jsxs("select",{id:"gatewayMode",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-3 py-3 text-base",value:U.gatewayMode,onChange:V=>R({...U,gatewayMode:V.target.value}),children:[T.jsx("option",{value:"whatsapp",children:"whatsapp"}),T.jsx("option",{value:"telegram",children:"telegram"}),T.jsx("option",{value:"both",children:"both"})]})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"prefix",children:"Command prefix"}),T.jsx("input",{id:"prefix",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 font-mono text-base",value:U.commandPrefix,onChange:V=>R({...U,commandPrefix:V.target.value})})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"shell",children:"Shell"}),T.jsx("input",{id:"shell",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 font-mono text-sm",value:U.shell,onChange:V=>R({...U,shell:V.target.value})})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"tgtoken",children:"Telegram bot token"}),T.jsxs("p",{className:"text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:["Stored in config unless ",T.jsx(pl,{children:"TELEGRAM_BOT_TOKEN"})," overrides (",U.telegramBotTokenEnvOverride?"env is set on this host":"env not set",")."]}),T.jsx("input",{id:"tgtoken",autoComplete:"off",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-4 py-3 font-mono text-sm",placeholder:U.telegramBotTokenConfigured?"(leave blank to keep current)":"digits:secret from @BotFather",value:U.telegramBotToken.includes("…")?"":U.telegramBotToken,onChange:V=>R({...U,telegramBotToken:V.target.value})})]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"waallow",children:"WhatsApp allowlist (one E.164 per line)"}),T.jsx("textarea",{id:"waallow",rows:4,className:"w-full resize-y rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-3 py-2 font-mono text-sm",defaultValue:w},w)]}),T.jsxs("div",{className:"space-y-2",children:[T.jsx("label",{className:"block text-sm font-medium",htmlFor:"tgallow",children:"Telegram allowlist (numeric ids, optional tg: prefix — one per line)"}),T.jsx("textarea",{id:"tgallow",rows:3,className:"w-full resize-y rounded-xl border border-[var(--color-omnish-border)] bg-black/35 px-3 py-2 font-mono text-sm",defaultValue:at},at)]})]}),T.jsxs("div",{className:"mt-6 space-y-3 border-t border-[color-mix(in_oklab,var(--color-omnish-border)_70%,transparent)] pt-5",children:[T.jsx("button",{type:"button",disabled:o,className:`w-full ${qn}`,onClick:()=>{const V=document.getElementById("waallow"),Et=document.getElementById("tgallow"),ol=U.telegramBotToken.trim();Ut({gatewayMode:U.gatewayMode,commandPrefix:U.commandPrefix,shell:U.shell,...ol?{telegramBotToken:ol}:{},allowFromText:V?.value??"",telegramAllowFromText:Et?.value??""})},children:o?"Saving…":"Save configuration"}),T.jsx("button",{type:"button",className:"w-full rounded-xl border border-[var(--color-omnish-border)] bg-black/20 px-4 py-3 text-sm text-[var(--color-omnish-muted)] transition duration-150 active:scale-[0.98]",onClick:()=>{zt()},children:"Lock session"}),T.jsx("button",{type:"button",disabled:B||o||$,className:"w-full rounded-xl border border-rose-500/45 bg-rose-500/5 px-4 py-3 text-sm text-rose-100/90 transition duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-40 disabled:active:scale-100 lg:hidden",onClick:Q,children:"Stop setup server"})]})]})]}),T.jsx("section",{className:"rounded-2xl border border-dashed border-[color-mix(in_oklab,var(--color-omnish-border)_80%,transparent)] bg-black/15 px-4 py-4 text-xs leading-relaxed text-[var(--color-omnish-muted)]",children:"This panel binds to your LAN — treat the setup token like a password. Prefer a trusted network and isolate guest Wi‑Fi where possible."})]}):null]}),L?T.jsx("div",{className:"fixed inset-0 z-50 flex min-h-dvh items-center justify-center overflow-y-auto bg-black/55 backdrop-blur-sm [padding:max(1rem,env(safe-area-inset-top))_max(1rem,env(safe-area-inset-right))_max(1rem,env(safe-area-inset-bottom))_max(1rem,env(safe-area-inset-left))] overscroll-contain",role:"presentation",onClick:()=>{B||ut()},children:T.jsx("div",{role:"dialog","aria-modal":"true","aria-labelledby":"shutdown-dialog-title","aria-live":"polite",className:"glass my-auto w-full max-h-[min(90dvh,calc(100dvh-2rem))] max-w-md overflow-y-auto rounded-2xl border border-[var(--color-omnish-border)] p-6 shadow-2xl",onClick:V=>V.stopPropagation(),children:J==="success"?T.jsxs(T.Fragment,{children:[T.jsx("h2",{id:"shutdown-dialog-title",className:"font-display text-lg font-semibold tracking-tight text-white",children:"Setup server shut down"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["The setup server on this machine has stopped. You can close this tab. When you need this panel again, run ",T.jsx(pl,{children:"omnish ui"})," on the host."]}),T.jsx("div",{className:"mt-6",children:T.jsx("button",{type:"button",className:`w-full sm:w-auto ${qn}`,onClick:ut,children:"Done"})})]}):J==="timeout"?T.jsxs(T.Fragment,{children:[T.jsx("h2",{id:"shutdown-dialog-title",className:"font-display text-lg font-semibold tracking-tight text-white",children:"Couldn't confirm shutdown"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["We couldn't tell if the setup server fully stopped. Try"," ",T.jsx("strong",{children:"Stop setup server"})," again, or run ",T.jsx(pl,{children:"omnish ui"})," on the host — if the panel opens, it may still be running."]}),T.jsx("div",{className:"mt-6",children:T.jsx("button",{type:"button",className:"w-full rounded-xl border border-[var(--color-omnish-border)] px-4 py-3 text-sm text-[var(--color-omnish-muted)] sm:w-auto",onClick:ut,children:"Close"})})]}):T.jsxs(T.Fragment,{children:[T.jsx("h2",{id:"shutdown-dialog-title",className:"font-display text-lg font-semibold tracking-tight text-white",children:"Stop setup server?"}),T.jsxs("p",{className:"mt-3 text-sm leading-relaxed text-[var(--color-omnish-muted)]",children:["This closes the setup server on this machine and this tab will stop working. Run"," ",T.jsx(pl,{children:"omnish ui"})," on the host whenever you want to open the panel again."]}),T.jsxs("div",{className:"mt-6 flex flex-col gap-3 sm:flex-row-reverse sm:justify-end",children:[T.jsx("button",{type:"button",disabled:B,className:"w-full rounded-xl bg-rose-500/90 px-4 py-3 text-sm font-semibold text-white shadow-lg shadow-rose-900/25 disabled:opacity-50 sm:w-auto",onClick:()=>{ft()},children:B?"Stopping…":"Stop server"}),T.jsx("button",{type:"button",disabled:B,className:"w-full rounded-xl border border-[var(--color-omnish-border)] px-4 py-3 text-sm text-[var(--color-omnish-muted)] disabled:opacity-40 sm:w-auto",onClick:ut,children:"Cancel"})]})]})})}):null]})}vg.createRoot(document.getElementById("root")).render(T.jsx(Dt.StrictMode,{children:T.jsx(Xg,{})}));
@@ -11,7 +11,7 @@
11
11
  href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;700&display=swap"
12
12
  rel="stylesheet"
13
13
  />
14
- <script type="module" crossorigin src="/assets/index-DxXW0CWH.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-aUJGrxrr.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="/assets/index-D6NDVsng.css">
16
16
  </head>
17
17
  <body class="min-h-dvh antialiased">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnish",
3
- "version": "1.6.4",
3
+ "version": "1.6.6",
4
4
  "description": "omnish — allowlisted inbox → your real shell (WhatsApp/Telegram; more surfaces later). No AI.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,6 +25,7 @@
25
25
  "homepage": "https://omnish.dev",
26
26
  "files": [
27
27
  "dist",
28
+ "scripts/fix-node-pty-perms.mjs",
28
29
  "README.md",
29
30
  "CHANGELOG.md",
30
31
  "LICENSE",
@@ -36,21 +37,6 @@
36
37
  "bin": {
37
38
  "omnish": "dist/index.js"
38
39
  },
39
- "scripts": {
40
- "reinstall": "rm -rf node_modules && pnpm install",
41
- "prepack": "npm run build",
42
- "build": "node scripts/build-bundle.mjs",
43
- "build:doc-index": "node scripts/build-doc-index.mjs",
44
- "typecheck": "tsc --noEmit",
45
- "pretypecheck": "node scripts/build-doc-index.mjs",
46
- "pretest": "node scripts/build-doc-index.mjs",
47
- "test": "tsx --test 'src/**/*.test.ts'",
48
- "omnish": "tsx src/index.ts",
49
- "link": "tsx src/index.ts link",
50
- "run": "tsx src/index.ts run",
51
- "logout": "tsx src/index.ts logout"
52
- },
53
- "packageManager": "pnpm@11.0.8+sha512.4c4097e1dd2d42372c4e7fa5a791ff28fc75a484c7ac192e64b1df0fdef17594ba982f9b4fed9adfb3c757846f565b799b2763fb3733d1de1bcb82cf46684912",
54
40
  "engines": {
55
41
  "node": ">=22.13"
56
42
  },
@@ -70,15 +56,33 @@
70
56
  "@types/qrcode-terminal": "^0.12.2",
71
57
  "@types/ws": "^8.18.1",
72
58
  "esbuild": "^0.24.2",
59
+ "prettier": "^3.5.3",
73
60
  "tsx": "^4.19.2",
74
61
  "typescript": "^5.7.2"
75
62
  },
76
- "pnpm": {
77
- "onlyBuiltDependencies": [
78
- "@parcel/watcher",
79
- "better-sqlite3",
80
- "esbuild",
81
- "node-pty"
82
- ]
63
+ "allowScripts": {
64
+ "@parcel/watcher": true,
65
+ "@whiskeysockets/baileys": true,
66
+ "better-sqlite3": true,
67
+ "node-pty": true,
68
+ "sharp": true,
69
+ "protobufjs": true
70
+ },
71
+ "scripts": {
72
+ "reinstall": "rm -rf node_modules && pnpm install",
73
+ "postinstall": "node scripts/fix-node-pty-perms.mjs",
74
+ "build": "node scripts/build-bundle.mjs",
75
+ "build:doc-index": "node scripts/build-doc-index.mjs",
76
+ "typecheck": "tsc --noEmit",
77
+ "pretypecheck": "node scripts/build-doc-index.mjs",
78
+ "pretest": "node scripts/build-doc-index.mjs",
79
+ "format": "prettier --write .",
80
+ "format:check": "prettier --check .",
81
+ "test": "tsx --test 'src/**/*.test.ts'",
82
+ "omnish": "tsx src/index.ts",
83
+ "link": "tsx src/index.ts link",
84
+ "run": "tsx src/index.ts run",
85
+ "local": "omnish stop && node scripts/build-bundle.mjs && npm link && omnish start",
86
+ "logout": "tsx src/index.ts logout"
83
87
  }
84
- }
88
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Ensure node-pty spawn-helper is executable on macOS after npm/pnpm install.
3
+ * @see https://github.com/microsoft/node-pty/issues/850
4
+ */
5
+ import { createRequire } from "node:module";
6
+ import fs from "node:fs";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+
10
+ if (os.platform() !== "darwin") {
11
+ process.exit(0);
12
+ }
13
+
14
+ const require = createRequire(import.meta.url);
15
+
16
+ let nodePtyRoot;
17
+ try {
18
+ nodePtyRoot = path.dirname(require.resolve("node-pty/package.json"));
19
+ } catch {
20
+ process.exit(0);
21
+ }
22
+
23
+ const candidates = [
24
+ path.join(nodePtyRoot, "prebuilds", `darwin-${process.arch}`, "spawn-helper"),
25
+ path.join(nodePtyRoot, "build", "Release", "spawn-helper"),
26
+ ];
27
+
28
+ for (const helperPath of candidates) {
29
+ if (!fs.existsSync(helperPath)) {
30
+ continue;
31
+ }
32
+ try {
33
+ const mode = fs.statSync(helperPath).mode;
34
+ if ((mode & 0o111) === 0) {
35
+ fs.chmodSync(helperPath, mode | 0o755);
36
+ console.log(`omnish: fixed execute permission on ${helperPath}`);
37
+ }
38
+ } catch (err) {
39
+ console.warn(`omnish: could not chmod node-pty spawn-helper (${helperPath}): ${err}`);
40
+ }
41
+ }