omnish 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,101 +1,102 @@
1
1
  #!/usr/bin/env node
2
- import ml from"node:dns";import{spawn as fl,spawnSync as gl}from"node:child_process";import ie from"node:fs";import ct from"node:path";import{fileURLToPath as hl}from"node:url";import Ps from"node:os";import vt from"node:fs";import Hs from"node:crypto";import cn from"node:fs";import js from"node:os";import te from"node:path";function Ws(){let e=process.env.OMNISH_HOME?.trim();if(e)return te.resolve(e);let t=js.homedir(),n=te.join(t,".omnish"),r=te.join(t,".whatslive");try{if(cn.existsSync(n))return n;if(cn.existsSync(r))return r}catch{}return n}var T=Ws(),q=te.join(T,"auth"),ye=te.join(T,"jobs"),mr=te.join(T,"apps"),fr=te.join(T,"logs"),pe=te.join(fr,"gateway.log"),Y=te.join(T,"gateway.pid"),Ue=te.join(T,"gateway-control.json"),v=te.join(T,"config.json"),bt=te.join(T,"shortcuts.json"),St=te.join(T,"recipes.json"),xt=te.join(T,"recipes-user.json");function ut(e){let t=Hs.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return te.join(mr,t)}function P(e){cn.mkdirSync(e,{recursive:!0,mode:448})}function G(){P(T),P(q),P(ye),P(mr),P(fr)}var hr=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,yr=/^(\d+)@c\.us$/i,wr=/^(\d+)@lid$/i;function br(e){let t=e.trim();for(;;){let n=t;if(t=t.replace(/^whatsapp:/i,"").trim(),t===n)return t}}function Ds(e){let t=br(e);if(!t.toLowerCase().endsWith("@g.us"))return!1;let r=t.slice(0,t.length-5);return!r||r.includes("@")?!1:/^[0-9]+(-[0-9]+)*$/.test(r)}function Us(e){let t=e.match(hr);if(t)return t[1]??null;let n=e.match(yr);if(n)return n[1]??null;let r=e.match(wr);return r?r[1]??null:null}function gr(e){let t=e.replace(/\D/g,"");return t?`+${t}`:""}function Sr(e){return`${e.replace(/\D/g,"")}@s.whatsapp.net`}function F(e){let t=br(e);if(!t||Ds(t))return null;if(hr.test(t)||yr.test(t)||wr.test(t)){let r=Us(t);if(!r)return null;let o=gr(r);return o.length>1?o:null}if(t.includes("@"))return null;let n=gr(t);return n.length>1?n:null}function xr(e){return e.map(t=>String(t).trim()).filter(t=>!!t).map(t=>t==="*"?t:F(t)).filter(t=>!!t)}function kr(e){let t=new Set;for(let n of e)n!=="*"&&t.add(n);return t}function me(e){let t=e.trim();for(;;){let n=t.toLowerCase();if(n.startsWith("tg:")){t=t.slice(3).trimStart();continue}if(n.startsWith("telegram:")){t=t.slice(9).trimStart();continue}break}return/^\d+$/.test(t)?t:null}function vr(e){let t=new Set;for(let n of e){let r=me(String(n));r&&t.add(r)}return t}function un(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let o=me(t);return o?{kind:"tg",id:o}:null}let r=F(t);return r?{kind:"wa",normalized:r}:null}var I={gatewayMode:"whatsapp",telegramBotToken:"",telegramAllowFrom:[],allowFrom:[],commandPrefix:"!",syncTimeoutMs:3e4,syncMaxBytes:32768,jobLogTailLines:80,shell:"/bin/bash",appsCols:120,appsRows:40,appsFlushMs:300,appsMinIntervalMs:800,appsMaxFlushBytes:8192,appsMaxSessions:5,appsMaxSessionsTotal:20,appsMaxWaChars:3500,appsLogTailLines:80,appsSubmitDelayMs:50,appsClearInput:!0,appsClearInputDelayMs:20,appsClearInputSequence:"^A,^K",fileSendMaxBytes:0,fileReceiveMaxBytes:0,fileInboxSubdir:"inbox",fileReceiveRootMode:"downloads",fileReceiveRootPath:"",recipesAllowDangerousBuiltins:!1,recipesMaxTaskChars:0,clusterEnabled:!1,clusterLabel:"",clusterRole:"secondary",clusterSenderBindings:{},serviceInstallFromChat:!1};function Gs(e){return e==="downloads"||e==="omnishData"||e==="sessionCwd"||e==="processCwd"||e==="fixed"?e:I.fileReceiveRootMode}function zs(e){return e==="primary"?"primary":"secondary"}function Js(e){if(!e||typeof e!="object")return{};let t={};for(let[n,r]of Object.entries(e)){if(typeof r!="string")continue;let o=r.trim();if(!o)continue;let s=n.trim(),i=s.toLowerCase();if(i.startsWith("wa:")){let l=F(s.slice(3));l&&(t[`wa:${l}`]=o.slice(0,64));continue}if(i.startsWith("tg:")||i.startsWith("telegram:")){let l=me(s);l&&(t[`tg:${l}`]=o.slice(0,64));continue}let a=F(s);a&&(t[`wa:${a}`]=o.slice(0,64))}return t}function kt(e){let t=typeof e.appsFlushMs=="number"&&e.appsFlushMs>=0?e.appsFlushMs:I.appsFlushMs,n=e.gatewayMode==="telegram"||e.gatewayMode==="both"||e.gatewayMode==="whatsapp"?e.gatewayMode:I.gatewayMode,r=typeof e.telegramBotToken=="string"?e.telegramBotToken:I.telegramBotToken,o=Array.isArray(e.telegramAllowFrom)?[...new Set(e.telegramAllowFrom.map(s=>me(String(s))).filter(s=>!!s))].sort():I.telegramAllowFrom;return{...I,...e,gatewayMode:n,telegramBotToken:r,telegramAllowFrom:o,allowFrom:Array.isArray(e.allowFrom)?xr(e.allowFrom.map(String)).filter(s=>s!=="*"):I.allowFrom,commandPrefix:(()=>{let s=typeof e.commandPrefix=="string"&&e.commandPrefix.length>0?e.commandPrefix:I.commandPrefix;return s==="! "?"!":s})(),syncTimeoutMs:typeof e.syncTimeoutMs=="number"&&e.syncTimeoutMs>0?e.syncTimeoutMs:I.syncTimeoutMs,syncMaxBytes:typeof e.syncMaxBytes=="number"&&e.syncMaxBytes>0?e.syncMaxBytes:I.syncMaxBytes,jobLogTailLines:typeof e.jobLogTailLines=="number"&&e.jobLogTailLines>0?e.jobLogTailLines:I.jobLogTailLines,shell:typeof e.shell=="string"&&e.shell.length>0?e.shell:I.shell,appsCols:typeof e.appsCols=="number"&&e.appsCols>0&&e.appsCols<=500?Math.floor(e.appsCols):I.appsCols,appsRows:typeof e.appsRows=="number"&&e.appsRows>0&&e.appsRows<=200?Math.floor(e.appsRows):I.appsRows,appsFlushMs:t,appsMinIntervalMs:typeof e.appsMinIntervalMs=="number"&&e.appsMinIntervalMs>=0?e.appsMinIntervalMs:I.appsMinIntervalMs,appsMaxFlushBytes:typeof e.appsMaxFlushBytes=="number"&&e.appsMaxFlushBytes>256?Math.floor(e.appsMaxFlushBytes):I.appsMaxFlushBytes,appsMaxSessions:typeof e.appsMaxSessions=="number"&&e.appsMaxSessions>0?Math.min(50,Math.floor(e.appsMaxSessions)):I.appsMaxSessions,appsMaxSessionsTotal:typeof e.appsMaxSessionsTotal=="number"&&e.appsMaxSessionsTotal>0?Math.min(200,Math.floor(e.appsMaxSessionsTotal)):I.appsMaxSessionsTotal,appsMaxWaChars:typeof e.appsMaxWaChars=="number"&&e.appsMaxWaChars>256?Math.floor(e.appsMaxWaChars):I.appsMaxWaChars,appsLogTailLines:typeof e.appsLogTailLines=="number"&&e.appsLogTailLines>0?Math.min(500,Math.floor(e.appsLogTailLines)):I.appsLogTailLines,appsSubmitDelayMs:typeof e.appsSubmitDelayMs=="number"&&e.appsSubmitDelayMs>=0?Math.min(500,Math.floor(e.appsSubmitDelayMs)):I.appsSubmitDelayMs,appsClearInput:typeof e.appsClearInput=="boolean"?e.appsClearInput:I.appsClearInput,appsClearInputDelayMs:typeof e.appsClearInputDelayMs=="number"&&e.appsClearInputDelayMs>=0?Math.min(200,Math.floor(e.appsClearInputDelayMs)):I.appsClearInputDelayMs,appsClearInputSequence:typeof e.appsClearInputSequence=="string"&&e.appsClearInputSequence.length>0?e.appsClearInputSequence.slice(0,200):I.appsClearInputSequence,fileSendMaxBytes:typeof e.fileSendMaxBytes=="number"&&e.fileSendMaxBytes>=0?e.fileSendMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileSendMaxBytes)):I.fileSendMaxBytes,fileReceiveMaxBytes:typeof e.fileReceiveMaxBytes=="number"&&e.fileReceiveMaxBytes>=0?e.fileReceiveMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileReceiveMaxBytes)):I.fileReceiveMaxBytes,fileInboxSubdir:typeof e.fileInboxSubdir=="string"&&e.fileInboxSubdir.length>0&&e.fileInboxSubdir.replace(/[/\\]/g,"").slice(0,80)||I.fileInboxSubdir,fileReceiveRootMode:Gs(e.fileReceiveRootMode),fileReceiveRootPath:typeof e.fileReceiveRootPath=="string"?e.fileReceiveRootPath.trim().slice(0,4096):I.fileReceiveRootPath,recipesAllowDangerousBuiltins:typeof e.recipesAllowDangerousBuiltins=="boolean"?e.recipesAllowDangerousBuiltins:I.recipesAllowDangerousBuiltins,recipesMaxTaskChars:typeof e.recipesMaxTaskChars=="number"&&e.recipesMaxTaskChars>=0?e.recipesMaxTaskChars===0?0:Math.min(Number.MAX_SAFE_INTEGER,Math.floor(e.recipesMaxTaskChars)):I.recipesMaxTaskChars,clusterEnabled:typeof e.clusterEnabled=="boolean"?e.clusterEnabled:I.clusterEnabled,clusterLabel:typeof e.clusterLabel=="string"?e.clusterLabel.trim().slice(0,128):I.clusterLabel,clusterRole:zs(e.clusterRole),clusterSenderBindings:Js(e.clusterSenderBindings),serviceInstallFromChat:typeof e.serviceInstallFromChat=="boolean"?e.serviceInstallFromChat:I.serviceInstallFromChat}}function x(){if(G(),!vt.existsSync(v)){let e=kt({});return Ce(e),e}try{let e=vt.readFileSync(v,"utf8"),t=JSON.parse(e);return kt(t)}catch{return kt({})}}function Ce(e){G();let t=kt(e);vt.writeFileSync(v,JSON.stringify(t,null,2)+`
3
- `,{mode:384})}function $t(e){let t=un(e);if(!t)throw new Error("Invalid entry. Use +E164 (WhatsApp) or tg:<user_id> (Telegram).");let n=x();if(t.kind==="wa"){if(t.normalized==="*")throw new Error("Wildcards are not allowed.");let r=new Set(n.allowFrom);r.add(t.normalized),n.allowFrom=[...r].sort()}else{let r=new Set(n.telegramAllowFrom);r.add(t.id),n.telegramAllowFrom=[...r].sort()}return Ce(n),n}function Rt(e){let t=un(e);if(!t)throw new Error("Invalid entry. Use +E164 (WhatsApp) or tg:<user_id> (Telegram).");let n=x();return t.kind==="wa"?n.allowFrom=n.allowFrom.filter(r=>r!==t.normalized):n.telegramAllowFrom=n.telegramAllowFrom.filter(r=>me(r)!==t.id),Ce(n),n}function ae(e){let t=typeof process.env.TELEGRAM_BOT_TOKEN=="string"?process.env.TELEGRAM_BOT_TOKEN.trim():"";return t||(e.telegramBotToken??"").trim()}function Ge(e){let t=e.trim();return/^\d{6,}:[A-Za-z0-9_-]{20,}$/.test(t)}function ze(e){let t=x();return t.telegramBotToken=e.trim(),Ce(t),x()}function Mt(e){let t=e.trim().toLowerCase();return t==="whatsapp"||t==="wa"||t==="w"?"whatsapp":t==="telegram"||t==="tg"||t==="t"?"telegram":t==="both"||t==="all"||t==="b"?"both":null}function Ct(e){let t=x();return t.gatewayMode=e,Ce(t),x()}function Tt(e){let t=x();return t.clusterEnabled=e,Ce(t),x()}function Je(){try{return vt.readdirSync(q).length>0}catch{return!1}}import Di from"node:path";import $r from"node:fs";import Rr from"node:path";var qs=new Set(["jpg","jpeg","png","gif","webp","bmp","tif","tiff","heic","avif"]),Ys=new Set(["mp4","mov","webm","mkv","avi","m4v","3gp"]),Ks=new Set(["mp3","ogg","opus","wav","m4a","flac","aac","wma"]),It={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",bmp:"image/bmp",tif:"image/tiff",tiff:"image/tiff",heic:"image/heic",avif:"image/avif",mp4:"video/mp4",mov:"video/quicktime",webm:"video/webm",mkv:"video/x-matroska",avi:"video/x-msvideo",m4v:"video/x-m4v","3gp":"video/3gpp",mp3:"audio/mpeg",ogg:"audio/ogg",opus:"audio/opus",wav:"audio/wav",m4a:"audio/mp4",flac:"audio/flac",aac:"audio/aac",wma:"audio/x-ms-wma",pdf:"application/pdf",zip:"application/zip",gz:"application/gzip",txt:"text/plain",json:"application/json",xml:"application/xml",csv:"text/csv"};function Vs(e){let t=e.replace(/^\./,"").toLowerCase();return qs.has(t)?{category:"image",mimetype:It[t]??"image/jpeg"}:Ys.has(t)?{category:"video",mimetype:It[t]??"video/mp4"}:Ks.has(t)?{category:"audio",mimetype:It[t]??"audio/mpeg"}:{category:"document",mimetype:It[t]??"application/octet-stream"}}function qe(e,t){let n;try{n=$r.realpathSync(e)}catch{return{error:"File not found or unreadable."}}let r;try{r=$r.lstatSync(n)}catch{return{error:"Cannot stat file."}}if(!r.isFile())return{error:"Not a regular file (directories and special files are not supported)."};if(t>0&&r.size>t)return{error:`File too large (max ${t} bytes).`};let o=Rr.basename(n),s=Rr.extname(n).slice(1),{category:i,mimetype:a}=Vs(s);return{absPath:n,category:i,mimetype:a,displayName:o}}import Xs from"node:os";import Et from"node:path";import dn from"node:fs";import Cr from"node:os";import Te from"node:path";var Tr=Te.join(T,"sessions.json"),Ye=new Map;function Ir(){return{cwd:Te.resolve(Cr.homedir())}}function Qs(e){return e.startsWith("wa:")||e.startsWith("tg:")?e:`wa:${e}`}function Zs(){try{let e=dn.readFileSync(Tr,"utf8"),t=JSON.parse(e);for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o=Qs(n),i={cwd:typeof r.cwd=="string"&&r.cwd.length>0?Te.resolve(r.cwd):Ir().cwd};r.fileReceiveRoot==="sessionCwd"&&(i.fileReceiveRoot="sessionCwd"),Ye.set(o,i)}}catch{}}function Ar(){P(T);let e={};for(let[t,n]of Ye){let r={cwd:n.cwd};n.fileReceiveRoot==="sessionCwd"&&(r.fileReceiveRoot="sessionCwd"),e[t]=r}dn.writeFileSync(Tr,JSON.stringify(e,null,2)+`
4
- `,{mode:384})}var Mr=!1;function pn(){Mr||(Zs(),Mr=!0)}function z(e){pn();let t=Ye.get(e);return t||(t=Ir(),Ye.set(e,t)),t}function At(e,t){pn();let n=Te.resolve(t),r=z(e);r.cwd=n,Ye.set(e,r),Ar()}function Er(e){return z(e).fileReceiveRoot==="sessionCwd"?"sessionCwd":"default"}function mn(e,t){pn();let n=z(e);t==="default"?delete n.fileReceiveRoot:n.fileReceiveRoot="sessionCwd",Ye.set(e,n),Ar()}function Or(e){let t=e.trim();if(/[&|;\n]/.test(t)||!t.startsWith("cd"))return null;if(t==="cd")return{kind:"home"};if(t.length>2&&t[2]!==" "&&t[2]!==" ")return null;let n=t.slice(2).trimStart();return n?{kind:"path",value:n}:{kind:"home"}}function Lr(e,t){if(t.kind==="home")return Te.resolve(Cr.homedir());let n=t.value.replace(/^['"]|['"]$/g,"");return Te.isAbsolute(n)?Te.normalize(n):Te.resolve(e,n)}function Pr(e){try{return dn.statSync(e).isDirectory()?{ok:!0}:{ok:!1,error:`Not a directory: ${e}`}}catch(t){return{ok:!1,error:String(t)}}}var ei="Omnish";function Fr(){return Et.join(Xs.homedir(),"Downloads",ei)}function Ke(e,t){let n=z(t);if(n.fileReceiveRoot==="sessionCwd")return n.cwd;switch(e.fileReceiveRootMode){case"downloads":return Fr();case"omnishData":return Et.join(T,e.fileInboxSubdir);case"sessionCwd":return n.cwd;case"processCwd":return process.cwd();case"fixed":{let r=(e.fileReceiveRootPath??"").trim();if(!r)throw new Error('fileReceiveRootPath is required when fileReceiveRootMode is "fixed".');if(!Et.isAbsolute(r))throw new Error('fileReceiveRootPath must be an absolute path when fileReceiveRootMode is "fixed".');return Et.resolve(r)}default:return Fr()}}import ve from"node:fs";import _r from"node:path";import dt from"node:process";var Be="\x1B";function ti(e){return e.replace(/\u001B\[[\d;]*m/g,"")}function Ot(e){return ti(e).length}function fn(e,t,n,r,o=2){let s=Math.max(0,t-Ot(n));return`${e}${n}${" ".repeat(s)}${" ".repeat(o)}${r}`}function Ie(e,t,n,r){if(n.length===0)return[];let o=n.map(i=>r(i.left)),s=Math.max(...o.map(Ot));return n.map((i,a)=>fn(t,s,o[a],y(e,i.right)))}var Ae={primary:"#b4ff24",foreground:"#eef2f4",muted:"#8a9199",border:"#2a3139",error:"#ef4444",warn:"#a0e614",warnAlt:"#8cce04"};function ni(e){let t=e.replace(/^#/,"");return t.length!==6||!/^[0-9a-fA-F]+$/.test(t)?null:{r:parseInt(t.slice(0,2),16),g:parseInt(t.slice(2,4),16),b:parseInt(t.slice(4,6),16)}}function Ee(e){let t=ni(e);return t?`${Be}[38;2;${t.r};${t.g};${t.b}m`:""}function Lt(e){if(process.env.NO_COLOR!==void 0&&process.env.NO_COLOR!=="")return!1;let t=process.env.FORCE_COLOR;return t==="1"||t==="true"?!0:t==="0"||t==="false"?!1:e.isTTY===!0}function ke(e,t,n){return!t||!Lt(e)?n:`${t}${n}${Be}[0m`}function W(e,t){return ke(e,`${Be}[1m`,t)}function ri(e,t){return Lt(e)?`${Ee(Ae.foreground)}${Be}[1m${t}${Be}[0m`:t}function K(e,t){return ke(e,`${Be}[2m`,t)}function V(e,t){return ke(e,`${Ee(Ae.primary)}${Be}[1m`,t)}function N(e,t){return ke(e,Ee(Ae.primary),t)}function y(e,t){return ke(e,Ee(Ae.foreground),t)}function g(e,t){return ke(e,Ee(Ae.muted),t)}function oi(e,t){return ke(e,Ee(Ae.border),t)}function Pt(e,t){return ke(e,Ee(Ae.error),t)}function we(e,t){return ke(e,Ee(Ae.warn),t)}function Ve(e,t=60,n="\u2500"){let r=n.repeat(Math.max(1,t));return oi(e,r)}function Q(e,t){return Lt(e)?`${`${g(e,"[")}${N(e,"omnish")}${g(e,"]")}`} ${t}`:`[omnish] ${t}`}function k(e,t){return Lt(e)?`${`${Pt(e,"[omnish]")}`} ${t}`:`[omnish] ${t}`}function Br(e,t){let n=[];for(let r of e)switch(r.kind){case"title":n.push("",V(t,r.text),"");break;case"sub":n.push("",ri(t,r.text),"");break;case"gap":n.push("");break;case"p":n.push(y(t,r.text));break;case"bullet":n.push(`${g(t,"\u2022")} ${y(t,r.text)}`);break}return n.join(`
5
- `).replace(/^\n+/,"").trimEnd()}function Ft(e){return(e&4)!==0}function gn(e){return(e&2)!==0}var Nr={error:3,warn:2,info:1};function Hr(e,t){let n=Nr[t];return e.filter(r=>Nr[r.severity]>=n)}function Qe(e,t={}){let n=[],r=t.gatewayMode??e.gatewayMode,o=r==="whatsapp"||r==="both",s=r==="telegram"||r==="both";if(e.allowFrom.includes("*")&&n.push({severity:"error",code:"allow-wildcard",message:'allowFrom contains "*" \u2014 this must never be used; remove it from config immediately.',detail:`Edit ${v} and delete wildcard entries.`,fixHint:`Edit ${v} and remove any "*" entries from allowFrom.`}),o&&e.allowFrom.length===0&&n.push({severity:"warn",code:"allow-wa-empty",message:"allowFrom is empty \u2014 no WhatsApp identity can run commands.",detail:"Add your number: omnish allow +<E164>",fixHint:"omnish allow +<your_E164_number>"}),s&&e.telegramAllowFrom.length===0&&n.push({severity:"warn",code:"allow-tg-empty",message:"telegramAllowFrom is empty \u2014 no Telegram user can run commands.",detail:"Add your user id: omnish allow tg:<id>",fixHint:"omnish allow tg:<your_telegram_user_id>"}),e.recipesAllowDangerousBuiltins&&n.push({severity:"warn",code:"recipes-dangerous",message:"recipesAllowDangerousBuiltins is enabled \u2014 built-in recipe helpers may add permissive Claude Code flags.",fixHint:`Set recipesAllowDangerousBuiltins to false in ${v} unless you trust every recipe.`}),e.serviceInstallFromChat&&n.push({severity:"warn",code:"service-install-from-chat",message:"serviceInstallFromChat is enabled \u2014 allowlisted users can run /service install and write user-level systemd or LaunchAgent units.",fixHint:`Set serviceInstallFromChat to false in ${v} unless you trust every allowlisted identity.`}),!_r.isAbsolute(e.shell))n.push({severity:"warn",code:"shell-not-absolute",message:`Shell path is not absolute: ${e.shell}`,fixHint:`Set "shell" to an absolute path (e.g. /bin/bash) in ${v}.`});else try{ve.existsSync(e.shell)||n.push({severity:"error",code:"shell-missing",message:`Configured shell does not exist: ${e.shell}`,fixHint:`Install the shell or update "shell" in ${v} to a valid binary.`})}catch{n.push({severity:"warn",code:"shell-stat-failed",message:`Could not verify shell path: ${e.shell}`,fixHint:`Check permissions and that "shell" in ${v} points to a real file.`})}if(e.fileReceiveRootMode==="fixed"){let a=e.fileReceiveRootPath.trim();a?_r.isAbsolute(a)||n.push({severity:"error",code:"receive-fixed-not-absolute",message:`fileReceiveRootPath must be absolute when fileReceiveRootMode is "fixed": ${a}`,fixHint:`Use an absolute path for fileReceiveRootPath in ${v}.`}):n.push({severity:"error",code:"receive-fixed-empty",message:'fileReceiveRootMode is "fixed" but fileReceiveRootPath is empty.',fixHint:`Set fileReceiveRootPath to an absolute directory in ${v}, or change fileReceiveRootMode.`})}if(dt.platform!=="win32"){try{if(ve.existsSync(v)){let u=ve.statSync(v);(Ft(u.mode)||gn(u.mode))&&n.push({severity:"warn",code:"config-permissions",message:"config.json is accessible to users other than the owner (group/world).",detail:`Recommended: chmod 600 ${v}`,fixHint:`chmod 600 ${v}`})}}catch{}(typeof dt.getuid=="function"?dt.getuid():null)===0&&n.push({severity:"warn",code:"run-as-root",message:"Process is running as root \u2014 allowlisted remote access has full system privileges.",fixHint:"Run omnish as a non-root user (systemd user service, container user, etc.)."});let l=!1;try{if(ve.existsSync(T)){let u=ve.statSync(T);(Ft(u.mode)||gn(u.mode))&&(l=!0,n.push({severity:"warn",code:"data-dir-permissive",message:"Omnish data directory is accessible to group or other users \u2014 auth, jobs, and logs may be exposed.",detail:`Recommended: chmod 700 ${T}`,fixHint:`chmod 700 ${T}`}))}}catch{}try{if(!l&&ve.existsSync(ye)){let u=ve.statSync(ye);(Ft(u.mode)||gn(u.mode))&&n.push({severity:"warn",code:"jobs-dir-permissive",message:"Jobs log directory is accessible to group or other users \u2014 command output may leak.",detail:`Recommended: chmod 700 ${ye}`,fixHint:`chmod 700 ${ye}`})}}catch{}try{if(ve.existsSync(q)){let u=ve.statSync(q);Ft(u.mode)&&n.push({severity:"warn",code:"auth-dir-world-readable",message:"WhatsApp auth directory is readable by others \u2014 session material may be exposed.",detail:`Recommended: chmod 700 ${q}`,fixHint:`chmod 700 ${q}`})}}catch{}}return(typeof dt.env.TELEGRAM_BOT_TOKEN=="string"?dt.env.TELEGRAM_BOT_TOKEN.trim():"")&&n.push({severity:"info",code:"telegram-token-env",message:"TELEGRAM_BOT_TOKEN is set in the environment; it overrides config.json until unset.",fixHint:"Unset TELEGRAM_BOT_TOKEN in the shell/service env if you want config.json to apply."}),s&&!ae(e)&&n.push({severity:"error",code:"telegram-no-token",message:"Telegram is enabled for this gateway but no bot token is configured.",detail:"Set telegramBotToken in config or TELEGRAM_BOT_TOKEN.",fixHint:`Set telegramBotToken in ${v} or export TELEGRAM_BOT_TOKEN=<token>.`}),e.clusterEnabled&&s&&n.push({severity:"info",code:"cluster-telegram-tokens",message:"Cluster mode with Telegram: use a distinct BotFather bot/token per omnish host if several gateways run Telegram \u2014 the same token cannot be long-polled twice.",fixHint:"Create separate bots for each machine or run Telegram on fewer hosts."}),n}function yn(e){return e.some(t=>t.severity==="error")}function si(e,t){switch(t){case"error":return Pt(e,"[ERROR]");case"warn":return we(e,"[WARN]");case"info":return g(e,"[INFO]")}}function hn(e,t,n,r){if(r.length!==0){t.push(W(e,`${n} (${r.length}):`));for(let o of r)t.push(` ${si(e,o.severity)} ${g(e,`${o.code}:`)} ${y(e,o.message)}`),o.detail&&t.push(` ${g(e,o.detail)}`),o.fixHint&&t.push(` ${g(e,`Fix: ${o.fixHint}`)}`);t.push("")}}function Bt(e,t){if(e.length===0)return[`${V(t,"Security check:")} ${y(t,"no issues reported by automated rules.")}`,"",g(t,"Note: allowlisted remote shell access is still equivalent to sharing credentials with those identities.")].join(`
6
- `);let n=e.filter(a=>a.severity==="error"),r=e.filter(a=>a.severity==="warn"),o=e.filter(a=>a.severity==="info"),i=[`${V(t,"Security check:")} `+y(t,`${n.length} error(s), ${r.length} warning(s), ${o.length} note(s).`),""];return hn(t,i,"Errors",n),hn(t,i,"Warnings",r),hn(t,i,"Notes",o),i.push(g(t,"Allowlisted identities can run commands as this user; treat them like passwords.")),i.join(`
7
- `).trimEnd()}function wn(e){return{errors:e.filter(t=>t.severity==="error").length,warns:e.filter(t=>t.severity==="warn").length,infos:e.filter(t=>t.severity==="info").length}}function jr(e){return`${JSON.stringify({findings:e,summary:wn(e)},null,2)}
8
- `}function Wr(e,t){let n=e.filter(a=>a.severity==="error").length,r=e.filter(a=>a.severity==="warn").length,o=e.filter(a=>a.severity==="info").length;if(n===0&&r===0&&o===0)return"security: ok (no automated findings)";let s=[];n&&s.push(`${n} error(s)`),r&&s.push(`${r} warning(s)`),o&&s.push(`${o} note(s)`);let i=t??"run `omnish security` for details";return`security: ${s.join(", ")} \u2014 ${i}`}function Dr(e,t,n){let r=e.filter(l=>l.severity==="error").length,o=e.filter(l=>l.severity==="warn").length,s=e.filter(l=>l.severity==="info").length;if(r===0&&o===0&&s===0)return`${V(t,"security:")} ${y(t,"ok (no automated findings)")}`;let i=[];r&&i.push(Pt(t,`${r} error(s)`)),o&&i.push(we(t,`${o} warning(s)`)),s&&i.push(g(t,`${s} note(s)`));let a=n??"run `omnish security` for details";return`${V(t,"security:")} ${i.join(", ")} ${g(t,`\u2014 ${a}`)}`}function m(e){return{wa:e,tg:e}}function D(e,t){return{wa:e,tg:t,tgHtml:!0}}function _e(e,t){return t==="whatsapp"?{text:e.wa}:e.tgHtml?{text:e.tg,parseModeHtml:!0}:{text:e.tg}}function ne(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function $e(e){return e.replace(/[*_~`]/g,t=>({"*":"\u2217",_:"\uFF3F","~":"\u02DC","`":"\u2032"})[t]??t)}function ii(e){let t=[];for(let n of e)switch(n.kind){case"title":t.push("",`*${n.text}*`,"");break;case"sub":t.push("",`_${n.text}_`,"");break;case"gap":t.push("");break;case"p":t.push(n.text);break;case"bullet":t.push(`\u2022 ${n.text}`);break}return t.join(`
9
- `).replace(/^\n+/,"").trimEnd()}function ai(e){let t=[];for(let n of e)switch(n.kind){case"title":t.push("",`<b>${ne(n.text)}</b>`,"");break;case"sub":t.push("",`<i>${ne(n.text)}</i>`,"");break;case"gap":t.push("");break;case"p":t.push(ne(n.text));break;case"bullet":t.push(`\u2022 ${ne(n.text)}`);break}return t.join(`
10
- `).replace(/^\n+/,"").trimEnd()}function E(e){return{wa:ii(e),tg:ai(e),tgHtml:!0}}function Ze(e){return[{kind:"title",text:"Omnish \u2014 quick help"},{kind:"p",text:"Per-chat shell cwd is stored under your data dir (see /wa help)."},{kind:"gap"},{kind:"sub",text:"Run commands"},{kind:"bullet",text:`${e.commandPrefix}<command> \u2014 sync shell in session cwd (timeout ${e.syncTimeoutMs} ms)`},{kind:"bullet",text:`${e.commandPrefix}cd <dir> \u2014 change session cwd (${e.commandPrefix}cd alone \u2192 home)`},{kind:"bullet",text:"!!start | !!stop \u2014 free shell mode (plain text = shell); space optional"},{kind:"bullet",text:"/bg <cmd> \u2014 background job; /jobs, /log, /tail, /kill"},{kind:"bullet",text:"/apps \u2026 \u2014 interactive app sessions (/apps help)"},{kind:"bullet",text:"/send path \u2014 host file \u2192 chat (/file); caption: path -- note"},{kind:"bullet",text:"/files \u2014 full help for /send and saving inbound media"},{kind:"bullet",text:"/receive \u2014 set this chat\u2019s inbound folder (e.g. session cwd)"},{kind:"bullet",text:"/computers \xB7 /pcs \xB7 /c \u2014 chat-driven cluster (/c here to take over, /c help)"},{kind:"bullet",text:"/config \u2014 view or change server settings (/config help, /config keys)"},{kind:"bullet",text:"/service \u2014 background service status, install hints, logs (/service help)"},{kind:"bullet",text:"/shortcut \u2014 per-chat saved commands (/shortcut help); invoke with bare !name or /name"},{kind:"bullet",text:"/run \u2014 parameterized CLI templates with a task (/run list); shorthand /r"},{kind:"gap"},{kind:"sub",text:"Setup & gateway"},{kind:"bullet",text:"/wa help \u2014 WhatsApp link, allowlist"},{kind:"bullet",text:"/tg help \u2014 Telegram; /tg token <paste>"},{kind:"bullet",text:"/reload | /restart \u2014 apply config"},{kind:"bullet",text:"/security \u2014 posture report; /security summary; /security tips; /security help"},{kind:"bullet",text:"/gateway | /gw | /mode \u2014 show or set gatewayMode"},{kind:"bullet",text:"/allow +E164 | /allow tg:id \u2014 allowlist; /deny \u2026; /allowlist"},{kind:"bullet",text:"/help \u2014 this message"}]}function Ur(e){let t=e.serviceInstallFromChat?[{kind:"bullet",text:"/service install \u2014 user-level systemd (Linux) or LaunchAgent (macOS)"},{kind:"bullet",text:"/service uninstall \u2014 remove that unit"}]:[{kind:"bullet",text:"/service install / uninstall \u2014 off by default. Enable: /config set serviceInstallFromChat true (same trust as shell)"}];return[{kind:"title",text:"Service and boot"},{kind:"p",text:"Inspect the gateway, get OS-specific install steps, or (if enabled) write the user service from chat. Same from the host terminal: omnish service help."},{kind:"bullet",text:"/service status \u2014 platform, data dir, pidfile, node + entry script"},{kind:"bullet",text:"/service instructions \u2014 copy-paste commands for this machine"},{kind:"bullet",text:"/service logs [n] \u2014 tail default gateway log (default 80 lines)"},...t,{kind:"gap"},{kind:"p",text:"See https://omnish.dev and docs/guides/background-and-boot.md."}]}function Gr(){return[{kind:"title",text:"Chat config"},{kind:"p",text:`Same trust as shell \u2014 allowlisted senders can change many keys saved to ${v}.`},{kind:"gap"},{kind:"bullet",text:"/config show \u2014 full snapshot (telegramBotToken masked)"},{kind:"bullet",text:"/config get <key> \u2014 single field"},{kind:"bullet",text:"/config set <key> <value> \u2014 values can be quoted for paths with spaces"},{kind:"bullet",text:"/config keys \u2014 comma-separated whitelist of keys"},{kind:"gap"},{kind:"p",text:"After edits: /reload while omnish run is active (needed for gatewayMode and telegramBotToken)."}]}function bn(){return[{kind:"title",text:"Gateway mode"},{kind:"p",text:"Which transports omnish uses:"},{kind:"bullet",text:"whatsapp (wa, w) \u2014 WhatsApp DMs only"},{kind:"bullet",text:"telegram (tg, t) \u2014 Telegram bot only"},{kind:"bullet",text:"both (all, b) \u2014 WhatsApp + Telegram"},{kind:"gap"},{kind:"sub",text:"Commands"},{kind:"bullet",text:"/gateway \u2014 current mode + hints"},{kind:"bullet",text:"/gateway telegram \u2014 save (auto-reloads Telegram if gateway is up)"},{kind:"bullet",text:"/gw both \u2014 short form; /mode wa \u2014 same"},{kind:"gap"},{kind:"p",text:`Config: ${v}`}]}function zr(e){let t=["*Gateway status*","",`Mode: *${e.gatewayMode}*`," \u2022 whatsapp \u2014 WhatsApp only"," \u2022 telegram \u2014 Telegram only"," \u2022 both \u2014 both channels","",`WhatsApp auth: ${e.authPresent?"present":"missing (omnish link)"}`,`Telegram token: ${e.tokenSet?"set":"not set"}`,`Allowlists: ${e.allowN} WA \xB7 ${e.tgAllowN} Telegram`,"","Change: /gateway both \xB7 /gw tg",`Config: ${$e(v)}`],n=["<b>Gateway status</b>","",`<b>${ne(e.gatewayMode)}</b> <i>current mode</i>`,"\u2022 whatsapp \u2014 WhatsApp only","\u2022 telegram \u2014 Telegram only","\u2022 both \u2014 both channels","",`${e.authPresent?"\u2713":"\u26A0"} WhatsApp auth: ${e.authPresent?"present":"missing \u2014 run omnish link"}`,`${e.tokenSet?"\u2713":"\u26A0"} Telegram token: ${e.tokenSet?"set":"not set"}`,`Allowlists: ${e.allowN} WA \xB7 ${e.tgAllowN} Telegram`,"","<i>Change:</i> /gateway both \xB7 /gw tg",ne(`Config: ${v}`)];return D(t.join(`
2
+ import Bc from"node:dns";import{spawn as Dc,spawnSync as Hc}from"node:child_process";import ge from"node:fs";import En from"node:path";import Pi from"node:os";import jt from"node:fs";import Di from"node:crypto";import On from"node:fs";import Hi from"node:os";import q from"node:path";function ji(){let e=process.env.OMNISH_HOME?.trim();if(e)return q.resolve(e);let t=Hi.homedir(),n=q.join(t,".omnish"),r=q.join(t,".whatslive");try{if(On.existsSync(n))return n;if(On.existsSync(r))return r}catch{}return n}var A=ji(),ee=q.join(A,"auth"),ke=q.join(A,"jobs"),Gr=q.join(A,"apps"),zr=q.join(A,"logs"),we=q.join(zr,"gateway.log"),te=q.join(A,"gateway.pid"),Ve=q.join(A,"gateway-control.json"),T=q.join(A,"config.json"),Nt=q.join(A,"shortcuts.json"),_t=q.join(A,"recipes.json"),Bt=q.join(A,"recipes-user.json"),Ce=q.join(A,"cowork"),Ln=q.join(Ce,"tasks.json"),Pn=q.join(Ce,"pending-runs.json"),Jr=q.join(Ce,"completions.sqlite");function wt(e){let t=Di.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return q.join(Gr,t)}function L(e){On.mkdirSync(e,{recursive:!0,mode:448})}function Q(){L(A),L(ee),L(ke),L(Gr),L(zr),L(Ce)}var qr=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,Yr=/^(\d+)@c\.us$/i,Vr=/^(\d+)@lid$/i;function Xr(e){let t=e.trim();for(;;){let n=t;if(t=t.replace(/^whatsapp:/i,"").trim(),t===n)return t}}function Wi(e){let t=Xr(e);if(!t.toLowerCase().endsWith("@g.us"))return!1;let r=t.slice(0,t.length-5);return!r||r.includes("@")?!1:/^[0-9]+(-[0-9]+)*$/.test(r)}function Ui(e){let t=e.match(qr);if(t)return t[1]??null;let n=e.match(Yr);if(n)return n[1]??null;let r=e.match(Vr);return r?r[1]??null:null}function Kr(e){let t=e.replace(/\D/g,"");return t?`+${t}`:""}function Dt(e){return`${e.replace(/\D/g,"")}@s.whatsapp.net`}function _(e){let t=Xr(e);if(!t||Wi(t))return null;if(qr.test(t)||Yr.test(t)||Vr.test(t)){let r=Ui(t);if(!r)return null;let o=Kr(r);return o.length>1?o:null}if(t.includes("@"))return null;let n=Kr(t);return n.length>1?n:null}function Qr(e){return e.map(t=>String(t).trim()).filter(t=>!!t).map(t=>t==="*"?t:_(t)).filter(t=>!!t)}function Zr(e){let t=new Set;for(let n of e)n!=="*"&&t.add(n);return t}function de(e){let t=e.trim();for(;;){let n=t.toLowerCase();if(n.startsWith("tg:")){t=t.slice(3).trimStart();continue}if(n.startsWith("telegram:")){t=t.slice(9).trimStart();continue}break}return/^\d+$/.test(t)?t:null}function eo(e){let t=new Set;for(let n of e){let r=de(String(n));r&&t.add(r)}return t}function Fn(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let o=de(t);return o?{kind:"tg",id:o}:null}let r=_(t);return r?{kind:"wa",normalized:r}:null}var I={gatewayMode:"whatsapp",telegramBotToken:"",telegramAllowFrom:[],allowFrom:[],commandPrefix:"!",syncTimeoutMs:3e4,syncMaxBytes:32768,jobLogTailLines:80,shell:"/bin/bash",appsCols:120,appsRows:40,appsFlushMs:300,appsMinIntervalMs:800,appsMaxFlushBytes:8192,appsMaxSessions:5,appsMaxSessionsTotal:20,appsMaxWaChars:3500,appsLogTailLines:80,appsSubmitDelayMs:50,appsClearInput:!0,appsClearInputDelayMs:20,appsClearInputSequence:"^A,^K",fileSendMaxBytes:0,fileReceiveMaxBytes:0,fileInboxSubdir:"inbox",fileReceiveRootMode:"downloads",fileReceiveRootPath:"",recipesAllowDangerousBuiltins:!1,recipesMaxTaskChars:0,clusterEnabled:!1,clusterLabel:"",clusterRole:"secondary",clusterSenderBindings:{},serviceInstallFromChat:!1,updateCheckEnabled:!1,updateCheckIntervalMs:864e5,updateCheckPackageName:"omnish",updateInfoUrl:""};function Gi(e){return e==="downloads"||e==="omnishData"||e==="sessionCwd"||e==="processCwd"||e==="fixed"?e:I.fileReceiveRootMode}function zi(e){return e==="primary"?"primary":"secondary"}function Ji(e){if(!e||typeof e!="object")return{};let t={};for(let[n,r]of Object.entries(e)){if(typeof r!="string")continue;let o=r.trim();if(!o)continue;let s=n.trim(),i=s.toLowerCase();if(i.startsWith("wa:")){let l=_(s.slice(3));l&&(t[`wa:${l}`]=o.slice(0,64));continue}if(i.startsWith("tg:")||i.startsWith("telegram:")){let l=de(s);l&&(t[`tg:${l}`]=o.slice(0,64));continue}let a=_(s);a&&(t[`wa:${a}`]=o.slice(0,64))}return t}function Ht(e){let t=typeof e.appsFlushMs=="number"&&e.appsFlushMs>=0?e.appsFlushMs:I.appsFlushMs,n=e.gatewayMode==="telegram"||e.gatewayMode==="both"||e.gatewayMode==="whatsapp"?e.gatewayMode:I.gatewayMode,r=typeof e.telegramBotToken=="string"?e.telegramBotToken:I.telegramBotToken,o=Array.isArray(e.telegramAllowFrom)?[...new Set(e.telegramAllowFrom.map(s=>de(String(s))).filter(s=>!!s))].sort():I.telegramAllowFrom;return{...I,...e,gatewayMode:n,telegramBotToken:r,telegramAllowFrom:o,allowFrom:Array.isArray(e.allowFrom)?Qr(e.allowFrom.map(String)).filter(s=>s!=="*"):I.allowFrom,commandPrefix:(()=>{let s=typeof e.commandPrefix=="string"&&e.commandPrefix.length>0?e.commandPrefix:I.commandPrefix;return s==="! "?"!":s})(),syncTimeoutMs:typeof e.syncTimeoutMs=="number"&&e.syncTimeoutMs>0?e.syncTimeoutMs:I.syncTimeoutMs,syncMaxBytes:typeof e.syncMaxBytes=="number"&&e.syncMaxBytes>0?e.syncMaxBytes:I.syncMaxBytes,jobLogTailLines:typeof e.jobLogTailLines=="number"&&e.jobLogTailLines>0?e.jobLogTailLines:I.jobLogTailLines,shell:typeof e.shell=="string"&&e.shell.length>0?e.shell:I.shell,appsCols:typeof e.appsCols=="number"&&e.appsCols>0&&e.appsCols<=500?Math.floor(e.appsCols):I.appsCols,appsRows:typeof e.appsRows=="number"&&e.appsRows>0&&e.appsRows<=200?Math.floor(e.appsRows):I.appsRows,appsFlushMs:t,appsMinIntervalMs:typeof e.appsMinIntervalMs=="number"&&e.appsMinIntervalMs>=0?e.appsMinIntervalMs:I.appsMinIntervalMs,appsMaxFlushBytes:typeof e.appsMaxFlushBytes=="number"&&e.appsMaxFlushBytes>256?Math.floor(e.appsMaxFlushBytes):I.appsMaxFlushBytes,appsMaxSessions:typeof e.appsMaxSessions=="number"&&e.appsMaxSessions>0?Math.min(50,Math.floor(e.appsMaxSessions)):I.appsMaxSessions,appsMaxSessionsTotal:typeof e.appsMaxSessionsTotal=="number"&&e.appsMaxSessionsTotal>0?Math.min(200,Math.floor(e.appsMaxSessionsTotal)):I.appsMaxSessionsTotal,appsMaxWaChars:typeof e.appsMaxWaChars=="number"&&e.appsMaxWaChars>256?Math.floor(e.appsMaxWaChars):I.appsMaxWaChars,appsLogTailLines:typeof e.appsLogTailLines=="number"&&e.appsLogTailLines>0?Math.min(500,Math.floor(e.appsLogTailLines)):I.appsLogTailLines,appsSubmitDelayMs:typeof e.appsSubmitDelayMs=="number"&&e.appsSubmitDelayMs>=0?Math.min(500,Math.floor(e.appsSubmitDelayMs)):I.appsSubmitDelayMs,appsClearInput:typeof e.appsClearInput=="boolean"?e.appsClearInput:I.appsClearInput,appsClearInputDelayMs:typeof e.appsClearInputDelayMs=="number"&&e.appsClearInputDelayMs>=0?Math.min(200,Math.floor(e.appsClearInputDelayMs)):I.appsClearInputDelayMs,appsClearInputSequence:typeof e.appsClearInputSequence=="string"&&e.appsClearInputSequence.length>0?e.appsClearInputSequence.slice(0,200):I.appsClearInputSequence,fileSendMaxBytes:typeof e.fileSendMaxBytes=="number"&&e.fileSendMaxBytes>=0?e.fileSendMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileSendMaxBytes)):I.fileSendMaxBytes,fileReceiveMaxBytes:typeof e.fileReceiveMaxBytes=="number"&&e.fileReceiveMaxBytes>=0?e.fileReceiveMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileReceiveMaxBytes)):I.fileReceiveMaxBytes,fileInboxSubdir:typeof e.fileInboxSubdir=="string"&&e.fileInboxSubdir.length>0&&e.fileInboxSubdir.replace(/[/\\]/g,"").slice(0,80)||I.fileInboxSubdir,fileReceiveRootMode:Gi(e.fileReceiveRootMode),fileReceiveRootPath:typeof e.fileReceiveRootPath=="string"?e.fileReceiveRootPath.trim().slice(0,4096):I.fileReceiveRootPath,recipesAllowDangerousBuiltins:typeof e.recipesAllowDangerousBuiltins=="boolean"?e.recipesAllowDangerousBuiltins:I.recipesAllowDangerousBuiltins,recipesMaxTaskChars:typeof e.recipesMaxTaskChars=="number"&&e.recipesMaxTaskChars>=0?e.recipesMaxTaskChars===0?0:Math.min(Number.MAX_SAFE_INTEGER,Math.floor(e.recipesMaxTaskChars)):I.recipesMaxTaskChars,clusterEnabled:typeof e.clusterEnabled=="boolean"?e.clusterEnabled:I.clusterEnabled,clusterLabel:typeof e.clusterLabel=="string"?e.clusterLabel.trim().slice(0,128):I.clusterLabel,clusterRole:zi(e.clusterRole),clusterSenderBindings:Ji(e.clusterSenderBindings),serviceInstallFromChat:typeof e.serviceInstallFromChat=="boolean"?e.serviceInstallFromChat:I.serviceInstallFromChat,updateCheckEnabled:typeof e.updateCheckEnabled=="boolean"?e.updateCheckEnabled:I.updateCheckEnabled,updateCheckIntervalMs:typeof e.updateCheckIntervalMs=="number"&&e.updateCheckIntervalMs>0?Math.min(6048e5,Math.max(36e5,Math.floor(e.updateCheckIntervalMs))):I.updateCheckIntervalMs,updateCheckPackageName:typeof e.updateCheckPackageName=="string"&&e.updateCheckPackageName.trim().length>0?e.updateCheckPackageName.trim().slice(0,214):I.updateCheckPackageName,updateInfoUrl:typeof e.updateInfoUrl=="string"?e.updateInfoUrl.trim().slice(0,2048):I.updateInfoUrl}}function $(){if(Q(),!jt.existsSync(T)){let e=Ht({});return Le(e),e}try{let e=jt.readFileSync(T,"utf8"),t=JSON.parse(e);return Ht(t)}catch{return Ht({})}}function Le(e){Q();let t=Ht(e);jt.writeFileSync(T,JSON.stringify(t,null,2)+`
3
+ `,{mode:384})}function Wt(e){let t=Fn(e);if(!t)throw new Error("Invalid entry. Use +E164 (WhatsApp) or tg:<user_id> (Telegram).");let n=$();if(t.kind==="wa"){if(t.normalized==="*")throw new Error("Wildcards are not allowed.");let r=new Set(n.allowFrom);r.add(t.normalized),n.allowFrom=[...r].sort()}else{let r=new Set(n.telegramAllowFrom);r.add(t.id),n.telegramAllowFrom=[...r].sort()}return Le(n),n}function Ut(e){let t=Fn(e);if(!t)throw new Error("Invalid entry. Use +E164 (WhatsApp) or tg:<user_id> (Telegram).");let n=$();return t.kind==="wa"?n.allowFrom=n.allowFrom.filter(r=>r!==t.normalized):n.telegramAllowFrom=n.telegramAllowFrom.filter(r=>de(r)!==t.id),Le(n),n}function pe(e){let t=typeof process.env.TELEGRAM_BOT_TOKEN=="string"?process.env.TELEGRAM_BOT_TOKEN.trim():"";return t||(e.telegramBotToken??"").trim()}function Xe(e){let t=e.trim();return/^\d{6,}:[A-Za-z0-9_-]{20,}$/.test(t)}function Qe(e){let t=$();return t.telegramBotToken=e.trim(),Le(t),$()}function Gt(e){let t=e.trim().toLowerCase();return t==="whatsapp"||t==="wa"||t==="w"?"whatsapp":t==="telegram"||t==="tg"||t==="t"?"telegram":t==="both"||t==="all"||t==="b"?"both":null}function zt(e){let t=$();return t.gatewayMode=e,Le(t),$()}function Jt(e){let t=$();return t.clusterEnabled=e,Le(t),$()}function Ze(){try{return jt.readdirSync(ee).length>0}catch{return!1}}import pl from"node:path";import to from"node:fs";import no from"node:path";var Ki=new Set(["jpg","jpeg","png","gif","webp","bmp","tif","tiff","heic","avif"]),qi=new Set(["mp4","mov","webm","mkv","avi","m4v","3gp"]),Yi=new Set(["mp3","ogg","opus","wav","m4a","flac","aac","wma"]),Kt={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",bmp:"image/bmp",tif:"image/tiff",tiff:"image/tiff",heic:"image/heic",avif:"image/avif",mp4:"video/mp4",mov:"video/quicktime",webm:"video/webm",mkv:"video/x-matroska",avi:"video/x-msvideo",m4v:"video/x-m4v","3gp":"video/3gpp",mp3:"audio/mpeg",ogg:"audio/ogg",opus:"audio/opus",wav:"audio/wav",m4a:"audio/mp4",flac:"audio/flac",aac:"audio/aac",wma:"audio/x-ms-wma",pdf:"application/pdf",zip:"application/zip",gz:"application/gzip",txt:"text/plain",json:"application/json",xml:"application/xml",csv:"text/csv"};function Vi(e){let t=e.replace(/^\./,"").toLowerCase();return Ki.has(t)?{category:"image",mimetype:Kt[t]??"image/jpeg"}:qi.has(t)?{category:"video",mimetype:Kt[t]??"video/mp4"}:Yi.has(t)?{category:"audio",mimetype:Kt[t]??"audio/mpeg"}:{category:"document",mimetype:Kt[t]??"application/octet-stream"}}function et(e,t){let n;try{n=to.realpathSync(e)}catch{return{error:"File not found or unreadable."}}let r;try{r=to.lstatSync(n)}catch{return{error:"Cannot stat file."}}if(!r.isFile())return{error:"Not a regular file (directories and special files are not supported)."};if(t>0&&r.size>t)return{error:`File too large (max ${t} bytes).`};let o=no.basename(n),s=no.extname(n).slice(1),{category:i,mimetype:a}=Vi(s);return{absPath:n,category:i,mimetype:a,displayName:o}}import Zi from"node:os";import Yt from"node:path";import Nn from"node:fs";import oo from"node:os";import Pe from"node:path";var so=Pe.join(A,"sessions.json"),tt=new Map;function io(){return{cwd:Pe.resolve(oo.homedir())}}function Xi(e){return e.startsWith("wa:")||e.startsWith("tg:")?e:`wa:${e}`}function Qi(){try{let e=Nn.readFileSync(so,"utf8"),t=JSON.parse(e);for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o=Xi(n),i={cwd:typeof r.cwd=="string"&&r.cwd.length>0?Pe.resolve(r.cwd):io().cwd};r.fileReceiveRoot==="sessionCwd"&&(i.fileReceiveRoot="sessionCwd"),tt.set(o,i)}}catch{}}function ao(){L(A);let e={};for(let[t,n]of tt){let r={cwd:n.cwd};n.fileReceiveRoot==="sessionCwd"&&(r.fileReceiveRoot="sessionCwd"),e[t]=r}Nn.writeFileSync(so,JSON.stringify(e,null,2)+`
4
+ `,{mode:384})}var ro=!1;function _n(){ro||(Qi(),ro=!0)}function H(e){_n();let t=tt.get(e);return t||(t=io(),tt.set(e,t)),t}function qt(e,t){_n();let n=Pe.resolve(t),r=H(e);r.cwd=n,tt.set(e,r),ao()}function lo(e){return H(e).fileReceiveRoot==="sessionCwd"?"sessionCwd":"default"}function Bn(e,t){_n();let n=H(e);t==="default"?delete n.fileReceiveRoot:n.fileReceiveRoot="sessionCwd",tt.set(e,n),ao()}function co(e){let t=e.trim();if(/[&|;\n]/.test(t)||!t.startsWith("cd"))return null;if(t==="cd")return{kind:"home"};if(t.length>2&&t[2]!==" "&&t[2]!==" ")return null;let n=t.slice(2).trimStart();return n?{kind:"path",value:n}:{kind:"home"}}function uo(e,t){if(t.kind==="home")return Pe.resolve(oo.homedir());let n=t.value.replace(/^['"]|['"]$/g,"");return Pe.isAbsolute(n)?Pe.normalize(n):Pe.resolve(e,n)}function po(e){try{return Nn.statSync(e).isDirectory()?{ok:!0}:{ok:!1,error:`Not a directory: ${e}`}}catch(t){return{ok:!1,error:String(t)}}}var ea="Omnish";function mo(){return Yt.join(Zi.homedir(),"Downloads",ea)}function nt(e,t){let n=H(t);if(n.fileReceiveRoot==="sessionCwd")return n.cwd;switch(e.fileReceiveRootMode){case"downloads":return mo();case"omnishData":return Yt.join(A,e.fileInboxSubdir);case"sessionCwd":return n.cwd;case"processCwd":return process.cwd();case"fixed":{let r=(e.fileReceiveRootPath??"").trim();if(!r)throw new Error('fileReceiveRootPath is required when fileReceiveRootMode is "fixed".');if(!Yt.isAbsolute(r))throw new Error('fileReceiveRootPath must be an absolute path when fileReceiveRootMode is "fixed".');return Yt.resolve(r)}default:return mo()}}import Ie from"node:fs";import go from"node:path";import bt from"node:process";var Ue="\x1B";function ta(e){return e.replace(/\u001B\[[\d;]*m/g,"")}function Vt(e){return ta(e).length}function Dn(e,t,n,r,o=2){let s=Math.max(0,t-Vt(n));return`${e}${n}${" ".repeat(s)}${" ".repeat(o)}${r}`}function Fe(e,t,n,r){if(n.length===0)return[];let o=n.map(i=>r(i.left)),s=Math.max(...o.map(Vt));return n.map((i,a)=>Dn(t,s,o[a],b(e,i.right)))}var Ne={primary:"#b4ff24",foreground:"#eef2f4",muted:"#8a9199",border:"#2a3139",error:"#ef4444",warn:"#a0e614",warnAlt:"#8cce04"};function na(e){let t=e.replace(/^#/,"");return t.length!==6||!/^[0-9a-fA-F]+$/.test(t)?null:{r:parseInt(t.slice(0,2),16),g:parseInt(t.slice(2,4),16),b:parseInt(t.slice(4,6),16)}}function _e(e){let t=na(e);return t?`${Ue}[38;2;${t.r};${t.g};${t.b}m`:""}function Xt(e){if(process.env.NO_COLOR!==void 0&&process.env.NO_COLOR!=="")return!1;let t=process.env.FORCE_COLOR;return t==="1"||t==="true"?!0:t==="0"||t==="false"?!1:e.isTTY===!0}function Te(e,t,n){return!t||!Xt(e)?n:`${t}${n}${Ue}[0m`}function Y(e,t){return Te(e,`${Ue}[1m`,t)}function ra(e,t){return Xt(e)?`${_e(Ne.foreground)}${Ue}[1m${t}${Ue}[0m`:t}function re(e,t){return Te(e,`${Ue}[2m`,t)}function oe(e,t){return Te(e,`${_e(Ne.primary)}${Ue}[1m`,t)}function U(e,t){return Te(e,_e(Ne.primary),t)}function b(e,t){return Te(e,_e(Ne.foreground),t)}function h(e,t){return Te(e,_e(Ne.muted),t)}function oa(e,t){return Te(e,_e(Ne.border),t)}function Qt(e,t){return Te(e,_e(Ne.error),t)}function Se(e,t){return Te(e,_e(Ne.warn),t)}function Ge(e,t=60,n="\u2500"){let r=n.repeat(Math.max(1,t));return oa(e,r)}function se(e,t){return Xt(e)?`${`${h(e,"[")}${U(e,"omnish")}${h(e,"]")}`} ${t}`:`[omnish] ${t}`}function R(e,t){return Xt(e)?`${`${Qt(e,"[omnish]")}`} ${t}`:`[omnish] ${t}`}function fo(e,t){let n=[];for(let r of e)switch(r.kind){case"title":n.push("",oe(t,r.text),"");break;case"sub":n.push("",ra(t,r.text),"");break;case"gap":n.push("");break;case"p":n.push(b(t,r.text));break;case"bullet":n.push(`${h(t,"\u2022")} ${b(t,r.text)}`);break}return n.join(`
5
+ `).replace(/^\n+/,"").trimEnd()}function Zt(e){return(e&4)!==0}function Hn(e){return(e&2)!==0}var ho={error:3,warn:2,info:1};function yo(e,t){let n=ho[t];return e.filter(r=>ho[r.severity]>=n)}function rt(e,t={}){let n=[],r=t.gatewayMode??e.gatewayMode,o=r==="whatsapp"||r==="both",s=r==="telegram"||r==="both";if(e.allowFrom.includes("*")&&n.push({severity:"error",code:"allow-wildcard",message:'allowFrom contains "*" \u2014 this must never be used; remove it from config immediately.',detail:`Edit ${T} and delete wildcard entries.`,fixHint:`Edit ${T} and remove any "*" entries from allowFrom.`}),o&&e.allowFrom.length===0&&n.push({severity:"warn",code:"allow-wa-empty",message:"allowFrom is empty \u2014 no WhatsApp identity can run commands.",detail:"Add your number: omnish allow +<E164>",fixHint:"omnish allow +<your_E164_number>"}),s&&e.telegramAllowFrom.length===0&&n.push({severity:"warn",code:"allow-tg-empty",message:"telegramAllowFrom is empty \u2014 no Telegram user can run commands.",detail:"Add your user id: omnish allow tg:<id>",fixHint:"omnish allow tg:<your_telegram_user_id>"}),e.recipesAllowDangerousBuiltins&&n.push({severity:"warn",code:"recipes-dangerous",message:"recipesAllowDangerousBuiltins is enabled \u2014 built-in recipe helpers may add permissive Claude Code flags.",fixHint:`Set recipesAllowDangerousBuiltins to false in ${T} unless you trust every recipe.`}),e.serviceInstallFromChat&&n.push({severity:"warn",code:"service-install-from-chat",message:"serviceInstallFromChat is enabled \u2014 allowlisted users can run /service install and write user-level systemd or LaunchAgent units.",fixHint:`Set serviceInstallFromChat to false in ${T} unless you trust every allowlisted identity.`}),!go.isAbsolute(e.shell))n.push({severity:"warn",code:"shell-not-absolute",message:`Shell path is not absolute: ${e.shell}`,fixHint:`Set "shell" to an absolute path (e.g. /bin/bash) in ${T}.`});else try{Ie.existsSync(e.shell)||n.push({severity:"error",code:"shell-missing",message:`Configured shell does not exist: ${e.shell}`,fixHint:`Install the shell or update "shell" in ${T} to a valid binary.`})}catch{n.push({severity:"warn",code:"shell-stat-failed",message:`Could not verify shell path: ${e.shell}`,fixHint:`Check permissions and that "shell" in ${T} points to a real file.`})}if(e.fileReceiveRootMode==="fixed"){let a=e.fileReceiveRootPath.trim();a?go.isAbsolute(a)||n.push({severity:"error",code:"receive-fixed-not-absolute",message:`fileReceiveRootPath must be absolute when fileReceiveRootMode is "fixed": ${a}`,fixHint:`Use an absolute path for fileReceiveRootPath in ${T}.`}):n.push({severity:"error",code:"receive-fixed-empty",message:'fileReceiveRootMode is "fixed" but fileReceiveRootPath is empty.',fixHint:`Set fileReceiveRootPath to an absolute directory in ${T}, or change fileReceiveRootMode.`})}if(bt.platform!=="win32"){try{if(Ie.existsSync(T)){let d=Ie.statSync(T);(Zt(d.mode)||Hn(d.mode))&&n.push({severity:"warn",code:"config-permissions",message:"config.json is accessible to users other than the owner (group/world).",detail:`Recommended: chmod 600 ${T}`,fixHint:`chmod 600 ${T}`})}}catch{}(typeof bt.getuid=="function"?bt.getuid():null)===0&&n.push({severity:"warn",code:"run-as-root",message:"Process is running as root \u2014 allowlisted remote access has full system privileges.",fixHint:"Run omnish as a non-root user (systemd user service, container user, etc.)."});let l=!1;try{if(Ie.existsSync(A)){let d=Ie.statSync(A);(Zt(d.mode)||Hn(d.mode))&&(l=!0,n.push({severity:"warn",code:"data-dir-permissive",message:"Omnish data directory is accessible to group or other users \u2014 auth, jobs, and logs may be exposed.",detail:`Recommended: chmod 700 ${A}`,fixHint:`chmod 700 ${A}`}))}}catch{}try{if(!l&&Ie.existsSync(ke)){let d=Ie.statSync(ke);(Zt(d.mode)||Hn(d.mode))&&n.push({severity:"warn",code:"jobs-dir-permissive",message:"Jobs log directory is accessible to group or other users \u2014 command output may leak.",detail:`Recommended: chmod 700 ${ke}`,fixHint:`chmod 700 ${ke}`})}}catch{}try{if(Ie.existsSync(ee)){let d=Ie.statSync(ee);Zt(d.mode)&&n.push({severity:"warn",code:"auth-dir-world-readable",message:"WhatsApp auth directory is readable by others \u2014 session material may be exposed.",detail:`Recommended: chmod 700 ${ee}`,fixHint:`chmod 700 ${ee}`})}}catch{}}return(typeof bt.env.TELEGRAM_BOT_TOKEN=="string"?bt.env.TELEGRAM_BOT_TOKEN.trim():"")&&n.push({severity:"info",code:"telegram-token-env",message:"TELEGRAM_BOT_TOKEN is set in the environment; it overrides config.json until unset.",fixHint:"Unset TELEGRAM_BOT_TOKEN in the shell/service env if you want config.json to apply."}),s&&!pe(e)&&n.push({severity:"error",code:"telegram-no-token",message:"Telegram is enabled for this gateway but no bot token is configured.",detail:"Set telegramBotToken in config or TELEGRAM_BOT_TOKEN.",fixHint:`Set telegramBotToken in ${T} or export TELEGRAM_BOT_TOKEN=<token>.`}),e.clusterEnabled&&s&&n.push({severity:"info",code:"cluster-telegram-tokens",message:"Cluster mode with Telegram: use a distinct BotFather bot/token per omnish host if several gateways run Telegram \u2014 the same token cannot be long-polled twice.",fixHint:"Create separate bots for each machine or run Telegram on fewer hosts."}),n}function Wn(e){return e.some(t=>t.severity==="error")}function sa(e,t){switch(t){case"error":return Qt(e,"[ERROR]");case"warn":return Se(e,"[WARN]");case"info":return h(e,"[INFO]")}}function jn(e,t,n,r){if(r.length!==0){t.push(Y(e,`${n} (${r.length}):`));for(let o of r)t.push(` ${sa(e,o.severity)} ${h(e,`${o.code}:`)} ${b(e,o.message)}`),o.detail&&t.push(` ${h(e,o.detail)}`),o.fixHint&&t.push(` ${h(e,`Fix: ${o.fixHint}`)}`);t.push("")}}function en(e,t){if(e.length===0)return[`${oe(t,"Security check:")} ${b(t,"no issues reported by automated rules.")}`,"",h(t,"Note: allowlisted remote shell access is still equivalent to sharing credentials with those identities.")].join(`
6
+ `);let n=e.filter(a=>a.severity==="error"),r=e.filter(a=>a.severity==="warn"),o=e.filter(a=>a.severity==="info"),i=[`${oe(t,"Security check:")} `+b(t,`${n.length} error(s), ${r.length} warning(s), ${o.length} note(s).`),""];return jn(t,i,"Errors",n),jn(t,i,"Warnings",r),jn(t,i,"Notes",o),i.push(h(t,"Allowlisted identities can run commands as this user; treat them like passwords.")),i.join(`
7
+ `).trimEnd()}function Un(e){return{errors:e.filter(t=>t.severity==="error").length,warns:e.filter(t=>t.severity==="warn").length,infos:e.filter(t=>t.severity==="info").length}}function wo(e){return`${JSON.stringify({findings:e,summary:Un(e)},null,2)}
8
+ `}function bo(e,t){let n=e.filter(a=>a.severity==="error").length,r=e.filter(a=>a.severity==="warn").length,o=e.filter(a=>a.severity==="info").length;if(n===0&&r===0&&o===0)return"security: ok (no automated findings)";let s=[];n&&s.push(`${n} error(s)`),r&&s.push(`${r} warning(s)`),o&&s.push(`${o} note(s)`);let i=t??"run `omnish security` for details";return`security: ${s.join(", ")} \u2014 ${i}`}function ko(e,t,n){let r=e.filter(l=>l.severity==="error").length,o=e.filter(l=>l.severity==="warn").length,s=e.filter(l=>l.severity==="info").length;if(r===0&&o===0&&s===0)return`${oe(t,"security:")} ${b(t,"ok (no automated findings)")}`;let i=[];r&&i.push(Qt(t,`${r} error(s)`)),o&&i.push(Se(t,`${o} warning(s)`)),s&&i.push(h(t,`${s} note(s)`));let a=n??"run `omnish security` for details";return`${oe(t,"security:")} ${i.join(", ")} ${h(t,`\u2014 ${a}`)}`}function p(e){return{wa:e,tg:e}}function J(e,t){return{wa:e,tg:t,tgHtml:!0}}function Re(e,t){return t==="whatsapp"?{text:e.wa}:e.tgHtml?{text:e.tg,parseModeHtml:!0}:{text:e.tg}}function B(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Z(e){return e.replace(/[*_~`]/g,t=>({"*":"\u2217",_:"\uFF3F","~":"\u02DC","`":"\u2032"})[t]??t)}function ia(e){let t=[];for(let n of e)switch(n.kind){case"title":t.push("",`*${n.text}*`,"");break;case"sub":t.push("",`_${n.text}_`,"");break;case"gap":t.push("");break;case"p":t.push(n.text);break;case"bullet":t.push(`\u2022 ${n.text}`);break}return t.join(`
9
+ `).replace(/^\n+/,"").trimEnd()}function aa(e){let t=[];for(let n of e)switch(n.kind){case"title":t.push("",`<b>${B(n.text)}</b>`,"");break;case"sub":t.push("",`<i>${B(n.text)}</i>`,"");break;case"gap":t.push("");break;case"p":t.push(B(n.text));break;case"bullet":t.push(`\u2022 ${B(n.text)}`);break}return t.join(`
10
+ `).replace(/^\n+/,"").trimEnd()}function O(e){return{wa:ia(e),tg:aa(e),tgHtml:!0}}function ot(e){return[{kind:"title",text:"Omnish \u2014 quick help"},{kind:"p",text:"Per-chat shell cwd is stored under your data dir (see /wa help)."},{kind:"gap"},{kind:"sub",text:"Run commands"},{kind:"bullet",text:`${e.commandPrefix}<command> \u2014 sync shell in session cwd (timeout ${e.syncTimeoutMs} ms)`},{kind:"bullet",text:`${e.commandPrefix}cd <dir> \u2014 change session cwd (${e.commandPrefix}cd alone \u2192 home)`},{kind:"bullet",text:"!!start | !!stop \u2014 free shell mode (plain text = shell); space optional"},{kind:"bullet",text:"/bg <cmd> \u2014 background job; /jobs, /log, /tail, /kill"},{kind:"bullet",text:"/apps \u2026 \u2014 interactive app sessions (/apps help)"},{kind:"bullet",text:"/send path \u2014 host file \u2192 chat (/file); caption: path -- note"},{kind:"bullet",text:"/files \u2014 full help for /send and saving inbound media"},{kind:"bullet",text:"/receive \u2014 set this chat\u2019s inbound folder (e.g. session cwd)"},{kind:"bullet",text:"/computers \xB7 /pcs \xB7 /c \u2014 chat-driven cluster (/c here to take over, /c help)"},{kind:"bullet",text:"/config \u2014 view or change server settings (/config help, /config keys)"},{kind:"bullet",text:"/service \u2014 background service status, install hints, logs (/service help)"},{kind:"bullet",text:"/shortcut \u2014 per-chat saved commands (/shortcut help); invoke with bare !name or /name"},{kind:"bullet",text:"/run \u2014 parameterized CLI templates with a task (/run list); shorthand /r"},{kind:"bullet",text:"/cowork | /cw \u2014 scheduled & on-demand shell tasks; logs to ~/Cowork/\u2026 (/cowork help)"},{kind:"gap"},{kind:"sub",text:"Setup & gateway"},{kind:"bullet",text:"/wa help \u2014 WhatsApp link, allowlist"},{kind:"bullet",text:"/tg help \u2014 Telegram; /tg token <paste>"},{kind:"bullet",text:"/reload | /restart \u2014 apply config"},{kind:"bullet",text:"/updates \u2014 npm latest + optional notice URL; /updates cached \u2014 last snapshot"},{kind:"bullet",text:"/security \u2014 posture report; /security summary; /security tips; /security help"},{kind:"bullet",text:"/gateway | /gw | /mode \u2014 show or set gatewayMode"},{kind:"bullet",text:"/allow +E164 | /allow tg:id \u2014 allowlist; /deny \u2026; /allowlist"},{kind:"bullet",text:"/help \u2014 this message"}]}function So(e){let t=e.serviceInstallFromChat?[{kind:"bullet",text:"/service install \u2014 user-level systemd (Linux) or LaunchAgent (macOS)"},{kind:"bullet",text:"/service uninstall \u2014 remove that unit"}]:[{kind:"bullet",text:"/service install / uninstall \u2014 off by default. Enable: /config set serviceInstallFromChat true (same trust as shell)"}];return[{kind:"title",text:"Service and boot"},{kind:"p",text:"Inspect the gateway, get OS-specific install steps, or (if enabled) write the user service from chat. Same from the host terminal: omnish service help."},{kind:"bullet",text:"/service status \u2014 platform, data dir, pidfile, node + entry script"},{kind:"bullet",text:"/service instructions \u2014 copy-paste commands for this machine"},{kind:"bullet",text:"/service logs [n] \u2014 tail default gateway log (default 80 lines)"},...t,{kind:"gap"},{kind:"p",text:"See https://omnish.dev and docs/guides/background-and-boot.md."}]}function xo(){return[{kind:"title",text:"Chat config"},{kind:"p",text:`Same trust as shell \u2014 allowlisted senders can change many keys saved to ${T}.`},{kind:"gap"},{kind:"bullet",text:"/config show \u2014 full snapshot (telegramBotToken masked)"},{kind:"bullet",text:"/config get <key> \u2014 single field"},{kind:"bullet",text:"/config set <key> <value> \u2014 values can be quoted for paths with spaces"},{kind:"bullet",text:"/config keys \u2014 comma-separated whitelist of keys"},{kind:"gap"},{kind:"p",text:"After edits: /reload while omnish run is active (needed for gatewayMode and telegramBotToken)."}]}function Gn(){return[{kind:"title",text:"Gateway mode"},{kind:"p",text:"Which transports omnish uses:"},{kind:"bullet",text:"whatsapp (wa, w) \u2014 WhatsApp DMs only"},{kind:"bullet",text:"telegram (tg, t) \u2014 Telegram bot only"},{kind:"bullet",text:"both (all, b) \u2014 WhatsApp + Telegram"},{kind:"gap"},{kind:"sub",text:"Commands"},{kind:"bullet",text:"/gateway \u2014 current mode + hints (includes last update snapshot if any)"},{kind:"bullet",text:"/gateway telegram \u2014 save (auto-reloads Telegram if gateway is up)"},{kind:"bullet",text:"/gw both \u2014 short form; /mode wa \u2014 same"},{kind:"gap"},{kind:"p",text:`Config: ${T}`}]}function vo(e){let t=["*Gateway status*","",`Mode: *${e.gatewayMode}*`," \u2022 whatsapp \u2014 WhatsApp only"," \u2022 telegram \u2014 Telegram only"," \u2022 both \u2014 both channels","",`WhatsApp auth: ${e.authPresent?"present":"missing (omnish link)"}`,`Telegram token: ${e.tokenSet?"set":"not set"}`,`Allowlists: ${e.allowN} WA \xB7 ${e.tgAllowN} Telegram`,""];e.updateBrief&&t.push(`Updates: ${Z(e.updateBrief)}`,""),t.push("Change: /gateway both \xB7 /gw tg","/updates \u2014 npm + optional notice URL",`Config: ${Z(T)}`);let n=["<b>Gateway status</b>","",`<b>${B(e.gatewayMode)}</b> <i>current mode</i>`,"\u2022 whatsapp \u2014 WhatsApp only","\u2022 telegram \u2014 Telegram only","\u2022 both \u2014 both channels","",`${e.authPresent?"\u2713":"\u26A0"} WhatsApp auth: ${e.authPresent?"present":"missing \u2014 run omnish link"}`,`${e.tokenSet?"\u2713":"\u26A0"} Telegram token: ${e.tokenSet?"set":"not set"}`,`Allowlists: ${e.allowN} WA \xB7 ${e.tgAllowN} Telegram`,""];return e.updateBrief&&n.push(`<b>Updates</b> ${B(e.updateBrief)}`,""),n.push("<i>Change:</i> /gateway both \xB7 /gw tg","<i>/updates</i> \u2014 npm + optional notice URL",B(`Config: ${T}`)),J(t.join(`
11
11
  `),n.join(`
12
- `))}function Jr(e){return[{kind:"title",text:"WhatsApp setup"},{kind:"p",text:"Do these on the machine running omnish (QR is shown in the terminal, not in chat)."},{kind:"gap"},{kind:"sub",text:"Steps"},{kind:"bullet",text:"Install omnish; build native deps (node-pty, Baileys)."},{kind:"bullet",text:`Data dir: ${T} (override: OMNISH_HOME). Auth: <data-dir>/auth/`},{kind:"bullet",text:"Run: omnish link \u2014 scan QR in WhatsApp \u2192 Linked devices."},{kind:"bullet",text:"Allow your number: omnish allow +<E164>"},{kind:"bullet",text:`Set gatewayMode to "whatsapp" or "both" in ${v}`},{kind:"bullet",text:"Run: omnish run \u2014 then use !cmd or /help here."},{kind:"gap"},{kind:"sub",text:"Troubleshooting"},{kind:"bullet",text:"Denied in logs but allowlist OK: may be LID mapping \u2014 try OMNISH_VERBOSE=1."},{kind:"bullet",text:"401 on link: omnish link --force after pnpm approve-builds && pnpm install"},{kind:"gap"},{kind:"p",text:`Current gatewayMode: ${e.gatewayMode}`}]}function qr(e){let t=!!ae(e);return[{kind:"title",text:"Telegram setup"},{kind:"p",text:"Configure on the host that runs omnish."},{kind:"gap"},{kind:"sub",text:"Steps"},{kind:"bullet",text:"@BotFather \u2192 /newbot \u2014 copy the API token."},{kind:"bullet",text:`Token: /tg token <paste>, or ${v}, or TELEGRAM_BOT_TOKEN env (env wins).`},{kind:"bullet",text:'Your numeric id: @userinfobot / @getidsbot, or logs on "telegram denied".'},{kind:"bullet",text:"Allow: omnish allow tg:<user_id>"},{kind:"bullet",text:`gatewayMode: "telegram" or "both" in ${v}; list ids in telegramAllowFrom.`},{kind:"bullet",text:"omnish run \u2014 then DM the bot with !cmd or /help."},{kind:"bullet",text:"After edits: /reload or /gateway both (saves + reloads when running)."},{kind:"gap"},{kind:"sub",text:"Notes"},{kind:"bullet",text:"Private text DMs only; groups ignored. Token stays secret."},{kind:"bullet",text:"/tg token stores token in config; chat history may retain it \u2014 prefer SSH/editor if worried."},{kind:"gap"},{kind:"p",text:`Token on host: ${t?"set (env or config)":"not set \u2014 add telegramBotToken or TELEGRAM_BOT_TOKEN"}`},{kind:"p",text:`gatewayMode: ${e.gatewayMode} \xB7 telegramAllowFrom: ${e.telegramAllowFrom.length} entries`}]}function Yr(e){let t=["*Allowlists*",""],n=["<b>Allowlists</b>",""];for(let r of e){let o=r.items.length?r.items.join(", "):"(none)";t.push(`*${r.label}* (${r.items.length})`,$e(o),""),n.push(`<b>${ne(r.label)}</b> (${r.items.length})`,ne(o),"")}return D(t.join(`
12
+ `))}function kt(e){let t=["*Update check*","",`Running: *${Z(e.runningVersion)}*`,`Checked (UTC): ${e.checkedAtIso}`,`npm package: ${Z(e.registryPackage)}`];e.registryError?t.push("",`Registry: ${Z(e.registryError)}`):e.registryLatest&&t.push("",e.updateAvailable?`*Newer version on npm:* ${Z(e.registryLatest)} (upgrade when ready).`:`npm latest: ${Z(e.registryLatest)} (this install is current or newer).`),e.infoError?t.push("",`Notice URL: ${Z(e.infoError)}`):e.infoMessage&&(t.push("",`Notice: ${Z(e.infoMessage)}`),e.infoLink&&t.push(Z(e.infoLink))),t.push("","Config: updateCheckEnabled, updateCheckIntervalMs, updateCheckPackageName, updateInfoUrl");let n=["<b>Update check</b>","",`<b>Running</b> <code>${B(e.runningVersion)}</code>`,`<b>Checked (UTC)</b> ${B(e.checkedAtIso)}`,`<b>npm package</b> <code>${B(e.registryPackage)}</code>`];return e.registryError?n.push("",`<b>Registry</b> ${B(e.registryError)}`):e.registryLatest&&n.push("",e.updateAvailable?`<b>Newer on npm</b> <code>${B(e.registryLatest)}</code>`:`<b>npm latest</b> <code>${B(e.registryLatest)}</code> (current or newer here)`),e.infoError?n.push("",`<b>Notice URL</b> ${B(e.infoError)}`):e.infoMessage&&(n.push("",`<b>Notice</b> ${B(e.infoMessage)}`),e.infoLink&&n.push(B(e.infoLink))),n.push("","<i>Config keys:</i> updateCheckEnabled, updateCheckIntervalMs, updateCheckPackageName, updateInfoUrl"),J(t.join(`
13
+ `),n.join(`
14
+ `))}function $o(e){return[{kind:"title",text:"WhatsApp setup"},{kind:"p",text:"Do these on the machine running omnish (QR is shown in the terminal, not in chat)."},{kind:"gap"},{kind:"sub",text:"Steps"},{kind:"bullet",text:"Install omnish; build native deps (node-pty, Baileys)."},{kind:"bullet",text:`Data dir: ${A} (override: OMNISH_HOME). Auth: <data-dir>/auth/`},{kind:"bullet",text:"Run: omnish link \u2014 scan QR in WhatsApp \u2192 Linked devices."},{kind:"bullet",text:"Allow your number: omnish allow +<E164>"},{kind:"bullet",text:`Set gatewayMode to "whatsapp" or "both" in ${T}`},{kind:"bullet",text:"Run: omnish run \u2014 then use !cmd or /help here."},{kind:"gap"},{kind:"sub",text:"Troubleshooting"},{kind:"bullet",text:"Denied in logs but allowlist OK: may be LID mapping \u2014 try OMNISH_VERBOSE=1."},{kind:"bullet",text:"401 on link: omnish link --force after pnpm approve-builds && pnpm install"},{kind:"gap"},{kind:"p",text:`Current gatewayMode: ${e.gatewayMode}`}]}function Co(e){let t=!!pe(e);return[{kind:"title",text:"Telegram setup"},{kind:"p",text:"Configure on the host that runs omnish."},{kind:"gap"},{kind:"sub",text:"Steps"},{kind:"bullet",text:"@BotFather \u2192 /newbot \u2014 copy the API token."},{kind:"bullet",text:`Token: /tg token <paste>, or ${T}, or TELEGRAM_BOT_TOKEN env (env wins).`},{kind:"bullet",text:'Your numeric id: @userinfobot / @getidsbot, or logs on "telegram denied".'},{kind:"bullet",text:"Allow: omnish allow tg:<user_id>"},{kind:"bullet",text:`gatewayMode: "telegram" or "both" in ${T}; list ids in telegramAllowFrom.`},{kind:"bullet",text:"omnish run \u2014 then DM the bot with !cmd or /help."},{kind:"bullet",text:"After edits: /reload or /gateway both (saves + reloads when running)."},{kind:"gap"},{kind:"sub",text:"Notes"},{kind:"bullet",text:"Private text DMs only; groups ignored. Token stays secret."},{kind:"bullet",text:"/tg token stores token in config; chat history may retain it \u2014 prefer SSH/editor if worried."},{kind:"gap"},{kind:"p",text:`Token on host: ${t?"set (env or config)":"not set \u2014 add telegramBotToken or TELEGRAM_BOT_TOKEN"}`},{kind:"p",text:`gatewayMode: ${e.gatewayMode} \xB7 telegramAllowFrom: ${e.telegramAllowFrom.length} entries`}]}function Ro(e){let t=["*Allowlists*",""],n=["<b>Allowlists</b>",""];for(let r of e){let o=r.items.length?r.items.join(", "):"(none)";t.push(`*${r.label}* (${r.items.length})`,Z(o),""),n.push(`<b>${B(r.label)}</b> (${r.items.length})`,B(o),"")}return J(t.join(`
13
15
  `).trimEnd(),n.join(`
14
- `).trimEnd())}function Sn(e){let t=[{label:"allowFrom (WhatsApp)",items:e.allowFrom},{label:"telegramAllowFrom",items:e.telegramAllowFrom}],n=["*Allowlist updated*","","Saved to config.",""],r=["<b>Allowlist updated</b>","","Saved to config.",""];for(let o of t){let s=o.items.length?o.items.join(", "):"(none)";n.push(`*${o.label}* (${o.items.length})`,$e(s),""),r.push(`<b>${ne(o.label)}</b> (${o.items.length})`,ne(s),"")}return D(n.join(`
16
+ `).trimEnd())}function zn(e){let t=[{label:"allowFrom (WhatsApp)",items:e.allowFrom},{label:"telegramAllowFrom",items:e.telegramAllowFrom}],n=["*Allowlist updated*","","Saved to config.",""],r=["<b>Allowlist updated</b>","","Saved to config.",""];for(let o of t){let s=o.items.length?o.items.join(", "):"(none)";n.push(`*${o.label}* (${o.items.length})`,Z(s),""),r.push(`<b>${B(o.label)}</b> (${o.items.length})`,B(s),"")}return J(n.join(`
15
17
  `).trimEnd(),r.join(`
16
- `).trimEnd())}function Kr(e){let t=["*Token saved*","","telegramBotToken written to config (not echoed).",`Config: ${$e(v)}`,...e.flatMap(r=>["",r]),"","Send /reload so the gateway picks it up."].join(`
17
- `),n=["<b>Token saved</b>","","telegramBotToken written to config (not echoed).",ne(`Config: ${v}`),...e.map(r=>`<i>${ne(r)}</i>`),"","Send /reload so the gateway picks it up."].join(`
18
+ `).trimEnd())}function Mo(e){let t=["*Token saved*","","telegramBotToken written to config (not echoed).",`Config: ${Z(T)}`,...e.flatMap(r=>["",r]),"","Send /reload so the gateway picks it up."].join(`
19
+ `),n=["<b>Token saved</b>","","telegramBotToken written to config (not echoed).",B(`Config: ${T}`),...e.map(r=>`<i>${B(r)}</i>`),"","Send /reload so the gateway picks it up."].join(`
18
20
  `)+`
19
- `;return D(t.trimEnd(),n.trimEnd())}function Vr(){return E([{kind:"title",text:"That does not look like a bot token"},{kind:"p",text:"Expected from @BotFather: one token, no spaces, like 123456789:AA_heG\u2026"},{kind:"bullet",text:"Example: /tg token 123456789:AAAbcd\u2026"}])}function Qr(e,t,n){let r=t?`
21
+ `;return J(t.trimEnd(),n.trimEnd())}function To(){return O([{kind:"title",text:"That does not look like a bot token"},{kind:"p",text:"Expected from @BotFather: one token, no spaces, like 123456789:AA_heG\u2026"},{kind:"bullet",text:"Example: /tg token 123456789:AAAbcd\u2026"}])}function Io(e,t,n){let r=t?`
20
22
 
21
23
  ${t}`:n?`
22
24
 
23
25
  Start omnish run on the host to apply (or /reload from a running gateway).`:"",o=t?`
24
26
 
25
- ${ne(t)}`:n?`
27
+ ${B(t)}`:n?`
26
28
 
27
29
  Start omnish run on the host to apply (or /reload from a running gateway).`:"",s=`*gatewayMode saved*
28
30
 
29
- "${$e(e)}"
30
- ${$e(v)}${r}`,i=`<b>gatewayMode saved</b>
31
+ "${Z(e)}"
32
+ ${Z(T)}${r}`,i=`<b>gatewayMode saved</b>
31
33
 
32
- <code>${ne(e)}</code>
33
- ${ne(v)}${o}`;return D(s,i)}function Zr(){return E([{kind:"title",text:"/allow \u2014 add to allowlist"},{kind:"bullet",text:"/allow +<E164> \u2014 WhatsApp (country code, no spaces)"},{kind:"bullet",text:"/allow tg:<user_id> \u2014 Telegram numeric id"},{kind:"gap"},{kind:"p",text:"Examples: /allow +15551234567 \xB7 /allow tg:987654321"}])}function Xr(){return E([{kind:"title",text:"/deny \u2014 remove from allowlist"},{kind:"p",text:"Same forms as /allow: +E164 or tg:id"}])}function eo(){return E([{kind:"title",text:"/bg \u2014 background job"},{kind:"p",text:"Usage: /bg <shell command>"},{kind:"bullet",text:"Example: /bg sleep 30 && echo done"}])}function xn(){return E([{kind:"title",text:"/send \u2014 push a host file to this chat"},{kind:"p",text:"Path is resolved from your session cwd (same as shell)."},{kind:"bullet",text:"/send ./photo.png"},{kind:"bullet",text:"/send /abs/path/report.pdf -- Q4 draft"},{kind:"bullet",text:"Alias: /file \u2026"},{kind:"gap"},{kind:"p",text:"Caps: fileSendMaxBytes / fileReceiveMaxBytes (0 = no omnish cap). Where inbound media is saved: fileReceiveRootMode + fileReceiveRootPath / fileInboxSubdir \u2014 send /files for details."}])}function kn(){return E([{kind:"title",text:"Files \u2014 send & receive"},{kind:"sub",text:"Host \u2192 chat"},{kind:"bullet",text:"/send <path> or /file \u2026 \u2014 path is relative to this chat\u2019s session cwd (same as ! shell); optional caption after -- "},{kind:"bullet",text:"fileSendMaxBytes in config caps outbound size (0 = no omnish cap)."},{kind:"gap"},{kind:"sub",text:"Chat \u2192 host"},{kind:"bullet",text:"Send a photo, video, document, audio, etc. in this DM; omnish saves it and replies with Saved: <path> (or an error)."},{kind:"bullet",text:"Folders: <root>/<peer>/<YYYY-MM-DD>/<filename> \u2014 root comes from config below."},{kind:"bullet",text:"fileReceiveRootMode: downloads (home/Downloads/Omnish) \xB7 omnishData (data dir + fileInboxSubdir) \xB7 sessionCwd \xB7 processCwd \xB7 fixed (needs absolute fileReceiveRootPath)."},{kind:"bullet",text:"fileReceiveMaxBytes \u2014 inbound size cap (0 = no omnish cap)."},{kind:"gap"},{kind:"p",text:`Edit config on the host (${v}) then use /reload. Tip: omnish status shows the data directory.`},{kind:"gap"},{kind:"p",text:"Per-chat folder: /receive here saves inbound files under your session cwd (!cd); /receive default clears."}])}function vn(){return E([{kind:"title",text:"/receive \u2014 inbound files for this chat"},{kind:"p",text:"Stored on the host with your session (sessions.json). Does not edit config.json."},{kind:"bullet",text:"/receive \u2014 show current setting and resolved save folder"},{kind:"bullet",text:"/receive here \u2014 save uploads under this chat\u2019s session cwd (same as !cd); subfolders: peer / date / file"},{kind:"bullet",text:"/receive default \u2014 clear per-chat rule; use global fileReceiveRootMode (/files, config.json)"},{kind:"gap"},{kind:"p",text:"Aliases: here = cwd = session = dir \xB7 default = global = reset"}])}function to(e,t){let n=Er(t),r=z(t),o="";try{o=Ke(e,t)}catch(s){o=`(${String(s)})`}return E(n==="sessionCwd"?[{kind:"title",text:"/receive \u2014 this chat"},{kind:"p",text:"Per-chat: inbound media saves under your session folder (updated when you !cd)."},{kind:"bullet",text:`Session cwd: ${r.cwd}`},{kind:"bullet",text:`Next file root: ${o}`},{kind:"p",text:"Send /receive default to follow server config instead."}]:[{kind:"title",text:"/receive \u2014 this chat"},{kind:"p",text:"Per-chat override: off \u2014 using global fileReceiveRootMode from config."},{kind:"bullet",text:`Global mode: ${e.fileReceiveRootMode}`},{kind:"bullet",text:`Next file root: ${o}`},{kind:"p",text:"Send /receive here to pin saves to your current session folder."}])}function no(){return E([{kind:"title",text:"Unknown /wa command"},{kind:"p",text:"Send /wa help for setup."}])}function ro(){return E([{kind:"title",text:"Unknown /tg command"},{kind:"p",text:"Send /tg help or /tg token <botfather_token>."}])}function oo(){return E([{kind:"title",text:"Free shell mode on"},{kind:"p",text:"Plain messages run as sync shell (no command prefix)."},{kind:"bullet",text:"Send !!stop to turn off."},{kind:"bullet",text:"Apps: plain DMs no longer go to the focused app \u2014 use >name text or /apps send."}])}function so(e){return E([{kind:"title",text:"Unknown command"},{kind:"p",text:`Try /help or ${e.commandPrefix}<command>.`},{kind:"gap"},...Ze(e)])}function io(e){return E([{kind:"title",text:"No command matched"},{kind:"p",text:`Use ${JSON.stringify(e.commandPrefix)}, a slash command, or /apps help.`},{kind:"gap"},...Ze(e)])}function ao(){let e=[{kind:"title",text:"Unknown mode"},{kind:"p",text:"Use: whatsapp | telegram | both (short: wa, tg, b)"},{kind:"bullet",text:"/gateway both \xB7 /gw wa \xB7 /mode telegram"},{kind:"gap"},...bn()];return E(e)}function $n(){return[{kind:"title",text:"User shortcuts (this chat)"},{kind:"p",text:"Macros are stored per chat on the host. Invoke with a bare token only (no extra words)."},{kind:"gap"},{kind:"sub",text:"Manage"},{kind:"bullet",text:"/shortcut add <name> <command\u2026> \u2014 save (name: letters, digits, _ -)"},{kind:"bullet",text:"/shortcut set <name> <command\u2026> \u2014 same as add (overwrite)"},{kind:"bullet",text:"/shortcut list \u2014 or /shortcuts"},{kind:"bullet",text:"/shortcut show <name>"},{kind:"bullet",text:"/shortcut remove <name> \u2014 aliases: rm, del"},{kind:"bullet",text:"/alias \u2026 \u2014 same as /shortcut \u2026 (including /aliases \u2026)"},{kind:"gap"},{kind:"sub",text:"Run"},{kind:"bullet",text:"!name \u2014 expands once to the saved line (e.g. !cd \u2026 updates session cwd)"},{kind:"bullet",text:"/name \u2014 same expansion for slash-style navigation"},{kind:"p",text:"Shortcut bodies may start with !, /, etc.; nested shortcuts are not expanded."}]}function lo(e){if(e.length===0)return m("(no shortcuts yet \u2014 /shortcut add <name> <command\u2026>)");let t=e.map(n=>`${n.name} \u2192 ${n.body}`);return m(["Shortcuts (this chat):","",...t].join(`
34
- `))}function Rn(e,t){return m(`Shortcut saved: ${e}
35
- \u2192 ${t}`)}function co(e){return m(`Shortcut removed: ${e}`)}function Mn(e){return m(`Unknown shortcut: ${e}`)}function uo(e,t){return m(`${e}
36
- \u2192 ${t}`)}function po(){return[{kind:"title",text:"/run \u2014 recipe templates"},{kind:"p",text:"Runs a command in an app session with your task injected via an environment variable (default OMNISH_TASK). Same host trust model as /apps start (session cwd)."},{kind:"gap"},{kind:"sub",text:"Invoke"},{kind:"bullet",text:"/run <name> <task\u2026> \u2014 start attached session (plain DMs go to it until /apps detach)"},{kind:"bullet",text:"/r \u2014 same as /run"},{kind:"gap"},{kind:"sub",text:"Discover"},{kind:"bullet",text:"/run list \u2014 featured, this chat, and other templates"},{kind:"bullet",text:"/run show <name> \u2014 resolved command and metadata"},{kind:"gap"},{kind:"sub",text:"This chat only"},{kind:"bullet",text:'/run add <name> <command\u2026> \u2014 command must reference "$OMNISH_TASK" (or your taskEnv)'},{kind:"bullet",text:"/run set <name> <command\u2026> \u2014 replace"},{kind:"bullet",text:"/run remove <name> \u2014 aliases: rm, del"},{kind:"gap"},{kind:"p",text:`Host overrides: ${St}`},{kind:"p",text:"Built-in Claude templates omit --dangerously-skip-permissions unless recipesAllowDangerousBuiltins is true in config."}]}function mo(e){let t=["Recipes (/run <name> <task>)",""];if(e.featured.length>0){t.push("Featured:");for(let n of e.featured){let r=n.description?` \u2014 ${n.description}`:"",o=n.dangerous?" [dangerous flags]":"";t.push(`\u2022 ${n.name} \u2014 ${n.label??n.name}${r}${o}`)}t.push("")}if(e.yours.length>0){t.push("This chat:");for(let n of e.yours){let r=n.description?` \u2014 ${n.description}`:"";t.push(`\u2022 ${n.name} \u2014 ${n.label??n.name}${r}`)}t.push("")}if(e.more.length>0){t.push("More:");for(let n of e.more){let r=n.description?` \u2014 ${n.description}`:"";t.push(`\u2022 ${n.name} \u2014 ${n.label??n.name}${r}`)}}return e.featured.length===0&&e.yours.length===0&&e.more.length===0&&t.push("(no recipes \u2014 add host file or /run add)"),m(t.join(`
37
- `).trimEnd())}function fo(e){let t=e.taskEnv??"OMNISH_TASK",n=[`Recipe: ${e.name}`,`Source: ${e.source}`,`Label: ${e.label??"(none)"}`,`Task env: ${t}`,`Command: ${e.command}`];return e.category&&n.push(`Category: ${e.category}`),e.description&&n.push(`Description: ${e.description}`),e.dangerous&&n.push("Note: built-in includes gated dangerous CLI flags."),m(n.join(`
38
- `))}function Cn(e,t){return m(`Recipe saved: ${e}
34
+ <code>${B(e)}</code>
35
+ ${B(T)}${o}`;return J(s,i)}function Ao(){return O([{kind:"title",text:"/allow \u2014 add to allowlist"},{kind:"bullet",text:"/allow +<E164> \u2014 WhatsApp (country code, no spaces)"},{kind:"bullet",text:"/allow tg:<user_id> \u2014 Telegram numeric id"},{kind:"gap"},{kind:"p",text:"Examples: /allow +15551234567 \xB7 /allow tg:987654321"}])}function Eo(){return O([{kind:"title",text:"/deny \u2014 remove from allowlist"},{kind:"p",text:"Same forms as /allow: +E164 or tg:id"}])}function Oo(){return O([{kind:"title",text:"/bg \u2014 background job"},{kind:"p",text:"Usage: /bg <shell command>"},{kind:"bullet",text:"Example: /bg sleep 30 && echo done"}])}function Jn(){return O([{kind:"title",text:"/send \u2014 push a host file to this chat"},{kind:"p",text:"Path is resolved from your session cwd (same as shell)."},{kind:"bullet",text:"/send ./photo.png"},{kind:"bullet",text:"/send /abs/path/report.pdf -- Q4 draft"},{kind:"bullet",text:"Alias: /file \u2026"},{kind:"gap"},{kind:"p",text:"Caps: fileSendMaxBytes / fileReceiveMaxBytes (0 = no omnish cap). Where inbound media is saved: fileReceiveRootMode + fileReceiveRootPath / fileInboxSubdir \u2014 send /files for details."}])}function Kn(){return O([{kind:"title",text:"Files \u2014 send & receive"},{kind:"sub",text:"Host \u2192 chat"},{kind:"bullet",text:"/send <path> or /file \u2026 \u2014 path is relative to this chat\u2019s session cwd (same as ! shell); optional caption after -- "},{kind:"bullet",text:"fileSendMaxBytes in config caps outbound size (0 = no omnish cap)."},{kind:"gap"},{kind:"sub",text:"Chat \u2192 host"},{kind:"bullet",text:"Send a photo, video, document, audio, etc. in this DM; omnish saves it and replies with Saved: <path> (or an error)."},{kind:"bullet",text:"Folders: <root>/<peer>/<YYYY-MM-DD>/<filename> \u2014 root comes from config below."},{kind:"bullet",text:"fileReceiveRootMode: downloads (home/Downloads/Omnish) \xB7 omnishData (data dir + fileInboxSubdir) \xB7 sessionCwd \xB7 processCwd \xB7 fixed (needs absolute fileReceiveRootPath)."},{kind:"bullet",text:"fileReceiveMaxBytes \u2014 inbound size cap (0 = no omnish cap)."},{kind:"gap"},{kind:"p",text:`Edit config on the host (${T}) then use /reload. Tip: omnish status shows the data directory.`},{kind:"gap"},{kind:"p",text:"Per-chat folder: /receive here saves inbound files under your session cwd (!cd); /receive default clears."}])}function qn(){return O([{kind:"title",text:"/receive \u2014 inbound files for this chat"},{kind:"p",text:"Stored on the host with your session (sessions.json). Does not edit config.json."},{kind:"bullet",text:"/receive \u2014 show current setting and resolved save folder"},{kind:"bullet",text:"/receive here \u2014 save uploads under this chat\u2019s session cwd (same as !cd); subfolders: peer / date / file"},{kind:"bullet",text:"/receive default \u2014 clear per-chat rule; use global fileReceiveRootMode (/files, config.json)"},{kind:"gap"},{kind:"p",text:"Aliases: here = cwd = session = dir \xB7 default = global = reset"}])}function Lo(e,t){let n=lo(t),r=H(t),o="";try{o=nt(e,t)}catch(s){o=`(${String(s)})`}return O(n==="sessionCwd"?[{kind:"title",text:"/receive \u2014 this chat"},{kind:"p",text:"Per-chat: inbound media saves under your session folder (updated when you !cd)."},{kind:"bullet",text:`Session cwd: ${r.cwd}`},{kind:"bullet",text:`Next file root: ${o}`},{kind:"p",text:"Send /receive default to follow server config instead."}]:[{kind:"title",text:"/receive \u2014 this chat"},{kind:"p",text:"Per-chat override: off \u2014 using global fileReceiveRootMode from config."},{kind:"bullet",text:`Global mode: ${e.fileReceiveRootMode}`},{kind:"bullet",text:`Next file root: ${o}`},{kind:"p",text:"Send /receive here to pin saves to your current session folder."}])}function Po(){return O([{kind:"title",text:"Unknown /wa command"},{kind:"p",text:"Send /wa help for setup."}])}function Fo(){return O([{kind:"title",text:"Unknown /tg command"},{kind:"p",text:"Send /tg help or /tg token <botfather_token>."}])}function No(){return O([{kind:"title",text:"Free shell mode on"},{kind:"p",text:"Plain messages run as sync shell (no command prefix)."},{kind:"bullet",text:"Send !!stop to turn off."},{kind:"bullet",text:"Apps: plain DMs no longer go to the focused app \u2014 use >name text or /apps send."}])}function _o(e){return O([{kind:"title",text:"Unknown command"},{kind:"p",text:`Try /help or ${e.commandPrefix}<command>.`},{kind:"gap"},...ot(e)])}function Bo(e){return O([{kind:"title",text:"No command matched"},{kind:"p",text:`Use ${JSON.stringify(e.commandPrefix)}, a slash command, or /apps help.`},{kind:"gap"},...ot(e)])}function Do(){let e=[{kind:"title",text:"Unknown mode"},{kind:"p",text:"Use: whatsapp | telegram | both (short: wa, tg, b)"},{kind:"bullet",text:"/gateway both \xB7 /gw wa \xB7 /mode telegram"},{kind:"gap"},...Gn()];return O(e)}function Yn(){return[{kind:"title",text:"User shortcuts (this chat)"},{kind:"p",text:"Macros are stored per chat on the host. Invoke with a bare token only (no extra words)."},{kind:"gap"},{kind:"sub",text:"Manage"},{kind:"bullet",text:"/shortcut add <name> <command\u2026> \u2014 save (name: letters, digits, _ -)"},{kind:"bullet",text:"/shortcut set <name> <command\u2026> \u2014 same as add (overwrite)"},{kind:"bullet",text:"/shortcut list \u2014 or /shortcuts"},{kind:"bullet",text:"/shortcut show <name>"},{kind:"bullet",text:"/shortcut remove <name> \u2014 aliases: rm, del"},{kind:"bullet",text:"/alias \u2026 \u2014 same as /shortcut \u2026 (including /aliases \u2026)"},{kind:"gap"},{kind:"sub",text:"Run"},{kind:"bullet",text:"!name \u2014 expands once to the saved line (e.g. !cd \u2026 updates session cwd)"},{kind:"bullet",text:"/name \u2014 same expansion for slash-style navigation"},{kind:"p",text:"Shortcut bodies may start with !, /, etc.; nested shortcuts are not expanded."}]}function Ho(e){if(e.length===0)return p("(no shortcuts yet \u2014 /shortcut add <name> <command\u2026>)");let t=e.map(n=>`${n.name} \u2192 ${n.body}`);return p(["Shortcuts (this chat):","",...t].join(`
36
+ `))}function Vn(e,t){return p(`Shortcut saved: ${e}
37
+ \u2192 ${t}`)}function jo(e){return p(`Shortcut removed: ${e}`)}function Xn(e){return p(`Unknown shortcut: ${e}`)}function Wo(e,t){return p(`${e}
38
+ \u2192 ${t}`)}function Uo(){return[{kind:"title",text:"/run \u2014 recipe templates"},{kind:"p",text:"Runs a command in an app session with your task injected via an environment variable (default OMNISH_TASK). Same host trust model as /apps start (session cwd)."},{kind:"gap"},{kind:"sub",text:"Invoke"},{kind:"bullet",text:"/run <name> <task\u2026> \u2014 start attached session (plain DMs go to it until /apps detach)"},{kind:"bullet",text:"/r \u2014 same as /run"},{kind:"gap"},{kind:"sub",text:"Discover"},{kind:"bullet",text:"/run list \u2014 featured, this chat, and other templates"},{kind:"bullet",text:"/run show <name> \u2014 resolved command and metadata"},{kind:"gap"},{kind:"sub",text:"This chat only"},{kind:"bullet",text:'/run add <name> <command\u2026> \u2014 command must reference "$OMNISH_TASK" (or your taskEnv)'},{kind:"bullet",text:"/run set <name> <command\u2026> \u2014 replace"},{kind:"bullet",text:"/run remove <name> \u2014 aliases: rm, del"},{kind:"gap"},{kind:"p",text:`Host overrides: ${_t}`},{kind:"p",text:"Built-in Claude templates omit --dangerously-skip-permissions unless recipesAllowDangerousBuiltins is true in config."}]}function Go(e){let t=["Recipes (/run <name> <task>)",""];if(e.featured.length>0){t.push("Featured:");for(let n of e.featured){let r=n.description?` \u2014 ${n.description}`:"",o=n.dangerous?" [dangerous flags]":"";t.push(`\u2022 ${n.name} \u2014 ${n.label??n.name}${r}${o}`)}t.push("")}if(e.yours.length>0){t.push("This chat:");for(let n of e.yours){let r=n.description?` \u2014 ${n.description}`:"";t.push(`\u2022 ${n.name} \u2014 ${n.label??n.name}${r}`)}t.push("")}if(e.more.length>0){t.push("More:");for(let n of e.more){let r=n.description?` \u2014 ${n.description}`:"";t.push(`\u2022 ${n.name} \u2014 ${n.label??n.name}${r}`)}}return e.featured.length===0&&e.yours.length===0&&e.more.length===0&&t.push("(no recipes \u2014 add host file or /run add)"),p(t.join(`
39
+ `).trimEnd())}function zo(e){let t=e.taskEnv??"OMNISH_TASK",n=[`Recipe: ${e.name}`,`Source: ${e.source}`,`Label: ${e.label??"(none)"}`,`Task env: ${t}`,`Command: ${e.command}`];return e.category&&n.push(`Category: ${e.category}`),e.description&&n.push(`Description: ${e.description}`),e.dangerous&&n.push("Note: built-in includes gated dangerous CLI flags."),p(n.join(`
40
+ `))}function Qn(e,t){return p(`Recipe saved: ${e}
39
41
  \u2192 ${t.command}
40
- (task env: ${t.taskEnv??"OMNISH_TASK"})`)}function _t(e){return m(`Unknown recipe: ${e}
41
- /run list`)}function Tn(){return[{kind:"title",text:"Apps (interactive CLI)"},{kind:"sub",text:"Sessions"},{kind:"bullet",text:"/apps start <name> <command\u2026> \u2014 spawn in session cwd; auto-attaches"},{kind:"bullet",text:"/apps attach <name> | /apps detach"},{kind:"bullet",text:"/apps list | /apps info <name>"},{kind:"gap"},{kind:"sub",text:"Input"},{kind:"bullet",text:"/apps send <name> <text> \u2014 text + newline"},{kind:"bullet",text:">name text \u2014 shorthand for send"},{kind:"bullet",text:"/apps key <name> <KEY[,KEY\u2026]> \u2014 Enter, ^C, Up, Esc, \\x1b, \u2026"},{kind:"gap"},{kind:"sub",text:"Output & control"},{kind:"bullet",text:"/apps tail <name> [lines] | /apps since <name>"},{kind:"bullet",text:"/apps mute|unmute <name> | /apps raw <name> on|off"},{kind:"bullet",text:"/apps resize <name> <cols> <rows>"},{kind:"bullet",text:"/apps stop <name> | /apps kill <name> | /apps rm <name>"},{kind:"gap"},{kind:"p",text:"Attached: plain DMs go to the focused app. Escaped by ! prefix, /commands, or >other."},{kind:"p",text:"Free shell: !!start \u2014 plain DMs run as sync shell; !!stop \u2014 back to attach."}]}function li(e){let{errors:t,warns:n,infos:r}=wn(e),o=[{kind:"title",text:"Security check"}];if(e.length===0)return o.push({kind:"p",text:"No issues reported by automated rules."},{kind:"gap"},{kind:"p",text:"Allowlisted remote shell access is still equivalent to sharing credentials with those identities."}),o;o.push({kind:"p",text:`${t} error(s), ${n} warning(s), ${r} note(s).`}),o.push({kind:"gap"});let s=(i,a)=>{if(a.length!==0){o.push({kind:"sub",text:`${i} (${a.length})`});for(let l of a){let u=l.severity.toUpperCase();o.push({kind:"bullet",text:$e(`[${u}] ${l.code}: ${l.message}`)}),l.detail&&o.push({kind:"bullet",text:$e(l.detail)}),l.fixHint&&o.push({kind:"bullet",text:$e(`Fix: ${l.fixHint}`)})}o.push({kind:"gap"})}};return s("Errors",e.filter(i=>i.severity==="error")),s("Warnings",e.filter(i=>i.severity==="warn")),s("Notes",e.filter(i=>i.severity==="info")),o.push({kind:"p",text:"Allowlisted identities can run commands as this user; treat them like passwords."}),o}function go(e){return E(li(e))}function ho(){return[{kind:"title",text:"Security tips"},{kind:"p",text:"Practical hardening for this gateway:"},{kind:"bullet",text:"Keep allowlists minimal \u2014 only numbers and tg: ids you trust."},{kind:"bullet",text:'Never use "*" in allowFrom; treat allowed identities like passwords.'},{kind:"bullet",text:"chmod 600 config.json and chmod 700 your data dir (~/.omnish or OMNISH_HOME)."},{kind:"bullet",text:"Do not paste bot tokens in group chats; revoke at @BotFather if leaked."},{kind:"bullet",text:"Prefer TELEGRAM_BOT_TOKEN via systemd/env over chat if your Telegram logs worry you."},{kind:"bullet",text:"Run omnish as a normal user, not root, unless you fully accept that risk."},{kind:"gap"},{kind:"p",text:"Send /security on this chat or run omnish security on the host for automated checks."}]}function yo(){return[{kind:"title",text:"/security commands"},{kind:"bullet",text:"/security \u2014 full report (same checks as omnish security)"},{kind:"bullet",text:"/security summary \u2014 one-line counts"},{kind:"bullet",text:"/security tips \u2014 short hardening checklist"},{kind:"bullet",text:"CLI: omnish security [--json] for scripts and monitoring"}]}import So from"node:fs";import ci from"node:path";var wo=500,xo=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,ui=new Set(["help","apps","bg","jobs","log","tail","kill","send","file","files","receive","reload","restart","gateway","gw","mode","allow","deny","allowlist","whatsapp","wa","telegram","tg","shortcut","shortcuts","alias","aliases"]),Nt=new Map,bo=!1;function di(){try{let e=So.readFileSync(bt,"utf8"),t=JSON.parse(e);if(t&&typeof t=="object")for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o={};for(let[s,i]of Object.entries(r)){let a=String(s).toLowerCase();typeof i=="string"&&i.length>0&&(o[a]=i.trim())}Nt.set(n,o)}}catch{}}function ko(){P(ci.dirname(bt));let e={};for(let[t,n]of Nt)Object.entries(n).length>0&&(e[t]={...n});So.writeFileSync(bt,JSON.stringify(e,null,2)+`
42
- `,{mode:384})}function pi(){bo||(di(),bo=!0)}function mi(e){return ui.has(e.trim().toLowerCase())}function Ht(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return xo.test(n)?mi(n)?{ok:!1,error:`Reserved name: ${n}`}:{ok:!0,normalized:n}:{ok:!1,error:`Invalid name (use letters, digits, _ or -; max 32 chars): ${t}`}}function fi(e){let t=e.replace(/\r\n/g,`
43
- `).replace(/\n/g," ").trim();return t?t.length>wo?{ok:!1,error:`Body too long (max ${wo} characters).`}:{ok:!0,body:t}:{ok:!1,error:"Body is empty."}}function jt(e){pi();let t=Nt.get(e);return t||(t={},Nt.set(e,t)),t}function vo(e){let t=jt(e);return Object.entries(t).map(([n,r])=>({name:n,body:r})).sort((n,r)=>n.name.localeCompare(r.name))}function Xe(e,t){let n=t.trim().toLowerCase();return jt(e)[n]}function In(e,t,n){let r=Ht(t);if(!r.ok)throw new Error(r.error);let o=fi(n);if(!o.ok)throw new Error(o.error);let s=jt(e);s[r.normalized]=o.body,ko()}function $o(e,t){let n=t.trim().toLowerCase(),r=jt(e);return n in r?(delete r[n],ko(),!0):!1}function Ro(e){let t=e.trim();return t.length>0&&!/\s/.test(t)&&xo.test(t.toLowerCase())}import gi from"node:crypto";import En from"node:fs";import hi from"node:path";var On=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,Ln=new Set(["help","list","show","add","set","remove","rm","del","run","r"]),Wt=new Map,Mo=!1;function yi(){try{let e=En.readFileSync(xt,"utf8"),t=JSON.parse(e);if(t&&typeof t=="object")for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o={};for(let[s,i]of Object.entries(r)){let a=String(s).toLowerCase();i&&typeof i=="object"&&typeof i.command=="string"&&(o[a]=Pn(i))}Wt.set(n,o)}}catch{}}function Pn(e){let t=typeof e.taskEnv=="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(e.taskEnv)?e.taskEnv:"OMNISH_TASK";return{command:String(e.command).trim(),taskEnv:t,label:typeof e.label=="string"?e.label.trim().slice(0,80):void 0,description:typeof e.description=="string"?e.description.trim().slice(0,200):void 0,category:typeof e.category=="string"?e.category.trim().slice(0,40):void 0,featured:typeof e.featured=="boolean"?e.featured:void 0,dangerous:typeof e.dangerous=="boolean"?e.dangerous:void 0}}function Co(){P(hi.dirname(xt));let e={};for(let[t,n]of Wt)Object.entries(n).length>0&&(e[t]={...n});En.writeFileSync(xt,JSON.stringify(e,null,2)+`
44
- `,{mode:384})}function wi(){Mo||(yi(),Mo=!0)}function Fn(e){wi();let t=Wt.get(e);return t||(t={},Wt.set(e,t)),t}function bi(){try{let e=En.readFileSync(St,"utf8"),t=JSON.parse(e);if(!t||typeof t!="object")return{};let n={};for(let[r,o]of Object.entries(t)){let s=r.trim().toLowerCase();!On.test(s)||Ln.has(s)||o&&typeof o=="object"&&typeof o.command=="string"&&(n[s]=Pn(o))}return n}catch{return{}}}function Si(e){return{claude:{command:'claude -p "$OMNISH_TASK" --allowedTools all --dangerously-skip-permissions',taskEnv:"OMNISH_TASK",label:"Claude Code",description:"Anthropic Claude Code CLI (requires `claude` on PATH)",category:"agents",featured:!0,dangerous:e.recipesAllowDangerousBuiltins},codex:{command:'codex "$OMNISH_TASK"',taskEnv:"OMNISH_TASK",label:"Codex CLI",description:"OpenAI Codex CLI if installed; override in recipes.json",category:"agents",featured:!1},gemini:{command:'gemini -p "$OMNISH_TASK"',taskEnv:"OMNISH_TASK",label:"Gemini CLI",description:"Google Gemini CLI if installed; override in recipes.json",category:"agents",featured:!1},cursor:{command:"agent --yolo --force -p ```Before writing any code:\n1. Analyze the codebase and state your full implementation plan\n2. List every file you will touch\n3. Identify any risks or ambiguities\n4. Then execute the plan step by step, <task> $OMNISH_TASK </task>```",taskEnv:"OMNISH_TASK",label:"Cursor Agent",description:"Cursor Agent if installed; override in recipes.json",category:"agents",featured:!0}}}function An(e,t,n){for(let[r,o]of Object.entries(t)){let s=r.toLowerCase();!On.test(s)||Ln.has(s)||o.command.trim()&&e.set(s,{...o,name:s,source:n})}}function To(e,t){let n=new Map;return An(n,Si(t),"builtin"),An(n,bi(),"global"),An(n,Fn(e),"peer"),n}function et(e,t,n){let r=n.trim().toLowerCase();return To(e,t).get(r)}function Dt(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return On.test(n)?Ln.has(n)?{ok:!1,error:`Reserved name: ${n}`}:{ok:!0,normalized:n}:{ok:!1,error:`Invalid name (use letters, digits, _ or -; max 32 chars): ${t}`}}function Io(e,t){let n=e.replace(/\r\n/g,`
45
- `).trim();return n?t>0&&n.length>t?{ok:!1,error:`Task too long (max ${t} characters).`}:{ok:!0,task:n}:{ok:!1,error:"Task is empty."}}function Bn(e,t){return e.includes("$")?e.includes(t):!1}function xi(e){let t=e.command.trim();if(!t)return{ok:!1,error:"Command is empty."};let n=e.taskEnv??"OMNISH_TASK";return/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)?Bn(t,n)?{ok:!0}:{ok:!1,error:`Command must reference "$${n}" (or include $${n}) so the task is passed via the environment.`}:{ok:!1,error:"Invalid taskEnv (use letters, digits, _)."}}function _n(e,t,n){let r=Dt(t);if(!r.ok)throw new Error(r.error);let o=Pn({...n,command:n.command}),s=xi(o);if(!s.ok)throw new Error(s.error);let i=Fn(e);i[r.normalized]=o,Co()}function Ao(e,t){let n=t.trim().toLowerCase(),r=Fn(e);return n in r?(delete r[n],Co(),!0):!1}function Eo(e,t){let n=[...To(e,t).values()],r=n.filter(i=>i.featured).sort((i,a)=>i.name.localeCompare(a.name)),o=n.filter(i=>i.source==="peer").sort((i,a)=>i.name.localeCompare(a.name)),s=n.filter(i=>!i.featured&&i.source!=="peer").sort((i,a)=>i.name.localeCompare(a.name));return{featured:r,yours:o,more:s}}function Oo(e){let t=gi.randomBytes(4).toString("hex");return`r-${e.replace(/[^a-zA-Z0-9_-]/g,"").slice(0,12)}-${t}`.slice(0,32)}import{spawn as ki}from"node:child_process";function Lo(e,t){return e.length<=t?e:`${e.slice(0,t)}
46
- [...truncated]`}function Po(e,t,n){return new Promise(r=>{let o=Date.now(),s=!1,i="",a="",l=n.cwd,u=ki(e,["-c",t],{stdio:["ignore","pipe","pipe"],env:{...process.env,TERM:"dumb",...l?{PWD:l}:{}},...l?{cwd:l}:{}}),c=setTimeout(()=>{s=!0,u.kill("SIGTERM")},n.timeoutMs),d=(p,f)=>{let w=p.toString("utf8");f==="stdout"?(i+=w,i.length>n.maxBytes&&(i=Lo(i,n.maxBytes),u.kill("SIGTERM"))):(a+=w,a.length>n.maxBytes&&(a=Lo(a,n.maxBytes),u.kill("SIGTERM")))};u.stdout?.on("data",p=>d(p,"stdout")),u.stderr?.on("data",p=>d(p,"stderr")),u.on("error",p=>{clearTimeout(c),r({code:null,stdout:i,stderr:`${a}
47
- ${String(p)}`,durationMs:Date.now()-o,timedOut:s,signal:null})}),u.on("close",(p,f)=>{clearTimeout(c),r({code:p,stdout:i,stderr:a,durationMs:Date.now()-o,timedOut:s,signal:f??null})})})}import tt from"node:fs";import Wn from"node:os";import pt from"node:path";import No from"node:crypto";var Hn="\u2063omnish/c v1",vi=/([nlra])=([^\s\]]*)/g;function be(e){return e.replace(/-/g,"").slice(0,8)}function Nn(e){return e.replace(/[\s\]\r\n]/g,"_").slice(0,64)}function $i(e){let t=Nn(be(e.nodeId)),n=Nn(e.label||""),r=e.role==="primary"?"p":"s",o=Nn(e.activeNodeId?be(e.activeNodeId):"");return`${Hn} [n=${t} l=${n} r=${r} a=${o}]`}function Fo(e,t){let n=$i(t);if(e.includes(n))return e;let r=e.replace(/\s+$/,"");return r.length===0?n:`${r}
42
+ (task env: ${t.taskEnv??"OMNISH_TASK"})`)}function tn(e){return p(`Unknown recipe: ${e}
43
+ /run list`)}function Zn(){return[{kind:"title",text:"Apps (interactive CLI)"},{kind:"sub",text:"Sessions"},{kind:"bullet",text:"/apps start <name> <command\u2026> \u2014 spawn in session cwd; auto-attaches"},{kind:"bullet",text:"/apps attach <name> | /apps detach"},{kind:"bullet",text:"/apps list | /apps info <name>"},{kind:"gap"},{kind:"sub",text:"Input"},{kind:"bullet",text:"/apps send <name> <text> \u2014 text + newline"},{kind:"bullet",text:">name text \u2014 shorthand for send"},{kind:"bullet",text:"/apps key <name> <KEY[,KEY\u2026]> \u2014 Enter, ^C, Up, Esc, \\x1b, \u2026"},{kind:"gap"},{kind:"sub",text:"Output & control"},{kind:"bullet",text:"/apps tail <name> [lines] | /apps since <name>"},{kind:"bullet",text:"/apps mute|unmute <name> | /apps raw <name> on|off"},{kind:"bullet",text:"/apps resize <name> <cols> <rows>"},{kind:"bullet",text:"/apps stop <name> | /apps kill <name> | /apps rm <name>"},{kind:"gap"},{kind:"p",text:"Attached: plain DMs go to the focused app. Escaped by ! prefix, /commands, or >other."},{kind:"p",text:"Free shell: !!start \u2014 plain DMs run as sync shell; !!stop \u2014 back to attach."}]}function la(e){let{errors:t,warns:n,infos:r}=Un(e),o=[{kind:"title",text:"Security check"}];if(e.length===0)return o.push({kind:"p",text:"No issues reported by automated rules."},{kind:"gap"},{kind:"p",text:"Allowlisted remote shell access is still equivalent to sharing credentials with those identities."}),o;o.push({kind:"p",text:`${t} error(s), ${n} warning(s), ${r} note(s).`}),o.push({kind:"gap"});let s=(i,a)=>{if(a.length!==0){o.push({kind:"sub",text:`${i} (${a.length})`});for(let l of a){let d=l.severity.toUpperCase();o.push({kind:"bullet",text:Z(`[${d}] ${l.code}: ${l.message}`)}),l.detail&&o.push({kind:"bullet",text:Z(l.detail)}),l.fixHint&&o.push({kind:"bullet",text:Z(`Fix: ${l.fixHint}`)})}o.push({kind:"gap"})}};return s("Errors",e.filter(i=>i.severity==="error")),s("Warnings",e.filter(i=>i.severity==="warn")),s("Notes",e.filter(i=>i.severity==="info")),o.push({kind:"p",text:"Allowlisted identities can run commands as this user; treat them like passwords."}),o}function Jo(e){return O(la(e))}function Ko(){return[{kind:"title",text:"Security tips"},{kind:"p",text:"Practical hardening for this gateway:"},{kind:"bullet",text:"Keep allowlists minimal \u2014 only numbers and tg: ids you trust."},{kind:"bullet",text:'Never use "*" in allowFrom; treat allowed identities like passwords.'},{kind:"bullet",text:"chmod 600 config.json and chmod 700 your data dir (~/.omnish or OMNISH_HOME)."},{kind:"bullet",text:"Do not paste bot tokens in group chats; revoke at @BotFather if leaked."},{kind:"bullet",text:"Prefer TELEGRAM_BOT_TOKEN via systemd/env over chat if your Telegram logs worry you."},{kind:"bullet",text:"Run omnish as a normal user, not root, unless you fully accept that risk."},{kind:"gap"},{kind:"p",text:"Send /security on this chat or run omnish security on the host for automated checks."}]}function qo(){return[{kind:"title",text:"/security commands"},{kind:"bullet",text:"/security \u2014 full report (same checks as omnish security)"},{kind:"bullet",text:"/security summary \u2014 one-line counts"},{kind:"bullet",text:"/security tips \u2014 short hardening checklist"},{kind:"bullet",text:"CLI: omnish security [--json] for scripts and monitoring"}]}import Xo from"node:fs";import ca from"node:path";var Yo=500,Qo=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,ua=new Set(["help","apps","bg","jobs","log","tail","kill","send","file","files","receive","reload","restart","updates","gateway","gw","mode","allow","deny","allowlist","whatsapp","wa","telegram","tg","cowork","cw","shortcut","shortcuts","alias","aliases"]),nn=new Map,Vo=!1;function da(){try{let e=Xo.readFileSync(Nt,"utf8"),t=JSON.parse(e);if(t&&typeof t=="object")for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o={};for(let[s,i]of Object.entries(r)){let a=String(s).toLowerCase();typeof i=="string"&&i.length>0&&(o[a]=i.trim())}nn.set(n,o)}}catch{}}function Zo(){L(ca.dirname(Nt));let e={};for(let[t,n]of nn)Object.entries(n).length>0&&(e[t]={...n});Xo.writeFileSync(Nt,JSON.stringify(e,null,2)+`
44
+ `,{mode:384})}function pa(){Vo||(da(),Vo=!0)}function ma(e){return ua.has(e.trim().toLowerCase())}function rn(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return Qo.test(n)?ma(n)?{ok:!1,error:`Reserved name: ${n}`}:{ok:!0,normalized:n}:{ok:!1,error:`Invalid name (use letters, digits, _ or -; max 32 chars): ${t}`}}function fa(e){let t=e.replace(/\r\n/g,`
45
+ `).replace(/\n/g," ").trim();return t?t.length>Yo?{ok:!1,error:`Body too long (max ${Yo} characters).`}:{ok:!0,body:t}:{ok:!1,error:"Body is empty."}}function on(e){pa();let t=nn.get(e);return t||(t={},nn.set(e,t)),t}function es(e){let t=on(e);return Object.entries(t).map(([n,r])=>({name:n,body:r})).sort((n,r)=>n.name.localeCompare(r.name))}function st(e,t){let n=t.trim().toLowerCase();return on(e)[n]}function er(e,t,n){let r=rn(t);if(!r.ok)throw new Error(r.error);let o=fa(n);if(!o.ok)throw new Error(o.error);let s=on(e);s[r.normalized]=o.body,Zo()}function ts(e,t){let n=t.trim().toLowerCase(),r=on(e);return n in r?(delete r[n],Zo(),!0):!1}function ns(e){let t=e.trim();return t.length>0&&!/\s/.test(t)&&Qo.test(t.toLowerCase())}import ga from"node:crypto";import nr from"node:fs";import ha from"node:path";var rr=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,or=new Set(["help","list","show","add","set","remove","rm","del","run","r"]),sn=new Map,rs=!1;function ya(){try{let e=nr.readFileSync(Bt,"utf8"),t=JSON.parse(e);if(t&&typeof t=="object")for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o={};for(let[s,i]of Object.entries(r)){let a=String(s).toLowerCase();i&&typeof i=="object"&&typeof i.command=="string"&&(o[a]=sr(i))}sn.set(n,o)}}catch{}}function sr(e){let t=typeof e.taskEnv=="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(e.taskEnv)?e.taskEnv:"OMNISH_TASK";return{command:String(e.command).trim(),taskEnv:t,label:typeof e.label=="string"?e.label.trim().slice(0,80):void 0,description:typeof e.description=="string"?e.description.trim().slice(0,200):void 0,category:typeof e.category=="string"?e.category.trim().slice(0,40):void 0,featured:typeof e.featured=="boolean"?e.featured:void 0,dangerous:typeof e.dangerous=="boolean"?e.dangerous:void 0}}function os(){L(ha.dirname(Bt));let e={};for(let[t,n]of sn)Object.entries(n).length>0&&(e[t]={...n});nr.writeFileSync(Bt,JSON.stringify(e,null,2)+`
46
+ `,{mode:384})}function wa(){rs||(ya(),rs=!0)}function ir(e){wa();let t=sn.get(e);return t||(t={},sn.set(e,t)),t}function ba(){try{let e=nr.readFileSync(_t,"utf8"),t=JSON.parse(e);if(!t||typeof t!="object")return{};let n={};for(let[r,o]of Object.entries(t)){let s=r.trim().toLowerCase();!rr.test(s)||or.has(s)||o&&typeof o=="object"&&typeof o.command=="string"&&(n[s]=sr(o))}return n}catch{return{}}}function ka(e){return{claude:{command:'claude -p "$OMNISH_TASK" --allowedTools all --dangerously-skip-permissions',taskEnv:"OMNISH_TASK",label:"Claude Code",description:"Anthropic Claude Code CLI (requires `claude` on PATH)",category:"agents",featured:!0,dangerous:e.recipesAllowDangerousBuiltins},codex:{command:'codex "$OMNISH_TASK"',taskEnv:"OMNISH_TASK",label:"Codex CLI",description:"OpenAI Codex CLI if installed; override in recipes.json",category:"agents",featured:!1},gemini:{command:'gemini -p "$OMNISH_TASK"',taskEnv:"OMNISH_TASK",label:"Gemini CLI",description:"Google Gemini CLI if installed; override in recipes.json",category:"agents",featured:!1},cursor:{command:"agent --yolo --force -p ```Before writing any code:\n1. Analyze the codebase and state your full implementation plan\n2. List every file you will touch\n3. Identify any risks or ambiguities\n4. Then execute the plan step by step, <task> $OMNISH_TASK </task>```",taskEnv:"OMNISH_TASK",label:"Cursor Agent",description:"Cursor Agent if installed; override in recipes.json",category:"agents",featured:!0}}}function tr(e,t,n){for(let[r,o]of Object.entries(t)){let s=r.toLowerCase();!rr.test(s)||or.has(s)||o.command.trim()&&e.set(s,{...o,name:s,source:n})}}function ss(e,t){let n=new Map;return tr(n,ka(t),"builtin"),tr(n,ba(),"global"),tr(n,ir(e),"peer"),n}function it(e,t,n){let r=n.trim().toLowerCase();return ss(e,t).get(r)}function an(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return rr.test(n)?or.has(n)?{ok:!1,error:`Reserved name: ${n}`}:{ok:!0,normalized:n}:{ok:!1,error:`Invalid name (use letters, digits, _ or -; max 32 chars): ${t}`}}function is(e,t){let n=e.replace(/\r\n/g,`
47
+ `).trim();return n?t>0&&n.length>t?{ok:!1,error:`Task too long (max ${t} characters).`}:{ok:!0,task:n}:{ok:!1,error:"Task is empty."}}function ar(e,t){return e.includes("$")?e.includes(t):!1}function Sa(e){let t=e.command.trim();if(!t)return{ok:!1,error:"Command is empty."};let n=e.taskEnv??"OMNISH_TASK";return/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)?ar(t,n)?{ok:!0}:{ok:!1,error:`Command must reference "$${n}" (or include $${n}) so the task is passed via the environment.`}:{ok:!1,error:"Invalid taskEnv (use letters, digits, _)."}}function lr(e,t,n){let r=an(t);if(!r.ok)throw new Error(r.error);let o=sr({...n,command:n.command}),s=Sa(o);if(!s.ok)throw new Error(s.error);let i=ir(e);i[r.normalized]=o,os()}function as(e,t){let n=t.trim().toLowerCase(),r=ir(e);return n in r?(delete r[n],os(),!0):!1}function ls(e,t){let n=[...ss(e,t).values()],r=n.filter(i=>i.featured).sort((i,a)=>i.name.localeCompare(a.name)),o=n.filter(i=>i.source==="peer").sort((i,a)=>i.name.localeCompare(a.name)),s=n.filter(i=>!i.featured&&i.source!=="peer").sort((i,a)=>i.name.localeCompare(a.name));return{featured:r,yours:o,more:s}}function cs(e){let t=ga.randomBytes(4).toString("hex");return`r-${e.replace(/[^a-zA-Z0-9_-]/g,"").slice(0,12)}-${t}`.slice(0,32)}import xa from"node:os";import*as ds from"node-pty";function va(e,t){return e.length<=t?e:`${e.slice(0,t)}
48
+ [...truncated]`}function $a(e){if(e===void 0||e===0)return null;let t=xa.constants.signals;for(let[n,r]of Object.entries(t))if(r===e)return n;return null}function us(e){try{process.platform==="win32"?e.kill():e.kill("SIGTERM")}catch{e.kill()}}function ln(e,t,n){return new Promise(r=>{let o=Date.now(),s=!1,i="",a=n.cwd,l=null,d=!1,c=null,u=null,m,f=w=>{if(d)return;d=!0,m!==void 0&&clearTimeout(m),c?.dispose(),c=null,r(w);let k=u;u=null,queueMicrotask(()=>k?.dispose())},y={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...a?{PWD:a}:{}};try{l=ds.spawn(e,["-c",t],{name:"xterm-256color",cols:120,rows:40,cwd:a,env:y})}catch(w){f({code:null,stdout:"",stderr:String(w),durationMs:Date.now()-o,timedOut:!1,signal:null});return}m=setTimeout(()=>{s=!0,l&&us(l)},n.timeoutMs),c=l.onData(w=>{i+=w,i.length>n.maxBytes&&(i=va(i,n.maxBytes),l&&us(l))}),u=l.onExit(w=>{f({code:w.exitCode,stdout:i,stderr:"",durationMs:Date.now()-o,timedOut:s,signal:$a(w.signal)})})})}import at from"node:fs";import pr from"node:os";import St from"node:path";import gs from"node:crypto";var ur="\u2063omnish/c v1",Ca=/([nlra])=([^\s\]]*)/g;function xe(e){return e.replace(/-/g,"").slice(0,8)}function cr(e){return e.replace(/[\s\]\r\n]/g,"_").slice(0,64)}function Ra(e){let t=cr(xe(e.nodeId)),n=cr(e.label||""),r=e.role==="primary"?"p":"s",o=cr(e.activeNodeId?xe(e.activeNodeId):"");return`${ur} [n=${t} l=${n} r=${r} a=${o}]`}function ps(e,t){let n=Ra(t);if(e.includes(n))return e;let r=e.replace(/\s+$/,"");return r.length===0?n:`${r}
48
49
 
49
- ${n}`}function Bo(e){if(!e||!e.includes(Hn))return null;let t=e.indexOf(Hn),n=e.slice(t),r=n.indexOf("["),o=n.indexOf("]");if(r<0||o<0||o<r)return null;let s=n.slice(r+1,o),i={};for(let l of s.matchAll(vi))i[l[1]]=l[2]??"";if(!i.n)return null;let a=i.r==="p"?"primary":"secondary";return{nodeId:i.n,label:i.l??"",role:a,activeNodeId:i.a??""}}var Ho=3,Ri="node-id",Mi="cluster-local.json",_o=8;function jo(){return pt.join(T,Mi)}function Dn(){return pt.join(T,Ri)}function fe(){P(T);let e=Dn();try{if(tt.existsSync(e)){let n=tt.readFileSync(e,"utf8").trim();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(n))return n}}catch{}let t=No.randomUUID();return tt.writeFileSync(e,`${t}
50
- `,{mode:384}),t}function Wo(){return{schemaVersion:Ho,updatedAt:new Date().toISOString(),peers:[],senderBindings:{}}}function Ci(e){if(!e||typeof e!="object")return{};let t={};for(let[n,r]of Object.entries(e)){if(!r||typeof r!="object")continue;let o=r;if(typeof o.nodeId!="string"||!o.nodeId)continue;let s=o.source==="config"?"config":"chat";t[n]={senderKey:typeof o.senderKey=="string"?o.senderKey:n,nodeId:o.nodeId,sinceIso:typeof o.sinceIso=="string"&&o.sinceIso?o.sinceIso:new Date(0).toISOString(),source:s}}return t}function H(){let e=jo();try{let t=tt.readFileSync(e,"utf8"),n=JSON.parse(t),r=Array.isArray(n.peers)?n.peers.filter(s=>typeof s=="object"&&s!==null&&typeof s.nodeId=="string"&&typeof s.label=="string").map(s=>({nodeId:s.nodeId,label:s.label,role:s.role==="primary"?"primary":"secondary",lastSeenIso:typeof s.lastSeenIso=="string"?s.lastSeenIso:new Date(0).toISOString()})):[],o=Ci(n.senderBindings);return{schemaVersion:Ho,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:new Date().toISOString(),peers:r,senderBindings:o}}catch{return Wo()}}function Ti(e,t){let n=pt.dirname(e);P(n);let r=`${JSON.stringify(t,null,2)}
51
- `,o=pt.join(n,`.${pt.basename(e)}.tmp.${process.pid}.${No.randomBytes(4).toString("hex")}`);tt.writeFileSync(o,r,{mode:384}),tt.renameSync(o,e)}function Gn(e){let t=jo(),n=Wo();for(let r=0;r<_o;r++){n=H(),e(n),n.updatedAt=new Date().toISOString();try{return Ti(t,n),n}catch{}}throw new Error(`Could not write cluster local state after ${_o} attempts: ${t}`)}function Do(e){return(e.clusterLabel??"").trim()||Wn.hostname()}function j(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Uo(e,t){let n=e.peers.findIndex(r=>r.nodeId===t.nodeId);n>=0?e.peers[n]=t:e.peers.push(t)}function mt(e){return{nodeId:be(fe()),label:Do(e),role:e.clusterRole,lastSeenIso:new Date().toISOString()}}function Go(e,t,n){let r=n.trim();if(!r)return{ok:!1,reason:"not-found"};let o=mt(t),s=[o];for(let l of e.peers)l.nodeId!==o.nodeId&&s.push(l);let i=r.toLowerCase();if(/^[0-9a-f]{8}$/i.test(r)){let l=s.find(u=>u.nodeId.toLowerCase()===i);if(l)return{ok:!0,peer:l}}let a=s.filter(l=>l.label.toLowerCase()===i);return a.length===1?{ok:!0,peer:a[0]}:a.length>1?{ok:!1,reason:"ambiguous-label",matches:a}:{ok:!1,reason:"not-found"}}function Re(e,t){let n=H(),r=n.senderBindings[t];if(r&&r.nodeId)return r;let o=e.clusterSenderBindings?.[t];if(typeof o=="string"&&o.trim()){let s=Go(n,e,o);if(s.ok)return{senderKey:t,nodeId:s.peer.nodeId,sinceIso:new Date(0).toISOString(),source:"config"}}return null}function Un(e,t,n="chat"){let r=x(),o=H(),s=Go(o,r,t);if(!s.ok)return{state:o,resolved:s};let i=new Date().toISOString();return{state:Gn(l=>{l.senderBindings[e]={senderKey:e,nodeId:s.peer.nodeId,sinceIso:i,source:n},Uo(l,{...s.peer,lastSeenIso:i})}),resolved:s}}function Ii(e){let t=null;return{state:Gn(r=>{r.senderBindings[e]&&(t=r.senderBindings[e]??null,delete r.senderBindings[e])}),removed:t}}function zo(e,t){let n=be(fe()),r=new Date().toISOString();return Gn(o=>{if(Uo(o,{nodeId:e.nodeId,label:e.label||e.nodeId,role:e.role,lastSeenIso:r}),e.nodeId!==n&&t&&e.activeNodeId){let s=o.senderBindings[t];(!s||s.nodeId!==e.activeNodeId)&&(o.senderBindings[t]={senderKey:t,nodeId:e.activeNodeId,sinceIso:r,source:"chat"})}})}function Jo(e,t){let n=Re(t,e);return n?n.nodeId===be(fe()):!1}function Ai(e,t){let n=mt(t).nodeId,r=new Set([n]);for(let s of e.peers)r.add(s.nodeId);return[...r].sort()[0]??n}function le(e,t){return Ai(e,t)===be(fe())}function Ut(e,t,n){let r=be(fe()),o=["*Computers*",""],s=n?Re(t,n):null;n&&(s?o.push(`Your binding: \`${s.nodeId}\` (${s.source})`):o.push("Your binding: (none \u2014 send /c use <label-or-id>)"),o.push(""));let i=new Map;i.set(r,mt(t));for(let l of e.peers)i.set(l.nodeId,l);let a=[...i.values()].sort((l,u)=>l.label.localeCompare(u.label));if(a.length===0)return o.push("(no peers observed yet \u2014 run /c status from this chat)"),o.join(`
52
- `);for(let l of a){let u=l.nodeId===r,d=[(s?l.nodeId===s.nodeId:!1)?"your binding":null,u?"you":null].filter(Boolean).join(", "),p=d?` (${d})`:"";o.push(`\u2022 *${l.label}*${p}
50
+ ${n}`}function ms(e){if(!e||!e.includes(ur))return null;let t=e.indexOf(ur),n=e.slice(t),r=n.indexOf("["),o=n.indexOf("]");if(r<0||o<0||o<r)return null;let s=n.slice(r+1,o),i={};for(let l of s.matchAll(Ca))i[l[1]]=l[2]??"";if(!i.n)return null;let a=i.r==="p"?"primary":"secondary";return{nodeId:i.n,label:i.l??"",role:a,activeNodeId:i.a??""}}var hs=3,Ma="node-id",Ta="cluster-local.json",fs=8;function ys(){return St.join(A,Ta)}function mr(){return St.join(A,Ma)}function be(){L(A);let e=mr();try{if(at.existsSync(e)){let n=at.readFileSync(e,"utf8").trim();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(n))return n}}catch{}let t=gs.randomUUID();return at.writeFileSync(e,`${t}
51
+ `,{mode:384}),t}function ws(){return{schemaVersion:hs,updatedAt:new Date().toISOString(),peers:[],senderBindings:{}}}function Ia(e){if(!e||typeof e!="object")return{};let t={};for(let[n,r]of Object.entries(e)){if(!r||typeof r!="object")continue;let o=r;if(typeof o.nodeId!="string"||!o.nodeId)continue;let s=o.source==="config"?"config":"chat";t[n]={senderKey:typeof o.senderKey=="string"?o.senderKey:n,nodeId:o.nodeId,sinceIso:typeof o.sinceIso=="string"&&o.sinceIso?o.sinceIso:new Date(0).toISOString(),source:s}}return t}function G(){let e=ys();try{let t=at.readFileSync(e,"utf8"),n=JSON.parse(t),r=Array.isArray(n.peers)?n.peers.filter(s=>typeof s=="object"&&s!==null&&typeof s.nodeId=="string"&&typeof s.label=="string").map(s=>({nodeId:s.nodeId,label:s.label,role:s.role==="primary"?"primary":"secondary",lastSeenIso:typeof s.lastSeenIso=="string"?s.lastSeenIso:new Date(0).toISOString()})):[],o=Ia(n.senderBindings);return{schemaVersion:hs,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:new Date().toISOString(),peers:r,senderBindings:o}}catch{return ws()}}function Aa(e,t){let n=St.dirname(e);L(n);let r=`${JSON.stringify(t,null,2)}
52
+ `,o=St.join(n,`.${St.basename(e)}.tmp.${process.pid}.${gs.randomBytes(4).toString("hex")}`);at.writeFileSync(o,r,{mode:384}),at.renameSync(o,e)}function gr(e){let t=ys(),n=ws();for(let r=0;r<fs;r++){n=G(),e(n),n.updatedAt=new Date().toISOString();try{return Aa(t,n),n}catch{}}throw new Error(`Could not write cluster local state after ${fs} attempts: ${t}`)}function bs(e){return(e.clusterLabel??"").trim()||pr.hostname()}function z(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function ks(e,t){let n=e.peers.findIndex(r=>r.nodeId===t.nodeId);n>=0?e.peers[n]=t:e.peers.push(t)}function xt(e){return{nodeId:xe(be()),label:bs(e),role:e.clusterRole,lastSeenIso:new Date().toISOString()}}function Ss(e,t,n){let r=n.trim();if(!r)return{ok:!1,reason:"not-found"};let o=xt(t),s=[o];for(let l of e.peers)l.nodeId!==o.nodeId&&s.push(l);let i=r.toLowerCase();if(/^[0-9a-f]{8}$/i.test(r)){let l=s.find(d=>d.nodeId.toLowerCase()===i);if(l)return{ok:!0,peer:l}}let a=s.filter(l=>l.label.toLowerCase()===i);return a.length===1?{ok:!0,peer:a[0]}:a.length>1?{ok:!1,reason:"ambiguous-label",matches:a}:{ok:!1,reason:"not-found"}}function Ae(e,t){let n=G(),r=n.senderBindings[t];if(r&&r.nodeId)return r;let o=e.clusterSenderBindings?.[t];if(typeof o=="string"&&o.trim()){let s=Ss(n,e,o);if(s.ok)return{senderKey:t,nodeId:s.peer.nodeId,sinceIso:new Date(0).toISOString(),source:"config"}}return null}function fr(e,t,n="chat"){let r=$(),o=G(),s=Ss(o,r,t);if(!s.ok)return{state:o,resolved:s};let i=new Date().toISOString();return{state:gr(l=>{l.senderBindings[e]={senderKey:e,nodeId:s.peer.nodeId,sinceIso:i,source:n},ks(l,{...s.peer,lastSeenIso:i})}),resolved:s}}function Ea(e){let t=null;return{state:gr(r=>{r.senderBindings[e]&&(t=r.senderBindings[e]??null,delete r.senderBindings[e])}),removed:t}}function xs(e,t){let n=xe(be()),r=new Date().toISOString();return gr(o=>{if(ks(o,{nodeId:e.nodeId,label:e.label||e.nodeId,role:e.role,lastSeenIso:r}),e.nodeId!==n&&t&&e.activeNodeId){let s=o.senderBindings[t];(!s||s.nodeId!==e.activeNodeId)&&(o.senderBindings[t]={senderKey:t,nodeId:e.activeNodeId,sinceIso:r,source:"chat"})}})}function vs(e,t){let n=Ae(t,e);return n?n.nodeId===xe(be()):!1}function Oa(e,t){let n=xt(t).nodeId,r=new Set([n]);for(let s of e.peers)r.add(s.nodeId);return[...r].sort()[0]??n}function me(e,t){return Oa(e,t)===xe(be())}function cn(e,t,n){let r=xe(be()),o=["*Computers*",""],s=n?Ae(t,n):null;n&&(s?o.push(`Your binding: \`${s.nodeId}\` (${s.source})`):o.push("Your binding: (none \u2014 send /c use <label-or-id>)"),o.push(""));let i=new Map;i.set(r,xt(t));for(let l of e.peers)i.set(l.nodeId,l);let a=[...i.values()].sort((l,d)=>l.label.localeCompare(d.label));if(a.length===0)return o.push("(no peers observed yet \u2014 run /c status from this chat)"),o.join(`
53
+ `);for(let l of a){let d=l.nodeId===r,u=[(s?l.nodeId===s.nodeId:!1)?"your binding":null,d?"you":null].filter(Boolean).join(", "),m=u?` (${u})`:"";o.push(`\u2022 *${l.label}*${m}
53
54
  id \`${l.nodeId}\` \xB7 role ${l.role}
54
55
  seen ${l.lastSeenIso}`)}return o.push(""),o.push(`Updated: ${e.updatedAt}`),o.join(`
55
- `)}function jn(e,t,n){let r=be(fe()),o=["<b>Computers</b>",""],s=n?Re(t,n):null;n&&(s?o.push(`Your binding: <code>${j(s.nodeId)}</code> (${j(s.source)})`):o.push("Your binding: (none \u2014 send /c use &lt;label-or-id&gt;)"),o.push(""));let i=new Map;i.set(r,mt(t));for(let l of e.peers)i.set(l.nodeId,l);let a=[...i.values()].sort((l,u)=>l.label.localeCompare(u.label));if(a.length===0)return o.push("(no peers observed yet \u2014 run /c status from this chat)"),o.join(`
56
- `);for(let l of a){let u=l.nodeId===r,d=[(s?l.nodeId===s.nodeId:!1)?"your binding":null,u?"you":null].filter(Boolean).join(", "),p=d?` (${j(d)})`:"";o.push(`\u2022 <b>${j(l.label)}</b>${p}<br/> id <code>${j(l.nodeId)}</code> \xB7 role ${j(l.role)}<br/> seen ${j(l.lastSeenIso)}`)}return o.push(""),o.push(`Updated: ${j(e.updatedAt)}`),o.join(`
57
- `)}function zn(e,t,n){return Ut(e,t,n??null).replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1")}function Jn(e,t){let n=fe(),r=be(n),o=H(),s=e.clusterRole,i=Do(e),a=t?Re(e,t):null,l=a?a.nodeId===r:!1,u=t?a?`your binding: ${a.nodeId} (${a.source}${l?", here":""})`:"your binding: (none)":"",c=["*This computer*","",`label: ${i}`,`node id: \`${r}\` (full id in ${Dn()})`,`host: ${Wn.hostname()}`,`clusterRole: ${s}`,u,`peers known: ${o.peers.length}`,`senderBindings (chat): ${Object.keys(o.senderBindings).length}`].filter(Boolean).join(`
58
- `),d=["<b>This computer</b>","",`label: ${j(i)}`,`node id: <code>${j(r)}</code> (full id in ${j(Dn())})`,`host: ${j(Wn.hostname())}`,`clusterRole: ${j(s)}`,t?j(u):"",`peers known: ${o.peers.length}`,`senderBindings (chat): ${Object.keys(o.senderBindings).length}`].filter(Boolean).join(`
59
- `);return{wa:c,tg:d}}function Ei(e){let t=e.clusterRole,n=["*Computers* (per-sender bindings)","","Each allowlisted phone picks one machine to talk to. Other senders are not affected.","Selection persists; defaults can be set in config (clusterSenderBindings).","","Shorthand: /pcs \u2026 \xB7 /c \u2026","","\u2022 /c use <label-or-id> \u2014 bind your messages to that machine","\u2022 /c here \u2014 bind your messages to THIS machine","\u2022 /c using \u2014 show your current binding","\u2022 /c unuse \u2014 clear your chat-set binding (config default still applies, if any)","\u2022 /c status \u2014 every online host replies with its own paragraph","\u2022 /c list \u2014 locally known roster (single responder)","\u2022 /c help \u2014 this help","",`clusterRole on this host: ${t}`].join(`
60
- `),r=["<b>Computers</b> (per-sender bindings)","","Each allowlisted phone picks one machine to talk to. Other senders are not affected.","Selection persists; defaults can be set in config (clusterSenderBindings).","","Shorthand: /pcs \u2026 \xB7 /c \u2026","","\u2022 /c use &lt;label-or-id&gt; \u2014 bind your messages to that machine","\u2022 /c here \u2014 bind your messages to THIS machine","\u2022 /c using \u2014 show your current binding","\u2022 /c unuse \u2014 clear your chat-set binding","\u2022 /c status \u2014 every online host replies with its own paragraph","\u2022 /c list \u2014 locally known roster (single responder)","\u2022 /c help \u2014 this help","",`clusterRole on this host: ${j(t)}`].join(`
61
- `);return D(n,r)}function Oi(e,t){if(t.ok)return m("");if(t.reason==="ambiguous-label"){let n=(t.matches??[]).map(r=>`\`${r.nodeId}\` (${r.label})`).join(", ");return m(`Label "${e}" matches multiple machines: ${n}. Use the 8-character id with /c use <id>.`)}return m(`No machine matches "${e}". Send /c list to see ids and labels, or /c status to refresh the roster.`)}function qo(e,t,n){let r=t.trim().split(/\s+/),o=r[0]?.toLowerCase()??"";if(!o||o==="help"){if(!e.clusterEnabled&&o!=="help"){let l=H();return le(l,e)?m("Cluster is disabled. Enable with: /config set clusterEnabled true (then /c use <label-or-id>). /c help for the new commands."):null}let a=H();return le(a,e)?Ei(e):null}let s=be(fe());if(o==="use"||o==="bind"){let a=r.slice(1).join(" ").trim();if(!n){let C=H();return le(C,e)?m("/c use is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}if(!a){let C=H();return le(C,e)?m("Usage: /c use <label-or-id>"):null}e.clusterEnabled||Tt(!0);let u=H().senderBindings[n]??null,{state:c,resolved:d}=Un(n,a,"chat");if(!d.ok)return le(c,e)?Oi(a,d):null;let p=d.peer.nodeId===s,f=u?u.nodeId===s:!1;if(!p)return null;let w=[`*Bound to ${d.peer.label}*`,`id \`${d.peer.nodeId}\``,"","Your messages now route to this machine. Other senders are not affected.","",Ut(c,e,n)].join(`
62
- `),M=[`<b>Bound to ${j(d.peer.label)}</b>`,`id <code>${j(d.peer.nodeId)}</code>`,"","Your messages now route to this machine. Other senders are not affected.","",jn(c,e,n)].join(`
63
- `);return D(w,M)}if(o==="here"||o==="take"){if(!n){let d=H();return le(d,e)?m("/c here is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}e.clusterEnabled||Tt(!0);let{state:a,resolved:l}=Un(n,s,"chat");if(!l.ok)return le(a,e)?m("Could not bind to this machine."):null;let u=["*Bound to this machine.*","","Your messages now route here. Other senders are not affected.","",Ut(a,e,n)].join(`
64
- `),c=["<b>Bound to this machine.</b>","","Your messages now route here. Other senders are not affected.","",jn(a,e,n)].join(`
65
- `);return D(u,c)}if(o==="using"){if(!n){let u=H();return le(u,e)?m("/c using is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}let a=Re(e,n);if(a){if(a.nodeId!==s)return null;let d=[...H().peers,mt(e)].find(w=>w.nodeId===a.nodeId)?.label??"(unknown label)",p=[`*Bound to ${d}*`,`id \`${a.nodeId}\` \xB7 source ${a.source}`,a.source==="chat"?`since ${a.sinceIso}`:"(from config)"].join(`
66
- `),f=[`<b>Bound to ${j(d)}</b>`,`id <code>${j(a.nodeId)}</code> \xB7 source ${j(a.source)}`,a.source==="chat"?`since ${j(a.sinceIso)}`:"(from config)"].join(`
67
- `);return D(p,f)}let l=H();return le(l,e)?m("You are not bound to any machine. Send /c use <label-or-id> to bind, or set a default in config.json (clusterSenderBindings)."):null}if(o==="unuse"||o==="unbind"||o==="release"){if(!n){let p=H();return le(p,e)?m("/c unuse is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}let l=H().senderBindings[n]??null,{state:u}=Ii(n);if(l){if(l.nodeId!==s)return null}else if(!le(u,e))return null;let c=Re(e,n),d=c?`
56
+ `)}function dr(e,t,n){let r=xe(be()),o=["<b>Computers</b>",""],s=n?Ae(t,n):null;n&&(s?o.push(`Your binding: <code>${z(s.nodeId)}</code> (${z(s.source)})`):o.push("Your binding: (none \u2014 send /c use &lt;label-or-id&gt;)"),o.push(""));let i=new Map;i.set(r,xt(t));for(let l of e.peers)i.set(l.nodeId,l);let a=[...i.values()].sort((l,d)=>l.label.localeCompare(d.label));if(a.length===0)return o.push("(no peers observed yet \u2014 run /c status from this chat)"),o.join(`
57
+ `);for(let l of a){let d=l.nodeId===r,u=[(s?l.nodeId===s.nodeId:!1)?"your binding":null,d?"you":null].filter(Boolean).join(", "),m=u?` (${z(u)})`:"";o.push(`\u2022 <b>${z(l.label)}</b>${m}<br/> id <code>${z(l.nodeId)}</code> \xB7 role ${z(l.role)}<br/> seen ${z(l.lastSeenIso)}`)}return o.push(""),o.push(`Updated: ${z(e.updatedAt)}`),o.join(`
58
+ `)}function hr(e,t,n){return cn(e,t,n??null).replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1")}function yr(e,t){let n=be(),r=xe(n),o=G(),s=e.clusterRole,i=bs(e),a=t?Ae(e,t):null,l=a?a.nodeId===r:!1,d=t?a?`your binding: ${a.nodeId} (${a.source}${l?", here":""})`:"your binding: (none)":"",c=["*This computer*","",`label: ${i}`,`node id: \`${r}\` (full id in ${mr()})`,`host: ${pr.hostname()}`,`clusterRole: ${s}`,d,`peers known: ${o.peers.length}`,`senderBindings (chat): ${Object.keys(o.senderBindings).length}`].filter(Boolean).join(`
59
+ `),u=["<b>This computer</b>","",`label: ${z(i)}`,`node id: <code>${z(r)}</code> (full id in ${z(mr())})`,`host: ${z(pr.hostname())}`,`clusterRole: ${z(s)}`,t?z(d):"",`peers known: ${o.peers.length}`,`senderBindings (chat): ${Object.keys(o.senderBindings).length}`].filter(Boolean).join(`
60
+ `);return{wa:c,tg:u}}function La(e){let t=e.clusterRole,n=["*Computers* (per-sender bindings)","","Each allowlisted phone picks one machine to talk to. Other senders are not affected.","Selection persists; defaults can be set in config (clusterSenderBindings).","","Shorthand: /pcs \u2026 \xB7 /c \u2026","","\u2022 /c use <label-or-id> \u2014 bind your messages to that machine","\u2022 /c here \u2014 bind your messages to THIS machine","\u2022 /c using \u2014 show your current binding","\u2022 /c unuse \u2014 clear your chat-set binding (config default still applies, if any)","\u2022 /c status \u2014 every online host replies with its own paragraph","\u2022 /c list \u2014 locally known roster (single responder)","\u2022 /c help \u2014 this help","",`clusterRole on this host: ${t}`].join(`
61
+ `),r=["<b>Computers</b> (per-sender bindings)","","Each allowlisted phone picks one machine to talk to. Other senders are not affected.","Selection persists; defaults can be set in config (clusterSenderBindings).","","Shorthand: /pcs \u2026 \xB7 /c \u2026","","\u2022 /c use &lt;label-or-id&gt; \u2014 bind your messages to that machine","\u2022 /c here \u2014 bind your messages to THIS machine","\u2022 /c using \u2014 show your current binding","\u2022 /c unuse \u2014 clear your chat-set binding","\u2022 /c status \u2014 every online host replies with its own paragraph","\u2022 /c list \u2014 locally known roster (single responder)","\u2022 /c help \u2014 this help","",`clusterRole on this host: ${z(t)}`].join(`
62
+ `);return J(n,r)}function Pa(e,t){if(t.ok)return p("");if(t.reason==="ambiguous-label"){let n=(t.matches??[]).map(r=>`\`${r.nodeId}\` (${r.label})`).join(", ");return p(`Label "${e}" matches multiple machines: ${n}. Use the 8-character id with /c use <id>.`)}return p(`No machine matches "${e}". Send /c list to see ids and labels, or /c status to refresh the roster.`)}function $s(e,t,n){let r=t.trim().split(/\s+/),o=r[0]?.toLowerCase()??"";if(!o||o==="help"){if(!e.clusterEnabled&&o!=="help"){let l=G();return me(l,e)?p("Cluster is disabled. Enable with: /config set clusterEnabled true (then /c use <label-or-id>). /c help for the new commands."):null}let a=G();return me(a,e)?La(e):null}let s=xe(be());if(o==="use"||o==="bind"){let a=r.slice(1).join(" ").trim();if(!n){let k=G();return me(k,e)?p("/c use is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}if(!a){let k=G();return me(k,e)?p("Usage: /c use <label-or-id>"):null}e.clusterEnabled||Jt(!0);let d=G().senderBindings[n]??null,{state:c,resolved:u}=fr(n,a,"chat");if(!u.ok)return me(c,e)?Pa(a,u):null;let m=u.peer.nodeId===s,f=d?d.nodeId===s:!1;if(!m)return null;let y=[`*Bound to ${u.peer.label}*`,`id \`${u.peer.nodeId}\``,"","Your messages now route to this machine. Other senders are not affected.","",cn(c,e,n)].join(`
63
+ `),w=[`<b>Bound to ${z(u.peer.label)}</b>`,`id <code>${z(u.peer.nodeId)}</code>`,"","Your messages now route to this machine. Other senders are not affected.","",dr(c,e,n)].join(`
64
+ `);return J(y,w)}if(o==="here"||o==="take"){if(!n){let u=G();return me(u,e)?p("/c here is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}e.clusterEnabled||Jt(!0);let{state:a,resolved:l}=fr(n,s,"chat");if(!l.ok)return me(a,e)?p("Could not bind to this machine."):null;let d=["*Bound to this machine.*","","Your messages now route here. Other senders are not affected.","",cn(a,e,n)].join(`
65
+ `),c=["<b>Bound to this machine.</b>","","Your messages now route here. Other senders are not affected.","",dr(a,e,n)].join(`
66
+ `);return J(d,c)}if(o==="using"){if(!n){let d=G();return me(d,e)?p("/c using is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}let a=Ae(e,n);if(a){if(a.nodeId!==s)return null;let u=[...G().peers,xt(e)].find(y=>y.nodeId===a.nodeId)?.label??"(unknown label)",m=[`*Bound to ${u}*`,`id \`${a.nodeId}\` \xB7 source ${a.source}`,a.source==="chat"?`since ${a.sinceIso}`:"(from config)"].join(`
67
+ `),f=[`<b>Bound to ${z(u)}</b>`,`id <code>${z(a.nodeId)}</code> \xB7 source ${z(a.source)}`,a.source==="chat"?`since ${z(a.sinceIso)}`:"(from config)"].join(`
68
+ `);return J(m,f)}let l=G();return me(l,e)?p("You are not bound to any machine. Send /c use <label-or-id> to bind, or set a default in config.json (clusterSenderBindings)."):null}if(o==="unuse"||o==="unbind"||o==="release"){if(!n){let m=G();return me(m,e)?p("/c unuse is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}let l=G().senderBindings[n]??null,{state:d}=Ea(n);if(l){if(l.nodeId!==s)return null}else if(!me(d,e))return null;let c=Ae(e,n),u=c?`
68
69
  Config default still applies: \`${c.nodeId}\`.`:`
69
- No config default is set; nobody will answer until you /c use <label-or-id>.`;return m(`Cleared your chat binding.${d}`)}if(o==="step-down"||o==="stepdown"){let a=H();return le(a,e)?m("/c step-down is no longer used. The cluster is per-sender: send /c unuse to clear your binding."):null}if(o==="status"){let a=Jn(e,n);return D(a.wa,a.tg)}if(o==="list"){let a=H(),l=n?Re(e,n):null;if(l){if(l.nodeId!==s)return null}else if(!le(a,e))return null;return D(Ut(a,e,n??null),jn(a,e,n??null))}let i=H();return le(i,e)?m(`Unknown /c subcommand "${o}". Try /c help`):null}function Yo(e,t){return Tt(!0),Un(e,t,"chat")}function re(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function qn(e){let t=e.trim();return t?t.length<=8?"(set)":`${t.slice(0,4)}\u2026${t.slice(-4)}`:"(empty)"}function Li(e){let t=e.trim();return(t.startsWith('"')&&t.endsWith('"')&&t.length>=2||t.startsWith("'")&&t.endsWith("'")&&t.length>=2)&&(t=t.slice(1,-1)),t}function Gt(e){let t=e.trim().toLowerCase();return t==="true"||t==="1"||t==="yes"||t==="on"?!0:t==="false"||t==="0"||t==="no"||t==="off"?!1:null}var Ko=new Set(["downloads","omnishData","sessionCwd","processCwd","fixed"]),zt=["gatewayMode","clusterEnabled","clusterRole","clusterLabel","clusterSenderBindings","commandPrefix","syncTimeoutMs","syncMaxBytes","jobLogTailLines","shell","appsCols","appsRows","appsFlushMs","appsMinIntervalMs","appsMaxFlushBytes","appsMaxSessions","appsMaxSessionsTotal","appsMaxWaChars","appsLogTailLines","appsSubmitDelayMs","appsClearInput","appsClearInputDelayMs","appsClearInputSequence","fileSendMaxBytes","fileReceiveMaxBytes","fileInboxSubdir","fileReceiveRootMode","fileReceiveRootPath","recipesAllowDangerousBuiltins","recipesMaxTaskChars","telegramBotToken","serviceInstallFromChat"];function Vo(e){return zt.includes(e)}function Pi(e){let t=ae(e);return["*Config* (secrets masked)","",`gatewayMode: ${e.gatewayMode}`,`commandPrefix: ${e.commandPrefix}`,`shell: ${e.shell}`,`syncTimeoutMs: ${e.syncTimeoutMs}`,`syncMaxBytes: ${e.syncMaxBytes}`,`jobLogTailLines: ${e.jobLogTailLines}`,"","*Cluster*",`clusterEnabled: ${e.clusterEnabled}`,`clusterRole: ${e.clusterRole}`,`clusterLabel: ${e.clusterLabel||"(hostname)"}`,`clusterSenderBindings: ${Object.keys(e.clusterSenderBindings??{}).length} entries`,"","*Telegram*",`telegramBotToken: ${qn(t)}`,`telegramAllowFrom: ${e.telegramAllowFrom.length} entries`,"","*WhatsApp allowFrom*",`${e.allowFrom.length} entries`,"","*Apps*",`appsCols \xD7 appsRows: ${e.appsCols}\xD7${e.appsRows}`,`appsFlushMs / appsMinIntervalMs: ${e.appsFlushMs} / ${e.appsMinIntervalMs}`,`appsMaxFlushBytes: ${e.appsMaxFlushBytes}`,`appsMaxSessions / total: ${e.appsMaxSessions} / ${e.appsMaxSessionsTotal}`,`appsMaxWaChars: ${e.appsMaxWaChars}`,`appsLogTailLines: ${e.appsLogTailLines}`,`appsSubmitDelayMs: ${e.appsSubmitDelayMs}`,`appsClearInput: ${e.appsClearInput}`,`appsClearInputDelayMs: ${e.appsClearInputDelayMs}`,`appsClearInputSequence: ${e.appsClearInputSequence}`,"","*Files*",`fileSendMaxBytes / fileReceiveMaxBytes: ${e.fileSendMaxBytes} / ${e.fileReceiveMaxBytes}`,`fileInboxSubdir: ${e.fileInboxSubdir}`,`fileReceiveRootMode: ${e.fileReceiveRootMode}`,`fileReceiveRootPath: ${e.fileReceiveRootPath||"(empty)"}`,"","*Recipes*",`recipesAllowDangerousBuiltins: ${e.recipesAllowDangerousBuiltins}`,`recipesMaxTaskChars: ${e.recipesMaxTaskChars}`,"","*Service (chat)*",`serviceInstallFromChat: ${e.serviceInstallFromChat}`,"",`File: ${v}`].join(`
70
- `)}function Fi(e){let t=ae(e);return["<b>Config</b> (secrets masked)","",`<b>gatewayMode</b> ${re(e.gatewayMode)}`,`<b>commandPrefix</b> ${re(e.commandPrefix)}`,`<b>shell</b> ${re(e.shell)}`,`<b>syncTimeoutMs</b> ${e.syncTimeoutMs}`,`<b>syncMaxBytes</b> ${e.syncMaxBytes}`,`<b>jobLogTailLines</b> ${e.jobLogTailLines}`,"","<b>Cluster</b>",`clusterEnabled: ${e.clusterEnabled} \xB7 clusterRole: ${re(e.clusterRole)}`,`clusterLabel: ${re(e.clusterLabel||"(hostname)")}`,`clusterSenderBindings: ${Object.keys(e.clusterSenderBindings??{}).length} entries`,"","<b>Telegram</b>",`telegramBotToken: ${re(qn(t))}`,`telegramAllowFrom: ${e.telegramAllowFrom.length} entries`,"",`<b>WhatsApp allowFrom</b> ${e.allowFrom.length} entries`,"","<b>Apps</b>",`${e.appsCols}\xD7${e.appsRows} flush ${e.appsFlushMs}/${e.appsMinIntervalMs} ms \u2026`,"","<b>Files</b>",`${re(e.fileReceiveRootMode)} \xB7 inbox ${re(e.fileInboxSubdir)}`,"","<b>Service (chat)</b>",`serviceInstallFromChat: ${e.serviceInstallFromChat}`,"",`<code>${re(v)}</code>`].join(`
71
- `)}function Qo(e,t){if(!Vo(t))return null;let n=t;if(n==="telegramBotToken")return`telegramBotToken: ${qn(ae(e))}`;let r=e[n];return`${t}: ${typeof r=="object"?JSON.stringify(r):String(r)}`}function Bi(e,t){let n=Qo(e,t);if(!n)return null;let r=n.split(": ");return r.length<2?re(n):`<b>${re(r[0])}</b> ${re(r.slice(1).join(": "))}`}function _i(e,t){let n=Li(t),r=!1,o=!1,s=!1;if(e==="telegramBotToken"){if(!Ge(n))throw new Error("Invalid bot token format (expect digits:secret from BotFather).");return ze(n),r=!0,s=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s}}let i=x();switch(e){case"gatewayMode":{let a=Mt(n);if(!a)throw new Error("gatewayMode: use whatsapp | telegram | both (or wa, tg, b)");i.gatewayMode=a,r=!0;break}case"clusterEnabled":{let a=Gt(n);if(a===null)throw new Error("clusterEnabled: true or false");i.clusterEnabled=a;break}case"clusterRole":{let a=n.trim().toLowerCase();if(a!=="primary"&&a!=="secondary")throw new Error("clusterRole: primary | secondary");i.clusterRole=a;break}case"clusterLabel":i.clusterLabel=n.trim().slice(0,128);break;case"clusterSenderBindings":{let a=n.trim();if(a===""||a==="{}"||a.toLowerCase()==="clear"){i.clusterSenderBindings={};break}let l;try{l=JSON.parse(a)}catch{throw new Error('clusterSenderBindings: pass a JSON object, e.g. {"wa:+15551234567":"workshop-box"}')}if(!l||typeof l!="object"||Array.isArray(l))throw new Error("clusterSenderBindings must be a JSON object of sender \u2192 label/id");let u={};for(let[c,d]of Object.entries(l)){if(typeof d!="string"||!d.trim())throw new Error(`clusterSenderBindings.${c}: value must be a non-empty string`);u[c]=d.trim()}i.clusterSenderBindings=u;break}case"commandPrefix":if(!n.trim())throw new Error("commandPrefix cannot be empty");i.commandPrefix=n.trim().slice(0,32);break;case"syncTimeoutMs":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<=0)throw new Error("syncTimeoutMs: positive integer (ms)");i.syncTimeoutMs=a;break}case"syncMaxBytes":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<=0)throw new Error("syncMaxBytes: positive integer");i.syncMaxBytes=a;break}case"jobLogTailLines":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<=0)throw new Error("jobLogTailLines: positive integer");i.jobLogTailLines=a;break}case"shell":if(!n.trim())throw new Error("shell: non-empty path");i.shell=n.trim().slice(0,4096),o=!0;break;case"appsCols":case"appsRows":case"appsFlushMs":case"appsMinIntervalMs":case"appsMaxFlushBytes":case"appsMaxSessions":case"appsMaxSessionsTotal":case"appsMaxWaChars":case"appsLogTailLines":case"appsSubmitDelayMs":case"appsClearInputDelayMs":case"recipesMaxTaskChars":case"fileSendMaxBytes":case"fileReceiveMaxBytes":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<0)throw new Error(`${e}: non-negative integer`);i[e]=a;break}case"appsClearInput":{let a=Gt(n);if(a===null)throw new Error("appsClearInput: true or false");i.appsClearInput=a;break}case"appsClearInputSequence":i.appsClearInputSequence=n.trim().slice(0,200);break;case"fileInboxSubdir":i.fileInboxSubdir=n.trim().slice(0,80);break;case"fileReceiveRootMode":{let a=n.trim();if(!Ko.has(a))throw new Error(`fileReceiveRootMode: ${[...Ko].join(" | ")}`);i.fileReceiveRootMode=a;break}case"fileReceiveRootPath":i.fileReceiveRootPath=n.trim().slice(0,4096);break;case"recipesAllowDangerousBuiltins":{let a=Gt(n);if(a===null)throw new Error("recipesAllowDangerousBuiltins: true or false");i.recipesAllowDangerousBuiltins=a;break}case"serviceInstallFromChat":{let a=Gt(n);if(a===null)throw new Error("serviceInstallFromChat: true or false");i.serviceInstallFromChat=a;break}}return Ce(i),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}async function Zo(e,t){let n=e.trim(),r=n.toLowerCase();if(!n||r==="help")return E(Gr());if(r==="keys"||r==="help keys")return m(["*Configurable keys* (/config set)","",zt.join(", "),"","Examples:","/config set clusterLabel work-laptop",'/config set fileReceiveRootPath "/path/with spaces"',"/config set gatewayMode both"].join(`
72
- `));if(r==="show"){let i=x();return D(Pi(i),Fi(i))}let o=n.match(/^get\s+(\S+)\s*$/i);if(o){let i=o[1],a=x(),l=Qo(a,i);if(!l)return m(`Unknown key "${i}". /config keys`);let u=Bi(a,i);return D(`${l}
70
+ No config default is set; nobody will answer until you /c use <label-or-id>.`;return p(`Cleared your chat binding.${u}`)}if(o==="step-down"||o==="stepdown"){let a=G();return me(a,e)?p("/c step-down is no longer used. The cluster is per-sender: send /c unuse to clear your binding."):null}if(o==="status"){let a=yr(e,n);return J(a.wa,a.tg)}if(o==="list"){let a=G(),l=n?Ae(e,n):null;if(l){if(l.nodeId!==s)return null}else if(!me(a,e))return null;return J(cn(a,e,n??null),dr(a,e,n??null))}let i=G();return me(i,e)?p(`Unknown /c subcommand "${o}". Try /c help`):null}function Cs(e,t){return Jt(!0),fr(e,t,"chat")}function ie(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function wr(e){let t=e.trim();return t?t.length<=8?"(set)":`${t.slice(0,4)}\u2026${t.slice(-4)}`:"(empty)"}function Fa(e){let t=e.trim();return(t.startsWith('"')&&t.endsWith('"')&&t.length>=2||t.startsWith("'")&&t.endsWith("'")&&t.length>=2)&&(t=t.slice(1,-1)),t}function vt(e){let t=e.trim().toLowerCase();return t==="true"||t==="1"||t==="yes"||t==="on"?!0:t==="false"||t==="0"||t==="no"||t==="off"?!1:null}var Rs=new Set(["downloads","omnishData","sessionCwd","processCwd","fixed"]),un=["gatewayMode","clusterEnabled","clusterRole","clusterLabel","clusterSenderBindings","commandPrefix","syncTimeoutMs","syncMaxBytes","jobLogTailLines","shell","appsCols","appsRows","appsFlushMs","appsMinIntervalMs","appsMaxFlushBytes","appsMaxSessions","appsMaxSessionsTotal","appsMaxWaChars","appsLogTailLines","appsSubmitDelayMs","appsClearInput","appsClearInputDelayMs","appsClearInputSequence","fileSendMaxBytes","fileReceiveMaxBytes","fileInboxSubdir","fileReceiveRootMode","fileReceiveRootPath","recipesAllowDangerousBuiltins","recipesMaxTaskChars","telegramBotToken","serviceInstallFromChat","updateCheckEnabled","updateCheckIntervalMs","updateCheckPackageName","updateInfoUrl"];function Ms(e){return un.includes(e)}function Na(e){let t=pe(e);return["*Config* (secrets masked)","",`gatewayMode: ${e.gatewayMode}`,`commandPrefix: ${e.commandPrefix}`,`shell: ${e.shell}`,`syncTimeoutMs: ${e.syncTimeoutMs}`,`syncMaxBytes: ${e.syncMaxBytes}`,`jobLogTailLines: ${e.jobLogTailLines}`,"","*Cluster*",`clusterEnabled: ${e.clusterEnabled}`,`clusterRole: ${e.clusterRole}`,`clusterLabel: ${e.clusterLabel||"(hostname)"}`,`clusterSenderBindings: ${Object.keys(e.clusterSenderBindings??{}).length} entries`,"","*Telegram*",`telegramBotToken: ${wr(t)}`,`telegramAllowFrom: ${e.telegramAllowFrom.length} entries`,"","*WhatsApp allowFrom*",`${e.allowFrom.length} entries`,"","*Apps*",`appsCols \xD7 appsRows: ${e.appsCols}\xD7${e.appsRows}`,`appsFlushMs / appsMinIntervalMs: ${e.appsFlushMs} / ${e.appsMinIntervalMs}`,`appsMaxFlushBytes: ${e.appsMaxFlushBytes}`,`appsMaxSessions / total: ${e.appsMaxSessions} / ${e.appsMaxSessionsTotal}`,`appsMaxWaChars: ${e.appsMaxWaChars}`,`appsLogTailLines: ${e.appsLogTailLines}`,`appsSubmitDelayMs: ${e.appsSubmitDelayMs}`,`appsClearInput: ${e.appsClearInput}`,`appsClearInputDelayMs: ${e.appsClearInputDelayMs}`,`appsClearInputSequence: ${e.appsClearInputSequence}`,"","*Files*",`fileSendMaxBytes / fileReceiveMaxBytes: ${e.fileSendMaxBytes} / ${e.fileReceiveMaxBytes}`,`fileInboxSubdir: ${e.fileInboxSubdir}`,`fileReceiveRootMode: ${e.fileReceiveRootMode}`,`fileReceiveRootPath: ${e.fileReceiveRootPath||"(empty)"}`,"","*Recipes*",`recipesAllowDangerousBuiltins: ${e.recipesAllowDangerousBuiltins}`,`recipesMaxTaskChars: ${e.recipesMaxTaskChars}`,"","*Service (chat)*",`serviceInstallFromChat: ${e.serviceInstallFromChat}`,"","*Updates (optional)*",`updateCheckEnabled: ${e.updateCheckEnabled}`,`updateCheckIntervalMs: ${e.updateCheckIntervalMs}`,`updateCheckPackageName: ${e.updateCheckPackageName}`,`updateInfoUrl: ${e.updateInfoUrl?"(set)":"(empty)"}`,"",`File: ${T}`].join(`
71
+ `)}function _a(e){let t=pe(e);return["<b>Config</b> (secrets masked)","",`<b>gatewayMode</b> ${ie(e.gatewayMode)}`,`<b>commandPrefix</b> ${ie(e.commandPrefix)}`,`<b>shell</b> ${ie(e.shell)}`,`<b>syncTimeoutMs</b> ${e.syncTimeoutMs}`,`<b>syncMaxBytes</b> ${e.syncMaxBytes}`,`<b>jobLogTailLines</b> ${e.jobLogTailLines}`,"","<b>Cluster</b>",`clusterEnabled: ${e.clusterEnabled} \xB7 clusterRole: ${ie(e.clusterRole)}`,`clusterLabel: ${ie(e.clusterLabel||"(hostname)")}`,`clusterSenderBindings: ${Object.keys(e.clusterSenderBindings??{}).length} entries`,"","<b>Telegram</b>",`telegramBotToken: ${ie(wr(t))}`,`telegramAllowFrom: ${e.telegramAllowFrom.length} entries`,"",`<b>WhatsApp allowFrom</b> ${e.allowFrom.length} entries`,"","<b>Apps</b>",`${e.appsCols}\xD7${e.appsRows} flush ${e.appsFlushMs}/${e.appsMinIntervalMs} ms \u2026`,"","<b>Files</b>",`${ie(e.fileReceiveRootMode)} \xB7 inbox ${ie(e.fileInboxSubdir)}`,"","<b>Service (chat)</b>",`serviceInstallFromChat: ${e.serviceInstallFromChat}`,"","<b>Updates (optional)</b>",`updateCheckEnabled: ${e.updateCheckEnabled} \xB7 interval ms: ${e.updateCheckIntervalMs}`,`package: <code>${ie(e.updateCheckPackageName)}</code> \xB7 info URL: ${e.updateInfoUrl?"set":"empty"}`,"",`<code>${ie(T)}</code>`].join(`
72
+ `)}function Ts(e,t){if(!Ms(t))return null;let n=t;if(n==="telegramBotToken")return`telegramBotToken: ${wr(pe(e))}`;let r=e[n];return`${t}: ${typeof r=="object"?JSON.stringify(r):String(r)}`}function Ba(e,t){let n=Ts(e,t);if(!n)return null;let r=n.split(": ");return r.length<2?ie(n):`<b>${ie(r[0])}</b> ${ie(r.slice(1).join(": "))}`}function Da(e,t){let n=Fa(t),r=!1,o=!1,s=!1;if(e==="telegramBotToken"){if(!Xe(n))throw new Error("Invalid bot token format (expect digits:secret from BotFather).");return Qe(n),r=!0,s=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s}}let i=$();switch(e){case"gatewayMode":{let a=Gt(n);if(!a)throw new Error("gatewayMode: use whatsapp | telegram | both (or wa, tg, b)");i.gatewayMode=a,r=!0;break}case"clusterEnabled":{let a=vt(n);if(a===null)throw new Error("clusterEnabled: true or false");i.clusterEnabled=a;break}case"clusterRole":{let a=n.trim().toLowerCase();if(a!=="primary"&&a!=="secondary")throw new Error("clusterRole: primary | secondary");i.clusterRole=a;break}case"clusterLabel":i.clusterLabel=n.trim().slice(0,128);break;case"clusterSenderBindings":{let a=n.trim();if(a===""||a==="{}"||a.toLowerCase()==="clear"){i.clusterSenderBindings={};break}let l;try{l=JSON.parse(a)}catch{throw new Error('clusterSenderBindings: pass a JSON object, e.g. {"wa:+15551234567":"workshop-box"}')}if(!l||typeof l!="object"||Array.isArray(l))throw new Error("clusterSenderBindings must be a JSON object of sender \u2192 label/id");let d={};for(let[c,u]of Object.entries(l)){if(typeof u!="string"||!u.trim())throw new Error(`clusterSenderBindings.${c}: value must be a non-empty string`);d[c]=u.trim()}i.clusterSenderBindings=d;break}case"commandPrefix":if(!n.trim())throw new Error("commandPrefix cannot be empty");i.commandPrefix=n.trim().slice(0,32);break;case"syncTimeoutMs":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<=0)throw new Error("syncTimeoutMs: positive integer (ms)");i.syncTimeoutMs=a;break}case"syncMaxBytes":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<=0)throw new Error("syncMaxBytes: positive integer");i.syncMaxBytes=a;break}case"jobLogTailLines":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<=0)throw new Error("jobLogTailLines: positive integer");i.jobLogTailLines=a;break}case"shell":if(!n.trim())throw new Error("shell: non-empty path");i.shell=n.trim().slice(0,4096),o=!0;break;case"appsCols":case"appsRows":case"appsFlushMs":case"appsMinIntervalMs":case"appsMaxFlushBytes":case"appsMaxSessions":case"appsMaxSessionsTotal":case"appsMaxWaChars":case"appsLogTailLines":case"appsSubmitDelayMs":case"appsClearInputDelayMs":case"recipesMaxTaskChars":case"fileSendMaxBytes":case"fileReceiveMaxBytes":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<0)throw new Error(`${e}: non-negative integer`);i[e]=a;break}case"appsClearInput":{let a=vt(n);if(a===null)throw new Error("appsClearInput: true or false");i.appsClearInput=a;break}case"appsClearInputSequence":i.appsClearInputSequence=n.trim().slice(0,200);break;case"fileInboxSubdir":i.fileInboxSubdir=n.trim().slice(0,80);break;case"fileReceiveRootMode":{let a=n.trim();if(!Rs.has(a))throw new Error(`fileReceiveRootMode: ${[...Rs].join(" | ")}`);i.fileReceiveRootMode=a;break}case"fileReceiveRootPath":i.fileReceiveRootPath=n.trim().slice(0,4096);break;case"recipesAllowDangerousBuiltins":{let a=vt(n);if(a===null)throw new Error("recipesAllowDangerousBuiltins: true or false");i.recipesAllowDangerousBuiltins=a;break}case"serviceInstallFromChat":{let a=vt(n);if(a===null)throw new Error("serviceInstallFromChat: true or false");i.serviceInstallFromChat=a;break}case"updateCheckEnabled":{let a=vt(n);if(a===null)throw new Error("updateCheckEnabled: true or false");i.updateCheckEnabled=a;break}case"updateCheckIntervalMs":{let a=Number.parseInt(n,10);if(!Number.isFinite(a)||a<36e5)throw new Error("updateCheckIntervalMs: integer ms, minimum 3600000 (1 hour)");i.updateCheckIntervalMs=Math.min(6048e5,a);break}case"updateCheckPackageName":if(!n.trim())throw new Error("updateCheckPackageName: non-empty npm package name");i.updateCheckPackageName=n.trim().slice(0,214);break;case"updateInfoUrl":i.updateInfoUrl=n.trim().slice(0,2048);break}return Le(i),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}async function Is(e,t){let n=e.trim(),r=n.toLowerCase();if(!n||r==="help")return O(xo());if(r==="keys"||r==="help keys")return p(["*Configurable keys* (/config set)","",un.join(", "),"","Examples:","/config set clusterLabel work-laptop",'/config set fileReceiveRootPath "/path/with spaces"',"/config set gatewayMode both"].join(`
73
+ `));if(r==="show"){let i=$();return J(Na(i),_a(i))}let o=n.match(/^get\s+(\S+)\s*$/i);if(o){let i=o[1],a=$(),l=Ts(a,i);if(!l)return p(`Unknown key "${i}". /config keys`);let d=Ba(a,i);return J(`${l}
73
74
 
74
- ${v}`,`${u}<br/><br/><code>${re(v)}</code>`)}let s=n.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(s){let i=s[1],a=s[2]??"";if(!Vo(i))return m(`Unknown key "${i}". /config keys`);try{let{reloadSuggested:l,shellWarning:u,tokenSaved:c}=_i(i,a),d="";if(t?.reload&&l){let C=await t.reload();d=C.ok?`
75
- Reload: ${C.summary}`:`
76
- Reload failed: ${C.error}`}else l?d=`
77
- Send /reload while omnish run is active (gatewayMode / Telegram).`:d=`
78
- Send /reload to pick up changes where applicable.`;let p=u?`
75
+ ${T}`,`${d}<br/><br/><code>${ie(T)}</code>`)}let s=n.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(s){let i=s[1],a=s[2]??"";if(!Ms(i))return p(`Unknown key "${i}". /config keys`);try{let{reloadSuggested:l,shellWarning:d,tokenSaved:c}=Da(i,a),u="";if(t?.reload&&l){let k=await t.reload();u=k.ok?`
76
+ Reload: ${k.summary}`:`
77
+ Reload failed: ${k.error}`}else l?u=`
78
+ Send /reload while omnish run is active (gatewayMode / Telegram).`:u=`
79
+ Send /reload to pick up changes where applicable.`;let m=d?`
79
80
  \u26A0 shell changed \u2014 affects all commands run via omnish.`:"",f=c?`
80
- telegramBotToken saved (not echoed).`:"",w=`Set *${i}* (saved).${f}${p}${d}`,M=`<b>Set ${re(i)}</b> (saved).${f?"<br/>token saved (not echoed).":""}${u?"<br/>\u26A0 shell path changed.":""}${re(d)}`;return D(w,M)}catch(l){return m(`Error: ${String(l)}`)}}return m("Unknown /config command. Try /config help or /config show")}import ts from"node:fs";import rt from"node:process";function Jt(e){let t=e.nodePath,n=e.scriptPath,r=e.omnishHome,o=["Linux (systemd --user), copy-paste on the host:","","mkdir -p ~/.config/systemd/user","# create ~/.config/systemd/user/omnish.service with ExecStart using:",`# ${t} ${n} run`,`# and Environment=OMNISH_HOME=${r}`,"# The generated unit uses Restart=on-failure and RestartSec=5 (tunable).","","systemctl --user daemon-reload","systemctl --user enable --now omnish.service","",'Optional (run without interactive login): loginctl enable-linger "$USER"',"","Full guide: docs/guides/background-and-boot.md \xB7 https://omnish.dev"].join(`
81
+ telegramBotToken saved (not echoed).`:"",y=`Set *${i}* (saved).${f}${m}${u}`,w=`<b>Set ${ie(i)}</b> (saved).${f?"<br/>token saved (not echoed).":""}${d?"<br/>\u26A0 shell path changed.":""}${ie(u)}`;return J(y,w)}catch(l){return p(`Error: ${String(l)}`)}}return p("Unknown /config command. Try /config help or /config show")}import Os from"node:fs";import ct from"node:process";function dn(e){let t=e.nodePath,n=e.scriptPath,r=e.omnishHome,o=["Linux (systemd --user), copy-paste on the host:","","mkdir -p ~/.config/systemd/user","# create ~/.config/systemd/user/omnish.service with ExecStart using:",`# ${t} ${n} run`,`# and Environment=OMNISH_HOME=${r}`,"# The generated unit uses Restart=on-failure and RestartSec=5 (tunable).","","systemctl --user daemon-reload","systemctl --user enable --now omnish.service","",'Optional (run without interactive login): loginctl enable-linger "$USER"',"","Full guide: docs/guides/background-and-boot.md \xB7 https://omnish.dev"].join(`
81
82
  `),s=["macOS (LaunchAgent), copy-paste on the host:","","# Use contrib/dev.omnish.gateway.plist from the repo with paths filled as:",`# Node: ${t}`,`# Script: ${n}`,`# OMNISH_HOME: ${r}`,"# Generated plist uses KeepAlive for crash restart.","","cp \u2026/dev.omnish.gateway.plist ~/Library/LaunchAgents/","launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/dev.omnish.gateway.plist","launchctl kickstart -k gui/$(id -u)/dev.omnish.gateway","","https://omnish.dev"].join(`
82
83
  `),i=["Windows: Task Scheduler \u2014 Action = Start a program:","",`Program: ${t}`,`Arguments: "${n}" run`,"","Set user env OMNISH_HOME if needed. Optional XML: contrib/omnish-windows-task.xml","","https://omnish.dev"].join(`
83
84
  `);return process.platform==="linux"?o:process.platform==="darwin"?s:process.platform==="win32"?i:[o,"","---","",s].join(`
84
- `)}import{execFileSync as Oe}from"node:child_process";import nt from"node:fs";import gt from"node:os";import Se from"node:path";import oe from"node:process";function Ne(){let e=oe.execPath,t=oe.argv[1];if(!t||!t.trim())return{nodePath:e,scriptPath:"",omnishHome:T,error:"Cannot resolve gateway entry script (missing argv[1]). Run omnish from its CLI entry."};let n=Se.resolve(t),r=oe.env.OMNISH_HOME?.trim(),o=r?Se.resolve(r):T;return{nodePath:e,scriptPath:n,omnishHome:o}}function Xo(e){return/[ "'\\\s]/.test(e)?`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:e}function Ni(e){return`Environment="OMNISH_HOME=${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function Hi(e){return`[Unit]
85
+ `)}import{execFileSync as Be}from"node:child_process";import lt from"node:fs";import Ct from"node:os";import ve from"node:path";import le from"node:process";function ze(){let e=le.execPath,t=le.argv[1];if(!t||!t.trim())return{nodePath:e,scriptPath:"",omnishHome:A,error:"Cannot resolve gateway entry script (missing argv[1]). Run omnish from its CLI entry."};let n=ve.resolve(t),r=le.env.OMNISH_HOME?.trim(),o=r?ve.resolve(r):A;return{nodePath:e,scriptPath:n,omnishHome:o}}function As(e){return/[ "'\\\s]/.test(e)?`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:e}function Ha(e){return`Environment="OMNISH_HOME=${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function ja(e){return`[Unit]
85
86
  Description=omnish gateway (WhatsApp/Telegram)
86
87
  After=network-online.target
87
88
  Wants=network-online.target
88
89
 
89
90
  [Service]
90
91
  Type=simple
91
- ExecStart=${`${Xo(e.nodePath)} ${Xo(e.scriptPath)} run`}
92
- ${Ni(e.omnishHome)}
92
+ ExecStart=${`${As(e.nodePath)} ${As(e.scriptPath)} run`}
93
+ ${Ha(e.omnishHome)}
93
94
  Restart=on-failure
94
95
  RestartSec=5
95
96
 
96
97
  [Install]
97
98
  WantedBy=default.target
98
- `}function ft(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function ji(e){let t=gt.homedir(),n=Se.join(e.omnishHome,"logs","launchd-stdout.log"),r=Se.join(e.omnishHome,"logs","launchd-stderr.log");P(Se.dirname(n));let o=ft(e.nodePath),s=ft(e.scriptPath),i=ft(e.omnishHome),a=ft(n),l=ft(r);return`<?xml version="1.0" encoding="UTF-8"?>
99
+ `}function $t(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function Wa(e){let t=Ct.homedir(),n=ve.join(e.omnishHome,"logs","launchd-stdout.log"),r=ve.join(e.omnishHome,"logs","launchd-stderr.log");L(ve.dirname(n));let o=$t(e.nodePath),s=$t(e.scriptPath),i=$t(e.omnishHome),a=$t(n),l=$t(r);return`<?xml version="1.0" encoding="UTF-8"?>
99
100
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
100
101
  <plist version="1.0">
101
102
  <dict>
@@ -122,92 +123,121 @@ WantedBy=default.target
122
123
  <string>${l}</string>
123
124
  </dict>
124
125
  </plist>
125
- `}function qt(){let e=Ne();if(e.error)return{ok:!1,detail:e.error};if(oe.platform==="win32")return{ok:!1,detail:"Automatic install is not supported on Windows from chat. Use Task Scheduler (see /service instructions) or omnish-windows-task.xml in the repo contrib folder."};if(oe.platform==="darwin")try{let t=Se.join(gt.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist");P(Se.dirname(t));let n=ji(e);nt.writeFileSync(t,n,{mode:384});let r=typeof oe.getuid=="function"?oe.getuid():null;if(r===null||r<0)return{ok:!1,detail:"Could not read user id for launchctl."};let o=`gui/${r}`;try{Oe("launchctl",["bootout",o,t],{stdio:"pipe"})}catch{}return Oe("launchctl",["bootstrap",o,t],{stdio:"inherit"}),Oe("launchctl",["kickstart","-k",`${o}/dev.omnish.gateway`],{stdio:"inherit"}),{ok:!0,detail:"LaunchAgent installed: ~/Library/LaunchAgents/dev.omnish.gateway.plist (label dev.omnish.gateway)."}}catch(t){return{ok:!1,detail:String(t)}}if(oe.platform==="linux")try{let t=Se.join(gt.homedir(),".config","systemd","user");P(t);let n=Se.join(t,"omnish.service"),r=Hi(e);return nt.writeFileSync(n,r,{mode:420}),Oe("systemctl",["--user","daemon-reload"],{stdio:"inherit"}),Oe("systemctl",["--user","enable","--now","omnish.service"],{stdio:"inherit"}),{ok:!0,detail:`User systemd unit installed: ${n} \u2014 enabled and started.`}}catch(t){return{ok:!1,detail:String(t)}}return{ok:!1,detail:`Unsupported platform: ${oe.platform}`}}function Yt(){if(oe.platform==="win32")return{ok:!0,detail:"Windows: remove the omnish task from Task Scheduler manually on this PC. See /service instructions."};if(oe.platform==="darwin")try{let e=Se.join(gt.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist"),n=`gui/${typeof oe.getuid=="function"?oe.getuid():0}`;if(nt.existsSync(e)){try{Oe("launchctl",["bootout",n,e],{stdio:"pipe"})}catch{}nt.unlinkSync(e)}return{ok:!0,detail:"LaunchAgent dev.omnish.gateway removed (if it was present)."}}catch(e){return{ok:!1,detail:String(e)}}if(oe.platform==="linux")try{let e=Se.join(gt.homedir(),".config","systemd","user","omnish.service");try{Oe("systemctl",["--user","disable","--now","omnish.service"],{stdio:"pipe"})}catch{}nt.existsSync(e)&&nt.unlinkSync(e);try{Oe("systemctl",["--user","daemon-reload"],{stdio:"pipe"})}catch{}return{ok:!0,detail:"User systemd unit omnish.service removed (if it was present)."}}catch(e){return{ok:!1,detail:String(e)}}return{ok:!1,detail:`Unsupported platform: ${oe.platform}`}}import es from"node:fs";var Kt=48e3;function Vt(e,t){try{if(!es.existsSync(e))return"(no log file yet \u2014 start with `omnish run -d` or the systemd/LaunchAgent service.)";let n=es.readFileSync(e),o=(n.length>Kt?n.subarray(n.length-Kt):n).toString("utf8");return n.length>Kt&&(o=`\u2026(truncated to last ${Kt} bytes)
126
+ `}function pn(){let e=ze();if(e.error)return{ok:!1,detail:e.error};if(le.platform==="win32")return{ok:!1,detail:"Automatic install is not supported on Windows from chat. Use Task Scheduler (see /service instructions) or omnish-windows-task.xml in the repo contrib folder."};if(le.platform==="darwin")try{let t=ve.join(Ct.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist");L(ve.dirname(t));let n=Wa(e);lt.writeFileSync(t,n,{mode:384});let r=typeof le.getuid=="function"?le.getuid():null;if(r===null||r<0)return{ok:!1,detail:"Could not read user id for launchctl."};let o=`gui/${r}`;try{Be("launchctl",["bootout",o,t],{stdio:"pipe"})}catch{}return Be("launchctl",["bootstrap",o,t],{stdio:"inherit"}),Be("launchctl",["kickstart","-k",`${o}/dev.omnish.gateway`],{stdio:"inherit"}),{ok:!0,detail:"LaunchAgent installed: ~/Library/LaunchAgents/dev.omnish.gateway.plist (label dev.omnish.gateway)."}}catch(t){return{ok:!1,detail:String(t)}}if(le.platform==="linux")try{let t=ve.join(Ct.homedir(),".config","systemd","user");L(t);let n=ve.join(t,"omnish.service"),r=ja(e);return lt.writeFileSync(n,r,{mode:420}),Be("systemctl",["--user","daemon-reload"],{stdio:"inherit"}),Be("systemctl",["--user","enable","--now","omnish.service"],{stdio:"inherit"}),{ok:!0,detail:`User systemd unit installed: ${n} \u2014 enabled and started.`}}catch(t){return{ok:!1,detail:String(t)}}return{ok:!1,detail:`Unsupported platform: ${le.platform}`}}function mn(){if(le.platform==="win32")return{ok:!0,detail:"Windows: remove the omnish task from Task Scheduler manually on this PC. See /service instructions."};if(le.platform==="darwin")try{let e=ve.join(Ct.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist"),n=`gui/${typeof le.getuid=="function"?le.getuid():0}`;if(lt.existsSync(e)){try{Be("launchctl",["bootout",n,e],{stdio:"pipe"})}catch{}lt.unlinkSync(e)}return{ok:!0,detail:"LaunchAgent dev.omnish.gateway removed (if it was present)."}}catch(e){return{ok:!1,detail:String(e)}}if(le.platform==="linux")try{let e=ve.join(Ct.homedir(),".config","systemd","user","omnish.service");try{Be("systemctl",["--user","disable","--now","omnish.service"],{stdio:"pipe"})}catch{}lt.existsSync(e)&&lt.unlinkSync(e);try{Be("systemctl",["--user","daemon-reload"],{stdio:"pipe"})}catch{}return{ok:!0,detail:"User systemd unit omnish.service removed (if it was present)."}}catch(e){return{ok:!1,detail:String(e)}}return{ok:!1,detail:`Unsupported platform: ${le.platform}`}}import Es from"node:fs";var fn=48e3;function gn(e,t){try{if(!Es.existsSync(e))return"(no log file yet \u2014 start with `omnish run -d` or the systemd/LaunchAgent service.)";let n=Es.readFileSync(e),o=(n.length>fn?n.subarray(n.length-fn):n).toString("utf8");return n.length>fn&&(o=`\u2026(truncated to last ${fn} bytes)
126
127
  ${o}`),o.split(/\r?\n/).slice(-t).join(`
127
- `).trimEnd()||"(empty)"}catch(n){return`Could not read log: ${String(n)}`}}var Wi=120;function Me(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function ns(e){let t=e.trim();return t==="/service"||t.startsWith("/service ")?t.slice(8).trim():null}async function rs(e,t){let n=t.trim().split(/\s+/),r=(n[0]??"").toLowerCase();if(!t.trim()||r==="help")return E(Ur(e));if(r==="status"){let s=Ne(),i=(()=>{try{return ts.existsSync(Y)?`gateway.pid: ${ts.readFileSync(Y,"utf8").trim()}`:"gateway.pid: (missing)"}catch(p){return`gateway.pid: (read error: ${String(p)})`}})(),a=rt.env.OMNISH_BACKGROUND_GATEWAY==="1"?"This process: background gateway (OMNISH_BACKGROUND_GATEWAY=1).":"This process: foreground gateway session.",l=typeof rt.env.OMNISH_HOME=="string"&&rt.env.OMNISH_HOME.trim()?`OMNISH_HOME env: ${rt.env.OMNISH_HOME.trim()}`:"OMNISH_HOME env: (not set \u2014 using default data dir)",u=s.error?s.error:`Node: ${s.nodePath}
128
- Script: ${s.scriptPath}`,c=["*Service status*","",`platform: ${rt.platform}`,a,l,`data dir: ${T}`,i,`default log: ${pe}`,"",u,"",e.serviceInstallFromChat?"Install from chat: enabled (/service install).":"Install from chat: off \u2014 `/config set serviceInstallFromChat true` to allow /service install."].join(`
129
- `),d=["<b>Service status</b>","",`<code>${Me(rt.platform)}</code>`,`<br/><code>${Me(a)}</code>`,`<br/><code>${Me(l)}</code>`,`<br/>data dir: <code>${Me(T)}</code>`,`<br/><code>${Me(i)}</code>`,`<br/>default log: <code>${Me(pe)}</code>`,"",`<pre>${Me(u)}</pre>`,"",e.serviceInstallFromChat?"Install from chat: enabled.":"Install from chat: off \u2014 <code>/config set serviceInstallFromChat true</code>."].join(`
130
- `);return D(c,d)}if(r==="instructions"){let s=Ne();if(s.error)return m(s.error);let i=Jt(s);return m(`*Install hints*
128
+ `).trimEnd()||"(empty)"}catch(n){return`Could not read log: ${String(n)}`}}var Ua=120;function Ee(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Ls(e){let t=e.trim();return t==="/service"||t.startsWith("/service ")?t.slice(8).trim():null}async function Ps(e,t){let n=t.trim().split(/\s+/),r=(n[0]??"").toLowerCase();if(!t.trim()||r==="help")return O(So(e));if(r==="status"){let s=ze(),i=(()=>{try{return Os.existsSync(te)?`gateway.pid: ${Os.readFileSync(te,"utf8").trim()}`:"gateway.pid: (missing)"}catch(m){return`gateway.pid: (read error: ${String(m)})`}})(),a=ct.env.OMNISH_BACKGROUND_GATEWAY==="1"?"This process: background gateway (OMNISH_BACKGROUND_GATEWAY=1).":"This process: foreground gateway session.",l=typeof ct.env.OMNISH_HOME=="string"&&ct.env.OMNISH_HOME.trim()?`OMNISH_HOME env: ${ct.env.OMNISH_HOME.trim()}`:"OMNISH_HOME env: (not set \u2014 using default data dir)",d=s.error?s.error:`Node: ${s.nodePath}
129
+ Script: ${s.scriptPath}`,c=["*Service status*","",`platform: ${ct.platform}`,a,l,`data dir: ${A}`,i,`default log: ${we}`,"",d,"",e.serviceInstallFromChat?"Install from chat: enabled (/service install).":"Install from chat: off \u2014 `/config set serviceInstallFromChat true` to allow /service install."].join(`
130
+ `),u=["<b>Service status</b>","",`<code>${Ee(ct.platform)}</code>`,`<br/><code>${Ee(a)}</code>`,`<br/><code>${Ee(l)}</code>`,`<br/>data dir: <code>${Ee(A)}</code>`,`<br/><code>${Ee(i)}</code>`,`<br/>default log: <code>${Ee(we)}</code>`,"",`<pre>${Ee(d)}</pre>`,"",e.serviceInstallFromChat?"Install from chat: enabled.":"Install from chat: off \u2014 <code>/config set serviceInstallFromChat true</code>."].join(`
131
+ `);return J(c,u)}if(r==="instructions"){let s=ze();if(s.error)return p(s.error);let i=dn(s);return p(`*Install hints*
131
132
 
132
- ${i}`)}if(r==="logs"){let s=n.length>=2?Number.parseInt(n[1],10):80,i=Number.isFinite(s)&&s>0?Math.min(s,Wi):80,a=Vt(pe,i),l=[`*Gateway log* (last ${i} lines)
133
- ${pe}
133
+ ${i}`)}if(r==="logs"){let s=n.length>=2?Number.parseInt(n[1],10):80,i=Number.isFinite(s)&&s>0?Math.min(s,Ua):80,a=gn(we,i),l=[`*Gateway log* (last ${i} lines)
134
+ ${we}
134
135
  `,"```",a,"```"].join(`
135
- `),u=`<b>Gateway log</b> (last ${i} lines)<br/><code>${Me(pe)}</code><pre>${Me(a)}</pre>`;return D(l,u)}if(r==="install"){if(!e.serviceInstallFromChat)return m("Install from chat is disabled. Same trust as shell \u2014 enable with:\n`/config set serviceInstallFromChat true`\nThen `/service install` again.");let s=qt();return m(s.ok?`*Installed*
136
+ `),d=`<b>Gateway log</b> (last ${i} lines)<br/><code>${Ee(we)}</code><pre>${Ee(a)}</pre>`;return J(l,d)}if(r==="install"){if(!e.serviceInstallFromChat)return p("Install from chat is disabled. Same trust as shell \u2014 enable with:\n`/config set serviceInstallFromChat true`\nThen `/service install` again.");let s=pn();return p(s.ok?`*Installed*
136
137
  ${s.detail}`:`*Install failed*
137
- ${s.detail}`)}if(r==="uninstall"){if(!e.serviceInstallFromChat)return m("Uninstall from chat is disabled. Enable with `/config set serviceInstallFromChat true` or remove files on the host manually.");let s=Yt();return m(`*Uninstall*
138
- ${s.detail}`)}return m("Unknown /service command. Try /service help")}function Yn(e){let t=e.trim();if(t==="/computers"||t.startsWith("/computers "))return t.slice(10).trim();if(t==="/pcs"||t.startsWith("/pcs "))return t.slice(4).trim();let n=t.match(/^\/c(?:$|\s+(.*))/);return n?(n[1]??"").trim():null}function S(e){return{kind:"text",body:e}}function Ui(e,t){return`${e}:${t}`}function Gi(e,t){return`${e}:apps:${t}`}async function zi(e,t){let n=e.trim();if(n===""||/^status$/i.test(n)||/^show$/i.test(n)||/^get$/i.test(n)){let a=x();return zr({gatewayMode:a.gatewayMode,authPresent:Je(),tokenSet:!!ae(a),allowN:a.allowFrom.length,tgAllowN:a.telegramAllowFrom.length})}if(/^help$/i.test(n))return E(bn());let r=Mt(n);if(!r)return ao();Ct(r);let o=x(),s,i=!1;if(t?.reload){let a=await t.reload();s=a.ok?a.summary:`Reload failed: ${a.error}`}else i=!0;return Qr(o.gatewayMode,s,i)}function Ji(e){let t=e.trim();if(!Ge(t))return Vr();let n=ze(t),r=[];return typeof process.env.TELEGRAM_BOT_TOKEN=="string"&&process.env.TELEGRAM_BOT_TOKEN.trim()&&r.push("TELEGRAM_BOT_TOKEN is set in the environment and overrides config until unset."),n.gatewayMode==="whatsapp"&&r.push('Set gatewayMode to "telegram" or "both" for Telegram to receive messages.'),Kr(r)}async function os(e,t,n){let r=z(t),o=Or(n);if(o!==null){let a=Lr(r.cwd,o),l=Pr(a);return l.ok?(At(t,a),m(`cwd: ${a}`)):m(`cd: ${l.error}`)}let s=await Po(e.shell,n,{timeoutMs:e.syncTimeoutMs,maxBytes:e.syncMaxBytes,cwd:r.cwd}),i=[];return i.push(`$ ${n}`),s.stdout.trim()&&i.push(s.stdout.trimEnd()),s.stderr.trim()&&(i.push("\u2014 stderr \u2014"),i.push(s.stderr.trimEnd())),s.timedOut?i.push(`Timed out (${Math.round(e.syncTimeoutMs/1e3)}s limit).`):s.code!==0&&s.code!==null&&i.push(`Exit ${s.code}`),m(i.join(`
139
- `))}async function He(e,t,n,r,o,s,i,a,l=null,u=!1){let c=s.text.trim(),d=s.peerKey,p=c.match(/^!!\s*(start|stop)\s*$/i);if(p)return p[1].toLowerCase()==="start"?(o.set(d,!0),S(oo())):(o.set(d,!1),S(m("Free shell mode off.")));if(c.startsWith(e.commandPrefix)){let w=c.slice(e.commandPrefix.length).trim();if(!w)return S(m(`Send ${e.commandPrefix}<command> or /help`));if(!u&&Ro(w)){let M=Xe(d,w);if(M!==void 0)return await He(e,t,n,r,o,{...s,text:M},i,a,l,!0)}return S(await os(e,d,w))}if(/^\/help\s+files$/i.test(c.trim()))return S(kn());if(c==="/help"||c==="help")return S(E(Ze(e)));if(c.startsWith("/")){if(/^\/files(?:\s+help)?$/i.test(c.trim()))return S(kn());let w=c.match(/^\/receive\b(?:\s+(\S+))?$/i);if(w){let h=(w[1]??"status").toLowerCase(),b=new Set(["here","cwd","session","dir"]),R=new Set(["default","global","reset"]);if(b.has(h)){mn(d,"sessionCwd");let J=z(d).cwd;return S(m(`Inbound files will save under this chat\u2019s session folder:
140
- ${J}
138
+ ${s.detail}`)}if(r==="uninstall"){if(!e.serviceInstallFromChat)return p("Uninstall from chat is disabled. Enable with `/config set serviceInstallFromChat true` or remove files on the host manually.");let s=mn();return p(`*Uninstall*
139
+ ${s.detail}`)}return p("Unknown /service command. Try /service help")}function Fs(e){let t=e.trim().match(/^(\d+)\.(\d+)\.(\d+)/);return t?[Number(t[1]),Number(t[2]),Number(t[3])]:null}function Ns(e,t){let n=Fs(e),r=Fs(t);if(!n||!r)return e.trim().localeCompare(t.trim());for(let o=0;o<3;o++)if(n[o]!==r[o])return n[o]<r[o]?-1:1;return 0}var Ga="https://registry.npmjs.org",_s=null,br=0;function Rt(){return _s}function za(e){let t=e.trim();return t.length<1||t.length>214?!1:!/\s/.test(t)}function Bs(e){let t=e.trim();if(!t||t.length>2048)return null;try{let n=new URL(t);return n.protocol!=="https:"?null:n.href}catch{return null}}async function Ja(e){let t=e.trim(),n=`${Ga}/${encodeURIComponent(t)}/latest`;try{let r=await fetch(n,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(2e4)});if(!r.ok)return{error:`npm registry: HTTP ${r.status}`};let o=await r.json(),s=typeof o.version=="string"?o.version.trim():"";return s?{version:s}:{error:"npm registry: missing version in response"}}catch(r){return{error:`npm registry: ${String(r)}`}}}async function Ka(e){try{let t=await fetch(e,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(15e3)});if(!t.ok)return{error:`updateInfoUrl: HTTP ${t.status}`};let n=await t.arrayBuffer(),r=n.byteLength>65536?n.slice(0,65536):n,o=new TextDecoder("utf-8",{fatal:!1}).decode(r),s;try{s=JSON.parse(o)}catch{return{error:"updateInfoUrl: body is not JSON"}}if(!s||typeof s!="object"||Array.isArray(s))return{error:"updateInfoUrl: JSON must be an object"};let i=s,a=null;typeof i.message=="string"&&i.message.trim()&&(a=i.message.trim().slice(0,1500));let l=null,d=i.link??i.url;return typeof d=="string"&&d.trim()&&(l=Bs(d)),{message:a,link:l}}catch(t){return{error:`updateInfoUrl: ${String(t)}`}}}function qa(e){return!Number.isFinite(e)||e<36e5?36e5:e>6048e5?6048e5:Math.floor(e)}async function Mt(e,t){let n=za(t.updateCheckPackageName)?t.updateCheckPackageName.trim():"omnish",r=await Ja(n),o="version"in r?r.version:null,s="error"in r?r.error:null,i=!1;o&&!s&&(i=Ns(e,o)<0);let a=null,l=null,d=null,c=Bs(t.updateInfoUrl);if(c){let m=await Ka(c);"error"in m?d=m.error:(a=m.message,l=m.link)}let u={runningVersion:e,checkedAtIso:new Date().toISOString(),registryPackage:n,registryLatest:o,registryError:s,updateAvailable:i,infoMessage:a,infoLink:l,infoError:d};return _s=u,u}function hn(e){if(!e)return;let t=[];if(e.registryError?t.push(`npm check: ${e.registryError}`):e.registryLatest&&t.push(e.updateAvailable?`npm latest *${e.registryLatest}* (running ${e.runningVersion})`:`npm latest ${e.registryLatest} (up to date)`),e.infoError?t.push(`info URL: ${e.infoError}`):e.infoMessage&&t.push(`notice: ${e.infoMessage}`),t.length!==0)return t.join(" \xB7 ")}function Ds(e){let t=!1,n=async()=>{if(t)return;let s=e.getConfig();if(!s.updateCheckEnabled)return;let i=qa(s.updateCheckIntervalMs),a=Date.now();if(!(br!==0&&a-br<i)){br=a;try{let l=await Mt(e.getRunningVersion(),s);l.updateAvailable?e.log.info({updateAvailable:!0,running:l.runningVersion,npmLatest:l.registryLatest,pkg:l.registryPackage},"omnish update check: newer npm version available"):e.log.info({running:l.runningVersion,npmLatest:l.registryLatest,pkg:l.registryPackage},"omnish update check ok"),l.infoMessage&&e.log.info({len:l.infoMessage.length},"omnish update info message present")}catch(l){e.log.warn({err:String(l)},"omnish update check failed")}}},r=setInterval(()=>void n(),6e4),o=setTimeout(()=>void n(),3e4);return()=>{t=!0,clearInterval(r),clearTimeout(o)}}import Ya from"node:fs";import Hs from"node:path";import{fileURLToPath as Va}from"node:url";var yn=null;function De(){if(yn!==null)return yn;let e=Hs.dirname(Va(import.meta.url)),t=Hs.join(e,"..","package.json"),n=Ya.readFileSync(t,"utf8"),r=JSON.parse(n);return yn=typeof r.version=="string"&&r.version.trim()?r.version.trim():"0.0.0",yn}function Tt(e,t,n){let r=new Date(e),o=r.getFullYear(),s=r.getMonth(),i=r.getDate(),a=new Date(o,s,i,t,n,0,0).getTime();return a<=e&&(a=new Date(o,s,i+1,t,n,0,0).getTime()),a}function Xa(e,t,n){let r=e;for(let o=0;o<14;o++){let s=Tt(r,t,n),i=new Date(s).getDay();if(i>=1&&i<=5)return s;r=s}return Tt(r,t,n)}function Qa(e,t,n,r){let o=e;for(let s=0;s<370;s++){let i=Tt(o,n,r);if(new Date(i).getDay()===t)return i;o=i}return Tt(o,n,r)}function Za(e,t){return e.kind==="ondemand"?Number.POSITIVE_INFINITY:e.kind==="daily"?Tt(t,e.hour,e.minute):e.kind==="weekdays"?Xa(t,e.hour,e.minute):Qa(t,e.weekday,e.hour,e.minute)}function js(e,t,n,r,o=32){if(e.kind==="ondemand")return[];let s=t??n-1,i=[],a=s;for(;i.length<o;){let l=Za(e,a);if(l>r)break;i.push(l),a=l}return i}var el={sun:0,sunday:0,mon:1,monday:1,tue:2,tues:2,tuesday:2,wed:3,wednesday:3,thu:4,thur:4,thurs:4,thursday:4,fri:5,friday:5,sat:6,saturday:6};function kr(e){let t=/^(\d{1,2}):(\d{2})$/.exec(e.trim());if(!t)return null;let n=Number(t[1]),r=Number(t[2]);return!Number.isFinite(n)||!Number.isFinite(r)||n>23||r>59?null:{hour:n,minute:r}}function Sr(e){if(e.length===0)return{ok:!1,error:"Missing schedule (try: ondemand, daily HH:MM, weekdays HH:MM, weekly <dow> HH:MM)."};let t=e[0].toLowerCase();if(t==="ondemand"||t==="manual")return e.length!==1?{ok:!1,error:"ondemand takes no extra tokens."}:{ok:!0,schedule:{kind:"ondemand"}};if(t==="daily"){if(e.length!==2)return{ok:!1,error:"Usage: daily HH:MM"};let n=kr(e[1]);return n?{ok:!0,schedule:{kind:"daily",hour:n.hour,minute:n.minute}}:{ok:!1,error:"daily needs HH:MM (24h)."}}if(t==="weekdays"){if(e.length!==2)return{ok:!1,error:"Usage: weekdays HH:MM"};let n=kr(e[1]);return n?{ok:!0,schedule:{kind:"weekdays",hour:n.hour,minute:n.minute}}:{ok:!1,error:"weekdays needs HH:MM (24h)."}}if(t==="weekly"){if(e.length!==3)return{ok:!1,error:"Usage: weekly <mon|tue|\u2026|sun> HH:MM"};let n=e[1].toLowerCase(),r=el[n];if(r===void 0){let s=Number(n);Number.isInteger(s)&&s>=0&&s<=6&&(r=s)}if(r===void 0)return{ok:!1,error:`Unknown weekday "${e[1]}". Use mon\u2026sun or 0\u20136 (Sun=0).`};let o=kr(e[2]);return o?{ok:!0,schedule:{kind:"weekly",weekday:r,hour:o.hour,minute:o.minute}}:{ok:!1,error:"weekly needs HH:MM (24h) after weekday."}}return{ok:!1,error:`Unknown schedule kind "${t}".`}}function It(e){let t=r=>r<10?`0${r}`:String(r),n=(r,o)=>`${t(r)}:${t(o)}`;switch(e.kind){case"ondemand":return"ondemand";case"daily":return`daily ${n(e.hour,e.minute)}`;case"weekdays":return`weekdays ${n(e.hour,e.minute)}`;case"weekly":return`weekly ${["sun","mon","tue","wed","thu","fri","sat"][e.weekday]??e.weekday} ${n(e.hour,e.minute)}`}}import rl from"better-sqlite3";import tl from"pino";function wn(){return process.env.OMNISH_VERBOSE==="1"||process.env.WHATSVERBOSE==="1"}var nl=wn()?"info":"silent",M=tl({level:nl,base:{app:"omnish"}});function Ws(){return M.child({module:"baileys"})}var Us=1,He=null;function Gs(){L(Ce);let e=new rl(Jr);e.pragma("journal_mode = WAL"),e.exec(`
140
+ CREATE TABLE IF NOT EXISTS cowork_meta (
141
+ key TEXT PRIMARY KEY,
142
+ value TEXT NOT NULL
143
+ );
144
+ CREATE TABLE IF NOT EXISTS cowork_slot_completion (
145
+ task_id TEXT NOT NULL,
146
+ slot_ms INTEGER NOT NULL,
147
+ kind TEXT NOT NULL,
148
+ completed_at_ms INTEGER NOT NULL,
149
+ log_path TEXT,
150
+ PRIMARY KEY (task_id, slot_ms)
151
+ );
152
+ CREATE INDEX IF NOT EXISTS idx_cowork_completion_task ON cowork_slot_completion(task_id);
153
+ `);let t=e.prepare("SELECT value FROM cowork_meta WHERE key = 'schema_version'").get();return(t?Number(t.value):0)<Us&&e.prepare("INSERT OR REPLACE INTO cowork_meta (key, value) VALUES ('schema_version', ?)").run(String(Us)),e}function At(e){He||(He=Gs()),sl(e)}function zs(){if(He){try{He.close()}catch{}He=null}}function xr(){return He||(He=Gs()),He}function ol(e){let n=xr().prepare("SELECT MAX(slot_ms) AS m FROM cowork_slot_completion WHERE task_id = ?").get(e)?.m;return n==null||!Number.isFinite(n)?null:n}function bn(e){let t=ol(e.id);return t??e.lastCompletedSlotMs}function kn(e,t){if(t.length===0)return;let n=xr(),r=n.prepare(`
154
+ INSERT INTO cowork_slot_completion (task_id, slot_ms, kind, completed_at_ms, log_path)
155
+ VALUES (?, ?, ?, ?, ?)
156
+ `);n.transaction(()=>{for(let s of t)r.run(e,s.slotMs,s.kind,s.completedAtMs,s.logPath)})()}function sl(e){let n=xr().prepare("SELECT COUNT(*) AS c FROM cowork_slot_completion WHERE task_id = ?"),r=Date.now();for(let o of e)if(!(o.lastCompletedSlotMs==null||!Number.isFinite(o.lastCompletedSlotMs)||n.get(o.id).c>0))try{kn(o.id,[{slotMs:o.lastCompletedSlotMs,kind:"migrated",logPath:null,completedAtMs:r}]),M.info({taskId:o.id,slotMs:o.lastCompletedSlotMs},"cowork seeded completion from tasks.json")}catch(i){M.warn({err:String(i),taskId:o.id},"cowork seed from tasks.json failed")}}import Js from"node:crypto";import Et from"node:fs";import vr from"node:os";import ut from"node:path";var il=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/;function Ks(e){let t=e.trim().toLowerCase();return il.test(t)?{ok:!0,name:t}:{ok:!1,error:"Name must be alphanumeric with _ or -, max 32 chars."}}function Ot(e,t){let n=e.trim();return n===""||n==="."?ut.resolve(t):n==="~"?vr.homedir():n.startsWith("~/")||n.startsWith("~\\")?ut.join(vr.homedir(),n.slice(2)):ut.isAbsolute(n)?n:ut.resolve(t,n)}function Cr(e){return ut.join(vr.homedir(),"Cowork",e)}function al(e){if(!e||typeof e!="object")return null;let t=e,n=typeof t.id=="string"&&t.id.length>=4?t.id.slice(0,32):"",r=typeof t.name=="string"?t.name.trim().toLowerCase():"",o=typeof t.ownerPeerKey=="string"?t.ownerPeerKey:"",s=typeof t.command=="string"?t.command:"";if(!n||!r||!o||!s)return null;let i=typeof t.cwd=="string"?t.cwd:"",a=typeof t.outputDir=="string"&&t.outputDir.trim()?t.outputDir:Cr(r),l=typeof t.enabled=="boolean"?t.enabled:!0,d=typeof t.notify=="string"?t.notify.toLowerCase():"self",c=d==="wa"||d==="whatsapp"?"wa":d==="tg"||d==="telegram"?"tg":d==="all"?"all":d==="none"?"none":"self",u={kind:"ondemand"};if(t.schedule&&typeof t.schedule=="object"){let y=t.schedule,w=typeof y.kind=="string"?y.kind:"";if(w==="ondemand")u={kind:"ondemand"};else if(w==="daily"){let k=Number(y.hour),E=Number(y.minute);Number.isFinite(k)&&Number.isFinite(E)&&(u={kind:"daily",hour:k,minute:E})}else if(w==="weekdays"){let k=Number(y.hour),E=Number(y.minute);Number.isFinite(k)&&Number.isFinite(E)&&(u={kind:"weekdays",hour:k,minute:E})}else if(w==="weekly"){let k=Number(y.hour),E=Number(y.minute),P=Number(y.weekday);Number.isFinite(k)&&Number.isFinite(E)&&Number.isInteger(P)&&(u={kind:"weekly",weekday:P,hour:k,minute:E})}}let m=null;typeof t.lastCompletedSlotMs=="number"&&Number.isFinite(t.lastCompletedSlotMs)&&(m=t.lastCompletedSlotMs);let f=typeof t.createdAtMs=="number"&&Number.isFinite(t.createdAtMs)?t.createdAtMs:Date.now();return{id:n,name:r,ownerPeerKey:o,command:s,cwd:i,outputDir:a,schedule:u,enabled:l,notify:c,lastCompletedSlotMs:m,createdAtMs:f}}function he(){try{let e=Et.readFileSync(Ln,"utf8"),t=JSON.parse(e);if(!t||!Array.isArray(t.tasks))return[];let n=[];for(let r of t.tasks){let o=al(r);o&&n.push(o)}return n}catch{return[]}}function Oe(e){L(Ce);let t={tasks:e},n=ut.join(Ce,`.tasks.${process.pid}.${Js.randomBytes(4).toString("hex")}.tmp`);Et.writeFileSync(n,JSON.stringify(t,null,2)+`
157
+ `,{mode:384}),Et.renameSync(n,Ln)}function dt(e,t,n){let r=t.trim().toLowerCase();return e.find(o=>o.name===r&&o.ownerPeerKey===n)}function qs(){return Js.randomBytes(4).toString("hex")}function Ys(e){L(Ce),Et.writeFileSync(Pn,JSON.stringify(e,null,2)+`
158
+ `,{mode:384})}function Vs(e){let t=$r();t.push(e),Ys(t)}function $r(){try{let e=Et.readFileSync(Pn,"utf8"),t=JSON.parse(e);return Array.isArray(t)?t.filter(n=>n&&typeof n=="object"&&typeof n.ownerPeerKey=="string"&&typeof n.name=="string"):[]}catch{return[]}}function Xs(e){if(e<=0)return{batch:[],remainingAfter:$r().length};let t=$r();if(t.length===0)return{batch:[],remainingAfter:0};let n=t.slice(0,e),r=t.slice(e);return Ys(r),{batch:n,remainingAfter:r.length}}function ll(){return p(["Cowork \u2014 scheduled shell tasks (gateway must be running).","","add <name> <schedule> -- <command\u2026>"," schedule: ondemand | daily HH:MM | weekdays HH:MM | weekly <mon\u2026sun> HH:MM","set <name> cmd -- <command\u2026> | schedule <\u2026> | out <path> | cwd <path>"," notify self|wa|tg|all|none","list | show <name> | run <name> | enable <name> | disable <name> | remove <name>","","Output logs: task outputDir (default ~/Cowork/<name>). Missed times catch up when the gateway is back."].join(`
159
+ `))}function cl(e){let t=" -- ",n=e.indexOf(t);if(n===-1)return{error:'Missing " -- " before the command. Example: /cowork add tick weekdays 09:00 -- date'};let r=e.slice(0,n).trim(),o=e.slice(n+t.length).trim();if(!o)return{error:"Command after -- is empty."};let s=r.split(/\s+/).filter(Boolean);if(s.length<2)return{error:"Usage: /cowork add <name> <schedule\u2026> -- <command\u2026>"};let i=s[0],a=s.slice(1);return{name:i,scheduleWords:a,command:o}}function Zs(e,t){let n=e.trim();if(!n||/^help$/i.test(n))return ll();let r=n.split(/\s+/)[0].toLowerCase();if(/^list$/i.test(r)){let d=he().filter(u=>u.ownerPeerKey===t);if(d.length===0)return p("(no cowork tasks for this chat)");let c=d.map(u=>{let m=u.enabled?"":" (disabled)";return`\u2022 ${u.name} ${It(u.schedule)} notify=${u.notify}${m}`});return p(c.join(`
160
+ `))}let o=n.match(/^show\s+(\S+)\s*$/i);if(o){let d=o[1],c=he();At(c);let u=dt(c,d,t);if(!u)return p(`Unknown task "${d}". /cowork list`);let m=bn(u),f=[`name: ${u.name}`,`id: ${u.id}`,`schedule: ${It(u.schedule)}`,`enabled: ${u.enabled}`,`notify: ${u.notify}`,`cwd: ${u.cwd||"(session cwd)"}`,`out: ${u.outputDir}`,`cmd: ${u.command}`,`last slot: ${m?new Date(m).toLocaleString():"(never)"}`];return p(f.join(`
161
+ `))}if(/^add$/i.test(r)){let d=n.slice(3).trim(),c=cl(d);if("error"in c)return p(c.error);let u=Ks(c.name);if(!u.ok)return p(u.error);let m=Sr(c.scheduleWords);if(!m.ok)return p(m.error);let f=he();if(dt(f,u.name,t))return p(`Task "${u.name}" already exists. Remove it first or pick another name.`);let y=H(t),w=Cr(u.name),k={id:qs(),name:u.name,ownerPeerKey:t,command:c.command,cwd:"",outputDir:w,schedule:m.schedule,enabled:!0,notify:"self",lastCompletedSlotMs:null,createdAtMs:Date.now()};return f.push(k),Oe(f),p([`Saved cowork task "${u.name}" (${It(m.schedule)}).`,`Output: ${w}`,`Notify: self \u2014 change with /cowork set ${u.name} notify wa|tg|all|none`].join(`
162
+ `))}let s=n.match(/^run\s+(\S+)\s*$/i);if(s){let d=s[1].toLowerCase(),c=dt(he(),d,t);return c?c.enabled?(Vs({ownerPeerKey:t,name:c.name,at:Date.now()}),p(`On-demand run queued for "${c.name}" (runs within ~30s while omnish run is active).`)):p(`Cowork "${c.name}" is disabled. /cowork enable ${c.name}`):p(`Unknown task "${s[1]}". /cowork list`)}let i=n.match(/^(?:remove|rm|del)\s+(\S+)\s*$/i);if(i){let d=i[1],c=he(),u=c.findIndex(m=>m.name===d.toLowerCase()&&m.ownerPeerKey===t);return u===-1?p(`Unknown task "${d}".`):(c.splice(u,1),Oe(c),p(`Removed cowork task "${d.toLowerCase()}".`))}let a=n.match(/^enable\s+(\S+)\s*$/i);if(a)return Qs(a[1],t,!0);let l=n.match(/^disable\s+(\S+)\s*$/i);return l?Qs(l[1],t,!1):/^set$/i.test(r)?dl(n.slice(3).trim(),t):p("Unknown /cowork command. Try /cowork help")}function Qs(e,t,n){let r=he(),o=dt(r,e,t);return o?(o.enabled=n,Oe(r),p(`Cowork "${o.name}" ${n?"enabled":"disabled"}.`)):p(`Unknown task "${e}".`)}function ul(e){let t=e.toLowerCase();return t==="self"?"self":t==="wa"||t==="whatsapp"?"wa":t==="tg"||t==="telegram"?"tg":t==="all"?"all":t==="none"?"none":null}function dl(e,t){let n=e.match(/^(\S+)\s+([\s\S]+)$/);if(!n)return p("Usage: /cowork set <name> cmd -- \u2026 | schedule \u2026 | out <path> | cwd <path> | notify <self|wa|tg|all|none>");let r=n[1],o=n[2].trim(),s=he(),i=dt(s,r,t);if(!i)return p(`Unknown task "${r}".`);if(o.toLowerCase().startsWith("cmd ")){let a=o.slice(4).trim(),l=a.indexOf(" -- ");if(l===-1)return p("Usage: /cowork set <name> cmd -- <command\u2026>");let d=a.slice(l+4).trim();return d?(i.command=d,Oe(s),p(`Updated command for "${i.name}".`)):p("Command is empty.")}if(o.toLowerCase().startsWith("schedule ")){let a=o.slice(9).trim().split(/\s+/).filter(Boolean),l=Sr(a);return l.ok?(i.schedule=l.schedule,Oe(s),p(`Schedule for "${i.name}": ${It(l.schedule)}`)):p(l.error)}if(o.toLowerCase().startsWith("out ")){let a=o.slice(4).trim(),l=H(t);return i.outputDir=Ot(a,l.cwd),Oe(s),p(`outputDir: ${i.outputDir}`)}if(o.toLowerCase().startsWith("cwd ")){let a=o.slice(4).trim(),l=H(t);return i.cwd=a?Ot(a,l.cwd):"",Oe(s),p(`cwd: ${i.cwd||"(session cwd at run time)"}`)}if(o.toLowerCase().startsWith("notify ")){let a=o.slice(7).trim(),l=ul(a);return l?(i.notify=l,Oe(s),p(`notify: ${l}`)):p("notify must be self, wa, tg, all, or none.")}return p("Unknown set field. Try: cmd, schedule, out, cwd, notify")}function Rr(e){let t=e.trim();if(t==="/computers"||t.startsWith("/computers "))return t.slice(10).trim();if(t==="/pcs"||t.startsWith("/pcs "))return t.slice(4).trim();let n=t.match(/^\/c(?:$|\s+(.*))/);return n?(n[1]??"").trim():null}function x(e){return{kind:"text",body:e}}function ml(e,t){return`${e}:${t}`}function fl(e,t){return`${e}:apps:${t}`}async function gl(e,t){let n=e.trim();if(n===""||/^status$/i.test(n)||/^show$/i.test(n)||/^get$/i.test(n)){let a=$();return vo({gatewayMode:a.gatewayMode,authPresent:Ze(),tokenSet:!!pe(a),allowN:a.allowFrom.length,tgAllowN:a.telegramAllowFrom.length,updateBrief:hn(Rt())})}if(/^help$/i.test(n))return O(Gn());let r=Gt(n);if(!r)return Do();zt(r);let o=$(),s,i=!1;if(t?.reload){let a=await t.reload();s=a.ok?a.summary:`Reload failed: ${a.error}`}else i=!0;return Io(o.gatewayMode,s,i)}function hl(e){let t=e.trim();if(!Xe(t))return To();let n=Qe(t),r=[];return typeof process.env.TELEGRAM_BOT_TOKEN=="string"&&process.env.TELEGRAM_BOT_TOKEN.trim()&&r.push("TELEGRAM_BOT_TOKEN is set in the environment and overrides config until unset."),n.gatewayMode==="whatsapp"&&r.push('Set gatewayMode to "telegram" or "both" for Telegram to receive messages.'),Mo(r)}async function ei(e,t,n){let r=H(t),o=co(n);if(o!==null){let a=uo(r.cwd,o),l=po(a);return l.ok?(qt(t,a),p(`cwd: ${a}`)):p(`cd: ${l.error}`)}let s=await ln(e.shell,n,{timeoutMs:e.syncTimeoutMs,maxBytes:e.syncMaxBytes,cwd:r.cwd}),i=[];return i.push(`$ ${n}`),s.stdout.trim()&&i.push(s.stdout.trimEnd()),s.stderr.trim()&&(i.push("\u2014 stderr \u2014"),i.push(s.stderr.trimEnd())),s.timedOut?i.push(`Timed out (${Math.round(e.syncTimeoutMs/1e3)}s limit).`):s.code!==0&&s.code!==null&&i.push(`Exit ${s.code}`),p(i.join(`
163
+ `))}async function Je(e,t,n,r,o,s,i,a,l=null,d=!1){let c=s.text.trim(),u=s.peerKey,m=c.match(/^!!\s*(start|stop)\s*$/i);if(m)return m[1].toLowerCase()==="start"?(o.set(u,!0),x(No())):(o.set(u,!1),x(p("Free shell mode off.")));if(c.startsWith(e.commandPrefix)){let y=c.slice(e.commandPrefix.length).trim();if(!y)return x(p(`Send ${e.commandPrefix}<command> or /help`));if(!d&&ns(y)){let w=st(u,y);if(w!==void 0)return await Je(e,t,n,r,o,{...s,text:w},i,a,l,!0)}return x(await ei(e,u,y))}if(/^\/help\s+files$/i.test(c.trim()))return x(Kn());if(c==="/help"||c==="help")return x(O(ot(e)));if(c.startsWith("/")){if(/^\/files(?:\s+help)?$/i.test(c.trim()))return x(Kn());let y=c.match(/^\/receive\b(?:\s+(\S+))?$/i);if(y){let g=(y[1]??"status").toLowerCase(),S=new Set(["here","cwd","session","dir"]),v=new Set(["default","global","reset"]);if(S.has(g)){Bn(u,"sessionCwd");let K=H(u).cwd;return x(p(`Inbound files will save under this chat\u2019s session folder:
164
+ ${K}
141
165
  (layout: \u2026/<peer>/<date>/<file> under that root).
142
166
 
143
- Change folder with ${e.commandPrefix}cd \u2026 Send /receive default to use the server config again.`))}return R.has(h)?(mn(d,"default"),S(m("Per-chat inbound folder cleared. Uploads now follow fileReceiveRootMode in config.json (/files)."))):S(h==="help"?vn():h==="status"?to(e,d):vn())}if(c==="/reload"||c==="/restart"){if(!a?.reload)return S(m("Reload is only available while the omnish gateway (omnish run) is running."));let h=await a.reload();return S(m(h.ok?h.summary:`Reload failed: ${h.error}`))}let M=c.match(/^\/security(?:\s+(\S+))?\s*$/i);if(M){let h=(M[1]??"").toLowerCase(),b=x(),R=Qe(b);return S(h==="help"||h==="?"?E(yo()):h==="summary"||h==="brief"?m(Wr(R,"Send /security for the full report.")):h==="tips"?E(ho()):h===""||h==="full"||h==="report"?go(R):m("Unknown /security subcommand. Try /security, /security summary, /security tips, or /security help"))}let C=c.match(/^\/(gateway|gw|mode)\b(?:\s+(.*))?$/i);if(C){let h=(C[2]??"").trim();return S(await zi(h,a))}if(c==="/config"||c.startsWith("/config ")){let h=c.slice(7).trim();return S(await Zo(h,a))}let X=ns(c);if(X!==null)return S(await rs(e,X));let ee=Yn(c);if(ee!==null){let h=qo(e,ee,l);return h===null?null:S(h)}let U=c.match(/^\/(send|file)\b(?:\s+([\s\S]+))?$/i);if(U){let h=(U[2]??"").trim();if(!h)return S(xn());let b=h.indexOf(" -- "),R,J;if(b!==-1?(R=h.slice(0,b).trim(),J=h.slice(b+4).trim()||void 0):R=h,(R.startsWith('"')&&R.endsWith('"')||R.startsWith("'")&&R.endsWith("'"))&&(R=R.slice(1,-1)),!R)return S(xn());let xe=Di.resolve(z(d).cwd,R),he=qe(xe,e.fileSendMaxBytes);return"error"in he?S(m(he.error)):{kind:"file",spec:{absPath:he.absPath,category:he.category,mimetype:he.mimetype,displayName:he.displayName,caption:J}}}if(c==="/allowlist"){let h=x();return S(Yr([{label:"allowFrom (WhatsApp)",items:h.allowFrom},{label:"telegramAllowFrom",items:h.telegramAllowFrom}]))}let ue=c.match(/^\/allow\b\s+(.+)$/i);if(ue)try{let h=$t(ue[1].trim());return S(Sn(h))}catch(h){return S(m(String(h)))}if(/^\/allow\b\s*$/i.test(c))return S(Zr());let ge=c.match(/^\/deny\b\s+(.+)$/i);if(ge)try{let h=Rt(ge[1].trim());return S(Sn(h))}catch(h){return S(m(String(h)))}if(/^\/deny\b\s*$/i.test(c))return S(Xr());let B=c.match(/^\/(whatsapp|wa|telegram|tg)\b(?:\s+(.*))?$/i);if(B){let h=B[1].toLowerCase(),b=(B[2]??"").trim(),R=h==="whatsapp"||h==="wa";if(h==="telegram"||h==="tg"){let xe=b.match(/^token\s+(\S+)\s*$/i);return xe?S(Ji(xe[1]??"")):b===""||/^help$/i.test(b)?S(E(qr(x()))):S(ro())}if(R)return b===""||/^help$/i.test(b)?S(E(Jr(e))):S(no())}if(c==="/apps"||c.startsWith("/apps "))return S(await Vi(c,d,e,i,r));let Fe=qi(c);if(Fe!==null)return S(Yi(Fe,d,e,i));if(c.startsWith("/bg")){let h=c.slice(3).trim();if(!h)return S(eo());let b=z(d).cwd,{id:R}=t.spawnJob(e.shell,h,{cwd:b});return S(m(`Job ${R} started.
144
- [cwd: ${b}]
145
- /log ${R}
146
- /tail ${R}`))}if(c==="/jobs"){let h=t.list().slice(0,20);return h.length===0?S(m("(no jobs yet)")):S(m(h.map(b=>{let R=b.finishedAt&&b.startedAt?`${((Date.parse(b.finishedAt)-Date.parse(b.startedAt))/1e3).toFixed(1)}s`:"\u2026";return`${b.id} ${b.status} exit=${b.exitCode??"?"} ${R}
147
- ${b.cmd.slice(0,120)}${b.cmd.length>120?"\u2026":""}`}).join(`
167
+ Change folder with ${e.commandPrefix}cd \u2026 Send /receive default to use the server config again.`))}return v.has(g)?(Bn(u,"default"),x(p("Per-chat inbound folder cleared. Uploads now follow fileReceiveRootMode in config.json (/files)."))):x(g==="help"?qn():g==="status"?Lo(e,u):qn())}if(c==="/reload"||c==="/restart"){if(!a?.reload)return x(p("Reload is only available while the omnish gateway (omnish run) is running."));let g=await a.reload();return x(p(g.ok?g.summary:`Reload failed: ${g.error}`))}if(c==="/updates"||c.startsWith("/updates ")){let g=c.slice(8).trim().toLowerCase();if(g==="cached"||g==="last"){let v=Rt();return x(v?kt(v):p("No update snapshot yet. Send /updates (live check) once, or enable updateCheckEnabled and wait for the scheduled check."))}let S=await Mt(De(),$());return x(kt(S))}let w=c.match(/^\/security(?:\s+(\S+))?\s*$/i);if(w){let g=(w[1]??"").toLowerCase(),S=$(),v=rt(S);return x(g==="help"||g==="?"?O(qo()):g==="summary"||g==="brief"?p(bo(v,"Send /security for the full report.")):g==="tips"?O(Ko()):g===""||g==="full"||g==="report"?Jo(v):p("Unknown /security subcommand. Try /security, /security summary, /security tips, or /security help"))}let k=c.match(/^\/(gateway|gw|mode)\b(?:\s+(.*))?$/i);if(k){let g=(k[2]??"").trim();return x(await gl(g,a))}if(c==="/config"||c.startsWith("/config ")){let g=c.slice(7).trim();return x(await Is(g,a))}let E=Ls(c);if(E!==null)return x(await Ps(e,E));let P=Rr(c);if(P!==null){let g=$s(e,P,l);return g===null?null:x(g)}let D=c.match(/^\/(send|file)\b(?:\s+([\s\S]+))?$/i);if(D){let g=(D[2]??"").trim();if(!g)return x(Jn());let S=g.indexOf(" -- "),v,K;if(S!==-1?(v=g.slice(0,S).trim(),K=g.slice(S+4).trim()||void 0):v=g,(v.startsWith('"')&&v.endsWith('"')||v.startsWith("'")&&v.endsWith("'"))&&(v=v.slice(1,-1)),!v)return x(Jn());let ne=pl.resolve(H(u).cwd,v),Me=et(ne,e.fileSendMaxBytes);return"error"in Me?x(p(Me.error)):{kind:"file",spec:{absPath:Me.absPath,category:Me.category,mimetype:Me.mimetype,displayName:Me.displayName,caption:K}}}if(c==="/allowlist"){let g=$();return x(Ro([{label:"allowFrom (WhatsApp)",items:g.allowFrom},{label:"telegramAllowFrom",items:g.telegramAllowFrom}]))}let W=c.match(/^\/allow\b\s+(.+)$/i);if(W)try{let g=Wt(W[1].trim());return x(zn(g))}catch(g){return x(p(String(g)))}if(/^\/allow\b\s*$/i.test(c))return x(Ao());let V=c.match(/^\/deny\b\s+(.+)$/i);if(V)try{let g=Ut(V[1].trim());return x(zn(g))}catch(g){return x(p(String(g)))}if(/^\/deny\b\s*$/i.test(c))return x(Eo());let F=c.match(/^\/(whatsapp|wa|telegram|tg)\b(?:\s+(.*))?$/i);if(F){let g=F[1].toLowerCase(),S=(F[2]??"").trim(),v=g==="whatsapp"||g==="wa";if(g==="telegram"||g==="tg"){let ne=S.match(/^token\s+(\S+)\s*$/i);return ne?x(hl(ne[1]??"")):S===""||/^help$/i.test(S)?x(O(Co($()))):x(Fo())}if(v)return S===""||/^help$/i.test(S)?x(O($o(e))):x(Po())}let ue=c.match(/^\/(cowork|cw)\b(?:\s+([\s\S]*))?$/i);if(ue){let g=(ue[2]??"").trim();return x(Zs(g,u))}if(c==="/apps"||c.startsWith("/apps "))return x(await kl(c,u,e,i,r));let X=yl(c);if(X!==null)return x(wl(X,u,e,i));if(c.startsWith("/bg")){let g=c.slice(3).trim();if(!g)return x(Oo());let S=H(u).cwd,{id:v}=t.spawnJob(e.shell,g,{cwd:S});return x(p(`Job ${v} started.
168
+ [cwd: ${S}]
169
+ /log ${v}
170
+ /tail ${v}`))}if(c==="/jobs"){let g=t.list().slice(0,20);return g.length===0?x(p("(no jobs yet)")):x(p(g.map(S=>{let v=S.finishedAt&&S.startedAt?`${((Date.parse(S.finishedAt)-Date.parse(S.startedAt))/1e3).toFixed(1)}s`:"\u2026";return`${S.id} ${S.status} exit=${S.exitCode??"?"} ${v}
171
+ ${S.cmd.slice(0,120)}${S.cmd.length>120?"\u2026":""}`}).join(`
148
172
 
149
- `)))}let $=c.match(/^\/log\s+([a-f0-9]{8})(?:\s+(\d+))?\s*$/i);if($){let h=$[1].toLowerCase(),b=$[2]?Number.parseInt($[2],10):e.jobLogTailLines,R=Number.isFinite(b)&&b>0?Math.min(b,500):e.jobLogTailLines;return S(m(t.tailLog(h,R)))}let L=c.match(/^\/tail\s+([a-f0-9]{8})\s*$/i);if(L){let h=L[1].toLowerCase(),b=Ui(d,h),R=n.get(b)??0,{text:J,nextOffset:xe}=t.readSince(h,R);return n.set(b,xe),S(J?m(J.trimEnd()||"(no new output)"):m(`(no new output; offset ${xe})`))}let _=c.match(/^\/kill\s+([a-f0-9]{8})\s*$/i);if(_){let h=_[1].toLowerCase();return S(m(t.kill(h)))}let O=c.match(/^\/(shortcut|shortcuts|alias|aliases)\b(?:\s+([\s\S]*))?$/i);if(O){let h=O[1].toLowerCase(),b=(O[2]??"").trim();return h==="shortcuts"&&!b?b="list":((h==="alias"||h==="aliases")&&!b||h==="shortcut"&&!b)&&(b="help"),S(Ki(b,d))}if(!u){let h=c.trim().match(/^\/([a-zA-Z0-9][a-zA-Z0-9_-]{0,31})\s*$/);if(h){let b=h[1],R=Xe(d,b);if(R!==void 0)return await He(e,t,n,r,o,{...s,text:R},i,a,l,!0)}}return S(so(e))}let f=c.match(/^>(\S+)\s*(.*)$/s);if(f){let w=f[1],M=f[2]??"",C=await i.writeNamedLine(d,w,M);return C?S(m(C)):null}return o.get(d)&&c?S(await os(e,d,c)):await i.writeFocusedLine(d,c)?null:S(io(e))}function qi(e){return e==="/run"||e.startsWith("/run ")?e.slice(4).trim():e==="/r"||e.startsWith("/r ")?e.slice(2).trim():null}function Yi(e,t,n,r){let o=e.trim();if(!o||/^help$/i.test(o))return E(po());if(/^list$/i.test(o))return mo(Eo(t,n));if(/^show$/i.test(o))return m("Usage: /run show <name>");let s=o.match(/^show\s+(\S+)\s*$/i);if(s){let d=s[1],p=et(t,n,d);return p?fo(p):_t(d)}if(/^add$/i.test(o))return m('Usage: /run add <name> <command\u2026> \u2014 command must include "$OMNISH_TASK"');if(/^set$/i.test(o))return m('Usage: /run set <name> <command\u2026> \u2014 command must include "$OMNISH_TASK"');let i=o.match(/^add\s+(\S+)\s+([\s\S]+)$/i);if(i)try{_n(t,i[1],{command:i[2].trim()});let d=Dt(i[1]),p=d.ok?d.normalized:i[1].toLowerCase(),f=et(t,n,p);return f?Cn(p,f):m("Recipe save failed.")}catch(d){return m(String(d))}let a=o.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(a)try{_n(t,a[1],{command:a[2].trim()});let d=Dt(a[1]),p=d.ok?d.normalized:a[1].toLowerCase(),f=et(t,n,p);return f?Cn(p,f):m("Recipe save failed.")}catch(d){return m(String(d))}let l=o.match(/^(?:remove|rm|del)\s+(\S+)\s*$/i);if(l){let d=l[1];return Ao(t,d)?m(`Recipe removed (this chat): ${d}`):_t(d)}if(/^(?:remove|rm|del)$/i.test(o))return m("Usage: /run remove <name>");let u=o.match(/^(\S+)\s+([\s\S]+)$/);if(u){let d=u[1],p=u[2],f=et(t,n,d);if(!f)return _t(d);let w=f.taskEnv??"OMNISH_TASK";if(!Bn(f.command,w))return m(`Recipe "${d}" command must reference "$${w}".`);let M=Io(p,n.recipesMaxTaskChars);if(!M.ok)return m(M.error);let C=Oo(d),X={[w]:M.task};return m(r.start(t,C,f.command,n,X))}let c=o.match(/^(\S+)$/);if(c){let d=c[1],p=d.toLowerCase();return p==="add"||p==="set"?m('Usage: /run add <name> <command\u2026> \u2014 include "$OMNISH_TASK"'):p==="show"?m("Usage: /run show <name>"):p==="remove"||p==="rm"||p==="del"?m("Usage: /run remove <name>"):et(t,n,p)?m(`Usage: /run ${d} <task\u2026>`):m(`Unknown recipe "${d}". /run list`)}return m("/run: could not parse. /run help")}function Ki(e,t){let n=e.trim();if(!n||/^help$/i.test(n))return E($n());if(/^list$/i.test(n))return lo(vo(t));let r=n.match(/^show\s+(\S+)\s*$/i);if(r){let a=r[1],l=Xe(t,a);return l===void 0?Mn(a):uo(a,l)}let o=n.match(/^add\s+(\S+)\s+([\s\S]+)$/i);if(o)try{In(t,o[1],o[2]);let a=Ht(o[1]),l=a.ok?a.normalized:o[1].trim().toLowerCase(),u=Xe(t,l);return Rn(l,u)}catch(a){return m(String(a))}let s=n.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(s)try{In(t,s[1],s[2]);let a=Ht(s[1]),l=a.ok?a.normalized:s[1].trim().toLowerCase(),u=Xe(t,l);return Rn(l,u)}catch(a){return m(String(a))}let i=n.match(/^(?:remove|rm|del)\s+(\S+)\s*$/i);if(i){let a=i[1];return $o(t,a)?co(a):Mn(a)}return E($n())}async function Vi(e,t,n,r,o){let s=e.slice(5).trim(),i=s.toLowerCase();if(!i||i==="help")return E(Tn());let a=s.match(/^(\S+)\s*(.*)$/s);if(!a)return E(Tn());let l=a[1].toLowerCase(),u=(a[2]??"").trim();switch(l){case"start":{let c=u.match(/^(\S+)\s+([\s\S]+)$/);return c?m(r.start(t,c[1],c[2],n)):m("Usage: /apps start <name> <command\u2026>")}case"attach":{let c=u.split(/\s+/)[0];return c?m(r.attach(t,c)):m("Usage: /apps attach <name>")}case"detach":return m(r.detach(t));case"list":return m(r.list(t));case"info":case"get":{let c=u.split(/\s+/)[0];return m(r.info(t,c||void 0))}case"send":{let c=u.match(/^(\S+)\s+([\s\S]+)$/);return c?m(await r.sendText(t,c[1],c[2])):m("Usage: /apps send <name> <text\u2026>")}case"key":{let c=u.match(/^(\S+)\s+([\s\S]+)$/);return c?m(r.sendKey(t,c[1],c[2].trim())):m("Usage: /apps key <name> <KEY[,KEY\u2026]>")}case"tail":{let c=u.match(/^(\S+)(?:\s+(\d+))?\s*$/);if(!c)return m("Usage: /apps tail <name> [lines]");let d=c[2]?Number.parseInt(c[2],10):n.appsLogTailLines;return m(r.tail(t,c[1],d))}case"since":{let c=u.split(/\s+/)[0];if(!c)return m("Usage: /apps since <name>");let d=Gi(t,c),p=o.get(d)??0,{text:f,nextOffset:w}=r.readSince(t,c,p);return o.set(d,w),m(f.trimEnd()||"(no new log bytes)")}case"mute":{let c=u.split(/\s+/)[0];return c?m(r.mute(t,c)):m("Usage: /apps mute <name>")}case"unmute":{let c=u.split(/\s+/)[0];return c?m(r.unmute(t,c)):m("Usage: /apps unmute <name>")}case"raw":{let c=u.match(/^(\S+)\s+(on|off)\s*$/i);return c?m(r.setRaw(t,c[1],c[2].toLowerCase()==="on")):m("Usage: /apps raw <name> on|off")}case"resize":{let c=u.trim().split(/\s+/).filter(Boolean);if(c.length<3)return m("Usage: /apps resize <name> <cols> <rows>");let d=c[0],p=Number(c[1]),f=Number(c[2]);return!Number.isFinite(p)||!Number.isFinite(f)?m("cols and rows must be numbers."):m(r.resize(t,d,p,f))}case"stop":{let c=u.split(/\s+/)[0];return c?m(r.stop(t,c)):m("Usage: /apps stop <name>")}case"kill":{let c=u.split(/\s+/)[0];return c?m(r.kill(t,c)):m("Usage: /apps kill <name>")}case"rm":{let c=u.split(/\s+/)[0];return c?m(r.rm(t,c)):m("Usage: /apps rm <name>")}default:return m(`Unknown /apps subcommand "${l}". /apps help`)}}function Kn(e,t,n){return!e.clusterEnabled||Yn(t.trim())!==null?!0:n?Jo(n,e):!1}import Qi from"pino";function Qt(){return process.env.OMNISH_VERBOSE==="1"||process.env.WHATSVERBOSE==="1"}var Zi=Qt()?"info":"silent",A=Qi({level:Zi,base:{app:"omnish"}});function ss(){return A.child({module:"baileys"})}function Xi(e){return`wa:${e}`}function Vn(e){return`tg:${e}`}function is(e){return{peerKey:Xi(e.fromJid),text:e.text,waMessageId:e.messageId,mediaSavedPath:e.mediaSavedPath,mediaError:e.mediaError}}import Le from"node:fs";import aa from"node:path";var as={enter:"\r",cr:"\r",lf:`
150
- `,return:"\r",tab:" ",esc:"\x1B",escape:"\x1B",space:" ",backspace:"\x7F",bs:"\x7F",delete:"\x1B[3~",up:"\x1B[A",down:"\x1B[B",right:"\x1B[C",left:"\x1B[D",home:"\x1B[H",end:"\x1B[F",pageup:"\x1B[5~",pagedown:"\x1B[6~","ctrl+c":"","ctrl+d":"","ctrl+z":"","ctrl+l":"\f","ctrl+u":"","ctrl+k":"\v"};function ea(e){let t="";for(let n=0;n<e.length;n++){let r=e[n];if(r==="\\"&&n+1<e.length){let o=e[n+1];if(o==="x"&&n+3<e.length){let s=e.slice(n+2,n+4);if(/^[0-9a-fA-F]{2}$/.test(s)){t+=String.fromCharCode(Number.parseInt(s,16)),n+=3;continue}}if(o==="r"){t+="\r",n++;continue}if(o==="n"){t+=`
151
- `,n++;continue}if(o==="t"){t+=" ",n++;continue}if(o==="\\"){t+="\\",n++;continue}}t+=r}return t}function ta(e){let t=e.trim();if(!t)return"";if(t.startsWith("\\"))return ea(t);let n=t.toLowerCase();if(as[n])return as[n];let r=t.match(/^\^([A-Za-z])$/);if(r){let s=r[1].toUpperCase().charCodeAt(0);if(s>=64&&s<=95)return String.fromCharCode(s-64)}let o=n.match(/^ctrl\+(.+)$/);if(o){let s=o[1];if(s.length===1){let i=s.toUpperCase().charCodeAt(0);if(i>=64&&i<=95)return String.fromCharCode(i-64)}}return t}function Qn(e){let t=e.split(",").map(n=>n.trim()).filter(Boolean);return t.length===0?"":t.map(n=>ta(n)).join("")}var ht="\x1B";function ls(e){let t=e;return t=t.replace(new RegExp(`${ht}\\[[\\d;?]*[ -/]*[@-~]`,"g"),""),t=t.replace(new RegExp(`${ht}\\][^${ht}\\u0007]*(?:\\u0007|${ht}\\\\)`,"g"),""),t=t.replace(new RegExp(`${ht}[@-Z\\\\-_]`,"g"),""),t=t.replace(/\u0007/g,""),t}function na(e,t){if(e.length<=t)return e?[e]:[];let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}function ra(e,t){return`${e}${t}`}var Zt=class{constructor(t){this.opts=t}pending=new Map;timers=new Map;lastFlushEnd=new Map;flushing=new Set;closed=!1;dispose(){this.closed=!0;for(let t of this.timers.values())clearTimeout(t);this.timers.clear(),this.pending.clear(),this.lastFlushEnd.clear(),this.flushing.clear()}push(t,n,r){if(this.closed||this.opts.isMuted(t,n))return;let o=ra(t,n);this.pending.set(o,(this.pending.get(o)??"")+r);let s=this.timers.get(o);s&&clearTimeout(s);let i=this.opts.getCfg().appsFlushMs,a=setTimeout(()=>{this.timers.delete(o),this.flushNow(o,t,n)},i);this.timers.set(o,a)}async flushNow(t,n,r){if(!(this.closed||this.flushing.has(t))){this.flushing.add(t);try{let o=this.opts.getCfg(),s=o.appsMinIntervalMs,i=this.lastFlushEnd.get(t)??0,a=Math.max(0,i+s-Date.now());if(a>0&&await new Promise(f=>setTimeout(f,a)),this.closed)return;let l=this.pending.get(t)??"";if(this.pending.delete(t),!l||(this.opts.isRaw(n,r)||(l=ls(l)),!l.trim()))return;let u=o.appsMaxFlushBytes;if(l.length>u){let f=l.slice(u);l=l.slice(0,u)+`
152
- [\u2026+${f.length} chars; /apps since ${r} to read more]`,this.pending.set(t,(this.pending.get(t)??"")+f)}let d=(this.opts.getRunningCount(n)>1?`[${r}] `:"")+l,p=na(d,o.appsMaxWaChars);for(let f of p){if(this.closed)break;try{await this.opts.send(n,f)}catch{break}}this.lastFlushEnd.set(t,Date.now())}finally{this.flushing.delete(t),!this.closed&&(this.pending.get(t)??"").length>0&&queueMicrotask(()=>void this.flushNow(t,n,r))}}}};import oa from"node:fs";import sa from"node:path";import*as cs from"node-pty";var ia=1024*1024,Xt=class e{peerKey;name;command;cwd;envKeysCount;logPath;term=null;logStream=null;disposeData=null;disposeExit=null;exited=!1;ringChunks=[];ringBytes=0;constructor(t){this.peerKey=t.peerKey,this.name=t.name,this.command=t.command,this.cwd=t.cwd,this.envKeysCount=t.envKeysCount,this.logPath=t.logPath}appendRing(t){for(this.ringChunks.push(t),this.ringBytes+=t.length;this.ringBytes>ia&&this.ringChunks.length>0;){let n=this.ringChunks.shift();this.ringBytes-=n.length}}static start(t){P(ut(t.peerKey));let n=sa.join(ut(t.peerKey),`${t.name}.log`),r=oa.createWriteStream(n,{flags:"a",mode:384}),o={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...t.cwd?{PWD:t.cwd}:{},...t.extraEnv??{}},s=cs.spawn(t.shell,["-lc",t.command],{name:"xterm-256color",cols:t.cols,rows:t.rows,cwd:t.cwd,env:o}),i=new e({...t,logPath:n});return i.term=s,i.logStream=r,i.disposeData=s.onData(a=>{let l=Buffer.from(a,"utf8");i.appendRing(l),r.write(a),t.router.push(t.peerKey,t.name,a)}),i.disposeExit=s.onExit(a=>{i.exited||(i.exited=!0,i.cleanupTerm(),t.onExit({exitCode:a.exitCode,signal:a.signal}))}),i}get alive(){return this.term!==null&&!this.exited}get ringByteCount(){return this.ringBytes}write(t){this.term?.write(t)}resize(t,n){this.term?.resize(t,n)}kill(t){if(this.term)try{this.term.kill(t)}catch{}}cleanupTerm(){this.disposeData?.dispose(),this.disposeData=null,this.disposeExit?.dispose(),this.disposeExit=null,this.term=null,this.logStream?.end(),this.logStream=null}destroy(){if(this.exited){this.cleanupTerm();return}this.exited=!0,this.kill("SIGHUP"),this.cleanupTerm()}};var la=/^[a-zA-Z0-9_-]{1,32}$/;function ce(e){return la.test(e)?null:"Session name must be 1\u201332 chars: letters, digits, _ or -."}function se(e,t){return`${e}:${t}`}function ca(e){let t=e.lastIndexOf(":");return t<=0?null:{peerKey:e.slice(0,t),name:e.slice(t+1)}}function Zn(e){return new Promise(t=>setTimeout(t,e))}async function Xn(e,t,n){let r=n.appsSubmitDelayMs,o=n.appsClearInputDelayMs,i=n.appsClearInput!==!1?Qn(n.appsClearInputSequence||"^A,^K"):"",l=t.replace(/\r\n/g,`
173
+ `)))}let $e=c.match(/^\/log\s+([a-f0-9]{8})(?:\s+(\d+))?\s*$/i);if($e){let g=$e[1].toLowerCase(),S=$e[2]?Number.parseInt($e[2],10):e.jobLogTailLines,v=Number.isFinite(S)&&S>0?Math.min(S,500):e.jobLogTailLines;return x(p(t.tailLog(g,v)))}let C=c.match(/^\/tail\s+([a-f0-9]{8})\s*$/i);if(C){let g=C[1].toLowerCase(),S=ml(u,g),v=n.get(S)??0,{text:K,nextOffset:ne}=t.readSince(g,v);return n.set(S,ne),x(K?p(K.trimEnd()||"(no new output)"):p(`(no new output; offset ${ne})`))}let N=c.match(/^\/kill\s+([a-f0-9]{8})\s*$/i);if(N){let g=N[1].toLowerCase();return x(p(t.kill(g)))}let j=c.match(/^\/(shortcut|shortcuts|alias|aliases)\b(?:\s+([\s\S]*))?$/i);if(j){let g=j[1].toLowerCase(),S=(j[2]??"").trim();return g==="shortcuts"&&!S?S="list":((g==="alias"||g==="aliases")&&!S||g==="shortcut"&&!S)&&(S="help"),x(bl(S,u))}if(!d){let g=c.trim().match(/^\/([a-zA-Z0-9][a-zA-Z0-9_-]{0,31})\s*$/);if(g){let S=g[1],v=st(u,S);if(v!==void 0)return await Je(e,t,n,r,o,{...s,text:v},i,a,l,!0)}}return x(_o(e))}let f=c.match(/^>(\S+)\s*(.*)$/s);if(f){let y=f[1],w=f[2]??"",k=await i.writeNamedLine(u,y,w);return k?x(p(k)):null}return o.get(u)&&c?x(await ei(e,u,c)):await i.writeFocusedLine(u,c)?null:x(Bo(e))}function yl(e){return e==="/run"||e.startsWith("/run ")?e.slice(4).trim():e==="/r"||e.startsWith("/r ")?e.slice(2).trim():null}function wl(e,t,n,r){let o=e.trim();if(!o||/^help$/i.test(o))return O(Uo());if(/^list$/i.test(o))return Go(ls(t,n));if(/^show$/i.test(o))return p("Usage: /run show <name>");let s=o.match(/^show\s+(\S+)\s*$/i);if(s){let u=s[1],m=it(t,n,u);return m?zo(m):tn(u)}if(/^add$/i.test(o))return p('Usage: /run add <name> <command\u2026> \u2014 command must include "$OMNISH_TASK"');if(/^set$/i.test(o))return p('Usage: /run set <name> <command\u2026> \u2014 command must include "$OMNISH_TASK"');let i=o.match(/^add\s+(\S+)\s+([\s\S]+)$/i);if(i)try{lr(t,i[1],{command:i[2].trim()});let u=an(i[1]),m=u.ok?u.normalized:i[1].toLowerCase(),f=it(t,n,m);return f?Qn(m,f):p("Recipe save failed.")}catch(u){return p(String(u))}let a=o.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(a)try{lr(t,a[1],{command:a[2].trim()});let u=an(a[1]),m=u.ok?u.normalized:a[1].toLowerCase(),f=it(t,n,m);return f?Qn(m,f):p("Recipe save failed.")}catch(u){return p(String(u))}let l=o.match(/^(?:remove|rm|del)\s+(\S+)\s*$/i);if(l){let u=l[1];return as(t,u)?p(`Recipe removed (this chat): ${u}`):tn(u)}if(/^(?:remove|rm|del)$/i.test(o))return p("Usage: /run remove <name>");let d=o.match(/^(\S+)\s+([\s\S]+)$/);if(d){let u=d[1],m=d[2],f=it(t,n,u);if(!f)return tn(u);let y=f.taskEnv??"OMNISH_TASK";if(!ar(f.command,y))return p(`Recipe "${u}" command must reference "$${y}".`);let w=is(m,n.recipesMaxTaskChars);if(!w.ok)return p(w.error);let k=cs(u),E={[y]:w.task};return p(r.start(t,k,f.command,n,E))}let c=o.match(/^(\S+)$/);if(c){let u=c[1],m=u.toLowerCase();return m==="add"||m==="set"?p('Usage: /run add <name> <command\u2026> \u2014 include "$OMNISH_TASK"'):m==="show"?p("Usage: /run show <name>"):m==="remove"||m==="rm"||m==="del"?p("Usage: /run remove <name>"):it(t,n,m)?p(`Usage: /run ${u} <task\u2026>`):p(`Unknown recipe "${u}". /run list`)}return p("/run: could not parse. /run help")}function bl(e,t){let n=e.trim();if(!n||/^help$/i.test(n))return O(Yn());if(/^list$/i.test(n))return Ho(es(t));let r=n.match(/^show\s+(\S+)\s*$/i);if(r){let a=r[1],l=st(t,a);return l===void 0?Xn(a):Wo(a,l)}let o=n.match(/^add\s+(\S+)\s+([\s\S]+)$/i);if(o)try{er(t,o[1],o[2]);let a=rn(o[1]),l=a.ok?a.normalized:o[1].trim().toLowerCase(),d=st(t,l);return Vn(l,d)}catch(a){return p(String(a))}let s=n.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(s)try{er(t,s[1],s[2]);let a=rn(s[1]),l=a.ok?a.normalized:s[1].trim().toLowerCase(),d=st(t,l);return Vn(l,d)}catch(a){return p(String(a))}let i=n.match(/^(?:remove|rm|del)\s+(\S+)\s*$/i);if(i){let a=i[1];return ts(t,a)?jo(a):Xn(a)}return O(Yn())}async function kl(e,t,n,r,o){let s=e.slice(5).trim(),i=s.toLowerCase();if(!i||i==="help")return O(Zn());let a=s.match(/^(\S+)\s*(.*)$/s);if(!a)return O(Zn());let l=a[1].toLowerCase(),d=(a[2]??"").trim();switch(l){case"start":{let c=d.match(/^(\S+)\s+([\s\S]+)$/);return c?p(r.start(t,c[1],c[2],n)):p("Usage: /apps start <name> <command\u2026>")}case"attach":{let c=d.split(/\s+/)[0];return c?p(r.attach(t,c)):p("Usage: /apps attach <name>")}case"detach":return p(r.detach(t));case"list":return p(r.list(t));case"info":case"get":{let c=d.split(/\s+/)[0];return p(r.info(t,c||void 0))}case"send":{let c=d.match(/^(\S+)\s+([\s\S]+)$/);return c?p(await r.sendText(t,c[1],c[2])):p("Usage: /apps send <name> <text\u2026>")}case"key":{let c=d.match(/^(\S+)\s+([\s\S]+)$/);return c?p(r.sendKey(t,c[1],c[2].trim())):p("Usage: /apps key <name> <KEY[,KEY\u2026]>")}case"tail":{let c=d.match(/^(\S+)(?:\s+(\d+))?\s*$/);if(!c)return p("Usage: /apps tail <name> [lines]");let u=c[2]?Number.parseInt(c[2],10):n.appsLogTailLines;return p(r.tail(t,c[1],u))}case"since":{let c=d.split(/\s+/)[0];if(!c)return p("Usage: /apps since <name>");let u=fl(t,c),m=o.get(u)??0,{text:f,nextOffset:y}=r.readSince(t,c,m);return o.set(u,y),p(f.trimEnd()||"(no new log bytes)")}case"mute":{let c=d.split(/\s+/)[0];return c?p(r.mute(t,c)):p("Usage: /apps mute <name>")}case"unmute":{let c=d.split(/\s+/)[0];return c?p(r.unmute(t,c)):p("Usage: /apps unmute <name>")}case"raw":{let c=d.match(/^(\S+)\s+(on|off)\s*$/i);return c?p(r.setRaw(t,c[1],c[2].toLowerCase()==="on")):p("Usage: /apps raw <name> on|off")}case"resize":{let c=d.trim().split(/\s+/).filter(Boolean);if(c.length<3)return p("Usage: /apps resize <name> <cols> <rows>");let u=c[0],m=Number(c[1]),f=Number(c[2]);return!Number.isFinite(m)||!Number.isFinite(f)?p("cols and rows must be numbers."):p(r.resize(t,u,m,f))}case"stop":{let c=d.split(/\s+/)[0];return c?p(r.stop(t,c)):p("Usage: /apps stop <name>")}case"kill":{let c=d.split(/\s+/)[0];return c?p(r.kill(t,c)):p("Usage: /apps kill <name>")}case"rm":{let c=d.split(/\s+/)[0];return c?p(r.rm(t,c)):p("Usage: /apps rm <name>")}default:return p(`Unknown /apps subcommand "${l}". /apps help`)}}function Mr(e,t,n){return!e.clusterEnabled||Rr(t.trim())!==null?!0:n?vs(n,e):!1}function Sl(e){return`wa:${e}`}function Tr(e){return`tg:${e}`}function ti(e){return{peerKey:Sl(e.fromJid),text:e.text,waMessageId:e.messageId,mediaSavedPath:e.mediaSavedPath,mediaError:e.mediaError}}import je from"node:fs";import Il from"node:path";var ni={enter:"\r",cr:"\r",lf:`
174
+ `,return:"\r",tab:" ",esc:"\x1B",escape:"\x1B",space:" ",backspace:"\x7F",bs:"\x7F",delete:"\x1B[3~",up:"\x1B[A",down:"\x1B[B",right:"\x1B[C",left:"\x1B[D",home:"\x1B[H",end:"\x1B[F",pageup:"\x1B[5~",pagedown:"\x1B[6~","ctrl+c":"","ctrl+d":"","ctrl+z":"","ctrl+l":"\f","ctrl+u":"","ctrl+k":"\v"};function xl(e){let t="";for(let n=0;n<e.length;n++){let r=e[n];if(r==="\\"&&n+1<e.length){let o=e[n+1];if(o==="x"&&n+3<e.length){let s=e.slice(n+2,n+4);if(/^[0-9a-fA-F]{2}$/.test(s)){t+=String.fromCharCode(Number.parseInt(s,16)),n+=3;continue}}if(o==="r"){t+="\r",n++;continue}if(o==="n"){t+=`
175
+ `,n++;continue}if(o==="t"){t+=" ",n++;continue}if(o==="\\"){t+="\\",n++;continue}}t+=r}return t}function vl(e){let t=e.trim();if(!t)return"";if(t.startsWith("\\"))return xl(t);let n=t.toLowerCase();if(ni[n])return ni[n];let r=t.match(/^\^([A-Za-z])$/);if(r){let s=r[1].toUpperCase().charCodeAt(0);if(s>=64&&s<=95)return String.fromCharCode(s-64)}let o=n.match(/^ctrl\+(.+)$/);if(o){let s=o[1];if(s.length===1){let i=s.toUpperCase().charCodeAt(0);if(i>=64&&i<=95)return String.fromCharCode(i-64)}}return t}function Ir(e){let t=e.split(",").map(n=>n.trim()).filter(Boolean);return t.length===0?"":t.map(n=>vl(n)).join("")}var Lt="\x1B";function ri(e){let t=e;return t=t.replace(new RegExp(`${Lt}\\[[\\d;?]*[ -/]*[@-~]`,"g"),""),t=t.replace(new RegExp(`${Lt}\\][^${Lt}\\u0007]*(?:\\u0007|${Lt}\\\\)`,"g"),""),t=t.replace(new RegExp(`${Lt}[@-Z\\\\-_]`,"g"),""),t=t.replace(/\u0007/g,""),t}function $l(e,t){if(e.length<=t)return e?[e]:[];let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}function Cl(e,t){return`${e}${t}`}var Sn=class{constructor(t){this.opts=t}pending=new Map;timers=new Map;lastFlushEnd=new Map;flushing=new Set;closed=!1;dispose(){this.closed=!0;for(let t of this.timers.values())clearTimeout(t);this.timers.clear(),this.pending.clear(),this.lastFlushEnd.clear(),this.flushing.clear()}push(t,n,r){if(this.closed||this.opts.isMuted(t,n))return;let o=Cl(t,n);this.pending.set(o,(this.pending.get(o)??"")+r);let s=this.timers.get(o);s&&clearTimeout(s);let i=this.opts.getCfg().appsFlushMs,a=setTimeout(()=>{this.timers.delete(o),this.flushNow(o,t,n)},i);this.timers.set(o,a)}async flushNow(t,n,r){if(!(this.closed||this.flushing.has(t))){this.flushing.add(t);try{let o=this.opts.getCfg(),s=o.appsMinIntervalMs,i=this.lastFlushEnd.get(t)??0,a=Math.max(0,i+s-Date.now());if(a>0&&await new Promise(f=>setTimeout(f,a)),this.closed)return;let l=this.pending.get(t)??"";if(this.pending.delete(t),!l||(this.opts.isRaw(n,r)||(l=ri(l)),!l.trim()))return;let d=o.appsMaxFlushBytes;if(l.length>d){let f=l.slice(d);l=l.slice(0,d)+`
176
+ [\u2026+${f.length} chars; /apps since ${r} to read more]`,this.pending.set(t,(this.pending.get(t)??"")+f)}let u=(this.opts.getRunningCount(n)>1?`[${r}] `:"")+l,m=$l(u,o.appsMaxWaChars);for(let f of m){if(this.closed)break;try{await this.opts.send(n,f)}catch{break}}this.lastFlushEnd.set(t,Date.now())}finally{this.flushing.delete(t),!this.closed&&(this.pending.get(t)??"").length>0&&queueMicrotask(()=>void this.flushNow(t,n,r))}}}};import Rl from"node:fs";import Ml from"node:path";import*as oi from"node-pty";var Tl=1024*1024,xn=class e{peerKey;name;command;cwd;envKeysCount;logPath;term=null;logStream=null;disposeData=null;disposeExit=null;exited=!1;ringChunks=[];ringBytes=0;constructor(t){this.peerKey=t.peerKey,this.name=t.name,this.command=t.command,this.cwd=t.cwd,this.envKeysCount=t.envKeysCount,this.logPath=t.logPath}appendRing(t){for(this.ringChunks.push(t),this.ringBytes+=t.length;this.ringBytes>Tl&&this.ringChunks.length>0;){let n=this.ringChunks.shift();this.ringBytes-=n.length}}static start(t){L(wt(t.peerKey));let n=Ml.join(wt(t.peerKey),`${t.name}.log`),r=Rl.createWriteStream(n,{flags:"a",mode:384}),o={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...t.cwd?{PWD:t.cwd}:{},...t.extraEnv??{}},s=oi.spawn(t.shell,["-lc",t.command],{name:"xterm-256color",cols:t.cols,rows:t.rows,cwd:t.cwd,env:o}),i=new e({...t,logPath:n});return i.term=s,i.logStream=r,i.disposeData=s.onData(a=>{let l=Buffer.from(a,"utf8");i.appendRing(l),r.write(a),t.router.push(t.peerKey,t.name,a)}),i.disposeExit=s.onExit(a=>{i.exited||(i.exited=!0,i.cleanupTerm(),t.onExit({exitCode:a.exitCode,signal:a.signal}))}),i}get alive(){return this.term!==null&&!this.exited}get ringByteCount(){return this.ringBytes}write(t){this.term?.write(t)}resize(t,n){this.term?.resize(t,n)}kill(t){if(this.term)try{this.term.kill(t)}catch{}}cleanupTerm(){this.disposeData?.dispose(),this.disposeData=null,this.disposeExit?.dispose(),this.disposeExit=null,this.term=null,this.logStream?.end(),this.logStream=null}destroy(){if(this.exited){this.cleanupTerm();return}this.exited=!0,this.kill("SIGHUP"),this.cleanupTerm()}};var Al=/^[a-zA-Z0-9_-]{1,32}$/;function fe(e){return Al.test(e)?null:"Session name must be 1\u201332 chars: letters, digits, _ or -."}function ce(e,t){return`${e}:${t}`}function El(e){let t=e.lastIndexOf(":");return t<=0?null:{peerKey:e.slice(0,t),name:e.slice(t+1)}}function Ar(e){return new Promise(t=>setTimeout(t,e))}async function Er(e,t,n){let r=n.appsSubmitDelayMs,o=n.appsClearInputDelayMs,i=n.appsClearInput!==!1?Ir(n.appsClearInputSequence||"^A,^K"):"",l=t.replace(/\r\n/g,`
153
177
  `).replace(/\r/g,"").split(`
154
- `);i&&(o>0&&await Zn(o),e.write(i));for(let u of l)u.length>0&&e.write(u),r>0&&await Zn(r),e.write("\r"),i&&(o>0&&await Zn(o),e.write(i))}function ua(e,t){try{let r=Le.readFileSync(e,"utf8").split(/\r?\n/);return r.slice(Math.max(0,r.length-t)).join(`
155
- `).trimEnd()}catch{return""}}var ot=class{constructor(t,n){this.getCfg=t;this.send=n,this.router=new Zt({getCfg:()=>this.getCfg(),send:n,isMuted:(r,o)=>this.muted.has(se(r,o)),isRaw:(r,o)=>this.rawMode.has(se(r,o)),getRunningCount:r=>this.countPeerRunning(r)})}sessions=new Map;focus=new Map;muted=new Set;rawMode=new Set;router;killTimers=new Set;send;countPeerRunning(t){let n=`${t}:`,r=0;for(let[o,s]of this.sessions)o.startsWith(n)&&s.alive&&r++;return r}countTotalRunning(){let t=0;for(let n of this.sessions.values())n.alive&&t++;return t}dispose(){for(let t of this.killTimers)clearTimeout(t);this.killTimers.clear(),this.stopAll(),this.router.dispose()}stopAll(){for(let t of this.sessions.values())t.destroy();this.sessions.clear(),this.focus.clear()}getFocus(t){return this.focus.get(t)??null}logPath(t,n){return aa.join(ut(t),`${n}.log`)}getSession(t,n){return this.sessions.get(se(t,n))}removeSessionRecord(t,n){this.sessions.delete(se(t,n)),this.focus.get(t)===n&&this.focus.set(t,null)}async writeFocusedLine(t,n){let r=this.focus.get(t);if(!r)return!1;let o=this.getSession(t,r);return o?.alive?(await Xn(o,n,this.getCfg()),!0):!1}async writeNamedLine(t,n,r){let o=ce(n);if(o)return o;let s=this.getSession(t,n);return s?.alive?(await Xn(s,r,this.getCfg()),null):`No app session "${n}". /apps list`}start(t,n,r,o,s){let i=ce(n);if(i)return i;if(!r.trim())return`Usage: /apps start <name> <command\u2026>
156
- Example: /apps start sh bash`;if(this.sessions.has(se(t,n)))return`Session "${n}" already exists. /apps stop ${n} or pick another name.`;if(this.countPeerRunning(t)>=o.appsMaxSessions)return`Per-chat app limit (${o.appsMaxSessions}) reached. /apps stop or /apps rm an old session.`;if(this.countTotalRunning()>=o.appsMaxSessionsTotal)return`Global app limit (${o.appsMaxSessionsTotal}) reached. Stop sessions in other chats first.`;G();let a=z(t).cwd,l={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...a?{PWD:a}:{},...s??{}},u;try{u=Xt.start({peerKey:t,name:n,shell:o.shell,command:r.trim(),cwd:a,cols:o.appsCols,rows:o.appsRows,envKeysCount:Object.keys(l).length,extraEnv:s,router:this.router,onExit:c=>{this.handleSessionExit(t,n,c)}})}catch(c){return`App spawn failed: ${String(c)}
157
- If install skipped native builds: pnpm approve-builds && pnpm install (needs @whiskeysockets/baileys, sharp, protobufjs, esbuild, node-pty).`}return this.sessions.set(se(t,n),u),this.focus.set(t,n),`App "${n}" started and attached.
178
+ `);i&&(o>0&&await Ar(o),e.write(i));for(let d of l)d.length>0&&e.write(d),r>0&&await Ar(r),e.write("\r"),i&&(o>0&&await Ar(o),e.write(i))}function Ol(e,t){try{let r=je.readFileSync(e,"utf8").split(/\r?\n/);return r.slice(Math.max(0,r.length-t)).join(`
179
+ `).trimEnd()}catch{return""}}var pt=class{constructor(t,n){this.getCfg=t;this.send=n,this.router=new Sn({getCfg:()=>this.getCfg(),send:n,isMuted:(r,o)=>this.muted.has(ce(r,o)),isRaw:(r,o)=>this.rawMode.has(ce(r,o)),getRunningCount:r=>this.countPeerRunning(r)})}sessions=new Map;focus=new Map;muted=new Set;rawMode=new Set;router;killTimers=new Set;send;countPeerRunning(t){let n=`${t}:`,r=0;for(let[o,s]of this.sessions)o.startsWith(n)&&s.alive&&r++;return r}countTotalRunning(){let t=0;for(let n of this.sessions.values())n.alive&&t++;return t}dispose(){for(let t of this.killTimers)clearTimeout(t);this.killTimers.clear(),this.stopAll(),this.router.dispose()}stopAll(){for(let t of this.sessions.values())t.destroy();this.sessions.clear(),this.focus.clear()}getFocus(t){return this.focus.get(t)??null}logPath(t,n){return Il.join(wt(t),`${n}.log`)}getSession(t,n){return this.sessions.get(ce(t,n))}removeSessionRecord(t,n){this.sessions.delete(ce(t,n)),this.focus.get(t)===n&&this.focus.set(t,null)}async writeFocusedLine(t,n){let r=this.focus.get(t);if(!r)return!1;let o=this.getSession(t,r);return o?.alive?(await Er(o,n,this.getCfg()),!0):!1}async writeNamedLine(t,n,r){let o=fe(n);if(o)return o;let s=this.getSession(t,n);return s?.alive?(await Er(s,r,this.getCfg()),null):`No app session "${n}". /apps list`}start(t,n,r,o,s){let i=fe(n);if(i)return i;if(!r.trim())return`Usage: /apps start <name> <command\u2026>
180
+ Example: /apps start sh bash`;if(this.sessions.has(ce(t,n)))return`Session "${n}" already exists. /apps stop ${n} or pick another name.`;if(this.countPeerRunning(t)>=o.appsMaxSessions)return`Per-chat app limit (${o.appsMaxSessions}) reached. /apps stop or /apps rm an old session.`;if(this.countTotalRunning()>=o.appsMaxSessionsTotal)return`Global app limit (${o.appsMaxSessionsTotal}) reached. Stop sessions in other chats first.`;Q();let a=H(t).cwd,l={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...a?{PWD:a}:{},...s??{}},d;try{d=xn.start({peerKey:t,name:n,shell:o.shell,command:r.trim(),cwd:a,cols:o.appsCols,rows:o.appsRows,envKeysCount:Object.keys(l).length,extraEnv:s,router:this.router,onExit:c=>{this.handleSessionExit(t,n,c)}})}catch(c){return`App spawn failed: ${String(c)}
181
+ If install skipped native builds: pnpm approve-builds && pnpm install (needs @whiskeysockets/baileys, sharp, protobufjs, esbuild, node-pty).`}return this.sessions.set(ce(t,n),d),this.focus.set(t,n),`App "${n}" started and attached.
158
182
  [cwd: ${a}]
159
- Plain DMs go to this session until /apps detach. Use >othername text for another session.`}async handleSessionExit(t,n,r){let o=se(t,n);if(!this.sessions.has(o))return;let s=this.focus.get(t)===n;this.sessions.delete(o),s&&this.focus.set(t,null),this.muted.delete(o),this.rawMode.delete(o);let i=r.signal!=null?` signal=${r.signal}`:"",a=s?" (detached)":"",l=`[${n}] exited code=${r.exitCode}${i}${a}`;try{await this.send(t,l)}catch{}}attach(t,n){let r=ce(n);return r||(this.getSession(t,n)?.alive?(this.focus.set(t,n),`Attached to "${n}". Plain messages (no ! or / or >) go to this app. /apps detach to stop.`):`No session "${n}". /apps list`)}detach(t){return this.focus.set(t,null),"Detached (attach mode off)."}list(t){let n=[];for(let[s,i]of this.sessions){let a=ca(s);if(!a||a.peerKey!==t||!i.alive)continue;let l=this.focus.get(t)===a.name?" *":"";n.push(`${a.name}${l}`)}if(n.length===0)return"(no app sessions; /apps start <name> <cmd>)";let r=this.focus.get(t);return`${r?`attached: ${r}`:"(no focus)"}
183
+ Plain DMs go to this session until /apps detach. Use >othername text for another session.`}async handleSessionExit(t,n,r){let o=ce(t,n);if(!this.sessions.has(o))return;let s=this.focus.get(t)===n;this.sessions.delete(o),s&&this.focus.set(t,null),this.muted.delete(o),this.rawMode.delete(o);let i=r.signal!=null?` signal=${r.signal}`:"",a=s?" (detached)":"",l=`[${n}] exited code=${r.exitCode}${i}${a}`;try{await this.send(t,l)}catch{}}attach(t,n){let r=fe(n);return r||(this.getSession(t,n)?.alive?(this.focus.set(t,n),`Attached to "${n}". Plain messages (no ! or / or >) go to this app. /apps detach to stop.`):`No session "${n}". /apps list`)}detach(t){return this.focus.set(t,null),"Detached (attach mode off)."}list(t){let n=[];for(let[s,i]of this.sessions){let a=El(s);if(!a||a.peerKey!==t||!i.alive)continue;let l=this.focus.get(t)===a.name?" *":"";n.push(`${a.name}${l}`)}if(n.length===0)return"(no app sessions; /apps start <name> <cmd>)";let r=this.focus.get(t);return`${r?`attached: ${r}`:"(no focus)"}
160
184
  App sessions:
161
185
  ${n.join(`
162
- `)}`}info(t,n){let r=this.getCfg(),o=n??this.focus.get(t)??"";if(!o)return"Usage: /apps info <name> (or /apps get <name>, or attach first)";let s=ce(o);if(s)return s;let i=this.getSession(t,o),a=this.logPath(t,o),l=0;try{l=Le.statSync(a).size}catch{}let u=this.muted.has(se(t,o)),c=this.rawMode.has(se(t,o));return[`session: ${o}`,`alive: ${i?.alive??!1}`,`cmd: ${i?.command??"(unknown)"}`,`cwd: ${i?.cwd??"(unknown)"}`,`env keys: ${i?.envKeysCount??"?"}`,`terminal size: ${r.appsCols}x${r.appsRows}`,`ring bytes (approx): ${i?.ringByteCount??0}`,`log: ${a} (${l} bytes)`,`mute outbound: ${u}`,`raw outbound: ${c}`].join(`
163
- `)}async sendText(t,n,r){let o=ce(n);if(o)return o;let s=this.getSession(t,n);if(!s?.alive)return`No session "${n}".`;let i=r.replace(/\r\n/g,`
164
- `);return await Xn(s,i,this.getCfg()),`Sent to "${n}" (${i.length} chars + Enter per line).`}sendKey(t,n,r){let o=ce(n);if(o)return o;let s=this.getSession(t,n);if(!s?.alive)return`No session "${n}".`;let i=Qn(r);return i?(s.write(i),`Sent keys to "${n}".`):"Empty key sequence. Example: /apps key sh Enter or ^C,Up,Enter"}tail(t,n,r){let o=ce(n);if(o)return o;let s=this.logPath(t,n);if(!Le.existsSync(s))return`(no log file for ${n})`;let i=this.getCfg(),a=Number.isFinite(r)&&r>0?Math.min(500,r):i.appsLogTailLines;return ua(s,a)||"(empty log)"}readSince(t,n,r){let o=this.logPath(t,n);try{let i=Le.statSync(o).size,a=Le.openSync(o,"r");try{let l=Math.min(r,i),u=i-l,c=Buffer.alloc(u);return u>0&&Le.readSync(a,c,0,u,l),{text:c.toString("utf8"),nextOffset:i}}finally{Le.closeSync(a)}}catch{return{text:"",nextOffset:r}}}mute(t,n){let r=ce(n);return r||(this.muted.add(se(t,n)),`Muted chat output for "${n}" (log still grows). /apps unmute ${n}`)}unmute(t,n){let r=ce(n);return r||(this.muted.delete(se(t,n)),`Unmuted "${n}".`)}setRaw(t,n,r){let o=ce(n);if(o)return o;let s=se(t,n);return r?this.rawMode.add(s):this.rawMode.delete(s),`raw chat output for "${n}": ${r?"on (ANSI kept)":"off (stripped)"}.`}resize(t,n,r,o){let s=ce(n);if(s)return s;let i=this.getSession(t,n);if(!i?.alive)return`No session "${n}".`;let a=Math.min(500,Math.max(20,Math.floor(r))),l=Math.min(200,Math.max(5,Math.floor(o)));return i.resize(a,l),`Resized "${n}" to ${a}x${l}.`}stop(t,n){let r=ce(n);if(r)return r;let o=this.getSession(t,n);if(!o?.alive)return`No running session "${n}".`;o.kill("SIGTERM");let s=se(t,n),i=setTimeout(()=>{this.killTimers.delete(i);let a=this.getSession(t,n);a?.alive&&a.kill("SIGKILL")},5e3);return this.killTimers.add(i),`SIGTERM sent to "${n}". SIGKILL in 5s if still running.`}kill(t,n){let r=ce(n);if(r)return r;let o=this.getSession(t,n);return o?.alive?(o.kill("SIGKILL"),`SIGKILL sent to "${n}".`):`No running session "${n}".`}rm(t,n){let r=ce(n);if(r)return r;if(this.getSession(t,n)?.alive)return`Session "${n}" is still running. /apps stop ${n} first, then /apps rm ${n}.`;this.removeSessionRecord(t,n),this.muted.delete(se(t,n)),this.rawMode.delete(se(t,n));let s=this.logPath(t,n);try{Le.rmSync(s,{force:!0})}catch{}return`Removed "${n}" metadata and log.`}};import{spawn as da}from"node:child_process";import pa from"node:crypto";import de from"node:fs";import er from"node:path";function st(e,t){de.writeFileSync(e,JSON.stringify(t,null,2)+`
165
- `,{mode:384})}function yt(e){try{return JSON.parse(de.readFileSync(e,"utf8"))}catch{return null}}var je=class{running=new Map;metaPath(t){return er.join(ye,`${t}.meta.json`)}logPath(t){return er.join(ye,`${t}.log`)}spawnJob(t,n,r={}){G();let o=pa.randomBytes(4).toString("hex"),s=this.logPath(o),i=this.metaPath(o);de.writeFileSync(s,"",{flag:"w",mode:384});let a=de.createWriteStream(s,{flags:"a"}),l=new Date().toISOString(),u=r.cwd,c=da(t,["-c",n],{stdio:["ignore","pipe","pipe"],env:{...process.env,TERM:"dumb",...u?{PWD:u}:{}},...u?{cwd:u}:{}});this.running.set(o,c);let d={id:o,cmd:n,pid:c.pid??null,startedAt:l,status:"running",exitCode:null,signal:null};return st(i,d),c.stdout?.on("data",p=>{a.write(p)}),c.stderr?.on("data",p=>{a.write(p)}),c.on("close",(p,f)=>{this.running.delete(o),a.end();let w=yt(i)??d,M={...w,status:w.status==="killed"?"killed":"done",exitCode:p,signal:f??null,finishedAt:new Date().toISOString()};st(i,M)}),c.on("error",p=>{this.running.delete(o),a.end(()=>{try{de.appendFileSync(s,`
166
- [spawn error] ${String(p)}
167
- `)}catch{}});let f=yt(i)??d;st(i,{...f,status:"done",exitCode:null,signal:null,finishedAt:new Date().toISOString()})}),{id:o,meta:d}}list(){G();let t=[];try{t=de.readdirSync(ye)}catch{return[]}let n=[];for(let r of t){if(!r.endsWith(".meta.json"))continue;let o=yt(er.join(ye,r));o&&n.push(o)}return n.sort((r,o)=>r.startedAt<o.startedAt?1:-1),n}tailLog(t,n){let r=this.logPath(t);if(!de.existsSync(r))return"(no log file)";let s=de.readFileSync(r,"utf8").split(`
186
+ `)}`}info(t,n){let r=this.getCfg(),o=n??this.focus.get(t)??"";if(!o)return"Usage: /apps info <name> (or /apps get <name>, or attach first)";let s=fe(o);if(s)return s;let i=this.getSession(t,o),a=this.logPath(t,o),l=0;try{l=je.statSync(a).size}catch{}let d=this.muted.has(ce(t,o)),c=this.rawMode.has(ce(t,o));return[`session: ${o}`,`alive: ${i?.alive??!1}`,`cmd: ${i?.command??"(unknown)"}`,`cwd: ${i?.cwd??"(unknown)"}`,`env keys: ${i?.envKeysCount??"?"}`,`terminal size: ${r.appsCols}x${r.appsRows}`,`ring bytes (approx): ${i?.ringByteCount??0}`,`log: ${a} (${l} bytes)`,`mute outbound: ${d}`,`raw outbound: ${c}`].join(`
187
+ `)}async sendText(t,n,r){let o=fe(n);if(o)return o;let s=this.getSession(t,n);if(!s?.alive)return`No session "${n}".`;let i=r.replace(/\r\n/g,`
188
+ `);return await Er(s,i,this.getCfg()),`Sent to "${n}" (${i.length} chars + Enter per line).`}sendKey(t,n,r){let o=fe(n);if(o)return o;let s=this.getSession(t,n);if(!s?.alive)return`No session "${n}".`;let i=Ir(r);return i?(s.write(i),`Sent keys to "${n}".`):"Empty key sequence. Example: /apps key sh Enter or ^C,Up,Enter"}tail(t,n,r){let o=fe(n);if(o)return o;let s=this.logPath(t,n);if(!je.existsSync(s))return`(no log file for ${n})`;let i=this.getCfg(),a=Number.isFinite(r)&&r>0?Math.min(500,r):i.appsLogTailLines;return Ol(s,a)||"(empty log)"}readSince(t,n,r){let o=this.logPath(t,n);try{let i=je.statSync(o).size,a=je.openSync(o,"r");try{let l=Math.min(r,i),d=i-l,c=Buffer.alloc(d);return d>0&&je.readSync(a,c,0,d,l),{text:c.toString("utf8"),nextOffset:i}}finally{je.closeSync(a)}}catch{return{text:"",nextOffset:r}}}mute(t,n){let r=fe(n);return r||(this.muted.add(ce(t,n)),`Muted chat output for "${n}" (log still grows). /apps unmute ${n}`)}unmute(t,n){let r=fe(n);return r||(this.muted.delete(ce(t,n)),`Unmuted "${n}".`)}setRaw(t,n,r){let o=fe(n);if(o)return o;let s=ce(t,n);return r?this.rawMode.add(s):this.rawMode.delete(s),`raw chat output for "${n}": ${r?"on (ANSI kept)":"off (stripped)"}.`}resize(t,n,r,o){let s=fe(n);if(s)return s;let i=this.getSession(t,n);if(!i?.alive)return`No session "${n}".`;let a=Math.min(500,Math.max(20,Math.floor(r))),l=Math.min(200,Math.max(5,Math.floor(o)));return i.resize(a,l),`Resized "${n}" to ${a}x${l}.`}stop(t,n){let r=fe(n);if(r)return r;let o=this.getSession(t,n);if(!o?.alive)return`No running session "${n}".`;o.kill("SIGTERM");let s=ce(t,n),i=setTimeout(()=>{this.killTimers.delete(i);let a=this.getSession(t,n);a?.alive&&a.kill("SIGKILL")},5e3);return this.killTimers.add(i),`SIGTERM sent to "${n}". SIGKILL in 5s if still running.`}kill(t,n){let r=fe(n);if(r)return r;let o=this.getSession(t,n);return o?.alive?(o.kill("SIGKILL"),`SIGKILL sent to "${n}".`):`No running session "${n}".`}rm(t,n){let r=fe(n);if(r)return r;if(this.getSession(t,n)?.alive)return`Session "${n}" is still running. /apps stop ${n} first, then /apps rm ${n}.`;this.removeSessionRecord(t,n),this.muted.delete(ce(t,n)),this.rawMode.delete(ce(t,n));let s=this.logPath(t,n);try{je.rmSync(s,{force:!0})}catch{}return`Removed "${n}" metadata and log.`}};import ii from"node:fs";import Ll from"node:path";function si(e,t,n){if(e==="none")return[];let r=new Set;if((e==="self"||e==="all")&&r.add(t),e==="wa"||e==="all")for(let o of n.allowFrom){let s=_(String(o));s&&r.add(`wa:${Dt(s)}`)}if(e==="tg"||e==="all")for(let o of n.telegramAllowFrom){let s=de(String(o));s&&r.add(`tg:${s}`)}return[...r]}var Pl=8,ai=12e4;function Fl(e){return e.toISOString().replace(/[:.]/g,"-")}async function li(e,t,n,r){let o=H(t.ownerPeerKey),s=t.cwd.trim()?t.cwd:o.cwd,i=Ot(t.outputDir,o.cwd);try{ii.mkdirSync(i,{recursive:!0,mode:448})}catch(X){M.warn({err:String(X),outDir:i},"cowork mkdir outputDir")}let a=n.slotMs!==null?new Date(n.slotMs).toLocaleString(void 0,{dateStyle:"short",timeStyle:"short"}):"on-demand",l=n.onDemand?"on-demand":n.catchUp?"catch-up":"scheduled",d=Date.now(),c=await ln(e.shell,t.command,{timeoutMs:e.syncTimeoutMs,maxBytes:e.syncMaxBytes,cwd:s}),u=Date.now()-d,m=`${Fl(new Date)}-${t.id}-${l}.log`,f=Ll.join(i,m),w=[`cowork task=${t.name} id=${t.id}`,`slot=${a} kind=${l}`,`cwd=${s}`,`exit=${c.code} timedOut=${c.timedOut} durationMs=${u}`,"---",""].join(`
189
+ `)+(c.stdout||"")+(c.stderr?`
190
+ --- stderr ---
191
+ ${c.stderr}`:"");try{ii.writeFileSync(f,w,{mode:384})}catch(X){M.warn({err:String(X),logPath:f},"cowork write log")}let k=c.code===0&&!c.timedOut&&c.signal===null,D=he().find(X=>X.id===t.id&&X.ownerPeerKey===t.ownerPeerKey)?.notify??t.notify,W=[`Cowork: ${t.name} (${l})`,`Slot: ${a}`,`Exit: ${c.code}${c.timedOut?" (timeout)":""}`,`Log: ${f}`];c.signal&&W.push(`Signal: ${c.signal}`);let V=W.join(`
192
+ `),F=p(V),ue=si(D,t.ownerPeerKey,e);for(let X of ue){let $e=Re(F,X.startsWith("tg:")?"telegram":"whatsapp").text;try{await r.sendToPeer(X,$e)}catch(C){M.warn({err:String(C),pk:X},"cowork notify failed")}}return{commandOk:k,logPath:f}}function ci(e){let t=!1;At(he());let n=async()=>{if(t)return;t=!0;let s=Date.now(),i=0,a=0,l=0,d=0,c=0;try{let u=e.getConfig(),{batch:m,remainingAfter:f}=Xs(Pl);a=m.length,l=f,i=m.length+f;for(let k of m)try{let P=he().find(D=>D.name===k.name.toLowerCase()&&D.ownerPeerKey===k.ownerPeerKey);P&&P.enabled&&(d+=1,await li(u,P,{slotMs:null,catchUp:!1,onDemand:!0},e))}catch(E){M.warn({err:String(E),pending:k.name},"cowork on-demand run failed")}let y=he();At(y);let w=Date.now();for(let k of y){if(!k.enabled||k.schedule.kind==="ondemand")continue;let E=bn(k),P=js(k.schedule,E,k.createdAtMs,w);if(P.length===0)continue;let D=P[P.length-1],W=w-D>ai;try{c+=1;let{commandOk:V,logPath:F}=await li(u,k,{slotMs:D,catchUp:W,onDemand:!1},e);if(V){let ue=Date.now(),X=w-D<=ai?"on_time":"catch_up";if(P.length===1)kn(k.id,[{slotMs:D,kind:X,logPath:F,completedAtMs:ue}]);else{let C=P.slice(0,-1).map(N=>({slotMs:N,kind:"coalesced",logPath:null,completedAtMs:ue}));C.push({slotMs:D,kind:X,logPath:F,completedAtMs:ue}),kn(k.id,C)}}}catch(V){M.warn({err:String(V),task:k.name},"cowork scheduled run failed")}}}finally{let u=Date.now()-s;M.info({tickMs:u,pendingDepthStart:i,pendingDequeued:a,pendingRemainingAfter:l,pendingRunsStarted:d,scheduledRan:c},"cowork tick"),t=!1}},r=setInterval(()=>void n(),3e4),o=setTimeout(()=>void n(),5e3);return()=>{clearInterval(r),clearTimeout(o),zs()}}import{spawn as Nl}from"node:child_process";import _l from"node:crypto";import ye from"node:fs";import Or from"node:path";function mt(e,t){ye.writeFileSync(e,JSON.stringify(t,null,2)+`
193
+ `,{mode:384})}function Pt(e){try{return JSON.parse(ye.readFileSync(e,"utf8"))}catch{return null}}var Ke=class{running=new Map;metaPath(t){return Or.join(ke,`${t}.meta.json`)}logPath(t){return Or.join(ke,`${t}.log`)}spawnJob(t,n,r={}){Q();let o=_l.randomBytes(4).toString("hex"),s=this.logPath(o),i=this.metaPath(o);ye.writeFileSync(s,"",{flag:"w",mode:384});let a=ye.createWriteStream(s,{flags:"a"}),l=new Date().toISOString(),d=r.cwd,c=Nl(t,["-c",n],{stdio:["ignore","pipe","pipe"],env:{...process.env,TERM:"dumb",...d?{PWD:d}:{}},...d?{cwd:d}:{}});this.running.set(o,c);let u={id:o,cmd:n,pid:c.pid??null,startedAt:l,status:"running",exitCode:null,signal:null};return mt(i,u),c.stdout?.on("data",m=>{a.write(m)}),c.stderr?.on("data",m=>{a.write(m)}),c.on("close",(m,f)=>{this.running.delete(o),a.end();let y=Pt(i)??u,w={...y,status:y.status==="killed"?"killed":"done",exitCode:m,signal:f??null,finishedAt:new Date().toISOString()};mt(i,w)}),c.on("error",m=>{this.running.delete(o),a.end(()=>{try{ye.appendFileSync(s,`
194
+ [spawn error] ${String(m)}
195
+ `)}catch{}});let f=Pt(i)??u;mt(i,{...f,status:"done",exitCode:null,signal:null,finishedAt:new Date().toISOString()})}),{id:o,meta:u}}list(){Q();let t=[];try{t=ye.readdirSync(ke)}catch{return[]}let n=[];for(let r of t){if(!r.endsWith(".meta.json"))continue;let o=Pt(Or.join(ke,r));o&&n.push(o)}return n.sort((r,o)=>r.startedAt<o.startedAt?1:-1),n}tailLog(t,n){let r=this.logPath(t);if(!ye.existsSync(r))return"(no log file)";let s=ye.readFileSync(r,"utf8").split(`
168
196
  `);return s.slice(Math.max(0,s.length-n)).join(`
169
- `).trimEnd()||"(empty log)"}readSince(t,n){let r=this.logPath(t);if(!de.existsSync(r))return{text:"",nextOffset:n};let s=de.statSync(r).size;if(n>=s)return{text:"",nextOffset:s};let i=Buffer.alloc(s-n),a=de.openSync(r,"r");try{de.readSync(a,i,0,i.length,n)}finally{de.closeSync(a)}return{text:i.toString("utf8"),nextOffset:s}}kill(t){let n=this.metaPath(t),r=yt(n);if(!r)return`Unknown job id: ${t}`;let o=this.running.get(t);if(o&&!o.killed)return o.kill("SIGTERM"),st(n,{...r,status:"killed",signal:"SIGTERM"}),`Sent SIGTERM to job ${t} (pid ${r.pid??"?"})`;if(r.pid)try{return process.kill(r.pid,"SIGTERM"),st(n,{...r,status:"killed",signal:"SIGTERM"}),`Sent SIGTERM to pid ${r.pid} (${t})`}catch{return`Job ${t} is not running (no live process).`}return`Job ${t} is not running.`}killAllRunning(){for(let[t,n]of this.running){n.killed||n.kill("SIGTERM");let r=yt(this.metaPath(t));r&&st(this.metaPath(t),{...r,status:"killed",signal:"SIGTERM"})}this.running.clear()}};import Ua from"node:fs";import{Bot as Ga,InputFile as za}from"grammy";import us from"node:fs";import it from"node:path";function ma(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"_").slice(0,120)||"unknown"}function fa(e){let r=it.basename(e.trim()||"file").replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^\.+/,"").slice(0,180);return r.length>0?r:"file"}function ga(e,t){let n=new Date().toISOString().slice(0,10),r=ma(t);return it.join(e,r,n)}function en(e,t,n){let r=ga(e,t);P(r);let o=fa(n),s=it.join(r,o);if(!us.existsSync(s))return s;let i=it.extname(o),a=i?o.slice(0,-i.length):o;for(let l=1;l<1e4;l+=1){let u=`${a}-${l}${i}`;if(s=it.join(r,u),!us.existsSync(s))return s}return it.join(r,`${a}-${Date.now()}${i}`)}import ha from"node:dns";import ya from"node:https";import{URL as wa}from"node:url";function at(e){if(e instanceof Error){let t=e.cause;return t!=null?`${e.message} (${String(t)})`:e.message}return String(e)}function ds(e){if("photo"in e&&e.photo&&e.photo.length>0)return{fileId:e.photo[e.photo.length-1].file_id,baseName:"photo.jpg"};if("document"in e&&e.document){let t=e.document,n=t.file_name?.trim();return{fileId:t.file_id,baseName:n&&n.length>0?n:"document.bin"}}if("video"in e&&e.video){let t=e.video,n=t.file_name?.trim();return{fileId:t.file_id,baseName:n&&n.length>0?n:"video.mp4"}}if("audio"in e&&e.audio){let t=e.audio,n=t.file_name?.trim();return{fileId:t.file_id,baseName:n&&n.length>0?n:"audio.m4a"}}if("voice"in e&&e.voice)return{fileId:e.voice.file_id,baseName:"voice.ogg"};if("video_note"in e&&e.video_note)return{fileId:e.video_note.file_id,baseName:"video_note.mp4"};if("sticker"in e&&e.sticker){let t=e.sticker,n=t.is_video?"webm":"webp";return{fileId:t.file_id,baseName:`sticker.${n}`}}return null}function ba(e,t){let r=t.split("/").filter(o=>o.length>0).map(encodeURIComponent).join("/");return`https://api.telegram.org/file/bot${e}/${r}`}var ps="omnish (Telegram bot; https://github.com/labKnowledge/whatsLive)";function Sa(e){let t=new wa(e);return new Promise((n,r)=>{let o=ya.request({hostname:t.hostname,port:t.port||443,path:t.pathname+t.search,method:"GET",headers:{"User-Agent":ps,Accept:"*/*"},lookup(s,i,a){ha.lookup(s,{family:4},a)}},s=>{let i=s.statusCode??0,a=[];s.on("data",l=>a.push(l)),s.on("end",()=>n({status:i,buffer:Buffer.concat(a)})),s.on("error",r)});o.on("error",r),o.end()})}async function ms(e,t,n){let r;try{r=await e.api.getFile(t)}catch(i){return A.warn({err:String(i),fileId:t},"telegram getFile failed"),{error:"Could not resolve file on Telegram."}}if(!r.file_path)return{error:"Telegram did not return a file path."};let o=ba(e.token,r.file_path),s;try{let i=await fetch(o,{headers:{"User-Agent":ps,Accept:"*/*"}});if(!i.ok)return A.warn({status:i.status,statusText:i.statusText,fileId:t},"telegram file fetch HTTP error"),{error:`Could not download file from Telegram (HTTP ${i.status}${i.statusText?` ${i.statusText}`:""}).`};try{s=Buffer.from(await i.arrayBuffer())}catch(a){return A.warn({err:String(a),fileId:t},"telegram file read body failed"),{error:`Could not read file from Telegram (${String(a)}).`}}}catch(i){A.warn({err:String(i),fileId:t},"telegram file fetch failed; retrying via HTTPS IPv4");try{let a=await Sa(o);if(a.status<200||a.status>=300)return A.warn({status:a.status,fileId:t},"telegram HTTPS IPv4 fallback HTTP error"),{error:`Could not download file from Telegram (HTTP ${a.status}).`};s=a.buffer}catch(a){return A.warn({err:String(i),err2:String(a),fileId:t},"telegram file download failed (fetch and IPv4 fallback)"),{error:`Could not download file from Telegram (network: ${at(i)}; IPv4 fallback: ${at(a)}).`}}}return n>0&&s.byteLength>n?{error:`Media too large (max ${n} bytes).`}:{buffer:s}}import{downloadMediaMessage as xa,extensionForMediaMessage as ka,getContentType as tn,isJidGroup as hs,isLidUser as va}from"@whiskeysockets/baileys";import $a from"node:fs";function Ra(e){if(!e||typeof e!="object")return"";let t=e;if(typeof t.conversation=="string")return t.conversation;let n=t.extendedTextMessage;return n&&typeof n.text=="string"?n.text:""}function Ma(e){if(!e||typeof e!="object")return"";let t=e;for(let n of["imageMessage","videoMessage","documentMessage","audioMessage","stickerMessage"]){let r=t[n];if(r&&typeof r.caption=="string"&&r.caption.trim())return r.caption}return""}function ys(e){return[Ra(e),Ma(e)].filter(n=>n.trim().length>0).join(`
170
- `).trim()}function tr(e){return e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g,"").replace(/\uFEFF/g,"").trim()}function ws(e){let t=tn(e??void 0);return t==="imageMessage"||t==="videoMessage"||t==="audioMessage"||t==="documentMessage"||t==="stickerMessage"}function Ca(e){let t=tn(e??void 0);if(!t)return;let r=e?.[t]?.fileLength;if(typeof r=="number"&&Number.isFinite(r))return r;if(r&&typeof r=="object"&&"toNumber"in r&&typeof r.toNumber=="function")try{let o=r.toNumber();return Number.isFinite(o)?o:void 0}catch{return}}function fs(e){try{if(!e)return"file.bin";let t=ka(e);return`file${t&&t.length>0?t.startsWith(".")?t:`.${t}`:".bin"}`}catch{return`${(tn(e??void 0)??"file").replace("Message","")||"file"}.bin`}}function Ta(e){let t=tn(e??void 0);if(!t)return fs(e);let n=e?.[t];return n?.fileName&&typeof n.fileName=="string"&&n.fileName.trim()?n.fileName.trim():fs(e)}async function gs(e,t,n,r){let o=t.message??void 0;if(!ws(o))return{};let s=r.fileReceiveMaxBytes,i=Ca(o);if(s>0&&i!==void 0&&i>s)return{error:`Media too large (max ${s} bytes).`};let a;try{a=await xa(t,"buffer",{},{logger:e.logger,reuploadRequest:e.updateMediaMessage})}catch(d){return A.warn({err:String(d),detail:at(d)},"whatsapp downloadMediaMessage failed"),{error:`Could not download media from WhatsApp (${at(d)}).`}}if(s>0&&a.length>s)return{error:`Media too large (max ${s} bytes).`};let l;try{l=Ke(r,n)}catch(d){return{error:String(d)}}let u=Ta(o),c=en(l,n,u);try{$a.writeFileSync(c,a,{mode:384})}catch{return{error:"Could not write media to inbox."}}return{path:c}}async function Ia(e,t){let n=t.remoteJid??"";if(!n)return{fromJid:"",fromE164:""};if(t.remoteJidAlt){let r=F(t.remoteJidAlt)??F(n)??"";return{fromJid:n,fromE164:r}}if(va(n))try{let r=await e.signalRepository?.lidMapping?.getPNForLID?.(n);if(r){let o=F(r)??"";if(o)return{fromJid:n,fromE164:o}}}catch{}return{fromJid:n,fromE164:F(n)??""}}function Aa(e){try{if(!x().clusterEnabled)return;let n=ys(e.message??void 0);if(!n)return;let r=Bo(n);if(!r)return;let o=e.key?.remoteJid??"",s=null;if(o&&!hs(o)){let i=F(o);i&&(s=`wa:${i}`)}zo(r,s)}catch(t){A.warn({err:String(t)},"cluster footer observation failed")}}function bs(e,t){let n=r=>{r.type==="notify"&&(async()=>{for(let o of r.messages){let s=o.key;if(!s)continue;if(s.fromMe){Aa(o);continue}let i=s.remoteJid;if(!i||hs(i)||i.toLowerCase().endsWith("@status")||i==="status@broadcast")continue;let l=tr(ys(o.message??void 0)),{fromJid:u,fromE164:c}=await Ia(e,s),d=`wa:${u}`,p=ws(o.message??void 0);if(p&&!l){(async()=>{try{let M=x(),C=await gs(e,o,d,M);await t({fromJid:u,fromE164:c,text:"",messageId:s.id??void 0,mediaSavedPath:C.path,mediaError:C.error})}catch(M){A.error({err:String(M),fromJid:u},"whatsapp media-only background task failed")}})();continue}let f,w;if(p){let M=x(),C=await gs(e,o,d,M);f=C.path,w=C.error}!l&&!f&&!w||await t({fromJid:u,fromE164:c,text:l,messageId:s.id??void 0,mediaSavedPath:f,mediaError:w})}})()};return e.ev.on("messages.upsert",n),()=>{e.ev.off("messages.upsert",n)}}import Na from"node:fs";import Ea from"node:process";import Oa,{DisconnectReason as We,fetchLatestBaileysVersion as La,makeCacheableSignalKeyStore as Pa,useMultiFileAuthState as Fa}from"@whiskeysockets/baileys";import Ba from"qrcode-terminal";var _a="0.1.0";function nr(e){return e?.error?.output?.statusCode}async function nn(e={}){G();let t=e.authDir??q,n=e.verbose===!0,r=ss(),{state:o,saveCreds:s}=await Fa(t),{version:i}=await La(),a=Oa({version:i,logger:r,printQRInTerminal:!1,browser:["omnish","cli",_a],auth:{creds:o.creds,keys:Pa(o.keys,r)},syncFullHistory:!1,markOnlineOnConnect:!1});return a.ev.on("creds.update",s),a.ev.on("connection.update",l=>{let{connection:u,lastDisconnect:c,qr:d}=l;if(d&&(e.onQr?.(d),e.printQr)){let p=Ea.stdout,f=g(p,"\xB7".repeat(42));console.log(K(p,"Scan with WhatsApp \u2192 Linked devices")),console.log(f),Ba.generate(d,{small:!0}),console.log(f)}if(u==="close"){let p=nr(c);n&&p===We.loggedOut&&r.warn("WhatsApp session logged out (401).")}u==="open"&&n&&r.info("WhatsApp Web connected.")}),a.ws&&typeof a.ws.on=="function"&&a.ws.on("error",l=>{r.error({err:String(l)},"WebSocket error")}),a}function rn(e){try{e.end(new Error("omnish: socket closed"))}catch{e.ws?.close()}}function rr(e){return e?.output?.statusCode??e?.status??e?.error?.output?.statusCode}function on(e){return e.user?.id?Promise.resolve():new Promise((t,n)=>{let r=o=>{if(o.connection==="open"){e.ev.off("connection.update",r),t();return}if(o.connection==="close"){e.ev.off("connection.update",r);let i=o.lastDisconnect?.error??o.lastDisconnect??new Error("Connection closed");n(i)}};e.ev.on("connection.update",r)})}function De(e,t,n){return new Promise((r,o)=>{let s=setTimeout(()=>o(new Error(n)),t);e.then(i=>{clearTimeout(s),r(i)},i=>{clearTimeout(s),o(i)})})}var $s=3500,Ha=400,Ss=18e4,xs=9e4,ks=3e5;function or(e,t=$s){if(e.length<=t)return[e];let n=[],r=0;for(;r<e.length;){let o=Math.min(r+t,e.length);if(o<e.length){let i=e.slice(r,o).lastIndexOf(`
197
+ `).trimEnd()||"(empty log)"}readSince(t,n){let r=this.logPath(t);if(!ye.existsSync(r))return{text:"",nextOffset:n};let s=ye.statSync(r).size;if(n>=s)return{text:"",nextOffset:s};let i=Buffer.alloc(s-n),a=ye.openSync(r,"r");try{ye.readSync(a,i,0,i.length,n)}finally{ye.closeSync(a)}return{text:i.toString("utf8"),nextOffset:s}}kill(t){let n=this.metaPath(t),r=Pt(n);if(!r)return`Unknown job id: ${t}`;let o=this.running.get(t);if(o&&!o.killed)return o.kill("SIGTERM"),mt(n,{...r,status:"killed",signal:"SIGTERM"}),`Sent SIGTERM to job ${t} (pid ${r.pid??"?"})`;if(r.pid)try{return process.kill(r.pid,"SIGTERM"),mt(n,{...r,status:"killed",signal:"SIGTERM"}),`Sent SIGTERM to pid ${r.pid} (${t})`}catch{return`Job ${t} is not running (no live process).`}return`Job ${t} is not running.`}killAllRunning(){for(let[t,n]of this.running){n.killed||n.kill("SIGTERM");let r=Pt(this.metaPath(t));r&&mt(this.metaPath(t),{...r,status:"killed",signal:"SIGTERM"})}this.running.clear()}};import fc from"node:fs";import{Bot as gc,InputFile as hc}from"grammy";import ui from"node:fs";import ft from"node:path";function Bl(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"_").slice(0,120)||"unknown"}function Dl(e){let r=ft.basename(e.trim()||"file").replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^\.+/,"").slice(0,180);return r.length>0?r:"file"}function Hl(e,t){let n=new Date().toISOString().slice(0,10),r=Bl(t);return ft.join(e,r,n)}function vn(e,t,n){let r=Hl(e,t);L(r);let o=Dl(n),s=ft.join(r,o);if(!ui.existsSync(s))return s;let i=ft.extname(o),a=i?o.slice(0,-i.length):o;for(let l=1;l<1e4;l+=1){let d=`${a}-${l}${i}`;if(s=ft.join(r,d),!ui.existsSync(s))return s}return ft.join(r,`${a}-${Date.now()}${i}`)}import jl from"node:dns";import Wl from"node:https";import{URL as Ul}from"node:url";function gt(e){if(e instanceof Error){let t=e.cause;return t!=null?`${e.message} (${String(t)})`:e.message}return String(e)}function di(e){if("photo"in e&&e.photo&&e.photo.length>0)return{fileId:e.photo[e.photo.length-1].file_id,baseName:"photo.jpg"};if("document"in e&&e.document){let t=e.document,n=t.file_name?.trim();return{fileId:t.file_id,baseName:n&&n.length>0?n:"document.bin"}}if("video"in e&&e.video){let t=e.video,n=t.file_name?.trim();return{fileId:t.file_id,baseName:n&&n.length>0?n:"video.mp4"}}if("audio"in e&&e.audio){let t=e.audio,n=t.file_name?.trim();return{fileId:t.file_id,baseName:n&&n.length>0?n:"audio.m4a"}}if("voice"in e&&e.voice)return{fileId:e.voice.file_id,baseName:"voice.ogg"};if("video_note"in e&&e.video_note)return{fileId:e.video_note.file_id,baseName:"video_note.mp4"};if("sticker"in e&&e.sticker){let t=e.sticker,n=t.is_video?"webm":"webp";return{fileId:t.file_id,baseName:`sticker.${n}`}}return null}function Gl(e,t){let r=t.split("/").filter(o=>o.length>0).map(encodeURIComponent).join("/");return`https://api.telegram.org/file/bot${e}/${r}`}var pi="omnish (Telegram bot; https://github.com/labKnowledge/whatsLive)";function zl(e){let t=new Ul(e);return new Promise((n,r)=>{let o=Wl.request({hostname:t.hostname,port:t.port||443,path:t.pathname+t.search,method:"GET",headers:{"User-Agent":pi,Accept:"*/*"},lookup(s,i,a){jl.lookup(s,{family:4},a)}},s=>{let i=s.statusCode??0,a=[];s.on("data",l=>a.push(l)),s.on("end",()=>n({status:i,buffer:Buffer.concat(a)})),s.on("error",r)});o.on("error",r),o.end()})}async function mi(e,t,n){let r;try{r=await e.api.getFile(t)}catch(i){return M.warn({err:String(i),fileId:t},"telegram getFile failed"),{error:"Could not resolve file on Telegram."}}if(!r.file_path)return{error:"Telegram did not return a file path."};let o=Gl(e.token,r.file_path),s;try{let i=await fetch(o,{headers:{"User-Agent":pi,Accept:"*/*"}});if(!i.ok)return M.warn({status:i.status,statusText:i.statusText,fileId:t},"telegram file fetch HTTP error"),{error:`Could not download file from Telegram (HTTP ${i.status}${i.statusText?` ${i.statusText}`:""}).`};try{s=Buffer.from(await i.arrayBuffer())}catch(a){return M.warn({err:String(a),fileId:t},"telegram file read body failed"),{error:`Could not read file from Telegram (${String(a)}).`}}}catch(i){M.warn({err:String(i),fileId:t},"telegram file fetch failed; retrying via HTTPS IPv4");try{let a=await zl(o);if(a.status<200||a.status>=300)return M.warn({status:a.status,fileId:t},"telegram HTTPS IPv4 fallback HTTP error"),{error:`Could not download file from Telegram (HTTP ${a.status}).`};s=a.buffer}catch(a){return M.warn({err:String(i),err2:String(a),fileId:t},"telegram file download failed (fetch and IPv4 fallback)"),{error:`Could not download file from Telegram (network: ${gt(i)}; IPv4 fallback: ${gt(a)}).`}}}return n>0&&s.byteLength>n?{error:`Media too large (max ${n} bytes).`}:{buffer:s}}import{downloadMediaMessage as Jl,extensionForMediaMessage as Kl,getContentType as $n,isJidGroup as hi,isLidUser as ql}from"@whiskeysockets/baileys";import Yl from"node:fs";function Vl(e){if(!e||typeof e!="object")return"";let t=e;if(typeof t.conversation=="string")return t.conversation;let n=t.extendedTextMessage;return n&&typeof n.text=="string"?n.text:""}function Xl(e){if(!e||typeof e!="object")return"";let t=e;for(let n of["imageMessage","videoMessage","documentMessage","audioMessage","stickerMessage"]){let r=t[n];if(r&&typeof r.caption=="string"&&r.caption.trim())return r.caption}return""}function yi(e){return[Vl(e),Xl(e)].filter(n=>n.trim().length>0).join(`
198
+ `).trim()}function Lr(e){return e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g,"").replace(/\uFEFF/g,"").trim()}function wi(e){let t=$n(e??void 0);return t==="imageMessage"||t==="videoMessage"||t==="audioMessage"||t==="documentMessage"||t==="stickerMessage"}function Ql(e){let t=$n(e??void 0);if(!t)return;let r=e?.[t]?.fileLength;if(typeof r=="number"&&Number.isFinite(r))return r;if(r&&typeof r=="object"&&"toNumber"in r&&typeof r.toNumber=="function")try{let o=r.toNumber();return Number.isFinite(o)?o:void 0}catch{return}}function fi(e){try{if(!e)return"file.bin";let t=Kl(e);return`file${t&&t.length>0?t.startsWith(".")?t:`.${t}`:".bin"}`}catch{return`${($n(e??void 0)??"file").replace("Message","")||"file"}.bin`}}function Zl(e){let t=$n(e??void 0);if(!t)return fi(e);let n=e?.[t];return n?.fileName&&typeof n.fileName=="string"&&n.fileName.trim()?n.fileName.trim():fi(e)}async function gi(e,t,n,r){let o=t.message??void 0;if(!wi(o))return{};let s=r.fileReceiveMaxBytes,i=Ql(o);if(s>0&&i!==void 0&&i>s)return{error:`Media too large (max ${s} bytes).`};let a;try{a=await Jl(t,"buffer",{},{logger:e.logger,reuploadRequest:e.updateMediaMessage})}catch(u){return M.warn({err:String(u),detail:gt(u)},"whatsapp downloadMediaMessage failed"),{error:`Could not download media from WhatsApp (${gt(u)}).`}}if(s>0&&a.length>s)return{error:`Media too large (max ${s} bytes).`};let l;try{l=nt(r,n)}catch(u){return{error:String(u)}}let d=Zl(o),c=vn(l,n,d);try{Yl.writeFileSync(c,a,{mode:384})}catch{return{error:"Could not write media to inbox."}}return{path:c}}async function ec(e,t){let n=t.remoteJid??"";if(!n)return{fromJid:"",fromE164:""};if(t.remoteJidAlt){let r=_(t.remoteJidAlt)??_(n)??"";return{fromJid:n,fromE164:r}}if(ql(n))try{let r=await e.signalRepository?.lidMapping?.getPNForLID?.(n);if(r){let o=_(r)??"";if(o)return{fromJid:n,fromE164:o}}}catch{}return{fromJid:n,fromE164:_(n)??""}}function tc(e){try{if(!$().clusterEnabled)return;let n=yi(e.message??void 0);if(!n)return;let r=ms(n);if(!r)return;let o=e.key?.remoteJid??"",s=null;if(o&&!hi(o)){let i=_(o);i&&(s=`wa:${i}`)}xs(r,s)}catch(t){M.warn({err:String(t)},"cluster footer observation failed")}}function bi(e,t){let n=r=>{r.type==="notify"&&(async()=>{for(let o of r.messages){let s=o.key;if(!s)continue;if(s.fromMe){tc(o);continue}let i=s.remoteJid;if(!i||hi(i)||i.toLowerCase().endsWith("@status")||i==="status@broadcast")continue;let l=Lr(yi(o.message??void 0)),{fromJid:d,fromE164:c}=await ec(e,s),u=`wa:${d}`,m=wi(o.message??void 0);if(m&&!l){(async()=>{try{let w=$(),k=await gi(e,o,u,w);await t({fromJid:d,fromE164:c,text:"",messageId:s.id??void 0,mediaSavedPath:k.path,mediaError:k.error})}catch(w){M.error({err:String(w),fromJid:d},"whatsapp media-only background task failed")}})();continue}let f,y;if(m){let w=$(),k=await gi(e,o,u,w);f=k.path,y=k.error}!l&&!f&&!y||await t({fromJid:d,fromE164:c,text:l,messageId:s.id??void 0,mediaSavedPath:f,mediaError:y})}})()};return e.ev.on("messages.upsert",n),()=>{e.ev.off("messages.upsert",n)}}import cc from"node:fs";import nc from"node:process";import rc,{DisconnectReason as qe,fetchLatestBaileysVersion as oc,makeCacheableSignalKeyStore as sc,useMultiFileAuthState as ic}from"@whiskeysockets/baileys";import ac from"qrcode-terminal";var lc="0.1.0";function Pr(e){return e?.error?.output?.statusCode}async function Cn(e={}){Q();let t=e.authDir??ee,n=e.verbose===!0,r=Ws(),{state:o,saveCreds:s}=await ic(t),{version:i}=await oc(),a=rc({version:i,logger:r,printQRInTerminal:!1,browser:["omnish","cli",lc],auth:{creds:o.creds,keys:sc(o.keys,r)},syncFullHistory:!1,markOnlineOnConnect:!1});return a.ev.on("creds.update",s),a.ev.on("connection.update",l=>{let{connection:d,lastDisconnect:c,qr:u}=l;if(u&&(e.onQr?.(u),e.printQr)){let m=nc.stdout,f=h(m,"\xB7".repeat(42));console.log(re(m,"Scan with WhatsApp \u2192 Linked devices")),console.log(f),ac.generate(u,{small:!0}),console.log(f)}if(d==="close"){let m=Pr(c);n&&m===qe.loggedOut&&r.warn("WhatsApp session logged out (401).")}d==="open"&&n&&r.info("WhatsApp Web connected.")}),a.ws&&typeof a.ws.on=="function"&&a.ws.on("error",l=>{r.error({err:String(l)},"WebSocket error")}),a}function Rn(e){try{e.end(new Error("omnish: socket closed"))}catch{e.ws?.close()}}function Fr(e){return e?.output?.statusCode??e?.status??e?.error?.output?.statusCode}function Mn(e){return e.user?.id?Promise.resolve():new Promise((t,n)=>{let r=o=>{if(o.connection==="open"){e.ev.off("connection.update",r),t();return}if(o.connection==="close"){e.ev.off("connection.update",r);let i=o.lastDisconnect?.error??o.lastDisconnect??new Error("Connection closed");n(i)}};e.ev.on("connection.update",r)})}function Ye(e,t,n){return new Promise((r,o)=>{let s=setTimeout(()=>o(new Error(n)),t);e.then(i=>{clearTimeout(s),r(i)},i=>{clearTimeout(s),o(i)})})}var $i=3500,uc=400,ki=18e4,Si=9e4,xi=3e5;function Nr(e,t=$i){if(e.length<=t)return[e];let n=[],r=0;for(;r<e.length;){let o=Math.min(r+t,e.length);if(o<e.length){let i=e.slice(r,o).lastIndexOf(`
171
199
 
172
- `);i>Math.floor(t*.35)&&(o=r+i+2)}n.push(e.slice(r,o)),r=o}return n}function sn(e){return new Promise(t=>setTimeout(t,e))}async function vs(e,t){await Promise.race([e,sn(Ss).then(()=>{A.warn({jid:t,ms:Ss},"whatsapp outbound self-heal: prior send chain waited too long; continuing")})])}async function ja(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{await De(e.sendMessage(t,{text:n}),xs,`whatsapp sendMessage timed out after ${xs}ms`);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await sn(800*s);continue}throw i}throw o}function Wa(e,t){let n=e.caption;switch(e.category){case"image":return{image:t,caption:n,mimetype:e.mimetype};case"video":return{video:t,caption:n,mimetype:e.mimetype};case"audio":return{audio:t,mimetype:e.mimetype,ptt:!1};case"document":return{document:t,mimetype:e.mimetype,fileName:e.displayName,caption:n}}}async function Da(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{await De(e.sendMessage(t,n),ks,`whatsapp sendMedia timed out after ${ks}ms`);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await sn(800*s);continue}throw i}throw o}function Rs(e,t={}){let n=new Map,r=t.decorate??(o=>o);return{async sendText(o,s){let i=r(s,o),a=n.get(o)??Promise.resolve(),l=vs(a,o).then(async()=>{let u=or(i,$s);for(let c=0;c<u.length;c+=1)await ja(e,o,u[c]??""),c<u.length-1&&await sn(Ha)}).catch(u=>{A.error({err:String(u),jid:o},"sendText failed")});n.set(o,l),await l.finally(()=>{n.get(o)===l&&n.delete(o)})},async sendMedia(o,s){let i=Na.readFileSync(s.absPath),a=Wa(s,i),l=n.get(o)??Promise.resolve(),u=vs(l,o).then(async()=>{await Da(e,o,a)}).catch(c=>{A.error({err:String(c),jid:o},"sendMedia failed")});n.set(o,u),await u.finally(()=>{n.get(o)===u&&n.delete(o)})}}}var Ja=400;async function Ms(e,t,n,r){let o=t(),s=await ms(e,r.fileId,o.fileReceiveMaxBytes);if("error"in s)return{mediaError:s.error};let i;try{i=Ke(o,n)}catch(l){return{mediaError:String(l)}}let a=en(i,n,r.baseName);try{return Ua.writeFileSync(a,s.buffer,{mode:384}),{mediaSavedPath:a}}catch{return{mediaError:"Could not write media to inbox."}}}function qa(e){return new Promise(t=>setTimeout(t,e))}async function sr(e,t,n,r={}){let o=new Ga(e);await o.api.deleteWebhook({drop_pending_updates:!1});let s=new Map,i=r.decorate??(c=>c);async function a(c,d){let p=Math.min(t().appsMaxWaChars,4096),f=_e(d,"telegram"),w=i(f.text,Vn(c)),M=f.parseModeHtml,X=(s.get(c)??Promise.resolve()).then(async()=>{let ee=or(w,p);for(let U=0;U<ee.length;U+=1){let ue=ee[U]??"",ge=M?{parse_mode:"HTML"}:void 0;try{await o.api.sendMessage(c,ue,ge)}catch(B){if(M){A.warn({err:String(B),chatId:c},"telegram HTML send failed; retrying plain");let Fe=ue.replace(/<[^>]+>/g,"");await o.api.sendMessage(c,Fe)}else throw B}U<ee.length-1&&await qa(Ja)}}).catch(ee=>{A.error({err:String(ee),chatId:c},"telegram sendText failed")});s.set(c,X),await X.finally(()=>{s.get(c)===X&&s.delete(c)})}async function l(c,d){let p=new za(d.absPath,d.displayName),f=d.caption,M=(s.get(c)??Promise.resolve()).then(async()=>{switch(d.category){case"image":await o.api.sendPhoto(c,p,f?{caption:f}:void 0);break;case"video":await o.api.sendVideo(c,p,f?{caption:f}:void 0);break;case"audio":await o.api.sendAudio(c,p,f?{caption:f}:void 0);break;case"document":await o.api.sendDocument(c,p,f?{caption:f}:void 0);break}}).catch(C=>{A.error({err:String(C),chatId:c},"telegram sendMedia failed")});s.set(c,M),await M.finally(()=>{s.get(c)===M&&s.delete(c)})}o.on("message",async c=>{let d=c.chat,p=c.message;if(!d||d.type!=="private"||!c.from||!p)return;let f="text"in p&&p.text?p.text:"",w="caption"in p&&p.caption?p.caption:"",M=tr([f,w].filter(Boolean).join(`
173
- `)),C=ds(p),X=Vn(d.id),ee=d.id,U=async B=>{B.kind==="file"?await l(ee,B.spec):await a(ee,B.body)};if(C&&!M){(async()=>{try{let B=await Ms(o,t,X,C);if(!B.mediaSavedPath&&!B.mediaError)return;await n({peerKey:X,text:"",tgChatId:d.id,tgReplyToMessageId:p.message_id,mediaSavedPath:B.mediaSavedPath,mediaError:B.mediaError},U)}catch(B){A.error({err:String(B),chatId:ee},"telegram media-only background task failed")}})();return}let ue,ge;if(C){let B=await Ms(o,t,X,C);ue=B.mediaSavedPath,ge=B.mediaError}!M&&!ue&&!ge||await n({peerKey:X,text:M,tgChatId:d.id,tgReplyToMessageId:p.message_id,mediaSavedPath:ue,mediaError:ge},U)}),o.catch(c=>{A.error({err:String(c)},"telegram bot error")});let u=o.start();return{bot:o,sendText:a,sendMedia:l,stop:async()=>{await o.stop(),await u.catch(()=>{})}}}import Ya from"node:fs";import Ka from"node:path";function Va(e){let t=Ka.join(e,"creds.json");try{let n=Ya.readFileSync(t,"utf8"),r=JSON.parse(n);if(!r.me||typeof r.me!="object"||r.me===null)return null;let o=r.me,s=typeof o.id=="string"?o.id:void 0,i=typeof o.phoneNumber=="string"?o.phoneNumber:void 0;return!s&&!i?null:{id:s,phoneNumber:i}}catch{return null}}function Cs(e){let t=Va(e);if(!t)return null;let n=t.phoneNumber?.trim();if(n){let s=F(n);return s?`phone ${s}`:`phone ${n}`}let r=t.id?.trim();if(!r)return null;let o=r.toLowerCase();if(o.endsWith("@s.whatsapp.net")||o.endsWith("@c.us")){let s=F(r);return s?`phone ${s}`:`id ${r}`}return o.endsWith("@lid")?`device ${r} (LID \u2014 not an E.164; your number may appear after the gateway runs)`:`id ${r}`}import an from"node:fs";import Pe from"node:process";function Ts(e){let t=String(e).toLowerCase();return t.includes("401")||t.includes("logged out")?!0:rr(e)===We.loggedOut}async function Qa(e,t){let n=Pe.stdout;console.log(`
174
- ${V(n,"omnish link")} ${g(n,"\u2014 QR appears below; scan from WhatsApp \u2192 Linked devices.")}
175
- `);let r=!1;for(let o=0;o<3;o++){let s=await nn({authDir:e,printQr:!0,verbose:t,onQr:()=>{}});try{await De(on(s),6e5,"Timed out after 10 minutes. Phone stuck on \u201CLogging in\u201D usually means: run `pnpm approve-builds && pnpm install`, check network/firewall, then try `omnish link --force` again."),console.log(`
176
- ${N(n,"Linked.")} ${y(n,"Session saved. You can run")} ${N(n,"omnish run")} ${y(n,"now.")}
177
- `);return}catch(i){if(rr(i)===We.restartRequired&&!r){r=!0,console.warn(`
178
- ${Q(Pe.stderr,"WhatsApp requested a restart after pairing (code 515). This is normal. Opening a new connection\u2026")}
179
- `),await new Promise(l=>setTimeout(l,1500));continue}throw i}finally{rn(s)}}throw new Error("Pairing failed after restart (515) retries.")}async function Is(e={}){let t=e.authDir??q,n=e.verbose===!0;G(),e.force&&(an.rmSync(t,{recursive:!0,force:!0}),an.mkdirSync(t,{recursive:!0,mode:448}),console.log(`${we(Pe.stdout,"Cleared saved session (--force).")} ${g(Pe.stdout,"Requesting a new QR\u2026")}
180
- `));for(let r=1;r<=2;r++)try{await Qa(t,n);return}catch(o){if(r===1&&Ts(o)){console.warn(`
181
- ${Q(Pe.stderr,"WhatsApp returned logged-out (401). This often happens after Ctrl+C during link or corrupt auth files.")}
182
- ${Q(Pe.stderr,"Clearing auth dir and retrying once with a fresh QR\u2026")}
183
- `),an.rmSync(t,{recursive:!0,force:!0}),an.mkdirSync(t,{recursive:!0,mode:448});continue}throw Ts(o)&&console.error(`
184
- ${k(Pe.stderr,"Still failing after a clean auth directory. Try:")}
185
- ${g(Pe.stderr,` pnpm approve-builds && pnpm install
200
+ `);i>Math.floor(t*.35)&&(o=r+i+2)}n.push(e.slice(r,o)),r=o}return n}function Tn(e){return new Promise(t=>setTimeout(t,e))}async function vi(e,t){await Promise.race([e,Tn(ki).then(()=>{M.warn({jid:t,ms:ki},"whatsapp outbound self-heal: prior send chain waited too long; continuing")})])}async function dc(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{await Ye(e.sendMessage(t,{text:n}),Si,`whatsapp sendMessage timed out after ${Si}ms`);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await Tn(800*s);continue}throw i}throw o}function pc(e,t){let n=e.caption;switch(e.category){case"image":return{image:t,caption:n,mimetype:e.mimetype};case"video":return{video:t,caption:n,mimetype:e.mimetype};case"audio":return{audio:t,mimetype:e.mimetype,ptt:!1};case"document":return{document:t,mimetype:e.mimetype,fileName:e.displayName,caption:n}}}async function mc(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{await Ye(e.sendMessage(t,n),xi,`whatsapp sendMedia timed out after ${xi}ms`);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await Tn(800*s);continue}throw i}throw o}function Ci(e,t={}){let n=new Map,r=t.decorate??(o=>o);return{async sendText(o,s){let i=r(s,o),a=n.get(o)??Promise.resolve(),l=vi(a,o).then(async()=>{let d=Nr(i,$i);for(let c=0;c<d.length;c+=1)await dc(e,o,d[c]??""),c<d.length-1&&await Tn(uc)}).catch(d=>{M.error({err:String(d),jid:o},"sendText failed")});n.set(o,l),await l.finally(()=>{n.get(o)===l&&n.delete(o)})},async sendMedia(o,s){let i=cc.readFileSync(s.absPath),a=pc(s,i),l=n.get(o)??Promise.resolve(),d=vi(l,o).then(async()=>{await mc(e,o,a)}).catch(c=>{M.error({err:String(c),jid:o},"sendMedia failed")});n.set(o,d),await d.finally(()=>{n.get(o)===d&&n.delete(o)})}}}var yc=400;async function Ri(e,t,n,r){let o=t(),s=await mi(e,r.fileId,o.fileReceiveMaxBytes);if("error"in s)return{mediaError:s.error};let i;try{i=nt(o,n)}catch(l){return{mediaError:String(l)}}let a=vn(i,n,r.baseName);try{return fc.writeFileSync(a,s.buffer,{mode:384}),{mediaSavedPath:a}}catch{return{mediaError:"Could not write media to inbox."}}}function wc(e){return new Promise(t=>setTimeout(t,e))}async function _r(e,t,n,r={}){let o=new gc(e);await o.api.deleteWebhook({drop_pending_updates:!1});let s=new Map,i=r.decorate??(c=>c);async function a(c,u){let m=Math.min(t().appsMaxWaChars,4096),f=Re(u,"telegram"),y=i(f.text,Tr(c)),w=f.parseModeHtml,E=(s.get(c)??Promise.resolve()).then(async()=>{let P=Nr(y,m);for(let D=0;D<P.length;D+=1){let W=P[D]??"",V=w?{parse_mode:"HTML"}:void 0;try{await o.api.sendMessage(c,W,V)}catch(F){if(w){M.warn({err:String(F),chatId:c},"telegram HTML send failed; retrying plain");let ue=W.replace(/<[^>]+>/g,"");await o.api.sendMessage(c,ue)}else throw F}D<P.length-1&&await wc(yc)}}).catch(P=>{M.error({err:String(P),chatId:c},"telegram sendText failed")});s.set(c,E),await E.finally(()=>{s.get(c)===E&&s.delete(c)})}async function l(c,u){let m=new hc(u.absPath,u.displayName),f=u.caption,w=(s.get(c)??Promise.resolve()).then(async()=>{switch(u.category){case"image":await o.api.sendPhoto(c,m,f?{caption:f}:void 0);break;case"video":await o.api.sendVideo(c,m,f?{caption:f}:void 0);break;case"audio":await o.api.sendAudio(c,m,f?{caption:f}:void 0);break;case"document":await o.api.sendDocument(c,m,f?{caption:f}:void 0);break}}).catch(k=>{M.error({err:String(k),chatId:c},"telegram sendMedia failed")});s.set(c,w),await w.finally(()=>{s.get(c)===w&&s.delete(c)})}o.on("message",async c=>{let u=c.chat,m=c.message;if(!u||u.type!=="private"||!c.from||!m)return;let f="text"in m&&m.text?m.text:"",y="caption"in m&&m.caption?m.caption:"",w=Lr([f,y].filter(Boolean).join(`
201
+ `)),k=di(m),E=Tr(u.id),P=u.id,D=async F=>{F.kind==="file"?await l(P,F.spec):await a(P,F.body)};if(k&&!w){(async()=>{try{let F=await Ri(o,t,E,k);if(!F.mediaSavedPath&&!F.mediaError)return;await n({peerKey:E,text:"",tgChatId:u.id,tgReplyToMessageId:m.message_id,mediaSavedPath:F.mediaSavedPath,mediaError:F.mediaError},D)}catch(F){M.error({err:String(F),chatId:P},"telegram media-only background task failed")}})();return}let W,V;if(k){let F=await Ri(o,t,E,k);W=F.mediaSavedPath,V=F.mediaError}!w&&!W&&!V||await n({peerKey:E,text:w,tgChatId:u.id,tgReplyToMessageId:m.message_id,mediaSavedPath:W,mediaError:V},D)}),o.catch(c=>{M.error({err:String(c)},"telegram bot error")});let d=o.start();return{bot:o,sendText:a,sendMedia:l,stop:async()=>{await o.stop(),await d.catch(()=>{})}}}import bc from"node:fs";import kc from"node:path";function Sc(e){let t=kc.join(e,"creds.json");try{let n=bc.readFileSync(t,"utf8"),r=JSON.parse(n);if(!r.me||typeof r.me!="object"||r.me===null)return null;let o=r.me,s=typeof o.id=="string"?o.id:void 0,i=typeof o.phoneNumber=="string"?o.phoneNumber:void 0;return!s&&!i?null:{id:s,phoneNumber:i}}catch{return null}}function Mi(e){let t=Sc(e);if(!t)return null;let n=t.phoneNumber?.trim();if(n){let s=_(n);return s?`phone ${s}`:`phone ${n}`}let r=t.id?.trim();if(!r)return null;let o=r.toLowerCase();if(o.endsWith("@s.whatsapp.net")||o.endsWith("@c.us")){let s=_(r);return s?`phone ${s}`:`id ${r}`}return o.endsWith("@lid")?`device ${r} (LID \u2014 not an E.164; your number may appear after the gateway runs)`:`id ${r}`}import In from"node:fs";import We from"node:process";function Ti(e){let t=String(e).toLowerCase();return t.includes("401")||t.includes("logged out")?!0:Fr(e)===qe.loggedOut}async function xc(e,t){let n=We.stdout;console.log(`
202
+ ${oe(n,"omnish link")} ${h(n,"\u2014 QR appears below; scan from WhatsApp \u2192 Linked devices.")}
203
+ `);let r=!1;for(let o=0;o<3;o++){let s=await Cn({authDir:e,printQr:!0,verbose:t,onQr:()=>{}});try{await Ye(Mn(s),6e5,"Timed out after 10 minutes. Phone stuck on \u201CLogging in\u201D usually means: run `pnpm approve-builds && pnpm install`, check network/firewall, then try `omnish link --force` again."),console.log(`
204
+ ${U(n,"Linked.")} ${b(n,"Session saved. You can run")} ${U(n,"omnish run")} ${b(n,"now.")}
205
+ `);return}catch(i){if(Fr(i)===qe.restartRequired&&!r){r=!0,console.warn(`
206
+ ${se(We.stderr,"WhatsApp requested a restart after pairing (code 515). This is normal. Opening a new connection\u2026")}
207
+ `),await new Promise(l=>setTimeout(l,1500));continue}throw i}finally{Rn(s)}}throw new Error("Pairing failed after restart (515) retries.")}async function Ii(e={}){let t=e.authDir??ee,n=e.verbose===!0;Q(),e.force&&(In.rmSync(t,{recursive:!0,force:!0}),In.mkdirSync(t,{recursive:!0,mode:448}),console.log(`${Se(We.stdout,"Cleared saved session (--force).")} ${h(We.stdout,"Requesting a new QR\u2026")}
208
+ `));for(let r=1;r<=2;r++)try{await xc(t,n);return}catch(o){if(r===1&&Ti(o)){console.warn(`
209
+ ${se(We.stderr,"WhatsApp returned logged-out (401). This often happens after Ctrl+C during link or corrupt auth files.")}
210
+ ${se(We.stderr,"Clearing auth dir and retrying once with a fresh QR\u2026")}
211
+ `),In.rmSync(t,{recursive:!0,force:!0}),In.mkdirSync(t,{recursive:!0,mode:448});continue}throw Ti(o)&&console.error(`
212
+ ${R(We.stderr,"Still failing after a clean auth directory. Try:")}
213
+ ${h(We.stderr,` pnpm approve-builds && pnpm install
186
214
  (pnpm may have skipped Baileys/sharp/protobuf build scripts.)
187
215
  Then: omnish link --force
188
- `)}`),o}}import Za from"node:crypto";import ir from"node:fs";import Xa from"node:net";var wt=null;function el(){try{let e=ir.readFileSync(Ue,"utf8"),t=JSON.parse(e);return typeof t.token=="string"?t.token:""}catch{return""}}function tl(e){ir.writeFileSync(Ue,JSON.stringify(e,null,2)+`
189
- `,{mode:384})}function nl(){try{ir.unlinkSync(Ue)}catch{}}async function rl(e,t,n){let r;try{r=JSON.parse(e)}catch{return{ok:!1,error:"Invalid JSON."}}if(!r||typeof r!="object"||r.op!=="sendMedia")return{ok:!1,error:"Unsupported operation."};if(typeof r.token!="string"||!n||r.token!==n)return{ok:!1,error:"Unauthorized."};let o=t.getCfg(),s=typeof r.absPath=="string"?r.absPath.trim():"";if(!s)return{ok:!1,error:"Missing absPath."};let i=typeof r.caption=="string"&&r.caption.length>0?r.caption:void 0,a=qe(s,o.fileSendMaxBytes);if("error"in a)return{ok:!1,error:a.error};let l={absPath:a.absPath,category:a.category,mimetype:a.mimetype,displayName:a.displayName,caption:i};if(r.channel==="whatsapp"){let u=t.getWaOutbound();if(!u)return{ok:!1,error:"WhatsApp outbound is not connected."};let c=o.gatewayMode;if(c!=="whatsapp"&&c!=="both")return{ok:!1,error:"gatewayMode does not include WhatsApp."};let d=typeof r.e164=="string"?r.e164.trim():"";if(!d.startsWith("+"))return{ok:!1,error:"WhatsApp destination must be E.164 (e.g. +15551234567)."};let p=Sr(d);try{return await u.sendMedia(p,l),{ok:!0}}catch(f){return{ok:!1,error:String(f)}}}if(r.channel==="telegram"){let u=t.getTgSendMedia();if(!u)return{ok:!1,error:"Telegram outbound is not connected."};let c=o.gatewayMode;if(c!=="telegram"&&c!=="both")return{ok:!1,error:"gatewayMode does not include Telegram."};if(!Number.isFinite(r.chatId))return{ok:!1,error:"Invalid Telegram chat id."};try{return await u(r.chatId,l),{ok:!0}}catch(d){return{ok:!1,error:String(d)}}}return{ok:!1,error:"Unknown channel."}}function As(e){if(wt)return;let t=Za.randomBytes(32).toString("hex"),n=Xa.createServer(r=>{let o="";r.setTimeout(12e4),r.on("data",s=>{o+=s.toString("utf8");let i=o.indexOf(`
190
- `);if(i===-1)return;let a=o.slice(0,i).trim();o=o.slice(i+1);let l=el();rl(a,e,l).then(u=>{r.write(`${JSON.stringify(u)}
191
- `),r.end()})}),r.on("error",()=>{})});n.listen(0,"127.0.0.1",()=>{let r=n.address();if(!r||typeof r=="string"){A.error("gateway control: could not read listen address");return}let o={token:t,host:r.address,port:r.port};tl(o),A.info({port:r.port},"gateway control listening")}),n.on("error",r=>{A.error({err:String(r)},"gateway control server error")}),wt=n}function ln(){if(wt){try{wt.close()}catch{}wt=null,nl()}}import al from"node:readline";import cr from"node:path";import Z from"node:process";import ol from"node:net";import sl from"node:fs";function il(){try{let e=sl.readFileSync(Ue,"utf8"),t=JSON.parse(e);return typeof t.host!="string"||typeof t.port!="number"||typeof t.token!="string"||!Number.isFinite(t.port)?null:{host:t.host,port:t.port,token:t.token}}catch{return null}}async function ar(e){let t=il();if(!t)return"No gateway control endpoint \u2014 is `omnish run` active? (control metadata missing.)";let n={...e,token:t.token},r=`${JSON.stringify(n)}
192
- `;return new Promise(o=>{let s=!1,i="";function a(u){s||(s=!0,o(u))}let l=ol.connect({host:t.host,port:t.port},()=>{l.write(r)});l.setTimeout(6e5),l.on("data",u=>{i+=u.toString("utf8");let c=i.indexOf(`
193
- `);if(c>=0){let d=i.slice(0,c).trim();try{let p=JSON.parse(d);p.ok?a(null):a(p.error||"Unknown error from gateway control.")}catch{a("Invalid response from gateway control.")}l.destroy()}}),l.on("error",u=>{a(`Control connection failed: ${String(u)}`)}),l.on("timeout",()=>{l.destroy(),a("Gateway control timed out.")}),l.on("close",()=>{!s&&i.trim()===""&&a("Gateway closed the control connection without a response.")})})}function Es(e){let t=e.trim();if(!/^\/sendto(\s|$)/i.test(t))return null;let n=t.replace(/^\/sendto\s+/i,"").trim();if(!n)return null;let r=n.indexOf(" ");if(r===-1)return null;let o=n.slice(0,r).trim(),s=n.slice(r+1).trim();if(!s)return null;let i=s.indexOf(" -- "),a,l;if(i>=0?(a=s.slice(0,i).trim(),l=s.slice(i+4).trim()||void 0):a=s,(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),!a)return null;let u=o.toLowerCase();if(u.startsWith("tg:")||u.startsWith("telegram:")){let c=me(o);if(!c)return null;let d=Number(c);return Number.isFinite(d)?{channel:"telegram",chatId:d,filePart:a,caption:l}:null}if(u.startsWith("wa:")){let c=F(o.slice(3));return c?{channel:"whatsapp",e164:c,filePart:a,caption:l}:null}if(o.startsWith("+")){let c=F(o);return c?{channel:"whatsapp",e164:c,filePart:a,caption:l}:null}return null}function lr(){return["/sendto wa:+E164 <file> [-- caption]","/sendto tg:<chat_id> <file> [-- caption]","Also: /sendto +E164 <file> (WhatsApp). Requires `omnish run` on this machine."].join(`
194
- `)}var lt="wa:cli:interactive";function ll(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let s=me(t);return s?`tg:${s}`:null}let r=n.startsWith("wa:")?t.slice(3):t,o=F(r);return o?`wa:${o}`:null}function cl(e){let t=null,n=null;for(let r=0;r<e.length;){let o=e[r]??"";if(o==="--as"){let s=e[r+1];if(!s||s.startsWith("-"))return{opts:{senderKey:null,oneShot:null},error:"--as requires a sender (wa:+E164 or tg:<id>)."};let i=ll(s);if(!i)return{opts:{senderKey:null,oneShot:null},error:`Could not parse sender "${s}". Use +E164, wa:+E164, or tg:<user_id>.`};t=i,r+=2;continue}if(o==="-c"||o==="--command"){let s=e[r+1];if(typeof s!="string")return{opts:{senderKey:null,oneShot:null},error:`${o} requires a command string.`};n=s,r+=2;continue}return o==="--help"||o==="-h"?{opts:{senderKey:null,oneShot:null},error:"help"}:{opts:{senderKey:null,oneShot:null},error:`Unknown argument: ${o}`}}return{opts:{senderKey:t,oneShot:n},error:null}}function ur(e){let t=Z.cwd(),n=[`${N(e,"omnish i")} ${g(e,"[options]")}`,K(e,"Interactive shell \u2014 same commands as WhatsApp/Telegram chat."),"",W(e,"Usage:"),` ${y(e,"omnish i [options]")}`,` ${y(e,"omnish interactive [options]")}`,"",W(e,"Options:"),...Ie(e," ",[{left:"--as <sender>",right:"Sender key for cluster commands (wa:+E164 or tg:id). Default: synthetic wa:cli:interactive."},{left:"-c, --command <line>",right:"Run one line and exit (non-interactive)."},{left:"-h, --help",right:"Show this help."}],r=>g(e,r)),"",`${g(e,"Trust:")} ${y(e,"Full local access like your shell; not gated by inbox allowlist.")}`,`${g(e,"Jobs:")} ${y(e,"/bg and /jobs apply only to this REPL session (not the gateway process).")}`,`${g(e,"Files:")} ${y(e,"Use /sendto to push a host file through the gateway; plain /send needs a chat peer.")}`,`${g(e,"Gateway:")} ${y(e,"/reload requires omnish run; /sendto requires omnish run for WA/TG delivery.")}`,"",lr(),"",`${g(e,"cwd:")} ${y(e,`session starts at ${t} (change with !cd or ${x().commandPrefix}cd).`)}`];console.log(n.join(`
195
- `))}async function ul(e){let t=x(),n=z(lt).cwd,r=cr.resolve(n,e.filePart),o=qe(r,t.fileSendMaxBytes);return"error"in o?o.error:e.channel==="whatsapp"?await ar({op:"sendMedia",channel:"whatsapp",e164:e.e164,absPath:o.absPath,caption:e.caption}):await ar({op:"sendMedia",channel:"telegram",chatId:e.chatId,absPath:o.absPath,caption:e.caption})}async function dl(e,t,n,r,o,s,i){let a=e.trim();if(!a)return;let l=Es(a);if(l!==null||/^\/sendto(\s|$)/i.test(a)){if(l===null){console.log(k(Z.stderr,`Invalid /sendto.
196
- `+lr()));return}let d=await ul(l);console.log(d?k(Z.stderr,d):Q(Z.stdout,"Sent."));return}let u={peerKey:lt,text:e},c=await He(x(),t,n,r,o,u,s,void 0,i);c!==null&&await pl(c)}async function pl(e){if(e===null)return;if(e.kind==="file"){console.log(Q(Z.stdout,["This CLI session has no chat peer to attach to.","Push through the gateway instead, for example:"," /sendto wa:+15551234567 ./my.pdf"," /sendto tg:123456789 ~/photo.jpg -- optional caption","(Requires `omnish run` on this machine.)"].join(`
197
- `)));return}let t=_e(e.body,"whatsapp").text;t.trim()&&console.log(t)}async function Os(e){let t=cl(e);if(t.error==="help"){ur(Z.stdout);return}if(t.error&&t.error!==null){console.error(k(Z.stderr,t.error)),console.error(g(Z.stderr,"Try: omnish i --help")),Z.exitCode=1;return}let{senderKey:n,oneShot:r}=t.opts,o=n??lt;G(),At(lt,Z.cwd());let s=new je,i=new Map,a=new Map,l=new Map,u=new ot(()=>x(),async(f,w)=>{Z.stdout.write(w),w.endsWith(`
198
- `)||Z.stdout.write(`
199
- `)}),c=async f=>{try{await dl(f,s,i,a,l,u,o)}catch(w){console.error(k(Z.stderr,String(w)))}};if(r!==null){await c(r),u.dispose(),s.killAllRunning();return}let d=al.createInterface({input:Z.stdin,output:Z.stdout}),p=cr.basename(z(lt).cwd);d.setPrompt(`${p}> `),d.on("line",f=>{c(f).then(()=>{let w=cr.basename(z(lt).cwd);d.setPrompt(`${w}> `),d.prompt()})}),d.on("close",()=>{u.dispose(),s.killAllRunning(),Z.stdout.write(`
200
- `)}),d.prompt()}ml.setDefaultResultOrder("ipv4first");var yl=ct.join(ct.dirname(hl(import.meta.url)),"..","package.json"),dr=JSON.parse(ie.readFileSync(yl,"utf8"));function Fs(){let e=process.stdout,t=[`${V(e,"omnish run")} ${g(e,"[options]")}`,K(e,"Listen for DMs and run shell commands from allowlisted chats."),"",W(e,"Usage:"),` ${y(e,"omnish run [options]")}`,"",W(e,"Options:"),...Ie(e," ",[{left:"-d, --background",right:"Start the gateway detached; log to --log-file (default: <data>/logs/gateway.log)."},{left:"--log-file <path>",right:`Append stdout/stderr when background (default: ${pe}).`},{left:"-h, --help",right:"Show this help."}],n=>g(e,n)),"",`${y(e,"Config reload:")} ${g(e,"while the gateway runs, edit config then send /reload or /restart from an allowlisted chat (no restart needed for many keys).")}`,""];console.log(t.join(`
201
- `))}function Bs(){let e=process.stdout,t=[{left:"omnish link [--force]",right:"WhatsApp: scan QR (Linked devices). --force wipes session first."},{left:"omnish link --tg <bot_token>",right:"Telegram: save token to config; gatewayMode telegram or both if WhatsApp is linked."}],n=t.map(i=>g(e,i.left)),r=Math.max(...n.map(Ot)),o=t.map((i,a)=>fn(" ",r,n[a],y(e,i.right))),s=[`${V(e,"omnish link")} ${g(e,"[options]")}`,K(e,"Connect WhatsApp (QR) or save a Telegram bot token."),"",W(e,"Usage:"),` ${y(e,"omnish link [--force]")}`,` ${y(e,"omnish link --tg <bot_token>")}`,"",W(e,"Modes:"),...o,` ${K(e,"Do not combine --tg with --force.")}`,"",W(e,"Options:"),...Ie(e," ",[{left:"-f, --force",right:"WhatsApp only: delete saved session before pairing."},{left:"-h, --help",right:"Show this help."}],i=>g(e,i)),"",`${y(e,"Next:")} ${N(e,"omnish allow tg:<your_user_id>")} ${g(e,"then")} ${N(e,"omnish run")}`,`${g(e,"Config:")} ${y(e,v)}`,""];console.log(s.join(`
202
- `))}function wl(e){let t=!1,n=null;for(let r=0;r<e.length;r++){let o=e[r]??"";if(o==="--help"||o==="-h")return{kind:"help"};if(o==="--force"||o==="-f"){t=!0;continue}if(o==="--tg"||o==="--telegram"){let s=e[r+1];if(!s||s.startsWith("-"))return{kind:"error",message:"[omnish] --tg requires a bot token (from @BotFather)."};n=s,r++;continue}if(o.startsWith("--tg=")||o.startsWith("--telegram=")){let s=o.indexOf("="),i=o.slice(s+1).trim();if(!i)return{kind:"error",message:"[omnish] --tg= requires a non-empty bot token."};n=i;continue}return{kind:"error",message:`[omnish] unknown link argument: ${o}
203
- Try: omnish link --help`}}return n!==null?t?{kind:"error",message:"[omnish] --force applies to WhatsApp only; do not combine with --tg."}:{kind:"tg",token:n}:{kind:"wa",force:t}}function pr(){let e=process.stdout,t=`${V(e,"omnish")} ${g(e,`v${dr.version}`)}`,n=[{left:"link [--force] [--tg <token>]",right:"WhatsApp (QR) or Telegram bot token \u2014 omnish link --help"},{left:"run [options]",right:"Listen for DMs (WhatsApp and/or Telegram \u2014 see gatewayMode in config)"},{left:"stop",right:`Stop background gateway (pidfile: ${Y})`},{left:"service <subcommand>",right:"Boot install hints, logs, systemd/LaunchAgent \u2014 omnish service help"},{left:"logout",right:"Delete saved WhatsApp session"},{left:"allow +<E164> | tg:<id>",right:"Add allowlist entry"},{left:"deny +<E164> | tg:<id>",right:"Remove allowlist entry"},{left:"status",right:"Channels, identity, allowlists, jobs, security, cluster (if enabled)"},{left:"commands",right:"Chat commands for allowlisted users (same as /help)"},{left:"security [--json]",right:"Configuration security report (JSON for scripts)"},{left:"cluster [status | use <sender> <label-or-id>]",right:"Per-sender machine bindings"},{left:"i | interactive [options]",right:"Local REPL (chat commands; /sendto needs omnish run)"}],r=[{left:"-v, --version",right:"Print version and exit."},{left:"-h, --help",right:"Show this help (same as omnish help)."}],o=[t,K(e,"Allowlisted inbox \u2192 your real shell. No AI."),"",W(e,"Usage:"),` ${y(e,"omnish [options] <command> [args...]")}`,"",W(e,"Options:"),...Ie(e," ",r,s=>g(e,s)),"",W(e,"Commands:"),...Ie(e," ",n,s=>g(e,s)),"",`${g(e,"Config:")} ${y(e,`${v} \u2014 gatewayMode: "whatsapp" | "telegram" | "both"`)}`,`${g(e,"Env:")} ${y(e,"OMNISH_VERBOSE=1 (Baileys; legacy WHATSVERBOSE=1 still works), TELEGRAM_BOT_TOKEN (optional)")}`,`${g(e,"Data:")} ${y(e,"~/.omnish by default; ~/.whatslive reused if it already exists. OMNISH_HOME overrides.")}`,`${g(e,"See also:")} ${y(e,"https://omnish.dev")}`,""];console.log(o.join(`
204
- `))}function bl(e){let t=(e??"").trim().toLowerCase(),n=process.stdout;if(!t){pr();return}switch(t){case"link":Bs();return;case"run":Fs();return;case"service":Ns();return;case"i":case"interactive":ur(n);return;default:console.error(k(process.stderr,`No detailed help for "${e}". Try: omnish help`)),process.exitCode=1}}function Sl(e){let t=!1,n="",r=!1;for(let s=0;s<e.length;s++){let i=e[s]??"";if(i==="-d"||i==="--background")t=!0;else if(i==="--log-file"||i==="--log"){let a=e[++s];a||(console.error(k(process.stderr,"--log-file requires a path.")),process.exit(1)),n=a}else if(i==="--help"||i==="-h")r=!0;else{let a=process.stderr;console.error(k(a,`unknown run option: ${i}`)),console.error(k(a,"Try: omnish run --help")),process.exit(1)}}let o=n.trim()!==""?ct.isAbsolute(n)?n:ct.resolve(process.cwd(),n):pe;return{background:t,logFile:o,help:r}}function xl(e){G(),P(ct.dirname(e));let t=process.argv[1];t||(console.error(k(process.stderr,"cannot resolve entry script; invoke via node path/to/dist/index.js.")),process.exit(1));let n=ie.openSync(e,"a"),r=fl(process.execPath,[t,"run"],{detached:!0,stdio:["ignore",n,n],env:{...process.env,OMNISH_BACKGROUND_GATEWAY:"1"}});ie.closeSync(n),r.unref(),r.pid||(console.error(k(process.stderr,"failed to start background gateway.")),process.exit(1));let o=process.stdout;console.log(`${Q(o,`gateway started in background (pid ${r.pid}).`)} ${g(o,`Log: ${e}`)}`)}function kl(){if(G(),!ie.existsSync(Y)){console.error(k(process.stderr,`no pidfile at ${Y} \u2014 is a background gateway running?`)),process.exitCode=1;return}let e=ie.readFileSync(Y,"utf8").trim(),t=Number(e);if(!Number.isFinite(t)||t<=0){console.error(k(process.stderr,"invalid pidfile."));try{ie.unlinkSync(Y)}catch{}process.exitCode=1;return}try{process.kill(t,0)}catch{console.log(Q(process.stdout,`process ${t} is not running; removing stale pidfile.`));try{ie.unlinkSync(Y)}catch{}return}try{process.kill(t,"SIGTERM"),console.log(Q(process.stdout,`sent SIGTERM to gateway (pid ${t}).`))}catch(n){if(process.platform==="win32"&&gl("taskkill",["/PID",String(t),"/T"],{windowsHide:!0}).status===0){console.log(Q(process.stdout,`stopped gateway (pid ${t}) using taskkill.`));return}console.error(k(process.stderr,`could not signal process: ${String(n)}`)),process.exitCode=1}}function Ls(){if(process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{ie.readFileSync(Y,"utf8").trim()===String(process.pid)&&ie.unlinkSync(Y)}catch{}}function vl(e){return e.length<=8?"(set)":`${e.slice(0,4)}\u2026${e.slice(-4)}`}function $l(){if(!ie.existsSync(Y))return"gateway process: not running (no pid file)";let e=ie.readFileSync(Y,"utf8").trim(),t=Number(e);if(!Number.isFinite(t)||t<=0)return"gateway process: invalid pid file";try{return process.kill(t,0),`gateway process: running (pid ${t})`}catch{return`gateway process: not running (stale pid ${t} in pid file)`}}var _s=120;function Ns(){let e=process.stdout,t=[{left:"help",right:"This help."},{left:"instructions",right:"Copy-paste install steps for this machine."},{left:"status",right:"Data dir, pidfile, Node + entry script."},{left:"logs [n]",right:`Tail default gateway log (default 80 lines, max ${_s}).`},{left:"install",right:"Write user systemd / LaunchAgent unit (needs serviceInstallFromChat=true)."},{left:"uninstall",right:"Remove that unit (same gate as install)."}],n=[`${V(e,"omnish service")} ${g(e,"<subcommand>")}`,K(e,"Boot integration, crash restart policy, and logs (same ideas as /service in chat)."),"",W(e,"Usage:"),` ${y(e,"omnish service <subcommand>")}`,"",W(e,"Subcommands:"),...Ie(e," ",t,r=>g(e,r)),"",W(e,"Restart and reload:"),` ${y(e,"Process")} ${g(e,"\u2014 Linux user unit: Restart=on-failure, RestartSec=5. macOS: KeepAlive. Full restart loads config from disk.")}`,` ${y(e,"Config live")} ${g(e,"\u2014 allowlisted chat while gateway runs: /reload or /restart")}`,"",`${g(e,"Docs:")} ${y(e,"docs/guides/background-and-boot.md")} ${K(e,"\xB7")} https://omnish.dev`,""];console.log(n.join(`
205
- `))}function Rl(e){let t=process.stdout,n=process.stderr,r=(e[0]??"help").toLowerCase();if(r==="help"||r==="--help"||r==="-h"){Ns();return}if(r==="instructions"){let o=Ne();if(o.error){console.error(k(n,o.error)),process.exitCode=1;return}console.log(Jt(o));return}if(r==="status"){let o=Ne(),s=(()=>{try{return ie.existsSync(Y)?`gateway.pid: ${ie.readFileSync(Y,"utf8").trim()}`:"gateway.pid: (missing)"}catch(d){return`gateway.pid: (read error: ${String(d)})`}})(),i=process.env.OMNISH_BACKGROUND_GATEWAY==="1"?"This process: background gateway (OMNISH_BACKGROUND_GATEWAY=1).":"This process: CLI (not the gateway \u2014 run omnish service status on the host where the gateway runs for live pid info).",a=typeof process.env.OMNISH_HOME=="string"&&process.env.OMNISH_HOME.trim()?`OMNISH_HOME env: ${process.env.OMNISH_HOME.trim()}`:"OMNISH_HOME env: (not set \u2014 using default data dir)",l=o.error?o.error:`Node: ${o.nodePath}
206
- Script: ${o.scriptPath}`,c=x().serviceInstallFromChat?"Install from CLI/chat: enabled (omnish service install / /service install).":"Install from CLI/chat: off \u2014 set serviceInstallFromChat true in config (same trust as shell).";console.log(V(t,"omnish service status")),console.log(""),console.log(`${g(t,"platform:")} ${y(t,process.platform)}`),console.log(`${g(t,"session:")} ${y(t,i)}`),console.log(`${g(t,"env:")} ${y(t,a)}`),console.log(`${g(t,"data dir:")} ${y(t,T)}`),console.log(`${g(t,"pidfile:")} ${y(t,s)}`),console.log(`${g(t,"default log:")} ${y(t,pe)}`),console.log(""),console.log(l),console.log(""),console.log(y(t,c));return}if(r==="logs"){let o=e.length>=2?Number.parseInt(e[1],10):80,s=Number.isFinite(o)&&o>0?Math.min(o,_s):80,i=Vt(pe,s);console.log(`${g(t,"file:")} ${y(t,pe)}`),console.log(`${g(t,"lines:")} ${y(t,String(s))}`),console.log(""),console.log(i);return}if(r==="install"){if(!x().serviceInstallFromChat){console.error(k(n,"Install is disabled. Set serviceInstallFromChat to true in config (same trust as shell), then run again.")),process.exitCode=1;return}let s=qt();s.ok?console.log(Q(t,s.detail)):(console.error(k(n,s.detail)),process.exitCode=1);return}if(r==="uninstall"){if(!x().serviceInstallFromChat){console.error(k(n,"Uninstall is disabled. Set serviceInstallFromChat to true in config or remove the unit file on the host manually.")),process.exitCode=1;return}let s=Yt();s.ok?console.log(Q(t,s.detail)):(console.error(k(n,s.detail)),process.exitCode=1);return}console.error(k(n,`Unknown subcommand "${r}". Try: omnish service help`)),process.exitCode=1}function Ml(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let s=me(t);return s?`tg:${s}`:null}let r=n.startsWith("wa:")?t.slice(3):t,o=F(r);return o?`wa:${o}`:null}async function Cl(){let e=x(),t=e.gatewayMode,n=t==="whatsapp"||t==="both",r=t==="telegram"||t==="both",o=ae(e);r&&!o&&(console.error(k(process.stderr,`Telegram enabled (gatewayMode) but no bot token. Set telegramBotToken in config or TELEGRAM_BOT_TOKEN.
207
- config: ${v}`)),process.exit(1)),n&&!Je()&&(console.error(k(process.stderr,"WhatsApp enabled but no session. Run `omnish link` first.")),process.exit(1));let s=Qe(e),i=process.stderr;yn(s)&&(console.error(Bt(s,i)),console.error(k(i,"Fix security errors above before starting the gateway (or change gatewayMode / token).")),process.exit(1));let a=Hr(s,"warn");if(a.length>0&&(console.warn(`${Q(i,`Security (${a.length} finding(s)):`)}
208
- `),console.warn(Bt(a,i))),process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{ie.writeFileSync(Y,`${process.pid}
209
- `,{mode:384})}catch($){A.warn({err:String($)},"could not write gateway pidfile")}let l=($,L)=>{let _=x();if(!_.clusterEnabled)return $;let O=fe(),h=(_.clusterLabel??"").trim()||Ps.hostname(),b=null;if(L.startsWith("tg:"))b=L;else if(L){let J=F(L);J&&(b=`wa:${J}`)}let R=b?Re(_,b):null;return Fo($,{nodeId:O,label:h,role:_.clusterRole,activeNodeId:R?.nodeId??""})},u=new je,c=new Map,d=new Map,p=new Map,f=null,w={stop:null,sendText:null,sendMedia:null},M=null,C=!1,X=async($,L)=>{if($.startsWith("wa:")){let _=$.slice(3);f&&await f.sendText(_,L)}else if($.startsWith("tg:")){let _=Number($.slice(3));w.sendText&&Number.isFinite(_)&&await w.sendText(_,m(L))}},ee=()=>new ot(()=>x(),X),U=ee();M=U;let ue,ge={async reload(){try{A.info("gateway reload requested from chat"),await w.stop?.().catch(()=>{}),w.stop=null,w.sendText=null,w.sendMedia=null;let $=x(),L=$.gatewayMode==="telegram"||$.gatewayMode==="both",_=ae($);if(L&&_){let h=await sr(_,()=>x(),ue,{decorate:l});w.sendText=h.sendText,w.sendMedia=h.sendMedia,w.stop=h.stop}return{ok:!0,summary:["Reload complete.",`gatewayMode: ${$.gatewayMode}`,L&&_?"Telegram bot is running with the current token.":"Telegram bot is stopped (enable telegram/both + token if you want it).","Allowlists, shell, app session limits, and timeouts are read from disk on each command."].join(`
210
- `)}}catch($){return{ok:!1,error:String($)}}}};if(ue=async($,L)=>{let _=x(),O=vr(_.telegramAllowFrom),h=$.peerKey.startsWith("tg:")?$.peerKey.slice(3):"";if(!h||!O.has(h)){A.warn({denied:$.peerKey,uid:h},"telegram denied");return}try{let b=$.peerKey;if(!Kn(_,$.text,b))return;if($.mediaError&&await L({kind:"text",body:m($.mediaError)}),$.mediaSavedPath&&await L({kind:"text",body:m(`Saved: ${$.mediaSavedPath}`)}),$.text.trim()){let R=await He(_,u,c,d,p,$,U,ge,b);R!==null&&await L(R)}}catch(b){A.error({err:String(b)},"telegram handler error"),await L({kind:"text",body:m(`Error: ${String(b)}`)}).catch(()=>{})}},r){let $=await sr(o,()=>x(),ue,{decorate:l});w.sendText=$.sendText,w.sendMedia=$.sendMedia,w.stop=$.stop}As({getCfg:()=>x(),getWaOutbound:()=>f,getTgSendMedia:()=>w.sendMedia});let B=!r,Fe=()=>{C=!0,Ls(),ln(),w.stop?.().catch(()=>{}),M?.dispose(),u.killAllRunning(),console.error(`
211
- ${k(process.stderr,"shutting down\u2026")}`),process.exit(0)};if(process.on("SIGINT",Fe),process.on("SIGTERM",Fe),n)for(;!C;){let $=!1,L;try{L=await nn({printQr:!1,verbose:Qt()}),await De(on(L),3e5,"Gateway: timed out waiting for WhatsApp connection (5 min).")}catch(O){console.error(k(process.stderr,`connect failed: ${String(O)}`)),await new Promise(h=>setTimeout(h,5e3));continue}f=Rs(L,{decorate:l});let _=bs(L,async O=>{let h=x(),b=kr(h.allowFrom),R=O.fromE164||F(O.fromJid)||"";if(!R||!b.has(R)){A.warn({denied:O.fromJid,phone:R},"denied");return}try{let J=is(O),xe=`wa:${R}`;if(!Kn(h,J.text,xe))return;if(O.mediaError&&await f.sendText(O.fromJid,O.mediaError),O.mediaSavedPath&&await f.sendText(O.fromJid,`Saved: ${O.mediaSavedPath}`),O.text.trim()){let he=await He(h,u,c,d,p,J,U,ge,xe);he!==null&&(he.kind==="file"?await f.sendMedia(O.fromJid,he.spec):await f.sendText(O.fromJid,_e(he.body,"whatsapp").text))}}catch(J){A.error({err:String(J)},"handler error"),await f.sendText(O.fromJid,_e(m(`Error: ${String(J)}`),"whatsapp").text).catch(()=>{})}});if(await new Promise(O=>{let h=b=>{b.connection==="close"&&(nr(b.lastDisconnect)===We.loggedOut&&($=!0),L.ev.off("connection.update",h),O())};L.ev.on("connection.update",h)}),_(),B&&(U.dispose(),U=ee(),M=U),rn(L),f=null,$&&(console.error(k(process.stderr,"session logged out. Run `omnish link` again.")),Ls(),ln(),w.stop?.().catch(()=>{}),process.exit(1)),C)break;await new Promise(O=>setTimeout(O,3e3))}else for(;!C;)await new Promise($=>setTimeout($,500));ln(),w.stop?.().catch(()=>{}),U.dispose()}async function Tl(){let[,,e,...t]=process.argv;if(e==="--version"||e==="-v"||e==="-V"){let n=process.stdout;console.log(`${V(n,"omnish")} ${g(n,dr.version)}`);return}if(e==="--help"||e==="-h"){pr();return}if(e==="help"){bl(t[0]);return}switch(G(),e){case"link":{let n=wl(t);if(n.kind==="help"){Bs();return}if(n.kind==="error"){let r=process.stderr,o=n.message.replace(/^\[omnish\]\s*/,"");console.error(k(r,o)),process.exitCode=1;return}if(n.kind==="tg"){let r=n.token.trim(),o=process.stderr,s=process.stdout;if(!Ge(r)){console.error(k(o,"That does not look like a Telegram bot token (expect digits:secret from @BotFather).")),process.exitCode=1;return}ze(r);let i=Je()?"both":"telegram";Ct(i),console.log([`${N(s,"Telegram")} ${y(s,"bot token saved to")} ${g(s,v)}`,`${g(s,"gatewayMode:")} ${N(s,i)}`,"",y(s,"Next:"),` ${g(s,"1.")} ${y(s,"Find your numeric user id (e.g. t.me/userinfobot), then:")} ${N(s,"omnish allow tg:<id>")}`,` ${g(s,"2.")} ${N(s,"omnish run")}`,""].join(`
212
- `));return}await Is({verbose:Qt(),force:n.force});return}case"run":{let n=Sl(t);if(n.help){Fs();return}if(n.background){xl(n.logFile);return}await Cl();return}case"stop":kl();return;case"logout":{try{ie.rmSync(q,{recursive:!0,force:!0}),console.log(Q(process.stdout,"Session removed. Run `omnish link` to pair again."))}catch(n){console.error(k(process.stderr,`logout failed: ${String(n)}`)),process.exitCode=1}return}case"allow":{let n=t[0],r=process.stdout,o=process.stderr;if(!n){console.error(k(o,"Usage: omnish allow +<E164> or omnish allow tg:<user_id>")),process.exitCode=1;return}try{let s=$t(n);console.log(`${g(r,"allowFrom:")} ${y(r,s.allowFrom.join(", ")||"(empty)")}`),console.log(`${g(r,"telegramAllowFrom:")} ${y(r,s.telegramAllowFrom.join(", ")||"(empty)")}`)}catch(s){console.error(k(o,String(s).replace(/^\[omnish\]\s*/,""))),process.exitCode=1}return}case"deny":{let n=t[0],r=process.stdout,o=process.stderr;if(!n){console.error(k(o,"Usage: omnish deny +<E164> or omnish deny tg:<user_id>")),process.exitCode=1;return}try{let s=Rt(n);console.log(`${g(r,"allowFrom:")} ${y(r,s.allowFrom.join(", ")||"(empty)")}`),console.log(`${g(r,"telegramAllowFrom:")} ${y(r,s.telegramAllowFrom.join(", ")||"(empty)")}`)}catch(s){console.error(k(o,String(s).replace(/^\[omnish\]\s*/,""))),process.exitCode=1}return}case"i":case"interactive":{await Os(t);return}case"status":{let n=process.stdout,r=x(),o=new je().list(),s=o.filter(f=>f.status==="running").length,i=ae(r),a=Qe(r),l=r.gatewayMode==="whatsapp"||r.gatewayMode==="both",u=r.gatewayMode==="telegram"||r.gatewayMode==="both",c=Je(),d=c?Cs(q):null,p=[];if(p.push(`${V(n,"omnish")} ${g(n,dr.version)}`,`${g(n,"gatewayMode:")} ${y(n,r.gatewayMode)}`,`${g(n,"data dir:")} ${y(n,ct.dirname(q))}`,"",`${g(n,"gateway process:")} ${y(n,$l().replace(/^gateway process: /,""))}`,"",Ve(n),N(n,"whatsapp"),` ${g(n,"in use:")} ${l?y(n,"yes"):we(n,"no (gatewayMode is telegram-only)")}`),l){let f=c?y(n,`linked (${q})`):we(n,"missing \u2014 run omnish link");p.push(` ${g(n,"session:")} ${f}`),c&&d&&p.push(` ${g(n,"linked as:")} ${y(n,d)}`),c&&!d&&p.push(` ${g(n,"linked as:")} ${K(n,"(not in creds yet \u2014 try again after omnish link completes)")}`)}if(p.push(` ${W(n,"Allowed")}`),r.allowFrom.length===0)p.push(` ${K(n,"(none)")}`);else for(let f of r.allowFrom)p.push(` ${g(n,"whatsapp:")} ${y(n,f)}`);if(p.push("",Ve(n),N(n,"telegram")),p.push(` ${g(n,"in use:")} ${u?y(n,"yes"):we(n,"no (gatewayMode is whatsapp-only)")}`),u){let f=i?y(n,vl(i)):we(n,"(none) \u2014 omnish link --tg <token> or TELEGRAM_BOT_TOKEN");p.push(` ${g(n,"bot token:")} ${f}`)}if(p.push(` ${W(n,"Allowed")}`),r.telegramAllowFrom.length===0)p.push(` ${K(n,"(none)")}`);else for(let f of r.telegramAllowFrom)p.push(` ${g(n,"telegram:")} ${y(n,f)}`);if(p.push("",Ve(n),`${N(n,"jobs")} ${g(n,`(recent): ${o.length} total, ${s} running`)}`,Dr(a,n)),console.log(p.join(`
213
- `)),r.clusterEnabled){let f=fe(),w=H(),M=Object.keys(w.senderBindings).length,C=Object.keys(r.clusterSenderBindings??{}).length;console.log(""),console.log(Ve(n)),console.log(N(n,"cluster")),console.log(` ${g(n,"\xB7")} ${y(n,`enabled \xB7 label ${r.clusterLabel||Ps.hostname()} \xB7 bindings ${M} chat / ${C} default`)}`),console.log(` ${g(n,"node:")} ${y(n,`${f.slice(0,8)}\u2026`)}`)}return}case"commands":{let n=process.stdout,r=x();console.log(Br(Ze(r),n)),console.log(""),console.log(Ve(n)),console.log(y(n,"Keys editable from chat via /config set (same trust as shell):")),console.log(g(n,zt.join(", "))),console.log(`${g(n,"See also:")} ${y(n,v)}`);return}case"cluster":{let n=process.stdout,r=process.stderr,o=(t[0]??"status").toLowerCase();if(o==="status"){let s=x(),i=fe();if(console.log(`${g(n,"clusterEnabled:")} ${y(n,String(s.clusterEnabled))}`),console.log(`${g(n,"clusterLabel:")} ${y(n,s.clusterLabel||"(hostname)")}`),console.log(`${g(n,"clusterRole:")} ${y(n,`${s.clusterRole} (informational; no longer used to gate traffic)`)}`),console.log(`${g(n,"node id:")} ${N(n,i)}`),s.clusterEnabled){let a=H(),l=Jn(s,null);console.log(""),console.log(y(n,l.wa.replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1"))),console.log(""),console.log(zn(a,s,null));let u=Object.keys(a.senderBindings).length,c=Object.entries(s.clusterSenderBindings??{});if(u>0){console.log(""),console.log(N(n,"Chat bindings (cluster-local.json)"));for(let[d,p]of Object.entries(a.senderBindings))console.log(` ${g(n,d)} ${K(n,"->")} ${y(n,`${p.nodeId} (${p.source}, since ${p.sinceIso})`)}`)}if(c.length>0){console.log(""),console.log(N(n,"Config defaults (clusterSenderBindings)"));for(let[d,p]of c)console.log(` ${g(n,d)} ${K(n,"->")} ${y(n,p)}`)}}else console.log(""),console.log(we(n,"(cluster disabled \u2014 /config set clusterEnabled true to enable, then /c use <label-or-id> from each sender)"));return}if(o==="use"||o==="bind"){let s=t[1],i=t.slice(2).join(" ").trim();if(!s||!i){console.error(k(r,"Usage: omnish cluster use <senderE164|tg:id> <label-or-id>")),process.exitCode=1;return}let a=Ml(s);if(!a){console.error(k(r,`Could not parse sender "${s}". Use +E164 (WhatsApp) or tg:<user_id> (Telegram).`)),process.exitCode=1;return}let{state:l,resolved:u}=Yo(a,i);if(!u.ok){if(u.reason==="ambiguous-label"){let d=(u.matches??[]).map(p=>`${p.nodeId}(${p.label})`).join(", ");console.error(k(r,`Label "${i}" matches multiple machines: ${d}. Use the 8-character id.`))}else console.error(k(r,`No machine matches "${i}". Run /c status from the chat first to populate the roster, or pass an 8-character node id.`));process.exitCode=1;return}console.log(`${N(n,"cluster:")} ${y(n,`${a} -> ${u.peer.nodeId} (${u.peer.label}).`)}`);let c=x();console.log(""),console.log(zn(l,c,a));return}if(o==="here"){console.error(k(r,"omnish cluster here is no longer available. Use: omnish cluster use <senderE164|tg:id> <label-or-id>")),console.error(k(r,"Or send /c here from the controller's chat on the machine you want to bind.")),process.exitCode=1;return}console.error(k(r,"Usage: omnish cluster [status | use <sender> <label-or-id>]")),process.exitCode=1;return}case"security":{let n=x(),r=Qe(n),o=t.includes("--json");console.log(o?jr(r):Bt(r,process.stdout)),yn(r)&&(process.exitCode=1);return}case"service":{Rl(t);return}default:pr(),e&&(process.exitCode=1)}}Tl().catch(e=>{console.error(k(process.stderr,String(e))),process.exit(1)});
216
+ `)}`),o}}import vc from"node:crypto";import Br from"node:fs";import $c from"node:net";var Ft=null;function Cc(){try{let e=Br.readFileSync(Ve,"utf8"),t=JSON.parse(e);return typeof t.token=="string"?t.token:""}catch{return""}}function Rc(e){Br.writeFileSync(Ve,JSON.stringify(e,null,2)+`
217
+ `,{mode:384})}function Mc(){try{Br.unlinkSync(Ve)}catch{}}async function Tc(e,t,n){let r;try{r=JSON.parse(e)}catch{return{ok:!1,error:"Invalid JSON."}}if(!r||typeof r!="object"||r.op!=="sendMedia")return{ok:!1,error:"Unsupported operation."};if(typeof r.token!="string"||!n||r.token!==n)return{ok:!1,error:"Unauthorized."};let o=t.getCfg(),s=typeof r.absPath=="string"?r.absPath.trim():"";if(!s)return{ok:!1,error:"Missing absPath."};let i=typeof r.caption=="string"&&r.caption.length>0?r.caption:void 0,a=et(s,o.fileSendMaxBytes);if("error"in a)return{ok:!1,error:a.error};let l={absPath:a.absPath,category:a.category,mimetype:a.mimetype,displayName:a.displayName,caption:i};if(r.channel==="whatsapp"){let d=t.getWaOutbound();if(!d)return{ok:!1,error:"WhatsApp outbound is not connected."};let c=o.gatewayMode;if(c!=="whatsapp"&&c!=="both")return{ok:!1,error:"gatewayMode does not include WhatsApp."};let u=typeof r.e164=="string"?r.e164.trim():"";if(!u.startsWith("+"))return{ok:!1,error:"WhatsApp destination must be E.164 (e.g. +15551234567)."};let m=Dt(u);try{return await d.sendMedia(m,l),{ok:!0}}catch(f){return{ok:!1,error:String(f)}}}if(r.channel==="telegram"){let d=t.getTgSendMedia();if(!d)return{ok:!1,error:"Telegram outbound is not connected."};let c=o.gatewayMode;if(c!=="telegram"&&c!=="both")return{ok:!1,error:"gatewayMode does not include Telegram."};if(!Number.isFinite(r.chatId))return{ok:!1,error:"Invalid Telegram chat id."};try{return await d(r.chatId,l),{ok:!0}}catch(u){return{ok:!1,error:String(u)}}}return{ok:!1,error:"Unknown channel."}}function Ai(e){if(Ft)return;let t=vc.randomBytes(32).toString("hex"),n=$c.createServer(r=>{let o="";r.setTimeout(12e4),r.on("data",s=>{o+=s.toString("utf8");let i=o.indexOf(`
218
+ `);if(i===-1)return;let a=o.slice(0,i).trim();o=o.slice(i+1);let l=Cc();Tc(a,e,l).then(d=>{r.write(`${JSON.stringify(d)}
219
+ `),r.end()})}),r.on("error",()=>{})});n.listen(0,"127.0.0.1",()=>{let r=n.address();if(!r||typeof r=="string"){M.error("gateway control: could not read listen address");return}let o={token:t,host:r.address,port:r.port};Rc(o),M.info({port:r.port},"gateway control listening")}),n.on("error",r=>{M.error({err:String(r)},"gateway control server error")}),Ft=n}function An(){if(Ft){try{Ft.close()}catch{}Ft=null,Mc()}}import Oc from"node:readline";import jr from"node:path";import ae from"node:process";import Ic from"node:net";import Ac from"node:fs";function Ec(){try{let e=Ac.readFileSync(Ve,"utf8"),t=JSON.parse(e);return typeof t.host!="string"||typeof t.port!="number"||typeof t.token!="string"||!Number.isFinite(t.port)?null:{host:t.host,port:t.port,token:t.token}}catch{return null}}async function Dr(e){let t=Ec();if(!t)return"No gateway control endpoint \u2014 is `omnish run` active? (control metadata missing.)";let n={...e,token:t.token},r=`${JSON.stringify(n)}
220
+ `;return new Promise(o=>{let s=!1,i="";function a(d){s||(s=!0,o(d))}let l=Ic.connect({host:t.host,port:t.port},()=>{l.write(r)});l.setTimeout(6e5),l.on("data",d=>{i+=d.toString("utf8");let c=i.indexOf(`
221
+ `);if(c>=0){let u=i.slice(0,c).trim();try{let m=JSON.parse(u);m.ok?a(null):a(m.error||"Unknown error from gateway control.")}catch{a("Invalid response from gateway control.")}l.destroy()}}),l.on("error",d=>{a(`Control connection failed: ${String(d)}`)}),l.on("timeout",()=>{l.destroy(),a("Gateway control timed out.")}),l.on("close",()=>{!s&&i.trim()===""&&a("Gateway closed the control connection without a response.")})})}function Ei(e){let t=e.trim();if(!/^\/sendto(\s|$)/i.test(t))return null;let n=t.replace(/^\/sendto\s+/i,"").trim();if(!n)return null;let r=n.indexOf(" ");if(r===-1)return null;let o=n.slice(0,r).trim(),s=n.slice(r+1).trim();if(!s)return null;let i=s.indexOf(" -- "),a,l;if(i>=0?(a=s.slice(0,i).trim(),l=s.slice(i+4).trim()||void 0):a=s,(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),!a)return null;let d=o.toLowerCase();if(d.startsWith("tg:")||d.startsWith("telegram:")){let c=de(o);if(!c)return null;let u=Number(c);return Number.isFinite(u)?{channel:"telegram",chatId:u,filePart:a,caption:l}:null}if(d.startsWith("wa:")){let c=_(o.slice(3));return c?{channel:"whatsapp",e164:c,filePart:a,caption:l}:null}if(o.startsWith("+")){let c=_(o);return c?{channel:"whatsapp",e164:c,filePart:a,caption:l}:null}return null}function Hr(){return["/sendto wa:+E164 <file> [-- caption]","/sendto tg:<chat_id> <file> [-- caption]","Also: /sendto +E164 <file> (WhatsApp). Requires `omnish run` on this machine."].join(`
222
+ `)}var ht="wa:cli:interactive";function Lc(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let s=de(t);return s?`tg:${s}`:null}let r=n.startsWith("wa:")?t.slice(3):t,o=_(r);return o?`wa:${o}`:null}function Pc(e){let t=null,n=null;for(let r=0;r<e.length;){let o=e[r]??"";if(o==="--as"){let s=e[r+1];if(!s||s.startsWith("-"))return{opts:{senderKey:null,oneShot:null},error:"--as requires a sender (wa:+E164 or tg:<id>)."};let i=Lc(s);if(!i)return{opts:{senderKey:null,oneShot:null},error:`Could not parse sender "${s}". Use +E164, wa:+E164, or tg:<user_id>.`};t=i,r+=2;continue}if(o==="-c"||o==="--command"){let s=e[r+1];if(typeof s!="string")return{opts:{senderKey:null,oneShot:null},error:`${o} requires a command string.`};n=s,r+=2;continue}return o==="--help"||o==="-h"?{opts:{senderKey:null,oneShot:null},error:"help"}:{opts:{senderKey:null,oneShot:null},error:`Unknown argument: ${o}`}}return{opts:{senderKey:t,oneShot:n},error:null}}function Wr(e){let t=ae.cwd(),n=[`${U(e,"omnish i")} ${h(e,"[options]")}`,re(e,"Interactive shell \u2014 same commands as WhatsApp/Telegram chat."),"",Y(e,"Usage:"),` ${b(e,"omnish i [options]")}`,` ${b(e,"omnish interactive [options]")}`,"",Y(e,"Options:"),...Fe(e," ",[{left:"--as <sender>",right:"Sender key for cluster commands (wa:+E164 or tg:id). Default: synthetic wa:cli:interactive."},{left:"-c, --command <line>",right:"Run one line and exit (non-interactive)."},{left:"-h, --help",right:"Show this help."}],r=>h(e,r)),"",`${h(e,"Trust:")} ${b(e,"Full local access like your shell; not gated by inbox allowlist.")}`,`${h(e,"Jobs:")} ${b(e,"/bg and /jobs apply only to this REPL session (not the gateway process).")}`,`${h(e,"Files:")} ${b(e,"Use /sendto to push a host file through the gateway; plain /send needs a chat peer.")}`,`${h(e,"Gateway:")} ${b(e,"/reload and /updates require omnish run; /sendto requires omnish run for WA/TG delivery.")}`,"",Hr(),"",`${h(e,"cwd:")} ${b(e,`session starts at ${t} (change with !cd or ${$().commandPrefix}cd).`)}`];console.log(n.join(`
223
+ `))}async function Fc(e){let t=$(),n=H(ht).cwd,r=jr.resolve(n,e.filePart),o=et(r,t.fileSendMaxBytes);return"error"in o?o.error:e.channel==="whatsapp"?await Dr({op:"sendMedia",channel:"whatsapp",e164:e.e164,absPath:o.absPath,caption:e.caption}):await Dr({op:"sendMedia",channel:"telegram",chatId:e.chatId,absPath:o.absPath,caption:e.caption})}async function Nc(e,t,n,r,o,s,i){let a=e.trim();if(!a)return;let l=Ei(a);if(l!==null||/^\/sendto(\s|$)/i.test(a)){if(l===null){console.log(R(ae.stderr,`Invalid /sendto.
224
+ `+Hr()));return}let u=await Fc(l);console.log(u?R(ae.stderr,u):se(ae.stdout,"Sent."));return}let d={peerKey:ht,text:e},c=await Je($(),t,n,r,o,d,s,void 0,i);c!==null&&await _c(c)}async function _c(e){if(e===null)return;if(e.kind==="file"){console.log(se(ae.stdout,["This CLI session has no chat peer to attach to.","Push through the gateway instead, for example:"," /sendto wa:+15551234567 ./my.pdf"," /sendto tg:123456789 ~/photo.jpg -- optional caption","(Requires `omnish run` on this machine.)"].join(`
225
+ `)));return}let t=Re(e.body,"whatsapp").text;t.trim()&&console.log(t)}async function Oi(e){let t=Pc(e);if(t.error==="help"){Wr(ae.stdout);return}if(t.error&&t.error!==null){console.error(R(ae.stderr,t.error)),console.error(h(ae.stderr,"Try: omnish i --help")),ae.exitCode=1;return}let{senderKey:n,oneShot:r}=t.opts,o=n??ht;Q(),qt(ht,ae.cwd());let s=new Ke,i=new Map,a=new Map,l=new Map,d=new pt(()=>$(),async(f,y)=>{ae.stdout.write(y),y.endsWith(`
226
+ `)||ae.stdout.write(`
227
+ `)}),c=async f=>{try{await Nc(f,s,i,a,l,d,o)}catch(y){console.error(R(ae.stderr,String(y)))}};if(r!==null){await c(r),d.dispose(),s.killAllRunning();return}let u=Oc.createInterface({input:ae.stdin,output:ae.stdout}),m=jr.basename(H(ht).cwd);u.setPrompt(`${m}> `),u.on("line",f=>{c(f).then(()=>{let y=jr.basename(H(ht).cwd);u.setPrompt(`${y}> `),u.prompt()})}),u.on("close",()=>{d.dispose(),s.killAllRunning(),ae.stdout.write(`
228
+ `)}),u.prompt()}Bc.setDefaultResultOrder("ipv4first");function Fi(){let e=process.stdout,t=[`${oe(e,"omnish run")} ${h(e,"[options]")}`,re(e,"Listen for DMs and run shell commands from allowlisted chats."),"",Y(e,"Usage:"),` ${b(e,"omnish run [options]")}`,"",Y(e,"Options:"),...Fe(e," ",[{left:"-d, --background",right:"Start the gateway detached; log to --log-file (default: <data>/logs/gateway.log)."},{left:"--log-file <path>",right:`Append stdout/stderr when background (default: ${we}).`},{left:"-h, --help",right:"Show this help."}],n=>h(e,n)),"",`${b(e,"Config reload:")} ${h(e,"while the gateway runs, edit config then send /reload or /restart from an allowlisted chat (no restart needed for many keys). /updates checks npm (and optional updateInfoUrl).")}`,""];console.log(t.join(`
229
+ `))}function Ni(){let e=process.stdout,t=[{left:"omnish link [--force]",right:"WhatsApp: scan QR (Linked devices). --force wipes session first."},{left:"omnish link --tg <bot_token>",right:"Telegram: save token to config; gatewayMode telegram or both if WhatsApp is linked."}],n=t.map(i=>h(e,i.left)),r=Math.max(...n.map(Vt)),o=t.map((i,a)=>Dn(" ",r,n[a],b(e,i.right))),s=[`${oe(e,"omnish link")} ${h(e,"[options]")}`,re(e,"Connect WhatsApp (QR) or save a Telegram bot token."),"",Y(e,"Usage:"),` ${b(e,"omnish link [--force]")}`,` ${b(e,"omnish link --tg <bot_token>")}`,"",Y(e,"Modes:"),...o,` ${re(e,"Do not combine --tg with --force.")}`,"",Y(e,"Options:"),...Fe(e," ",[{left:"-f, --force",right:"WhatsApp only: delete saved session before pairing."},{left:"-h, --help",right:"Show this help."}],i=>h(e,i)),"",`${b(e,"Next:")} ${U(e,"omnish allow tg:<your_user_id>")} ${h(e,"then")} ${U(e,"omnish run")}`,`${h(e,"Config:")} ${b(e,T)}`,""];console.log(s.join(`
230
+ `))}function jc(e){let t=!1,n=null;for(let r=0;r<e.length;r++){let o=e[r]??"";if(o==="--help"||o==="-h")return{kind:"help"};if(o==="--force"||o==="-f"){t=!0;continue}if(o==="--tg"||o==="--telegram"){let s=e[r+1];if(!s||s.startsWith("-"))return{kind:"error",message:"[omnish] --tg requires a bot token (from @BotFather)."};n=s,r++;continue}if(o.startsWith("--tg=")||o.startsWith("--telegram=")){let s=o.indexOf("="),i=o.slice(s+1).trim();if(!i)return{kind:"error",message:"[omnish] --tg= requires a non-empty bot token."};n=i;continue}return{kind:"error",message:`[omnish] unknown link argument: ${o}
231
+ Try: omnish link --help`}}return n!==null?t?{kind:"error",message:"[omnish] --force applies to WhatsApp only; do not combine with --tg."}:{kind:"tg",token:n}:{kind:"wa",force:t}}function Ur(){let e=process.stdout,t=`${oe(e,"omnish")} ${h(e,`v${De()}`)}`,n=[{left:"link [--force] [--tg <token>]",right:"WhatsApp (QR) or Telegram bot token \u2014 omnish link --help"},{left:"run [options]",right:"Listen for DMs (WhatsApp and/or Telegram \u2014 see gatewayMode in config)"},{left:"stop",right:`Stop background gateway (pidfile: ${te})`},{left:"service <subcommand>",right:"Boot install hints, logs, systemd/LaunchAgent \u2014 omnish service help"},{left:"logout",right:"Delete saved WhatsApp session"},{left:"allow +<E164> | tg:<id>",right:"Add allowlist entry"},{left:"deny +<E164> | tg:<id>",right:"Remove allowlist entry"},{left:"status [--check-updates]",right:"Channels, identity, allowlists, jobs, security, cluster (if enabled)"},{left:"commands",right:"Chat commands for allowlisted users (same as /help)"},{left:"security [--json]",right:"Configuration security report (JSON for scripts)"},{left:"cluster [status | use <sender> <label-or-id>]",right:"Per-sender machine bindings"},{left:"i | interactive [options]",right:"Local REPL (chat commands; /sendto needs omnish run)"}],r=[{left:"-v, --version",right:"Print version and exit."},{left:"-h, --help",right:"Show this help (same as omnish help)."}],o=[t,re(e,"Allowlisted inbox \u2192 your real shell. No AI."),"",Y(e,"Usage:"),` ${b(e,"omnish [options] <command> [args...]")}`,"",Y(e,"Options:"),...Fe(e," ",r,s=>h(e,s)),"",Y(e,"Commands:"),...Fe(e," ",n,s=>h(e,s)),"",`${h(e,"Config:")} ${b(e,`${T} \u2014 gatewayMode: "whatsapp" | "telegram" | "both"`)}`,`${h(e,"Env:")} ${b(e,"OMNISH_VERBOSE=1 (Baileys; legacy WHATSVERBOSE=1 still works), TELEGRAM_BOT_TOKEN (optional)")}`,`${h(e,"Data:")} ${b(e,"~/.omnish by default; ~/.whatslive reused if it already exists. OMNISH_HOME overrides.")}`,`${h(e,"See also:")} ${b(e,"https://omnish.dev")}`,""];console.log(o.join(`
232
+ `))}function Wc(e){let t=(e??"").trim().toLowerCase(),n=process.stdout;if(!t){Ur();return}switch(t){case"link":Ni();return;case"run":Fi();return;case"service":Bi();return;case"i":case"interactive":Wr(n);return;default:console.error(R(process.stderr,`No detailed help for "${e}". Try: omnish help`)),process.exitCode=1}}function Uc(e){let t=!1,n="",r=!1;for(let s=0;s<e.length;s++){let i=e[s]??"";if(i==="-d"||i==="--background")t=!0;else if(i==="--log-file"||i==="--log"){let a=e[++s];a||(console.error(R(process.stderr,"--log-file requires a path.")),process.exit(1)),n=a}else if(i==="--help"||i==="-h")r=!0;else{let a=process.stderr;console.error(R(a,`unknown run option: ${i}`)),console.error(R(a,"Try: omnish run --help")),process.exit(1)}}let o=n.trim()!==""?En.isAbsolute(n)?n:En.resolve(process.cwd(),n):we;return{background:t,logFile:o,help:r}}function Gc(e){Q(),L(En.dirname(e));let t=process.argv[1];t||(console.error(R(process.stderr,"cannot resolve entry script; invoke via node path/to/dist/index.js.")),process.exit(1));let n=ge.openSync(e,"a"),r=Dc(process.execPath,[t,"run"],{detached:!0,stdio:["ignore",n,n],env:{...process.env,OMNISH_BACKGROUND_GATEWAY:"1"}});ge.closeSync(n),r.unref(),r.pid||(console.error(R(process.stderr,"failed to start background gateway.")),process.exit(1));let o=process.stdout;console.log(`${se(o,`gateway started in background (pid ${r.pid}).`)} ${h(o,`Log: ${e}`)}`)}function zc(){if(Q(),!ge.existsSync(te)){console.error(R(process.stderr,`no pidfile at ${te} \u2014 is a background gateway running?`)),process.exitCode=1;return}let e=ge.readFileSync(te,"utf8").trim(),t=Number(e);if(!Number.isFinite(t)||t<=0){console.error(R(process.stderr,"invalid pidfile."));try{ge.unlinkSync(te)}catch{}process.exitCode=1;return}try{process.kill(t,0)}catch{console.log(se(process.stdout,`process ${t} is not running; removing stale pidfile.`));try{ge.unlinkSync(te)}catch{}return}try{process.kill(t,"SIGTERM"),console.log(se(process.stdout,`sent SIGTERM to gateway (pid ${t}).`))}catch(n){if(process.platform==="win32"&&Hc("taskkill",["/PID",String(t),"/T"],{windowsHide:!0}).status===0){console.log(se(process.stdout,`stopped gateway (pid ${t}) using taskkill.`));return}console.error(R(process.stderr,`could not signal process: ${String(n)}`)),process.exitCode=1}}function Li(){if(process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{ge.readFileSync(te,"utf8").trim()===String(process.pid)&&ge.unlinkSync(te)}catch{}}function Jc(e){return e.length<=8?"(set)":`${e.slice(0,4)}\u2026${e.slice(-4)}`}function Kc(){if(!ge.existsSync(te))return"gateway process: not running (no pid file)";let e=ge.readFileSync(te,"utf8").trim(),t=Number(e);if(!Number.isFinite(t)||t<=0)return"gateway process: invalid pid file";try{return process.kill(t,0),`gateway process: running (pid ${t})`}catch{return`gateway process: not running (stale pid ${t} in pid file)`}}var _i=120;function Bi(){let e=process.stdout,t=[{left:"help",right:"This help."},{left:"instructions",right:"Copy-paste install steps for this machine."},{left:"status",right:"Data dir, pidfile, Node + entry script."},{left:"logs [n]",right:`Tail default gateway log (default 80 lines, max ${_i}).`},{left:"install",right:"Write user systemd / LaunchAgent unit (needs serviceInstallFromChat=true)."},{left:"uninstall",right:"Remove that unit (same gate as install)."}],n=[`${oe(e,"omnish service")} ${h(e,"<subcommand>")}`,re(e,"Boot integration, crash restart policy, and logs (same ideas as /service in chat)."),"",Y(e,"Usage:"),` ${b(e,"omnish service <subcommand>")}`,"",Y(e,"Subcommands:"),...Fe(e," ",t,r=>h(e,r)),"",Y(e,"Restart and reload:"),` ${b(e,"Process")} ${h(e,"\u2014 Linux user unit: Restart=on-failure, RestartSec=5. macOS: KeepAlive. Full restart loads config from disk.")}`,` ${b(e,"Config live")} ${h(e,"\u2014 allowlisted chat while gateway runs: /reload or /restart")}`,"",`${h(e,"Docs:")} ${b(e,"docs/guides/background-and-boot.md")} ${re(e,"\xB7")} https://omnish.dev`,""];console.log(n.join(`
233
+ `))}function qc(e){let t=process.stdout,n=process.stderr,r=(e[0]??"help").toLowerCase();if(r==="help"||r==="--help"||r==="-h"){Bi();return}if(r==="instructions"){let o=ze();if(o.error){console.error(R(n,o.error)),process.exitCode=1;return}console.log(dn(o));return}if(r==="status"){let o=ze(),s=(()=>{try{return ge.existsSync(te)?`gateway.pid: ${ge.readFileSync(te,"utf8").trim()}`:"gateway.pid: (missing)"}catch(u){return`gateway.pid: (read error: ${String(u)})`}})(),i=process.env.OMNISH_BACKGROUND_GATEWAY==="1"?"This process: background gateway (OMNISH_BACKGROUND_GATEWAY=1).":"This process: CLI (not the gateway \u2014 run omnish service status on the host where the gateway runs for live pid info).",a=typeof process.env.OMNISH_HOME=="string"&&process.env.OMNISH_HOME.trim()?`OMNISH_HOME env: ${process.env.OMNISH_HOME.trim()}`:"OMNISH_HOME env: (not set \u2014 using default data dir)",l=o.error?o.error:`Node: ${o.nodePath}
234
+ Script: ${o.scriptPath}`,c=$().serviceInstallFromChat?"Install from CLI/chat: enabled (omnish service install / /service install).":"Install from CLI/chat: off \u2014 set serviceInstallFromChat true in config (same trust as shell).";console.log(oe(t,"omnish service status")),console.log(""),console.log(`${h(t,"platform:")} ${b(t,process.platform)}`),console.log(`${h(t,"session:")} ${b(t,i)}`),console.log(`${h(t,"env:")} ${b(t,a)}`),console.log(`${h(t,"data dir:")} ${b(t,A)}`),console.log(`${h(t,"pidfile:")} ${b(t,s)}`),console.log(`${h(t,"default log:")} ${b(t,we)}`),console.log(""),console.log(l),console.log(""),console.log(b(t,c));return}if(r==="logs"){let o=e.length>=2?Number.parseInt(e[1],10):80,s=Number.isFinite(o)&&o>0?Math.min(o,_i):80,i=gn(we,s);console.log(`${h(t,"file:")} ${b(t,we)}`),console.log(`${h(t,"lines:")} ${b(t,String(s))}`),console.log(""),console.log(i);return}if(r==="install"){if(!$().serviceInstallFromChat){console.error(R(n,"Install is disabled. Set serviceInstallFromChat to true in config (same trust as shell), then run again.")),process.exitCode=1;return}let s=pn();s.ok?console.log(se(t,s.detail)):(console.error(R(n,s.detail)),process.exitCode=1);return}if(r==="uninstall"){if(!$().serviceInstallFromChat){console.error(R(n,"Uninstall is disabled. Set serviceInstallFromChat to true in config or remove the unit file on the host manually.")),process.exitCode=1;return}let s=mn();s.ok?console.log(se(t,s.detail)):(console.error(R(n,s.detail)),process.exitCode=1);return}console.error(R(n,`Unknown subcommand "${r}". Try: omnish service help`)),process.exitCode=1}function Yc(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let s=de(t);return s?`tg:${s}`:null}let r=n.startsWith("wa:")?t.slice(3):t,o=_(r);return o?`wa:${o}`:null}async function Vc(){let e=null,t=$(),n=t.gatewayMode,r=n==="whatsapp"||n==="both",o=n==="telegram"||n==="both",s=pe(t);o&&!s&&(console.error(R(process.stderr,`Telegram enabled (gatewayMode) but no bot token. Set telegramBotToken in config or TELEGRAM_BOT_TOKEN.
235
+ config: ${T}`)),process.exit(1)),r&&!Ze()&&(console.error(R(process.stderr,"WhatsApp enabled but no session. Run `omnish link` first.")),process.exit(1));let i=rt(t),a=process.stderr;Wn(i)&&(console.error(en(i,a)),console.error(R(a,"Fix security errors above before starting the gateway (or change gatewayMode / token).")),process.exit(1));let l=yo(i,"warn");if(l.length>0&&(console.warn(`${se(a,`Security (${l.length} finding(s)):`)}
236
+ `),console.warn(en(l,a))),process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{ge.writeFileSync(te,`${process.pid}
237
+ `,{mode:384})}catch(C){M.warn({err:String(C)},"could not write gateway pidfile")}let d=(C,N)=>{let j=$();if(!j.clusterEnabled)return C;let g=be(),S=(j.clusterLabel??"").trim()||Pi.hostname(),v=null;if(N.startsWith("tg:"))v=N;else if(N){let ne=_(N);ne&&(v=`wa:${ne}`)}let K=v?Ae(j,v):null;return ps(C,{nodeId:g,label:S,role:j.clusterRole,activeNodeId:K?.nodeId??""})},c=new Ke,u=new Map,m=new Map,f=new Map,y=null,w={stop:null,sendText:null,sendMedia:null},k=null,E=!1,P=async(C,N)=>{if(C.startsWith("wa:")){let j=C.slice(3);y&&await y.sendText(j,N)}else if(C.startsWith("tg:")){let j=Number(C.slice(3));w.sendText&&Number.isFinite(j)&&await w.sendText(j,p(N))}},D=()=>new pt(()=>$(),P),W=D();k=W;let V,F={async reload(){try{M.info("gateway reload requested from chat"),await w.stop?.().catch(()=>{}),w.stop=null,w.sendText=null,w.sendMedia=null;let C=$(),N=C.gatewayMode==="telegram"||C.gatewayMode==="both",j=pe(C);if(N&&j){let v=await _r(j,()=>$(),V,{decorate:d});w.sendText=v.sendText,w.sendMedia=v.sendMedia,w.stop=v.stop}let g=["Reload complete.",`gatewayMode: ${C.gatewayMode}`,N&&j?"Telegram bot is running with the current token.":"Telegram bot is stopped (enable telegram/both + token if you want it).","Allowlists, shell, app session limits, and timeouts are read from disk on each command."].join(`
238
+ `),S=hn(Rt());return{ok:!0,summary:S?`${g}
239
+
240
+ Updates (last check): ${S}`:g}}catch(C){return{ok:!1,error:String(C)}}}};if(V=async(C,N)=>{let j=$(),g=eo(j.telegramAllowFrom),S=C.peerKey.startsWith("tg:")?C.peerKey.slice(3):"";if(!S||!g.has(S)){M.warn({denied:C.peerKey,uid:S},"telegram denied");return}try{let v=C.peerKey;if(!Mr(j,C.text,v))return;if(C.mediaError&&await N({kind:"text",body:p(C.mediaError)}),C.mediaSavedPath&&await N({kind:"text",body:p(`Saved: ${C.mediaSavedPath}`)}),C.text.trim()){let K=await Je(j,c,u,m,f,C,W,F,v);K!==null&&await N(K)}}catch(v){M.error({err:String(v)},"telegram handler error"),await N({kind:"text",body:p(`Error: ${String(v)}`)}).catch(()=>{})}},o){let C=await _r(s,()=>$(),V,{decorate:d});w.sendText=C.sendText,w.sendMedia=C.sendMedia,w.stop=C.stop}Ai({getCfg:()=>$(),getWaOutbound:()=>y,getTgSendMedia:()=>w.sendMedia}),e=Ds({getRunningVersion:De,getConfig:$,log:M});let ue=ci({getConfig:$,sendToPeer:P}),X=!o,$e=()=>{E=!0,ue(),e?.(),e=null,Li(),An(),w.stop?.().catch(()=>{}),k?.dispose(),c.killAllRunning(),console.error(`
241
+ ${R(process.stderr,"shutting down\u2026")}`),process.exit(0)};if(process.on("SIGINT",$e),process.on("SIGTERM",$e),r)for(;!E;){let C=!1,N;try{N=await Cn({printQr:!1,verbose:wn()}),await Ye(Mn(N),3e5,"Gateway: timed out waiting for WhatsApp connection (5 min).")}catch(g){console.error(R(process.stderr,`connect failed: ${String(g)}`)),await new Promise(S=>setTimeout(S,5e3));continue}y=Ci(N,{decorate:d});let j=bi(N,async g=>{let S=$(),v=Zr(S.allowFrom),K=g.fromE164||_(g.fromJid)||"";if(!K||!v.has(K)){M.warn({denied:g.fromJid,phone:K},"denied");return}try{let ne=ti(g),Me=`wa:${K}`;if(!Mr(S,ne.text,Me))return;if(g.mediaError&&await y.sendText(g.fromJid,g.mediaError),g.mediaSavedPath&&await y.sendText(g.fromJid,`Saved: ${g.mediaSavedPath}`),g.text.trim()){let yt=await Je(S,c,u,m,f,ne,W,F,Me);yt!==null&&(yt.kind==="file"?await y.sendMedia(g.fromJid,yt.spec):await y.sendText(g.fromJid,Re(yt.body,"whatsapp").text))}}catch(ne){M.error({err:String(ne)},"handler error"),await y.sendText(g.fromJid,Re(p(`Error: ${String(ne)}`),"whatsapp").text).catch(()=>{})}});if(await new Promise(g=>{let S=v=>{v.connection==="close"&&(Pr(v.lastDisconnect)===qe.loggedOut&&(C=!0),N.ev.off("connection.update",S),g())};N.ev.on("connection.update",S)}),j(),X&&(W.dispose(),W=D(),k=W),Rn(N),y=null,C&&(console.error(R(process.stderr,"session logged out. Run `omnish link` again.")),ue(),e?.(),e=null,Li(),An(),w.stop?.().catch(()=>{}),process.exit(1)),E)break;await new Promise(g=>setTimeout(g,3e3))}else for(;!E;)await new Promise(C=>setTimeout(C,500));ue(),e?.(),An(),w.stop?.().catch(()=>{}),W.dispose()}async function Xc(){let[,,e,...t]=process.argv;if(e==="--version"||e==="-v"||e==="-V"){let n=process.stdout;console.log(`${oe(n,"omnish")} ${h(n,De())}`);return}if(e==="--help"||e==="-h"){Ur();return}if(e==="help"){Wc(t[0]);return}switch(Q(),e){case"link":{let n=jc(t);if(n.kind==="help"){Ni();return}if(n.kind==="error"){let r=process.stderr,o=n.message.replace(/^\[omnish\]\s*/,"");console.error(R(r,o)),process.exitCode=1;return}if(n.kind==="tg"){let r=n.token.trim(),o=process.stderr,s=process.stdout;if(!Xe(r)){console.error(R(o,"That does not look like a Telegram bot token (expect digits:secret from @BotFather).")),process.exitCode=1;return}Qe(r);let i=Ze()?"both":"telegram";zt(i),console.log([`${U(s,"Telegram")} ${b(s,"bot token saved to")} ${h(s,T)}`,`${h(s,"gatewayMode:")} ${U(s,i)}`,"",b(s,"Next:"),` ${h(s,"1.")} ${b(s,"Find your numeric user id (e.g. t.me/userinfobot), then:")} ${U(s,"omnish allow tg:<id>")}`,` ${h(s,"2.")} ${U(s,"omnish run")}`,""].join(`
242
+ `));return}await Ii({verbose:wn(),force:n.force});return}case"run":{let n=Uc(t);if(n.help){Fi();return}if(n.background){Gc(n.logFile);return}await Vc();return}case"stop":zc();return;case"logout":{try{ge.rmSync(ee,{recursive:!0,force:!0}),console.log(se(process.stdout,"Session removed. Run `omnish link` to pair again."))}catch(n){console.error(R(process.stderr,`logout failed: ${String(n)}`)),process.exitCode=1}return}case"allow":{let n=t[0],r=process.stdout,o=process.stderr;if(!n){console.error(R(o,"Usage: omnish allow +<E164> or omnish allow tg:<user_id>")),process.exitCode=1;return}try{let s=Wt(n);console.log(`${h(r,"allowFrom:")} ${b(r,s.allowFrom.join(", ")||"(empty)")}`),console.log(`${h(r,"telegramAllowFrom:")} ${b(r,s.telegramAllowFrom.join(", ")||"(empty)")}`)}catch(s){console.error(R(o,String(s).replace(/^\[omnish\]\s*/,""))),process.exitCode=1}return}case"deny":{let n=t[0],r=process.stdout,o=process.stderr;if(!n){console.error(R(o,"Usage: omnish deny +<E164> or omnish deny tg:<user_id>")),process.exitCode=1;return}try{let s=Ut(n);console.log(`${h(r,"allowFrom:")} ${b(r,s.allowFrom.join(", ")||"(empty)")}`),console.log(`${h(r,"telegramAllowFrom:")} ${b(r,s.telegramAllowFrom.join(", ")||"(empty)")}`)}catch(s){console.error(R(o,String(s).replace(/^\[omnish\]\s*/,""))),process.exitCode=1}return}case"i":case"interactive":{await Oi(t);return}case"status":{let n=process.stdout,r=$(),o=t.includes("--check-updates"),s=new Ke().list(),i=s.filter(y=>y.status==="running").length,a=pe(r),l=rt(r),d=r.gatewayMode==="whatsapp"||r.gatewayMode==="both",c=r.gatewayMode==="telegram"||r.gatewayMode==="both",u=Ze(),m=u?Mi(ee):null,f=[];if(f.push(`${oe(n,"omnish")} ${h(n,De())}`,`${h(n,"gatewayMode:")} ${b(n,r.gatewayMode)}`,`${h(n,"data dir:")} ${b(n,En.dirname(ee))}`,"",`${h(n,"gateway process:")} ${b(n,Kc().replace(/^gateway process: /,""))}`,"",Ge(n),U(n,"whatsapp"),` ${h(n,"in use:")} ${d?b(n,"yes"):Se(n,"no (gatewayMode is telegram-only)")}`),d){let y=u?b(n,`linked (${ee})`):Se(n,"missing \u2014 run omnish link");f.push(` ${h(n,"session:")} ${y}`),u&&m&&f.push(` ${h(n,"linked as:")} ${b(n,m)}`),u&&!m&&f.push(` ${h(n,"linked as:")} ${re(n,"(not in creds yet \u2014 try again after omnish link completes)")}`)}if(f.push(` ${Y(n,"Allowed")}`),r.allowFrom.length===0)f.push(` ${re(n,"(none)")}`);else for(let y of r.allowFrom)f.push(` ${h(n,"whatsapp:")} ${b(n,y)}`);if(f.push("",Ge(n),U(n,"telegram")),f.push(` ${h(n,"in use:")} ${c?b(n,"yes"):Se(n,"no (gatewayMode is whatsapp-only)")}`),c){let y=a?b(n,Jc(a)):Se(n,"(none) \u2014 omnish link --tg <token> or TELEGRAM_BOT_TOKEN");f.push(` ${h(n,"bot token:")} ${y}`)}if(f.push(` ${Y(n,"Allowed")}`),r.telegramAllowFrom.length===0)f.push(` ${re(n,"(none)")}`);else for(let y of r.telegramAllowFrom)f.push(` ${h(n,"telegram:")} ${b(n,y)}`);if(f.push("",Ge(n),`${U(n,"jobs")} ${h(n,`(recent): ${s.length} total, ${i} running`)}`,ko(l,n)),console.log(f.join(`
243
+ `)),o){let y=await Mt(De(),r),w=kt(y);console.log(""),console.log(Ge(n)),console.log(Re(w,"whatsapp").text)}if(r.clusterEnabled){let y=be(),w=G(),k=Object.keys(w.senderBindings).length,E=Object.keys(r.clusterSenderBindings??{}).length;console.log(""),console.log(Ge(n)),console.log(U(n,"cluster")),console.log(` ${h(n,"\xB7")} ${b(n,`enabled \xB7 label ${r.clusterLabel||Pi.hostname()} \xB7 bindings ${k} chat / ${E} default`)}`),console.log(` ${h(n,"node:")} ${b(n,`${y.slice(0,8)}\u2026`)}`)}return}case"commands":{let n=process.stdout,r=$();console.log(fo(ot(r),n)),console.log(""),console.log(Ge(n)),console.log(b(n,"Keys editable from chat via /config set (same trust as shell):")),console.log(h(n,un.join(", "))),console.log(`${h(n,"See also:")} ${b(n,T)}`);return}case"cluster":{let n=process.stdout,r=process.stderr,o=(t[0]??"status").toLowerCase();if(o==="status"){let s=$(),i=be();if(console.log(`${h(n,"clusterEnabled:")} ${b(n,String(s.clusterEnabled))}`),console.log(`${h(n,"clusterLabel:")} ${b(n,s.clusterLabel||"(hostname)")}`),console.log(`${h(n,"clusterRole:")} ${b(n,`${s.clusterRole} (informational; no longer used to gate traffic)`)}`),console.log(`${h(n,"node id:")} ${U(n,i)}`),s.clusterEnabled){let a=G(),l=yr(s,null);console.log(""),console.log(b(n,l.wa.replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1"))),console.log(""),console.log(hr(a,s,null));let d=Object.keys(a.senderBindings).length,c=Object.entries(s.clusterSenderBindings??{});if(d>0){console.log(""),console.log(U(n,"Chat bindings (cluster-local.json)"));for(let[u,m]of Object.entries(a.senderBindings))console.log(` ${h(n,u)} ${re(n,"->")} ${b(n,`${m.nodeId} (${m.source}, since ${m.sinceIso})`)}`)}if(c.length>0){console.log(""),console.log(U(n,"Config defaults (clusterSenderBindings)"));for(let[u,m]of c)console.log(` ${h(n,u)} ${re(n,"->")} ${b(n,m)}`)}}else console.log(""),console.log(Se(n,"(cluster disabled \u2014 /config set clusterEnabled true to enable, then /c use <label-or-id> from each sender)"));return}if(o==="use"||o==="bind"){let s=t[1],i=t.slice(2).join(" ").trim();if(!s||!i){console.error(R(r,"Usage: omnish cluster use <senderE164|tg:id> <label-or-id>")),process.exitCode=1;return}let a=Yc(s);if(!a){console.error(R(r,`Could not parse sender "${s}". Use +E164 (WhatsApp) or tg:<user_id> (Telegram).`)),process.exitCode=1;return}let{state:l,resolved:d}=Cs(a,i);if(!d.ok){if(d.reason==="ambiguous-label"){let u=(d.matches??[]).map(m=>`${m.nodeId}(${m.label})`).join(", ");console.error(R(r,`Label "${i}" matches multiple machines: ${u}. Use the 8-character id.`))}else console.error(R(r,`No machine matches "${i}". Run /c status from the chat first to populate the roster, or pass an 8-character node id.`));process.exitCode=1;return}console.log(`${U(n,"cluster:")} ${b(n,`${a} -> ${d.peer.nodeId} (${d.peer.label}).`)}`);let c=$();console.log(""),console.log(hr(l,c,a));return}if(o==="here"){console.error(R(r,"omnish cluster here is no longer available. Use: omnish cluster use <senderE164|tg:id> <label-or-id>")),console.error(R(r,"Or send /c here from the controller's chat on the machine you want to bind.")),process.exitCode=1;return}console.error(R(r,"Usage: omnish cluster [status | use <sender> <label-or-id>]")),process.exitCode=1;return}case"security":{let n=$(),r=rt(n),o=t.includes("--json");console.log(o?wo(r):en(r,process.stdout)),Wn(r)&&(process.exitCode=1);return}case"service":{qc(t);return}default:Ur(),e&&(process.exitCode=1)}}Xc().catch(e=>{console.error(R(process.stderr,String(e))),process.exit(1)});