omnish 1.4.0 → 1.4.2
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/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/dist/index.js +191 -191
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var xm=Object.defineProperty;var Zn=(e,t)=>()=>(e&&(t=e(e=0)),t);var $m=(e,t)=>{for(var n in t)xm(e,n,{get:t[n],enumerable:!0})};import Rm from"node:crypto";import _s from"node:fs";import Cm from"node:os";import re from"node:path";function Mm(){let e=process.env.OMNISH_HOME?.trim();if(e)return re.resolve(e);let t=Cm.homedir(),n=re.join(t,".omnish"),r=re.join(t,".whatslive");try{if(_s.existsSync(n))return n;if(_s.existsSync(r))return r}catch{}return n}function nr(e){let t=Rm.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return re.join(qa,t)}function j(e){_s.mkdirSync(e,{recursive:!0,mode:448})}function te(){j(H),j(ne),j(tt),j(qa),j(Ya),j(ut),j(bt)}var H,ne,tt,qa,Ya,Ne,le,hn,er,ct,_r,Fr,_,Wr,Ur,Dr,ut,Fs,Ws,Qa,bt,tr,Hr,G=Zn(()=>{"use strict";H=Mm(),ne=re.join(H,"auth"),tt=re.join(H,"jobs"),qa=re.join(H,"apps"),Ya=re.join(H,"logs"),Ne=re.join(Ya,"gateway.log"),le=re.join(H,"gateway.pid"),hn=re.join(H,"gateway-control.json"),er=re.join(H,"config-ui.json"),ct=re.join(H,"ui.json"),_r=re.join(H,"tunnel-auth.json"),Fr=re.join(H,"ui-server.json"),_=re.join(H,"config.json"),Wr=re.join(H,"shortcuts.json"),Ur=re.join(H,"recipes.json"),Dr=re.join(H,"recipes-user.json"),ut=re.join(H,"cowork"),Fs=re.join(ut,"tasks.json"),Ws=re.join(ut,"pending-runs.json"),Qa=re.join(ut,"completions.sqlite"),bt=re.join(H,"watch"),tr=re.join(bt,"rules.json"),Hr=re.join(bt,"events.sqlite")});function tl(e){let t=e.trim();for(;;){let n=t;if(t=t.replace(/^whatsapp:/i,"").trim(),t===n)return t}}function Tm(e){let t=tl(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 Em(e){let t=e.match(Xa);if(t)return t[1]??null;let n=e.match(Za);if(n)return n[1]??null;let r=e.match(el);return r?r[1]??null:null}function Va(e){let t=e.replace(/\D/g,"");return t?`+${t}`:""}function It(e){return`${e.replace(/\D/g,"")}@s.whatsapp.net`}function ee(e){let t=tl(e);if(!t||Tm(t))return null;if(Xa.test(t)||Za.test(t)||el.test(t)){let r=Em(t);if(!r)return null;let o=Va(r);return o.length>1?o:null}if(t.includes("@"))return null;let n=Va(t);return n.length>1?n:null}function Br(e){return e.map(t=>String(t).trim()).filter(t=>!!t).map(t=>t==="*"?t:ee(t)).filter(t=>!!t)}function jr(e){let t=new Set;for(let n of e){if(n==="*")continue;let r=ee(String(n));r&&t.add(r)}return t}function Ee(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 Gr(e){let t=new Set;for(let n of e){let r=Ee(String(n));r&&t.add(r)}return t}function Us(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let o=Ee(t);return o?{kind:"tg",id:o}:null}let r=ee(t);return r?{kind:"wa",normalized:r}:null}function nl(e,t){let n=ee(t);return n?e.has(n):!1}var Xa,Za,el,qe=Zn(()=>{"use strict";Xa=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,Za=/^(\d+)@c\.us$/i,el=/^(\d+)@lid$/i});import Jr from"node:fs";function Pm(e){return e==="downloads"||e==="omnishData"||e==="sessionCwd"||e==="processCwd"||e==="fixed"?e:N.fileReceiveRootMode}function Am(e){return e==="primary"?"primary":"secondary"}function Im(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=ee(s.slice(3));l&&(t[`wa:${l}`]=o.slice(0,64));continue}if(i.startsWith("tg:")||i.startsWith("telegram:")){let l=Ee(s);l&&(t[`tg:${l}`]=o.slice(0,64));continue}let a=ee(s);a&&(t[`wa:${a}`]=o.slice(0,64))}return t}function rr(e){let t=typeof e.appsFlushMs=="number"&&e.appsFlushMs>=0?e.appsFlushMs:N.appsFlushMs,n=e.gatewayMode==="telegram"||e.gatewayMode==="both"||e.gatewayMode==="whatsapp"?e.gatewayMode:N.gatewayMode,r=typeof e.telegramBotToken=="string"?e.telegramBotToken:N.telegramBotToken,o=Array.isArray(e.telegramAllowFrom)?[...new Set(e.telegramAllowFrom.map(s=>Ee(String(s))).filter(s=>!!s))].sort():N.telegramAllowFrom;return{...N,...e,gatewayMode:n,telegramBotToken:r,telegramAllowFrom:o,allowFrom:Array.isArray(e.allowFrom)?Br(e.allowFrom.map(String)).filter(s=>s!=="*"):N.allowFrom,commandPrefix:(()=>{let s=typeof e.commandPrefix=="string"&&e.commandPrefix.length>0?e.commandPrefix:N.commandPrefix;return s==="! "?"!":s})(),syncTimeoutMs:typeof e.syncTimeoutMs=="number"&&e.syncTimeoutMs>0?e.syncTimeoutMs:N.syncTimeoutMs,syncMaxBytes:typeof e.syncMaxBytes=="number"&&e.syncMaxBytes>0?e.syncMaxBytes:N.syncMaxBytes,jobLogTailLines:typeof e.jobLogTailLines=="number"&&e.jobLogTailLines>0?e.jobLogTailLines:N.jobLogTailLines,shell:typeof e.shell=="string"&&e.shell.length>0?e.shell:N.shell,appsCols:typeof e.appsCols=="number"&&e.appsCols>0&&e.appsCols<=500?Math.floor(e.appsCols):N.appsCols,appsRows:typeof e.appsRows=="number"&&e.appsRows>0&&e.appsRows<=200?Math.floor(e.appsRows):N.appsRows,appsFlushMs:t,appsMinIntervalMs:typeof e.appsMinIntervalMs=="number"&&e.appsMinIntervalMs>=0?e.appsMinIntervalMs:N.appsMinIntervalMs,appsMaxFlushBytes:typeof e.appsMaxFlushBytes=="number"&&e.appsMaxFlushBytes>256?Math.floor(e.appsMaxFlushBytes):N.appsMaxFlushBytes,appsMaxSessions:typeof e.appsMaxSessions=="number"&&e.appsMaxSessions>0?Math.min(50,Math.floor(e.appsMaxSessions)):N.appsMaxSessions,appsMaxSessionsTotal:typeof e.appsMaxSessionsTotal=="number"&&e.appsMaxSessionsTotal>0?Math.min(200,Math.floor(e.appsMaxSessionsTotal)):N.appsMaxSessionsTotal,appsMaxWaChars:typeof e.appsMaxWaChars=="number"&&e.appsMaxWaChars>256?Math.floor(e.appsMaxWaChars):N.appsMaxWaChars,appsLogTailLines:typeof e.appsLogTailLines=="number"&&e.appsLogTailLines>0?Math.min(500,Math.floor(e.appsLogTailLines)):N.appsLogTailLines,appsSubmitDelayMs:typeof e.appsSubmitDelayMs=="number"&&e.appsSubmitDelayMs>=0?Math.min(500,Math.floor(e.appsSubmitDelayMs)):N.appsSubmitDelayMs,appsClearInput:typeof e.appsClearInput=="boolean"?e.appsClearInput:N.appsClearInput,appsClearInputDelayMs:typeof e.appsClearInputDelayMs=="number"&&e.appsClearInputDelayMs>=0?Math.min(200,Math.floor(e.appsClearInputDelayMs)):N.appsClearInputDelayMs,appsClearInputSequence:typeof e.appsClearInputSequence=="string"&&e.appsClearInputSequence.length>0?e.appsClearInputSequence.slice(0,200):N.appsClearInputSequence,appsSkipClearOnPasswordPrompt:typeof e.appsSkipClearOnPasswordPrompt=="boolean"?e.appsSkipClearOnPasswordPrompt:N.appsSkipClearOnPasswordPrompt,appsPasswordPromptHint:typeof e.appsPasswordPromptHint=="boolean"?e.appsPasswordPromptHint:N.appsPasswordPromptHint,fileSendMaxBytes:typeof e.fileSendMaxBytes=="number"&&e.fileSendMaxBytes>=0?e.fileSendMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileSendMaxBytes)):N.fileSendMaxBytes,fileReceiveMaxBytes:typeof e.fileReceiveMaxBytes=="number"&&e.fileReceiveMaxBytes>=0?e.fileReceiveMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileReceiveMaxBytes)):N.fileReceiveMaxBytes,fileInboxSubdir:typeof e.fileInboxSubdir=="string"&&e.fileInboxSubdir.length>0&&e.fileInboxSubdir.replace(/[/\\]/g,"").slice(0,80)||N.fileInboxSubdir,fileReceiveRootMode:Pm(e.fileReceiveRootMode),fileReceiveRootPath:typeof e.fileReceiveRootPath=="string"?e.fileReceiveRootPath.trim().slice(0,4096):N.fileReceiveRootPath,recipesAllowDangerousBuiltins:typeof e.recipesAllowDangerousBuiltins=="boolean"?e.recipesAllowDangerousBuiltins:N.recipesAllowDangerousBuiltins,recipesMaxTaskChars:typeof e.recipesMaxTaskChars=="number"&&e.recipesMaxTaskChars>=0?e.recipesMaxTaskChars===0?0:Math.min(Number.MAX_SAFE_INTEGER,Math.floor(e.recipesMaxTaskChars)):N.recipesMaxTaskChars,recipesMacroDefaultCommand:typeof e.recipesMacroDefaultCommand=="string"&&e.recipesMacroDefaultCommand.trim().length>0?e.recipesMacroDefaultCommand.trim().slice(0,4096):N.recipesMacroDefaultCommand,clusterEnabled:typeof e.clusterEnabled=="boolean"?e.clusterEnabled:N.clusterEnabled,clusterLabel:typeof e.clusterLabel=="string"?e.clusterLabel.trim().slice(0,128):N.clusterLabel,clusterRole:Am(e.clusterRole),clusterSenderBindings:Im(e.clusterSenderBindings),serviceInstallFromChat:typeof e.serviceInstallFromChat=="boolean"?e.serviceInstallFromChat:N.serviceInstallFromChat,updateCheckEnabled:typeof e.updateCheckEnabled=="boolean"?e.updateCheckEnabled:N.updateCheckEnabled,updateCheckIntervalMs:typeof e.updateCheckIntervalMs=="number"&&e.updateCheckIntervalMs>0?Math.min(6048e5,Math.max(36e5,Math.floor(e.updateCheckIntervalMs))):N.updateCheckIntervalMs,updateCheckPackageName:typeof e.updateCheckPackageName=="string"&&e.updateCheckPackageName.trim().length>0?e.updateCheckPackageName.trim().slice(0,214):N.updateCheckPackageName,updateInfoUrl:typeof e.updateInfoUrl=="string"?e.updateInfoUrl.trim().slice(0,2048):N.updateInfoUrl,chatLlmFallbackEnabled:typeof e.chatLlmFallbackEnabled=="boolean"?e.chatLlmFallbackEnabled:N.chatLlmFallbackEnabled,chatLlmShellCommand:typeof e.chatLlmShellCommand=="string"?e.chatLlmShellCommand.trim().slice(0,8192):N.chatLlmShellCommand,chatLlmTimeoutMs:typeof e.chatLlmTimeoutMs=="number"&&e.chatLlmTimeoutMs>0?Math.min(9e5,Math.floor(e.chatLlmTimeoutMs)):N.chatLlmTimeoutMs,chatLlmMaxInputChars:typeof e.chatLlmMaxInputChars=="number"&&e.chatLlmMaxInputChars>0?Math.min(5e5,Math.floor(e.chatLlmMaxInputChars)):N.chatLlmMaxInputChars,chatLlmMaxOutputChars:typeof e.chatLlmMaxOutputChars=="number"&&e.chatLlmMaxOutputChars>0?Math.min(2e6,Math.floor(e.chatLlmMaxOutputChars)):N.chatLlmMaxOutputChars,chatLlmNeedsTty:typeof e.chatLlmNeedsTty=="boolean"?e.chatLlmNeedsTty:N.chatLlmNeedsTty,chatLlmWorkDir:typeof e.chatLlmWorkDir=="string"?e.chatLlmWorkDir.trim().slice(0,4096):N.chatLlmWorkDir,tunnelEnabled:typeof e.tunnelEnabled=="boolean"?e.tunnelEnabled:N.tunnelEnabled,tunnelRelayUrl:typeof e.tunnelRelayUrl=="string"&&e.tunnelRelayUrl.trim().length>0?e.tunnelRelayUrl.trim().slice(0,2048):N.tunnelRelayUrl,tunnelMaxActive:typeof e.tunnelMaxActive=="number"&&e.tunnelMaxActive>0?Math.min(50,Math.floor(e.tunnelMaxActive)):N.tunnelMaxActive,platformToken:typeof e.platformToken=="string"?e.platformToken.trim():N.platformToken,platformDeviceId:typeof e.platformDeviceId=="string"?e.platformDeviceId.trim().slice(0,128):N.platformDeviceId,webhookEnabled:typeof e.webhookEnabled=="boolean"?e.webhookEnabled:N.webhookEnabled,webhookPort:typeof e.webhookPort=="number"&&e.webhookPort>=0?Math.min(65535,Math.floor(e.webhookPort)):N.webhookPort,webhookHost:typeof e.webhookHost=="string"&&e.webhookHost.trim().length>0?e.webhookHost.trim():N.webhookHost,webhookToken:typeof e.webhookToken=="string"?e.webhookToken.trim():N.webhookToken,watchEnabled:typeof e.watchEnabled=="boolean"?e.watchEnabled:N.watchEnabled,watchDebounceMs:typeof e.watchDebounceMs=="number"&&Number.isFinite(e.watchDebounceMs)?Math.max(500,Math.min(6e4,Math.floor(e.watchDebounceMs))):N.watchDebounceMs,watchMaxEventsPerMinute:typeof e.watchMaxEventsPerMinute=="number"&&Number.isFinite(e.watchMaxEventsPerMinute)?Math.max(1,Math.min(120,Math.floor(e.watchMaxEventsPerMinute))):N.watchMaxEventsPerMinute,watchAutoRestore:typeof e.watchAutoRestore=="boolean"?e.watchAutoRestore:N.watchAutoRestore}}function W(e){let t=$(),n=rr({...t,...e});return _e(n),n}function $(){if(te(),!Jr.existsSync(_)){let e=rr({});return _e(e),e}try{let e=Jr.readFileSync(_,"utf8"),t=JSON.parse(e);return rr(t)}catch{return rr({})}}function _e(e){te();let t=rr(e);Jr.writeFileSync(_,JSON.stringify(t,null,2)+`
|
|
3
|
-
`,{mode:384})}function
|
|
4
|
-
`,{mode:384}),
|
|
5
|
-
`,{mode:384})
|
|
2
|
+
var Am=Object.defineProperty;var Ot=(e,t)=>()=>(e&&(t=e(e=0)),t);var Im=(e,t)=>{for(var n in t)Am(e,n,{get:t[n],enumerable:!0})};import Om from"node:crypto";import Us from"node:fs";import Lm from"node:os";import re from"node:path";function Nm(){let e=process.env.OMNISH_HOME?.trim();if(e)return re.resolve(e);let t=Lm.homedir(),n=re.join(t,".omnish"),r=re.join(t,".whatslive");try{if(Us.existsSync(n))return n;if(Us.existsSync(r))return r}catch{}return n}function sr(e){let t=Om.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return re.join(tl,t)}function j(e){Us.mkdirSync(e,{recursive:!0,mode:448})}function te(){j(H),j(ne),j(tt),j(tl),j(nl),j(dt),j(kt)}var H,ne,tt,tl,nl,Ne,ce,kn,rr,ut,Dr,Hr,_,Br,jr,Gr,dt,Ds,Hs,rl,kt,or,Jr,G=Ot(()=>{"use strict";H=Nm(),ne=re.join(H,"auth"),tt=re.join(H,"jobs"),tl=re.join(H,"apps"),nl=re.join(H,"logs"),Ne=re.join(nl,"gateway.log"),ce=re.join(H,"gateway.pid"),kn=re.join(H,"gateway-control.json"),rr=re.join(H,"config-ui.json"),ut=re.join(H,"ui.json"),Dr=re.join(H,"tunnel-auth.json"),Hr=re.join(H,"ui-server.json"),_=re.join(H,"config.json"),Br=re.join(H,"shortcuts.json"),jr=re.join(H,"recipes.json"),Gr=re.join(H,"recipes-user.json"),dt=re.join(H,"cowork"),Ds=re.join(dt,"tasks.json"),Hs=re.join(dt,"pending-runs.json"),rl=re.join(dt,"completions.sqlite"),kt=re.join(H,"watch"),or=re.join(kt,"rules.json"),Jr=re.join(kt,"events.sqlite")});function ll(e){let t=e.trim();for(;;){let n=t;if(t=t.replace(/^whatsapp:/i,"").trim(),t===n)return t}}function _m(e){let t=ll(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 Fm(e){let t=e.match(sl);if(t)return t[1]??null;let n=e.match(il);if(n)return n[1]??null;let r=e.match(al);return r?r[1]??null:null}function ol(e){let t=e.replace(/\D/g,"");return t?`+${t}`:""}function Lt(e){return`${e.replace(/\D/g,"")}@s.whatsapp.net`}function ee(e){let t=ll(e);if(!t||_m(t))return null;if(sl.test(t)||il.test(t)||al.test(t)){let r=Fm(t);if(!r)return null;let o=ol(r);return o.length>1?o:null}if(t.includes("@"))return null;let n=ol(t);return n.length>1?n:null}function Kr(e){return e.map(t=>String(t).trim()).filter(t=>!!t).map(t=>t==="*"?t:ee(t)).filter(t=>!!t)}function zr(e){let t=new Set;for(let n of e){if(n==="*")continue;let r=ee(String(n));r&&t.add(r)}return t}function Ee(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 qr(e){let t=new Set;for(let n of e){let r=Ee(String(n));r&&t.add(r)}return t}function Bs(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let o=Ee(t);return o?{kind:"tg",id:o}:null}let r=ee(t);return r?{kind:"wa",normalized:r}:null}function cl(e,t){let n=ee(t);return n?e.has(n):!1}var sl,il,al,qe=Ot(()=>{"use strict";sl=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,il=/^(\d+)@c\.us$/i,al=/^(\d+)@lid$/i});import Yr from"node:fs";function Wm(e){return e==="downloads"||e==="omnishData"||e==="sessionCwd"||e==="processCwd"||e==="fixed"?e:N.fileReceiveRootMode}function Um(e){return e==="primary"?"primary":"secondary"}function Dm(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=ee(s.slice(3));l&&(t[`wa:${l}`]=o.slice(0,64));continue}if(i.startsWith("tg:")||i.startsWith("telegram:")){let l=Ee(s);l&&(t[`tg:${l}`]=o.slice(0,64));continue}let a=ee(s);a&&(t[`wa:${a}`]=o.slice(0,64))}return t}function ir(e){let t=typeof e.appsFlushMs=="number"&&e.appsFlushMs>=0?e.appsFlushMs:N.appsFlushMs,n=e.gatewayMode==="telegram"||e.gatewayMode==="both"||e.gatewayMode==="whatsapp"?e.gatewayMode:N.gatewayMode,r=typeof e.telegramBotToken=="string"?e.telegramBotToken:N.telegramBotToken,o=Array.isArray(e.telegramAllowFrom)?[...new Set(e.telegramAllowFrom.map(s=>Ee(String(s))).filter(s=>!!s))].sort():N.telegramAllowFrom;return{...N,...e,gatewayMode:n,telegramBotToken:r,telegramAllowFrom:o,allowFrom:Array.isArray(e.allowFrom)?Kr(e.allowFrom.map(String)).filter(s=>s!=="*"):N.allowFrom,commandPrefix:(()=>{let s=typeof e.commandPrefix=="string"&&e.commandPrefix.length>0?e.commandPrefix:N.commandPrefix;return s==="! "?"!":s})(),syncTimeoutMs:typeof e.syncTimeoutMs=="number"&&e.syncTimeoutMs>0?e.syncTimeoutMs:N.syncTimeoutMs,syncMaxBytes:typeof e.syncMaxBytes=="number"&&e.syncMaxBytes>0?e.syncMaxBytes:N.syncMaxBytes,jobLogTailLines:typeof e.jobLogTailLines=="number"&&e.jobLogTailLines>0?e.jobLogTailLines:N.jobLogTailLines,shell:typeof e.shell=="string"&&e.shell.length>0?e.shell:N.shell,appsCols:typeof e.appsCols=="number"&&e.appsCols>0&&e.appsCols<=500?Math.floor(e.appsCols):N.appsCols,appsRows:typeof e.appsRows=="number"&&e.appsRows>0&&e.appsRows<=200?Math.floor(e.appsRows):N.appsRows,appsFlushMs:t,appsMinIntervalMs:typeof e.appsMinIntervalMs=="number"&&e.appsMinIntervalMs>=0?e.appsMinIntervalMs:N.appsMinIntervalMs,appsMaxFlushBytes:typeof e.appsMaxFlushBytes=="number"&&e.appsMaxFlushBytes>256?Math.floor(e.appsMaxFlushBytes):N.appsMaxFlushBytes,appsMaxSessions:typeof e.appsMaxSessions=="number"&&e.appsMaxSessions>0?Math.min(50,Math.floor(e.appsMaxSessions)):N.appsMaxSessions,appsMaxSessionsTotal:typeof e.appsMaxSessionsTotal=="number"&&e.appsMaxSessionsTotal>0?Math.min(200,Math.floor(e.appsMaxSessionsTotal)):N.appsMaxSessionsTotal,appsMaxWaChars:typeof e.appsMaxWaChars=="number"&&e.appsMaxWaChars>256?Math.floor(e.appsMaxWaChars):N.appsMaxWaChars,appsLogTailLines:typeof e.appsLogTailLines=="number"&&e.appsLogTailLines>0?Math.min(500,Math.floor(e.appsLogTailLines)):N.appsLogTailLines,appsSubmitDelayMs:typeof e.appsSubmitDelayMs=="number"&&e.appsSubmitDelayMs>=0?Math.min(500,Math.floor(e.appsSubmitDelayMs)):N.appsSubmitDelayMs,appsClearInput:typeof e.appsClearInput=="boolean"?e.appsClearInput:N.appsClearInput,appsClearInputDelayMs:typeof e.appsClearInputDelayMs=="number"&&e.appsClearInputDelayMs>=0?Math.min(200,Math.floor(e.appsClearInputDelayMs)):N.appsClearInputDelayMs,appsClearInputSequence:typeof e.appsClearInputSequence=="string"&&e.appsClearInputSequence.length>0?e.appsClearInputSequence.slice(0,200):N.appsClearInputSequence,appsSkipClearOnPasswordPrompt:typeof e.appsSkipClearOnPasswordPrompt=="boolean"?e.appsSkipClearOnPasswordPrompt:N.appsSkipClearOnPasswordPrompt,appsPasswordPromptHint:typeof e.appsPasswordPromptHint=="boolean"?e.appsPasswordPromptHint:N.appsPasswordPromptHint,fileSendMaxBytes:typeof e.fileSendMaxBytes=="number"&&e.fileSendMaxBytes>=0?e.fileSendMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileSendMaxBytes)):N.fileSendMaxBytes,fileReceiveMaxBytes:typeof e.fileReceiveMaxBytes=="number"&&e.fileReceiveMaxBytes>=0?e.fileReceiveMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileReceiveMaxBytes)):N.fileReceiveMaxBytes,fileInboxSubdir:typeof e.fileInboxSubdir=="string"&&e.fileInboxSubdir.length>0&&e.fileInboxSubdir.replace(/[/\\]/g,"").slice(0,80)||N.fileInboxSubdir,fileReceiveRootMode:Wm(e.fileReceiveRootMode),fileReceiveRootPath:typeof e.fileReceiveRootPath=="string"?e.fileReceiveRootPath.trim().slice(0,4096):N.fileReceiveRootPath,recipesAllowDangerousBuiltins:typeof e.recipesAllowDangerousBuiltins=="boolean"?e.recipesAllowDangerousBuiltins:N.recipesAllowDangerousBuiltins,recipesMaxTaskChars:typeof e.recipesMaxTaskChars=="number"&&e.recipesMaxTaskChars>=0?e.recipesMaxTaskChars===0?0:Math.min(Number.MAX_SAFE_INTEGER,Math.floor(e.recipesMaxTaskChars)):N.recipesMaxTaskChars,recipesMacroDefaultCommand:typeof e.recipesMacroDefaultCommand=="string"&&e.recipesMacroDefaultCommand.trim().length>0?e.recipesMacroDefaultCommand.trim().slice(0,4096):N.recipesMacroDefaultCommand,clusterEnabled:typeof e.clusterEnabled=="boolean"?e.clusterEnabled:N.clusterEnabled,clusterLabel:typeof e.clusterLabel=="string"?e.clusterLabel.trim().slice(0,128):N.clusterLabel,clusterRole:Um(e.clusterRole),clusterSenderBindings:Dm(e.clusterSenderBindings),serviceInstallFromChat:typeof e.serviceInstallFromChat=="boolean"?e.serviceInstallFromChat:N.serviceInstallFromChat,updateCheckEnabled:typeof e.updateCheckEnabled=="boolean"?e.updateCheckEnabled:N.updateCheckEnabled,updateCheckIntervalMs:typeof e.updateCheckIntervalMs=="number"&&e.updateCheckIntervalMs>0?Math.min(6048e5,Math.max(36e5,Math.floor(e.updateCheckIntervalMs))):N.updateCheckIntervalMs,updateCheckPackageName:typeof e.updateCheckPackageName=="string"&&e.updateCheckPackageName.trim().length>0?e.updateCheckPackageName.trim().slice(0,214):N.updateCheckPackageName,updateInfoUrl:typeof e.updateInfoUrl=="string"?e.updateInfoUrl.trim().slice(0,2048):N.updateInfoUrl,chatLlmFallbackEnabled:typeof e.chatLlmFallbackEnabled=="boolean"?e.chatLlmFallbackEnabled:N.chatLlmFallbackEnabled,chatLlmShellCommand:typeof e.chatLlmShellCommand=="string"?e.chatLlmShellCommand.trim().slice(0,8192):N.chatLlmShellCommand,chatLlmTimeoutMs:typeof e.chatLlmTimeoutMs=="number"&&e.chatLlmTimeoutMs>0?Math.min(9e5,Math.floor(e.chatLlmTimeoutMs)):N.chatLlmTimeoutMs,chatLlmMaxInputChars:typeof e.chatLlmMaxInputChars=="number"&&e.chatLlmMaxInputChars>0?Math.min(5e5,Math.floor(e.chatLlmMaxInputChars)):N.chatLlmMaxInputChars,chatLlmMaxOutputChars:typeof e.chatLlmMaxOutputChars=="number"&&e.chatLlmMaxOutputChars>0?Math.min(2e6,Math.floor(e.chatLlmMaxOutputChars)):N.chatLlmMaxOutputChars,chatLlmNeedsTty:typeof e.chatLlmNeedsTty=="boolean"?e.chatLlmNeedsTty:N.chatLlmNeedsTty,chatLlmWorkDir:typeof e.chatLlmWorkDir=="string"?e.chatLlmWorkDir.trim().slice(0,4096):N.chatLlmWorkDir,tunnelEnabled:typeof e.tunnelEnabled=="boolean"?e.tunnelEnabled:N.tunnelEnabled,tunnelRelayUrl:typeof e.tunnelRelayUrl=="string"&&e.tunnelRelayUrl.trim().length>0?e.tunnelRelayUrl.trim().slice(0,2048):N.tunnelRelayUrl,tunnelMaxActive:typeof e.tunnelMaxActive=="number"&&e.tunnelMaxActive>0?Math.min(50,Math.floor(e.tunnelMaxActive)):N.tunnelMaxActive,platformToken:typeof e.platformToken=="string"?e.platformToken.trim():N.platformToken,platformDeviceId:typeof e.platformDeviceId=="string"?e.platformDeviceId.trim().slice(0,128):N.platformDeviceId,webhookEnabled:typeof e.webhookEnabled=="boolean"?e.webhookEnabled:N.webhookEnabled,webhookPort:typeof e.webhookPort=="number"&&e.webhookPort>=0?Math.min(65535,Math.floor(e.webhookPort)):N.webhookPort,webhookHost:typeof e.webhookHost=="string"&&e.webhookHost.trim().length>0?e.webhookHost.trim():N.webhookHost,webhookToken:typeof e.webhookToken=="string"?e.webhookToken.trim():N.webhookToken,watchEnabled:typeof e.watchEnabled=="boolean"?e.watchEnabled:N.watchEnabled,watchDebounceMs:typeof e.watchDebounceMs=="number"&&Number.isFinite(e.watchDebounceMs)?Math.max(500,Math.min(6e4,Math.floor(e.watchDebounceMs))):N.watchDebounceMs,watchMaxEventsPerMinute:typeof e.watchMaxEventsPerMinute=="number"&&Number.isFinite(e.watchMaxEventsPerMinute)?Math.max(1,Math.min(120,Math.floor(e.watchMaxEventsPerMinute))):N.watchMaxEventsPerMinute,watchAutoRestore:typeof e.watchAutoRestore=="boolean"?e.watchAutoRestore:N.watchAutoRestore}}function W(e){let t=$(),n=ir({...t,...e});return _e(n),n}function $(){if(te(),!Yr.existsSync(_)){let e=ir({});return _e(e),e}try{let e=Yr.readFileSync(_,"utf8"),t=JSON.parse(e);return ir(t)}catch{return ir({})}}function _e(e){te();let t=ir(e);Yr.writeFileSync(_,JSON.stringify(t,null,2)+`
|
|
3
|
+
`,{mode:384})}function Qr(e){let t=Bs(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 _e(n),n}function Vr(e){let t=Bs(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=>Ee(r)!==t.id),_e(n),n}function ve(e){let t=typeof process.env.TELEGRAM_BOT_TOKEN=="string"?process.env.TELEGRAM_BOT_TOKEN.trim():"";return t||(e.telegramBotToken??"").trim()}function pt(e){let t=e.trim();return/^\d{6,}:[A-Za-z0-9_-]{20,}$/.test(t)}function Nt(e){let t=$();return t.telegramBotToken=e.trim(),_e(t),$()}function Sn(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 Xr(e){let t=$();return t.gatewayMode=e,_e(t),$()}function Zr(e){let t=$();return t.clusterEnabled=e,_e(t),$()}function nt(){try{return Yr.readdirSync(ne).length>0}catch{return!1}}var N,me=Ot(()=>{"use strict";G();qe();N={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",appsSkipClearOnPasswordPrompt:!0,appsPasswordPromptHint:!0,fileSendMaxBytes:0,fileReceiveMaxBytes:0,fileInboxSubdir:"inbox",fileReceiveRootMode:"downloads",fileReceiveRootPath:"",recipesAllowDangerousBuiltins:!1,recipesMaxTaskChars:0,recipesMacroDefaultCommand:'claude -p "$OMNISH_TASK"',clusterEnabled:!1,clusterLabel:"",clusterRole:"secondary",clusterSenderBindings:{},serviceInstallFromChat:!1,updateCheckEnabled:!1,updateCheckIntervalMs:864e5,updateCheckPackageName:"omnish",updateInfoUrl:"",chatLlmFallbackEnabled:!1,chatLlmShellCommand:"",chatLlmTimeoutMs:12e4,chatLlmMaxInputChars:16e3,chatLlmMaxOutputChars:24e3,chatLlmNeedsTty:!1,chatLlmWorkDir:"",tunnelEnabled:!1,tunnelRelayUrl:"https://tunnel.omnish.dev",platformToken:"",platformDeviceId:"",tunnelMaxActive:5,webhookEnabled:!1,webhookPort:0,webhookHost:"127.0.0.1",webhookToken:"",watchEnabled:!1,watchDebounceMs:2e3,watchMaxEventsPerMinute:30,watchAutoRestore:!0}});import Hm from"pino";function vn(){return process.env.OMNISH_VERBOSE==="1"||process.env.WHATSVERBOSE==="1"}function ul(){return vn()?"info":"silent"}function js(e){e?process.env.OMNISH_VERBOSE="1":delete process.env.OMNISH_VERBOSE,M.level=ul()}function dl(){return M.child({module:"baileys"})}var M,be=Ot(()=>{"use strict";M=Hm({level:ul(),base:{app:"omnish"}})});import ri from"node:fs";function $t(){try{let e=ri.readFileSync(Dr,"utf8"),t=JSON.parse(e);return!t||typeof t.token!="string"||!t.token.trim()?null:{token:t.token.trim(),relayUrl:typeof t.relayUrl=="string"?t.relayUrl.trim():void 0}}catch{return null}}function ht(e){te(),ri.writeFileSync(Dr,JSON.stringify({token:e.token.trim(),...e.relayUrl?{relayUrl:e.relayUrl.trim()}:{}},null,2)+`
|
|
4
|
+
`,{mode:384})}function mo(){try{ri.unlinkSync(Dr)}catch{}}function Df(){return process.env.OMNISH_TOKEN?.trim()||process.env.OMNISH_TUNNEL_TOKEN?.trim()||process.env.OMNISH_DEVICE_TOKEN?.trim()||""}function gt(){let e=Df();if(e)return e;let t=$().platformToken.trim();return t||($t()?.token??"")}function oi(e){let t=process.env.OMNISH_PLATFORM_URL?.trim()||process.env.OMNISH_COMM_LAYER_URL?.trim()||process.env.OMNISH_TUNNEL_RELAY?.trim();if(t)return t.replace(/\/$/,"");let n=$().tunnelRelayUrl.trim();if(n)return n.replace(/\/$/,"");let r=$t()?.relayUrl?.trim();return r?r.replace(/\/$/,""):e.replace(/\/$/,"")}function rt(e){return oi(e)}var rn=Ot(()=>{"use strict";me();G()});var $e,on=Ot(()=>{"use strict";$e="https://tunnel.omnish.dev"});function Vt(e){return(e??"").trim()}function Cy(){return Vt(process.env.OMNISH_PLATFORM_URL)||Vt(process.env.OMNISH_COMM_LAYER_URL)||Vt(process.env.OMNISH_TUNNEL_RELAY)}function My(){return Vt(process.env.OMNISH_TOKEN)||Vt(process.env.OMNISH_DEVICE_TOKEN)||Vt(process.env.OMNISH_TUNNEL_TOKEN)}function na(){return gt()}function zn(){return My()?"env":$().platformToken.trim()?"config":$t()?.token?"file":"default"}function Rr(){let e=$();return oi(e.tunnelRelayUrl||$e)}function qn(){return Cy()?"env":$().tunnelRelayUrl.trim()?"config":$t()?.relayUrl?.trim()?"file":"default"}function ra(){let e=Vt(process.env.OMNISH_DEVICE_ID);if(e)return e;let t=$().platformDeviceId.trim();if(t)return t}function oa(){return Vt(process.env.OMNISH_DEVICE_ID)?"env":$().platformDeviceId.trim()?"config":"default"}function se(){let e=Rr(),t=na();if(!e||!t)return null;let n=ra();return{platformUrl:e.replace(/\/$/,""),token:t,deviceId:n}}var it=Ot(()=>{"use strict";me();rn();on()});var vd={};Im(vd,{fetchPlatformAccount:()=>hn,getAttachedConfig:()=>la,getAttachedPlatformSnapshot:()=>Py,loadConfigForSendtoBroadcast:()=>ca,mergeAttachedPlatformPolicy:()=>aa,parsePlatformMeResponse:()=>kd,setAttachedPlatformSnapshot:()=>sa,setPlatformDefaultDevice:()=>ua,snapshotFromRegisteredAccount:()=>Sd,syncAttachedPlatformPolicy:()=>is,updatePlatformAllowlists:()=>ss});function ia(e){let t=e.replace(/\/$/,"");return/^https?:\/\//i.test(t)?t:`http://${t}`}function Ty(e){return e==="telegram"||e==="both"||e==="whatsapp"?e:"whatsapp"}function Ey(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,s=typeof o.status=="string"?o.status:"idle";t[n]={status:s,linked:o.linked===!0||s==="linked",...typeof o.tokenConfigured=="boolean"?{tokenConfigured:o.tokenConfigured}:{}}}return t}function kd(e){let t=e.routing,n=t&&typeof t=="object"?t:null,r=Array.isArray(n?.onlineDeviceIds)?n.onlineDeviceIds.map(String):[],o=n?.defaultDeviceId!=null?String(n.defaultDeviceId):e.defaultDeviceId!=null?String(e.defaultDeviceId):null;return{allowFrom:Array.isArray(e.allowFrom)?e.allowFrom.map(String):[],telegramAllowFrom:Array.isArray(e.telegramAllowFrom)?e.telegramAllowFrom.map(String):[],gatewayMode:Ty(e.gatewayMode),connectors:Ey(e.connectors),defaultDeviceId:o,routing:{defaultDeviceId:o,onlineDeviceIds:r,onlineCount:typeof n?.onlineCount=="number"?n.onlineCount:r.length}}}function Sd(e,t=[],n=[]){let r=e.defaultDeviceId??null;return{allowFrom:t,telegramAllowFrom:n,gatewayMode:e.gatewayMode,connectors:e.connectors,defaultDeviceId:r,routing:{defaultDeviceId:r,onlineDeviceIds:[],onlineCount:0}}}function aa(e,t){return{...e,allowFrom:[...t.allowFrom],telegramAllowFrom:[...t.telegramAllowFrom],gatewayMode:t.gatewayMode}}function sa(e){os=e}function Py(){return os}function la(){let e=$();return os?aa(e,os):e}async function ca(){let e=$(),t=se();if(!t)return e;try{return aa(e,await hn(t))}catch(n){return M.warn({err:String(n)},"sendto: could not fetch platform allowlists; using local config.json"),e}}async function hn(e){let t=await fetch(`${ia(e.platformUrl)}/v1/me`,{headers:{Authorization:`Bearer ${e.token}`}});if(!t.ok)throw new Error(`Platform GET /v1/me failed: HTTP ${t.status}`);let n=await t.json();return kd(n)}async function ss(e,t){let n=await fetch(`${ia(e.platformUrl)}/v1/me/allowlists`,{method:"PUT",headers:{"content-type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify(t)}),r=await n.json().catch(()=>({}));if(!n.ok)throw new Error(r.error||`Platform PUT /v1/me/allowlists failed: HTTP ${n.status}`);return{allowFrom:Array.isArray(r.allowFrom)?r.allowFrom.map(String):[],telegramAllowFrom:Array.isArray(r.telegramAllowFrom)?r.telegramAllowFrom.map(String):[]}}async function ua(e,t){let n=await fetch(`${ia(e.platformUrl)}/v1/me/default-device`,{method:"PUT",headers:{"content-type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({deviceId:t})});if(!n.ok){let r=await n.json().catch(()=>({}));throw new Error(r.error||`Platform PUT /v1/me/default-device failed: HTTP ${n.status}`)}}async function is(e,t){try{let n=await hn(e);return sa(n),M.info({gatewayMode:n.gatewayMode,waLinked:n.connectors.whatsapp?.linked===!0,tgLinked:n.connectors.telegram?.linked===!0,allowFromCount:n.allowFrom.length,telegramAllowFromCount:n.telegramAllowFrom.length},"attached platform policy loaded"),n}catch(n){if(t){let r=Sd(t);return sa(r),M.warn({err:String(n)},"platform GET /v1/me failed; using register ack for gatewayMode/connectors only (allowlists from local config until /v1/me works)"),r}return M.warn({err:String(n)},"platform GET /v1/me failed; attached inbound uses local config.json allowlists"),null}}var os,Cr=Ot(()=>{"use strict";me();be();it();os=null});me();import Xb from"node:dns";import Zb from"node:crypto";import en from"node:fs";import Za from"node:path";import $m from"node:os";me();be();import Tf from"node:os";import Ef from"node:fs";G();import pl from"node:crypto";import ar from"node:fs";import Gs from"node:os";import xn from"node:path";var Bm=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/;function Ks(e){let t=e.trim().toLowerCase();return Bm.test(t)?{ok:!0,name:t}:{ok:!1,error:"Name must be alphanumeric with _ or -, max 32 chars."}}function Ge(e,t){let n=e.trim();return n===""||n==="."?xn.resolve(t):n==="~"?Gs.homedir():n.startsWith("~/")||n.startsWith("~\\")?xn.join(Gs.homedir(),n.slice(2)):xn.isAbsolute(n)?n:xn.resolve(t,n)}function eo(e){return xn.join(Gs.homedir(),"Cowork",e)}function jm(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:eo(r),l=typeof t.enabled=="boolean"?t.enabled:!0,d=typeof t.notify=="string"?t.notify.toLowerCase():"self",u=d==="wa"||d==="whatsapp"?"wa":d==="tg"||d==="telegram"?"tg":d==="all"?"all":d==="none"?"none":"self",c={kind:"ondemand"};if(t.schedule&&typeof t.schedule=="object"){let v=t.schedule,E=typeof v.kind=="string"?v.kind:"";if(E==="ondemand")c={kind:"ondemand"};else if(E==="daily"){let R=Number(v.hour),P=Number(v.minute);Number.isFinite(R)&&Number.isFinite(P)&&(c={kind:"daily",hour:R,minute:P})}else if(E==="weekdays"){let R=Number(v.hour),P=Number(v.minute);Number.isFinite(R)&&Number.isFinite(P)&&(c={kind:"weekdays",hour:R,minute:P})}else if(E==="hourly"){let R=Number(v.minute);Number.isFinite(R)&&Number.isInteger(R)&&R>=0&&R<=59&&(c={kind:"hourly",minute:R})}else if(E==="weekly"){let R=Number(v.hour),P=Number(v.minute),T=Number(v.weekday);Number.isFinite(R)&&Number.isFinite(P)&&Number.isInteger(T)&&(c={kind:"weekly",weekday:T,hour:R,minute:P})}else if(E==="heartbeat"){let R=Number(v.intervalMs),P=Number(v.graceMs);Number.isFinite(R)&&R>0&&Number.isFinite(P)&&P>0&&(c={kind:"heartbeat",intervalMs:R,graceMs:P})}}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(),h=typeof t.attachLog=="boolean"?t.attachLog:!1,g=Array.isArray(t.attachFiles)?t.attachFiles.filter(v=>typeof v=="string"&&v.trim().length>0):[],y=typeof t.notifyWhen=="string"?t.notifyWhen.toLowerCase():"always";return{id:n,name:r,ownerPeerKey:o,command:s,cwd:i,outputDir:a,schedule:c,enabled:l,notify:u,notifyWhen:y==="failure"?"failure":y==="state-change"?"state-change":"always",attachLog:h,attachFiles:g,lastCompletedSlotMs:m,createdAtMs:f}}function xe(){try{let e=ar.readFileSync(Ds,"utf8"),t=JSON.parse(e);if(!t||!Array.isArray(t.tasks))return[];let n=[];for(let r of t.tasks){let o=jm(r);o&&n.push(o)}return n}catch{return[]}}function Oe(e){j(dt);let t={tasks:e},n=xn.join(dt,`.tasks.${process.pid}.${pl.randomBytes(4).toString("hex")}.tmp`);ar.writeFileSync(n,JSON.stringify(t,null,2)+`
|
|
5
|
+
`,{mode:384}),ar.renameSync(n,Ds)}function Ye(e,t,n){let r=t.trim().toLowerCase();return e.find(o=>o.name===r&&o.ownerPeerKey===n)}function lr(){return pl.randomBytes(4).toString("hex")}function ml(e){j(dt),ar.writeFileSync(Hs,JSON.stringify(e,null,2)+`
|
|
6
|
+
`,{mode:384})}function fl(e){let t=Js();t.push(e),ml(t)}function Js(){try{let e=ar.readFileSync(Hs,"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 hl(e){if(e<=0)return{batch:[],remainingAfter:Js().length};let t=Js();if(t.length===0)return{batch:[],remainingAfter:0};let n=t.slice(0,e),r=t.slice(e);return ml(r),{batch:n,remainingAfter:r.length}}G();G();import Gm from"better-sqlite3";var gl=1,yl=200,$n=null;function Jm(){j(kt);let e=new Gm(Jr);e.pragma("journal_mode = WAL"),e.exec(`
|
|
6
7
|
CREATE TABLE IF NOT EXISTS watch_meta (
|
|
7
8
|
key TEXT PRIMARY KEY,
|
|
8
9
|
value TEXT NOT NULL
|
|
@@ -21,31 +22,30 @@ var xm=Object.defineProperty;var Zn=(e,t)=>()=>(e&&(t=e(e=0)),t);var $m=(e,t)=>{
|
|
|
21
22
|
state_key TEXT NOT NULL,
|
|
22
23
|
updated_at_ms INTEGER NOT NULL
|
|
23
24
|
);
|
|
24
|
-
`);let t=e.prepare("SELECT value FROM watch_meta WHERE key = 'schema_version'").get();return(t?Number(t.value):0)<
|
|
25
|
+
`);let t=e.prepare("SELECT value FROM watch_meta WHERE key = 'schema_version'").get();return(t?Number(t.value):0)<gl&&e.prepare("INSERT OR REPLACE INTO watch_meta (key, value) VALUES ('schema_version', ?)").run(String(gl)),e}function cr(){return $n||($n=Jm()),$n}function to(){cr()}function wl(){if($n){try{$n.close()}catch{}$n=null}}function bl(e){let t=cr();t.prepare("INSERT INTO watch_recent (rule_id, rule_name, kind, summary, ts_ms) VALUES (?, ?, ?, ?, ?)").run(e.ruleId,e.ruleName,e.kind,e.summary.slice(0,2e3),e.tsMs);let n=t.prepare("SELECT COUNT(*) AS c FROM watch_recent").get();n.c>yl&&t.prepare(`DELETE FROM watch_recent WHERE id IN (
|
|
25
26
|
SELECT id FROM watch_recent ORDER BY ts_ms ASC LIMIT ?
|
|
26
|
-
)`).run(n.c-
|
|
27
|
-
`,r=`${
|
|
28
|
-
`)){let y=g.trim();y&&t(y)}}finally{
|
|
29
|
-
`)){let i=s.match(/^Unit=(.+)$/);if(i){o=i[1];continue}let a=s.match(/^ActiveState=(.+)$/);a&&o&&t.set(o,a[1].trim())}if(t.size===0)for(let s of e){let i=s.endsWith(".service")?s:`${s}.service`,a=
|
|
30
|
-
`,{mode:384})}var
|
|
31
|
-
`).replace(/^\n+/,"").trimEnd()}
|
|
32
|
-
|
|
33
|
-
`)
|
|
34
|
-
`).
|
|
35
|
-
`
|
|
36
|
-
`).replace(/^\n+/,"").trimEnd()}function
|
|
37
|
-
`).replace(/^\n+/,"").trimEnd()}function Z(e){return{wa:Nf(e),tg:_f(e),tgHtml:!0}}function xn(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 (plain \u2192 sync shell only when no focused /apps session); space optional"},{kind:"bullet",text:"/bg <cmd> \u2014 background job; optional -n name; /jobs, /log, /tail, /kill (id or name)"},{kind:"bullet",text:e.tunnelEnabled?"/tunnel login|logout|status|http|tcp \u2014 login/status anytime; /tunnels needs tunnelEnabled":"/tunnel expose/list off until tunnelEnabled true (login/status still work)"},{kind:"bullet",text:"/apps \u2026 \u2014 interactive app sessions (/apps help)"},{kind:"bullet",text:"/send selectors \u2014 host files \u2192 chat (/file); caption: selectors -- 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 this chat & shared shortcuts (/shortcut help); !name or /name expands chat override first, then shared"},{kind:"bullet",text:"/run \u2014 recipe-based task runs (/r); per-chat or gateway-shared /run add \u2014 /run list, /run help"},{kind:"bullet",text:"/cowork | /cw \u2014 scheduled & on-demand shell tasks; logs to ~/Cowork/\u2026 (/cowork help)"},{kind:"bullet",text:"/watch \u2014 OS event eye: fs/pkg/svc alerts; pause/stop/rm, excludes (/watch help; docs/features/watch.md)"},{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"},{kind:"gap"},{kind:"sub",text:"Terms"},{kind:"bullet",text:"Gateway = omnish on this host; shell runs here. Standalone = messengers on this host; attached = communication layer routes chat here."},{kind:"bullet",text:'Communication layer (when shipped) = link chats once, device token on this CLI; shell stays here. Standalone = no layer. /service "platform" = OS.'}]}function ec(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:"p",text:'"platform" in status means your OS (Linux/macOS/Windows), not a hosted omnish account.'},{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 tc(){return[{kind:"title",text:"Chat config"},{kind:"p",text:`Same trust as shell \u2014 allowlisted senders can change many keys saved to ${_}.`},{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 allowed keys for /config set (includes tunnel*, webhook*, watch*, chatLlm*, cluster*, \u2026)"},{kind:"gap"},{kind:"p",text:"After edits: /reload while omnish run is active (needed for gatewayMode and telegramBotToken)."}]}function si(){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: ${_}`}]}function nc(e){let t=["*Gateway status*","",`Mode: *${e.gatewayMode}*`,"- whatsapp \u2014 WhatsApp only","- telegram \u2014 Telegram only","- 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: ${Me(e.updateBrief)}`,""),t.push("Change: /gateway both \xB7 /gw tg","/updates \u2014 npm + optional notice URL",`Config: ${Me(_)}`);let n=["<b>Gateway status</b>","",`<b>${q(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> ${q(e.updateBrief)}`,""),n.push("<i>Change:</i> /gateway both \xB7 /gw tg","<i>/updates</i> \u2014 npm + optional notice URL",q(`Config: ${_}`)),ue(t.join(`
|
|
27
|
+
)`).run(n.c-yl)}function kl(e,t){let n=cr(),r=Math.min(Math.max(1,e),50),o=n.prepare("SELECT rule_id, rule_name, kind, summary, ts_ms FROM watch_recent ORDER BY ts_ms DESC LIMIT ?").all(r*3),s=[];for(let i of o)if(!(t&&!t.has(i.rule_id))&&(s.push({ruleId:i.rule_id,ruleName:i.rule_name,kind:i.kind,stateKey:"",summary:i.summary,tsMs:i.ts_ms}),s.length>=r))break;return s}function Sl(e){return cr().prepare("SELECT state_key FROM watch_rule_state WHERE rule_id = ?").get(e)?.state_key??null}function vl(e,t,n){cr().prepare("INSERT OR REPLACE INTO watch_rule_state (rule_id, state_key, updated_at_ms) VALUES (?, ?, ?)").run(e,t,n)}import Ml from"node:path";import St from"node:path";function Km(e,t){let n=St.normalize(e);for(let r of t){let o=St.normalize(r);if(n===o||n.startsWith(o+St.sep))return!0}return!1}function zm(e,t,n){let r=St.relative(t,e);if(r.startsWith("..")||St.isAbsolute(r))return!1;let o=r.split(St.sep).join("/"),s=n.replace(/\\/g,"/").replace(/^\//,"");if(s.includes("**")){let i=s.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"___GLOBSTAR___").replace(/\*/g,"[^/]*").replace(/___GLOBSTAR___/g,".*");try{if(new RegExp(`^${i}$`).test(o))return!0;if(s.startsWith("**/")){let l=s.slice(3);if(l&&!l.includes("*"))return o.split("/").includes(l)}return!1}catch{return!1}}if(s.includes("*")){let i=s.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*");try{return new RegExp(`^${i}$`).test(o)}catch{return!1}}return o===s||o.endsWith("/"+s)||o.includes("/"+s+"/")}function no(e,t){if(t.excludePaths.length&&Km(e,t.excludePaths))return!0;let n=t.path;if(n&&t.excludeGlobs.length){for(let r of t.excludeGlobs)if(zm(e,n,r))return!0}return!1}function xl(e){let t=[];for(let n of e.excludeGlobs){let r=n.replace(/\\/g,"/");r.startsWith("**/")?t.push(r):r.includes("*")?t.push(`**/${r}`):t.push(`**/${r}/**`)}for(let n of e.excludePaths)if(e.path)try{let r=St.relative(e.path,n);!r.startsWith("..")&&!St.isAbsolute(r)&&t.push(r.split(St.sep).join("/")+"/**")}catch{}return t}qe();function Rn(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=ee(String(o));s&&r.add(`wa:${Lt(s)}`)}if(e==="tg"||e==="all")for(let o of n.telegramAllowFrom){let s=Ee(String(o));s&&r.add(`tg:${s}`)}return[...r]}function $l(e,t,n){return Rn(e,t,n)}be();G();import qm from"node:crypto";import zs from"node:fs";var Ym=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,Qm=1,qs=20;function ro(e){let t=e.trim().toLowerCase();return Ym.test(t)?{ok:!0,name:t}:{ok:!1,error:"Name must be alphanumeric with _ or -, max 32 chars."}}function oo(){return qm.randomBytes(8).toString("hex")}function Vm(e){if(!Array.isArray(e)||e.length===0)return["create","delete","rename"];let t=new Set(["create","delete","rename","update"]),n=[];for(let r of e)typeof r=="string"&&t.has(r)&&n.push(r);return n.length?n:["create","delete","rename"]}function Xm(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.kind=="string"?t.kind:"",i=s==="fs"||s==="pkg"||s==="svc"?s:null;if(!n||!r||!o||!i)return null;let a=typeof t.notify=="string"?t.notify.toLowerCase():"self",l=a==="wa"||a==="whatsapp"?"wa":a==="tg"||a==="telegram"?"tg":a==="all"?"all":a==="none"?"none":"self",d=typeof t.notifyWhen=="string"?t.notifyWhen:"always",u=d==="failure"||d==="state-change"?d:"always",c=Array.isArray(t.units)?t.units.filter(h=>typeof h=="string"&&h.trim().length>0).map(h=>h.trim()):[],m=Array.isArray(t.excludePaths)?t.excludePaths.filter(h=>typeof h=="string"&&h.trim().length>0):[],f=Array.isArray(t.excludeGlobs)?t.excludeGlobs.filter(h=>typeof h=="string"&&h.trim().length>0):[];return{id:n,name:r,ownerPeerKey:o,kind:i,enabled:typeof t.enabled=="boolean"?t.enabled:!0,paused:typeof t.paused=="boolean"?t.paused:!1,notify:l,notifyWhen:u,path:typeof t.path=="string"?t.path:"",events:Vm(t.events),units:c,excludePaths:m,excludeGlobs:f,adapterStatus:typeof t.adapterStatus=="string"?t.adapterStatus:"",createdAtMs:typeof t.createdAtMs=="number"&&Number.isFinite(t.createdAtMs)?t.createdAtMs:Date.now()}}function Zm(e){let t=JSON.parse(e);return!t||!Array.isArray(t.rules)?[]:t.rules.map(Xm).filter(n=>n!==null)}function ef(e){let t=[...e].sort((s,i)=>s.createdAtMs-i.createdAtMs),n=new Set,r=!1,o=[];for(let s of t){if(!n.has(s.name)){n.add(s.name),o.push(s);continue}let i=s.id.slice(0,8),a=`${s.name}-${i}`;a.length>32&&(a=`${s.name.slice(0,32-i.length-1)}-${i}`);let l=0;for(;n.has(a);){l+=1;let d=String(l);a=`${s.name.slice(0,Math.max(1,32-i.length-d.length-1))}-${i}${d}`}n.add(a),M.warn({oldName:s.name,newName:a,id:s.id},"watch: renamed duplicate rule for device-wide namespace"),o.push({...s,name:a}),r=!0}return{rules:o,changed:r}}function Le(){try{let e=zs.readFileSync(or,"utf8"),t=Zm(e),{rules:n,changed:r}=ef(t);return r&&mt(n),n}catch{return[]}}function tf(e){let t=0,n=0,r=0;for(let o of e)o.enabled?o.paused?n+=1:t+=1:r+=1;return{total:e.length,active:t,paused:n,disabled:r}}function ur(){let e=Le();return{rules:e,summary:tf(e)}}function mt(e){j(kt);let n=`${JSON.stringify({version:Qm,rules:e},null,2)}
|
|
28
|
+
`,r=`${or}.tmp`;zs.writeFileSync(r,n,{mode:384}),zs.renameSync(r,or)}function Ys(){return or}function tn(e,t){let n=t.trim().toLowerCase();return e.find(r=>r.name===n)}function Rl(e,t){return e.find(n=>n.id===t)}function Cn(e,t){let n=e.findIndex(r=>r.id===t.id);if(n>=0){let r=[...e];return r[n]=t,r}return[...e,t]}function Cl(e,t){let n=t.trim().toLowerCase();return e.filter(r=>r.name!==n)}import nf from"node:os";import ft from"node:path";var rf=new Set([".env","id_rsa","id_ed25519","id_ecdsa","known_hosts","credentials.json","secrets.json",".netrc","shadow","passwd"]);function Qe(e){let t=ft.normalize(e),n=t.toLowerCase(),r=nf.homedir().toLowerCase();if(n.includes(`${ft.sep}.ssh${ft.sep}`)||n.endsWith(`${ft.sep}.ssh`)||n.includes(`${ft.sep}browser${ft.sep}`)&&n.includes("profile")||r&&(n===`${r}/.gnupg`||n.startsWith(`${r}/.gnupg${ft.sep}`))||n.includes(`${ft.sep}keychains${ft.sep}`))return!0;let o=ft.basename(t);return!!(rf.has(o)||o.startsWith(".env.")||o.endsWith(".pem")||o.endsWith(".key"))}var of=["node_modules",".git",".svn",".hg","__pycache__",".cache",".next","dist","build"],sf=[".tmp",".swp",".swx","~",".part"];function Tl(e,t){let n=new Map,r=new Map;function o(u,c){let m=u.split(Ml.sep);for(let h of m)if(of.includes(h))return!0;let f=Ml.basename(u);for(let h of sf)if(f.endsWith(h))return!0;return!!no(u,c)}function s(u){let c=Rl(Le(),u);return!c||!c.enabled||c.paused?null:c}function i(u){let c=Date.now(),m=r.get(u);return!m||c-m.windowStart>=6e4?(r.set(u,{windowStart:c,count:1}),!1):m.count>=t.maxEventsPerMinute?!0:(m.count+=1,!1)}async function a(u,c){let m=e.getConfig();if(!m.watchEnabled)return;let f=s(u.id);if(!f||c.kind==="fs"&&c.meta?.path&&(Qe(c.meta.path)||o(c.meta.path,f)))return;if(bl(c),(f.notifyWhen??"always")==="state-change"){if(Sl(f.id)===c.stateKey)return;vl(f.id,c.stateKey,c.tsMs)}let g=$l(f.notify,f.ownerPeerKey,m);if(g.length===0)return;let y=`[watch:${f.name}] ${c.summary}`;await Promise.all(g.map(b=>e.sendToPeer(b,y).catch(()=>{})))}function l(u){let c=n.get(u);if(!c)return;n.delete(u);let m=s(c.ruleId);m&&(i(c.ruleId)||a(m,c.event))}function d(u){for(let[c,m]of n)m.ruleId===u&&(clearTimeout(m.timer),n.delete(c))}return{ingest(u,c){if(!u.enabled||u.paused||c.meta?.path&&(Qe(c.meta.path)||o(c.meta.path,u)))return;let m=`${u.id}:${c.stateKey||c.summary}`,f=n.get(m);f&&clearTimeout(f.timer);let h=setTimeout(()=>l(m),t.debounceMs);h.unref?.(),n.set(m,{timer:h,event:c,ruleId:u.id})},cancelForRule:d,dispose(){for(let u of n.values())clearTimeout(u.timer);n.clear(),r.clear()}}}function El(e,t){let n=e.toLowerCase();return!!(n==="create"&&t.has("create")||n==="delete"&&t.has("delete")||(n==="update"||n==="rename")&&(t.has("update")||t.has("rename")))}be();import Pl from"node:fs";import af from"node:path";import{subscribe as lf}from"@parcel/watcher";var cf=["**/node_modules/**","**/.git/**","**/.svn/**","**/.hg/**","**/__pycache__/**","**/.cache/**"];function uf(e){return e==="create"?"create":e==="delete"?"delete":e==="update"?"update":e}function df(e,t){try{let n=Pl.statSync(t),r=n.isFile()&&n.size<1024*1024?` (${n.size<1024?`${n.size} B`:`${(n.size/1024).toFixed(1)} KB`})`:"";return`fs: ${e} ${t}${r}`}catch{return`fs: ${e} ${t}`}}async function Al(e,t){let n=e.path;if(!n||!Pl.existsSync(n))return{stop:async()=>{},status:()=>"error: path missing or not found"};if(Qe(n))return{stop:async()=>{},status:()=>"error: sensitive path denied"};let r=new Set(e.events.map(i=>i.toLowerCase())),o="ok",s=null;try{s=await lf(n,(i,a)=>{if(i){o=`error: ${i.message}`,M.warn({rule:e.name,err:i.message},"watch fs adapter");return}for(let l of a){let d=uf(l.type);if(!El(d,r))continue;let u=af.resolve(l.path);if(!u.startsWith(n)||Qe(u)||no(u,e))continue;let c=df(d,u);t({ruleId:e.id,ruleName:e.name,kind:"fs",stateKey:`${d}:${u}`,summary:c,tsMs:Date.now(),meta:{path:u,type:d}})}},{ignore:[...cf,...xl(e)]})}catch(i){o=`error: ${String(i)}`,M.warn({rule:e.name,err:String(i)},"watch fs subscribe failed")}return{stop:async()=>{s&&(await s.unsubscribe().catch(()=>{}),s=null)},status:()=>o}}import bf from"node:os";be();import _t from"node:fs";function pf(e,t,n){let r=n?.pollMs??2e3,o=0,s=!1,i=null,a=null,l="starting";function d(){if(!s)try{let u=_t.statSync(e);if(u.size<o&&(o=0),u.size<=o)return;let c=_t.openSync(e,"r");try{let m=u.size-o,f=Buffer.alloc(m);_t.readSync(c,f,0,m,o),o=u.size;let h=f.toString("utf8");for(let g of h.split(`
|
|
29
|
+
`)){let y=g.trim();y&&t(y)}}finally{_t.closeSync(c)}l="ok"}catch(u){l=`error: ${String(u)}`}}try{_t.existsSync(e)&&(o=_t.statSync(e).size),i=_t.watch(e,()=>d()),i.on("error",()=>{i?.close(),i=null}),l="ok (watch)"}catch{l="ok (poll)",a=setInterval(d,r),a.unref?.(),d()}return{stop(){s=!0,i?.close(),a&&clearInterval(a)},status:()=>l}}function so(e,t){for(let n of e)try{if(_t.existsSync(n))return pf(n,t)}catch(r){M.debug({path:n,err:String(r)},"watch log-tail skip path")}return null}var mf=["/var/log/install.log"];function ff(e){let t=e.toLowerCase();return t.includes("installed")||t.includes("upgraded")||t.includes("removed")?e.length>240?`pkg: ${e.slice(0,240)}\u2026`:`pkg: ${e}`:null}function Il(e,t){return so(mf,n=>{let r=ff(n);r&&t({ruleId:e.id,ruleName:e.name,kind:"pkg",stateKey:r.slice(0,200),summary:r,tsMs:Date.now()})})}var hf=["/var/log/dpkg.log","/var/log/apt/history.log"];function gf(e){if(e.includes("status installed")){let t=e.match(/install\s+(\S+):/);if(t)return`pkg: installed ${t[1]} (dpkg)`}if(e.includes("status removed")||e.includes("remove ")){let t=e.match(/remove\s+(\S+):/);if(t)return`pkg: removed ${t[1]} (dpkg)`}return null}function yf(e){return e.startsWith("Install:")||e.startsWith("Upgrade:")?`pkg: ${e.slice(0,120)} (apt)`:e.startsWith("Remove:")?`pkg: ${e.slice(0,120)} (apt)`:null}function Ol(e,t){return so(hf,n=>{let r=gf(n)??yf(n);r&&t({ruleId:e.id,ruleName:e.name,kind:"pkg",stateKey:r,summary:r,tsMs:Date.now()})})}import{spawn as wf}from"node:child_process";function Ll(e,t){let n=!1,r="ok",o=0,s=()=>{if(n)return;let a=wf("powershell.exe",["-NoProfile","-NonInteractive","-Command","Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName=@('MsiInstaller','Windows Installer')} -MaxEvents 5 -ErrorAction SilentlyContinue | Select-Object -Property RecordId,Message | ConvertTo-Json -Compress"],{windowsHide:!0}),l="";a.stdout?.on("data",d=>{l+=String(d)}),a.on("close",d=>{if(n||d!==0||!l.trim()){d!==0&&(r="ok (no events or access denied)"),i();return}try{let u=JSON.parse(l),c=Array.isArray(u)?u:[u];for(let m of c.sort((f,h)=>f.RecordId-h.RecordId)){if(m.RecordId<=o)continue;o=m.RecordId;let f=(m.Message??"").replace(/\s+/g," ").trim().slice(0,300);if(!f)continue;let h=`pkg: ${f}`;t({ruleId:e.id,ruleName:e.name,kind:"pkg",stateKey:`win:${m.RecordId}`,summary:h,tsMs:Date.now()})}r="ok"}catch(u){r=`parse error: ${String(u)}`}i()}),a.on("error",d=>{r=`error: ${String(d)}`,i()})},i=()=>{n||setTimeout(s,3e4).unref?.()};return s(),{stop(){n=!0},status:()=>r}}function Nl(e,t){let n=bf.platform();if(n==="win32"){let o=Ll(e,t);return{stop:()=>o.stop(),status:o.status}}if(n==="darwin"){let o=Il(e,t);return o?{stop:()=>o.stop(),status:o.status}:{stop:()=>{},status:()=>"error: cannot read /var/log/install.log (try sudo or adm group)"}}let r=Ol(e,t);return r?{stop:()=>r.stop(),status:r.status}:{stop:()=>{},status:()=>"error: cannot read dpkg/apt logs (add user to adm or run gateway with read access)"}}import Mf from"node:os";import{spawnSync as _l}from"node:child_process";var kf=3e4;function Sf(e){let t=new Map;for(let n of e){let r=_l("launchctl",["print",`system/${n}`],{encoding:"utf8",timeout:1e4});if(r.status!==0){let s=process.getuid?.()??501,i=_l("launchctl",["print",`gui/${s}/${n}`],{encoding:"utf8",timeout:1e4});if(i.status!==0){t.set(n,"not-found");continue}let a=(i.stdout??"").includes("state = running")?"running":"stopped";t.set(n,a);continue}let o=(r.stdout??"").includes("state = running")?"running":"stopped";t.set(n,o)}return t}function Fl(e,t){let n=e.units,r=!1,o="ok",s=new Map,i=()=>{if(r)return;let a=Sf(n);if(a.size===0)o="error: no launchd labels configured";else{o="ok";for(let[l,d]of a){let u=s.get(l);if(u!==void 0&&u!==d){let c=`svc: ${l} ${u} \u2192 ${d}`;t({ruleId:e.id,ruleName:e.name,kind:"svc",stateKey:`${l}:${d}`,summary:c,tsMs:Date.now(),meta:{unit:l,state:d}})}}s=a}r||setTimeout(i,kf).unref?.()};return i(),{stop(){r=!0},status:()=>o}}import{spawnSync as Wl}from"node:child_process";var vf=3e4;function xf(e){let t=new Map;if(e.length===0)return t;let n=["show",...e,"--property=ActiveState,SubState,UnitFileState","--no-pager"],r=Wl("systemctl",n,{encoding:"utf8",timeout:15e3});if(r.status!==0)return t;let o="";for(let s of(r.stdout??"").split(`
|
|
30
|
+
`)){let i=s.match(/^Unit=(.+)$/);if(i){o=i[1];continue}let a=s.match(/^ActiveState=(.+)$/);a&&o&&t.set(o,a[1].trim())}if(t.size===0)for(let s of e){let i=s.endsWith(".service")?s:`${s}.service`,a=Wl("systemctl",["is-active",i],{encoding:"utf8",timeout:5e3}),l=(a.stdout??a.stderr??"unknown").trim();t.set(i,l)}return t}function Ul(e,t){let n=e.units.map(a=>a.endsWith(".service")?a:`${a}.service`),r=!1,o="ok",s=new Map,i=()=>{if(r)return;let a=xf(n);if(a.size===0)o="error: systemctl unavailable or units not found";else{o="ok";for(let[l,d]of a){let u=s.get(l);if(u!==void 0&&u!==d){let c=`svc: ${l} ${u} \u2192 ${d}`;t({ruleId:e.id,ruleName:e.name,kind:"svc",stateKey:`${l}:${d}`,summary:c,tsMs:Date.now(),meta:{unit:l,state:d}})}}s=a}r||setTimeout(i,vf).unref?.()};return i(),{stop(){r=!0},status:()=>o}}import{spawnSync as $f}from"node:child_process";var Rf=3e4;function Cf(e){let t=new Map;for(let n of e){let r=$f("sc",["query",n],{encoding:"utf8",timeout:1e4,windowsHide:!0});if(r.status!==0){t.set(n,"not-found");continue}let o=r.stdout??"",s="unknown";o.includes("RUNNING")?s="running":o.includes("STOPPED")?s="stopped":o.includes("START_PENDING")?s="start-pending":o.includes("STOP_PENDING")&&(s="stop-pending"),t.set(n,s)}return t}function Dl(e,t){let n=e.units,r=!1,o="ok",s=new Map,i=()=>{if(r)return;let a=Cf(n);if(a.size===0)o="error: no service names configured";else{o="ok";for(let[l,d]of a){let u=s.get(l);if(u!==void 0&&u!==d){let c=`svc: ${l} ${u} \u2192 ${d}`;t({ruleId:e.id,ruleName:e.name,kind:"svc",stateKey:`${l}:${d}`,summary:c,tsMs:Date.now(),meta:{unit:l,state:d}})}}s=a}r||setTimeout(i,Rf).unref?.()};return i(),{stop(){r=!0},status:()=>o}}function Hl(e,t){let n=Mf.platform();return n==="win32"?Dl(e,t):n==="darwin"?Fl(e,t):Ul(e,t)}var Ve=null,Ft=null;function Bl(e){let t=e.getConfig();return Tl(e,{debounceMs:Math.max(500,t.watchDebounceMs??2e3),maxEventsPerMinute:Math.max(1,t.watchMaxEventsPerMinute??30)})}function Pf(e){return e.watchEnabled&&e.watchAutoRestore}var Qs=class{deps;pipeline;runtimes=new Map;stopped=!1;constructor(t){this.deps=t,this.pipeline=Bl(t)}onEvent=(t,n)=>{this.pipeline.ingest(t,n)};cancelPendingForRule(t){this.pipeline.cancelForRule(t)}async reload(){if(this.pipeline.dispose(),this.pipeline=Bl(this.deps),await this.stopAdapters(),this.stopped||!this.deps.getConfig().watchEnabled)return 0;let n=Le().filter(r=>r.enabled&&!r.paused);for(let r of n)await this.startRule(r);return this.runtimes.size}async startRule(t){try{let n;if(t.kind==="fs"){let r=Ge(t.path,Tf.homedir()),o={...t,path:r};if(Qe(r)){t.adapterStatus="denied: sensitive path",this.persistRuleStatus(t);return}if(!Ef.existsSync(r)){t.adapterStatus="error: path not found",this.persistRuleStatus(t);return}let s=await Al(o,i=>this.onEvent(o,i));n={stop:()=>s.stop(),status:s.status}}else if(t.kind==="pkg")n=Nl(t,o=>this.onEvent(t,o));else if(t.kind==="svc"){if(t.units.length===0){t.adapterStatus="error: no units",this.persistRuleStatus(t);return}n=Hl(t,o=>this.onEvent(t,o))}else return;t.adapterStatus=n.status(),this.persistRuleStatus(t),this.runtimes.set(t.id,{rule:t,adapter:n})}catch(n){t.adapterStatus=`error: ${String(n)}`,this.persistRuleStatus(t),M.warn({rule:t.name,err:String(n)},"watch rule start failed")}}persistRuleStatus(t){let n=Le(),r=n.findIndex(o=>o.id===t.id);r>=0&&(n[r]={...n[r],adapterStatus:t.adapterStatus},mt(n))}async stopAdapters(){for(let t of this.runtimes.values())try{await t.adapter.stop()}catch{}this.runtimes.clear()}async stop(){this.stopped=!0,await this.stopAdapters(),this.pipeline.dispose(),wl()}getStatusLines(){let t=Le();return t.length===0?["(no watch rules)"]:t.map(n=>{let o=this.runtimes.get(n.id)?.adapter.status()??n.adapterStatus,s=n.enabled?n.paused?"paused":"on":"disabled",i=n.kind==="fs"?n.path:n.kind==="svc"?n.units.join(","):"system",a=n.kind==="fs"&&(n.excludePaths.length||n.excludeGlobs.length)?` excludes:${n.excludePaths.length+n.excludeGlobs.length}`:"";return`${n.name} [${n.kind}] ${s} notify=${n.notify} when=${n.notifyWhen} \u2014 ${i}${a} \u2014 ${o}`})}getRunningCount(){return this.runtimes.size}isRuleRunning(t){return this.runtimes.has(t)}};function jl(){return Ve}function Vs(e){Ve?.cancelPendingForRule(e)}function Af(){j(kt),to()}function Xs(){Ft&&(Ve||(Ve=new Qs(Ft)),Ve.reload())}function io(e){Ft=e,Af();let t=e.getConfig(),{summary:n}=ur();return n.total>0&&M.info({rules:n.total,active:n.active,paused:n.paused,disabled:n.disabled},"watch rules loaded from disk"),Pf(t)&&Xs(),()=>{Ve?.stop(),Ve=null,Ft=null}}async function Gl(){return Ft?Ft.getConfig().watchEnabled?(Xs(),Ve?.getRunningCount()??0):(Ve?.stop(),Ve=null,-1):-1}function De(){if(!Ft)return;if(!Ft.getConfig().watchEnabled){Ve?.stop(),Ve=null;return}Xs()}G();me();G();import Lf from"node:os";import lo from"node:path";G();import Zs from"node:fs";import Kl from"node:os";import Wt from"node:path";var zl=Wt.join(H,"sessions.json"),Mn=new Map;function ql(){return{cwd:Wt.resolve(Kl.homedir())}}function If(e){return e.startsWith("wa:")||e.startsWith("tg:")?e:`wa:${e}`}function Of(){try{let e=Zs.readFileSync(zl,"utf8"),t=JSON.parse(e);for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o=If(n),i={cwd:typeof r.cwd=="string"&&r.cwd.length>0?Wt.resolve(r.cwd):ql().cwd};r.fileReceiveRoot==="sessionCwd"&&(i.fileReceiveRoot="sessionCwd"),Mn.set(o,i)}}catch{}}function Yl(){j(H);let e={};for(let[t,n]of Mn){let r={cwd:n.cwd};n.fileReceiveRoot==="sessionCwd"&&(r.fileReceiveRoot="sessionCwd"),e[t]=r}Zs.writeFileSync(zl,JSON.stringify(e,null,2)+`
|
|
31
|
+
`,{mode:384})}var Jl=!1;function ei(){Jl||(Of(),Jl=!0)}function oe(e){ei();let t=Mn.get(e);return t||(t=ql(),Mn.set(e,t)),t}function ao(e,t){ei();let n=Wt.resolve(t),r=oe(e);r.cwd=n,Mn.set(e,r),Yl()}function Ql(e){return oe(e).fileReceiveRoot==="sessionCwd"?"sessionCwd":"default"}function ti(e,t){ei();let n=oe(e);t==="default"?delete n.fileReceiveRoot:n.fileReceiveRoot="sessionCwd",Mn.set(e,n),Yl()}function Vl(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 Xl(e,t){if(t.kind==="home")return Wt.resolve(Kl.homedir());let n=t.value.replace(/^['"]|['"]$/g,"");return Wt.isAbsolute(n)?Wt.normalize(n):Wt.resolve(e,n)}function Zl(e){try{return Zs.statSync(e).isDirectory()?{ok:!0}:{ok:!1,error:`Not a directory: ${e}`}}catch(t){return{ok:!1,error:String(t)}}}var Nf="Omnish";function ec(){return lo.join(Lf.homedir(),"Downloads",Nf)}function Ut(e,t){let n=oe(t);if(n.fileReceiveRoot==="sessionCwd")return n.cwd;switch(e.fileReceiveRootMode){case"downloads":return ec();case"omnishData":return lo.join(H,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(!lo.isAbsolute(r))throw new Error('fileReceiveRootPath must be an absolute path when fileReceiveRootMode is "fixed".');return lo.resolve(r)}default:return ec()}}G();import Rt from"node:fs";import nc from"node:path";import jt from"node:process";var nn="\x1B";function _f(e){return e.replace(/\u001B\[[\d;]*m/g,"")}function co(e){return _f(e).length}function ni(e,t,n,r,o=2){let s=Math.max(0,t-co(n));return`${e}${n}${" ".repeat(s)}${" ".repeat(o)}${r}`}function vt(e,t,n,r){if(n.length===0)return[];let o=n.map(i=>r(i.left)),s=Math.max(...o.map(co));return n.map((i,a)=>ni(t,s,o[a],S(e,i.right)))}var Dt={primary:"#b4ff24",foreground:"#eef2f4",muted:"#8a9199",border:"#2a3139",error:"#ef4444",warn:"#a0e614",warnAlt:"#8cce04"};function Ff(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 Ht(e){let t=Ff(e);return t?`${nn}[38;2;${t.r};${t.g};${t.b}m`:""}function uo(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 xt(e,t,n){return!t||!uo(e)?n:`${t}${n}${nn}[0m`}function J(e,t){return xt(e,`${nn}[1m`,t)}function Wf(e,t){return uo(e)?`${Ht(Dt.foreground)}${nn}[1m${t}${nn}[0m`:t}function V(e,t){return xt(e,`${nn}[2m`,t)}function Ce(e,t){return xt(e,`${Ht(Dt.primary)}${nn}[1m`,t)}function ue(e,t){return xt(e,Ht(Dt.primary),t)}function S(e,t){return xt(e,Ht(Dt.foreground),t)}function w(e,t){return xt(e,Ht(Dt.muted),t)}function Uf(e,t){return xt(e,Ht(Dt.border),t)}function po(e,t){return xt(e,Ht(Dt.error),t)}function fe(e,t){return xt(e,Ht(Dt.warn),t)}function Bt(e,t=60,n="\u2500"){let r=n.repeat(Math.max(1,t));return Uf(e,r)}function B(e,t){return uo(e)?`${`${w(e,"[")}${ue(e,"omnish")}${w(e,"]")}`} ${t}`:`[omnish] ${t}`}function C(e,t){return uo(e)?`${`${po(e,"[omnish]")}`} ${t}`:`[omnish] ${t}`}function tc(e,t){let n=[];for(let r of e)switch(r.kind){case"title":n.push("",Ce(t,r.text),"");break;case"sub":n.push("",Wf(t,r.text),"");break;case"gap":n.push("");break;case"p":n.push(S(t,r.text));break;case"bullet":n.push(`${w(t,"\u2022")} ${S(t,r.text)}`);break}return n.join(`
|
|
32
|
+
`).replace(/^\n+/,"").trimEnd()}me();G();rn();on();function fo(e){return(e&4)!==0}function si(e){return(e&2)!==0}var rc={error:3,warn:2,info:1};function oc(e,t){let n=rc[t];return e.filter(r=>rc[r.severity]>=n)}function Ct(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 ${_} and delete wildcard entries.`,fixHint:`Edit ${_} 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 ${_} 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 ${_} unless you trust every allowlisted identity.`}),!nc.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 ${_}.`});else try{Rt.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 ${_} 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 ${_} points to a real file.`})}if(e.fileReceiveRootMode==="fixed"){let a=e.fileReceiveRootPath.trim();a?nc.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 ${_}.`}):n.push({severity:"error",code:"receive-fixed-empty",message:'fileReceiveRootMode is "fixed" but fileReceiveRootPath is empty.',fixHint:`Set fileReceiveRootPath to an absolute directory in ${_}, or change fileReceiveRootMode.`})}if(jt.platform!=="win32"){try{if(Rt.existsSync(_)){let d=Rt.statSync(_);(fo(d.mode)||si(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 ${_}`,fixHint:`chmod 600 ${_}`})}}catch{}(typeof jt.getuid=="function"?jt.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(Rt.existsSync(H)){let d=Rt.statSync(H);(fo(d.mode)||si(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 ${H}`,fixHint:`chmod 700 ${H}`}))}}catch{}try{if(!l&&Rt.existsSync(tt)){let d=Rt.statSync(tt);(fo(d.mode)||si(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 ${tt}`,fixHint:`chmod 700 ${tt}`})}}catch{}try{if(Rt.existsSync(ne)){let d=Rt.statSync(ne);fo(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 ${ne}`,fixHint:`chmod 700 ${ne}`})}}catch{}}return(typeof jt.env.TELEGRAM_BOT_TOKEN=="string"?jt.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&&!ve(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 ${_} 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."}),e.platformToken.trim()&&n.push({severity:"info",code:"platform-token-config",message:"platformToken is stored in config.json (same trust boundary as your shell account).",fixHint:"Use OMNISH_TOKEN in the environment for CI/ephemeral hosts; env overrides config."}),(jt.env.OMNISH_TOKEN?.trim()||jt.env.OMNISH_TUNNEL_TOKEN?.trim()||jt.env.OMNISH_DEVICE_TOKEN?.trim())&&n.push({severity:"info",code:"platform-token-env",message:"OMNISH_TOKEN (or OMNISH_TUNNEL_TOKEN / OMNISH_DEVICE_TOKEN) is set in the environment.",fixHint:"Unset platform token env vars if you want config.json / tunnel-auth.json to apply."}),e.tunnelEnabled&&(n.push({severity:"warn",code:"tunnel-enabled",message:"Chat tunneling is enabled \u2014 allowlisted users can publish public URLs to local HTTP/TCP services.",fixHint:"Disable tunnelEnabled or restrict allowlists if you do not want remote tunnel control."}),gt()||n.push({severity:"warn",code:"tunnel-no-token",message:"Chat tunneling is enabled but no tunnel token is configured.",fixHint:"Run `omnish tunnel login` or set OMNISH_TUNNEL_TOKEN for the gateway process."})),e.tunnelRelayUrl.trim()&&e.tunnelRelayUrl.trim()!==$e&&n.push({severity:"info",code:"tunnel-relay-custom",message:`Custom tunnel relay configured: ${e.tunnelRelayUrl.trim()}`,fixHint:"Use the default relay only if you trust the operator of that endpoint."}),n}function dr(e){return e.some(t=>t.severity==="error")}function Hf(e,t){switch(t){case"error":return po(e,"[ERROR]");case"warn":return fe(e,"[WARN]");case"info":return w(e,"[INFO]")}}function ii(e,t,n,r){if(r.length!==0){t.push(J(e,`${n} (${r.length}):`));for(let o of r)t.push(` ${Hf(e,o.severity)} ${w(e,`${o.code}:`)} ${S(e,o.message)}`),o.detail&&t.push(` ${w(e,o.detail)}`),o.fixHint&&t.push(` ${w(e,`Fix: ${o.fixHint}`)}`);t.push("")}}function ai(e,t){if(e.length===0)return[`${Ce(t,"Security check:")} ${S(t,"no issues reported by automated rules.")}`,"",w(t,"Note: allowlisted remote shell access is still equivalent to sharing credentials with those identities.")].join(`
|
|
33
|
+
`);let n=e.filter(a=>a.severity==="error"),r=e.filter(a=>a.severity==="warn"),o=e.filter(a=>a.severity==="info"),i=[`${Ce(t,"Security check:")} `+S(t,`${n.length} error(s), ${r.length} warning(s), ${o.length} note(s).`),""];return ii(t,i,"Errors",n),ii(t,i,"Warnings",r),ii(t,i,"Notes",o),i.push(w(t,"Allowlisted identities can run commands as this user; treat them like passwords.")),i.join(`
|
|
34
|
+
`).trimEnd()}function li(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 sc(e){return`${JSON.stringify({findings:e,summary:li(e)},null,2)}
|
|
35
|
+
`}function ic(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 ac(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`${Ce(t,"security:")} ${S(t,"ok (no automated findings)")}`;let i=[];r&&i.push(po(t,`${r} error(s)`)),o&&i.push(fe(t,`${o} warning(s)`)),s&&i.push(w(t,`${s} note(s)`));let a=n??"run `omnish security` for details";return`${Ce(t,"security:")} ${i.join(", ")} ${w(t,`\u2014 ${a}`)}`}var Re="- ";function p(e){return{wa:e,tg:e}}function de(e,t){return{wa:e,tg:t,tgHtml:!0}}function ke(e,t){return t==="whatsapp"?{text:e.wa}:e.tgHtml?{text:e.tg,parseModeHtml:!0}:{text:e.tg}}function q(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Me(e){return e.replace(/[*_~`]/g,t=>({"*":"\u2217",_:"\uFF3F","~":"\u02DC","`":"\u2032"})[t]??t)}function Bf(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(`${Re}${n.text}`);break}return t.join(`
|
|
36
|
+
`).replace(/^\n+/,"").trimEnd()}function jf(e){let t=[];for(let n of e)switch(n.kind){case"title":t.push("",`<b>${q(n.text)}</b>`,"");break;case"sub":t.push("",`<i>${q(n.text)}</i>`,"");break;case"gap":t.push("");break;case"p":t.push(q(n.text));break;case"bullet":t.push(`\u2022 ${q(n.text)}`);break}return t.join(`
|
|
37
|
+
`).replace(/^\n+/,"").trimEnd()}function Z(e){return{wa:Bf(e),tg:jf(e),tgHtml:!0}}function Tn(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 (plain \u2192 sync shell only when no focused /apps session); space optional"},{kind:"bullet",text:"/bg <cmd> \u2014 background job; optional -n name; /jobs, /log, /tail, /kill (id or name)"},{kind:"bullet",text:e.tunnelEnabled?"/tunnel login|logout|status|http|tcp \u2014 login/status anytime; /tunnels needs tunnelEnabled":"/tunnel expose/list off until tunnelEnabled true (login/status still work)"},{kind:"bullet",text:"/apps \u2026 \u2014 interactive app sessions (/apps help)"},{kind:"bullet",text:"/send selectors \u2014 host files \u2192 chat (/file); caption: selectors -- 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 this chat & shared shortcuts (/shortcut help); !name or /name expands chat override first, then shared"},{kind:"bullet",text:"/run \u2014 recipe-based task runs (/r); per-chat or gateway-shared /run add \u2014 /run list, /run help"},{kind:"bullet",text:"/cowork | /cw \u2014 scheduled & on-demand shell tasks; logs to ~/Cowork/\u2026 (/cowork help)"},{kind:"bullet",text:"/watch \u2014 OS event eye: fs/pkg/svc alerts; pause/stop/rm, excludes (/watch help; docs/features/watch.md)"},{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"},{kind:"gap"},{kind:"sub",text:"Terms"},{kind:"bullet",text:"Gateway = omnish on this host; shell runs here. Standalone = messengers on this host; attached = communication layer routes chat here."},{kind:"bullet",text:'Communication layer (when shipped) = link chats once, device token on this CLI; shell stays here. Standalone = no layer. /service "platform" = OS.'}]}function lc(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:"p",text:'"platform" in status means your OS (Linux/macOS/Windows), not a hosted omnish account.'},{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 cc(){return[{kind:"title",text:"Chat config"},{kind:"p",text:`Same trust as shell \u2014 allowlisted senders can change many keys saved to ${_}.`},{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 allowed keys for /config set (includes tunnel*, webhook*, watch*, chatLlm*, cluster*, \u2026)"},{kind:"gap"},{kind:"p",text:"After edits: /reload while omnish run is active (needed for gatewayMode and telegramBotToken)."}]}function ci(){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: ${_}`}]}function uc(e){let t=["*Gateway status*","",`Mode: *${e.gatewayMode}*`,"- whatsapp \u2014 WhatsApp only","- telegram \u2014 Telegram only","- 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: ${Me(e.updateBrief)}`,""),t.push("Change: /gateway both \xB7 /gw tg","/updates \u2014 npm + optional notice URL",`Config: ${Me(_)}`);let n=["<b>Gateway status</b>","",`<b>${q(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> ${q(e.updateBrief)}`,""),n.push("<i>Change:</i> /gateway both \xB7 /gw tg","<i>/updates</i> \u2014 npm + optional notice URL",q(`Config: ${_}`)),de(t.join(`
|
|
38
38
|
`),n.join(`
|
|
39
|
-
`))}function
|
|
39
|
+
`))}function pr(e){let t=["*Update check*","",`Running: *${Me(e.runningVersion)}*`,`Checked (UTC): ${e.checkedAtIso}`,`npm package: ${Me(e.registryPackage)}`];e.registryError?t.push("",`Registry: ${Me(e.registryError)}`):e.registryLatest&&t.push("",e.updateAvailable?`*Newer version on npm:* ${Me(e.registryLatest)} (upgrade when ready).`:`npm latest: ${Me(e.registryLatest)} (this install is current or newer).`),e.infoError?t.push("",`Notice URL: ${Me(e.infoError)}`):e.infoMessage&&(t.push("",`Notice: ${Me(e.infoMessage)}`),e.infoLink&&t.push(Me(e.infoLink))),t.push("","Config: updateCheckEnabled, updateCheckIntervalMs, updateCheckPackageName, updateInfoUrl");let n=["<b>Update check</b>","",`<b>Running</b> <code>${q(e.runningVersion)}</code>`,`<b>Checked (UTC)</b> ${q(e.checkedAtIso)}`,`<b>npm package</b> <code>${q(e.registryPackage)}</code>`];return e.registryError?n.push("",`<b>Registry</b> ${q(e.registryError)}`):e.registryLatest&&n.push("",e.updateAvailable?`<b>Newer on npm</b> <code>${q(e.registryLatest)}</code>`:`<b>npm latest</b> <code>${q(e.registryLatest)}</code> (current or newer here)`),e.infoError?n.push("",`<b>Notice URL</b> ${q(e.infoError)}`):e.infoMessage&&(n.push("",`<b>Notice</b> ${q(e.infoMessage)}`),e.infoLink&&n.push(q(e.infoLink))),n.push("","<i>Config keys:</i> updateCheckEnabled, updateCheckIntervalMs, updateCheckPackageName, updateInfoUrl"),de(t.join(`
|
|
40
40
|
`),n.join(`
|
|
41
|
-
`))}function
|
|
41
|
+
`))}function dc(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: ${H} (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 ${_}`},{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 run --verbose."},{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 pc(e){let t=!!ve(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 ${_}, 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 ${_}; 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 mc(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})`,Me(o),""),n.push(`<b>${q(r.label)}</b> (${r.items.length})`,q(o),"")}return de(t.join(`
|
|
42
42
|
`).trimEnd(),n.join(`
|
|
43
|
-
`).trimEnd())}function
|
|
43
|
+
`).trimEnd())}function ui(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})`,Me(s),""),r.push(`<b>${q(o.label)}</b> (${o.items.length})`,q(s),"")}return de(n.join(`
|
|
44
44
|
`).trimEnd(),r.join(`
|
|
45
|
-
`).trimEnd())}function
|
|
45
|
+
`).trimEnd())}function fc(e){let t=["*Token saved*","","telegramBotToken written to config (not echoed).",`Config: ${Me(_)}`,...e.flatMap(r=>["",r]),"","Send /reload so the gateway picks it up."].join(`
|
|
46
46
|
`),n=["<b>Token saved</b>","","telegramBotToken written to config (not echoed).",q(`Config: ${_}`),...e.map(r=>`<i>${q(r)}</i>`),"","Send /reload so the gateway picks it up."].join(`
|
|
47
47
|
`)+`
|
|
48
|
-
`;return
|
|
48
|
+
`;return de(t.trimEnd(),n.trimEnd())}function hc(){return Z([{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 gc(e,t,n){let r=t?`
|
|
49
49
|
|
|
50
50
|
${t}`:n?`
|
|
51
51
|
|
|
@@ -59,72 +59,72 @@ Start omnish run on the host to apply (or /reload from a running gateway).`:"",s
|
|
|
59
59
|
${Me(_)}${r}`,i=`<b>gatewayMode saved</b>
|
|
60
60
|
|
|
61
61
|
<code>${q(e)}</code>
|
|
62
|
-
${q(_)}${o}`;return
|
|
62
|
+
${q(_)}${o}`;return de(s,i)}function yc(){return Z([{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 wc(){return Z([{kind:"title",text:"/deny \u2014 remove from allowlist"},{kind:"p",text:"Same forms as /allow: +E164 or tg:id"}])}function bc(){return Z([{kind:"title",text:"/bg \u2014 background job"},{kind:"p",text:"Usage: /bg [flags] <shell command>"},{kind:"bullet",text:"Optional name: /bg -n mybuild npm run build \xB7 /bg --name mybuild \u2026 \xB7 /bg --name=mybuild \u2026"},{kind:"bullet",text:"Notify on completion: /bg --notify <cmd> or /bg -N <cmd> \u2014 sends a message when the job finishes (with exit status)."},{kind:"bullet",text:"Combine flags: /bg -N -n deploy git pull && docker compose up -d"},{kind:"bullet",text:"Then use /log mybuild, /tail mybuild, /kill mybuild (or the 8-char id). Names: letters, digits, . _ - up to 64 chars."},{kind:"bullet",text:"Example: /bg sleep 30 && echo done"}])}function di(){return Z([{kind:"title",text:"/send \u2014 push a host file to this chat"},{kind:"p",text:"Usage: /send <selectors> [-- caption] \u2014 selectors resolve from session cwd."},{kind:"bullet",text:"/send ./photo.png"},{kind:"bullet",text:"/send ./clip1.mp4,./clip2.mp4 -- Launch set"},{kind:"bullet",text:"/send **/*.mp4"},{kind:"bullet",text:"/send /abs/path/report.pdf -- Q4 draft"},{kind:"bullet",text:"Selectors: file1,file2 | *.ext | **/*.ext"},{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 pi(){return Z([{kind:"title",text:"Files \u2014 send & receive"},{kind:"sub",text:"Host \u2192 chat"},{kind:"bullet",text:"/send <selectors> or /file \u2026 \u2014 selectors support file1,file2, *.ext, **/*.ext from 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 (${_}) 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 mi(){return Z([{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 kc(e,t){let n=Ql(t),r=oe(t),o="";try{o=Ut(e,t)}catch(s){o=`(${String(s)})`}return Z(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 Sc(){return Z([{kind:"title",text:"Unknown /wa command"},{kind:"p",text:"Send /wa help for setup."}])}function vc(){return Z([{kind:"title",text:"Unknown /tg command"},{kind:"p",text:"Send /tg help or /tg token <botfather_token>."}])}function xc(){return Z([{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 $c(e){return Z([{kind:"title",text:"Unknown command"},{kind:"p",text:`Try /help or ${e.commandPrefix}<command>.`},{kind:"gap"},...Tn(e)])}function Rc(e){return Z([{kind:"title",text:"No command matched"},{kind:"p",text:`Use ${JSON.stringify(e.commandPrefix)}, a slash command, or /apps help.`},{kind:"gap"},...Tn(e)])}function Cc(){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"},...ci()];return Z(e)}function fi(){return[{kind:"title",text:"Shortcuts (this gateway)"},{kind:"p",text:"Stored per-chat or shared for every chat on this gateway. Expansion: this chat wins, then shared. Bare token only \u2014 for task injection use /run recipes."},{kind:"p",text:"Scope flags: -g or --global = shared on this gateway; -p or --chat = private to this chat."},{kind:"gap"},{kind:"sub",text:"Manage"},{kind:"bullet",text:"/shortcut add <name> <command\u2026> \u2014 private by default; add -g|--global to share on this gateway"},{kind:"bullet",text:"/shortcut add -p|--chat <name> <command\u2026> \u2014 explicit private (this chat)"},{kind:"bullet",text:"/shortcut set <name> <command\u2026> \u2014 overwrite in chosen bucket; scope-only (same line): /shortcut set -g <name> or /shortcut set <name> -g (share); /shortcut set -p <name> or /shortcut set <name> -p (private)"},{kind:"bullet",text:"/shortcut list \u2014 merged view (/shortcuts); list --chat | -p | list --global | -g"},{kind:"bullet",text:"/shortcut show <name>; show --global|-g|--chat|-p to read one bucket"},{kind:"bullet",text:"/shortcut remove <name> \u2014 private bucket; remove --global|-g drops shared \xB7 rm, del \xB7 --chat|-p"},{kind:"bullet",text:"/shortcut <name> publish \u2014 share to online catalog (platform login)"},{kind:"bullet",text:"/shortcut online trending | show <publicId> | <publicId> download \u2014 shortcuts only"},{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 Mc(e){if(e.length===0)return p("(no shortcuts \u2014 /shortcut add <name> <command\u2026> or /shortcut add --global <name> <command\u2026>)");let t=e.every(l=>l.scope==="global"),n=e.every(l=>l.scope==="chat"),r=t?"_Shared (every chat)_":n?"_This chat only_":"_This chat + shared_",o=t?"<i>Shared (every chat)</i>":n?"<i>This chat only</i>":"<i>This chat + shared</i>",s=e.some(l=>l.scope==="chat")&&e.some(l=>l.scope==="global"),i=["*Shortcuts*",r,"",...e.map(l=>{let d=s?l.scope==="chat"?"[chat] ":"[global] ":"";return`${Re}\`${d}${l.name}\` \u2192 ${l.body}`})].join(`
|
|
63
63
|
`),a=["<b>Shortcuts</b>",o,"",...e.map(l=>{let u=`${s?l.scope==="chat"?"[chat] ":"[global] ":""}${l.name}`;return`\u2022 <code>${q(u)}</code> \u2192 ${q(l.body)}`})].join(`
|
|
64
|
-
`);return
|
|
64
|
+
`);return de(i,a)}function mr(e,t,n="chat"){return p(`Shortcut saved: ${e}
|
|
65
65
|
\u2192 ${t}
|
|
66
|
-
(${n==="global"?"Shared on this gateway (every chat unless this chat overrides the name).":"Stored for this chat only."})`)}function
|
|
66
|
+
(${n==="global"?"Shared on this gateway (every chat unless this chat overrides the name).":"Stored for this chat only."})`)}function Tc(e,t="chat"){return p(`Shortcut removed (${t==="global"?"shared":"this chat"}): ${e}`)}function Ec(e){return p(`Unknown shortcut: ${e}`)}function Pc(e,t){return p(`Unknown shortcut "${e}" in ${t==="global"?"shared shortcuts":"this chat"}.`)}function hi(e,t,n){let r=n?`
|
|
67
67
|
|
|
68
68
|
${n}`:"";return p(`${e}
|
|
69
|
-
\u2192 ${t}${r}`)}function
|
|
69
|
+
\u2192 ${t}${r}`)}function Ac(){return[{kind:"title",text:"/run \u2014 recipe templates"},{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 <name> <task\u2026> \u2014 short alias for /run"},{kind:"gap"},{kind:"sub",text:"Queue"},{kind:"bullet",text:"/run <name> -q <task\u2026> or /run <name> --queue <task\u2026> \u2014 FIFO per chat: head starts immediately; others wait in memory until the head exits cleanly (code=0, signal=0)"},{kind:"bullet",text:"Pending counts only jobs not yet started \u2014 the first queued item becomes Active right away, so /run queue can show Pending: 0 while a queued run is still executing"},{kind:"bullet",text:"/run queue \u2014 active session + recipe, numbered waiting list, paused flag"},{kind:"bullet",text:"/run queue resume \u2014 after a pause or non-clean exit, clear pause and start the next waiting item"},{kind:"bullet",text:"/run queue load <file.json> \u2014 enqueue jobs from JSON (paths relative to session cwd); /run queue load json [\u2026] \u2014 same payload inline; attach a file with caption /run queue load"},{kind:"bullet",text:'Queue JSON: [ { "recipe": "<name>", "task": "<text>" }, \u2026 ] or { "tasks": [ \u2026 ] } (max 64 jobs per load; same rules as /run <name> -q)'},{kind:"gap"},{kind:"sub",text:"Discover"},{kind:"bullet",text:"/run list \u2014 featured, gateway-shared, this chat, host templates; list --chat | -p | list --global | -g"},{kind:"bullet",text:"/run show <name> \u2014 merged resolution; show --global|-g|--chat|-p reads one user bucket"},{kind:"gap"},{kind:"sub",text:"Manage"},{kind:"p",text:"Recipe scope flags: -g or --global = shared on this gateway; -p or --chat = private to this chat."},{kind:"bullet",text:'/run add <name> <command\u2026> [--template "\u2026"] \u2014 this chat; add --global|-g share on this gateway'},{kind:"bullet",text:"/run set <name> <command\u2026> \u2014 overwrite in chosen bucket (--global|-g|--chat|-p); scope-only (same body): /run set -g <name> or /run set <name> -g (share); /run set -p <name> or /run set <name> -p (this chat only)"},{kind:"bullet",text:"/run remove <name> \u2014 this chat storage; remove --global|-g clears gateway-shared \xB7 rm, del \xB7 --chat|-p"},{kind:"gap"},{kind:"sub",text:"Notes"},{kind:"bullet",text:"Commands must reference the task env variable (default `$OMNISH_TASK`)."},{kind:"bullet",text:"Template placeholders `<<<OMNISH_TASK>>>`, `<<<```$OMNISH_TASK```>>>`, and `$OMNISH_TASK` are replaced with task text."},{kind:"bullet",text:"Host overrides file: "+jr},{kind:"bullet",text:"Built-in Claude recipes omit dangerous flags unless recipesAllowDangerousBuiltins=true."},{kind:"gap"},{kind:"sub",text:"Online catalog"},{kind:"bullet",text:"/run online trending | search <query> | show <publicId> | <publicId> download \u2014 all kinds"},{kind:"bullet",text:"/run <recipe> publish \u2014 share to platform (requires omnish platform login)"}]}function Gf(e){switch(e){case"builtin":return"built-in";case"global":return"host recipes.json";case"shared":return"gateway-shared (/run add --global)";case"peer":return"this chat (/run add)";default:return e}}function Ic(e){let t=["*Recipes*","`/run <name> <task>`",""],n=["<b>Recipes</b>","<code>/run <name> <task></code>",""],r=(o,s)=>{let i=o.description?` \u2014 ${o.description}`:"",a=s&&o.dangerous?" [dangerous flags]":"";t.push(`${Re}${o.name} \u2014 ${o.label??o.name}${i}${a}`);let l=o.description?` \u2014 ${q(o.description)}`:"",d=s&&o.dangerous?q(" [dangerous flags]"):"";n.push(`\u2022 ${q(o.name)} \u2014 ${q(o.label??o.name)}${l}${d}`)};if(e.featured.length>0){t.push("_Featured:_"),n.push("<i>Featured:</i>");for(let o of e.featured)r(o,!0);t.push(""),n.push("")}if(e.shared.length>0){t.push("_Shared (every chat):_"),n.push("<i>Shared (every chat):</i>");for(let o of e.shared)r(o,!1);t.push(""),n.push("")}if(e.yours.length>0){t.push("_This chat:_"),n.push("<i>This chat:</i>");for(let o of e.yours)r(o,!1);t.push(""),n.push("")}if(e.more.length>0){t.push("_More:_"),n.push("<i>More:</i>");for(let o of e.more)r(o,!1)}return e.featured.length===0&&e.shared.length===0&&e.yours.length===0&&e.more.length===0&&(t.push("(no recipes \u2014 add host file or /run add)"),n.push(q("(no recipes \u2014 add host file or /run add)"))),de(t.join(`
|
|
70
70
|
`).trimEnd(),n.join(`
|
|
71
|
-
`).trimEnd())}function
|
|
72
|
-
`))}function
|
|
73
|
-
`))}function
|
|
71
|
+
`).trimEnd())}function gi(e,t){let n=e.taskEnv??"OMNISH_TASK",r=[`Recipe: ${e.name}`,`Source: ${Gf(e.source)}`,`Label: ${e.label??"(none)"}`];if(e.steps&&e.steps.length>0){r.push(`Type: runbook (${e.steps.length} steps)`);for(let o=0;o<e.steps.length;o++){let s=e.steps[o],i=s.label?` (${s.label})`:"",a=s.continueOnFail?" [continue-on-fail]":"";r.push(` ${o+1}. ${s.cmd}${i}${a}`)}}else r.push(`Task env: ${n}`),r.push(`Command: ${e.command}`);if(e.promptTemplate){r.push(`Template: ${e.promptTemplate.length} chars`);let s=e.promptTemplate.replace(/\s+/g," ").trim().slice(0,200);r.push(`Preview: ${s}${e.promptTemplate.length>200?"\u2026":""}`)}return e.category&&r.push(`Category: ${e.category}`),e.description&&r.push(`Description: ${e.description}`),e.dangerous&&r.push("Note: built-in includes gated dangerous CLI flags."),t&&r.push("",t),p(r.join(`
|
|
72
|
+
`))}function fr(e,t,n="chat"){let r=n==="global"?"Shared on this gateway (every chat unless this chat overrides the name).":"Stored for this chat only.",o=[`Recipe saved: ${e}`,`\u2192 ${t.command}`,`(task env: ${t.taskEnv??"OMNISH_TASK"})`];return t.promptTemplate&&o.push(`Template stored: ${t.promptTemplate.length} chars`),o.push(`(${r})`),p(o.join(`
|
|
73
|
+
`))}function Oc(e,t="chat"){return p(`Recipe removed (${t==="global"?"gateway-shared storage":"this chat"}): ${e}`)}function Lc(e,t){return p(`Unknown recipe "${e}" in ${t==="global"?"gateway-shared storage":"this chat storage"}.`)}function Nc(e,t){let n=t==="global"?"_Gateway-shared recipes_":"_This chat recipes_",r=t==="global"?"<i>Gateway-shared recipes</i>":"<i>This chat recipes</i>";if(e.length===0)return p(t==="global"?"(no gateway-shared recipes \u2014 /run add --global <name> <command\u2026>)":"(no recipes in this chat \u2014 /run add <name> <command\u2026>)");let o=["*Recipes*",n,""],s=["<b>Recipes</b>",r,""];for(let i of e){let a=i.description?` \u2014 ${i.description}`:"";o.push(`${Re}${i.name} \u2014 ${i.label??i.name}${a}`);let l=i.description?` \u2014 ${q(i.description)}`:"";s.push(`\u2022 ${q(i.name)} \u2014 ${q(i.label??i.name)}${l}`)}return de(o.join(`
|
|
74
74
|
`).trimEnd(),s.join(`
|
|
75
|
-
`).trimEnd())}function
|
|
76
|
-
/run list`)}function
|
|
77
|
-
`)}function
|
|
78
|
-
`)}function
|
|
79
|
-
`));if(r==="show"){let i=$();return
|
|
75
|
+
`).trimEnd())}function yi(e){return p(`Unknown recipe: ${e}
|
|
76
|
+
/run list`)}function wi(){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:"bullet",text:"/apps <session> publish \u2014 share session command to online catalog"},{kind:"bullet",text:"/apps online trending | show <publicId> | <publicId> download \u2014 browse app templates only"},{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 when no focused PTY; !!stop \u2014 off. Attached session wins over free shell for plain text."}]}function Jf(e){let{errors:t,warns:n,infos:r}=li(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:Me(`[${d}] ${l.code}: ${l.message}`)}),l.detail&&o.push({kind:"bullet",text:Me(l.detail)}),l.fixHint&&o.push({kind:"bullet",text:Me(`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 _c(e){return Z(Jf(e))}function Fc(){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 Wc(){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"}]}function Se(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function En(e){let t=e.trim();return t?t.length<=8?"(set)":`${t.slice(0,4)}\u2026${t.slice(-4)}`:"(empty)"}function Uc(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 Je(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 Dc=new Set(["downloads","omnishData","sessionCwd","processCwd","fixed"]),Gt=["gatewayMode","clusterEnabled","clusterRole","clusterLabel","clusterSenderBindings","commandPrefix","syncTimeoutMs","syncMaxBytes","jobLogTailLines","shell","appsCols","appsRows","appsFlushMs","appsMinIntervalMs","appsMaxFlushBytes","appsMaxSessions","appsMaxSessionsTotal","appsMaxWaChars","appsLogTailLines","appsSubmitDelayMs","appsClearInput","appsClearInputDelayMs","appsClearInputSequence","appsSkipClearOnPasswordPrompt","appsPasswordPromptHint","fileSendMaxBytes","fileReceiveMaxBytes","fileInboxSubdir","fileReceiveRootMode","fileReceiveRootPath","recipesAllowDangerousBuiltins","recipesMaxTaskChars","recipesMacroDefaultCommand","telegramBotToken","serviceInstallFromChat","updateCheckEnabled","updateCheckIntervalMs","updateCheckPackageName","updateInfoUrl","chatLlmFallbackEnabled","chatLlmShellCommand","chatLlmTimeoutMs","chatLlmMaxInputChars","chatLlmMaxOutputChars","chatLlmNeedsTty","chatLlmWorkDir","tunnelEnabled","tunnelRelayUrl","tunnelMaxActive","webhookEnabled","webhookPort","webhookHost","webhookToken","watchEnabled","watchDebounceMs","watchMaxEventsPerMinute","watchAutoRestore"];function Hc(e){return Gt.includes(e)}function Kf(e){let t=ve(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: ${En(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}`,`appsSkipClearOnPasswordPrompt: ${e.appsSkipClearOnPasswordPrompt}`,`appsPasswordPromptHint: ${e.appsPasswordPromptHint}`,"","*Files*",`fileSendMaxBytes / fileReceiveMaxBytes: ${e.fileSendMaxBytes} / ${e.fileReceiveMaxBytes}`,`fileInboxSubdir: ${e.fileInboxSubdir}`,`fileReceiveRootMode: ${e.fileReceiveRootMode}`,`fileReceiveRootPath: ${e.fileReceiveRootPath||"(empty)"}`,"","*Recipes*",`recipesAllowDangerousBuiltins: ${e.recipesAllowDangerousBuiltins}`,`recipesMaxTaskChars: ${e.recipesMaxTaskChars}`,`recipesMacroDefaultCommand: ${e.recipesMacroDefaultCommand}`,"","*Service (chat)*",`serviceInstallFromChat: ${e.serviceInstallFromChat}`,"","*Updates (optional)*",`updateCheckEnabled: ${e.updateCheckEnabled}`,`updateCheckIntervalMs: ${e.updateCheckIntervalMs}`,`updateCheckPackageName: ${e.updateCheckPackageName}`,`updateInfoUrl: ${e.updateInfoUrl?"(set)":"(empty)"}`,"","*Tunneling (chat /tunnel)*",`tunnelEnabled: ${e.tunnelEnabled}`,`tunnelRelayUrl: ${e.tunnelRelayUrl}`,`tunnelMaxActive: ${e.tunnelMaxActive}`,"","*Chat LLM fallback (optional)*",`chatLlmFallbackEnabled: ${e.chatLlmFallbackEnabled}`,`chatLlmShellCommand: ${e.chatLlmShellCommand?"(set)":"(empty)"}`,`chatLlmTimeoutMs: ${e.chatLlmTimeoutMs}`,`chatLlmMaxInputChars / chatLlmMaxOutputChars: ${e.chatLlmMaxInputChars} / ${e.chatLlmMaxOutputChars}`,`chatLlmNeedsTty: ${e.chatLlmNeedsTty}`,`chatLlmWorkDir: ${e.chatLlmWorkDir||"(empty \u2014 temp dir per run)"}`,"","*Webhook receiver (optional)*",`webhookEnabled: ${e.webhookEnabled}`,`webhookPort: ${e.webhookPort} (0 = random)`,`webhookHost: ${e.webhookHost}`,`webhookToken: ${En(e.webhookToken)}`,"","*Watch (OS event eye)*",`watchEnabled: ${e.watchEnabled}`,`watchDebounceMs: ${e.watchDebounceMs}`,`watchMaxEventsPerMinute: ${e.watchMaxEventsPerMinute}`,`watchAutoRestore: ${e.watchAutoRestore}`,"",`File: ${_}`].join(`
|
|
77
|
+
`)}function zf(e){let t=ve(e);return["<b>Config</b> (secrets masked)","",`<b>gatewayMode</b> ${Se(e.gatewayMode)}`,`<b>commandPrefix</b> ${Se(e.commandPrefix)}`,`<b>shell</b> ${Se(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: ${Se(e.clusterRole)}`,`clusterLabel: ${Se(e.clusterLabel||"(hostname)")}`,`clusterSenderBindings: ${Object.keys(e.clusterSenderBindings??{}).length} entries`,"","<b>Telegram</b>",`telegramBotToken: ${Se(En(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>",`${Se(e.fileReceiveRootMode)} \xB7 inbox ${Se(e.fileInboxSubdir)}`,"","<b>Service (chat)</b>",`serviceInstallFromChat: ${e.serviceInstallFromChat}`,"","<b>Updates (optional)</b>",`updateCheckEnabled: ${e.updateCheckEnabled} \xB7 interval ms: ${e.updateCheckIntervalMs}`,`package: <code>${Se(e.updateCheckPackageName)}</code> \xB7 info URL: ${e.updateInfoUrl?"set":"empty"}`,"","<b>Tunneling (chat /tunnel)</b>",`tunnelEnabled: ${e.tunnelEnabled} \xB7 relay <code>${Se(e.tunnelRelayUrl)}</code> \xB7 max active: ${e.tunnelMaxActive}`,"","<b>Chat LLM fallback</b>",`enabled: ${e.chatLlmFallbackEnabled} \xB7 command: ${e.chatLlmShellCommand?"set":"empty"}`,`timeout ms: ${e.chatLlmTimeoutMs} \xB7 in/out chars: ${e.chatLlmMaxInputChars} / ${e.chatLlmMaxOutputChars}`,`needsTty: ${e.chatLlmNeedsTty} \xB7 workDir: ${Se(e.chatLlmWorkDir||"(empty)")}`,"","<b>Webhook receiver</b>",`enabled: ${e.webhookEnabled} \xB7 ${Se(e.webhookHost)}:${e.webhookPort} \xB7 token: ${Se(En(e.webhookToken))}`,"","<b>Watch (OS event eye)</b>",`enabled: ${e.watchEnabled} \xB7 debounce ms: ${e.watchDebounceMs} \xB7 max/min: ${e.watchMaxEventsPerMinute} \xB7 autoRestore: ${e.watchAutoRestore}`,"",`<code>${Se(_)}</code>`].join(`
|
|
78
|
+
`)}function Bc(e,t){if(!Hc(t))return null;let n=t;if(n==="telegramBotToken")return`telegramBotToken: ${En(ve(e))}`;if(n==="webhookToken")return`webhookToken: ${En(e.webhookToken)}`;let r=e[n];return`${t}: ${typeof r=="object"?JSON.stringify(r):String(r)}`}function qf(e,t){let n=Bc(e,t);if(!n)return null;let r=n.split(": ");return r.length<2?Se(n):`<b>${Se(r[0])}</b> ${Se(r.slice(1).join(": "))}`}function ho(e,t){let n=Uc(t),r=!1,o=!1,s=!1;if(e==="telegramBotToken"){if(!pt(n))throw new Error("Invalid bot token format (expect digits:secret from BotFather).");return Nt(n),r=!0,s=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s}}let i=$();switch(e){case"gatewayMode":{let a=Sn(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=Je(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[u,c]of Object.entries(l)){if(typeof c!="string"||!c.trim())throw new Error(`clusterSenderBindings.${u}: value must be a non-empty string`);d[u]=c.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"recipesMacroDefaultCommand":if(!n.trim())throw new Error('recipesMacroDefaultCommand: non-empty shell snippet with "$OMNISH_TASK"');i.recipesMacroDefaultCommand=Uc(n).trim().slice(0,4096);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=Je(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"appsSkipClearOnPasswordPrompt":{let a=Je(n);if(a===null)throw new Error("appsSkipClearOnPasswordPrompt: true or false");i.appsSkipClearOnPasswordPrompt=a;break}case"appsPasswordPromptHint":{let a=Je(n);if(a===null)throw new Error("appsPasswordPromptHint: true or false");i.appsPasswordPromptHint=a;break}case"fileInboxSubdir":i.fileInboxSubdir=n.trim().slice(0,80);break;case"fileReceiveRootMode":{let a=n.trim();if(!Dc.has(a))throw new Error(`fileReceiveRootMode: ${[...Dc].join(" | ")}`);i.fileReceiveRootMode=a;break}case"fileReceiveRootPath":i.fileReceiveRootPath=n.trim().slice(0,4096);break;case"recipesAllowDangerousBuiltins":{let a=Je(n);if(a===null)throw new Error("recipesAllowDangerousBuiltins: true or false");i.recipesAllowDangerousBuiltins=a;break}case"serviceInstallFromChat":{let a=Je(n);if(a===null)throw new Error("serviceInstallFromChat: true or false");i.serviceInstallFromChat=a;break}case"updateCheckEnabled":{let a=Je(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;case"tunnelEnabled":{let a=Je(n);if(a===null)throw new Error("tunnelEnabled: true or false");return W({tunnelEnabled:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"tunnelRelayUrl":{let a=n.trim();if(!a)throw new Error("tunnelRelayUrl: non-empty URL");let l;try{l=new URL(a)}catch{throw new Error("tunnelRelayUrl: invalid URL")}if(l.protocol!=="http:"&&l.protocol!=="https:")throw new Error("tunnelRelayUrl: use http:// or https://");return W({tunnelRelayUrl:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"tunnelMaxActive":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<1||a>50)throw new Error("tunnelMaxActive: integer 1\u201350");return W({tunnelMaxActive:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"chatLlmFallbackEnabled":{let a=Je(n);if(a===null)throw new Error("chatLlmFallbackEnabled: true or false");return W({chatLlmFallbackEnabled:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"chatLlmShellCommand":return W({chatLlmShellCommand:n}),{reloadSuggested:r,shellWarning:o,tokenSaved:s};case"chatLlmTimeoutMs":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<=0)throw new Error("chatLlmTimeoutMs: positive integer (ms)");return W({chatLlmTimeoutMs:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"chatLlmMaxInputChars":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<=0)throw new Error("chatLlmMaxInputChars: positive integer");return W({chatLlmMaxInputChars:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"chatLlmMaxOutputChars":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<=0)throw new Error("chatLlmMaxOutputChars: positive integer");return W({chatLlmMaxOutputChars:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"chatLlmNeedsTty":{let a=Je(n);if(a===null)throw new Error("chatLlmNeedsTty: true or false");return W({chatLlmNeedsTty:a}),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"chatLlmWorkDir":return W({chatLlmWorkDir:n.trim()}),{reloadSuggested:r,shellWarning:o,tokenSaved:s};case"webhookEnabled":{let a=Je(n);if(a===null)throw new Error("webhookEnabled: true or false");return W({webhookEnabled:a}),r=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"webhookPort":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<0||a>65535)throw new Error("webhookPort: integer 0\u201365535 (0 = random free port)");return W({webhookPort:a}),r=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"webhookHost":if(!n.trim())throw new Error("webhookHost: non-empty bind address");return W({webhookHost:n.trim().slice(0,256)}),r=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s};case"webhookToken":return W({webhookToken:n.trim()}),r=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s};case"watchEnabled":{let a=Je(n);if(a===null)throw new Error("watchEnabled: true or false");return W({watchEnabled:a}),De(),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"watchDebounceMs":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<500||a>6e4)throw new Error("watchDebounceMs: integer 500\u201360000");return W({watchDebounceMs:a}),De(),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"watchMaxEventsPerMinute":{let a=Number.parseInt(n.trim(),10);if(!Number.isFinite(a)||a<1||a>120)throw new Error("watchMaxEventsPerMinute: integer 1\u2013120");return W({watchMaxEventsPerMinute:a}),De(),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}case"watchAutoRestore":{let a=Je(n);if(a===null)throw new Error("watchAutoRestore: true or false");return W({watchAutoRestore:a}),De(),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}}return _e(i),{reloadSuggested:r,shellWarning:o,tokenSaved:s}}async function jc(e,t){let n=e.trim(),r=n.toLowerCase();if(!n||r==="help")return Z(cc());if(r==="keys"||r==="help keys")return p(["*Configurable keys* (/config set)","",Gt.join(", "),"","Examples:","/config set clusterLabel work-laptop",'/config set fileReceiveRootPath "/path/with spaces"',"/config set gatewayMode both","/config set tunnelEnabled true","/config set chatLlmFallbackEnabled false","/config set webhookEnabled true","/config set watchEnabled true"].join(`
|
|
79
|
+
`));if(r==="show"){let i=$();return de(Kf(i),zf(i))}let o=n.match(/^get\s+(\S+)\s*$/i);if(o){let i=o[1],a=$(),l=Bc(a,i);if(!l)return p(`Unknown key "${i}". /config keys`);let d=qf(a,i);return de(`${l}
|
|
80
80
|
|
|
81
|
-
${_}`,`${d}<br/><br/><code>${Se(_)}</code>`)}let s=n.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(s){let i=s[1],a=s[2]??"";if(!
|
|
81
|
+
${_}`,`${d}<br/><br/><code>${Se(_)}</code>`)}let s=n.match(/^set\s+(\S+)\s+([\s\S]+)$/i);if(s){let i=s[1],a=s[2]??"";if(!Hc(i))return p(`Unknown key "${i}". /config keys`);try{let{reloadSuggested:l,shellWarning:d,tokenSaved:u}=ho(i,a),c="";if(t?.reload&&l){let y=await t.reload();c=y.ok?`
|
|
82
82
|
Reload: ${y.summary}`:`
|
|
83
83
|
Reload failed: ${y.error}`}else l?c=`
|
|
84
84
|
Send /reload while omnish run is active (gatewayMode / Telegram).`:c=`
|
|
85
85
|
Send /reload to pick up changes where applicable.`;let m=d?`
|
|
86
86
|
\u26A0 shell changed \u2014 affects all commands run via omnish.`:"",f=u?`
|
|
87
|
-
telegramBotToken saved (not echoed).`:"",h=`Set *${i}* (saved).${f}${m}${c}`,g=`<b>Set ${Se(i)}</b> (saved).${f?"<br/>token saved (not echoed).":""}${d?"<br/>\u26A0 shell path changed.":""}${Se(c)}`;return
|
|
87
|
+
telegramBotToken saved (not echoed).`:"",h=`Set *${i}* (saved).${f}${m}${c}`,g=`<b>Set ${Se(i)}</b> (saved).${f?"<br/>token saved (not echoed).":""}${d?"<br/>\u26A0 shell path changed.":""}${Se(c)}`;return de(h,g)}catch(l){return p(`Error: ${String(l)}`)}}return p("Unknown /config command. Try /config help or /config show")}me();var bi=[...Gt,"platformToken","platformDeviceId"],ki={platform_url:"tunnelRelayUrl",tunnel_relay_url:"tunnelRelayUrl",platform_token:"platformToken",token:"platformToken",omnish_token:"platformToken",platform_device_id:"platformDeviceId",device_id:"platformDeviceId"};for(let e of bi)ki[e]=e;function go(e){let t=e.trim().toLowerCase().replace(/-/g,"_");return ki[t]??null}function Gc(){return Object.keys(ki).sort()}function Ke(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}function Yf(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 Qf(e){return N[e]}function Pn(e,t){let n=Yf(t),r=$();switch(e){case"platformToken":return W({platformToken:n});case"platformDeviceId":return W({platformDeviceId:n});case"gatewayMode":{let o=Sn(n);if(!o)throw new Error('gatewayMode: "whatsapp", "telegram", or "both"');return r.gatewayMode=o,_e(r),r}case"telegramBotToken":if(!pt(n))throw new Error("telegramBotToken: invalid bot token format");return Nt(n);case"tunnelRelayUrl":{let o=n.trim();if(!o)throw new Error("tunnelRelayUrl: non-empty URL");let s;try{s=new URL(o)}catch{throw new Error("tunnelRelayUrl: invalid URL")}if(s.protocol!=="http:"&&s.protocol!=="https:")throw new Error("tunnelRelayUrl: use http:// or https://");return W({tunnelRelayUrl:o})}case"tunnelEnabled":{let o=Ke(n);if(o===null)throw new Error("tunnelEnabled: true or false");return W({tunnelEnabled:o})}case"tunnelMaxActive":{let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<1||o>50)throw new Error("tunnelMaxActive: integer 1\u201350");return W({tunnelMaxActive:o})}case"clusterSenderBindings":{let o;try{o=JSON.parse(n)}catch{throw new Error("clusterSenderBindings: valid JSON object")}if(!o||typeof o!="object"||Array.isArray(o))throw new Error("clusterSenderBindings: JSON object required");return W({clusterSenderBindings:o})}default:break}if(e==="clusterEnabled"){let o=Ke(n);if(o===null)throw new Error("clusterEnabled: true or false");r.clusterEnabled=o}else if(e==="clusterRole"){if(n!=="primary"&&n!=="secondary")throw new Error('clusterRole: "primary" or "secondary"');r.clusterRole=n}else if(e==="clusterLabel")r.clusterLabel=n.trim().slice(0,64);else if(e==="commandPrefix"){if(!n)throw new Error("commandPrefix: non-empty");r.commandPrefix=n}else if(e==="shell"){if(!n)throw new Error("shell: non-empty path");r.shell=n}else if(e==="syncTimeoutMs"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<=0)throw new Error("syncTimeoutMs: positive integer");r.syncTimeoutMs=o}else if(e==="syncMaxBytes"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<=0)throw new Error("syncMaxBytes: positive integer");r.syncMaxBytes=o}else if(e==="jobLogTailLines"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<=0)throw new Error("jobLogTailLines: positive integer");r.jobLogTailLines=o}else if(e==="appsCols"||e==="appsRows"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<20)throw new Error(`${e}: integer >= 20`);r[e]=o}else if(e==="appsFlushMs"||e==="appsMinIntervalMs"||e==="appsMaxFlushBytes"||e==="appsMaxWaChars"||e==="appsLogTailLines"||e==="appsSubmitDelayMs"||e==="appsClearInputDelayMs"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<0)throw new Error(`${e}: non-negative integer`);r[e]=o}else if(e==="appsMaxSessions"||e==="appsMaxSessionsTotal"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<1)throw new Error(`${e}: positive integer`);r[e]=o}else if(e==="appsClearInput"){let o=Ke(n);if(o===null)throw new Error("appsClearInput: true or false");r.appsClearInput=o}else if(e==="appsClearInputSequence")r.appsClearInputSequence=n;else if(e==="appsSkipClearOnPasswordPrompt"){let o=Ke(n);if(o===null)throw new Error("appsSkipClearOnPasswordPrompt: true or false");r.appsSkipClearOnPasswordPrompt=o}else if(e==="appsPasswordPromptHint"){let o=Ke(n);if(o===null)throw new Error("appsPasswordPromptHint: true or false");r.appsPasswordPromptHint=o}else if(e==="fileSendMaxBytes"||e==="fileReceiveMaxBytes"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<0)throw new Error(`${e}: non-negative integer`);r[e]=o}else if(e==="fileInboxSubdir")r.fileInboxSubdir=n.trim().slice(0,128);else if(e==="fileReceiveRootMode"){if(!new Set(["downloads","omnishData","sessionCwd","processCwd","fixed"]).has(n))throw new Error("fileReceiveRootMode: downloads|omnishData|sessionCwd|processCwd|fixed");r.fileReceiveRootMode=n}else if(e==="fileReceiveRootPath")r.fileReceiveRootPath=n.trim().slice(0,4096);else if(e==="recipesAllowDangerousBuiltins"){let o=Ke(n);if(o===null)throw new Error("recipesAllowDangerousBuiltins: true or false");r.recipesAllowDangerousBuiltins=o}else if(e==="recipesMaxTaskChars"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<0)throw new Error("recipesMaxTaskChars: non-negative integer");r.recipesMaxTaskChars=o}else if(e==="recipesMacroDefaultCommand"){if(!n.includes("$OMNISH_TASK"))throw new Error('recipesMacroDefaultCommand: must include "$OMNISH_TASK"');r.recipesMacroDefaultCommand=n}else if(e==="serviceInstallFromChat"){let o=Ke(n);if(o===null)throw new Error("serviceInstallFromChat: true or false");r.serviceInstallFromChat=o}else if(e==="updateCheckEnabled"){let o=Ke(n);if(o===null)throw new Error("updateCheckEnabled: true or false");r.updateCheckEnabled=o}else if(e==="updateCheckIntervalMs"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<36e5)throw new Error("updateCheckIntervalMs: min 3600000");r.updateCheckIntervalMs=Math.min(6048e5,o)}else if(e==="updateCheckPackageName"){if(!n.trim())throw new Error("updateCheckPackageName: non-empty");r.updateCheckPackageName=n.trim().slice(0,214)}else if(e==="updateInfoUrl")r.updateInfoUrl=n.trim().slice(0,2048);else if(e==="chatLlmFallbackEnabled"){let o=Ke(n);if(o===null)throw new Error("chatLlmFallbackEnabled: true or false");return W({chatLlmFallbackEnabled:o})}else{if(e==="chatLlmShellCommand")return W({chatLlmShellCommand:n});if(e==="chatLlmTimeoutMs"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<=0)throw new Error("chatLlmTimeoutMs: positive integer");return W({chatLlmTimeoutMs:o})}else if(e==="chatLlmMaxInputChars"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<=0)throw new Error("chatLlmMaxInputChars: positive integer");return W({chatLlmMaxInputChars:o})}else if(e==="chatLlmMaxOutputChars"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<=0)throw new Error("chatLlmMaxOutputChars: positive integer");return W({chatLlmMaxOutputChars:o})}else if(e==="chatLlmNeedsTty"){let o=Ke(n);if(o===null)throw new Error("chatLlmNeedsTty: true or false");return W({chatLlmNeedsTty:o})}else{if(e==="chatLlmWorkDir")return W({chatLlmWorkDir:n.trim()});if(e==="webhookEnabled"){let o=Ke(n);if(o===null)throw new Error("webhookEnabled: true or false");return W({webhookEnabled:o})}else if(e==="webhookPort"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<0||o>65535)throw new Error("webhookPort: integer 0\u201365535");return W({webhookPort:o})}else if(e==="webhookHost"){if(!n.trim())throw new Error("webhookHost: non-empty");return W({webhookHost:n.trim().slice(0,256)})}else{if(e==="webhookToken")return W({webhookToken:n.trim()});if(e==="watchEnabled"){let o=Ke(n);if(o===null)throw new Error("watchEnabled: true or false");return W({watchEnabled:o})}else if(e==="watchDebounceMs"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<500||o>6e4)throw new Error("watchDebounceMs: integer 500\u201360000");return W({watchDebounceMs:o})}else if(e==="watchMaxEventsPerMinute"){let o=Number.parseInt(n,10);if(!Number.isFinite(o)||o<1||o>120)throw new Error("watchMaxEventsPerMinute: integer 1\u2013120");return W({watchMaxEventsPerMinute:o})}else if(e==="watchAutoRestore"){let o=Ke(n);if(o===null)throw new Error("watchAutoRestore: true or false");return W({watchAutoRestore:o})}else throw new Error(`Unsupported key: ${e}`)}}}return _e(r),r}function Jc(e){let t=Qf(e);if(e==="platformToken"||e==="platformDeviceId")return W({[e]:t});if(e==="tunnelRelayUrl")return W({tunnelRelayUrl:t});let n=$();return n[e]=t,_e(n),n}function sn(e,t){if(e==="platformToken"||e==="telegramBotToken"||e==="webhookToken"){let n=t.trim();return n?n.length<=8?"(set)":`${n.slice(0,4)}\u2026${n.slice(-4)}`:"(empty)"}return t}me();G();import An from"node:fs";import $i from"node:os";import hr from"node:path";import Yc from"node:crypto";var vi="\u2063omnish/c v1",Vf=/([nlra])=([^\s\]]*)/g;function ot(e){return e.replace(/-/g,"").slice(0,8)}function Si(e){return e.replace(/[\s\]\r\n]/g,"_").slice(0,64)}function Xf(e){let t=Si(ot(e.nodeId)),n=Si(e.label||""),r=e.role==="primary"?"p":"s",o=Si(e.activeNodeId?ot(e.activeNodeId):"");return`${vi} [n=${t} l=${n} r=${r} a=${o}]`}function Kc(e,t){let n=Xf(t);if(e.includes(n))return e;let r=e.replace(/\s+$/,"");return r.length===0?n:`${r}
|
|
88
88
|
|
|
89
|
-
${n}`}function
|
|
90
|
-
`,{mode:384}),t}function
|
|
91
|
-
`,o=
|
|
89
|
+
${n}`}function zc(e){if(!e||!e.includes(vi))return null;let t=e.indexOf(vi),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(Vf))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 Qc=3,Zf="node-id",eh="cluster-local.json",qc=8;function Vc(){return hr.join(H,eh)}function Ri(){return hr.join(H,Zf)}function Xe(){j(H);let e=Ri();try{if(An.existsSync(e)){let n=An.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=Yc.randomUUID();return An.writeFileSync(e,`${t}
|
|
90
|
+
`,{mode:384}),t}function Xc(){return{schemaVersion:Qc,updatedAt:new Date().toISOString(),peers:[],senderBindings:{}}}function th(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 ge(){let e=Vc();try{let t=An.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=th(n.senderBindings);return{schemaVersion:Qc,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:new Date().toISOString(),peers:r,senderBindings:o}}catch{return Xc()}}function nh(e,t){let n=hr.dirname(e);j(n);let r=`${JSON.stringify(t,null,2)}
|
|
91
|
+
`,o=hr.join(n,`.${hr.basename(e)}.tmp.${process.pid}.${Yc.randomBytes(4).toString("hex")}`);An.writeFileSync(o,r,{mode:384}),An.renameSync(o,e)}function Mi(e){let t=Vc(),n=Xc();for(let r=0;r<qc;r++){n=ge(),e(n),n.updatedAt=new Date().toISOString();try{return nh(t,n),n}catch{}}throw new Error(`Could not write cluster local state after ${qc} attempts: ${t}`)}function Zc(e){return(e.clusterLabel??"").trim()||$i.hostname()}function ye(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function eu(e,t){let n=e.peers.findIndex(r=>r.nodeId===t.nodeId);n>=0?e.peers[n]=t:e.peers.push(t)}function gr(e){return{nodeId:ot(Xe()),label:Zc(e),role:e.clusterRole,lastSeenIso:new Date().toISOString()}}function tu(e,t,n){let r=n.trim();if(!r)return{ok:!1,reason:"not-found"};let o=gr(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 Mt(e,t){let n=ge(),r=n.senderBindings[t];if(r&&r.nodeId)return r;let o=e.clusterSenderBindings?.[t];if(typeof o=="string"&&o.trim()){let s=tu(n,e,o);if(s.ok)return{senderKey:t,nodeId:s.peer.nodeId,sinceIso:new Date(0).toISOString(),source:"config"}}return null}function Ci(e,t,n="chat"){let r=$(),o=ge(),s=tu(o,r,t);if(!s.ok)return{state:o,resolved:s};let i=new Date().toISOString();return{state:Mi(l=>{l.senderBindings[e]={senderKey:e,nodeId:s.peer.nodeId,sinceIso:i,source:n},eu(l,{...s.peer,lastSeenIso:i})}),resolved:s}}function rh(e){let t=null;return{state:Mi(r=>{r.senderBindings[e]&&(t=r.senderBindings[e]??null,delete r.senderBindings[e])}),removed:t}}function nu(e,t){let n=ot(Xe()),r=new Date().toISOString();return Mi(o=>{if(eu(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 ru(e,t){let n=Mt(t,e);return n?n.nodeId===ot(Xe()):!1}function oh(e,t){let n=gr(t).nodeId,r=new Set([n]);for(let s of e.peers)r.add(s.nodeId);return[...r].sort()[0]??n}function He(e,t){return oh(e,t)===ot(Xe())}function yo(e,t,n){let r=ot(Xe()),o=["*Computers*",""],s=n?Mt(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,gr(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(`
|
|
92
92
|
`);for(let l of a){let d=l.nodeId===r,c=[(s?l.nodeId===s.nodeId:!1)?"your binding":null,d?"you":null].filter(Boolean).join(", "),m=c?` (${c})`:"";o.push(`${Re}*${l.label}*${m}
|
|
93
93
|
id \`${l.nodeId}\` \xB7 role ${l.role}
|
|
94
94
|
seen ${l.lastSeenIso}`)}return o.push(""),o.push(`Updated: ${e.updatedAt}`),o.join(`
|
|
95
|
-
`)}function
|
|
95
|
+
`)}function xi(e,t,n){let r=ot(Xe()),o=["<b>Computers</b>",""],s=n?Mt(t,n):null;n&&(s?o.push(`Your binding: <code>${ye(s.nodeId)}</code> (${ye(s.source)})`):o.push("Your binding: (none \u2014 send /c use <label-or-id>)"),o.push(""));let i=new Map;i.set(r,gr(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(`
|
|
96
96
|
`);for(let l of a){let d=l.nodeId===r,c=[(s?l.nodeId===s.nodeId:!1)?"your binding":null,d?"you":null].filter(Boolean).join(", "),m=c?` (${ye(c)})`:"";o.push(`\u2022 <b>${ye(l.label)}</b>${m}<br/> id <code>${ye(l.nodeId)}</code> \xB7 role ${ye(l.role)}<br/> seen ${ye(l.lastSeenIso)}`)}return o.push(""),o.push(`Updated: ${ye(e.updatedAt)}`),o.join(`
|
|
97
|
-
`)}function
|
|
98
|
-
`),c=["<b>This computer</b>","",`label: ${ye(i)}`,`node id: <code>${ye(r)}</code> (full id in ${ye(
|
|
99
|
-
`);return{wa:u,tg:c}}function
|
|
97
|
+
`)}function Ti(e,t,n){return yo(e,t,n??null).replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1")}function Ei(e,t){let n=Xe(),r=ot(n),o=ge(),s=e.clusterRole,i=Zc(e),a=t?Mt(e,t):null,l=a?a.nodeId===r:!1,d=t?a?`your binding: ${a.nodeId} (${a.source}${l?", here":""})`:"your binding: (none)":"",u=["*This computer*","",`label: ${i}`,`node id: \`${r}\` (full id in ${Ri()})`,`host: ${$i.hostname()}`,`clusterRole: ${s}`,d,`peers known: ${o.peers.length}`,`senderBindings (chat): ${Object.keys(o.senderBindings).length}`].filter(Boolean).join(`
|
|
98
|
+
`),c=["<b>This computer</b>","",`label: ${ye(i)}`,`node id: <code>${ye(r)}</code> (full id in ${ye(Ri())})`,`host: ${ye($i.hostname())}`,`clusterRole: ${ye(s)}`,t?ye(d):"",`peers known: ${o.peers.length}`,`senderBindings (chat): ${Object.keys(o.senderBindings).length}`].filter(Boolean).join(`
|
|
99
|
+
`);return{wa:u,tg:c}}function sh(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","",`${Re}/c use <label-or-id> \u2014 bind your messages to that machine`,`${Re}/c here \u2014 bind your messages to THIS machine`,`${Re}/c using \u2014 show your current binding`,`${Re}/c unuse \u2014 clear your chat-set binding (config default still applies, if any)`,`${Re}/c status \u2014 every online host replies with its own paragraph`,`${Re}/c list \u2014 locally known roster (single responder)`,`${Re}/c help \u2014 this help`,"",`clusterRole on this host: ${t}`].join(`
|
|
100
100
|
`),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 <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","\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: ${ye(t)}`].join(`
|
|
101
|
-
`);return
|
|
102
|
-
`),g=[`<b>Bound to ${ye(c.peer.label)}</b>`,`id <code>${ye(c.peer.nodeId)}</code>`,"","Your messages now route to this machine. Other senders are not affected.","",
|
|
103
|
-
`);return
|
|
104
|
-
`),u=["<b>Bound to this machine.</b>","","Your messages now route here. Other senders are not affected.","",
|
|
105
|
-
`);return
|
|
101
|
+
`);return de(n,r)}function ih(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 ou(e,t,n){let r=t.trim().split(/\s+/),o=r[0]?.toLowerCase()??"";if(!o||o==="help"){if(!e.clusterEnabled&&o!=="help"){let l=ge();return He(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=ge();return He(a,e)?sh(e):null}let s=ot(Xe());if(o==="use"||o==="bind"){let a=r.slice(1).join(" ").trim();if(!n){let y=ge();return He(y,e)?p("/c use is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}if(!a){let y=ge();return He(y,e)?p("Usage: /c use <label-or-id>"):null}e.clusterEnabled||Zr(!0);let d=ge().senderBindings[n]??null,{state:u,resolved:c}=Ci(n,a,"chat");if(!c.ok)return He(u,e)?ih(a,c):null;let m=c.peer.nodeId===s,f=d?d.nodeId===s:!1;if(!m)return null;let h=[`*Bound to ${c.peer.label}*`,`id \`${c.peer.nodeId}\``,"","Your messages now route to this machine. Other senders are not affected.","",yo(u,e,n)].join(`
|
|
102
|
+
`),g=[`<b>Bound to ${ye(c.peer.label)}</b>`,`id <code>${ye(c.peer.nodeId)}</code>`,"","Your messages now route to this machine. Other senders are not affected.","",xi(u,e,n)].join(`
|
|
103
|
+
`);return de(h,g)}if(o==="here"||o==="take"){if(!n){let c=ge();return He(c,e)?p("/c here is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}e.clusterEnabled||Zr(!0);let{state:a,resolved:l}=Ci(n,s,"chat");if(!l.ok)return He(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.","",yo(a,e,n)].join(`
|
|
104
|
+
`),u=["<b>Bound to this machine.</b>","","Your messages now route here. Other senders are not affected.","",xi(a,e,n)].join(`
|
|
105
|
+
`);return de(d,u)}if(o==="using"){if(!n){let d=ge();return He(d,e)?p("/c using is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}let a=Mt(e,n);if(a){if(a.nodeId!==s)return null;let c=[...ge().peers,gr(e)].find(h=>h.nodeId===a.nodeId)?.label??"(unknown label)",m=[`*Bound to ${c}*`,`id \`${a.nodeId}\` \xB7 source ${a.source}`,a.source==="chat"?`since ${a.sinceIso}`:"(from config)"].join(`
|
|
106
106
|
`),f=[`<b>Bound to ${ye(c)}</b>`,`id <code>${ye(a.nodeId)}</code> \xB7 source ${ye(a.source)}`,a.source==="chat"?`since ${ye(a.sinceIso)}`:"(from config)"].join(`
|
|
107
|
-
`);return
|
|
107
|
+
`);return de(m,f)}let l=ge();return He(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=ge();return He(m,e)?p("/c unuse is only available on chats with a known sender (allowlisted WhatsApp/Telegram)."):null}let l=ge().senderBindings[n]??null,{state:d}=rh(n);if(l){if(l.nodeId!==s)return null}else if(!He(d,e))return null;let u=Mt(e,n),c=u?`
|
|
108
108
|
Config default still applies: \`${u.nodeId}\`.`:`
|
|
109
|
-
No config default is set; nobody will answer until you /c use <label-or-id>.`;return p(`Cleared your chat binding.${c}`)}if(o==="step-down"||o==="stepdown"){let a=ge();return He(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=
|
|
109
|
+
No config default is set; nobody will answer until you /c use <label-or-id>.`;return p(`Cleared your chat binding.${c}`)}if(o==="step-down"||o==="stepdown"){let a=ge();return He(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=Ei(e,n);return de(a.wa,a.tg)}if(o==="list"){let a=ge(),l=n?Mt(e,n):null;if(l){if(l.nodeId!==s)return null}else if(!He(a,e))return null;return de(yo(a,e,n??null),xi(a,e,n??null))}let i=ge();return He(i,e)?p(`Unknown /c subcommand "${o}". Try /c help`):null}function su(e,t){return Zr(!0),Ci(e,t,"chat")}qe();be();function ah(e){return`wa:${e}`}function Pi(e){return`tg:${e}`}function iu(e){return{peerKey:ah(e.fromJid),text:e.text,waMessageId:e.messageId,mediaSavedPath:e.mediaSavedPath,mediaError:e.mediaError}}G();function wo(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(`
|
|
110
110
|
`),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(`
|
|
111
111
|
`),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(`
|
|
112
112
|
`);return process.platform==="linux"?o:process.platform==="darwin"?s:process.platform==="win32"?i:[o,"","---","",s].join(`
|
|
113
|
-
`)}G();import{execFileSync as
|
|
113
|
+
`)}G();import{execFileSync as Jt}from"node:child_process";import In from"node:fs";import wr from"node:os";import st from"node:path";import Fe from"node:process";function an(){let e=Fe.execPath,t=Fe.argv[1];if(!t||!t.trim())return{nodePath:e,scriptPath:"",omnishHome:H,error:"Cannot resolve gateway entry script (missing argv[1]). Run omnish from its CLI entry."};let n=st.resolve(t),r=Fe.env.OMNISH_HOME?.trim(),o=r?st.resolve(r):H;return{nodePath:e,scriptPath:n,omnishHome:o}}function au(e){return/[ "'\\\s]/.test(e)?`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:e}function lh(e){return`Environment="OMNISH_HOME=${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function ch(e){return`[Unit]
|
|
114
114
|
Description=omnish gateway (WhatsApp/Telegram)
|
|
115
115
|
After=network-online.target
|
|
116
116
|
Wants=network-online.target
|
|
117
117
|
|
|
118
118
|
[Service]
|
|
119
119
|
Type=simple
|
|
120
|
-
ExecStart=${`${
|
|
121
|
-
${
|
|
120
|
+
ExecStart=${`${au(e.nodePath)} ${au(e.scriptPath)} run`}
|
|
121
|
+
${lh(e.omnishHome)}
|
|
122
122
|
Restart=on-failure
|
|
123
123
|
RestartSec=5
|
|
124
124
|
|
|
125
125
|
[Install]
|
|
126
126
|
WantedBy=default.target
|
|
127
|
-
`}function
|
|
127
|
+
`}function yr(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function uh(e){let t=wr.homedir(),n=st.join(e.omnishHome,"logs","launchd-stdout.log"),r=st.join(e.omnishHome,"logs","launchd-stderr.log");j(st.dirname(n));let o=yr(e.nodePath),s=yr(e.scriptPath),i=yr(e.omnishHome),a=yr(n),l=yr(r);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
128
128
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
129
129
|
<plist version="1.0">
|
|
130
130
|
<dict>
|
|
@@ -151,34 +151,34 @@ WantedBy=default.target
|
|
|
151
151
|
<string>${l}</string>
|
|
152
152
|
</dict>
|
|
153
153
|
</plist>
|
|
154
|
-
`}function
|
|
154
|
+
`}function bo(){let e=an();if(e.error)return{ok:!1,detail:e.error};if(Fe.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(Fe.platform==="darwin")try{let t=st.join(wr.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist");j(st.dirname(t));let n=uh(e);In.writeFileSync(t,n,{mode:384});let r=typeof Fe.getuid=="function"?Fe.getuid():null;if(r===null||r<0)return{ok:!1,detail:"Could not read user id for launchctl."};let o=`gui/${r}`;try{Jt("launchctl",["bootout",o,t],{stdio:"pipe"})}catch{}return Jt("launchctl",["bootstrap",o,t],{stdio:"inherit"}),Jt("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(Fe.platform==="linux")try{let t=st.join(wr.homedir(),".config","systemd","user");j(t);let n=st.join(t,"omnish.service"),r=ch(e);return In.writeFileSync(n,r,{mode:420}),Jt("systemctl",["--user","daemon-reload"],{stdio:"inherit"}),Jt("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: ${Fe.platform}`}}function ko(){if(Fe.platform==="win32")return{ok:!0,detail:"Windows: remove the omnish task from Task Scheduler manually on this PC. See /service instructions."};if(Fe.platform==="darwin")try{let e=st.join(wr.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist"),n=`gui/${typeof Fe.getuid=="function"?Fe.getuid():0}`;if(In.existsSync(e)){try{Jt("launchctl",["bootout",n,e],{stdio:"pipe"})}catch{}In.unlinkSync(e)}return{ok:!0,detail:"LaunchAgent dev.omnish.gateway removed (if it was present)."}}catch(e){return{ok:!1,detail:String(e)}}if(Fe.platform==="linux")try{let e=st.join(wr.homedir(),".config","systemd","user","omnish.service");try{Jt("systemctl",["--user","disable","--now","omnish.service"],{stdio:"pipe"})}catch{}In.existsSync(e)&&In.unlinkSync(e);try{Jt("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: ${Fe.platform}`}}import lu from"node:fs";var So=48e3;function vo(e,t){try{if(!lu.existsSync(e))return"(no log file yet \u2014 start with `omnish run -d` or the systemd/LaunchAgent service.)";let n=lu.readFileSync(e),o=(n.length>So?n.subarray(n.length-So):n).toString("utf8");return n.length>So&&(o=`\u2026(truncated to last ${So} bytes)
|
|
155
155
|
${o}`),o.split(/\r?\n/).slice(-t).join(`
|
|
156
|
-
`).trimEnd()||"(empty)"}catch(n){return`Could not read log: ${String(n)}`}}import
|
|
157
|
-
`,{mode:384})}function
|
|
158
|
-
### `)}function
|
|
159
|
-
`).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
|
|
160
|
-
`).trim();if(!n)throw new Error("Recipe body is empty.");let r=n.match(/^--steps\s+([\s\S]+)$/i);if(r){let m=r[1].trim().split(/\s*;\s*|\n/).filter(h=>h.trim());if(m.length===0)throw new Error("No steps found. Separate steps with ; or newlines.");let f=m.map(h=>{let g=h.startsWith("+"),y=g?h.slice(1).trim():h.trim();if(!y)throw new Error("Empty step in recipe.");return{cmd:y,...g?{continueOnFail:!0}:{}}});return Be({command:f[0].cmd,steps:f})}let o="OMNISH_TASK",{command:s,template:i}=
|
|
161
|
-
`)}G();var
|
|
162
|
-
`,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
|
|
163
|
-
`,n++;continue}if(o==="t"){t+=" ",n++;continue}if(o==="\\"){t+="\\",n++;continue}}t+=r}return t}function
|
|
164
|
-
[\u2026+${f.length} chars; /apps since ${r} to read more]`,this.pending.set(t,(this.pending.get(t)??"")+f)}let c=(this.opts.getRunningCount(n)>1?`[${r}] `:"")+l,m=
|
|
156
|
+
`).trimEnd()||"(empty)"}catch(n){return`Could not read log: ${String(n)}`}}import Kt from"node:fs";import Ah from"node:path";G();import dh from"node:crypto";import Oi from"node:fs";import ph from"node:path";var Li=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,Ln="__omnish_recipes_global__",Ni=new Set(["help","list","show","add","set","remove","rm","del","run","r","online"]),On=new Map,cu=!1;function mh(){try{let e=Oi.readFileSync(Gr,"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]=Be(i))}On.set(n,o)}}catch{}}function fh(e){if(!Array.isArray(e)||e.length===0)return;let t=[];for(let n of e)if(typeof n=="string"&&n.trim())t.push({cmd:n.trim()});else if(n&&typeof n=="object"){let r=n,o=typeof r.cmd=="string"?r.cmd.trim():"";if(!o)continue;t.push({cmd:o,label:typeof r.label=="string"?r.label.trim().slice(0,80):void 0,continueOnFail:typeof r.continueOnFail=="boolean"?r.continueOnFail:void 0})}return t.length>0?t:void 0}function Be(e){let t=typeof e.taskEnv=="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(e.taskEnv)?e.taskEnv:"OMNISH_TASK",n=typeof e.promptTemplate=="string"&&e.promptTemplate.trim().length>0?e.promptTemplate.trim():void 0,r=fh(e.steps),o={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};return n!==void 0&&(o.promptTemplate=n),r!==void 0&&(o.steps=r),o}function $o(){j(ph.dirname(Gr));let e={};for(let[t,n]of On)Object.entries(n).length>0&&(e[t]={...n});Oi.writeFileSync(Gr,JSON.stringify(e,null,2)+`
|
|
157
|
+
`,{mode:384})}function Ro(){cu||(mh(),cu=!0)}function uu(e){return Ro(),On.get(e)??{}}function Ai(e){Ro();let t=On.get(e);return t||(t={},On.set(e,t)),t}function hh(e,t){let n=e.taskEnv??"OMNISH_TASK",r=t.recipesMacroDefaultCommand.trim();return ln(r,n).ok?Be({...e,command:r,promptTemplate:e.command}):e}function gh(e,t){if(e.promptTemplate||ln(e.command,t).ok||!Nn(e.command,t))return!1;let n=e.command;return n.includes("```")||n.length>2e3||/^"Create\b/i.test(n)||n.includes("<<<")||n.includes(`
|
|
158
|
+
### `)}function _i(e,t){let n=Be(e),r=n.taskEnv??"OMNISH_TASK";return!n.promptTemplate&&gh(n,r)&&(n=hh(n,t)),n}function yh(e){try{let t=Oi.readFileSync(jr,"utf8"),n=JSON.parse(t);if(!n||typeof n!="object")return{};let r={};for(let[o,s]of Object.entries(n)){let i=o.trim().toLowerCase();if(!(!Li.test(i)||Ni.has(i))&&s&&typeof s=="object"&&typeof s.command=="string"){let l=_i(s,e),d=cn(l);if(!d.ok){console.warn(`[omnish] recipes.json: skipping "${i}": ${d.error}`);continue}r[i]=l}}return r}catch{return{}}}function wh(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 xo(e,t,n){for(let[r,o]of Object.entries(t)){let s=r.toLowerCase();!Li.test(s)||Ni.has(s)||o.command.trim()&&e.set(s,{...o,name:s,source:n})}}function Ii(e,t){let n=uu(e),r={};for(let[o,s]of Object.entries(n)){let i=_i(s,t);cn(i).ok&&(r[o]=i)}return r}function du(e,t){let n=new Map;return xo(n,wh(t),"builtin"),xo(n,yh(t),"global"),xo(n,Ii(Ln,t),"shared"),xo(n,Ii(e,t),"peer"),n}function je(e,t,n){let r=n.trim().toLowerCase();return du(e,t).get(r)}function pu(e){let t=e.trim();if(/^--global$/i.test(t))return{mode:"global",remainder:""};if(/^-g$/i.test(t))return{mode:"global",remainder:""};if(/^--chat$/i.test(t))return{mode:"chat",remainder:""};if(/^-p$/i.test(t))return{mode:"chat",remainder:""};let n=/^--global\s+/i.exec(t);if(n)return{mode:"global",remainder:t.slice(n[0].length).trimStart()};let r=/^-g\s+/i.exec(t);if(r)return{mode:"global",remainder:t.slice(r[0].length).trimStart()};let o=/^--chat\s+/i.exec(t);if(o)return{mode:"chat",remainder:t.slice(o[0].length).trimStart()};let s=/^-p\s+/i.exec(t);return s?{mode:"chat",remainder:t.slice(s[0].length).trimStart()}:{mode:"resolved",remainder:t}}function Fi(e){let t=e.trim();if(/^--global$/i.test(t))return{scope:"global",remainder:"",explicit:!0};if(/^-g$/i.test(t))return{scope:"global",remainder:"",explicit:!0};if(/^--chat$/i.test(t))return{scope:"chat",remainder:"",explicit:!0};if(/^-p$/i.test(t))return{scope:"chat",remainder:"",explicit:!0};let n=/^--global\s+([\s\S]*)$/i.exec(t);if(n?.[1]!==void 0)return{scope:"global",remainder:n[1].trimStart(),explicit:!0};let r=/^-g\s+([\s\S]*)$/i.exec(t);if(r?.[1]!==void 0)return{scope:"global",remainder:r[1].trimStart(),explicit:!0};let o=/^--chat\s+([\s\S]*)$/i.exec(t);if(o?.[1]!==void 0)return{scope:"chat",remainder:o[1].trimStart(),explicit:!0};let s=/^-p\s+([\s\S]*)$/i.exec(t);return s?.[1]!==void 0?{scope:"chat",remainder:s[1].trimStart(),explicit:!0}:{scope:"chat",remainder:t,explicit:!1}}function Wi(e){let t=Fi(e);return{scope:t.scope,remainder:t.remainder}}function mu(e){let t=e.trim();return!t||/^-+$/i.test(t)?{filter:"merged"}:/^(?:--global|-g)$/i.test(t)?{filter:"global"}:/^(?:--chat|-p)$/i.test(t)?{filter:"chat"}:{filter:"merged",bad:t}}function bh(e){let t=e.trim().toLowerCase();if(t==="--global"||t==="-g")return"global";if(t==="--chat"||t==="-p")return"chat"}function fu(e){let t=e.trim().match(/^(\S+)\s+(--global|-g|--chat|-p)\s*$/i);if(!t?.[1]||!t[2])return;let n=bh(t[2]);if(n)return{name:t[1],target:n}}function Tt(e,t,n,r){let o=r.trim().toLowerCase(),s=e==="global"?Ln:t,i=uu(s)[o];if(i===void 0)return;let a=_i(i,n);if(cn(a).ok)return{...a,name:o,source:e==="global"?"shared":"peer"}}function hu(e,t,n){if(n==="merged")return[];let r=n==="global"?Ln:e,o=n==="global"?"shared":"peer",s=Ii(r,t);return Object.entries(s).map(([i,a])=>({...a,name:i,source:o})).sort((i,a)=>i.name.localeCompare(a.name))}function yt(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return Li.test(n)?Ni.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 Co(e,t){let n=e.replace(/\r\n/g,`
|
|
159
|
+
`).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 Nn(e,t){return e.includes("$")?e.includes(t):!1}function ln(e,t){let n=e.trim();if(!n)return{ok:!1,error:"Command is empty."};if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(t))return{ok:!1,error:"Invalid taskEnv (use letters, digits, _)."};if(!Nn(n,t))return{ok:!1,error:`Command must reference "$${t}" so the task is passed via the environment.`};let r=`"$${t}"`;return n.includes(r)?n.includes("```")?{ok:!1,error:"Recipe command must not contain markdown code fences (```). Use promptTemplate or split with a --- line (see /run help)."}:{ok:!0}:{ok:!1,error:`Command must include ${r} (quoted).`}}function cn(e){let t=e.taskEnv??"OMNISH_TASK",n=ln(e.command,t);return n.ok?e.promptTemplate!==void 0&&e.promptTemplate.trim().length===0?{ok:!1,error:"promptTemplate cannot be empty."}:{ok:!0}:n}function kh(e){let t=e,n=null,r=!1,o=-1,s=-1;for(let l=0;l<t.length;l+=1){let d=t[l];if(r){r=!1;continue}if(d==="\\"){r=!0;continue}if(n){d===n&&(n=null);continue}if(d==='"'||d==="'"){n=d;continue}if(d!=="-"||t[l+1]!=="-")continue;let u=l===0?"":t[l-1];if(u&&!/\s/.test(u))continue;let c=t.slice(l+2),m=/^(template|tamplate)\b/i.exec(c);if(!m)continue;let f=l+2+m[0].length,h=t[f]??"";if(!h||!/\s/.test(h))continue;o=l;let g=f;for(;g<t.length&&/\s/.test(t[g]);)g+=1;s=g;break}if(o<0||s<0)return{command:t.trim()};let i=t.slice(0,o).trim(),a=t.slice(s).trim();return(a.startsWith('"')&&a.endsWith('"')&&a.length>=2||a.startsWith("'")&&a.endsWith("'")&&a.length>=2)&&(a=a.slice(1,-1)),{command:i,template:a}}function Ui(e,t){let n=e.replace(/\r\n/g,`
|
|
160
|
+
`).trim();if(!n)throw new Error("Recipe body is empty.");let r=n.match(/^--steps\s+([\s\S]+)$/i);if(r){let m=r[1].trim().split(/\s*;\s*|\n/).filter(h=>h.trim());if(m.length===0)throw new Error("No steps found. Separate steps with ; or newlines.");let f=m.map(h=>{let g=h.startsWith("+"),y=g?h.slice(1).trim():h.trim();if(!y)throw new Error("Empty step in recipe.");return{cmd:y,...g?{continueOnFail:!0}:{}}});return Be({command:f[0].cmd,steps:f})}let o="OMNISH_TASK",{command:s,template:i}=kh(n);if(i!==void 0){if(!s)throw new Error("Command part (before --template) is empty.");if(!i.trim())throw new Error("Template part (after --template) is empty.");let c=ln(s,o);if(!c.ok)throw new Error(c.error);return Be({command:s,promptTemplate:i})}let a=/\n---\n/,l=n.search(a);if(l>=0){let c=n.slice(0,l).trim(),m=n.slice(l).replace(/^\n---\n/,"").trim();if(!c)throw new Error("Command part (before ---) is empty.");if(!m)throw new Error("Template part (after ---) is empty.");let f=ln(c,o);if(!f.ok)throw new Error(f.error);return Be({command:c,promptTemplate:m})}if(ln(n,o).ok)return Be({command:n});let d=t.trim(),u=ln(d,o);if(!u.ok)throw new Error(`recipesMacroDefaultCommand invalid (${u.error}). Fix config or paste runner then --- then template.`);return Be({command:d,promptTemplate:n})}function Mo(e,t,n){let r="`".repeat(3),o=`<<<${r}$${t}${r}>>>`,s=e;s.includes(o)&&(s=s.split(o).join(n));let i=`<<<${t}>>>`;s.includes(i)&&(s=s.split(i).join(n));let a=new RegExp(`\\$${t}\\b`,"g");return s.replace(a,n)}function _n(e,t,n,r="chat",o){let s=yt(t);if(!s.ok)throw new Error(s.error);let i=Be({...n,command:n.command});if(o?.skipCommandValidation){if(!i.command.trim())throw new Error("Command is empty.")}else{let d=cn(i);if(!d.ok)throw new Error(d.error)}let a=r==="global"?Ln:e,l=Ai(a);l[s.normalized]=i,$o()}function gu(e,t,n="chat"){let r=t.trim().toLowerCase(),o=n==="global"?Ln:e;Ro();let s=On.get(o);return!s||!(r in s)?!1:(delete s[r],$o(),!0)}function Di(e,t,n,r){let o=yt(t);if(!o.ok)return{ok:!1,error:o.error};let s=o.normalized,i=e,a=Ln;Ro();let l=Ai(i),d=Ai(a),u=l[s],c=d[s],m=f=>{let h=Be({...f}),g=cn(h);if(!g.ok)throw new Error(g.error);return h};try{if(n==="global"){if(u!==void 0){let g=m(u);return d[s]=g,delete l[s],$o(),{ok:!0,kind:"moved",target:"global",name:s}}if(c!==void 0)return{ok:!0,kind:"noop",message:`Recipe "${s}" is already gateway-shared.`};let h=je(e,r,s);return h?.source==="builtin"||h?.source==="global"?{ok:!1,error:`Recipe "${s}" is built-in or from host recipes.json \u2014 not moved via /run set. Edit recipes.json or use a different name.`}:{ok:!1,error:`No user recipe "${s}" in this chat to promote. Add with /run add ${s} \u2026 or demote from global with /run set -p ${s}.`}}if(c!==void 0){let h=m(c);return l[s]=h,delete d[s],$o(),{ok:!0,kind:"moved",target:"chat",name:s}}if(u!==void 0)return{ok:!0,kind:"noop",message:`Recipe "${s}" is already stored for this chat only.`};let f=je(e,r,s);return f?.source==="builtin"||f?.source==="global"?{ok:!1,error:`Recipe "${s}" is built-in or from host recipes.json \u2014 not moved via /run set.`}:{ok:!1,error:`No gateway-shared user recipe "${s}" to demote. Add with /run add --global ${s} \u2026 or promote from this chat with /run set -g ${s}.`}}catch(f){return{ok:!1,error:String(f)}}}function yu(e,t){let n=[...du(e,t).values()],r=n.filter(a=>a.featured).sort((a,l)=>a.name.localeCompare(l.name)),o=n.filter(a=>a.source==="peer").sort((a,l)=>a.name.localeCompare(l.name)),s=n.filter(a=>a.source==="shared").sort((a,l)=>a.name.localeCompare(l.name)),i=n.filter(a=>!a.featured&&a.source!=="peer"&&a.source!=="shared").sort((a,l)=>a.name.localeCompare(l.name));return{featured:r,shared:s,yours:o,more:i}}function To(e){let t=dh.randomBytes(4).toString("hex");return`r-${e.replace(/[^a-zA-Z0-9_-]/g,"").slice(0,12)}-${t}`.slice(0,32)}function wu(e,t){let n=[`runbook: ${e}`];for(let o of t){let s=o.skipped?"skip":o.exitCode===0?"ok":"FAIL",i=o.label||`step ${o.index+1}`;if(o.skipped)n.push(`[${s}] ${i}`);else{n.push(`[${s}] ${i}${o.timedOut?" (timeout)":o.exitCode!==0?` (exit ${o.exitCode})`:""}`);let a=o.output.trim();if(a){let l=a.length>300?a.slice(0,300)+"\u2026":a;n.push(l)}}}let r=t.every(o=>o.skipped||o.exitCode===0);return n.push(r?"All steps completed successfully.":"Runbook stopped on failure."),n.join(`
|
|
161
|
+
`)}G();var bu={enter:"\r",cr:"\r",lf:`
|
|
162
|
+
`,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 Sh(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+=`
|
|
163
|
+
`,n++;continue}if(o==="t"){t+=" ",n++;continue}if(o==="\\"){t+="\\",n++;continue}}t+=r}return t}function vh(e){let t=e.trim();if(!t)return"";if(t.startsWith("\\"))return Sh(t);let n=t.toLowerCase();if(bu[n])return bu[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 Eo(e){let t=e.split(",").map(n=>n.trim()).filter(Boolean);return t.length===0?"":t.map(n=>vh(n)).join("")}var br="\x1B";function Po(e){let t=e;return t=t.replace(new RegExp(`${br}\\[[\\d;?]*[ -/]*[@-~]`,"g"),""),t=t.replace(new RegExp(`${br}\\][^${br}\\u0007]*(?:\\u0007|${br}\\\\)`,"g"),""),t=t.replace(new RegExp(`${br}[@-Z\\\\-_]`,"g"),""),t=t.replace(/\u0007/g,""),t}function xh(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 $h(e,t){return`${e}${t}`}var Ao=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=$h(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=Po(l)),!l.trim()))return;let d=o.appsMaxFlushBytes;if(l.length>d){let f=l.slice(d);l=l.slice(0,d)+`
|
|
164
|
+
[\u2026+${f.length} chars; /apps since ${r} to read more]`,this.pending.set(t,(this.pending.get(t)??"")+f)}let c=(this.opts.getRunningCount(n)>1?`[${r}] `:"")+l,m=xh(c,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))}}}};var Io=4096,Rh=/\[sudo\]\s+password\s+for\s+/i,Ch=/passphrase\s+for\s+/i,Mh=/(?:^|\n)\s*(?:Password|password):\s*$/;function Oo(e){let n=Po(e).replace(/\r/g,"").slice(-512);return!!(Rh.test(n)||Ch.test(n)||Mh.test(n))}G();import Th from"node:fs";import Eh from"node:path";import*as ku from"node-pty";var Ph=1024*1024,Lo=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>Ph&&this.ringChunks.length>0;){let n=this.ringChunks.shift();this.ringBytes-=n.length}}static start(t){j(sr(t.peerKey));let n=Eh.join(sr(t.peerKey),`${t.name}.log`),r=Th.createWriteStream(n,{flags:"a",mode:384}),o={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...t.cwd?{PWD:t.cwd}:{},...t.extraEnv??{}},s=ku.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.onOutput?.(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}recentOutputTail(t=4096){if(this.ringBytes===0)return"";let n=Math.max(1,t),r=[],o=Math.min(n,this.ringBytes);for(let s=this.ringChunks.length-1;s>=0&&o>0;s--){let i=this.ringChunks[s];i.length<=o?(r.unshift(i),o-=i.length):(r.unshift(i.subarray(i.length-o)),o=0)}return Buffer.concat(r).toString("utf8")}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()}};function Hi(e){return new Promise(t=>setTimeout(t,e))}async function No(e,t,n){let r=n.appsSubmitDelayMs,o=n.appsClearInputDelayMs,s=n.appsClearInput!==!1,a=n.appsSkipClearOnPasswordPrompt!==!1&&Oo(e.recentOutputTail(Io)),l=s&&!a?Eo(n.appsClearInputSequence||"^A,^K"):"",u=t.replace(/\r\n/g,`
|
|
165
165
|
`).replace(/\r/g,"").split(`
|
|
166
|
-
`);l&&(o>0&&await
|
|
167
|
-
`).trimEnd()}catch{return""}}var
|
|
168
|
-
`)}drainNextQueuedRun(t,n){let r=this.runQueue.get(t);if(!r||r.length===0)return"";let o=r.shift();r.length===0?this.runQueue.delete(t):this.runQueue.set(t,r);let s
|
|
166
|
+
`);l&&(o>0&&await Hi(o),e.write(l));for(let c of u)c.length>0&&e.write(c),r>0&&await Hi(r),e.write("\r"),l&&(o>0&&await Hi(o),e.write(l))}var Ih=/^[a-zA-Z0-9_-]{1,32}$/;function We(e){return Ih.test(e)?null:"Session name must be 1\u201332 chars: letters, digits, _ or -."}function Pe(e,t){return`${e}:${t}`}function Oh(e){let t=e.lastIndexOf(":");return t<=0?null:{peerKey:e.slice(0,t),name:e.slice(t+1)}}function Lh(e,t){return e===0&&(t===0||t==null)}function Nh(e,t){try{let r=Kt.readFileSync(e,"utf8").split(/\r?\n/);return r.slice(Math.max(0,r.length-t)).join(`
|
|
167
|
+
`).trimEnd()}catch{return""}}var zt=class{constructor(t,n){this.getCfg=t;this.send=n,this.router=new Ao({getCfg:()=>this.getCfg(),send:n,isMuted:(r,o)=>this.muted.has(Pe(r,o)),isRaw:(r,o)=>this.rawMode.has(Pe(r,o)),getRunningCount:r=>this.countPeerRunning(r)})}sessions=new Map;focus=new Map;muted=new Set;rawMode=new Set;router;killTimers=new Set;send;runQueue=new Map;activeQueuedRunHead=new Map;runQueuePaused=new Map;passwordHintSent=new Set;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(),this.runQueue.clear(),this.activeQueuedRunHead.clear(),this.runQueuePaused.clear()}getFocus(t){return this.focus.get(t)??null}logPath(t,n){return Ah.join(sr(t),`${n}.log`)}getSession(t,n){return this.sessions.get(Pe(t,n))}removeSessionRecord(t,n){let r=Pe(t,n);this.sessions.delete(r),this.passwordHintSent.delete(r),this.focus.get(t)===n&&this.focus.set(t,null)}onSessionOutput(t,n){let r=Pe(t,n),o=this.getSession(t,n);if(!o?.alive)return;let s=this.getCfg(),i=o.recentOutputTail(Io);if(!Oo(i)){this.passwordHintSent.delete(r);return}if(s.appsPasswordPromptHint===!1||this.passwordHintSent.has(r))return;this.passwordHintSent.add(r);let l=`Password prompt in app "${n}" \u2014 reply with your password only (no line-clear keys). It is not echoed in chat but is written to the session log.`;this.send(t,l).catch(()=>{})}async writeFocusedLine(t,n){let r=this.focus.get(t);if(!r)return!1;let o=this.getSession(t,r);return o?.alive?(await No(o,n,this.getCfg()),!0):!1}async writeNamedLine(t,n,r){let o=We(n);if(o)return o;let s=this.getSession(t,n);return s?.alive?(await No(s,r,this.getCfg()),null):`No app session "${n}". /apps list`}enqueueQueuedRun(t,n,r){let o=this.runQueue.get(t)??[];o.push(n),this.runQueue.set(t,o);let s=o.length,i=this.runQueuePaused.get(t)??!1,a=this.activeQueuedRunHead.get(t)??null,l=a?.sessionName??null;if(l?this.getSession(t,l)?.alive??!1:!1){let u=a?.recipeLabel?` (recipe: ${a.recipeLabel})`:"",c=s-1,m=c>0?`${c} other job(s) in line before this one.`:"Next in line after the active run finishes.";return`Queued "${n.recipeLabel}" (wait slot ${s} behind active ${l}${u}). ${m}`}return i?`Queued "${n.recipeLabel}" (position ${s}). Run queue is paused \u2014 /run queue resume to continue.`:this.drainNextQueuedRun(t,r)}resumeRunQueue(t,n){this.runQueuePaused.set(t,!1);let r=this.activeQueuedRunHead.get(t)??null,o=r?.sessionName??null;if(o?this.getSession(t,o)?.alive??!1:!1){let a=r?.recipeLabel?` (recipe: ${r.recipeLabel})`:"";return`Run queue: session "${o}"${a} is still running. Wait for exit code=0 and signal=0 before the next starts.`}return(this.runQueue.get(t)??[]).length===0?"Run queue is empty.":(this.activeQueuedRunHead.set(t,null),this.drainNextQueuedRun(t,n))}runQueueStatus(t){let n=this.runQueue.get(t)??[],r=this.activeQueuedRunHead.get(t)??null,o=r?.sessionName??null,s=this.runQueuePaused.get(t)??!1,i=o?this.getSession(t,o)?.alive??!1:!1,a=["Run queue (this chat)"];if(o&&i){let l=r?.recipeLabel?` \xB7 recipe: ${r.recipeLabel}`:"";a.push(`Active: ${o}${l}`)}else o?a.push(`Active: ${o} (exiting or stale)`):a.push("Active: (none)");if(a.push(`Pending: ${n.length} (waiting only \u2014 not counting the active run above)`),a.push(`Paused: ${s}`),n.length>0){a.push("Waiting (FIFO order):");for(let d=0;d<Math.min(n.length,20);d++)a.push(`${d+1}) ${n[d].recipeLabel}`);n.length>20&&a.push(`\u2026 and ${n.length-20} more`)}return a.push("Next auto-starts only after exit code=0 and signal=0."),a.push("Commands: /run queue resume"),a.join(`
|
|
168
|
+
`)}drainNextQueuedRun(t,n){let r=this.runQueue.get(t);if(!r||r.length===0)return"";let o=r.shift();r.length===0?this.runQueue.delete(t):this.runQueue.set(t,r);let s=To(o.recipeLabel),i=this.runQueue.get(t)?.length??0,a=this.start(t,s,o.command,n,o.extraEnv);if(!a.includes("started and attached"))return r.unshift(o),this.runQueue.set(t,r),this.runQueuePaused.set(t,!0),this.activeQueuedRunHead.set(t,null),`${a}
|
|
169
169
|
Run queue paused; fix the issue, then /run queue resume.`;this.activeQueuedRunHead.set(t,{sessionName:s,recipeLabel:o.recipeLabel});let d=i>0?`
|
|
170
170
|
Run queue: started head above; ${i} job(s) still waiting in FIFO.`:`
|
|
171
171
|
Run queue: started head above; no further queued jobs.`;return`${a}${d}`}start(t,n,r,o,s){let i=We(n);if(i)return i;if(!r.trim())return`Usage: /apps start <name> <command\u2026>
|
|
172
|
-
Example: /apps start sh bash`;if(this.sessions.has(Pe(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.`;te();let a=oe(t).cwd,l={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...a?{PWD:a}:{},...s??{}},d;try{d=
|
|
172
|
+
Example: /apps start sh bash`;if(this.sessions.has(Pe(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.`;te();let a=oe(t).cwd,l={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...a?{PWD:a}:{},...s??{}},d;try{d=Lo.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,onOutput:()=>{this.onSessionOutput(t,n)},onExit:u=>{this.handleSessionExit(t,n,u)}})}catch(u){return`App spawn failed: ${String(u)}
|
|
173
173
|
If install skipped native builds: pnpm approve-builds && pnpm install (needs @whiskeysockets/baileys, sharp, protobufjs, esbuild, node-pty).`}return this.sessions.set(Pe(t,n),d),this.focus.set(t,n),`App "${n}" started and attached.
|
|
174
174
|
[cwd: ${a}]
|
|
175
|
-
Plain DMs go to this session until /apps detach. Use >othername text for another session.`}async handleSessionExit(t,n,r){let o=Pe(t,n);if(!this.sessions.has(o))return;let s=this.activeQueuedRunHead.get(t)?.sessionName===n,i=this.focus.get(t)===n;this.sessions.delete(o),i&&this.focus.set(t,null),this.muted.delete(o),this.rawMode.delete(o),this.passwordHintSent.delete(o);let a=r.signal!=null?` signal=${r.signal}`:"",l=i?" (detached)":"",d=`[${n}] exited code=${r.exitCode}${a}${l}`;try{await this.send(t,d)}catch{}if(!s)return;this.activeQueuedRunHead.set(t,null);let u=this.getCfg(),c=
|
|
175
|
+
Plain DMs go to this session until /apps detach. Use >othername text for another session.`}async handleSessionExit(t,n,r){let o=Pe(t,n);if(!this.sessions.has(o))return;let s=this.activeQueuedRunHead.get(t)?.sessionName===n,i=this.focus.get(t)===n;this.sessions.delete(o),i&&this.focus.set(t,null),this.muted.delete(o),this.rawMode.delete(o),this.passwordHintSent.delete(o);let a=r.signal!=null?` signal=${r.signal}`:"",l=i?" (detached)":"",d=`[${n}] exited code=${r.exitCode}${a}${l}`;try{await this.send(t,d)}catch{}if(!s)return;this.activeQueuedRunHead.set(t,null);let u=this.getCfg(),c=Lh(r.exitCode,r.signal),m=this.runQueue.get(t)?.length??0;if(c){if(this.runQueuePaused.set(t,!1),m>0){let f=this.drainNextQueuedRun(t,u);if(f)try{await this.send(t,f)}catch{}}return}if(this.runQueuePaused.set(t,!0),m>0){let f=`Run queue paused (exit code=${r.exitCode}${r.signal!=null?` signal=${r.signal}`:""}). ${m} run(s) waiting. /run queue resume to continue.`;try{await this.send(t,f)}catch{}}}attach(t,n){let r=We(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=Oh(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)"}
|
|
176
176
|
App sessions:
|
|
177
177
|
${n.join(`
|
|
178
|
-
`)}`}getSessionCommand(t,n){if(We(n))return null;let o=this.getSession(t,n);return o?.command?.trim()?o.command.trim():null}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=We(o);if(s)return s;let i=this.getSession(t,o),a=this.logPath(t,o),l=0;try{l=
|
|
178
|
+
`)}`}getSessionCommand(t,n){if(We(n))return null;let o=this.getSession(t,n);return o?.command?.trim()?o.command.trim():null}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=We(o);if(s)return s;let i=this.getSession(t,o),a=this.logPath(t,o),l=0;try{l=Kt.statSync(a).size}catch{}let d=this.muted.has(Pe(t,o)),u=this.rawMode.has(Pe(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: ${u}`].join(`
|
|
179
179
|
`)}async sendText(t,n,r){let o=We(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,`
|
|
180
|
-
`);return await
|
|
181
|
-
[...truncated]`}function
|
|
180
|
+
`);return await No(s,i,this.getCfg()),`Sent to "${n}" (${i.length} chars + Enter per line).`}sendKey(t,n,r){let o=We(n);if(o)return o;let s=this.getSession(t,n);if(!s?.alive)return`No session "${n}".`;let i=Eo(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=We(n);if(o)return o;let s=this.logPath(t,n);if(!Kt.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 Nh(s,a)||"(empty log)"}readSince(t,n,r){let o=this.logPath(t,n);try{let i=Kt.statSync(o).size,a=Kt.openSync(o,"r");try{let l=Math.min(r,i),d=i-l,u=Buffer.alloc(d);return d>0&&Kt.readSync(a,u,0,d,l),{text:u.toString("utf8"),nextOffset:i}}finally{Kt.closeSync(a)}}catch{return{text:"",nextOffset:r}}}mute(t,n){let r=We(n);return r||(this.muted.add(Pe(t,n)),`Muted chat output for "${n}" (log still grows). /apps unmute ${n}`)}unmute(t,n){let r=We(n);return r||(this.muted.delete(Pe(t,n)),`Unmuted "${n}".`)}setRaw(t,n,r){let o=We(n);if(o)return o;let s=Pe(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=We(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=We(n);if(r)return r;let o=this.getSession(t,n);if(!o?.alive)return`No running session "${n}".`;o.kill("SIGTERM");let s=Pe(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=We(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=We(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(Pe(t,n)),this.rawMode.delete(Pe(t,n)),this.passwordHintSent.delete(Pe(t,n));let s=this.logPath(t,n);try{Kt.rmSync(s,{force:!0})}catch{}return`Removed "${n}" metadata and log.`}};qe();be();import Sr from"node:fs";import vr from"node:path";import Su from"node:fs";import vu from"node:path";var _h=new Set(["jpg","jpeg","png","gif","webp","bmp","tif","tiff","heic","avif"]),Fh=new Set(["mp4","mov","webm","mkv","avi","m4v","3gp"]),Wh=new Set(["mp3","ogg","opus","wav","m4a","flac","aac","wma"]),_o={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 Uh(e){let t=e.replace(/^\./,"").toLowerCase();return _h.has(t)?{category:"image",mimetype:_o[t]??"image/jpeg"}:Fh.has(t)?{category:"video",mimetype:_o[t]??"video/mp4"}:Wh.has(t)?{category:"audio",mimetype:_o[t]??"audio/mpeg"}:{category:"document",mimetype:_o[t]??"application/octet-stream"}}function qt(e,t){let n;try{n=Su.realpathSync(e)}catch{return{error:"File not found or unreadable."}}let r;try{r=Su.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=vu.basename(n),s=vu.extname(n).slice(1),{category:i,mimetype:a}=Uh(s);return{absPath:n,category:i,mimetype:a,displayName:o}}import Dh from"node:os";import*as $u from"node-pty";function Hh(e,t){return e.length<=t?e:`${e.slice(0,t)}
|
|
181
|
+
[...truncated]`}function Bh(e){if(e===void 0||e===0)return null;let t=Dh.constants.signals;for(let[n,r]of Object.entries(t))if(r===e)return n;return null}function xu(e){try{process.platform==="win32"?e.kill():e.kill("SIGTERM")}catch{e.kill()}}function un(e,t,n){return new Promise(r=>{let o=Date.now(),s=!1,i="",a=n.cwd,l=null,d=!1,u=null,c=null,m,f=y=>{if(d)return;d=!0,m!==void 0&&clearTimeout(m),u?.dispose(),u=null,r(y);let b=c;c=null,queueMicrotask(()=>b?.dispose())},g={...n.env??process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...a?{PWD:a}:{}};try{l=$u.spawn(e,["-c",t],{name:"xterm-256color",cols:120,rows:40,cwd:a,env:g})}catch(y){f({code:null,stdout:"",stderr:String(y),durationMs:Date.now()-o,timedOut:!1,signal:null});return}m=setTimeout(()=>{s=!0,l&&xu(l)},n.timeoutMs),u=l.onData(y=>{i+=y,i.length>n.maxBytes&&(i=Hh(i,n.maxBytes),l&&xu(l))}),c=l.onExit(y=>{f({code:y.exitCode,stdout:i,stderr:"",durationMs:Date.now()-o,timedOut:s,signal:Bh(y.signal)})})})}function kr(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 jh(e,t,n){let r=e;for(let o=0;o<14;o++){let s=kr(r,t,n),i=new Date(s).getDay();if(i>=1&&i<=5)return s;r=s}return kr(r,t,n)}function Gh(e,t,n,r){let o=e;for(let s=0;s<370;s++){let i=kr(o,n,r);if(new Date(i).getDay()===t)return i;o=i}return kr(o,n,r)}function Jh(e,t){let n=new Date(e),r=n.getFullYear(),o=n.getMonth(),s=n.getDate(),i=n.getHours(),a=new Date(r,o,s,i,t,0,0).getTime();return a<=e&&(a=new Date(r,o,s,i+1,t,0,0).getTime()),a}function Kh(e,t){return e.kind==="ondemand"||e.kind==="heartbeat"?Number.POSITIVE_INFINITY:e.kind==="daily"?kr(t,e.hour,e.minute):e.kind==="weekdays"?jh(t,e.hour,e.minute):e.kind==="hourly"?Jh(t,e.minute):Gh(t,e.weekday,e.hour,e.minute)}function Mu(e,t,n,r,o=32){if(e.kind==="ondemand"||e.kind==="heartbeat")return[];let s=t??n-1,i=[],a=s;for(;i.length<o;){let l=Kh(e,a);if(l>r)break;i.push(l),a=l}return i}var zh={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 Bi(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 qh(e){let t=e.trim(),n=/^:(\d{1,2})$/.exec(t),r=/^(\d{1,2})$/.exec(t),o=n?n[1]:r?r[1]:null;if(o===null)return null;let s=Number(o);return!Number.isInteger(s)||s<0||s>59?null:s}function Fo(e){if(e.length===0)return{ok:!1,error:"Missing schedule (try: ondemand, hourly [:MM], 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=Bi(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=Bi(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==="hourly"){if(e.length===1)return{ok:!0,schedule:{kind:"hourly",minute:0}};if(e.length!==2)return{ok:!1,error:"Usage: hourly | hourly :MM | hourly MM (minute 0\u201359)."};let n=qh(e[1]);return n===null?{ok:!1,error:"hourly needs :MM or MM (minute 0\u201359), e.g. hourly :30 or hourly 15."}:{ok:!0,schedule:{kind:"hourly",minute:n}}}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=zh[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=Bi(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."}}if(t==="heartbeat"){if(e.length<2||e.length>3)return{ok:!1,error:"Usage: heartbeat <interval> [grace] \u2014 e.g. heartbeat 1h, heartbeat 30m 10m"};let n=Ru(e[1]);if(n===null||n<6e4)return{ok:!1,error:"heartbeat interval must be >= 1m. Use 5m, 1h, 2h, 1d, etc."};let r=Math.floor(n*.5);if(e.length===3){let o=Ru(e[2]);if(o===null||o<3e4)return{ok:!1,error:"heartbeat grace must be >= 30s. Use 1m, 5m, etc."};r=o}return{ok:!0,schedule:{kind:"heartbeat",intervalMs:n,graceMs:r}}}return{ok:!1,error:`Unknown schedule kind "${t}".`}}function Ru(e){let t=e.trim().toLowerCase();if(!t)return null;let n=t.match(/^(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/);if(!n||t===""||!n[1]&&!n[2]&&!n[3]&&!n[4])return null;let r=n[1]?Number(n[1]):0,o=n[2]?Number(n[2]):0,s=n[3]?Number(n[3]):0,i=n[4]?Number(n[4]):0;return((r*24+o)*60+s)*6e4+i*1e3}function Cu(e){let t=Math.floor(e/1e3),n=Math.floor(t/86400),r=Math.floor(t%86400/3600),o=Math.floor(t%3600/60),s=[];return n>0&&s.push(`${n}d`),r>0&&s.push(`${r}h`),o>0&&s.push(`${o}m`),s.length>0?s.join(""):`${t}s`}function Fn(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"hourly":return e.minute===0?"hourly":`hourly :${t(e.minute)}`;case"weekly":return`weekly ${["sun","mon","tue","wed","thu","fri","sat"][e.weekday]??e.weekday} ${n(e.hour,e.minute)}`;case"heartbeat":return`heartbeat every ${Cu(e.intervalMs)} grace ${Cu(e.graceMs)}`}}G();be();import Yh from"better-sqlite3";var Tu=2,Yt=null;function Eu(){j(dt);let e=new Yh(rl);e.pragma("journal_mode = WAL"),e.exec(`
|
|
182
182
|
CREATE TABLE IF NOT EXISTS cowork_meta (
|
|
183
183
|
key TEXT PRIMARY KEY,
|
|
184
184
|
value TEXT NOT NULL
|
|
@@ -197,108 +197,108 @@ ${n.join(`
|
|
|
197
197
|
last_ok INTEGER NOT NULL,
|
|
198
198
|
updated_at_ms INTEGER NOT NULL
|
|
199
199
|
);
|
|
200
|
-
`);let t=e.prepare("SELECT value FROM cowork_meta WHERE key = 'schema_version'").get(),n=t?Number(t.value):0;return n<
|
|
200
|
+
`);let t=e.prepare("SELECT value FROM cowork_meta WHERE key = 'schema_version'").get(),n=t?Number(t.value):0;return n<Tu&&(n<2&&e.exec(`
|
|
201
201
|
CREATE TABLE IF NOT EXISTS cowork_task_state (
|
|
202
202
|
task_id TEXT PRIMARY KEY,
|
|
203
203
|
last_ok INTEGER NOT NULL,
|
|
204
204
|
updated_at_ms INTEGER NOT NULL
|
|
205
205
|
);
|
|
206
|
-
`),e.prepare("INSERT OR REPLACE INTO cowork_meta (key, value) VALUES ('schema_version', ?)").run(String(
|
|
206
|
+
`),e.prepare("INSERT OR REPLACE INTO cowork_meta (key, value) VALUES ('schema_version', ?)").run(String(Tu))),e}function dn(e){Yt||(Yt=Eu()),Vh(e)}function Pu(){if(Yt){try{Yt.close()}catch{}Yt=null}}function pn(){return Yt||(Yt=Eu()),Yt}function Qh(e){let n=pn().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 Wo(e){let t=Qh(e.id);return t??e.lastCompletedSlotMs}function Uo(e,t){if(t.length===0)return;let n=pn(),r=n.prepare(`
|
|
207
207
|
INSERT INTO cowork_slot_completion (task_id, slot_ms, kind, completed_at_ms, log_path)
|
|
208
208
|
VALUES (?, ?, ?, ?, ?)
|
|
209
|
-
`);n.transaction(()=>{for(let s of t)r.run(e,s.slotMs,s.kind,s.completedAtMs,s.logPath)})()}function
|
|
209
|
+
`);n.transaction(()=>{for(let s of t)r.run(e,s.slotMs,s.kind,s.completedAtMs,s.logPath)})()}function ji(e){pn().prepare("INSERT OR REPLACE INTO cowork_task_state (task_id, last_ok, updated_at_ms) VALUES (?, 1, ?)").run(e,Date.now())}function Do(e){return pn().prepare("SELECT updated_at_ms FROM cowork_task_state WHERE task_id = ?").get(e)?.updated_at_ms??null}function Ho(e){let t=pn().prepare("SELECT last_ok FROM cowork_task_state WHERE task_id = ?").get(e);return t==null?null:t.last_ok===1}function Bo(e,t){pn().prepare("INSERT OR REPLACE INTO cowork_task_state (task_id, last_ok, updated_at_ms) VALUES (?, ?, ?)").run(e,t?1:0,Date.now())}function Vh(e){let n=pn().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{Uo(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")}}function Gi(e,t){if(e.startsWith("tg:")){let n=e.slice(3);return qr(t.telegramAllowFrom).has(n)}return cl(zr(t.allowFrom),e.replace(/^wa:/,""))}var Xh=8,Au=12e4,Iu=10,Zh=1e3;function eg(e){return e.toISOString().replace(/[:.]/g,"-")}function tg(e){let t="";for(let n of e)n==="*"?t+="[^/\\\\]*":n==="?"?t+="[^/\\\\]":/[.+^${}()|[\]\\]/.test(n)?t+=`\\${n}`:t+=n;return new RegExp(`^${t}$`)}function ng(e,t,n){let r=Ge(e,t),o=vr.dirname(r),s=vr.basename(r);if(o.includes("*")||o.includes("?"))return[];if(!s.includes("*")&&!s.includes("?")){try{let d=Sr.statSync(r);if(d.isFile()&&d.mtimeMs>=n)return[r]}catch{}return[]}let i;try{i=Sr.readdirSync(o)}catch{return[]}let a=tg(s),l=[];for(let d of i){if(!a.test(d))continue;let u=vr.join(o,d);try{let c=Sr.statSync(u);c.isFile()&&c.mtimeMs>=n&&l.push(u)}catch{}}return l}function Ou(e,t,n){let r=qt(e,t.fileSendMaxBytes);return"error"in r?{ok:!1,displayName:n??vr.basename(e),reason:r.error.replace(/\.$/,"").toLowerCase()}:{ok:!0,spec:{absPath:r.absPath,category:r.category,mimetype:r.mimetype,displayName:n??r.displayName}}}async function Lu(e,t,n,r){let o=oe(t.ownerPeerKey),s=t.cwd.trim()?t.cwd:o.cwd,i=Ge(t.outputDir,o.cwd);try{Sr.mkdirSync(i,{recursive:!0,mode:448})}catch(k){M.warn({err:String(k),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(),u=await un(e.shell,t.command,{timeoutMs:e.syncTimeoutMs,maxBytes:e.syncMaxBytes,cwd:s}),c=Date.now()-d,m=`${eg(new Date)}-${t.id}-${l}.log`,f=vr.join(i,m),g=[`cowork task=${t.name} id=${t.id}`,`slot=${a} kind=${l}`,`cwd=${s}`,`exit=${u.code} timedOut=${u.timedOut} durationMs=${c}`,"---",""].join(`
|
|
210
210
|
`)+(u.stdout||"")+(u.stderr?`
|
|
211
211
|
--- stderr ---
|
|
212
|
-
${u.stderr}`:"");try{
|
|
213
|
-
`),Ue=p(we),Ie=
|
|
214
|
-
[...input truncated]`}function
|
|
212
|
+
${u.stderr}`:"");try{Sr.writeFileSync(f,g,{mode:384})}catch(k){M.warn({err:String(k),logPath:f},"cowork write log")}let y=u.code===0&&!u.timedOut&&u.signal===null,v=xe().find(k=>k.id===t.id&&k.ownerPeerKey===t.ownerPeerKey),E=v?.notify??t.notify,R=v?.notifyWhen??t.notifyWhen??"always",P=v?.attachLog??t.attachLog,T=v?.attachFiles??t.attachFiles,O=!0;if(R==="failure")O=!y;else if(R==="state-change"){let k=Ho(t.id);O=k===null||k!==y}Bo(t.id,y);let A=u.timedOut?"timeout":u.signal?`signal ${u.signal}`:u.code!==0&&u.code!==null?`exit ${u.code}`:null,K=`slot: ${a} \xB7 ${l}${A?` \xB7 ${A}`:""}`,X=(u.stdout||"").replace(/\s+$/,""),ie=(u.stderr||"").trim(),he=X||(ie?`(stderr) ${ie}`:"(no output)"),D=R==="state-change"?y?" [recovered]":" [failing]":"",le=`${t.name}${D} : ${A?`[${A}] `:""}${he}`,Y=n.onDemand?[K,`output: ${he}`]:[le];if(O){let k=[],x=[],L=d-Zh,F=[],Q=new Set;if(Array.isArray(T))for(let pe of T){let lt;try{lt=ng(pe,s,L)}catch(ct){M.warn({err:String(ct),pat:pe},"cowork attach glob"),k.push(`attach: ${pe} skipped (glob error)`);continue}if(lt.length!==0)for(let ct of lt)Q.has(ct)||(Q.add(ct),F.push(ct))}if(P){let pe=Ou(f,e,`${t.name}-${l}.log`);pe.ok?x.push(pe.spec):k.push(`attach: ${pe.displayName} skipped (${pe.reason})`)}let z=0;for(let pe of F){if(x.length>=Iu){z+=1;continue}let lt=Ou(pe,e);lt.ok?x.push(lt.spec):k.push(`attach: ${lt.displayName} skipped (${lt.reason})`)}z>0&&k.push(`attached: skipped ${z} file(s) over cap ${Iu}`),k.length>0&&Y.push(...k);let we=Y.join(`
|
|
213
|
+
`),Ue=p(we),Ie=Rn(E,t.ownerPeerKey,e);for(let pe of Ie){let lt=ke(Ue,pe.startsWith("tg:")?"telegram":"whatsapp").text;try{await r.sendToPeer(pe,lt)}catch(ct){M.warn({err:String(ct),pk:pe},"cowork notify failed")}for(let ct of x)try{await r.sendMediaToPeer(pe,ct)}catch(Pm){M.warn({err:String(Pm),pk:pe,file:ct.displayName},"cowork media notify failed")}}}return{commandOk:y,logPath:f}}function jo(e){let t=!1;dn(xe());let n=async()=>{if(t)return;t=!0;let s=Date.now(),i=0,a=0,l=0,d=0,u=0;try{let c=e.getConfig(),{batch:m,remainingAfter:f}=hl(Xh);a=m.length,l=f,i=m.length+f;for(let y of m)try{let v=xe().find(E=>E.name===y.name.toLowerCase()&&E.ownerPeerKey===y.ownerPeerKey);if(v&&v.enabled){if(!Gi(v.ownerPeerKey,c)){M.warn({task:v.name,peer:v.ownerPeerKey},"cowork: skipping on-demand run \u2014 owner no longer on allowlist");continue}d+=1,await Lu(c,v,{slotMs:null,catchUp:!1,onDemand:!0},e)}}catch(b){M.warn({err:String(b),pending:y.name},"cowork on-demand run failed")}let h=xe();dn(h);let g=Date.now();for(let y of h){if(!y.enabled||y.schedule.kind!=="heartbeat"||!Gi(y.ownerPeerKey,c))continue;let b=Do(y.id);if(b===null)continue;let v=b+y.schedule.intervalMs+y.schedule.graceMs;if(g>v){if(Ho(y.id)===!1)continue;Bo(y.id,!1);let R=Math.round((g-b)/6e4),P=`${y.name} [heartbeat missed] \u2014 last check-in ${R}m ago`,T=y.notify,O=Rn(T,y.ownerPeerKey,c);for(let A of O)try{await e.sendToPeer(A,P)}catch(K){M.warn({err:String(K),pk:A},"cowork heartbeat notify failed")}}else if(g<=v&&Ho(y.id)===!1){Bo(y.id,!0);let R=`${y.name} [heartbeat recovered]`,P=y.notify,T=Rn(P,y.ownerPeerKey,c);for(let O of T)try{await e.sendToPeer(O,R)}catch(A){M.warn({err:String(A),pk:O},"cowork heartbeat recovery notify failed")}}}for(let y of h){if(!y.enabled||y.schedule.kind==="ondemand"||y.schedule.kind==="heartbeat")continue;if(!Gi(y.ownerPeerKey,c)){M.warn({task:y.name,peer:y.ownerPeerKey},"cowork: skipping scheduled run \u2014 owner no longer on allowlist");continue}let b=Wo(y),v=Mu(y.schedule,b,y.createdAtMs,g);if(v.length===0)continue;let E=v[v.length-1],R=g-E>Au;try{u+=1;let{commandOk:P,logPath:T}=await Lu(c,y,{slotMs:E,catchUp:R,onDemand:!1},e);if(P){let O=Date.now(),A=g-E<=Au?"on_time":"catch_up";if(v.length===1)Uo(y.id,[{slotMs:E,kind:A,logPath:T,completedAtMs:O}]);else{let X=v.slice(0,-1).map(ie=>({slotMs:ie,kind:"coalesced",logPath:null,completedAtMs:O}));X.push({slotMs:E,kind:A,logPath:T,completedAtMs:O}),Uo(y.id,X)}}}catch(P){M.warn({err:String(P),task:y.name},"cowork scheduled run failed")}}}finally{let c=Date.now()-s;M.info({tickMs:c,pendingDepthStart:i,pendingDequeued:a,pendingRemainingAfter:l,pendingRunsStarted:d,scheduledRan:u},"cowork tick"),t=!1}},r=setInterval(()=>void n(),3e4),o=setTimeout(()=>void n(),5e3);return()=>{clearInterval(r),clearTimeout(o),Pu()}}import rg from"node:fs";import Nu from"node:path";import{fileURLToPath as og}from"node:url";var Go=null;function Ze(){if(Go!==null)return Go;let e=Nu.dirname(og(import.meta.url)),t=Nu.join(e,"..","package.json"),n=rg.readFileSync(t,"utf8"),r=JSON.parse(n);return Go=typeof r.version=="string"&&r.version.trim()?r.version.trim():"0.0.0",Go}be();G();import{spawn as sg}from"node:child_process";import _u from"node:fs";import Fu from"node:path";var ig=new Set(["PATH","HOME","USER","LOGNAME","SHELL","LANG","LC_ALL","LC_CTYPE","LC_MESSAGES","TMPDIR","TZ"]),ag=new Set(["OPENAI_API_KEY","ANTHROPIC_API_KEY","GOOGLE_API_KEY","GEMINI_API_KEY","MISTRAL_API_KEY","GROQ_API_KEY","COHERE_API_KEY","HUGGINGFACE_TOKEN","TOGETHER_API_KEY","FIREWORKS_API_KEY","PERPLEXITY_API_KEY","DEEPSEEK_API_KEY","XAI_API_KEY","CURSOR_API_KEY"]);function lg(e,t){let n={OMNISH_PEER_KEY:e,OMNISH_CHAT_MESSAGE:t};for(let r of ig){let o=process.env[r];o!==void 0&&(n[r]=o)}for(let[r,o]of Object.entries(process.env))o&&(r.startsWith("OMNISH_")||ag.has(r))&&(n[r]=o);return n}var Wu=new Map;function cg(e,t){let r=(Wu.get(e)??Promise.resolve()).then(t).catch(o=>{M.warn({peerKey:e,err:String(o)},"chat LLM fallback queue task failed")});Wu.set(e,r)}function ug(e){te();let t=e.chatLlmWorkDir.trim();if(t){let r=Fu.resolve(t);return j(r),{cwd:r,cleanup:()=>{}}}let n=_u.mkdtempSync(Fu.join(H,"chat-llm-"));return{cwd:n,cleanup:()=>{try{_u.rmSync(n,{recursive:!0,force:!0})}catch{}}}}function dg(e,t){return e.length<=t?e:`${e.slice(0,t)}
|
|
214
|
+
[...input truncated]`}function pg(e,t){let n=[],r=e.stdout.trimEnd(),o=e.stderr.trimEnd();return r&&n.push(r.length>t?`${r.slice(0,t)}
|
|
215
215
|
[...truncated]`:r),o&&(n.push("\u2014 stderr \u2014"),n.push(o.length>t?`${o.slice(0,t)}
|
|
216
216
|
[...truncated]`:o)),n.length===0&&n.push("(no output)"),e.timedOut?n.push(`(timed out after ${Math.round(e.durationMs/1e3)}s)`):e.code!==0&&e.code!==null?n.push(`(exit ${e.code})`):e.signal&&n.push(`(signal ${e.signal})`),n.join(`
|
|
217
|
-
`)}function
|
|
217
|
+
`)}function Jo(e){let t=e&&typeof e=="object"&&"code"in e?String(e.code):"";return t==="EPIPE"||t==="EOF"}function Uu(e){try{e?.stdin?.end()}catch(t){if(!Jo(t))throw t}}function mg(e,t,n,r){return new Promise(o=>{let s=Date.now(),i=!1,a="",l="",d=!1,u=null,c,m=b=>{d||(d=!0,clearTimeout(c),o(b))},f=r.maxOutChars,h=(b,v)=>{b==="out"?a+=v:l+=v;let E=a.length+l.length;if(E>f){let R=E-f;if(l.length>=R)l=`${l.slice(0,Math.max(0,l.length-R))}
|
|
218
218
|
[...truncated]`;else{let P=R-l.length;l="",a=`${a.slice(0,Math.max(0,a.length-P))}
|
|
219
|
-
[...truncated]`}try{u?.kill("SIGTERM")}catch{}}};try{u=
|
|
220
|
-
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null})}),(()=>{if(!(!g||d))try{g.write(n,"utf8",b=>{if(b&&!
|
|
221
|
-
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null});return}
|
|
222
|
-
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null});return}
|
|
223
|
-
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null})}),u.on("close",(b,v)=>{m({code:b,stdout:a,stderr:l,durationMs:Date.now()-s,timedOut:i,signal:v??null})})})}async function
|
|
224
|
-
`,{mode:384})}function
|
|
225
|
-
`)}var
|
|
219
|
+
[...truncated]`}try{u?.kill("SIGTERM")}catch{}}};try{u=sg(e,["-c",t],{cwd:r.cwd,env:r.env,stdio:["pipe","pipe","pipe"]})}catch(b){m({code:null,stdout:"",stderr:String(b),durationMs:Date.now()-s,timedOut:!1,signal:null});return}c=setTimeout(()=>{i=!0;try{u?.kill("SIGTERM")}catch{}},r.timeoutMs),u.stdout?.setEncoding("utf8"),u.stderr?.setEncoding("utf8"),u.stdout?.on("data",b=>h("out",b)),u.stderr?.on("data",b=>h("err",b));let g=u.stdin;g&&g.on("error",b=>{Jo(b)||m({code:null,stdout:a,stderr:`${l}
|
|
220
|
+
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null})}),(()=>{if(!(!g||d))try{g.write(n,"utf8",b=>{if(b&&!Jo(b)){try{u?.kill("SIGTERM")}catch{}m({code:null,stdout:a,stderr:`${l}
|
|
221
|
+
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null});return}Uu(u)})}catch(b){if(!Jo(b)){m({code:null,stdout:a,stderr:`${l}
|
|
222
|
+
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null});return}Uu(u)}})(),u.on("error",b=>{m({code:null,stdout:a,stderr:`${l}
|
|
223
|
+
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null})}),u.on("close",(b,v)=>{m({code:b,stdout:a,stderr:l,durationMs:Date.now()-s,timedOut:i,signal:v??null})})})}async function fg(e,t,n,r){let o=e.chatLlmShellCommand.trim();if(!o){await r("(chat LLM fallback: chatLlmShellCommand is empty)");return}let{cwd:s,cleanup:i}=ug(e);try{let a=dg(n,e.chatLlmMaxInputChars),l=lg(t,a),d=e.chatLlmMaxOutputChars,u;e.chatLlmNeedsTty?u=await un(e.shell,o,{cwd:s,timeoutMs:e.chatLlmTimeoutMs,maxBytes:d,env:l}):u=await mg(e.shell,o,a,{cwd:s,timeoutMs:e.chatLlmTimeoutMs,maxOutChars:d,env:l});let c=pg(u,d);await r(c)}catch(a){M.warn({peerKey:t,err:String(a)},"chat LLM fallback run failed"),await r(`(assistant error) ${String(a)}`)}finally{i()}}function Wn(e,t,n,r){M.info({peerKey:t,len:n.length},"chat LLM fallback enqueued"),cg(t,async()=>{await fg(e,t,n,r),M.info({peerKey:t},"chat LLM fallback completed")})}G();import{spawn as hg}from"node:child_process";import gg from"node:crypto";import ze from"node:fs";import Ji from"node:path";var Du=64,yg=/^[a-zA-Z0-9._-]+$/;function wg(e){let t=e.trim();return t?t.length>Du?`Job name must be at most ${Du} characters.`:yg.test(t)?null:"Job name may only use letters, digits, and . _ -":"Job name must not be empty."}function Hu(e){let t=e.trim();if(!t)return{error:"empty"};let n=null,r=!1,o=!0;for(;o;){o=!1;let i=t.trim();if(/^--notify(?:\s|$)/i.test(i)){r=!0,t=i.slice(8).trim(),o=!0;continue}if(/^-N(?:\s|$)/.test(i)){r=!0,t=i.slice(2).trim(),o=!0;continue}let a=[[/^--name\s*=\s*(\S+)\s+([\s\S]+)$/i,1,2],[/^--name\s+(\S+)\s+([\s\S]+)$/i,1,2],[/^-n\s+(\S+)\s+([\s\S]+)$/i,1,2]];for(let[l,d,u]of a){let c=i.match(l);if(c){n=c[d],t=c[u].trim(),o=!0;break}}}let s=t.trim();if(n===null&&[/^-n\s+\S+\s*$/i,/^--name\s+\S+\s*$/i,/^--name=\S+\s*$/i,/^-n\s*$/i,/^--name\s*$/i].some(a=>a.test(s)))return{error:"Add a shell command after the name."};if(n!==null){let i=wg(n);if(i)return{error:i}}return s?{cmd:s,name:n,notify:r}:{error:"Add a shell command after the flags."}}function bg(e,t){let n=t.trim();if(!n)return{ok:!1,error:"Missing job id or name."};let r=n.toLowerCase(),o=/^[a-f0-9]{8}$/;if(o.test(r)&&e.find(i=>i.id===r))return{ok:!0,id:r};for(let s of e)if(s.name&&s.name.toLowerCase()===r)return{ok:!0,id:s.id};return o.test(r)?{ok:!1,error:`Unknown job id: ${r}`}:{ok:!1,error:`Unknown job name: ${n}`}}function Un(e,t){ze.writeFileSync(e,JSON.stringify(t,null,2)+`
|
|
224
|
+
`,{mode:384})}function xr(e){try{return JSON.parse(ze.readFileSync(e,"utf8"))}catch{return null}}function Bu(e){let t=e.name?`${e.id} (${e.name})`:e.id,n=e.finishedAt&&e.startedAt?Date.parse(e.finishedAt)-Date.parse(e.startedAt):null,r=n!==null?`${(n/1e3).toFixed(1)}s`:"?",o=e.exitCode===0&&!e.signal,s=e.status==="killed"?`killed (signal ${e.signal??"?"})`:o?"completed successfully":e.signal?`signal ${e.signal}`:`exit ${e.exitCode??"?"}`,i=e.cmd.length>100?`${e.cmd.slice(0,100)}\u2026`:e.cmd;return[`Job ${t} ${s}`,`duration: ${r}`,`$ ${i}`,`/log ${e.name??e.id}`].join(`
|
|
225
|
+
`)}var Et=class{running=new Map;metaPath(t){return Ji.join(tt,`${t}.meta.json`)}logPath(t){return Ji.join(tt,`${t}.log`)}spawnJob(t,n,r={}){te();let o=gg.randomBytes(4).toString("hex"),s=this.logPath(o),i=this.metaPath(o);ze.writeFileSync(s,"",{flag:"w",mode:384});let a=ze.createWriteStream(s,{flags:"a"}),l=new Date().toISOString(),d=r.cwd,u=hg(t,["-c",n],{stdio:["ignore","pipe","pipe"],env:{...process.env,TERM:"dumb",...d?{PWD:d}:{}},...d?{cwd:d}:{}});this.running.set(o,u);let c={id:o,cmd:n,...r.name?{name:r.name}:{},pid:u.pid??null,startedAt:l,status:"running",exitCode:null,signal:null,...r.notifyPeerKey?{notifyPeerKey:r.notifyPeerKey}:{}};return Un(i,c),u.stdout?.on("data",m=>{a.write(m)}),u.stderr?.on("data",m=>{a.write(m)}),u.on("close",(m,f)=>{this.running.delete(o),a.end();let h=xr(i)??c,g={...h,status:h.status==="killed"?"killed":"done",exitCode:m,signal:f??null,finishedAt:new Date().toISOString()};Un(i,g),r.onComplete&&r.onComplete(g)}),u.on("error",m=>{this.running.delete(o),a.end(()=>{try{ze.appendFileSync(s,`
|
|
226
226
|
[spawn error] ${String(m)}
|
|
227
|
-
`)}catch{}});let h={...
|
|
227
|
+
`)}catch{}});let h={...xr(i)??c,status:"done",exitCode:null,signal:null,finishedAt:new Date().toISOString()};Un(i,h),r.onComplete&&r.onComplete(h)}),{id:o,meta:c}}list(){te();let t=[];try{t=ze.readdirSync(tt)}catch{return[]}let n=[];for(let r of t){if(!r.endsWith(".meta.json"))continue;let o=xr(Ji.join(tt,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(!ze.existsSync(r))return"(no log file)";let s=ze.readFileSync(r,"utf8").split(`
|
|
228
228
|
`);return s.slice(Math.max(0,s.length-n)).join(`
|
|
229
|
-
`).trimEnd()||"(empty log)"}readSince(t,n){let r=this.logPath(t);if(!ze.existsSync(r))return{text:"",nextOffset:n};let s=ze.statSync(r).size;if(n>=s)return{text:"",nextOffset:s};let i=Buffer.alloc(s-n),a=ze.openSync(r,"r");try{ze.readSync(a,i,0,i.length,n)}finally{ze.closeSync(a)}return{text:i.toString("utf8"),nextOffset:s}}resolveJobRef(t){return
|
|
230
|
-
`).trim()}function
|
|
229
|
+
`).trimEnd()||"(empty log)"}readSince(t,n){let r=this.logPath(t);if(!ze.existsSync(r))return{text:"",nextOffset:n};let s=ze.statSync(r).size;if(n>=s)return{text:"",nextOffset:s};let i=Buffer.alloc(s-n),a=ze.openSync(r,"r");try{ze.readSync(a,i,0,i.length,n)}finally{ze.closeSync(a)}return{text:i.toString("utf8"),nextOffset:s}}resolveJobRef(t){return bg(this.list(),t)}kill(t){let n=this.metaPath(t),r=xr(n);if(!r)return`Unknown job id: ${t}`;let o=this.running.get(t);if(o&&!o.killed)return o.kill("SIGTERM"),Un(n,{...r,status:"killed",signal:"SIGTERM"}),`Sent SIGTERM to job ${t} (pid ${r.pid??"?"})`;if(r.pid)try{return process.kill(r.pid,"SIGTERM"),Un(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=xr(this.metaPath(t));r&&Un(this.metaPath(t),{...r,status:"killed",signal:"SIGTERM"})}this.running.clear()}};import Zg from"node:fs";import{Bot as ey,InputFile as ty}from"grammy";G();import ju from"node:fs";import Dn from"node:path";function kg(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"_").slice(0,120)||"unknown"}function Sg(e){let r=Dn.basename(e.trim()||"file").replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^\.+/,"").slice(0,180);return r.length>0?r:"file"}function vg(e,t){let n=new Date().toISOString().slice(0,10),r=kg(t);return Dn.join(e,r,n)}function Hn(e,t,n){let r=vg(e,t);j(r);let o=Sg(n),s=Dn.join(r,o);if(!ju.existsSync(s))return s;let i=Dn.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=Dn.join(r,d),!ju.existsSync(s))return s}return Dn.join(r,`${a}-${Date.now()}${i}`)}be();import xg from"node:dns";import $g from"node:https";import{URL as Rg}from"node:url";function Bn(e){if(e instanceof Error){let t=e.cause;return t!=null?`${e.message} (${String(t)})`:e.message}return String(e)}be();function Gu(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 Cg(e,t){let r=t.split("/").filter(o=>o.length>0).map(encodeURIComponent).join("/");return`https://api.telegram.org/file/bot${e}/${r}`}var Ju="omnish (Telegram bot; https://github.com/labKnowledge/whatsLive)";function Mg(e){let t=new Rg(e);return new Promise((n,r)=>{let o=$g.request({hostname:t.hostname,port:t.port||443,path:t.pathname+t.search,method:"GET",headers:{"User-Agent":Ju,Accept:"*/*"},lookup(s,i,a){xg.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 Ku(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=Cg(e.token,r.file_path),s;try{let i=await fetch(o,{headers:{"User-Agent":Ju,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 Mg(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: ${Bn(i)}; IPv4 fallback: ${Bn(a)}).`}}}return n>0&&s.byteLength>n?{error:`Media too large (max ${n} bytes).`}:{buffer:s}}me();qe();import{downloadMediaMessage as Ag,extensionForMediaMessage as Ig,getContentType as Ko,isJidGroup as Qu,isLidUser as Og}from"@whiskeysockets/baileys";import Lg from"node:fs";be();var Qt=new Map;function Tg(){let e=Date.now();for(let[t,n]of Qt)e-n>6e5&&Qt.delete(t);for(;Qt.size>500;){let t=Qt.keys().next().value;if(t===void 0)break;Qt.delete(t)}}function Eg(e){!e||typeof e!="string"||(Tg(),Qt.set(e,Date.now()))}function Ki(e){Eg(e?.key?.id??void 0)}function Pg(e){if(!e)return!1;let t=Qt.get(e);return t===void 0?!1:Date.now()-t>6e5?(Qt.delete(e),!1):!0}function zu(e){return!Pg(e)}function Ng(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 _g(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 Vu(e){return[Ng(e),_g(e)].filter(n=>n.trim().length>0).join(`
|
|
230
|
+
`).trim()}function zi(e){return e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g,"").replace(/\uFEFF/g,"").trim()}function Xu(e){let t=Ko(e??void 0);return t==="imageMessage"||t==="videoMessage"||t==="audioMessage"||t==="documentMessage"||t==="stickerMessage"}function Fg(e){let t=Ko(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 qu(e){try{if(!e)return"file.bin";let t=Ig(e);return`file${t&&t.length>0?t.startsWith(".")?t:`.${t}`:".bin"}`}catch{return`${(Ko(e??void 0)??"file").replace("Message","")||"file"}.bin`}}function Wg(e){let t=Ko(e??void 0);if(!t)return qu(e);let n=e?.[t];return n?.fileName&&typeof n.fileName=="string"&&n.fileName.trim()?n.fileName.trim():qu(e)}async function Yu(e,t,n,r){let o=t.message??void 0;if(!Xu(o))return{};let s=r.fileReceiveMaxBytes,i=Fg(o);if(s>0&&i!==void 0&&i>s)return{error:`Media too large (max ${s} bytes).`};let a;try{a=await Ag(t,"buffer",{},{logger:e.logger,reuploadRequest:e.updateMediaMessage})}catch(c){return M.warn({err:String(c),detail:Bn(c)},"whatsapp downloadMediaMessage failed"),{error:`Could not download media from WhatsApp (${Bn(c)}).`}}if(s>0&&a.length>s)return{error:`Media too large (max ${s} bytes).`};let l;try{l=Ut(r,n)}catch(c){return{error:String(c)}}let d=Wg(o),u=Hn(l,n,d);try{Lg.writeFileSync(u,a,{mode:384})}catch{return{error:"Could not write media to inbox."}}return{path:u}}async function Ug(e,t){let n=t.remoteJid??"";if(!n)return{fromJid:"",fromE164:""};if(t.remoteJidAlt){let r=ee(t.remoteJidAlt)??ee(n)??"";return{fromJid:n,fromE164:r}}if(Og(n))try{let r=await e.signalRepository?.lidMapping?.getPNForLID?.(n);if(r){let o=ee(r)??"";if(o)return{fromJid:n,fromE164:o}}}catch{}return{fromJid:n,fromE164:ee(n)??""}}function Dg(e){try{if(!$().clusterEnabled)return;let n=Vu(e.message??void 0);if(!n)return;let r=zc(n);if(!r)return;let o=e.key?.remoteJid??"",s=null;if(o&&!Qu(o)){let i=ee(o);i&&(s=`wa:${i}`)}nu(r,s)}catch(t){M.warn({err:String(t)},"cluster footer observation failed")}}function Zu(e,t){let n=r=>{r.type==="notify"&&(async()=>{for(let o of r.messages){let s=o.key;if(!s||s.fromMe&&(Dg(o),!zu(s.id)))continue;let i=s.remoteJid;if(!i||Qu(i)||i.toLowerCase().endsWith("@status")||i==="status@broadcast")continue;let l=zi(Vu(o.message??void 0)),{fromJid:d,fromE164:u}=await Ug(e,s),c=`wa:${d}`,m=Xu(o.message??void 0);if(m&&!l){(async()=>{try{let g=$(),y=await Yu(e,o,c,g);await t({fromJid:d,fromE164:u,text:"",messageId:s.id??void 0,mediaSavedPath:y.path,mediaError:y.error})}catch(g){M.error({err:String(g),fromJid:d},"whatsapp media-only background task failed")}})();continue}let f,h;if(m){let g=$(),y=await Yu(e,o,c,g);f=y.path,h=y.error}!l&&!f&&!h||await t({fromJid:d,fromE164:u,text:l,messageId:s.id??void 0,mediaSavedPath:f,mediaError:h})}})()};return e.ev.on("messages.upsert",n),()=>{e.ev.off("messages.upsert",n)}}be();import qg from"node:fs";import Hg from"node:process";import Bg,{DisconnectReason as mn,fetchLatestBaileysVersion as jg,makeCacheableSignalKeyStore as Gg,useMultiFileAuthState as Jg}from"@whiskeysockets/baileys";import Kg from"qrcode-terminal";G();be();var zg="0.1.0";function qi(e){return e?.error?.output?.statusCode}async function zo(e={}){te();let t=e.authDir??ne,n=e.verbose===!0,r=dl(),{state:o,saveCreds:s}=await Jg(t),{version:i}=await jg(),a=Bg({version:i,logger:r,printQRInTerminal:!1,browser:["omnish","cli",zg],auth:{creds:o.creds,keys:Gg(o.keys,r)},syncFullHistory:!1,markOnlineOnConnect:!1});return a.ev.on("creds.update",s),a.ev.on("connection.update",l=>{let{connection:d,lastDisconnect:u,qr:c}=l;if(c&&(e.onQr?.(c),e.printQr)){let m=Hg.stdout,f=w(m,"\xB7".repeat(42));console.log(V(m,"Scan with WhatsApp \u2192 Linked devices")),console.log(f),Kg.generate(c,{small:!0}),console.log(f)}if(d==="close"){let m=qi(u);n&&m===mn.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 jn(e){try{e.end(new Error("omnish: socket closed"))}catch{e.ws?.close()}}function Yi(e){return e?.output?.statusCode??e?.status??e?.error?.output?.statusCode}function qo(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 fn(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 od=3500,Yg=400,ed=18e4,td=9e4,nd=3e5;function Qi(e,t=od){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(`
|
|
231
231
|
|
|
232
|
-
`);i>Math.floor(t*.35)&&(o=r+i+2)}n.push(e.slice(r,o)),r=o}return n}function
|
|
232
|
+
`);i>Math.floor(t*.35)&&(o=r+i+2)}n.push(e.slice(r,o)),r=o}return n}function Yo(e){return new Promise(t=>setTimeout(t,e))}async function rd(e,t){await Promise.race([e,Yo(ed).then(()=>{M.warn({jid:t,ms:ed},"whatsapp outbound self-heal: prior send chain waited too long; continuing")})])}async function Qg(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{let i=await fn(e.sendMessage(t,{text:n}),td,`whatsapp sendMessage timed out after ${td}ms`);Ki(i);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await Yo(800*s);continue}throw i}throw o}function Vg(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 Xg(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{let i=await fn(e.sendMessage(t,n),nd,`whatsapp sendMedia timed out after ${nd}ms`);Ki(i);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await Yo(800*s);continue}throw i}throw o}function sd(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=rd(a,o).then(async()=>{let d=Qi(i,od);for(let u=0;u<d.length;u+=1)await Qg(e,o,d[u]??""),u<d.length-1&&await Yo(Yg)}).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=qg.readFileSync(s.absPath),a=Vg(s,i),l=n.get(o)??Promise.resolve(),d=rd(l,o).then(async()=>{await Xg(e,o,a)}).catch(u=>{M.error({err:String(u),jid:o},"sendMedia failed")});n.set(o,d),await d.finally(()=>{n.get(o)===d&&n.delete(o)})}}}function id(e){let t=e.trim();return t?/^\/id(?:@[\w_]+)?$/i.test(t):!1}function ad(e){let t=String(e).replace(/\D/g,"");return`Your Telegram user id: ${t}
|
|
233
233
|
Add to allowlist on this gateway host:
|
|
234
|
-
omnish allow tg:${t}`}var
|
|
235
|
-
`));if(g&&
|
|
234
|
+
omnish allow tg:${t}`}var ny=400;async function ld(e,t,n,r){let o=t(),s=await Ku(e,r.fileId,o.fileReceiveMaxBytes);if("error"in s)return{mediaError:s.error};let i;try{i=Ut(o,n)}catch(l){return{mediaError:String(l)}}let a=Hn(i,n,r.baseName);try{return Zg.writeFileSync(a,s.buffer,{mode:384}),{mediaSavedPath:a}}catch{return{mediaError:"Could not write media to inbox."}}}function ry(e){return new Promise(t=>setTimeout(t,e))}async function Vi(e,t,n,r={}){let o=new ey(e);await o.api.deleteWebhook({drop_pending_updates:!1});let s=new Map,i=r.decorate??(u=>u);async function a(u,c){let m=Math.min(t().appsMaxWaChars,4096),f=ke(c,"telegram"),h=i(f.text,Pi(u)),g=f.parseModeHtml,b=(s.get(u)??Promise.resolve()).then(async()=>{let v=Qi(h,m);for(let E=0;E<v.length;E+=1){let R=v[E]??"",P=g?{parse_mode:"HTML"}:void 0;try{await o.api.sendMessage(u,R,P)}catch(T){if(g){M.warn({err:String(T),chatId:u},"telegram HTML send failed; retrying plain");let O=R.replace(/<[^>]+>/g,"");await o.api.sendMessage(u,O)}else throw T}E<v.length-1&&await ry(ny)}}).catch(v=>{M.error({err:String(v),chatId:u},"telegram sendText failed")});s.set(u,b),await b.finally(()=>{s.get(u)===b&&s.delete(u)})}async function l(u,c){let m=new ty(c.absPath,c.displayName),f=c.caption,g=(s.get(u)??Promise.resolve()).then(async()=>{switch(c.category){case"image":await o.api.sendPhoto(u,m,f?{caption:f}:void 0);break;case"video":await o.api.sendVideo(u,m,f?{caption:f}:void 0);break;case"audio":await o.api.sendAudio(u,m,f?{caption:f}:void 0);break;case"document":await o.api.sendDocument(u,m,f?{caption:f}:void 0);break}}).catch(y=>{M.error({err:String(y),chatId:u},"telegram sendMedia failed")});s.set(u,g),await g.finally(()=>{s.get(u)===g&&s.delete(u)})}o.on("message",async u=>{let c=u.chat,m=u.message;if(!c||c.type!=="private"||!u.from||!m)return;let f="text"in m&&m.text?m.text:"",h="caption"in m&&m.caption?m.caption:"",g=zi([f,h].filter(Boolean).join(`
|
|
235
|
+
`));if(g&&id(g)){let T=u.from.id;await o.api.sendMessage(c.id,ad(T));return}let y=Gu(m),b=Pi(c.id),v=c.id,E=async T=>{if(T.kind==="file")await l(v,T.spec);else if(T.kind==="files")for(let O of T.specs)await l(v,O);else if(T.kind==="texts")for(let O of T.bodies)await a(v,O);else await a(v,T.body)};if(y&&!g){(async()=>{try{let T=await ld(o,t,b,y);if(!T.mediaSavedPath&&!T.mediaError)return;await n({peerKey:b,text:"",tgChatId:c.id,tgReplyToMessageId:m.message_id,mediaSavedPath:T.mediaSavedPath,mediaError:T.mediaError},E)}catch(T){M.error({err:String(T),chatId:v},"telegram media-only background task failed")}})();return}let R,P;if(y){let T=await ld(o,t,b,y);R=T.mediaSavedPath,P=T.mediaError}!g&&!R&&!P||await n({peerKey:b,text:g,tgChatId:c.id,tgReplyToMessageId:m.message_id,mediaSavedPath:R,mediaError:P},E)}),o.catch(u=>{M.error({err:String(u)},"telegram bot error")});let d=o.start();return{bot:o,sendText:a,sendMedia:l,stop:async()=>{await o.stop(),await d.catch(()=>{})}}}qe();import oy from"node:fs";import sy from"node:path";function iy(e){let t=sy.join(e,"creds.json");try{let n=oy.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 cd(e){let t=iy(e);if(!t)return null;let n=t.phoneNumber?.trim();if(n){let s=ee(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=ee(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 Vo from"node:fs";import et from"node:process";G();G();import ud from"node:fs";var ay="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.";function Qo(e){let t=String(e).toLowerCase();return t.includes("401")||t.includes("logged out")?!0:Yi(e)===mn.loggedOut}function ly(e){return new Promise((t,n)=>{let r=()=>{n(new Error("Pairing cancelled."))};if(e.aborted){r();return}e.addEventListener("abort",r,{once:!0})})}async function Xi(e){let t=!1;for(let n=0;n<3;n++){if(e.signal?.aborted)throw new Error("Pairing cancelled.");let r=await zo({authDir:e.authDir,printQr:e.printQr===!0,verbose:e.verbose===!0,onQr:e.onQr});e.onSocketReady?.(r);try{let o=fn(qo(r),6e5,ay);e.signal?await Promise.race([o,ly(e.signal)]):await o;return}catch(o){if(o instanceof Error&&o.message==="Pairing cancelled.")throw o;if(Yi(o)===mn.restartRequired&&!t){t=!0,e.onRestart515?.(),await new Promise(i=>setTimeout(i,1500));continue}throw o}finally{e.onSocketClosed?.(),jn(r)}}throw new Error("Pairing failed after restart (515) retries.")}async function dd(e){let t=e.authDir??ne;te();for(let n=1;n<=2;n++)try{await Xi({...e,authDir:t});return}catch(r){if(r instanceof Error&&r.message==="Pairing cancelled.")throw r;if(n===1&&Qo(r)){ud.rmSync(t,{recursive:!0,force:!0}),ud.mkdirSync(t,{recursive:!0,mode:448});continue}throw r}}async function cy(e,t){let n=et.stdout;console.log(`
|
|
236
236
|
${Ce(n,"omnish link")} ${w(n,"\u2014 QR appears below; scan from WhatsApp \u2192 Linked devices.")}
|
|
237
|
-
`),await
|
|
237
|
+
`),await Xi({authDir:e,verbose:t,printQr:!0,onRestart515:()=>{console.warn(`
|
|
238
238
|
${B(et.stderr,"WhatsApp requested a restart after pairing (code 515). This is normal. Opening a new connection\u2026")}
|
|
239
|
-
`)}})}async function
|
|
240
|
-
`));for(let r=1;r<=2;r++)try{await
|
|
241
|
-
${
|
|
242
|
-
`);return}catch(o){if(r===1&&
|
|
239
|
+
`)}})}async function pd(e={}){let t=e.authDir??ne,n=e.verbose===!0;te(),e.force&&(Vo.rmSync(t,{recursive:!0,force:!0}),Vo.mkdirSync(t,{recursive:!0,mode:448}),console.log(`${fe(et.stdout,"Cleared saved session (--force).")} ${w(et.stdout,"Requesting a new QR\u2026")}
|
|
240
|
+
`));for(let r=1;r<=2;r++)try{await cy(t,n),console.log(`
|
|
241
|
+
${ue(et.stdout,"Linked.")} ${S(et.stdout,"Session saved. You can run")} ${ue(et.stdout,"omnish run")} ${S(et.stdout,"now.")}
|
|
242
|
+
`);return}catch(o){if(r===1&&Qo(o)){console.warn(`
|
|
243
243
|
${B(et.stderr,"WhatsApp returned logged-out (401). This often happens after Ctrl+C during link or corrupt auth files.")}
|
|
244
244
|
${B(et.stderr,"Clearing auth dir and retrying once with a fresh QR\u2026")}
|
|
245
|
-
`),
|
|
245
|
+
`),Vo.rmSync(t,{recursive:!0,force:!0}),Vo.mkdirSync(t,{recursive:!0,mode:448});continue}throw Qo(o)&&console.error(`
|
|
246
246
|
${C(et.stderr,"Still failing after a clean auth directory. Try:")}
|
|
247
247
|
${w(et.stderr,` pnpm approve-builds && pnpm install
|
|
248
248
|
(pnpm may have skipped Baileys/sharp/protobuf build scripts.)
|
|
249
249
|
Then: omnish link --force
|
|
250
|
-
`)}`),o}}G();import{spawn as
|
|
250
|
+
`)}`),o}}G();import{spawn as uy,spawnSync as dy}from"node:child_process";import Gn from"node:fs";import py from"node:path";import Jn from"node:process";function Xo(e,t={}){te(),j(py.dirname(e));let n=Jn.argv[1];if(!n)return{ok:!1,message:"Cannot resolve entry script; invoke via node path/to/dist/index.js."};let r=["run"];t.verbose&&r.push("-vb");let o=Gn.openSync(e,"a"),s=uy(Jn.execPath,[n,...r],{detached:!0,stdio:["ignore",o,o],env:{...Jn.env,OMNISH_BACKGROUND_GATEWAY:"1"}});return Gn.closeSync(o),s.unref(),s.pid?{ok:!0,pid:s.pid}:{ok:!1,message:"Failed to start background gateway."}}function Zo(){if(te(),!Gn.existsSync(ce))return{outcome:"no_pidfile"};let e=Gn.readFileSync(ce,"utf8").trim(),t=Number(e);if(!Number.isFinite(t)||t<=0){try{Gn.unlinkSync(ce)}catch{}return{outcome:"invalid_pidfile"}}try{Jn.kill(t,0)}catch{try{Gn.unlinkSync(ce)}catch{}return{outcome:"stale_cleaned",pid:t}}try{return Jn.kill(t,"SIGTERM"),{outcome:"sent_signal",pid:t}}catch(n){return Jn.platform==="win32"&&dy("taskkill",["/PID",String(t),"/T"],{windowsHide:!0}).status===0?{outcome:"taskkill_ok",pid:t}:{outcome:"failed",message:`could not signal process: ${String(n)}`}}}import wd from"node:crypto";import ea from"node:fs";import my from"node:net";qe();be();G();import gd from"node:fs";var md=Number(process.env.PLATFORM_INBOUND_MEDIA_MAX_BYTES)>0?Number(process.env.PLATFORM_INBOUND_MEDIA_MAX_BYTES):54525952,fd=50;function hd(e){try{return JSON.parse(e)}catch{return null}}function ts(e){return e.fileSendMaxBytes<=0?8388608:Math.min(e.fileSendMaxBytes,8388608)}function yd(e){if(gd.statSync(e.absPath).size>8388608)throw new Error(`File too large for attached mode (max ${8388608} bytes).`);let n=gd.readFileSync(e.absPath).toString("base64");return{name:e.displayName,mimetype:e.mimetype,category:e.category,dataBase64:n,...e.caption?{caption:e.caption}:{}}}function Zi(e,t,n,r){return t.kind==="texts"?{body:t.bodies.map(s=>ke(s,r).text).filter(s=>s.trim()).join(`
|
|
251
251
|
|
|
252
|
-
`),...n?{messageId:n}:{}}:t.kind==="text"?{body:ke(t.body,r).text,...n?{messageId:n}:{}}:t.kind==="file"?{...n?{messageId:n}:{},files:[
|
|
253
|
-
`,{mode:384})}function
|
|
254
|
-
`);if(i===-1)return;let a=o.slice(0,i).trim();o=o.slice(i+1);let l=
|
|
255
|
-
`),r.end()})}),r.on("error",()=>{})});n.listen(0,"127.0.0.1",()=>{let r=n.address();if(!r||typeof r=="string"){
|
|
252
|
+
`),...n?{messageId:n}:{}}:t.kind==="text"?{body:ke(t.body,r).text,...n?{messageId:n}:{}}:t.kind==="file"?{...n?{messageId:n}:{},files:[yd(t.spec)]}:{...n?{messageId:n}:{},files:t.specs.map(yd)}}var $r=null;function fy(){try{let e=ea.readFileSync(kn,"utf8"),t=JSON.parse(e);return typeof t.token=="string"?t.token:""}catch{return""}}function hy(e){ea.writeFileSync(kn,JSON.stringify(e,null,2)+`
|
|
253
|
+
`,{mode:384})}function gy(){try{ea.unlinkSync(kn)}catch{}}async function yy(e,t){let n=t.getCfg(),r=typeof e.absPath=="string"?e.absPath.trim():"";if(!r)return{ok:!1,error:"Missing absPath."};let o=typeof e.caption=="string"&&e.caption.length>0?e.caption:void 0,s=t.sendPlatformMedia&&!t.getWaOutbound()&&!t.getTgSendMedia()?ts(n):n.fileSendMaxBytes,i=qt(r,s);if("error"in i)return{ok:!1,error:i.error};let a={absPath:i.absPath,category:i.category,mimetype:i.mimetype,displayName:i.displayName,caption:o};if(e.channel==="whatsapp"){let l=t.getWaOutbound(),d=typeof e.e164=="string"?e.e164.trim():"";if(!d.startsWith("+"))return{ok:!1,error:"WhatsApp destination must be E.164 (e.g. +15551234567)."};let u=Lt(d);if(!l){let m=t.sendPlatformMedia;if(!m)return{ok:!1,error:"WhatsApp outbound is not connected."};try{return await m(`wa:${u}`,a),{ok:!0}}catch(f){return{ok:!1,error:String(f)}}}let c=n.gatewayMode;if(c!=="whatsapp"&&c!=="both")return{ok:!1,error:"gatewayMode does not include WhatsApp."};try{return await l.sendMedia(u,a),{ok:!0}}catch(m){return{ok:!1,error:String(m)}}}if(e.channel==="telegram"){let l=t.getTgSendMedia();if(!l){let u=t.sendPlatformMedia;if(!u)return{ok:!1,error:"Telegram outbound is not connected."};if(!Number.isFinite(e.chatId))return{ok:!1,error:"Invalid Telegram chat id."};let c=`tg:${e.chatId}`;try{return await u(c,a),{ok:!0}}catch(m){return{ok:!1,error:String(m)}}}let d=n.gatewayMode;if(d!=="telegram"&&d!=="both")return{ok:!1,error:"gatewayMode does not include Telegram."};if(!Number.isFinite(e.chatId))return{ok:!1,error:"Invalid Telegram chat id."};try{return await l(e.chatId,a),{ok:!0}}catch(u){return{ok:!1,error:String(u)}}}return{ok:!1,error:"Unknown channel."}}async function wy(e,t){let n=t.getCfg(),r=typeof e.text=="string"?e.text.trim():"";if(!r)return{ok:!1,error:"Missing or empty text."};if(e.channel==="whatsapp"){let o=t.getWaOutbound();if(!o){let l=t.sendPlatformText;if(!l)return{ok:!1,error:"WhatsApp outbound is not connected."};let d=typeof e.e164=="string"?e.e164.trim():"";if(!d.startsWith("+"))return{ok:!1,error:"WhatsApp destination must be E.164 (e.g. +15551234567)."};let u=Lt(d);try{return await l(`wa:${u}`,r),{ok:!0}}catch(c){return{ok:!1,error:String(c)}}}let s=n.gatewayMode;if(s!=="whatsapp"&&s!=="both")return{ok:!1,error:"gatewayMode does not include WhatsApp."};let i=typeof e.e164=="string"?e.e164.trim():"";if(!i.startsWith("+"))return{ok:!1,error:"WhatsApp destination must be E.164 (e.g. +15551234567)."};let a=Lt(i);try{return await o.sendText(a,r),{ok:!0}}catch(l){return{ok:!1,error:String(l)}}}if(e.channel==="telegram"){let o=t.getTgSendText();if(!o){let i=t.sendPlatformText;if(!i)return{ok:!1,error:"Telegram outbound is not connected."};if(!Number.isFinite(e.chatId))return{ok:!1,error:"Invalid Telegram chat id."};try{return await i(`tg:${e.chatId}`,r),{ok:!0}}catch(a){return{ok:!1,error:String(a)}}}let s=n.gatewayMode;if(s!=="telegram"&&s!=="both")return{ok:!1,error:"gatewayMode does not include Telegram."};if(!Number.isFinite(e.chatId))return{ok:!1,error:"Invalid Telegram chat id."};try{return await o(e.chatId,p(r)),{ok:!0}}catch(i){return{ok:!1,error:String(i)}}}return{ok:!1,error:"Unknown channel."}}async function by(e,t,n){let r;try{r=JSON.parse(e)}catch{return{ok:!1,error:"Invalid JSON."}}if(!r||typeof r!="object")return{ok:!1,error:"Invalid request."};if(typeof r.token!="string"||!n)return{ok:!1,error:"Unauthorized."};try{let o=Buffer.from(r.token,"utf8"),s=Buffer.from(n,"utf8");if(o.length!==s.length||!wd.timingSafeEqual(o,s))return{ok:!1,error:"Unauthorized."}}catch{return{ok:!1,error:"Unauthorized."}}return r.op==="sendMedia"?yy(r,t):r.op==="sendText"?wy(r,t):{ok:!1,error:"Unsupported operation."}}function ns(e){if($r)return;let t=wd.randomBytes(32).toString("hex"),n=my.createServer(r=>{let o="";r.setTimeout(12e4),r.on("data",s=>{o+=s.toString("utf8");let i=o.indexOf(`
|
|
254
|
+
`);if(i===-1)return;let a=o.slice(0,i).trim();o=o.slice(i+1);let l=fy();by(a,e,l).then(d=>{r.write(`${JSON.stringify(d)}
|
|
255
|
+
`),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};hy(o),M.info({port:r.port},"gateway control listening")}),n.on("error",r=>{M.error({err:String(r)},"gateway control server error")}),$r=n}function Kn(){if($r){try{$r.close()}catch{}$r=null,gy()}}be();import ky from"node:crypto";import Sy from"node:http";var vy=256*1024;function xy(e,t){if(!e||!t)return!1;try{let n=Buffer.from(e,"utf8"),r=Buffer.from(t,"utf8");return n.length===r.length&&ky.timingSafeEqual(n,r)}catch{return!1}}function $y(e){let t=typeof e.source=="string"?e.source:"webhook";if(e.action==="completed"&&e.workflow_run&&typeof e.workflow_run=="object"){let a=e.workflow_run,l=a.name??"?",d=a.conclusion??"?",u=a.head_branch??"?",c=a.html_url??"",m=e.repository?.full_name??"?";return`[${t}] ${m} \u2014 ${l}
|
|
256
256
|
result: ${d}
|
|
257
257
|
branch: ${u}${c?`
|
|
258
258
|
${c}`:""}`}if(e.object_kind==="pipeline"&&e.object_attributes&&typeof e.object_attributes=="object"){let a=e.object_attributes,l=a.status??"?",d=a.ref??"?",u=a.id??"?",c=e.project?.path_with_namespace??"?";return`[${t}] ${c} \u2014 pipeline #${u}
|
|
259
259
|
status: ${l}
|
|
260
260
|
ref: ${d}`}let n=typeof e.text=="string"?e.text:null,r=typeof e.message=="string"?e.message:null,o=typeof e.title=="string"?e.title:null,s=typeof e.status=="string"?e.status:null;if(n)return`[${t}] ${n}`;let i=[`[${t}]`];if(o&&i.push(o),r&&i.push(r),s&&i.push(`status: ${s}`),i.length===1){let a=JSON.stringify(e).slice(0,500);i.push(a)}return i.join(`
|
|
261
|
-
`)}var Vi=null;function Zo(e,t){if(Vi)return{stop:()=>{}};let n=fy.createServer((r,o)=>{if(r.method!=="POST"){o.writeHead(405,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Method not allowed"}));return}let s=r.headers.authorization,i=s?.startsWith("Bearer ")?s.slice(7):void 0,a=new URL(r.url??"/",`http://${r.headers.host??"localhost"}`).searchParams.get("token")??void 0;if(!gy(i??a,e.token)){o.writeHead(401,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Unauthorized"}));return}let d="",u=0;r.on("data",c=>{if(u+=c.length,u>hy){o.writeHead(413,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Payload too large"})),r.destroy();return}d+=c.toString("utf8")}),r.on("end",()=>{let c;try{c=JSON.parse(d)}catch{o.writeHead(400,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Invalid JSON"}));return}let f=new URL(r.url??"/",`http://${r.headers.host??"localhost"}`).searchParams.get("source")??r.headers["x-webhook-source"]??void 0;f&&(c.source=f);let h=typeof c.peerKey=="string"&&c.peerKey||t.getDefaultPeerKey();if(!h){o.writeHead(400,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"No target peer. Set peerKey in body or configure an allowlisted identity."}));return}let g=yy(c);t.sendToPeer(h,g).then(()=>{o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!0}))},y=>{T.warn({err:String(y)},"webhook: sendToPeer failed"),o.writeHead(502,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Failed to deliver message"}))})})});return n.listen(e.port,e.host,()=>{let r=n.address(),o=typeof r=="object"&&r?r.port:e.port;T.info({port:o,host:e.host},"webhook receiver listening")}),n.on("error",r=>{T.error({err:String(r)},"webhook receiver error")}),Vi=n,{stop:()=>{try{n.close()}catch{}Vi=null}}}pe();import qw from"node:crypto";import Ea from"node:fs";be();import wy from"node:fs";function dd(e,t,n){let r=e.fileReceiveMaxBytes,o;try{o=Buffer.from(n.dataBase64,"base64")}catch{return{mediaError:"Invalid inbound media payload."}}if(r>0&&o.length>r)return{mediaError:`Media too large (max ${r} bytes).`};let s;try{s=Ft(e,t)}catch(a){return{mediaError:String(a)}}let i=_n(s,t,n.name);try{return wy.writeFileSync(i,o,{mode:384}),{mediaSavedPath:i}}catch{return{mediaError:"Could not write media to inbox."}}}G();rs();be();import na from"ws";import xy from"ws";var vy=["/platform/device","/control/device"];function os(e){let t=e.replace(/\/$/,"");return vy.map(n=>{let r=new URL(n,t);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.toString()})}var $y=Math.ceil(sd*1.4)+512*1024;function Ry(e){let t=String(e instanceof Error?e.message:e);return/Unexpected server response:\s*400/.test(t)||/Unexpected server response:\s*404/.test(t)}async function gd(e,t){let n=os(e),r=null;for(let s of n)try{return{ws:await new Promise((a,l)=>{let d=new xy(s,{headers:{Authorization:`Bearer ${t}`},maxPayload:$y});d.once("open",()=>a(d)),d.once("error",l)}),pathname:new URL(s).pathname}}catch(i){if(r=i instanceof Error?i:new Error(String(i)),Ry(i))continue;throw r}let o="Could not open a device WebSocket. Redeploy the relay (for /control/device fallback) and ensure /platform/* or /control/* route to port 8788.";throw r&&/Unexpected server response:\s*400/.test(r.message)?new Error(`${r.message} \u2014 ${o}`):new Error(r?`${r.message} \u2014 ${o}`:o)}var Cy=1e3,My=6e4,ss=class{constructor(t){this.options=t}ws=null;stopped=!1;pingTimer=null;registerResolve=null;registerReject=null;registeredAccount=null;registeredDeviceId=null;reconnectAttempt=0;reconnectTimer=null;outboundQueue=[];getRegisteredAccount(){return this.registeredAccount}async connect(){return this.connectOnce()}async connectOnce(){let{env:t}=this.options,n=new Promise((a,l)=>{this.registerResolve=a,this.registerReject=l}),{ws:r,pathname:o}=await gd(t.platformUrl,t.token);this.ws=r,o!=="/platform/device"&&T.info({pathname:o},"platform device websocket connected via fallback path"),r.on("message",a=>{this.handleMessage(a.toString())}),r.on("close",()=>{this.stopped||(T.warn("platform device websocket closed; scheduling reconnect"),this.scheduleReconnect())}),r.on("error",a=>{T.warn({err:String(a)},"platform device websocket error")});let s=setTimeout(()=>{this.registerReject?.(new Error("Platform device register timeout (15s)"))},15e3);this.sendRaw({type:"register",...t.deviceId?{deviceId:t.deviceId}:{},label:process.env.OMNISH_DEVICE_LABEL?.trim()||"default"});let i=await n;return clearTimeout(s),this.registeredDeviceId=i.deviceId,this.reconnectAttempt=0,this.pingTimer&&clearInterval(this.pingTimer),this.pingTimer=setInterval(()=>{this.sendRaw({type:"ping"})},3e4),this.flushOutboundQueue(),i}scheduleReconnect(){if(this.stopped||this.reconnectTimer)return;this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null),this.ws=null;let t=Math.min(Cy*2**this.reconnectAttempt,My);this.reconnectAttempt+=1,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,!this.stopped&&this.connectOnce().catch(n=>{T.warn({err:String(n)},"platform device reconnect failed"),this.scheduleReconnect()})},t),this.reconnectTimer.unref?.()}async handleMessage(t){let n=ad(t);if(n){if(n.type==="registered"&&"deviceId"in n){n.account&&(this.registeredAccount=n.account),this.registerResolve?.({deviceId:n.deviceId,...n.account?{account:n.account}:{}}),this.registerResolve=null,this.registerReject=null;return}if(n.type==="message"){await this.options.onMessage(n);return}if(n.type==="reply_error"){await this.options.onReplyError?.(n.peerKey,n.error,n.messageId);return}n.type==="error"&&(T.warn({message:n.message},"platform error"),this.registerReject?.(new Error(n.message)),this.registerResolve=null,this.registerReject=null)}}sendReply(t,n,r,o){this.enqueue({type:"reply",peerKey:t,...n?{body:n}:{},...r?{messageId:r}:{},...o?.length?{files:o}:{}})}sendRoutedReply(t,n){this.enqueue({type:"reply",peerKey:t,...n})}enqueue(t){if(this.ws?.readyState===na.OPEN){this.sendRaw(t);return}if(this.outboundQueue.length>=id){T.warn("platform outbound queue full; dropping reply");return}this.outboundQueue.push(t)}flushOutboundQueue(){for(;this.outboundQueue.length>0&&this.ws?.readyState===na.OPEN;){let t=this.outboundQueue.shift();t&&this.sendRaw(t)}}sendRaw(t){this.ws?.readyState===na.OPEN&&this.ws.send(JSON.stringify(t))}stop(){this.stopped=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null);try{this.ws?.close()}catch{}this.ws=null,this.outboundQueue.length=0}};import ia from"node:readline/promises";import{stdin as aa,stdout as ps}from"node:process";pe();var Ty=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;function wd(e){let t=e.trim().toLowerCase();return t?t.length>63?"Tunnel name must be at most 63 characters.":Ty.test(t)?null:"Tunnel name may only use letters, digits, and hyphens.":"Tunnel name must not be empty."}function bd(e){let t=Number.parseInt(e,10);return!Number.isInteger(t)||t<1||t>65535?null:t}function yd(e,t){let n="127.0.0.1",r,o,s=!1,i=[];for(let d=0;d<t.length;d++){let u=t[d];if(u==="--host"){let c=t[++d];if(!c)return{kind:"error",message:"--host requires an address."};n=c;continue}if(u.startsWith("--host=")){n=u.slice(7);continue}if(u==="--relay"){let c=t[++d];if(!c)return{kind:"error",message:"--relay requires a URL."};r=c;continue}if(u.startsWith("--relay=")){r=u.slice(8);continue}if(u==="--name"){let c=t[++d];if(!c)return{kind:"error",message:"--name requires a slug."};o=c;continue}if(u.startsWith("--name=")){o=u.slice(7);continue}if(u==="--background"||u==="-b"){s=!0;continue}i.push(u)}let a=i[0];if(!a)return{kind:"error",message:`Usage: omnish tunnel ${e} <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]`};let l=bd(a);if(l===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};if(o){let d=wd(o);if(d)return{kind:"error",message:d}}return{kind:"expose",options:{kind:e,port:l,host:n,relayUrl:r??"",name:o,background:s}}}function ra(e){let[t,...n]=e,r=(t??"").trim().toLowerCase();if(!r||r==="help"||r==="-h"||r==="--help")return{kind:"help"};if(r==="signup"){let o,s,i,a;for(let l=0;l<n.length;l++){let d=n[l];if(d==="--email"){o=n[++l];continue}if(d.startsWith("--email=")){o=d.slice(8);continue}if(d==="--phone"){s=n[++l];continue}if(d.startsWith("--phone=")){s=d.slice(8);continue}if(d==="--password"){i=n[++l];continue}if(d.startsWith("--password=")){i=d.slice(11);continue}if(d==="--relay"){a=n[++l];continue}if(d.startsWith("--relay=")){a=d.slice(8);continue}}return{kind:"signup",email:o,phone:s,password:i,relayUrl:a}}if(r==="login"){let o,s,i,a,l;for(let d=0;d<n.length;d++){let u=n[d];if(u==="--token"){o=n[++d];continue}if(u.startsWith("--token=")){o=u.slice(8);continue}if(u==="--email"){s=n[++d];continue}if(u.startsWith("--email=")){s=u.slice(8);continue}if(u==="--phone"){i=n[++d];continue}if(u.startsWith("--phone=")){i=u.slice(8);continue}if(u==="--password"){a=n[++d];continue}if(u.startsWith("--password=")){a=u.slice(11);continue}if(u==="--relay"){l=n[++d];continue}if(u.startsWith("--relay=")){l=u.slice(8);continue}o||(o=u)}return{kind:"login",token:o,email:s,phone:i,password:a,relayUrl:l}}if(r==="logout")return{kind:"logout"};if(r==="list")return{kind:"list"};if(r==="status"){let o;for(let s=0;s<n.length;s++){let i=n[s];if(i==="--relay"){o=n[s+1],s++;continue}i.startsWith("--relay=")&&(o=i.slice(8))}return{kind:"status",relayUrl:o}}if(r==="stop"){let o=n[0]?.trim();return o?{kind:"stop",target:o}:{kind:"error",message:"Usage: omnish tunnel stop <id|slug>"}}return r==="http"?yd("http",n):r==="tcp"?yd("tcp",n):{kind:"error",message:`Unknown tunnel subcommand "${t}". Try: omnish tunnel help`}}function Ey(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){s===r?r=null:n+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){n.length&&(t.push(n),n="");continue}n+=s}return n.length&&t.push(n),t}function kd(e){let t=e.trim();if(!t||t==="help")return{kind:"help"};let n=Ey(t),r=n[0]?.toLowerCase();if(r==="login"||r==="logout"||r==="status"||r==="signup")return ra(n);if(t.toLowerCase()==="list"||t.toLowerCase()==="ls")return{kind:"list"};let o=t.match(/^stop\s+(\S+)\s*$/i);if(o)return{kind:"stop",target:o[1]};let s=t.match(/^(http|tcp)\s+(\d+)(?:\s+--name\s+(\S+))?(?:\s+--host\s+(\S+))?\s*$/i);if(s){let i=s[1].toLowerCase(),a=bd(s[2]);if(a===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};let l=s[3],d=s[4]??"127.0.0.1";if(l){let u=wd(l);if(u)return{kind:"error",message:u}}return{kind:"expose",options:{kind:i,port:a,host:d,relayUrl:"",name:l,background:!0}}}return{kind:"error",message:"Usage: /tunnel login \u2026 | /tunnel status | /tunnel http <port> | /tunnel tcp <port> | /tunnels | /tunnel stop <id>"}}import Py from"ws";import{URL as Sd}from"node:url";function jn(e){let t=new Sd(e);return t.protocol=t.protocol==="https:"?"wss:":"ws:",(!t.pathname||t.pathname==="/")&&(t.pathname="/control"),t.toString()}function vd(e){return new Sd("/health",e).toString()}async function is(e,t,n=1e4){let r=t.trim();if(!r)return{ok:!1,healthOk:!1,controlOk:!1,error:"Tunnel token is missing."};let o=vd(e),s=!1,i;try{let d=await fetch(o,{method:"GET",signal:AbortSignal.timeout(n)});if(!d.ok)return{ok:!1,healthOk:!1,controlOk:!1,error:`Health HTTP ${d.status} (${o})`};let u=await d.json();if(!u?.ok)return{ok:!1,healthOk:!1,controlOk:!1,error:"Health JSON missing ok:true"};s=!0,typeof u.version=="string"&&(i=u.version)}catch(d){return{ok:!1,healthOk:!1,controlOk:!1,error:`Health fetch failed: ${String(d)}`}}let a=jn(e),l=!1;try{await new Promise((d,u)=>{let c=new Py(a,{headers:{Authorization:`Bearer ${r}`}}),m=setTimeout(()=>{c.terminate(),u(new Error("WSS auth timeout"))},n);c.once("message",f=>{clearTimeout(m);try{let h=JSON.parse(f.toString());if(h.type!=="auth_ok"){u(new Error(`Expected auth_ok, got ${h.type??"?"}`));return}c.close(),d()}catch(h){u(h)}}),c.once("error",f=>{clearTimeout(m),u(f)})}),l=!0}catch(d){return{ok:!1,healthOk:!0,healthVersion:i,controlOk:!1,error:`Control WebSocket: ${String(d)}`}}return{ok:!0,healthOk:s,healthVersion:i,controlOk:!0}}import Rd from"node:crypto";import Ay from"node:http";import Iy from"node:net";import Yt from"ws";function as(e,t,n=Buffer.alloc(0)){let r=Buffer.allocUnsafe(9+n.length);return r.writeUInt8(e,0),r.writeUInt32BE(t,1),r.writeUInt32BE(n.length,5),n.copy(r,9),r}function xd(e){if(e.length<9)return null;let t=e.readUInt8(0),n=e.readUInt32BE(1),r=e.readUInt32BE(5);return e.length<9+r?null:{frameType:t,streamId:n,payload:e.subarray(9,9+r)}}function oa(e){try{let t=JSON.parse(e);return!t||typeof t!="object"||typeof t.type!="string"?null:t}catch{return null}}function Gn(e){return JSON.stringify(e)}function Ly(e){let t=Rd.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return Number.parseInt(t,16)>>>0}var ls=class{constructor(t){this.opts=t;let n=Rd.randomBytes(4).toString("hex");this.record={id:n,kind:t.expose.kind,slug:t.expose.name?.trim().toLowerCase()??"",localHost:t.expose.host,localPort:t.expose.port,publicUrl:"",status:"connecting",startedAt:new Date().toISOString()}}ws=null;record;tcpStreams=new Map;tcpStreamIds=new Map;stopped=!1;pingTimer=null;getRecord(){return{...this.record}}setStatus(t,n){this.record.status=t,this.record.error=n,this.opts.onStatus?.(this.getRecord())}async start(){if(this.stopped)throw new Error("Tunnel client already stopped.");let t=jn(this.opts.relayUrl),n=new Yt(t,{headers:{Authorization:`Bearer ${this.opts.token}`}});this.ws=n,await new Promise((o,s)=>{let i=d=>{l(),s(d)},a=()=>{l(),o()},l=()=>{n.off("error",i),n.off("open",a)};n.once("error",i),n.once("open",a)}),n.on("message",(o,s)=>{if(s){this.handleBinary(Buffer.isBuffer(o)?o:Buffer.from(o));return}let i=typeof o=="string"?o:o.toString("utf8");this.handleControl(i)}),n.on("close",()=>{this.stopped||this.setStatus("error","Relay connection closed."),this.cleanupTcpStreams()}),n.on("error",o=>{this.stopped||this.setStatus("error",String(o))}),this.pingTimer=setInterval(()=>{n.readyState===Yt.OPEN&&n.send(Gn({type:"ping"}))},3e4),n.send(Gn({type:"register",id:this.record.id,kind:this.opts.expose.kind,localHost:this.opts.expose.host,localPort:this.opts.expose.port,...this.opts.expose.name?{name:this.opts.expose.name}:{}}));let r=await this.waitForRegistered();return this.record.slug=r.slug,this.record.publicUrl=r.publicUrl,this.setStatus("active"),this.getRecord()}waitForRegistered(){let t=this.ws;return t?new Promise((n,r)=>{let o=s=>{if(typeof s!="string"&&!Buffer.isBuffer(s))return;let i=typeof s=="string"?s:s.toString("utf8"),a=oa(i);if(a){if(a.type==="registered"&&a.id===this.record.id){t.off("message",o),n(a);return}a.type==="error"&&(t.off("message",o),r(new Error(a.message)))}};t.on("message",o)}):Promise.reject(new Error("WebSocket not connected."))}async handleControl(t){let n=oa(t);if(n&&!(n.type==="pong"||n.type==="auth_ok")){if(n.type==="error"){this.setStatus("error",n.message);return}if(n.type==="http"){await this.handleHttpRequest(n);return}if(n.type==="tcp_open"){await this.handleTcpOpen(n.streamId);return}n.type==="tcp_close"&&this.closeTcpStream(n.streamId)}}handleBinary(t){let n=xd(t);if(!n)return;let r=[...this.tcpStreamIds.entries()].find(([,s])=>s===n.streamId)?.[0];if(!r)return;let o=this.tcpStreams.get(r);if(o){if(n.frameType===2){o.write(n.payload);return}n.frameType===3&&(o.end(),this.tcpStreams.delete(r),this.tcpStreamIds.delete(r))}}async handleHttpRequest(t){let n=this.ws;if(!n||n.readyState!==Yt.OPEN)return;let r=t.bodyBase64?Buffer.from(t.bodyBase64,"base64"):void 0,o={host:this.opts.expose.host,port:this.opts.expose.port,method:t.method,path:t.path,headers:{...t.headers}};await new Promise(s=>{let i=Ay.request(o,a=>{let l=[];a.on("data",d=>l.push(Buffer.isBuffer(d)?d:Buffer.from(d))),a.on("end",()=>{let d=Buffer.concat(l);n.send(Gn({type:"http_res",requestId:t.requestId,status:a.statusCode??502,headers:a.headers,...d.length>0?{bodyBase64:d.toString("base64")}:{}})),s()})});i.on("error",a=>{n.send(Gn({type:"http_res",requestId:t.requestId,status:502,headers:{"content-type":"text/plain"},bodyBase64:Buffer.from(String(a)).toString("base64")})),s()}),r&&r.length>0&&i.write(r),i.end()})}async handleTcpOpen(t){let n=this.ws;if(!n||n.readyState!==Yt.OPEN)return;let r=Ly(t);this.tcpStreamIds.set(t,r);let o=Iy.connect({host:this.opts.expose.host,port:this.opts.expose.port});this.tcpStreams.set(t,o),o.on("data",s=>{n.readyState===Yt.OPEN&&n.send(as(2,r,Buffer.isBuffer(s)?s:Buffer.from(s)))}),o.on("close",()=>{n.readyState===Yt.OPEN&&n.send(as(3,r)),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)}),o.on("error",()=>{n.readyState===Yt.OPEN&&n.send(as(3,r)),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)})}closeTcpStream(t){let n=this.tcpStreams.get(t);n&&n.destroy(),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)}cleanupTcpStreams(){for(let t of this.tcpStreams.values())t.destroy();this.tcpStreams.clear(),this.tcpStreamIds.clear()}async stop(){if(this.stopped)return;this.stopped=!0,this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null);let t=this.ws;t&&t.readyState===Yt.OPEN&&(t.send(Gn({type:"unregister",id:this.record.id})),t.close()),this.cleanupTcpStreams(),this.setStatus("stopped")}};var cs=class{clients=new Map;list(){return[...new Set(this.clients.values())].map(t=>t.getRecord())}getActiveCount(){return[...new Set(this.clients.values())].filter(t=>t.getRecord().status==="active").length}async expose(t,n){let r=ht();if(!r)throw new Error("No tunnel token configured. Run `omnish tunnel login` or set OMNISH_TUNNEL_TOKEN.");let o=t.tunnelMaxActive>0?t.tunnelMaxActive:5;if(this.getActiveCount()>=o)throw new Error(`Active tunnel limit reached (${o}). Stop one with \`omnish tunnel stop <id>\`.`);let s=n.relayUrl||rt(t.tunnelRelayUrl||$e),i=new ls({relayUrl:s,token:r,expose:n,onStatus:l=>{(l.status==="stopped"||l.status==="error")&&this.clients.delete(l.id)}}),a=await i.start();return this.clients.set(a.id,i),a.slug&&this.clients.set(a.slug,i),a}async stop(t){let n=t.trim().toLowerCase(),r=this.clients.get(n)??this.clients.get(t.trim());if(!r)return null;let o=r.getRecord();return await r.stop(),this.clients.delete(o.id),o.slug&&this.clients.delete(o.slug),r.getRecord()}async stopAll(){let t=[...new Set(this.clients.values())];await Promise.all(t.map(n=>n.stop())),this.clients.clear()}};async function Cd(e,t){let n=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)}),r=await n.json();return!n.ok||!r.token?{ok:!1,error:r.error??`HTTP ${n.status}`}:{ok:!0,token:r.token}}function us(e,t){let n=new URL("/auth/signup",e).toString();return Cd(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}function ds(e,t){let n=new URL("/auth/login",e).toString();return Cd(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}var Jn=new cs;function dn(){return Jn}function Oy(e){let t=[J(e,"omnish tunnel"),w(e,"Expose local HTTP or TCP ports through the omnish relay."),"",J(e,"Usage:"),` ${S(e,"omnish tunnel signup [--email <email>] [--phone <phone>] [--password <pass>] [--relay <url>]")}`,` ${S(e,"omnish tunnel login [--token <token>] [--relay <url>]")}`,` ${S(e,"omnish tunnel login --email <email> --password <pass> [--relay <url>]")}`,` ${S(e,"omnish tunnel logout")}`,` ${S(e,"omnish tunnel status [--relay <url>]")}`,` ${S(e,"omnish tunnel http <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]")}`,` ${S(e,"omnish tunnel tcp <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]")}`,` ${S(e,"omnish tunnel list")}`,` ${S(e,"omnish tunnel stop <id|slug>")}`,"",w(e,"Secrets live in ~/.omnish/tunnel-auth.json or OMNISH_TUNNEL_TOKEN."),w(e,`Default relay: ${$e}`),""];console.log(t.join(`
|
|
262
|
-
`))}async function
|
|
263
|
-
${w(n,`${i.localHost}:${i.localPort}`)}`);return}if(t.kind==="stop"){let s=await
|
|
264
|
-
`,{mode:384})}function
|
|
265
|
-
`).replace(/\n/g," ").trim();return t?t.length>
|
|
266
|
-
Script: ${s.scriptPath}`,u=["*Service status*","",`platform: ${
|
|
267
|
-
`),c=["<b>Service status</b>","",`<code>${
|
|
268
|
-
`);return
|
|
261
|
+
`)}var ta=null;function rs(e,t){if(ta)return{stop:()=>{}};let n=Sy.createServer((r,o)=>{if(r.method!=="POST"){o.writeHead(405,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Method not allowed"}));return}let s=r.headers.authorization,i=s?.startsWith("Bearer ")?s.slice(7):void 0,a=new URL(r.url??"/",`http://${r.headers.host??"localhost"}`).searchParams.get("token")??void 0;if(!xy(i??a,e.token)){o.writeHead(401,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Unauthorized"}));return}let d="",u=0;r.on("data",c=>{if(u+=c.length,u>vy){o.writeHead(413,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Payload too large"})),r.destroy();return}d+=c.toString("utf8")}),r.on("end",()=>{let c;try{c=JSON.parse(d)}catch{o.writeHead(400,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Invalid JSON"}));return}let f=new URL(r.url??"/",`http://${r.headers.host??"localhost"}`).searchParams.get("source")??r.headers["x-webhook-source"]??void 0;f&&(c.source=f);let h=typeof c.peerKey=="string"&&c.peerKey||t.getDefaultPeerKey();if(!h){o.writeHead(400,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"No target peer. Set peerKey in body or configure an allowlisted identity."}));return}let g=$y(c);t.sendToPeer(h,g).then(()=>{o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!0}))},y=>{M.warn({err:String(y)},"webhook: sendToPeer failed"),o.writeHead(502,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Failed to deliver message"}))})})});return n.listen(e.port,e.host,()=>{let r=n.address(),o=typeof r=="object"&&r?r.port:e.port;M.info({port:o,host:e.host},"webhook receiver listening")}),n.on("error",r=>{M.error({err:String(r)},"webhook receiver error")}),ta=n,{stop:()=>{try{n.close()}catch{}ta=null}}}me();import tb from"node:crypto";import Na from"node:fs";be();import Ry from"node:fs";function bd(e,t,n){let r=e.fileReceiveMaxBytes,o;try{o=Buffer.from(n.dataBase64,"base64")}catch{return{mediaError:"Invalid inbound media payload."}}if(r>0&&o.length>r)return{mediaError:`Media too large (max ${r} bytes).`};let s;try{s=Ut(e,t)}catch(a){return{mediaError:String(a)}}let i=Hn(s,t,n.name);try{return Ry.writeFileSync(i,o,{mode:384}),{mediaSavedPath:i}}catch{return{mediaError:"Could not write media to inbox."}}}G();Cr();be();import da from"ws";import Iy from"ws";var Ay=["/platform/device","/control/device"];function as(e){let t=e.replace(/\/$/,"");return Ay.map(n=>{let r=new URL(n,t);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.toString()})}var Oy=Math.ceil(md*1.4)+512*1024;function Ly(e){let t=String(e instanceof Error?e.message:e);return/Unexpected server response:\s*400/.test(t)||/Unexpected server response:\s*404/.test(t)}async function xd(e,t){let n=as(e),r=null;for(let s of n)try{return{ws:await new Promise((a,l)=>{let d=new Iy(s,{headers:{Authorization:`Bearer ${t}`},maxPayload:Oy});d.once("open",()=>a(d)),d.once("error",l)}),pathname:new URL(s).pathname}}catch(i){if(r=i instanceof Error?i:new Error(String(i)),Ly(i))continue;throw r}let o="Could not open a device WebSocket. Redeploy the relay (for /control/device fallback) and ensure /platform/* or /control/* route to port 8788.";throw r&&/Unexpected server response:\s*400/.test(r.message)?new Error(`${r.message} \u2014 ${o}`):new Error(r?`${r.message} \u2014 ${o}`:o)}var Ny=1e3,_y=6e4,ls=class{constructor(t){this.options=t}ws=null;stopped=!1;pingTimer=null;registerResolve=null;registerReject=null;registeredAccount=null;registeredDeviceId=null;reconnectAttempt=0;reconnectTimer=null;outboundQueue=[];getRegisteredAccount(){return this.registeredAccount}async connect(){return this.connectOnce()}async connectOnce(){let{env:t}=this.options,n=new Promise((a,l)=>{this.registerResolve=a,this.registerReject=l}),{ws:r,pathname:o}=await xd(t.platformUrl,t.token);this.ws=r,o!=="/platform/device"&&M.info({pathname:o},"platform device websocket connected via fallback path"),r.on("message",a=>{this.handleMessage(a.toString())}),r.on("close",()=>{this.stopped||(M.warn("platform device websocket closed; scheduling reconnect"),this.scheduleReconnect())}),r.on("error",a=>{M.warn({err:String(a)},"platform device websocket error")});let s=setTimeout(()=>{this.registerReject?.(new Error("Platform device register timeout (15s)"))},15e3);this.sendRaw({type:"register",...t.deviceId?{deviceId:t.deviceId}:{},label:process.env.OMNISH_DEVICE_LABEL?.trim()||"default"});let i=await n;return clearTimeout(s),this.registeredDeviceId=i.deviceId,this.reconnectAttempt=0,this.pingTimer&&clearInterval(this.pingTimer),this.pingTimer=setInterval(()=>{this.sendRaw({type:"ping"})},3e4),this.flushOutboundQueue(),i}scheduleReconnect(){if(this.stopped||this.reconnectTimer)return;this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null),this.ws=null;let t=Math.min(Ny*2**this.reconnectAttempt,_y);this.reconnectAttempt+=1,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,!this.stopped&&this.connectOnce().catch(n=>{M.warn({err:String(n)},"platform device reconnect failed"),this.scheduleReconnect()})},t),this.reconnectTimer.unref?.()}async handleMessage(t){let n=hd(t);if(n){if(n.type==="registered"&&"deviceId"in n){n.account&&(this.registeredAccount=n.account),this.registerResolve?.({deviceId:n.deviceId,...n.account?{account:n.account}:{}}),this.registerResolve=null,this.registerReject=null;return}if(n.type==="message"){await this.options.onMessage(n);return}if(n.type==="reply_error"){await this.options.onReplyError?.(n.peerKey,n.error,n.messageId);return}n.type==="error"&&(M.warn({message:n.message},"platform error"),this.registerReject?.(new Error(n.message)),this.registerResolve=null,this.registerReject=null)}}sendReply(t,n,r,o){this.enqueue({type:"reply",peerKey:t,...n?{body:n}:{},...r?{messageId:r}:{},...o?.length?{files:o}:{}})}sendRoutedReply(t,n){this.enqueue({type:"reply",peerKey:t,...n})}enqueue(t){if(this.ws?.readyState===da.OPEN){this.sendRaw(t);return}if(this.outboundQueue.length>=fd){M.warn("platform outbound queue full; dropping reply");return}this.outboundQueue.push(t)}flushOutboundQueue(){for(;this.outboundQueue.length>0&&this.ws?.readyState===da.OPEN;){let t=this.outboundQueue.shift();t&&this.sendRaw(t)}}sendRaw(t){this.ws?.readyState===da.OPEN&&this.ws.send(JSON.stringify(t))}stop(){this.stopped=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null);try{this.ws?.close()}catch{}this.ws=null,this.outboundQueue.length=0}};import ha from"node:readline/promises";import{stdin as ga,stdout as hs}from"node:process";me();var Fy=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;function Rd(e){let t=e.trim().toLowerCase();return t?t.length>63?"Tunnel name must be at most 63 characters.":Fy.test(t)?null:"Tunnel name may only use letters, digits, and hyphens.":"Tunnel name must not be empty."}function Cd(e){let t=Number.parseInt(e,10);return!Number.isInteger(t)||t<1||t>65535?null:t}function $d(e,t){let n="127.0.0.1",r,o,s=!1,i=[];for(let d=0;d<t.length;d++){let u=t[d];if(u==="--host"){let c=t[++d];if(!c)return{kind:"error",message:"--host requires an address."};n=c;continue}if(u.startsWith("--host=")){n=u.slice(7);continue}if(u==="--relay"){let c=t[++d];if(!c)return{kind:"error",message:"--relay requires a URL."};r=c;continue}if(u.startsWith("--relay=")){r=u.slice(8);continue}if(u==="--name"){let c=t[++d];if(!c)return{kind:"error",message:"--name requires a slug."};o=c;continue}if(u.startsWith("--name=")){o=u.slice(7);continue}if(u==="--background"||u==="-b"){s=!0;continue}i.push(u)}let a=i[0];if(!a)return{kind:"error",message:`Usage: omnish tunnel ${e} <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]`};let l=Cd(a);if(l===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};if(o){let d=Rd(o);if(d)return{kind:"error",message:d}}return{kind:"expose",options:{kind:e,port:l,host:n,relayUrl:r??"",name:o,background:s}}}function pa(e){let[t,...n]=e,r=(t??"").trim().toLowerCase();if(!r||r==="help"||r==="-h"||r==="--help")return{kind:"help"};if(r==="signup"){let o,s,i,a;for(let l=0;l<n.length;l++){let d=n[l];if(d==="--email"){o=n[++l];continue}if(d.startsWith("--email=")){o=d.slice(8);continue}if(d==="--phone"){s=n[++l];continue}if(d.startsWith("--phone=")){s=d.slice(8);continue}if(d==="--password"){i=n[++l];continue}if(d.startsWith("--password=")){i=d.slice(11);continue}if(d==="--relay"){a=n[++l];continue}if(d.startsWith("--relay=")){a=d.slice(8);continue}}return{kind:"signup",email:o,phone:s,password:i,relayUrl:a}}if(r==="login"){let o,s,i,a,l;for(let d=0;d<n.length;d++){let u=n[d];if(u==="--token"){o=n[++d];continue}if(u.startsWith("--token=")){o=u.slice(8);continue}if(u==="--email"){s=n[++d];continue}if(u.startsWith("--email=")){s=u.slice(8);continue}if(u==="--phone"){i=n[++d];continue}if(u.startsWith("--phone=")){i=u.slice(8);continue}if(u==="--password"){a=n[++d];continue}if(u.startsWith("--password=")){a=u.slice(11);continue}if(u==="--relay"){l=n[++d];continue}if(u.startsWith("--relay=")){l=u.slice(8);continue}o||(o=u)}return{kind:"login",token:o,email:s,phone:i,password:a,relayUrl:l}}if(r==="logout")return{kind:"logout"};if(r==="list")return{kind:"list"};if(r==="status"){let o;for(let s=0;s<n.length;s++){let i=n[s];if(i==="--relay"){o=n[s+1],s++;continue}i.startsWith("--relay=")&&(o=i.slice(8))}return{kind:"status",relayUrl:o}}if(r==="stop"){let o=n[0]?.trim();return o?{kind:"stop",target:o}:{kind:"error",message:"Usage: omnish tunnel stop <id|slug>"}}return r==="http"?$d("http",n):r==="tcp"?$d("tcp",n):{kind:"error",message:`Unknown tunnel subcommand "${t}". Try: omnish tunnel help`}}function Wy(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){s===r?r=null:n+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){n.length&&(t.push(n),n="");continue}n+=s}return n.length&&t.push(n),t}function Md(e){let t=e.trim();if(!t||t==="help")return{kind:"help"};let n=Wy(t),r=n[0]?.toLowerCase();if(r==="login"||r==="logout"||r==="status"||r==="signup")return pa(n);if(t.toLowerCase()==="list"||t.toLowerCase()==="ls")return{kind:"list"};let o=t.match(/^stop\s+(\S+)\s*$/i);if(o)return{kind:"stop",target:o[1]};let s=t.match(/^(http|tcp)\s+(\d+)(?:\s+--name\s+(\S+))?(?:\s+--host\s+(\S+))?\s*$/i);if(s){let i=s[1].toLowerCase(),a=Cd(s[2]);if(a===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};let l=s[3],d=s[4]??"127.0.0.1";if(l){let u=Rd(l);if(u)return{kind:"error",message:u}}return{kind:"expose",options:{kind:i,port:a,host:d,relayUrl:"",name:l,background:!0}}}return{kind:"error",message:"Usage: /tunnel login \u2026 | /tunnel status | /tunnel http <port> | /tunnel tcp <port> | /tunnels | /tunnel stop <id>"}}import Uy from"ws";import{URL as Td}from"node:url";function Yn(e){let t=new Td(e);return t.protocol=t.protocol==="https:"?"wss:":"ws:",(!t.pathname||t.pathname==="/")&&(t.pathname="/control"),t.toString()}function Ed(e){return new Td("/health",e).toString()}async function cs(e,t,n=1e4){let r=t.trim();if(!r)return{ok:!1,healthOk:!1,controlOk:!1,error:"Tunnel token is missing."};let o=Ed(e),s=!1,i;try{let d=await fetch(o,{method:"GET",signal:AbortSignal.timeout(n)});if(!d.ok)return{ok:!1,healthOk:!1,controlOk:!1,error:`Health HTTP ${d.status} (${o})`};let u=await d.json();if(!u?.ok)return{ok:!1,healthOk:!1,controlOk:!1,error:"Health JSON missing ok:true"};s=!0,typeof u.version=="string"&&(i=u.version)}catch(d){return{ok:!1,healthOk:!1,controlOk:!1,error:`Health fetch failed: ${String(d)}`}}let a=Yn(e),l=!1;try{await new Promise((d,u)=>{let c=new Uy(a,{headers:{Authorization:`Bearer ${r}`}}),m=setTimeout(()=>{c.terminate(),u(new Error("WSS auth timeout"))},n);c.once("message",f=>{clearTimeout(m);try{let h=JSON.parse(f.toString());if(h.type!=="auth_ok"){u(new Error(`Expected auth_ok, got ${h.type??"?"}`));return}c.close(),d()}catch(h){u(h)}}),c.once("error",f=>{clearTimeout(m),u(f)})}),l=!0}catch(d){return{ok:!1,healthOk:!0,healthVersion:i,controlOk:!1,error:`Control WebSocket: ${String(d)}`}}return{ok:!0,healthOk:s,healthVersion:i,controlOk:!0}}rn();on();on();rn();import Id from"node:crypto";import Dy from"node:http";import Hy from"node:net";import Xt from"ws";function us(e,t,n=Buffer.alloc(0)){let r=Buffer.allocUnsafe(9+n.length);return r.writeUInt8(e,0),r.writeUInt32BE(t,1),r.writeUInt32BE(n.length,5),n.copy(r,9),r}function Pd(e){if(e.length<9)return null;let t=e.readUInt8(0),n=e.readUInt32BE(1),r=e.readUInt32BE(5);return e.length<9+r?null:{frameType:t,streamId:n,payload:e.subarray(9,9+r)}}function ma(e){try{let t=JSON.parse(e);return!t||typeof t!="object"||typeof t.type!="string"?null:t}catch{return null}}function Qn(e){return JSON.stringify(e)}function By(e){let t=Id.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return Number.parseInt(t,16)>>>0}var ds=class{constructor(t){this.opts=t;let n=Id.randomBytes(4).toString("hex");this.record={id:n,kind:t.expose.kind,slug:t.expose.name?.trim().toLowerCase()??"",localHost:t.expose.host,localPort:t.expose.port,publicUrl:"",status:"connecting",startedAt:new Date().toISOString()}}ws=null;record;tcpStreams=new Map;tcpStreamIds=new Map;stopped=!1;pingTimer=null;getRecord(){return{...this.record}}setStatus(t,n){this.record.status=t,this.record.error=n,this.opts.onStatus?.(this.getRecord())}async start(){if(this.stopped)throw new Error("Tunnel client already stopped.");let t=Yn(this.opts.relayUrl),n=new Xt(t,{headers:{Authorization:`Bearer ${this.opts.token}`}});this.ws=n,await new Promise((o,s)=>{let i=d=>{l(),s(d)},a=()=>{l(),o()},l=()=>{n.off("error",i),n.off("open",a)};n.once("error",i),n.once("open",a)}),n.on("message",(o,s)=>{if(s){this.handleBinary(Buffer.isBuffer(o)?o:Buffer.from(o));return}let i=typeof o=="string"?o:o.toString("utf8");this.handleControl(i)}),n.on("close",()=>{this.stopped||this.setStatus("error","Relay connection closed."),this.cleanupTcpStreams()}),n.on("error",o=>{this.stopped||this.setStatus("error",String(o))}),this.pingTimer=setInterval(()=>{n.readyState===Xt.OPEN&&n.send(Qn({type:"ping"}))},3e4),n.send(Qn({type:"register",id:this.record.id,kind:this.opts.expose.kind,localHost:this.opts.expose.host,localPort:this.opts.expose.port,...this.opts.expose.name?{name:this.opts.expose.name}:{}}));let r=await this.waitForRegistered();return this.record.slug=r.slug,this.record.publicUrl=r.publicUrl,this.setStatus("active"),this.getRecord()}waitForRegistered(){let t=this.ws;return t?new Promise((n,r)=>{let o=s=>{if(typeof s!="string"&&!Buffer.isBuffer(s))return;let i=typeof s=="string"?s:s.toString("utf8"),a=ma(i);if(a){if(a.type==="registered"&&a.id===this.record.id){t.off("message",o),n(a);return}a.type==="error"&&(t.off("message",o),r(new Error(a.message)))}};t.on("message",o)}):Promise.reject(new Error("WebSocket not connected."))}async handleControl(t){let n=ma(t);if(n&&!(n.type==="pong"||n.type==="auth_ok")){if(n.type==="error"){this.setStatus("error",n.message);return}if(n.type==="http"){await this.handleHttpRequest(n);return}if(n.type==="tcp_open"){await this.handleTcpOpen(n.streamId);return}n.type==="tcp_close"&&this.closeTcpStream(n.streamId)}}handleBinary(t){let n=Pd(t);if(!n)return;let r=[...this.tcpStreamIds.entries()].find(([,s])=>s===n.streamId)?.[0];if(!r)return;let o=this.tcpStreams.get(r);if(o){if(n.frameType===2){o.write(n.payload);return}n.frameType===3&&(o.end(),this.tcpStreams.delete(r),this.tcpStreamIds.delete(r))}}async handleHttpRequest(t){let n=this.ws;if(!n||n.readyState!==Xt.OPEN)return;let r=t.bodyBase64?Buffer.from(t.bodyBase64,"base64"):void 0,o={host:this.opts.expose.host,port:this.opts.expose.port,method:t.method,path:t.path,headers:{...t.headers}};await new Promise(s=>{let i=Dy.request(o,a=>{let l=[];a.on("data",d=>l.push(Buffer.isBuffer(d)?d:Buffer.from(d))),a.on("end",()=>{let d=Buffer.concat(l);n.send(Qn({type:"http_res",requestId:t.requestId,status:a.statusCode??502,headers:a.headers,...d.length>0?{bodyBase64:d.toString("base64")}:{}})),s()})});i.on("error",a=>{n.send(Qn({type:"http_res",requestId:t.requestId,status:502,headers:{"content-type":"text/plain"},bodyBase64:Buffer.from(String(a)).toString("base64")})),s()}),r&&r.length>0&&i.write(r),i.end()})}async handleTcpOpen(t){let n=this.ws;if(!n||n.readyState!==Xt.OPEN)return;let r=By(t);this.tcpStreamIds.set(t,r);let o=Hy.connect({host:this.opts.expose.host,port:this.opts.expose.port});this.tcpStreams.set(t,o),o.on("data",s=>{n.readyState===Xt.OPEN&&n.send(us(2,r,Buffer.isBuffer(s)?s:Buffer.from(s)))}),o.on("close",()=>{n.readyState===Xt.OPEN&&n.send(us(3,r)),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)}),o.on("error",()=>{n.readyState===Xt.OPEN&&n.send(us(3,r)),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)})}closeTcpStream(t){let n=this.tcpStreams.get(t);n&&n.destroy(),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)}cleanupTcpStreams(){for(let t of this.tcpStreams.values())t.destroy();this.tcpStreams.clear(),this.tcpStreamIds.clear()}async stop(){if(this.stopped)return;this.stopped=!0,this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null);let t=this.ws;t&&t.readyState===Xt.OPEN&&(t.send(Qn({type:"unregister",id:this.record.id})),t.close()),this.cleanupTcpStreams(),this.setStatus("stopped")}};var ps=class{clients=new Map;list(){return[...new Set(this.clients.values())].map(t=>t.getRecord())}getActiveCount(){return[...new Set(this.clients.values())].filter(t=>t.getRecord().status==="active").length}async expose(t,n){let r=gt();if(!r)throw new Error("No tunnel token configured. Run `omnish tunnel login` or set OMNISH_TUNNEL_TOKEN.");let o=t.tunnelMaxActive>0?t.tunnelMaxActive:5;if(this.getActiveCount()>=o)throw new Error(`Active tunnel limit reached (${o}). Stop one with \`omnish tunnel stop <id>\`.`);let s=n.relayUrl||rt(t.tunnelRelayUrl||$e),i=new ds({relayUrl:s,token:r,expose:n,onStatus:l=>{(l.status==="stopped"||l.status==="error")&&this.clients.delete(l.id)}}),a=await i.start();return this.clients.set(a.id,i),a.slug&&this.clients.set(a.slug,i),a}async stop(t){let n=t.trim().toLowerCase(),r=this.clients.get(n)??this.clients.get(t.trim());if(!r)return null;let o=r.getRecord();return await r.stop(),this.clients.delete(o.id),o.slug&&this.clients.delete(o.slug),r.getRecord()}async stopAll(){let t=[...new Set(this.clients.values())];await Promise.all(t.map(n=>n.stop())),this.clients.clear()}};async function Od(e,t){let n=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)}),r=await n.json();return!n.ok||!r.token?{ok:!1,error:r.error??`HTTP ${n.status}`}:{ok:!0,token:r.token}}function ms(e,t){let n=new URL("/auth/signup",e).toString();return Od(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}function fs(e,t){let n=new URL("/auth/login",e).toString();return Od(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}var Vn=new ps;function gn(){return Vn}function jy(e){let t=[J(e,"omnish tunnel"),w(e,"Expose local HTTP or TCP ports through the omnish relay."),"",J(e,"Usage:"),` ${S(e,"omnish tunnel signup [--email <email>] [--phone <phone>] [--password <pass>] [--relay <url>]")}`,` ${S(e,"omnish tunnel login [--token <token>] [--relay <url>]")}`,` ${S(e,"omnish tunnel login --email <email> --password <pass> [--relay <url>]")}`,` ${S(e,"omnish tunnel logout")}`,` ${S(e,"omnish tunnel status [--relay <url>]")}`,` ${S(e,"omnish tunnel http <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]")}`,` ${S(e,"omnish tunnel tcp <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]")}`,` ${S(e,"omnish tunnel list")}`,` ${S(e,"omnish tunnel stop <id|slug>")}`,"",w(e,"Secrets live in ~/.omnish/tunnel-auth.json or OMNISH_TUNNEL_TOKEN."),w(e,`Default relay: ${$e}`),""];console.log(t.join(`
|
|
262
|
+
`))}async function Gy(){let e=ha.createInterface({input:ga,output:hs});try{return(await e.question("Tunnel token: ")).trim()}finally{e.close()}}async function Ld(e){let t=pa(e),n=hs,r=process.stderr;if(t.kind==="help"){jy(n);return}if(t.kind==="error"){console.error(C(r,t.message)),process.exitCode=1;return}let o=$();if(t.kind==="signup"){let s=t.relayUrl||rt(o.tunnelRelayUrl||$e),i=ha.createInterface({input:ga,output:hs});try{let a=t.email?.trim()||(await i.question("Email (or leave empty for phone): ")).trim(),l=t.phone?.trim()||"";if(a||(l=l||(await i.question("Phone: ")).trim()),!a&&!l){console.error(C(r,"Email or phone is required.")),process.exitCode=1;return}let d=t.password||(await i.question("Password (min 8 chars): ")).trim();if(d.length<8){console.error(C(r,"Password must be at least 8 characters.")),process.exitCode=1;return}let u=await ms(s,{...a?{email:a}:{},...l?{phone:l}:{},password:d});if(!u.ok){console.error(C(r,u.error)),process.exitCode=1;return}ht({token:u.token,...t.relayUrl?{relayUrl:t.relayUrl}:{}}),console.log(B(n,"Account created. Token saved."))}finally{i.close()}return}if(t.kind==="login"){if(t.email||t.phone){let a=t.relayUrl||rt(o.tunnelRelayUrl||$e),l=ha.createInterface({input:ga,output:hs});try{let d=t.password||(await l.question("Password: ")).trim(),u=await fs(a,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:d});if(!u.ok){console.error(C(r,u.error)),process.exitCode=1;return}ht({token:u.token,...t.relayUrl?{relayUrl:t.relayUrl}:{}}),console.log(B(n,"Logged in. Token saved."))}finally{l.close()}return}let i=t.token?.trim()||await Gy();if(!i){console.error(C(r,"Tunnel token is required.")),process.exitCode=1;return}ht({token:i,...t.relayUrl?{relayUrl:t.relayUrl}:{}}),console.log(B(n,"Tunnel token saved."));return}if(t.kind==="logout"){mo(),console.log(B(n,"Tunnel token removed."));return}if(t.kind==="status"){let s=t.relayUrl||rt(o.tunnelRelayUrl||$e),i=gt(),a=!!process.env.OMNISH_TUNNEL_TOKEN?.trim(),l=await cs(s,i);console.log(`${w(n,"relay:")} ${S(n,s)}`),console.log(`${w(n,"token:")} ${S(n,i?`configured${a?" (OMNISH_TUNNEL_TOKEN)":""}`:C(r,"missing"))}`),console.log(`${w(n,"health:")} ${l.healthOk?S(n,`ok${l.healthVersion?` (${l.healthVersion})`:""}`):C(r,"fail")}`),console.log(`${w(n,"control:")} ${l.controlOk?S(n,"auth ok"):C(r,"fail")}${l.error&&!l.ok?` \u2014 ${l.error}`:""}`),console.log(`${w(n,"active:")} ${S(n,String(Vn.getActiveCount()))}`);return}if(t.kind==="list"){let s=Vn.list();if(s.length===0){console.log(B(n,"(no active tunnels)"));return}for(let i of s)console.log(`${S(n,i.id)} ${i.kind} ${i.status} ${i.publicUrl||"(pending)"}
|
|
263
|
+
${w(n,`${i.localHost}:${i.localPort}`)}`);return}if(t.kind==="stop"){let s=await Vn.stop(t.target);if(!s){console.error(C(r,`No active tunnel matched "${t.target}".`)),process.exitCode=1;return}console.log(B(n,`Stopped tunnel ${s.id}.`));return}if(t.kind==="expose"){let s=t.options.relayUrl||rt(o.tunnelRelayUrl||$e),i=await Vn.expose(o,{...t.options,relayUrl:s});console.log(B(n,`${i.kind.toUpperCase()} tunnel active`)),console.log(`${w(n,"public:")} ${S(n,i.publicUrl)}`),console.log(`${w(n,"local:")} ${S(n,`${i.localHost}:${i.localPort}`)}`),console.log(`${w(n,"id:")} ${S(n,i.id)}`),t.options.background||(console.log(w(n,"Press Ctrl+C to stop.")),await new Promise(a=>{let l=async()=>{await Vn.stop(i.id),a()};process.once("SIGINT",l),process.once("SIGTERM",l)}))}}function Nd(e){let t=e.trim().match(/^(\d+)\.(\d+)\.(\d+)/);return t?[Number(t[1]),Number(t[2]),Number(t[3])]:null}function _d(e,t){let n=Nd(e),r=Nd(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 Jy="https://registry.npmjs.org",Fd=null,ya=0;function Mr(){return Fd}function Ky(e){let t=e.trim();return t.length<1||t.length>214?!1:!/\s/.test(t)}function Wd(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 zy(e){let t=e.trim(),n=`${Jy}/${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 qy(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=Wd(d)),{message:a,link:l}}catch(t){return{error:`updateInfoUrl: ${String(t)}`}}}function Yy(e){return!Number.isFinite(e)||e<36e5?36e5:e>6048e5?6048e5:Math.floor(e)}async function Tr(e,t){let n=Ky(t.updateCheckPackageName)?t.updateCheckPackageName.trim():"omnish",r=await zy(n),o="version"in r?r.version:null,s="error"in r?r.error:null,i=!1;o&&!s&&(i=_d(e,o)<0);let a=null,l=null,d=null,u=Wd(t.updateInfoUrl);if(u){let m=await qy(u);"error"in m?d=m.error:(a=m.message,l=m.link)}let c={runningVersion:e,checkedAtIso:new Date().toISOString(),registryPackage:n,registryLatest:o,registryError:s,updateAvailable:i,infoMessage:a,infoLink:l,infoError:d};return Fd=c,c}function gs(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 ys(e){let t=!1,n=async()=>{if(t)return;let s=e.getConfig();if(!s.updateCheckEnabled)return;let i=Yy(s.updateCheckIntervalMs),a=Date.now();if(!(ya!==0&&a-ya<i)){ya=a;try{let l=await Tr(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)}}me();it();import Ud from"node:path";import{glob as Qy,stat as Vy}from"node:fs/promises";function ws(e){let t=e.trim();if(!t||t.startsWith("-- ")||t==="--")return null;let n=t.indexOf(" -- "),r,o;return n!==-1?(r=t.slice(0,n).trim(),o=t.slice(n+4).trim()||void 0):r=t,(r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'"))&&(r=r.slice(1,-1)),r.trim()?{selectorPart:r,caption:o}:null}function Xy(e){return/[*?[]/.test(e)}function Zy(e){return e.split(",").map(t=>t.trim()).filter(t=>t.length>0)}async function Er(e,t){let n=Zy(t),r=new Set,o=[];for(let s of n){if(Xy(s)){for await(let a of Qy(s,{cwd:e,withFileTypes:!1})){let l=Ud.resolve(e,a);r.has(l)||(r.add(l),o.push(l))}continue}let i=Ud.resolve(e,s);r.has(i)||(r.add(i),o.push(i))}return o}async function Pr(e){for(let t of e)try{if(!(await Vy(t)).isFile())return{ok:!1,error:`Not a file: ${t}`}}catch{return{ok:!1,error:`File not found: ${t}`}}return{ok:!0}}G();import Bd from"node:fs";import ew from"node:path";var yn="__omnish_shortcuts_global__",Dd=500,jd=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,tw=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"]),Ar=new Map,Hd=!1;function nw(){try{let e=Bd.readFileSync(Br,"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())}Ar.set(n,o)}}catch{}}function bs(){j(ew.dirname(Br));let e={};for(let[t,n]of Ar)Object.entries(n).length>0&&(e[t]={...n});Bd.writeFileSync(Br,JSON.stringify(e,null,2)+`
|
|
264
|
+
`,{mode:384})}function ks(){Hd||(nw(),Hd=!0)}function rw(e){return tw.has(e.trim().toLowerCase())}function bt(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return jd.test(n)?rw(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 wa(e){let t=e.replace(/\r\n/g,`
|
|
265
|
+
`).replace(/\n/g," ").trim();return t?t.length>Dd?{ok:!1,error:`Body too long (max ${Dd} characters).`}:{ok:!0,body:t}:{ok:!1,error:"Body is empty."}}function wt(e,t){ks();let n=Ar.get(e);return!n&&t&&(n={},Ar.set(e,n)),n??{}}function Gd(e){let t=e.trim();if(/^--global$/i.test(t))return{mode:"global",remainder:""};if(/^-g$/i.test(t))return{mode:"global",remainder:""};if(/^--chat$/i.test(t))return{mode:"chat",remainder:""};if(/^-p$/i.test(t))return{mode:"chat",remainder:""};let n=/^--global\s+/i.exec(t);if(n)return{mode:"global",remainder:t.slice(n[0].length).trimStart()};let r=/^-g\s+/i.exec(t);if(r)return{mode:"global",remainder:t.slice(r[0].length).trimStart()};let o=/^--chat\s+/i.exec(t);if(o)return{mode:"chat",remainder:t.slice(o[0].length).trimStart()};let s=/^-p\s+/i.exec(t);return s?{mode:"chat",remainder:t.slice(s[0].length).trimStart()}:{mode:"resolved",remainder:t}}function ba(e){let t=e.trim();if(/^--global$/i.test(t))return{scope:"global",remainder:"",explicit:!0};if(/^-g$/i.test(t))return{scope:"global",remainder:"",explicit:!0};if(/^--chat$/i.test(t))return{scope:"chat",remainder:"",explicit:!0};if(/^-p$/i.test(t))return{scope:"chat",remainder:"",explicit:!0};let n=/^--global\s+([\s\S]*)$/i.exec(t);if(n?.[1]!==void 0)return{scope:"global",remainder:n[1].trimStart(),explicit:!0};let r=/^-g\s+([\s\S]*)$/i.exec(t);if(r?.[1]!==void 0)return{scope:"global",remainder:r[1].trimStart(),explicit:!0};let o=/^--chat\s+([\s\S]*)$/i.exec(t);if(o?.[1]!==void 0)return{scope:"chat",remainder:o[1].trimStart(),explicit:!0};let s=/^-p\s+([\s\S]*)$/i.exec(t);return s?.[1]!==void 0?{scope:"chat",remainder:s[1].trimStart(),explicit:!0}:{scope:"chat",remainder:t,explicit:!1}}function ka(e){let t=ba(e);return{scope:t.scope,remainder:t.remainder}}function Jd(e){let t=e.trim();return!t||/^-+$/i.test(t)?{filter:"merged"}:/^(?:--global|-g)$/i.test(t)?{filter:"global"}:/^(?:--chat|-p)$/i.test(t)?{filter:"chat"}:{filter:"merged",bad:t}}function ow(e){let t=e.trim().toLowerCase();if(t==="--global"||t==="-g")return"global";if(t==="--chat"||t==="-p")return"chat"}function Kd(e){let t=e.trim().match(/^(\S+)\s+(--global|-g|--chat|-p)\s*$/i);if(!t?.[1]||!t[2])return;let n=ow(t[2]);if(n)return{name:t[1],target:n}}function sw(e,t){ks();let n=e,r=wt(n,!1),o=wt(yn,!1);if(t==="chat")return Object.entries(r).map(([a,l])=>({name:a,body:l,scope:"chat"})).sort((a,l)=>a.name.localeCompare(l.name));if(t==="global")return Object.entries(o).map(([a,l])=>({name:a,body:l,scope:"global"})).sort((a,l)=>a.name.localeCompare(l.name));let s=new Set([...Object.keys(r),...Object.keys(o)]),i=[];for(let a of[...s].sort()){if(a in r){let d=r[a];d!==void 0&&i.push({name:a,body:d,scope:"chat"});continue}let l=o[a];l!==void 0&&i.push({name:a,body:l,scope:"global"})}return i}function zd(e,t="merged"){return sw(e,t)}function Sa(e,t){let n=t.trim().toLowerCase(),r=wt(e,!1)[n];return r!==void 0?r:wt(yn,!1)[n]}function Ss(e,t){let n=bt(t);if(!n.ok)return;let r=n.normalized,o=wt(e,!1)[r];if(o!==void 0)return{name:r,body:o,scope:"chat"};let s=wt(yn,!1)[r];if(s!==void 0)return{name:r,body:s,scope:"global"}}function Pt(e,t,n){let r=n.trim().toLowerCase(),o=e==="global"?yn:t;return wt(o,!1)[r]}function Ir(e,t,n,r="chat"){let o=bt(t);if(!o.ok)throw new Error(o.error);let s=wa(n);if(!s.ok)throw new Error(s.error);let i=r==="global"?yn:e,a=wt(i,!0);a[o.normalized]=s.body,bs()}function qd(e,t,n="chat"){let r=t.trim().toLowerCase(),o=n==="global"?yn:e;ks();let s=Ar.get(o);return!s||!(r in s)?!1:(delete s[r],bs(),!0)}function va(e,t,n){let r=bt(t);if(!r.ok)return{ok:!1,error:r.error};let o=r.normalized,s=e;ks();let i=wt(s,!0),a=wt(yn,!0),l=i[o],d=a[o];if(n==="global"){if(l!==void 0){let u=wa(l);return u.ok?(a[o]=u.body,delete i[o],bs(),{ok:!0,kind:"moved",target:"global",name:o}):{ok:!1,error:u.error}}return d!==void 0?{ok:!0,kind:"noop",message:`Shortcut "${o}" is already shared on this gateway.`}:{ok:!1,error:`No shortcut "${o}" in this chat to share. Add with /shortcut add ${o} \u2026 or make the shared copy private with /shortcut set -p ${o}.`}}if(d!==void 0){let u=wa(d);return u.ok?(i[o]=u.body,delete a[o],bs(),{ok:!0,kind:"moved",target:"chat",name:o}):{ok:!1,error:u.error}}return l!==void 0?{ok:!0,kind:"noop",message:`Shortcut "${o}" is already private to this chat.`}:{ok:!1,error:`No shared shortcut "${o}" to make private. Add with /shortcut add --global ${o} \u2026 or share from this chat with /shortcut set -g ${o}.`}}function Yd(e){let t=e.trim();return t.length>0&&!/\s/.test(t)&&jd.test(t.toLowerCase())}import Qd from"node:fs";var Vd=64,iw=1024*1024;function Xd(e){return e.fileReceiveMaxBytes>0?e.fileReceiveMaxBytes:iw}function Zd(e){let t;try{t=JSON.parse(e)}catch(o){return{ok:!1,error:`Invalid JSON: ${String(o)}`}}let n;if(Array.isArray(t))n=t;else if(t&&typeof t=="object"&&!Array.isArray(t)){let o=t,s=Object.keys(o);if(s.length!==1||s[0]!=="tasks")return{ok:!1,error:'JSON must be an array or a single-key object: { "tasks": [ \u2026 ] }.'};let i=o.tasks;if(!Array.isArray(i))return{ok:!1,error:'"tasks" must be an array.'};n=i}else return{ok:!1,error:'JSON must be an array or { "tasks": [ \u2026 ] }.'};if(n.length===0)return{ok:!1,error:"Queue JSON must contain at least one job."};if(n.length>Vd)return{ok:!1,error:`Too many jobs (max ${Vd}).`};let r=[];for(let o=0;o<n.length;o++){let s=n[o];if(!s||typeof s!="object"||Array.isArray(s))return{ok:!1,error:`Job ${o+1}: must be an object with "recipe" and "task".`};let i=s;if(Object.keys(i).length!==2||typeof i.recipe!="string"||typeof i.task!="string")return{ok:!1,error:`Job ${o+1}: must contain only "recipe" and "task" string fields.`};r.push({recipe:i.recipe,task:i.task})}return{ok:!0,jobs:r}}function ep(e,t,n){let r=[];for(let o=0;o<n.length;o++){let{recipe:s,task:i}=n[o],a=je(e,t,s);if(!a)return{ok:!1,error:`Job ${o+1}: unknown recipe "${s}".`};let l=a.taskEnv??"OMNISH_TASK";if(!Nn(a.command,l))return{ok:!1,error:`Job ${o+1}: recipe "${s}" command must reference "$${l}".`};let d=Co(i,t.recipesMaxTaskChars);if(!d.ok)return{ok:!1,error:`Job ${o+1}: ${d.error}`};let u=a.promptTemplate?Mo(a.promptTemplate,l,d.task):d.task,c={[l]:u};r.push({command:a.command,extraEnv:c,recipeLabel:s})}return{ok:!0,items:r}}function xa(e,t){let n;try{n=Qd.statSync(e)}catch{return{ok:!1,error:`Cannot read file: ${e}`}}if(!n.isFile())return{ok:!1,error:`Not a file: ${e}`};if(n.size>t)return{ok:!1,error:`File too large (max ${t} bytes for queue load).`};try{return{ok:!0,text:Qd.readFileSync(e,"utf8")}}catch(r){return{ok:!1,error:String(r)}}}G();import tp from"node:fs";import Xn from"node:process";var aw=120;function At(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function np(e){let t=e.trim();return t==="/service"||t.startsWith("/service ")?t.slice(8).trim():null}async function rp(e,t){let n=t.trim().split(/\s+/),r=(n[0]??"").toLowerCase();if(!t.trim()||r==="help")return Z(lc(e));if(r==="status"){let s=an(),i=(()=>{try{return tp.existsSync(ce)?`gateway.pid: ${tp.readFileSync(ce,"utf8").trim()}`:"gateway.pid: (missing)"}catch(m){return`gateway.pid: (read error: ${String(m)})`}})(),a=Xn.env.OMNISH_BACKGROUND_GATEWAY==="1"?"This process: background gateway (OMNISH_BACKGROUND_GATEWAY=1).":"This process: foreground gateway session.",l=typeof Xn.env.OMNISH_HOME=="string"&&Xn.env.OMNISH_HOME.trim()?`OMNISH_HOME env: ${Xn.env.OMNISH_HOME.trim()}`:"OMNISH_HOME env: (not set \u2014 using default data dir)",d=s.error?s.error:`Node: ${s.nodePath}
|
|
266
|
+
Script: ${s.scriptPath}`,u=["*Service status*","",`platform: ${Xn.platform}`,a,l,`data dir: ${H}`,i,`default log: ${Ne}`,"",d,"",e.serviceInstallFromChat?"Install from chat: enabled (/service install).":"Install from chat: off \u2014 `/config set serviceInstallFromChat true` to allow /service install."].join(`
|
|
267
|
+
`),c=["<b>Service status</b>","",`<code>${At(Xn.platform)}</code>`,`<br/><code>${At(a)}</code>`,`<br/><code>${At(l)}</code>`,`<br/>data dir: <code>${At(H)}</code>`,`<br/><code>${At(i)}</code>`,`<br/>default log: <code>${At(Ne)}</code>`,"",`<pre>${At(d)}</pre>`,"",e.serviceInstallFromChat?"Install from chat: enabled.":"Install from chat: off \u2014 <code>/config set serviceInstallFromChat true</code>."].join(`
|
|
268
|
+
`);return de(u,c)}if(r==="instructions"){let s=an();if(s.error)return p(s.error);let i=wo(s);return p(`*Install hints*
|
|
269
269
|
|
|
270
|
-
${i}`)}if(r==="logs"){let s=n.length>=2?Number.parseInt(n[1],10):80,i=Number.isFinite(s)&&s>0?Math.min(s,
|
|
270
|
+
${i}`)}if(r==="logs"){let s=n.length>=2?Number.parseInt(n[1],10):80,i=Number.isFinite(s)&&s>0?Math.min(s,aw):80,a=vo(Ne,i),l=[`*Gateway log* (last ${i} lines)
|
|
271
271
|
${Ne}
|
|
272
272
|
`,"```",a,"```"].join(`
|
|
273
|
-
`),d=`<b>Gateway log</b> (last ${i} lines)<br/><code>${
|
|
273
|
+
`),d=`<b>Gateway log</b> (last ${i} lines)<br/><code>${At(Ne)}</code><pre>${At(a)}</pre>`;return de(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=bo();return p(s.ok?`*Installed*
|
|
274
274
|
${s.detail}`:`*Install failed*
|
|
275
|
-
${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=
|
|
276
|
-
${s.detail}`)}return p("Unknown /service command. Try /service help")}
|
|
277
|
-
`))}function
|
|
278
|
-
(no results)`);let r=[t,""];return e.forEach((o,s)=>{let i=o.category?` \xB7 ${o.category}`:"";r.push(`${s+1}. ${o.publicId} (${o.kind}${i}) \u2193${o.downloadCount} \u2014 ${o.title||o.name}`),o.description&&r.push(` ${o.description.slice(0,120)}`)}),r.push("",`Install: ${
|
|
279
|
-
`))}function
|
|
280
|
-
`))}var
|
|
281
|
-
`))}function
|
|
282
|
-
`))}let a=r.match(/^show\s+(\S+)\s*$/i);if(a){let f=a[1],h=xe();
|
|
283
|
-
`))}if(/^add$/i.test(i)){let f=r.slice(3).trim(),h=f.match(/^(\S+)\s+(heartbeat\s+.+)$/i);if(h){let
|
|
284
|
-
`))}let g=
|
|
285
|
-
`))}let l=r.match(/^run\s+(\S+)\s*$/i);if(l){let f=l[1].toLowerCase(),h=Ye(xe(),f,t);return h?h.enabled?(
|
|
286
|
-
`)){let r=n.trim();if(!r)continue;let o=r.split(/\s+/);if(o.length<4)continue;let s=o[0];if(!s.endsWith(".service"))continue;let i=o[2].toLowerCase(),a=s.slice(0,-8);t.push({name:a,state:i})}return t}function
|
|
287
|
-
`);for(let r=0;r<n.length;r++){let o=n[r].trim();if(!o||o.startsWith("PID"))continue;let s=o.split(/\s+/);if(s.length<3)continue;let i=s[s.length-1];if(!i.includes("."))continue;let l=s[0]==="-"?"stopped":"running";t.push({name:i,state:l})}return t}function
|
|
288
|
-
`)){let o=r.match(/SERVICE_NAME:\s*(.+)/i);if(o){n=o[1].trim();continue}let s=r.match(/^\s*STATE\s*:\s*\d+\s+(\S+)/i);if(s&&n){let i=s[1].toUpperCase(),a=i.toLowerCase();i==="RUNNING"?a="running":i==="STOPPED"&&(a="stopped"),t.push({name:n,state:a}),n=""}}return t}function
|
|
289
|
-
`)){let o=r.trim();if(!o)continue;let s=o.lastIndexOf(" ");if(s<=0)continue;let i=o.slice(0,s).trim(),a=o.slice(s+1).trim().toLowerCase();n.push({name:i,state:a})}return{entries:n}}function
|
|
290
|
-
`))}function
|
|
291
|
-
`))}function
|
|
292
|
-
`))}function U(e){return{replies:[e]}}function
|
|
293
|
-
`))}function
|
|
294
|
-
`)))}if(/^reload$/i.test(r)){let{summary:u}=
|
|
295
|
-
`)))}let o=n.match(/^recent(?:\s+(\d+))?\s*$/i);if(o){let u=o[1]?Number(o[1]):15,c=
|
|
296
|
-
`)))}let s=n.match(/^show\s+(\S+)\s*$/i);if(s){let u=
|
|
297
|
-
`)))}if(/^on$/i.test(r))return W({watchEnabled:!0}),De(),U(p("watchEnabled: true (gateway picks up watchers when running)."));if(/^off$/i.test(r))return W({watchEnabled:!1}),De(),U(p("watchEnabled: false \u2014 all adapters stopped."));let i=n.match(/^exclude\s+(\S+)\s+(\S+)(?:\s+([\s\S]+))?\s*$/i);if(i){let u=i[1],c=i[2].toLowerCase(),m=(i[3]??"").trim(),f=
|
|
275
|
+
${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=ko();return p(`*Uninstall*
|
|
276
|
+
${s.detail}`)}return p("Unknown /service command. Try /service help")}me();it();on();function vs(){let e=se();return e?.platformUrl?e.platformUrl.replace(/\/$/,""):($().tunnelRelayUrl||$e).trim().replace(/\/$/,"")}function xs(){let e=se();return e?.token?{Authorization:`Bearer ${e.token}`}:{}}async function Or(e){try{return await e.json()}catch{return{error:`HTTP ${e.status}`}}}function lw(){return`Set platform URL: omnish config add tunnelRelayUrl ${$e} \u2014 publish: omnish platform login`}function $a(){return se()?.token?{ok:!0}:{ok:!1,error:`Publish requires a platform account token. ${lw()}`}}async function op(e){let t=new URLSearchParams;e?.kind&&t.set("kind",e.kind),e?.limit&&t.set("limit",String(e.limit));let n=t.toString(),r=`${vs()}/v1/catalog/trending${n?`?${n}`:""}`,o=await fetch(r,{headers:xs()}),s=await Or(o);return o.ok?s:{error:s.error??`HTTP ${o.status}`}}async function sp(e,t){let n=new URLSearchParams;n.set("q",e),t?.kind&&n.set("kind",t.kind),t?.category&&n.set("category",t.category),t?.limit&&n.set("limit",String(t.limit));let r=`${vs()}/v1/catalog/search?${n}`,o=await fetch(r,{headers:xs()}),s=await Or(o);return o.ok?s:{error:s.error??`HTTP ${o.status}`}}async function ip(e){let t=encodeURIComponent(e.trim()),n=`${vs()}/v1/catalog/${t}`,r=await fetch(n,{headers:xs()}),o=await Or(r);return r.ok?o:{error:o.error??`HTTP ${r.status}`}}async function ap(e){let t=encodeURIComponent(e.trim()),n=`${vs()}/v1/catalog/${t}/download`,r=await fetch(n,{method:"POST",headers:xs()}),o=await Or(r);return r.ok?o:{error:o.error??`HTTP ${r.status}`}}async function lp(e){let t=$a();if(!t.ok)return{error:t.error};let n=se(),r=`${n.platformUrl.replace(/\/$/,"")}/v1/catalog`,o=await fetch(r,{method:"POST",headers:{"content-type":"application/json",Authorization:`Bearer ${n.token}`},body:JSON.stringify(e)}),s=await Or(o);return o.ok?s:{error:s.error??`HTTP ${o.status}`}}function cp(e){return e==="global"?"global":"chat"}function up(e,t,n,r="global"){switch(e.kind){case"recipe":{let o=e.payload,s=Be({...o,dangerous:void 0}),i=cn(s);if(!i.ok)return{ok:!1,error:i.error};let a=yt(e.name);if(!a.ok)return{ok:!1,error:a.error};try{_n(t,a.normalized,s,cp(r))}catch(d){return{ok:!1,error:String(d.message??d)}}let l=r==="global"?`/run ${a.normalized} <task>`:`/run ${a.normalized} <task> (this chat)`;return{ok:!0,message:`Installed recipe "${a.normalized}" (${r}). ${l}`}}case"app":{let o=e.payload;if(!o.command?.trim())return{ok:!1,error:"App payload has no command."};let s=Be({command:o.command.trim(),label:o.label??e.title,description:o.description??e.description,category:e.category||"app"}),i=yt(e.name);if(!i.ok)return{ok:!1,error:i.error};try{_n(t,i.normalized,s,cp(r),{skipCommandValidation:!0})}catch(a){return{ok:!1,error:String(a.message??a)}}return{ok:!0,message:`Installed app template "${i.normalized}" (${r}). /apps start <session> ${o.command.trim()}`}}case"shortcut":{let o=e.payload,s=bt(e.name);if(!s.ok)return{ok:!1,error:s.error};try{Ir(t,s.normalized,o.body,r==="global"?"global":"chat")}catch(i){return{ok:!1,error:String(i.message??i)}}return{ok:!0,message:`Installed shortcut "${s.normalized}" (${r}). Type ${s.normalized} to expand.`}}case"cowork":{let o=e.payload,s=xe();if(Ye(s,e.name,t))return{ok:!1,error:`Cowork task "${e.name}" already exists for this chat. Remove it first or rename.`};let i=Date.now(),a={id:lr(),name:e.name,ownerPeerKey:t,command:o.command,cwd:o.cwd??"",outputDir:o.outputDir??"",schedule:o.schedule,enabled:o.enabled??!0,notify:o.notify??"self",notifyWhen:o.notifyWhen??"always",attachLog:o.attachLog??!1,attachFiles:o.attachFiles??[],lastCompletedSlotMs:null,createdAtMs:i};return s.push(a),Oe(s),{ok:!0,message:`Installed cowork task "${e.name}" for this chat. /cowork show ${e.name}`}}default:return{ok:!1,error:"Unknown catalog kind."}}}function dp(e){return{name:e.name,command:e.command,cwd:e.cwd,outputDir:e.outputDir,schedule:e.schedule,enabled:e.enabled,notify:e.notify,notifyWhen:e.notifyWhen,attachLog:e.attachLog,attachFiles:e.attachFiles}}function pp(e){let{dangerous:t,...n}=e;return Be(n)}var Ra=new Map;function Ca(e,t){return`${e}:${t}`}function Ma(e,t,n){Ra.set(Ca(e,t),n)}function mp(e,t){return Ra.get(Ca(e,t))}function $s(e,t,n){let r=Number.parseInt(n,10);if(!Number.isFinite(r)||r<1)return null;let o=Ra.get(Ca(e,t));return!o||r>o.length?null:o[r-1].publicId}function wn(e){return!!(e&&typeof e=="object"&&typeof e.error=="string")}function Rs(e,t){return`${e.commandPrefix} online ${t}`}function fp(e){let t=o=>Rs(e,o),n=e.defaultKind===void 0?" [recipe|app|cowork|shortcut]":` (${e.defaultKind} only)`,r=[`Online catalog \u2014 ${e.defaultKind??"all kinds"}`,"",t(`trending${e.defaultKind===void 0?" [kind]":""}`),t(`search <query>${n}`),t("show <publicId>"),t("<publicId> download [--chat|-p for this chat only]"),t("trending <n> download \u2014 install #n from last list"),t("list \u2014 repeat last trending/search list")];return e.commandPrefix==="/run"&&r.push("","Also: /apps online \u2026 \xB7 /cowork online \u2026 \xB7 /shortcut online \u2026","","Publish (platform account):","/run <recipe> publish [--title \u2026] [--category \u2026]","/apps <session> publish","/cowork <name> publish","/shortcut <name> publish"),p(r.join(`
|
|
277
|
+
`))}function Cs(e,t,n){if(e.length===0)return p(`${t}
|
|
278
|
+
(no results)`);let r=[t,""];return e.forEach((o,s)=>{let i=o.category?` \xB7 ${o.category}`:"";r.push(`${s+1}. ${o.publicId} (${o.kind}${i}) \u2193${o.downloadCount} \u2014 ${o.title||o.name}`),o.description&&r.push(` ${o.description.slice(0,120)}`)}),r.push("",`Install: ${Rs(n,"<publicId> download")} \u2014 or ${Rs(n,"trending <n> download")}`),p(r.join(`
|
|
279
|
+
`))}function hp(e,t){let n=[`${e.publicId} (${e.kind})`,`title: ${e.title||e.name}`,e.description?`description: ${e.description}`:"",e.category?`category: ${e.category}`:"",e.tags?.length?`tags: ${e.tags.join(", ")}`:"",`downloads: ${e.downloadCount}`,`author: ${e.authorLabel||"(unknown)"}`,"","payload:"].filter(Boolean),r=e.payload;if(e.kind==="recipe"||e.kind==="app"){let o=r;if(n.push(` command: ${o.command??""}`),o.promptTemplate&&n.push(` template: ${o.promptTemplate.slice(0,400)}${o.promptTemplate.length>400?"\u2026":""}`),Array.isArray(o.steps)&&o.steps.length>0){n.push(` steps: ${o.steps.length}`);for(let[s,i]of o.steps.entries()){let a=typeof i=="string"?i:i.cmd;n.push(` ${s+1}. ${a??""}`)}}}else if(e.kind==="shortcut")n.push(` body: ${r.body}`);else if(e.kind==="cowork"){let o=r;n.push(` command: ${o.command??""}`),n.push(` schedule: ${o.schedule?.kind??"?"}`)}return n.push("",Rs(t,`${e.publicId} download`)),p(n.join(`
|
|
280
|
+
`))}var Ta=new Set(["recipe","app","cowork","shortcut"]),cw={commandPrefix:"/run",listScope:"run"},gp={commandPrefix:"/apps",defaultKind:"app",listScope:"apps"},yp={commandPrefix:"/cowork",defaultKind:"cowork",listScope:"cowork"},wp={commandPrefix:"/shortcut",defaultKind:"shortcut",listScope:"shortcut"};function uw(e){if(!e)return;let t=e.toLowerCase();return Ta.has(t)?t:void 0}function It(e,t){return`${e.commandPrefix} online ${t}`}function dw(e,t){if(e.defaultKind)return t&&t.toLowerCase()!==e.defaultKind?{error:`This command only lists ${e.defaultKind} entries. Omit the kind suffix.`}:e.defaultKind;let n=uw(t);return t&&!n?{error:`Unknown kind "${t}". Use: recipe, app, cowork, shortcut`}:n}function pw(e,t){if(e.defaultKind){if(t.length>1&&Ta.has(t[t.length-1].toLowerCase())){if(t[t.length-1].toLowerCase()!==e.defaultKind)return{error:`This command only searches ${e.defaultKind} entries. Omit the kind suffix.`};t.pop()}return{kind:e.defaultKind,query:t.join(" ")}}let n;return t.length>1&&Ta.has(t[t.length-1].toLowerCase())&&(n=t.pop().toLowerCase()),{kind:n,query:t.join(" ")}}async function Zn(e,t,n,r){let o=e.trim();if(!o||/^help$/i.test(o))return fp(r);let s=o.match(/^(.+?)\s+download(?:\s+(.*))?$/i);if(s){let d=s[1].trim(),u=(s[2]??"").trim(),c=/--chat|-p/i.test(u)?"chat":"global",m=null,f=/^trending\s+(\d+)$/i.exec(d),h=/^search\s+(\S+)\s+(\d+)$/i.exec(d);if(f){if(m=$s(t,r.listScope,f[1]),!m)return p(`No trending list in this chat \u2014 run ${It(r,"trending")} first, or use ${It(r,"<publicId> download")}.`)}else if(h){if(m=$s(t,r.listScope,h[2]),!m)return p(`No search list in this chat \u2014 run ${It(r,"search <query>")} first, or use ${It(r,"<publicId> download")}.`)}else if(/^\d+$/.test(d)){if(m=$s(t,r.listScope,d),!m)return p(`No list item #${d}. Run trending or search first, or use ${It(r,"<publicId> download")}.`)}else m=d;let g=await ap(m);if(wn(g))return p(`Download failed: ${g.error}`);if(r.defaultKind&&g.kind!==r.defaultKind)return p(`Entry "${m}" is kind=${g.kind}, not ${r.defaultKind}. Use /run online show ${m} from /run.`);let y=up(g,t,n,c);return y.ok?p(y.message):p(`Download failed: ${y.error}`)}let i=/^show\s+(\S+)\s*$/i.exec(o);if(i){let d=await ip(i[1]);return wn(d)?p(`Not found: ${d.error}`):r.defaultKind&&d.kind!==r.defaultKind?p(`Entry "${i[1]}" is kind=${d.kind}, not ${r.defaultKind}. Use /run online show ${i[1]}.`):hp(d,r)}let a=/^trending(?:\s+(\S+))?\s*$/i.exec(o);if(a){let d=dw(r,a[1]);if(typeof d=="object"&&"error"in d)return p(d.error);let u=await op(d?{kind:d}:void 0);if(wn(u))return p(`Trending failed: ${u.error}`);Ma(t,r.listScope,u.items);let c=r.defaultKind?`Trending (${r.defaultKind})`:"Trending";return Cs(u.items,c,r)}let l=/^search\s+([\s\S]+)$/i.exec(o);if(l){let d=l[1].trim().split(/\s+/),u=pw(r,d);if("error"in u)return p(u.error);let{kind:c,query:m}=u;if(!m)return p(`Usage: ${It(r,"search <query>")}`);let f=await sp(m,c?{kind:c}:void 0);return wn(f)?p(`Search failed: ${f.error}`):(Ma(t,r.listScope,f.items),Cs(f.items,`Search: ${m}`,r))}if(/^list\s*$/i.test(o)){let d=mp(t,r.listScope);return d?.length?Cs(d,"Last list",r):p(`No cached list. ${It(r,"trending")} or ${It(r,"search <query>")}`)}return p(`Unknown ${r.commandPrefix} online command. ${It(r,"help")}`)}async function bp(e,t,n){return Zn(e,t,n,cw)}function Lr(e){let t=e.trim(),n=[],r,o,s,i=a=>{let l=t.match(a);if(!l?.[1])return;let d=l[1].trim();if(t=(t.slice(0,l.index)+t.slice(l.index+l[0].length)).trim(),a.source.includes("title"))r=d.slice(0,120);else if(a.source.includes("description"))o=d.slice(0,500);else if(a.source.includes("category"))s=d.slice(0,40);else if(a.source.includes("tag"))for(let u of d.split(/[,;]/)){let c=u.trim();c&&n.push(c.slice(0,32))}};for(let a=0;a<8;a+=1){let l=t;if(i(/--title\s+"([^"]+)"/i),i(/--title\s+(\S+)/i),i(/--description\s+"([^"]+)"/i),i(/--description\s+(\S+)/i),i(/--category\s+"([^"]+)"/i),i(/--category\s+(\S+)/i),i(/--tag\s+"([^"]+)"/i),i(/--tag\s+(\S+)/i),t===l)break}return{title:r,description:o,category:s,tags:n,remainder:t.trim()}}function mw(e,t,n){return{kind:"recipe",name:e,title:n.title??t.label??e,description:n.description??t.description,category:n.category??t.category,tags:n.tags,payload:pp(t)}}function kp(e,t,n,r){let o=Lr(r),s=n.trim().toLowerCase(),i=je(e,t,s);return i?i.source==="builtin"?{ok:!1,error:"Built-in recipes cannot be published. Copy with /run add first."}:{ok:!0,body:mw(i.name,i,o)}:{ok:!1,error:`Unknown recipe "${n}".`}}function Sp(e,t,n){let r=Lr(n),o=Ss(e,t);return o?{ok:!0,body:{kind:"shortcut",name:o.name,title:r.title??o.name,description:r.description,category:r.category??"shortcut",tags:r.tags,payload:{body:o.body}}}:{ok:!1,error:`Unknown shortcut "${t}".`}}function vp(e,t,n){let r=Lr(n),o=xe(),s=Ye(o,t,e);return s?{ok:!0,body:{kind:"cowork",name:s.name,title:r.title??s.name,description:r.description,category:r.category??"cowork",tags:r.tags,payload:dp(s)}}:{ok:!1,error:`Unknown cowork task "${t}" for this chat.`}}function xp(e,t,n){let r=Lr(n),o=e.trim().toLowerCase();return t.trim()?{ok:!0,body:{kind:"app",name:o,title:r.title??o,description:r.description,category:r.category??"app",tags:r.tags,payload:{command:t.trim(),label:r.title}}}:{ok:!1,error:"Session has no command to publish."}}async function er(e){let t=$a();if(!t.ok)return{ok:!1,error:t.error};let n=await lp(e);if(wn(n))return{ok:!1,error:n.error};let r=n;return{ok:!0,message:`${r.updated?"Updated":"Published"}: ${r.publicId} (${e.kind}). Others: /run online ${r.publicId} download`}}function fw(){return p(["Cowork \u2014 scheduled shell tasks (gateway must be running).","","add <name> <schedule> -- <command\u2026>"," schedule: ondemand | hourly [:MM] | daily HH:MM | weekdays HH:MM | weekly <mon\u2026sun> HH:MM","add <name> heartbeat <interval> [grace] \u2014 dead-man's-switch (no command needed)"," e.g. /cowork add backup heartbeat 1h 10m","set <name> cmd -- <command\u2026> | schedule <\u2026> | out <path> | cwd <path>"," notify self|wa|tg|all|none"," when always|failure|state-change \u2014 notify condition (default: always)"," attach on|off \u2014 send run log as a file with notify messages"," files clear | <glob/path \u2026> \u2014 optional artifacts (basename * ?); quote paths with spaces","list | show <name> | run <name> | checkin <name> | enable <name> | disable <name> | remove <name>","publish <name> \u2014 share task to online catalog (platform login)","online trending | show <publicId> | <publicId> download \u2014 cowork tasks only","","Output logs: task outputDir (default ~/Cowork/<name>). Missed times catch up when the gateway is back."].join(`
|
|
281
|
+
`))}function $p(e){let t=[],n=0;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n+=1;if(n>=e.length)break;if(e[n]==='"'){let o=n+1,s=e.indexOf('"',o);if(s===-1){t.push(e.slice(o));break}t.push(e.slice(o,s)),n=s+1;continue}let r=n;for(;r<e.length&&!/\s/.test(e[r]);)r+=1;t.push(e.slice(n,r)),n=r}return t}function hw(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}}async function Cp(e,t,n){let r=e.trim();if(!r||/^help$/i.test(r))return fw();let o=/^online\b([\s\S]*)$/i.exec(r);if(o)return Zn((o[1]??"").trim(),t,n,yp);let s=/^(\S+)\s+publish\b([\s\S]*)$/i.exec(r);if(s){let f=vp(t,s[1],s[2]??"");if(!f.ok)return p(f.error);let h=await er(f.body);return p(h.ok?h.message:h.error)}let i=r.split(/\s+/)[0].toLowerCase();if(/^list$/i.test(i)){let f=xe().filter(g=>g.ownerPeerKey===t);if(f.length===0)return p("(no cowork tasks for this chat)");let h=f.map(g=>{let y=g.enabled?"":" (disabled)",b=g.notifyWhen&&g.notifyWhen!=="always"?` when=${g.notifyWhen}`:"";return`${Re}${g.name} ${Fn(g.schedule)} notify=${g.notify}${b}${y}`});return p(h.join(`
|
|
282
|
+
`))}let a=r.match(/^show\s+(\S+)\s*$/i);if(a){let f=a[1],h=xe();dn(h);let g=Ye(h,f,t);if(!g)return p(`Unknown task "${f}". /cowork list`);let y=Wo(g),b=[`name: ${g.name}`,`id: ${g.id}`,`schedule: ${Fn(g.schedule)}`,`enabled: ${g.enabled}`,`notify: ${g.notify}`,`notifyWhen: ${g.notifyWhen??"always"}`];if(g.schedule.kind==="heartbeat"){let v=Do(g.id);b.push(`lastCheckin: ${v?new Date(v).toLocaleString():"(never \u2014 send /cowork checkin "+g.name+")"}`)}else b.push(`attachLog: ${g.attachLog}`),b.push(`files: ${g.attachFiles.length?g.attachFiles.join(", "):"(none)"}`),b.push(`cwd: ${g.cwd||"(session cwd)"}`),b.push(`out: ${g.outputDir}`),b.push(`cmd: ${g.command}`),b.push(`last slot: ${y?new Date(y).toLocaleString():"(never)"}`);return p(b.join(`
|
|
283
|
+
`))}if(/^add$/i.test(i)){let f=r.slice(3).trim(),h=f.match(/^(\S+)\s+(heartbeat\s+.+)$/i);if(h){let T=Ks(h[1]);if(!T.ok)return p(T.error);let O=h[2].split(/\s+/).filter(Boolean),A=Fo(O);if(!A.ok)return p(A.error);let K=xe();if(Ye(K,T.name,t))return p(`Task "${T.name}" already exists. Remove it first or pick another name.`);let X=eo(T.name),ie={id:lr(),name:T.name,ownerPeerKey:t,command:"",cwd:"",outputDir:X,schedule:A.schedule,enabled:!0,notify:"self",notifyWhen:"always",attachLog:!1,attachFiles:[],lastCompletedSlotMs:null,createdAtMs:Date.now()};return K.push(ie),Oe(K),dn(K),ji(ie.id),p([`Saved heartbeat task "${T.name}" (${Fn(A.schedule)}).`,`Send /cowork checkin ${T.name} to record a heartbeat.`,"Alerts if no check-in arrives within the expected interval + grace period."].join(`
|
|
284
|
+
`))}let g=hw(f);if("error"in g)return p(g.error);let y=Ks(g.name);if(!y.ok)return p(y.error);let b=Fo(g.scheduleWords);if(!b.ok)return p(b.error);let v=xe();if(Ye(v,y.name,t))return p(`Task "${y.name}" already exists. Remove it first or pick another name.`);let E=oe(t),R=eo(y.name),P={id:lr(),name:y.name,ownerPeerKey:t,command:g.command,cwd:"",outputDir:R,schedule:b.schedule,enabled:!0,notify:"self",notifyWhen:"always",attachLog:!1,attachFiles:[],lastCompletedSlotMs:null,createdAtMs:Date.now()};return v.push(P),Oe(v),p([`Saved cowork task "${y.name}" (${Fn(b.schedule)}).`,`Output: ${R}`,`Notify: self \u2014 change with /cowork set ${y.name} notify wa|tg|all|none`].join(`
|
|
285
|
+
`))}let l=r.match(/^run\s+(\S+)\s*$/i);if(l){let f=l[1].toLowerCase(),h=Ye(xe(),f,t);return h?h.enabled?(fl({ownerPeerKey:t,name:h.name,at:Date.now()}),p(`On-demand run queued for "${h.name}" (runs within ~30s while omnish run is active).`)):p(`Cowork "${h.name}" is disabled. /cowork enable ${h.name}`):p(`Unknown task "${l[1]}". /cowork list`)}let d=r.match(/^checkin\s+(\S+)\s*$/i);if(d){let f=d[1].toLowerCase(),h=xe();dn(h);let g=Ye(h,f,t);return g?g.schedule.kind!=="heartbeat"?p(`"${g.name}" is not a heartbeat task.`):(ji(g.id),p(`Heartbeat recorded for "${g.name}".`)):p(`Unknown task "${d[1]}". /cowork list`)}let u=r.match(/^(?:remove|rm|del)\s+(\S+)\s*$/i);if(u){let f=u[1],h=xe(),g=h.findIndex(y=>y.name===f.toLowerCase()&&y.ownerPeerKey===t);return g===-1?p(`Unknown task "${f}".`):(h.splice(g,1),Oe(h),p(`Removed cowork task "${f.toLowerCase()}".`))}let c=r.match(/^enable\s+(\S+)\s*$/i);if(c)return Rp(c[1],t,!0);let m=r.match(/^disable\s+(\S+)\s*$/i);return m?Rp(m[1],t,!1):/^set$/i.test(i)?bw(r.slice(3).trim(),t):p("Unknown /cowork command. Try /cowork help")}function Rp(e,t,n){let r=xe(),o=Ye(r,e,t);return o?(o.enabled=n,Oe(r),p(`Cowork "${o.name}" ${n?"enabled":"disabled"}.`)):p(`Unknown task "${e}".`)}function gw(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 yw(e){let t=e.toLowerCase();return t==="always"||t==="all"?"always":t==="failure"||t==="fail"||t==="failures"?"failure":t==="state-change"||t==="statechange"||t==="change"||t==="transition"?"state-change":null}function ww(e){let t=e.toLowerCase();return t==="on"||t==="true"||t==="1"||t==="yes"?!0:t==="off"||t==="false"||t==="0"||t==="no"?!1:null}function bw(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 \u2026 | when \u2026 | attach <on|off> | files \u2026");let r=n[1],o=n[2].trim(),s=xe(),i=Ye(s,r,t);if(!i)return p(`Unknown task "${r}".`);if(o.toLowerCase().startsWith("cmd ")){let a=o.slice(4).trim(),l=" -- ",d=a.indexOf(l),u;if(d!==-1)u=a.slice(d+l.length).trim();else if(a.startsWith("--"))u=a.slice(2).trim();else return p("Usage: /cowork set <name> cmd -- <command\u2026>");return u?(i.command=u,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=Fo(a);return l.ok?(i.schedule=l.schedule,Oe(s),p(`Schedule for "${i.name}": ${Fn(l.schedule)}`)):p(l.error)}if(o.toLowerCase().startsWith("out ")){let a=o.slice(4).trim(),l=oe(t);return i.outputDir=Ge(a,l.cwd),Oe(s),p(`outputDir: ${i.outputDir}`)}if(o.toLowerCase().startsWith("cwd ")){let a=o.slice(4).trim(),l=oe(t);return i.cwd=a?Ge(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=gw(a);return l?(i.notify=l,Oe(s),p(`notify: ${l}`)):p("notify must be self, wa, tg, all, or none.")}if(o.toLowerCase().startsWith("when ")){let a=o.slice(5).trim(),l=yw(a);return l?(i.notifyWhen=l,Oe(s),p(`notifyWhen: ${l}`)):p("when must be always, failure, or state-change.")}if(o.toLowerCase().startsWith("attach ")){let a=o.slice(7).trim(),l=$p(a);if(l.length!==1)return p("Usage: /cowork set <name> attach on|off");let d=ww(l[0]);return d===null?p("attach must be on or off"):(i.attachLog=d,Oe(s),p(`attachLog: ${d}`))}if(o.toLowerCase().startsWith("files ")){let a=o.slice(6).trim(),l=$p(a);return l.length===1&&l[0].toLowerCase()==="clear"?(i.attachFiles=[],Oe(s),p("files: (cleared)")):l.length===0?p("Usage: /cowork set <name> files clear | <pattern \u2026> \u2014 quote paths with spaces"):(i.attachFiles=l,Oe(s),p(`files: ${i.attachFiles.join(", ")}`))}return p("Unknown set field. Try: cmd, schedule, out, cwd, notify, when, attach, files")}me();import Dw from"node:fs";G();import Mp from"node:os";import kw from"node:path";var Sw=new Set(["create","delete","rename","update"]);function vw(e){let t=[],n=0;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n+=1;if(n>=e.length)break;if(e[n]==='"'){let o=n+1,s=e.indexOf('"',o);if(s===-1){t.push(e.slice(o));break}t.push(e.slice(o,s)),n=s+1;continue}let r=n;for(;r<e.length&&!/\s/.test(e[r]);)r+=1;t.push(e.slice(n,r)),n=r}return t}function xw(e){let t=e.split(",").map(n=>n.trim().toLowerCase());return t.length===0?!1:t.every(n=>Sw.has(n))}function $w(e){return e.split(",").map(t=>t.trim().toLowerCase())}function Ea(e,t,n){let r=e.trim();if(r.startsWith("-")&&(r=r.slice(1)),!r)return{};let o=Ge(r,n);return r.includes("*")||r.includes("?")?{glob:r.replace(/\\/g,"/")}:kw.isAbsolute(o)||r.startsWith("~")||r.startsWith("./")||r.startsWith("../")?{path:o}:r.startsWith("/")?{path:o}:{glob:r.includes("/")?r:`**/${r}`}}function Tp(e,t=Mp.homedir()){let n=e.replace(/\s+&&\s+/g," ").trim(),r=vw(n);if(r.length===0)return{ok:!1,error:"Usage: /watch add fs <name> <path> [events] [-exclude \u2026] [--exclude \u2026]"};let o=0,s=r[o];o+=1;let i=["create","delete","rename"],a=[],l=[];for(;o<r.length;){let u=r[o];if(u==="--exclude"){if(o+=1,o>=r.length)return{ok:!1,error:"--exclude requires a pattern."};let c=r[o];o+=1;let m=Ge(s,t),f=Ea(c.startsWith("-")?c:`-${c}`,m,t);f.path?a.push(f.path):f.glob&&l.push(f.glob);continue}if(u.startsWith("--"))return{ok:!1,error:`Unknown flag: ${u}`};if(u.startsWith("-")){let c=Ge(s,t),m=Ea(u,c,t);m.path?a.push(m.path):m.glob&&l.push(m.glob),o+=1;continue}if(xw(u)){i=$w(u),o+=1;continue}return{ok:!1,error:`Unexpected token "${u}". Put path first, then events or -excludes.`}}return{ok:!0,value:{rootPath:Ge(s,t),events:i,excludePaths:a,excludeGlobs:l}}}function Pa(e,t,n=Mp.homedir()){let r=Ea(e.startsWith("-")?e:`-${e}`,t,n);return!r.path&&!r.glob?{error:"Empty exclude pattern."}:r}import{spawnSync as Ms}from"node:child_process";import Ep from"node:fs";import Rw from"node:os";import Cw from"node:path";var Mw=40,Tw=10,Ts=15e3,Ew=["~/Projects","~/deploy","~/Downloads","~/src","/var/www","/srv"],Pp={linux:"/var/log/dpkg.log (also /var/log/apt/history.log)",darwin:"/var/log/install.log",win32:"Windows Application event log (install/remove)"};function Pw(e){return e.startsWith("~/")?Cw.join(Rw.homedir(),e.slice(2)):e}function Aw(e,t){return t?.trim()?e.toLowerCase().includes(t.trim().toLowerCase()):!0}function Iw(e){let t=n=>n==="running"||n==="active";return[...e].sort((n,r)=>{let o=t(n.state),s=t(r.state);return o!==s?o?-1:1:n.name.localeCompare(r.name)})}function Ow(e){let t=[];for(let n of e.split(`
|
|
286
|
+
`)){let r=n.trim();if(!r)continue;let o=r.split(/\s+/);if(o.length<4)continue;let s=o[0];if(!s.endsWith(".service"))continue;let i=o[2].toLowerCase(),a=s.slice(0,-8);t.push({name:a,state:i})}return t}function Lw(e){let t=[],n=e.split(`
|
|
287
|
+
`);for(let r=0;r<n.length;r++){let o=n[r].trim();if(!o||o.startsWith("PID"))continue;let s=o.split(/\s+/);if(s.length<3)continue;let i=s[s.length-1];if(!i.includes("."))continue;let l=s[0]==="-"?"stopped":"running";t.push({name:i,state:l})}return t}function Nw(e){let t=[],n="";for(let r of e.split(`
|
|
288
|
+
`)){let o=r.match(/SERVICE_NAME:\s*(.+)/i);if(o){n=o[1].trim();continue}let s=r.match(/^\s*STATE\s*:\s*\d+\s+(\S+)/i);if(s&&n){let i=s[1].toUpperCase(),a=i.toLowerCase();i==="RUNNING"?a="running":i==="STOPPED"&&(a="stopped"),t.push({name:n,state:a}),n=""}}return t}function _w(){let e=Ms("systemctl",["list-units","--type=service","--all","--no-pager","--plain","--no-legend"],{encoding:"utf8",timeout:Ts});return e.error||e.status!==0?{entries:[],error:"systemctl unavailable \u2014 install systemd or run on Linux."}:{entries:Ow(e.stdout??"")}}function Fw(){let e=Ms("launchctl",["list"],{encoding:"utf8",timeout:Ts});return e.error||e.status!==0?{entries:[],error:"launchctl unavailable."}:{entries:Lw(e.stdout??"")}}function Ww(){let e=Ms("sc",["query","type=","service","state=","all"],{encoding:"utf8",timeout:Ts,windowsHide:!0});if(!e.error&&e.status===0&&(e.stdout??"").includes("SERVICE_NAME"))return{entries:Nw(e.stdout??"")};let t=Ms("powershell",["-NoProfile","-Command","Get-Service | ForEach-Object { $_.Name + ' ' + $_.Status }"],{encoding:"utf8",timeout:Ts,windowsHide:!0});if(t.error||t.status!==0)return{entries:[],error:"sc query and Get-Service unavailable."};let n=[];for(let r of(t.stdout??"").split(`
|
|
289
|
+
`)){let o=r.trim();if(!o)continue;let s=o.lastIndexOf(" ");if(s<=0)continue;let i=o.slice(0,s).trim(),a=o.slice(s+1).trim().toLowerCase();n.push({name:i,state:a})}return{entries:n}}function Es(e){let t=e?.limit??Mw,n=e?.filter,r,o=process.platform;if(o==="linux")r=_w();else if(o==="darwin")r=Fw();else if(o==="win32")r=Ww();else return{entries:[],truncated:!1,totalMatched:0,error:`Service discovery not supported on ${o}.`};if(r.error)return{entries:[],truncated:!1,totalMatched:0,error:r.error};let s=Iw(r.entries.filter(l=>Aw(l.name,n))),i=s.length,a=i>t;return{entries:s.slice(0,t),truncated:a,totalMatched:i}}function Uw(e,t=Tw){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}function Aa(e,t){if(e.error)return p(e.error);if(e.entries.length===0){let o=t?.trim()?`No services match "${t}". Try /watch svc list without a filter.`:"No services found on this host.";return p(o)}let n=e.entries.map(o=>`${Re}${o.name} \u2014 ${o.state}`),r=t?.trim()?`Services matching "${t}" (${e.entries.length} shown):`:`Services on ${process.platform} (${e.entries.length} shown):`;if(n.unshift(r),e.truncated){let o=e.totalMatched-e.entries.length;n.push("",`${o} more \u2014 narrow with /watch svc list <filter>`)}return n.push("","Copy-paste templates follow in the next message."),p(n.join(`
|
|
290
|
+
`))}function Ia(e,t){let n=t?.trim()||"<name>";if(e.length===0)return p("No services to template \u2014 run /watch svc list first.");let r=e.map(i=>i.name),o=Uw(r),s=[t?.trim()?`Copy-paste (/watch add svc ${n} \u2026):`:"Copy-paste (replace <name>):",""];for(let i of o)s.push(`/watch add svc ${n} ${i.join(" ")}`);return p(s.join(`
|
|
291
|
+
`))}function Ap(){let e=process.platform,t=e==="linux"?"linux":e==="darwin"?"darwin":"win32",n=["Watch hints",""];n.push("Package log (pkg watches):"),n.push(` ${Pp[t]??Pp.linux}`),n.push("","Filesystem roots that exist on this host:");let r=[];for(let o of Ew){let s=Pw(o);try{Ep.existsSync(s)&&Ep.statSync(s).isDirectory()&&r.push(o)}catch{}}if(r.length===0)n.push(" (none of the usual paths found \u2014 use any directory you own)");else for(let o of r)n.push(` ${o}`),n.push(` /watch add fs <name> ${o} create,delete,rename`);return n.push("","Service names: /watch svc list [filter]"),p(n.join(`
|
|
292
|
+
`))}function U(e){return{replies:[e]}}function Hw(...e){return{replies:e}}function Bw(e){let t=e.trim();if(!t)return{};let n=t.split(/\s+/);if(n.length>=2){let s=ro(n[0]);return s.ok?{ruleName:s.name,filter:n.slice(1).join(" ")}:{filter:t}}let r=n[0],o=ro(r);if(o.ok){let s=Es({filter:r,limit:1});if(s.totalMatched===0&&!s.error)return{ruleName:o.name}}return{filter:r}}function jw(){return p(["Watch \u2014 OS event eye (watchEnabled + omnish run). Docs: docs/features/watch.md","","add fs <name> <path> [events] [-/exclude \u2026] [--exclude glob]",' e.g. /watch add fs home ~/Projects create,delete -~/Projects/tmp --exclude "**/.keyfolder"',"add pkg <name> | add svc <name> <unit\u2026>","svc list [filter] \u2014 services on this host (+ templates in next message)","svc templates [ruleName] [filter] \u2014 copy-paste /watch add svc lines only","hints \u2014 suggested FS paths and package log location","list | status | reload | show <name> | recent [N]","pause|stop <name> \u2014 stop alerts, keep rule","resume <name> | enable <name> | disable <name> | rm <name>","exclude <name> list|add <pattern>|rm <pattern>","set <name> notify self|wa|tg|all|none","set <name> when always|state-change","on | off \u2014 global watchEnabled in config","Rules are device-wide (~/.omnish/watch/rules.json); any allowlisted peer can manage.","notify:self alerts the peer who created the rule."].join(`
|
|
293
|
+
`))}function Ip(){return{excludePaths:[],excludeGlobs:[]}}function Gw(e){return e.notify==="self"?`notify=self (${e.ownerPeerKey})`:`notify=${e.notify}`}function Jw(e,t){Vs(e.id),t==="pause"||t==="stop"?e.paused=!0:t==="resume"?e.paused=!1:t==="enable"?(e.enabled=!0,e.paused=!1):t==="disable"&&(e.enabled=!1,e.paused=!1)}function Op(e,t){let n=e.trim();if(!n||/^help$/i.test(n))return U(jw());let r=n.split(/\s+/)[0].toLowerCase();if(to(),/^hints$/i.test(r))return U(Ap());if(/^svc$/i.test(r)){let u=n.slice(3).trim(),m=(u.split(/\s+/)[0]??"").toLowerCase();if(m==="list"){let f=u.slice(4).trim()||void 0,h=Es({filter:f});return h.error?U(p(h.error)):h.entries.length===0?U(Aa(h,f)):Hw(Aa(h,f),Ia(h.entries))}if(m==="templates"){let f=u.slice(9).trim(),{ruleName:h,filter:g}=Bw(f),y=Es({filter:g});return y.error?U(p(y.error)):U(Ia(y.entries,h))}return U(p("svc subcommands: list [filter] | templates [ruleName] [filter]"))}if(/^status$/i.test(r)){let u=$(),{summary:c}=ur(),m=[`watchEnabled: ${u.watchEnabled} watchAutoRestore: ${u.watchAutoRestore}`,`debounce: ${u.watchDebounceMs}ms max/min: ${u.watchMaxEventsPerMinute}`,`rules file: ${Ys()} (${c.total} saved, ${c.active} active, ${c.paused} paused, ${c.disabled} disabled)`,`events db: ${Jr}`];c.total>0&&!u.watchEnabled?m.push("Rules are on disk; adapters stopped \u2014 /watch on to start."):c.total>0&&u.watchEnabled&&!u.watchAutoRestore?m.push("watchAutoRestore is off \u2014 /watch reload to start adapters without restarting gateway."):c.paused>0&&m.push(`${c.paused} paused rule(s) stay stopped until /watch resume <name>.`);let f=jl();return f?(m.push("","Adapters:"),m.push(...f.getStatusLines())):u.watchEnabled&&u.watchAutoRestore?m.push("","(manager starting \u2014 try /watch status again)"):u.watchEnabled?m.push("","(manager idle \u2014 /watch reload)"):m.push("","(manager off \u2014 /watch on)"),U(p(m.join(`
|
|
294
|
+
`)))}if(/^reload$/i.test(r)){let{summary:u}=ur();return $().watchEnabled?(Gl(),U(p(`Reloading from ${Ys()}: ${u.total} rule(s) on disk, ${u.active} eligible to run. /watch status for adapters.`))):U(p(`Rules on disk: ${u.total} (${u.active} active). watchEnabled is false \u2014 /watch on first.`))}if(/^list$/i.test(r)){let u=Le();if(u.length===0)return U(p("(no watch rules on this device)"));let c=u.map(m=>{let f=m.enabled?m.paused?"paused":"on":"disabled",h=m.kind==="fs"?m.path:m.kind==="svc"?m.units.join(","):"system";return`${Re}${m.name} [${m.kind}] ${f} ${Gw(m)} when=${m.notifyWhen} \u2014 ${h}`});return U(p(c.join(`
|
|
295
|
+
`)))}let o=n.match(/^recent(?:\s+(\d+))?\s*$/i);if(o){let u=o[1]?Number(o[1]):15,c=Le(),m=new Set(c.map(g=>g.id)),f=kl(u,m);if(f.length===0)return U(p("(no recent watch events)"));let h=f.map(g=>`${new Date(g.tsMs).toLocaleString()} ${g.ruleName} ${g.summary}`);return U(p(h.join(`
|
|
296
|
+
`)))}let s=n.match(/^show\s+(\S+)\s*$/i);if(s){let u=tn(Le(),s[1]);if(!u)return U(p(`Unknown rule "${s[1]}". /watch list`));let c=[`name: ${u.name}`,`kind: ${u.kind}`,`creator: ${u.ownerPeerKey}`,`enabled: ${u.enabled}`,`paused: ${u.paused}`,`notify: ${u.notify}`,`notifyWhen: ${u.notifyWhen}`,`adapter: ${u.adapterStatus||"(unknown)"}`];return u.kind==="fs"&&(c.push(`path: ${u.path}`),c.push(`events: ${u.events.join(",")}`),c.push(`excludePaths: ${u.excludePaths.length?u.excludePaths.join(", "):"(none)"}`),c.push(`excludeGlobs: ${u.excludeGlobs.length?u.excludeGlobs.join(", "):"(none)"}`)),u.kind==="svc"&&c.push(`units: ${u.units.join(", ")||"(none)"}`),U(p(c.join(`
|
|
297
|
+
`)))}if(/^on$/i.test(r))return W({watchEnabled:!0}),De(),U(p("watchEnabled: true (gateway picks up watchers when running)."));if(/^off$/i.test(r))return W({watchEnabled:!1}),De(),U(p("watchEnabled: false \u2014 all adapters stopped."));let i=n.match(/^exclude\s+(\S+)\s+(\S+)(?:\s+([\s\S]+))?\s*$/i);if(i){let u=i[1],c=i[2].toLowerCase(),m=(i[3]??"").trim(),f=Le(),h=tn(f,u);if(!h)return U(p(`Unknown rule "${u}".`));if(h.kind!=="fs")return U(p("exclude applies to filesystem rules only."));if(c==="list"){let g=[`excludePaths: ${h.excludePaths.length?h.excludePaths.join(`
|
|
298
298
|
`):"(none)"}`,`excludeGlobs: ${h.excludeGlobs.length?h.excludeGlobs.join(`
|
|
299
299
|
`):"(none)"}`];return U(p(g.join(`
|
|
300
|
-
`)))}if(c==="add"){if(!m)return U(p("Usage: /watch exclude <name> add <pattern>"));let g
|
|
301
|
-
`))}async function
|
|
300
|
+
`)))}if(c==="add"){if(!m)return U(p("Usage: /watch exclude <name> add <pattern>"));let g=Pa(m,h.path);if("error"in g)return U(p(g.error));if(g.path){if(Qe(g.path))return U(p("That path is blocked."));h.excludePaths.includes(g.path)||h.excludePaths.push(g.path)}return g.glob&&!h.excludeGlobs.includes(g.glob)&&h.excludeGlobs.push(g.glob),mt(Cn(f,h)),De(),U(p(`Added exclude to "${h.name}".`))}if(c==="rm"||c==="remove"){if(!m)return U(p("Usage: /watch exclude <name> rm <pattern>"));let g=Pa(m,h.path);return"error"in g?U(p(g.error)):(g.path&&(h.excludePaths=h.excludePaths.filter(y=>y!==g.path)),g.glob&&(h.excludeGlobs=h.excludeGlobs.filter(y=>y!==g.glob)),mt(Cn(f,h)),De(),U(p(`Removed exclude from "${h.name}".`)))}return U(p("exclude subcommands: list | add | rm"))}if(/^add$/i.test(r)){let u=n.slice(3).trim(),c=u.split(/\s+/);if(c.length<2)return U(p("Usage: /watch add fs|pkg|svc <name> \u2026"));let m=c[0].toLowerCase(),f=m==="fs"||m==="pkg"||m==="svc"?m:null;if(!f)return U(p("Kind must be fs, pkg, or svc."));let h=c[1],g=ro(h);if(!g.ok)return U(p(g.error));let y=Le();if(y.length>=qs)return U(p(`Max ${qs} watch rules on this device.`));if(tn(y,g.name))return U(p(`Rule "${g.name}" already exists.`));let b;if(f==="fs"){let R=u.slice(m.length+1+h.length).trim(),P=Tp(R);if(!P.ok)return U(p(P.error));let{rootPath:T,events:O,excludePaths:A,excludeGlobs:K}=P.value;if(Qe(T))return U(p("That path is blocked (sensitive). Choose another directory."));if(!Dw.existsSync(T))return U(p(`Path not found: ${T}`));for(let X of A)if(Qe(X))return U(p(`Excluded path blocked: ${X}`));b={id:oo(),name:g.name,ownerPeerKey:t,kind:"fs",enabled:!0,paused:!1,notify:"self",notifyWhen:"always",path:T,events:O,units:[],excludePaths:A,excludeGlobs:K,adapterStatus:"",createdAtMs:Date.now()}}else if(f==="pkg")b={id:oo(),name:g.name,ownerPeerKey:t,kind:"pkg",enabled:!0,paused:!1,notify:"self",notifyWhen:"always",path:"",events:[],units:[],...Ip(),adapterStatus:"",createdAtMs:Date.now()};else{let R=c.slice(2);if(R.length===0)return U(p("Usage: /watch add svc <name> <unit\u2026>"));b={id:oo(),name:g.name,ownerPeerKey:t,kind:"svc",enabled:!0,paused:!1,notify:"self",notifyWhen:"always",path:"",events:[],units:R,...Ip(),adapterStatus:"",createdAtMs:Date.now()}}mt(Cn(y,b)),De();let E=$().watchEnabled?"":" Rule saved to disk. /watch on to start adapters.";return U(p(`Watch rule "${b.name}" added (${b.kind}).${E}`))}let a=n.match(/^set\s+(\S+)\s+(\S+)\s+(\S+)\s*$/i);if(a){let[,u,c,m]=a,f=Le(),h=tn(f,u);if(!h)return U(p(`Unknown rule "${u}".`));let g=c.toLowerCase(),y=m.toLowerCase();if(g==="notify"){let b=y==="wa"||y==="whatsapp"?"wa":y==="tg"||y==="telegram"?"tg":y==="all"?"all":y==="none"?"none":y==="self"?"self":null;if(!b)return U(p("notify must be self, wa, tg, all, or none."));h.notify=b}else if(g==="when"){let b=y==="state-change"?"state-change":y==="always"?"always":null;if(!b)return U(p("when must be always or state-change."));h.notifyWhen=b}else return U(p("set supports: notify, when"));return mt(Cn(f,h)),De(),U(p(`Updated ${h.name} ${g}=${y}.`))}let l=n.match(/^(?:rm|remove)\s+(\S+)\s*$/i);if(l){let u=l[1],c=Le(),m=tn(c,u);return m?(Vs(m.id),mt(Cl(c,u)),De(),U(p(`Removed watch rule "${u}".`))):U(p(`Unknown rule "${u}".`))}let d=n.match(/^(pause|stop|resume|enable|disable)\s+(\S+)\s*$/i);if(d){let u=d[1].toLowerCase(),c=d[2],m=Le(),f=tn(m,c);if(!f)return U(p(`Unknown rule "${c}".`));Jw(f,u==="stop"?"pause":u),mt(Cn(m,f)),De();let g=u==="stop"?"paused (stop)":`${u}d`;return U(p(`${f.name}: ${g}.`))}return U(p("Unknown /watch command. Try /watch help"))}me();rn();on();function Lp(){return p(["Tunnel commands:",'/tunnel signup --email "you@example.com" --password "yourpass"','/tunnel signup --phone "+1234567890" --password "yourpass"','/tunnel login --email "you@example.com" --password "yourpass"','/tunnel login --token "<token>" [--relay <url>]',"/tunnel logout","/tunnel status [--relay <url>]","/tunnel http <port> [--name <slug>] [--host <addr>]","/tunnel tcp <port> [--name <slug>] [--host <addr>]","/tunnels","/tunnel stop <id|slug>"].join(`
|
|
301
|
+
`))}async function Oa(e,t,n){let r=Md(e);if(r.kind==="help")return Lp();if(r.kind==="error")return p(r.message);if(r.kind==="signup"){let o=r.email?.trim()||"",s=r.phone?.trim()||"",i=r.password||"";if(!o&&!s)return p('Usage: /tunnel signup --email "you@example.com" --password "yourpass"');if(i.length<8)return p("Password must be at least 8 characters.");let a=$(),l=r.relayUrl?.trim()||rt(a.tunnelRelayUrl||$e),d=await ms(l,{...o?{email:o}:{},...s?{phone:s}:{},password:i});return d.ok?(ht({token:d.token,...r.relayUrl?.trim()?{relayUrl:r.relayUrl.trim()}:{}}),p("Account created. Token saved.")):p(`Signup failed: ${d.error}`)}if(r.kind==="login"){if(r.email||r.phone){let i=r.password||"";if(!i)return p('Usage: /tunnel login --email "you@example.com" --password "yourpass"');let a=$(),l=r.relayUrl?.trim()||rt(a.tunnelRelayUrl||$e),d=await fs(l,{...r.email?{email:r.email}:{},...r.phone?{phone:r.phone}:{},password:i});return d.ok?(ht({token:d.token,...r.relayUrl?.trim()?{relayUrl:r.relayUrl.trim()}:{}}),p("Logged in. Token saved.")):p(`Login failed: ${d.error}`)}let s=r.token?.trim();return s?(ht({token:s,...r.relayUrl?.trim()?{relayUrl:r.relayUrl.trim()}:{}}),p("Tunnel token saved on this host (not shown). If OMNISH_TUNNEL_TOKEN is set in the gateway environment, it overrides the file until unset.")):p('Usage: /tunnel login --token "<token>" [--relay <url>]')}if(r.kind==="logout")return mo(),p("Tunnel token file removed. Unset OMNISH_TUNNEL_TOKEN in the gateway environment if you rely on it.");if(r.kind==="status"){let o=$(),s=r.relayUrl?.trim()||rt(o.tunnelRelayUrl||$e),i=gt(),a=!!process.env.OMNISH_TUNNEL_TOKEN?.trim(),d=!!$t()?.token?.trim(),u=await cs(s,i),c=[`Relay: ${s}`,`Token: ${i?"configured":"missing"}${a?" (OMNISH_TUNNEL_TOKEN)":d?" (tunnel-auth.json)":""}`,`Health: ${u.healthOk?`ok${u.healthVersion?` (version ${u.healthVersion})`:""}`:"fail"}`,`Control (WSS): ${u.controlOk?"auth ok":"fail"}`,`Active tunnels: ${n.getActiveCount()}`];return!u.ok&&u.error&&c.push(`Detail: ${u.error}`),p(c.join(`
|
|
302
302
|
`))}if(!t.tunnelEnabled)return p("Chat tunneling is disabled. Use /config set tunnelEnabled true (then expose with /tunnel http \u2026).");if(r.kind==="list"){let o=n.list();return o.length===0?p("(no active tunnels)"):p(o.map(s=>`${s.id} ${s.kind} ${s.status}
|
|
303
303
|
${s.publicUrl||"(pending)"}
|
|
304
304
|
${s.localHost}:${s.localPort}`).join(`
|
|
@@ -306,76 +306,76 @@ ${s.detail}`)}return p("Unknown /service command. Try /service help")}pe();funct
|
|
|
306
306
|
`))}if(r.kind==="stop"){let o=await n.stop(r.target);return o?p(`Stopped tunnel ${o.id}.`):p(`No active tunnel matched "${r.target}".`)}if(r.kind==="expose"){let o=await n.expose(t,r.options);return p(`${o.kind.toUpperCase()} tunnel active
|
|
307
307
|
public: ${o.publicUrl}
|
|
308
308
|
local: ${o.localHost}:${o.localPort}
|
|
309
|
-
id: ${o.id}`)}return
|
|
310
|
-
`))}async function
|
|
309
|
+
id: ${o.id}`)}return Lp()}function La(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 I(e){return{kind:"text",body:e}}function Kw(e,t){return`${e}:${t}`}function zw(e,t){return`${e}:apps:${t}`}async function qw(e,t){let n=e.trim();if(n===""||/^status$/i.test(n)||/^show$/i.test(n)||/^get$/i.test(n)){let a=$();return uc({gatewayMode:a.gatewayMode,authPresent:nt(),tokenSet:!!ve(a),allowN:a.allowFrom.length,tgAllowN:a.telegramAllowFrom.length,updateBrief:gs(Mr())})}if(/^help$/i.test(n))return Z(ci());let r=Sn(n);if(!r)return Cc();Xr(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 gc(o.gatewayMode,s,i)}function Yw(e){let t=e.trim();if(!pt(t))return hc();let n=Nt(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.'),fc(r)}async function Np(e,t,n){let r=oe(t),o=Vl(n);if(o!==null){let a=Xl(r.cwd,o),l=Zl(a);return l.ok?(ao(t,a),p(`cwd: ${a}`)):p(`cd: ${l.error}`)}let s=await un(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(`
|
|
310
|
+
`))}async function tr(e,t,n,r,o,s,i,a,l=null,d=!1,u){let c=s.text.trim(),m=s.peerKey,f=c.match(/^!!\s*(start|stop)\s*$/i);if(f)return f[1].toLowerCase()==="start"?(o.set(m,!0),I(xc())):(o.set(m,!1),I(p("Free shell mode off.")));if(c.startsWith(e.commandPrefix)){let g=c.slice(e.commandPrefix.length).trim();if(!g)return I(p(`Send ${e.commandPrefix}<command> or /help`));if(!d&&Yd(g)){let y=Sa(m,g);if(y!==void 0)return await tr(e,t,n,r,o,{...s,text:y},i,a,l,!0,u)}return I(await Np(e,m,g))}if(/^\/help\s+files$/i.test(c.trim()))return I(pi());if(c==="/help"||c==="help")return I(Z(Tn(e)));if(c.startsWith("/")){if(/^\/files(?:\s+help)?$/i.test(c.trim()))return I(pi());let g=c.match(/^\/receive\b(?:\s+(\S+))?$/i);if(g){let k=(g[1]??"status").toLowerCase(),x=new Set(["here","cwd","session","dir"]),L=new Set(["default","global","reset"]);if(x.has(k)){ti(m,"sessionCwd");let F=oe(m).cwd;return I(p(`Inbound files will save under this chat\u2019s session folder:
|
|
311
311
|
${F}
|
|
312
312
|
(layout: \u2026/<peer>/<date>/<file> under that root).
|
|
313
313
|
|
|
314
|
-
Change folder with ${e.commandPrefix}cd \u2026 Send /receive default to use the server config again.`))}return
|
|
314
|
+
Change folder with ${e.commandPrefix}cd \u2026 Send /receive default to use the server config again.`))}return L.has(k)?(ti(m,"default"),I(p("Per-chat inbound folder cleared. Uploads now follow fileReceiveRootMode in config.json (/files)."))):I(k==="help"?mi():k==="status"?kc(e,m):mi())}if(c==="/reload"||c==="/restart"){if(!a?.reload)return I(p("Reload is only available while the omnish gateway (omnish run) is running."));let k=await a.reload();return I(p(k.ok?k.summary:`Reload failed: ${k.error}`))}if(c==="/updates"||c.startsWith("/updates ")){let k=c.slice(8).trim().toLowerCase();if(k==="cached"||k==="last"){let L=Mr();return I(L?pr(L):p("No update snapshot yet. Send /updates (live check) once, or enable updateCheckEnabled and wait for the scheduled check."))}let x=await Tr(Ze(),$());return I(pr(x))}let y=c.match(/^\/security(?:\s+(\S+))?\s*$/i);if(y){let k=(y[1]??"").toLowerCase(),x=$(),L=Ct(x);return I(k==="help"||k==="?"?Z(Wc()):k==="summary"||k==="brief"?p(ic(L,"Send /security for the full report.")):k==="tips"?Z(Fc()):k===""||k==="full"||k==="report"?_c(L):p("Unknown /security subcommand. Try /security, /security summary, /security tips, or /security help"))}let b=c.match(/^\/(gateway|gw|mode)\b(?:\s+(.*))?$/i);if(b){let k=(b[2]??"").trim();return I(await qw(k,a))}if(c==="/config"||c.startsWith("/config ")){let k=c.slice(7).trim();return I(await jc(k,a))}let v=np(c);if(v!==null)return I(await rp(e,v));let E=La(c);if(E!==null){let k=ou(e,E,l);return k===null?null:I(k)}let R=c.match(/^\/(send|file)\b(?:\s+([\s\S]+))?$/i);if(R){let k=(R[2]??"").trim();if(!k)return I(di());let x=ws(k);if(!x)return I(di());let L=oe(m).cwd,F=await Er(L,x.selectorPart);if(F.length===0)return I(p(`No files matched: ${x.selectorPart}`));let Q=await Pr(F);if(!Q.ok)return I(p(Q.error));let z=se()?ts(e):e.fileSendMaxBytes,we=[];for(let Ue of F){let Ie=qt(Ue,z);if("error"in Ie)return I(p(Ie.error));we.push({absPath:Ie.absPath,category:Ie.category,mimetype:Ie.mimetype,displayName:Ie.displayName,caption:x.caption})}return we.length===1?{kind:"file",spec:we[0]}:{kind:"files",specs:we}}if(c==="/allowlist"){let k=$();return I(mc([{label:"allowFrom (WhatsApp)",items:k.allowFrom},{label:"telegramAllowFrom",items:k.telegramAllowFrom}]))}let P=c.match(/^\/allow\b\s+(.+)$/i);if(P)try{let k=Qr(P[1].trim());return I(ui(k))}catch(k){return I(p(String(k)))}if(/^\/allow\b\s*$/i.test(c))return I(yc());let T=c.match(/^\/deny\b\s+(.+)$/i);if(T)try{let k=Vr(T[1].trim());return I(ui(k))}catch(k){return I(p(String(k)))}if(/^\/deny\b\s*$/i.test(c))return I(wc());let O=c.match(/^\/(whatsapp|wa|telegram|tg)\b(?:\s+(.*))?$/i);if(O){let k=O[1].toLowerCase(),x=(O[2]??"").trim(),L=k==="whatsapp"||k==="wa";if(k==="telegram"||k==="tg"){let Q=x.match(/^token\s+(\S+)\s*$/i);return Q?I(Yw(Q[1]??"")):x===""||/^help$/i.test(x)?I(Z(pc($()))):I(vc())}if(L)return x===""||/^help$/i.test(x)?I(Z(dc(e))):I(Sc())}let A=c.match(/^\/(cowork|cw)\b(?:\s+([\s\S]*))?$/i);if(A){let k=(A[2]??"").trim();return I(await Cp(k,m,e))}let K=c.match(/^\/watch\b(?:\s+([\s\S]*))?$/i);if(K){let k=(K[1]??"").trim(),x=Op(k,m);return x.replies.length===1?I(x.replies[0]):{kind:"texts",bodies:x.replies}}if(c==="/apps"||c.startsWith("/apps "))return I(await eb(c,m,e,i,r));let X=Qw(c);if(X!==null)return I(await Xw(X,m,e,i,s.mediaSavedPath,u));if(c.startsWith("/bg")){let k=c.slice(3).trim();if(!k)return I(bc());let x=Hu(k);if("error"in x)return I(p(x.error==="empty"?"Usage: /bg <command> or /bg -n <name> <command>.":x.error));let L=oe(m).cwd,F=x.notify&&u?.sendToPeer?Ie=>{let pe=Bu(Ie);u.sendToPeer(m,pe).catch(()=>{})}:void 0,{id:Q,meta:z}=t.spawnJob(e.shell,x.cmd,{cwd:L,name:x.name,notifyPeerKey:x.notify?m:null,onComplete:F}),we=z.name?`${Q} (${z.name})`:Q,Ue=x.notify?`
|
|
315
315
|
Notify on completion: on`:"";return I(p(`Job ${we} started.
|
|
316
|
-
[cwd: ${
|
|
316
|
+
[cwd: ${L}]
|
|
317
317
|
/log ${z.name??Q}
|
|
318
|
-
/tail ${z.name??Q}${Ue}`))}if(c==="/tunnels")return I(await
|
|
318
|
+
/tail ${z.name??Q}${Ue}`))}if(c==="/tunnels")return I(await Oa("list",e,gn()));let ie=c.match(/^\/tunnel\b(?:\s+([\s\S]*))?$/i);if(ie){let k=(ie[1]??"").trim();return I(await Oa(k||"help",e,gn()))}if(c==="/jobs"){let k=t.list().slice(0,20);return k.length===0?I(p("(no jobs yet)")):I(p(k.map(x=>{let L=x.finishedAt&&x.startedAt?`${((Date.parse(x.finishedAt)-Date.parse(x.startedAt))/1e3).toFixed(1)}s`:"\u2026";return`${x.name?`${x.id} ${x.name}`:x.id} ${x.status} exit=${x.exitCode??"?"} ${L}
|
|
319
319
|
${x.cmd.slice(0,120)}${x.cmd.length>120?"\u2026":""}`}).join(`
|
|
320
320
|
|
|
321
|
-
`)))}let he=c.match(/^\/log\s+(\S+)(?:\s+(\d+))?\s*$/i);if(he){let k=he[1],x=t.resolveJobRef(k);if(!x.ok)return I(p(x.error));let
|
|
322
|
-
(Gateway-shared recipe exists: /run show --global ${P})`:"",K=
|
|
323
|
-
(This chat stores an override: /run show --chat ${P})`:"",X=
|
|
324
|
-
/run remove --global ${R}`):
|
|
325
|
-
`))}if(/^queue$/i.test(i))return p(r.runQueueStatus(t));if(/^queue\s+resume\s*$/i.test(i))return p(r.resumeRunQueue(t,n));let g=
|
|
326
|
-
`).trim(),z=F.code===0&&!F.timedOut;
|
|
327
|
-
(Shared shortcut exists: /shortcut show --global ${g})`:"",E=y==="global"&&
|
|
328
|
-
(This chat overrides the name: /shortcut show --chat ${g})`:"",R=y==="global"?`Unknown shortcut "${g}" in shared shortcuts.`:`Unknown shortcut "${g}" in this chat.`;return p(`${R}${v}${E}`)}let l=/^add\b([\s\S]*)$/i.exec(r);if(l){let{scope:c,remainder:m}=
|
|
329
|
-
/shortcut remove --global ${h}`):
|
|
330
|
-
`,{mode:384})}catch(D){
|
|
331
|
-
${C(process.stderr,"shutting down\u2026")}`),process.exit(0)};process.on("SIGINT",he),process.on("SIGTERM",he),await new Promise(()=>{})}function
|
|
321
|
+
`)))}let he=c.match(/^\/log\s+(\S+)(?:\s+(\d+))?\s*$/i);if(he){let k=he[1],x=t.resolveJobRef(k);if(!x.ok)return I(p(x.error));let L=x.id,F=he[2]?Number.parseInt(he[2],10):e.jobLogTailLines,Q=Number.isFinite(F)&&F>0?Math.min(F,500):e.jobLogTailLines;return I(p(t.tailLog(L,Q)))}let D=c.match(/^\/tail\s+(\S+)\s*$/i);if(D){let k=D[1],x=t.resolveJobRef(k);if(!x.ok)return I(p(x.error));let L=x.id,F=Kw(m,L),Q=n.get(F)??0,{text:z,nextOffset:we}=t.readSince(L,Q);return n.set(F,we),I(z?p(z.trimEnd()||"(no new output)"):p(`(no new output; offset ${we})`))}let le=c.match(/^\/kill\s+(\S+)\s*$/i);if(le){let k=le[1],x=t.resolveJobRef(k);return x.ok?I(p(t.kill(x.id))):I(p(x.error))}let Y=c.match(/^\/(shortcut|shortcuts|alias|aliases)\b(?:\s+([\s\S]*))?$/i);if(Y){let k=Y[1].toLowerCase(),x=(Y[2]??"").trim();return k==="shortcuts"&&!x?x="list":((k==="alias"||k==="aliases")&&!x||k==="shortcut"&&!x)&&(x="help"),I(await Zw(x,m,e))}if(!d){let k=c.trim().match(/^\/([a-zA-Z0-9][a-zA-Z0-9_-]{0,31})\s*$/);if(k){let x=k[1],L=Sa(m,x);if(L!==void 0)return await tr(e,t,n,r,o,{...s,text:L},i,a,l,!0,u)}}return I($c(e))}let h=c.match(/^>(\S+)\s*(.*)$/s);if(h){let g=h[1],y=h[2]??"",b=await i.writeNamedLine(m,g,y);return b?I(p(b)):null}return await i.writeFocusedLine(m,c)?null:o.get(m)&&c?I(await Np(e,m,c)):e.chatLlmFallbackEnabled&&e.chatLlmShellCommand.trim().length>0&&u?.onPlainTextLlmFallback?(u.onPlainTextLlmFallback(m,c),null):I(Rc(e))}function Qw(e){return e==="/run"||e.startsWith("/run ")?e.slice(4).trim():e==="/r"||e.startsWith("/r ")?e.slice(2).trim():null}function Vw(e){let t=e.trim(),n=t.match(/^(\S+)\s+(?:--queue|-q)\s+([\s\S]+)$/i);if(n)return{recipe:n[1],task:n[2],queued:!0};let r=t.match(/^(\S+)\s+([\s\S]+)$/);return r?{recipe:r[1],task:r[2],queued:!1}:null}async function Xw(e,t,n,r,o,s){let i=e.trim();if(!i||/^help$/i.test(i))return Z(Ac());let a=/^online\b([\s\S]*)$/i.exec(i);if(a)return bp((a[1]??"").trim(),t,n);let l=/^(\S+)\s+publish\b([\s\S]*)$/i.exec(i);if(l){let b=kp(t,n,l[1],l[2]??"");if(!b.ok)return p(b.error);let v=await er(b.body);return p(v.ok?v.message:v.error)}let d=/^list\b([\s\S]*)$/i.exec(i);if(d){let b=(d[1]??"").trim(),{filter:v,bad:E}=mu(b);if(E)return p(`Unknown /run list suffix: "${E}". Use: list | list --chat | list -p | list --global | list -g`);if(v==="merged")return Ic(yu(t,n));let R=hu(t,n,v);return Nc(R,v)}let u=/^show\b([\s\S]*)$/i.exec(i);if(u){let b=(u[1]??"").trim(),{mode:v,remainder:E}=pu(b),R=/^(\S+)\s*$/i.exec(E);if(!R?.[1])return p("Usage: /run show <name> \u2014 or show --global|-g|--chat|-p <name> (-g shared, -p private)");let P=R[1];if(v==="resolved"){let ie=je(t,n,P);return ie?gi(ie):yi(P)}let T=v==="global"?"global":"chat",O=Tt(T,t,n,P);if(O)return gi(O,T==="global"?"From gateway-shared recipes (--global).":"From this chat only (--chat).");let A=T==="chat"&&Tt("global",t,n,P)?`
|
|
322
|
+
(Gateway-shared recipe exists: /run show --global ${P})`:"",K=T==="global"&&Tt("chat",t,n,P)?`
|
|
323
|
+
(This chat stores an override: /run show --chat ${P})`:"",X=T==="global"?`Unknown recipe "${P}" in gateway-shared storage.`:`Unknown recipe "${P}" in this chat storage.`;return p(`${X}${A}${K}`)}let c=/^add\b([\s\S]*)$/i.exec(i);if(c){let{scope:b,remainder:v}=Wi((c[1]??"").trim()),E=v.match(/^(\S+)\s+([\s\S]+)$/);if(!E)return p(b==="global"?'Usage: /run add --global <name> <command\u2026> [--template "\u2026"] \u2014 cmd must reference "$OMNISH_TASK"':"Usage: /run add [--global|-g|--chat|-p] <name> <command\u2026> \u2014 see /run help");try{let R=Ui(E[2],n.recipesMacroDefaultCommand);_n(t,E[1],R,b);let P=yt(E[1]),T=P.ok?P.normalized:E[1].toLowerCase(),O=Tt(b,t,n,T)??je(t,n,T);return O?fr(T,O,b):p("Recipe save failed.")}catch(R){return p(String(R))}}let m=/^set\b([\s\S]*)$/i.exec(i);if(m){let{scope:b,remainder:v,explicit:E}=Fi((m[1]??"").trim()),R=fu(v);if(R){if(E)return p("Cannot combine a leading scope flag (-g, --global, --chat, -p) with a trailing scope flag on the same line.");let O=yt(R.name);if(!O.ok)return p(O.error);let A=Di(t,O.normalized,R.target,n);if(!A.ok)return p(A.error);if(A.kind==="noop")return p(A.message);let K=Tt(A.target,t,n,O.normalized)??je(t,n,O.normalized);return K?fr(O.normalized,K,A.target):p("Recipe scope update failed.")}let P=v.match(/^(\S+)\s*$/);if(P?.[1]&&E){let O=yt(P[1]);if(!O.ok)return p(O.error);let A=Di(t,O.normalized,b,n);if(!A.ok)return p(A.error);if(A.kind==="noop")return p(A.message);let K=Tt(A.target,t,n,O.normalized)??je(t,n,O.normalized);return K?fr(O.normalized,K,A.target):p("Recipe scope update failed.")}let T=v.match(/^(\S+)\s+([\s\S]+)$/);if(!T)return p(b==="global"?'Usage: /run set --global <name> <command\u2026> [--template "\u2026"] \u2014 or scope-only: /run set --global <name> | /run set <name> -g':"Usage: /run set [--global|-g|--chat|-p] <name> <command\u2026> \u2014 or move scope without changing the body: /run set -g <name> | /run set <name> -p \u2014 see /run help");try{let O=Ui(T[2],n.recipesMacroDefaultCommand);_n(t,T[1],O,b);let A=yt(T[1]),K=A.ok?A.normalized:T[1].toLowerCase(),X=Tt(b,t,n,K)??je(t,n,K);return X?fr(K,X,b):p("Recipe save failed.")}catch(O){return p(String(O))}}let f=/^(?:remove|rm|del)\b([\s\S]*)$/i.exec(i);if(f){let{scope:b,remainder:v}=Wi((f[1]??"").trim()),E=v.match(/^(\S+)\s*$/);if(!E?.[1])return p(b==="global"?"Usage: /run remove --global <name> (aliases: rm, del)":"Usage: /run remove [--global|-g|--chat|-p] <name>");let R=E[1];return gu(t,R,b)?Oc(R,b):b==="chat"&&Tt("global",t,n,R)?p(`No recipe "${R}" in this chat. There is a gateway-shared recipe with that name \u2014 remove it with:
|
|
324
|
+
/run remove --global ${R}`):Lc(R,b)}let h=/^queue\s+load\b([\s\S]*)$/i.exec(i);if(h){let b=(h[1]??"").trim(),v=Xd(n),E=null,R=/^json(?:\s+([\s\S]+))?$/i.exec(b);if(R){let A=(R[1]??"").trim();if(!A)return p('Usage: /run queue load json [{"recipe":"\u2026","task":"\u2026"}, \u2026] \u2014 or { "tasks": [ \u2026 ] }');E=A}else if(b.length>0){let A=b;(A.startsWith('"')&&A.endsWith('"')||A.startsWith("'")&&A.endsWith("'"))&&(A=A.slice(1,-1));let K=oe(t).cwd,X=await Er(K,A);if(X.length===0)return p(`No files matched: ${A}`);if(X.length>1)return p("Queue load: specify a single JSON file.");let ie=await Pr(X);if(!ie.ok)return p(ie.error);let he=xa(X[0],v);if(!he.ok)return p(he.error);E=he.text}else if(o){let A=xa(o,v);if(!A.ok)return p(A.error);E=A.text}else return p("Usage: /run queue load <file.json> \u2014 or /run queue load json [\u2026] \u2014 or attach a file with caption /run queue load");let P=Zd(E);if(!P.ok)return p(P.error);let T=ep(t,n,P.jobs);if(!T.ok)return p(T.error);let O=[];for(let A of T.items)O.push(r.enqueueQueuedRun(t,A,n));return p(O.join(`
|
|
325
|
+
`))}if(/^queue$/i.test(i))return p(r.runQueueStatus(t));if(/^queue\s+resume\s*$/i.test(i))return p(r.resumeRunQueue(t,n));let g=Vw(i);if(g){let{recipe:b,task:v,queued:E}=g,R=je(t,n,b);if(!R)return yi(b);if(R.steps&&R.steps.length>0){let X=oe(t).cwd,ie=R.steps.length,he=R.steps;if(s?.sendToPeer){let D=s.sendToPeer;(async()=>{let le=[],Y=!1;for(let x=0;x<he.length;x++){let L=he[x];if(Y){le.push({index:x,label:L.label??`step ${x+1}`,cmd:L.cmd,exitCode:null,timedOut:!1,skipped:!0,output:""});continue}let F=await un(n.shell,L.cmd,{timeoutMs:n.syncTimeoutMs,maxBytes:n.syncMaxBytes,cwd:X}),Q=[F.stdout,F.stderr].filter(Boolean).join(`
|
|
326
|
+
`).trim(),z=F.code===0&&!F.timedOut;le.push({index:x,label:L.label??`step ${x+1}`,cmd:L.cmd,exitCode:F.code,timedOut:F.timedOut,skipped:!1,output:Q}),!z&&!L.continueOnFail&&(Y=!0)}let k=wu(b,le);await D(t,k)})().catch(()=>{})}return p(`Runbook "${b}" started (${ie} steps). Results will be sent when complete.`)}let P=R.taskEnv??"OMNISH_TASK";if(!Nn(R.command,P))return p(`Recipe "${b}" command must reference "$${P}".`);let T=Co(v,n.recipesMaxTaskChars);if(!T.ok)return p(T.error);let O=R.promptTemplate?Mo(R.promptTemplate,P,T.task):T.task,A={[P]:O};if(E)return p(r.enqueueQueuedRun(t,{command:R.command,extraEnv:A,recipeLabel:b},n));let K=To(b);return p(r.start(t,K,R.command,n,A))}let y=i.match(/^(\S+)$/);if(y){let b=y[1],v=b.toLowerCase();return v==="add"||v==="set"?p('Usage: /run add <name> cmd [--template "\u2026"] \u2014 cmd must include "$OMNISH_TASK"'):v==="show"?p("Usage: /run show <name> \u2014 optional show --global|-g|--chat|-p <name>"):v==="remove"||v==="rm"||v==="del"?p("Usage: /run remove [--global|-g|--chat|-p] <name>"):je(t,n,v)?p(`Usage: /run ${b} <task text\u2026> \u2014 replaces <<<OMNISH_TASK>>> / $OMNISH_TASK in stored templates`):p(`Unknown recipe "${b}". /run list`)}return p("/run: could not parse. /run help")}async function Zw(e,t,n){let r=e.trim();if(!r||/^help$/i.test(r))return Z(fi());let o=/^online\b([\s\S]*)$/i.exec(r);if(o)return Zn((o[1]??"").trim(),t,n,wp);let s=/^(\S+)\s+publish\b([\s\S]*)$/i.exec(r);if(s){let c=Sp(t,s[1],s[2]??"");if(!c.ok)return p(c.error);let m=await er(c.body);return p(m.ok?m.message:m.error)}let i=/^list\b([\s\S]*)$/i.exec(r);if(i){let c=(i[1]??"").trim(),{filter:m,bad:f}=Jd(c);return f?p(`Unknown /shortcut list suffix: "${f}". Use: list | list --chat | list -p | list --global | list -g`):Mc(zd(t,m))}let a=/^show\b([\s\S]*)$/i.exec(r);if(a){let c=(a[1]??"").trim(),{mode:m,remainder:f}=Gd(c),h=/^(\S+)\s*$/i.exec(f);if(!h?.[1])return p("Usage: /shortcut show <name> \u2014 or show --global|-g|--chat|-p <name> (-g shared, -p private)");let g=h[1];if(m==="resolved"){let P=Ss(t,g);if(!P)return Ec(g);let T=P.scope==="global"?"Shared shortcut (all chats use it unless this chat overrides the name).":"This chat only.";return hi(g,P.body,T)}let y=m==="global"?"global":"chat",b=Pt(y,t,g);if(b!==void 0)return hi(g,b,y==="global"?"From the shared shortcut list (--global / -g).":"From this chat only (--chat / -p).");let v=y==="chat"&&Pt("global",t,g)!==void 0?`
|
|
327
|
+
(Shared shortcut exists: /shortcut show --global ${g})`:"",E=y==="global"&&Pt("chat",t,g)!==void 0?`
|
|
328
|
+
(This chat overrides the name: /shortcut show --chat ${g})`:"",R=y==="global"?`Unknown shortcut "${g}" in shared shortcuts.`:`Unknown shortcut "${g}" in this chat.`;return p(`${R}${v}${E}`)}let l=/^add\b([\s\S]*)$/i.exec(r);if(l){let{scope:c,remainder:m}=ka((l[1]??"").trim()),f=m.match(/^(\S+)\s+([\s\S]+)$/);if(!f)return p(c==="global"?"Usage: /shortcut add --global <name> <command\u2026> (short: add -g <name> <command\u2026>) \u2014 -g shared, -p private":"Usage: /shortcut add [--global|-g|--chat|-p] <name> <command\u2026> \u2014 -g shared, -p private");try{Ir(t,f[1],f[2],c);let h=bt(f[1]),g=h.ok?h.normalized:f[1].trim().toLowerCase(),y=Pt(c,t,g)??"";return mr(g,y,c)}catch(h){return p(String(h))}}let d=/^set\b([\s\S]*)$/i.exec(r);if(d){let{scope:c,remainder:m,explicit:f}=ba((d[1]??"").trim()),h=Kd(m);if(h){if(f)return p("Cannot combine a leading scope flag (-g, --global, --chat, -p) with a trailing flag on the same line.");let b=bt(h.name);if(!b.ok)return p(b.error);let v=va(t,b.normalized,h.target);if(!v.ok)return p(v.error);if(v.kind==="noop")return p(v.message);let E=Pt(v.target,t,b.normalized)??"";return mr(b.normalized,E,v.target)}let g=m.match(/^(\S+)\s*$/);if(g?.[1]&&f){let b=bt(g[1]);if(!b.ok)return p(b.error);let v=va(t,b.normalized,c);if(!v.ok)return p(v.error);if(v.kind==="noop")return p(v.message);let E=Pt(v.target,t,b.normalized)??"";return mr(b.normalized,E,v.target)}let y=m.match(/^(\S+)\s+([\s\S]+)$/);if(!y)return p(c==="global"?"Usage: /shortcut set --global <name> <command\u2026> \u2014 or scope-only: /shortcut set -g <name> | /shortcut set <name> -g (-g shared)":"Usage: /shortcut set [--global|-g|--chat|-p] <name> <command\u2026> \u2014 or move scope: /shortcut set -g <name> | /shortcut set <name> -p (-g shared, -p private)");try{Ir(t,y[1],y[2],c);let b=bt(y[1]),v=b.ok?b.normalized:y[1].trim().toLowerCase(),E=Pt(c,t,v)??"";return mr(v,E,c)}catch(b){return p(String(b))}}let u=/^(?:remove|rm|del)\b([\s\S]*)$/i.exec(r);if(u){let{scope:c,remainder:m}=ka((u[1]??"").trim()),f=m.match(/^(\S+)\s*$/);if(!f?.[1])return p(c==="global"?"Usage: /shortcut remove --global <name> (aliases: rm, del)":"Usage: /shortcut remove [--global|-g|--chat|-p] <name>");let h=f[1];return qd(t,h,c)?Tc(h,c):c==="chat"&&Pt("global",t,h)!==void 0?p(`No shortcut "${h}" in this chat. There is a shared shortcut with that name \u2014 remove it with:
|
|
329
|
+
/shortcut remove --global ${h}`):Pc(h,c)}return Z(fi())}async function eb(e,t,n,r,o){let s=e.slice(5).trim(),i=s.toLowerCase();if(!i||i==="help")return Z(wi());let a=s.match(/^(\S+)\s*(.*)$/s);if(!a)return Z(wi());let l=a[1].toLowerCase(),d=(a[2]??"").trim();if(l==="online")return Zn(d,t,n,gp);let u=d.match(/^publish\b([\s\S]*)$/i);if(u){let c=l,m=r.getSessionCommand(t,c);if(!m)return p(`No running session "${c}" with a command. /apps list`);let f=xp(c,m,u[1]??"");if(!f.ok)return p(f.error);let h=await er(f.body);return p(h.ok?h.message:h.error)}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 m=c[2]?Number.parseInt(c[2],10):n.appsLogTailLines;return p(r.tail(t,c[1],m))}case"since":{let c=d.split(/\s+/)[0];if(!c)return p("Usage: /apps since <name>");let m=zw(t,c),f=o.get(m)??0,{text:h,nextOffset:g}=r.readSince(t,c,f);return o.set(m,g),p(h.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 m=c[0],f=Number(c[1]),h=Number(c[2]);return!Number.isFinite(f)||!Number.isFinite(h)?p("cols and rows must be numbers."):p(r.resize(t,m,f,h))}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 _p(e,t,n){return!e.clusterEnabled||La(t.trim())!==null?!0:n?ru(n,e):!1}be();qe();function Fp(){return p("Not allowlisted on this omnish device.")}async function Nr(e,t,n,r,o,s,i,a,l,d,u,c){if((c?.surface??(s.peerKey.startsWith("tg:")?"telegram":"whatsapp"))==="telegram"){let f=qr(e.telegramAllowFrom),h=s.peerKey.startsWith("tg:")?s.peerKey.slice(3):"";if(!h||!f.has(h)){M.warn({denied:s.peerKey,uid:h},"telegram denied"),await u({kind:"text",body:Fp()});return}}else{let f=zr(e.allowFrom),h=l.startsWith("wa:")&&/^wa:\+\d+$/.test(l)?l.slice(3):s.peerKey.replace(/^wa:/,""),g=ee(h)||"";if(!g||!f.has(g)){M.warn({denied:s.peerKey,phone:g,senderKey:l},"denied"),await u({kind:"text",body:Fp()});return}}try{if(!!!(s.mediaSavedPath||s.mediaError)&&!_p(e,s.text,l))return;if(s.mediaError&&await u({kind:"text",body:p(s.mediaError)}),s.mediaSavedPath&&await u({kind:"text",body:p(`Saved: ${s.mediaSavedPath}`)}),s.text.trim()){let h=await tr(e,t,n,r,o,s,i,a,l,!1,d);if(h!==null)if(h.kind==="texts")for(let g of h.bodies)await u({kind:"text",body:g});else await u(h)}}catch(f){M.error({err:String(f)},"inbound handler error"),await u({kind:"text",body:p(`Error: ${String(f)}`)}).catch(()=>{})}}function nb(){if(process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{Na.readFileSync(ce,"utf8").trim()===String(process.pid)&&Na.unlinkSync(ce)}catch{}}async function Wp(e){let t=new Et,n=new Map,r=new Map,o=new Map,s=null,i=new Map,a=async(D,le)=>{let Y=i.get(D);s?.sendReply(D,le,Y)},l=async(D,le)=>{let Y=D.startsWith("tg:")?"telegram":"whatsapp",k=i.get(D),x=Zi(D,{kind:"file",spec:le},k,Y);s?.sendRoutedReply(D,x)},d=async(D,le)=>{let Y=i.get(D),k=D.startsWith("tg:")?"telegram":"whatsapp";s?.sendReply(D,ke(p(le),k).text,Y)},u={onPlainTextLlmFallback(D,le){Wn($(),D,le,Y=>a(D,Y))},sendToPeer:a},c=new zt(()=>$(),a),m={async reload(){return{ok:!0,summary:"Attached mode: config reloaded from disk. Messengers run on the omnish platform; this device executes commands locally."}}};if(s=new ls({env:e,onReplyError:async(D,le,Y)=>{let k=D.startsWith("tg:")?"telegram":"whatsapp";s?.sendReply(D,ke(p(`Error sending: ${le}`),k).text,Y)},onMessage:async D=>{let le=la(),Y=D.peerKey;i.set(Y,D.messageId);let k=D.surface==="telegram"?"telegram":"whatsapp",x=D.senderE164&&k==="whatsapp"?`wa:${D.senderE164}`:Y;vn()&&M.info({peerKey:Y,senderKey:x,surface:k},"platform inbound message");let L=D.mediaSavedPath,F=D.mediaError;if(D.inboundMedia){let z=bd(le,Y,D.inboundMedia);L=z.mediaSavedPath??L,F=z.mediaError??F}let Q={peerKey:Y,text:D.text,...L?{mediaSavedPath:L}:{},...F?{mediaError:F}:{}};await Nr(le,t,n,r,o,Q,c,m,x,u,async z=>{try{if(z.kind==="texts"){for(let Ue of z.bodies){let Ie=ke(Ue,k);s?.sendReply(Y,Ie.text,D.messageId)}return}if(z.kind==="text"){let Ue=ke(z.body,k);s?.sendReply(Y,Ue.text,D.messageId);return}let we=Zi(Y,z,D.messageId,k);s?.sendRoutedReply(Y,we)}catch(we){s?.sendReply(Y,`Error sending file: ${String(we)}`,D.messageId)}},{surface:k})}}),process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{Na.writeFileSync(ce,`${process.pid}
|
|
330
|
+
`,{mode:384})}catch(D){M.warn({err:String(D)},"could not write gateway pidfile")}ns({getCfg:()=>$(),getWaOutbound:()=>null,getTgSendMedia:()=>null,getTgSendText:()=>null,sendPlatformMedia:l,sendPlatformText:d});let f=null,h=$();if(h.webhookEnabled){let D=h.webhookToken||tb.randomBytes(32).toString("hex");h.webhookToken||W({webhookToken:D}),f=rs({port:h.webhookPort,host:h.webhookHost,token:D},{sendToPeer:a,getDefaultPeerKey:()=>null}).stop}let g=ys({getRunningVersion:Ze,getConfig:$,log:M}),y=jo({getConfig:$,sendToPeer:a,sendMediaToPeer:l}),b=io({getConfig:$,sendToPeer:a}),{deviceId:v,account:E}=await s.connect(),R=await is(e,E??null),P=5*60*1e3,T=setInterval(()=>{is(e,null).catch(()=>{})},P);T.unref?.();let O=e.deviceId?.trim();if(O){O!==v&&M.warn({configuredDeviceId:O,registeredDeviceId:v},"platform_device_id does not match registered device id");try{await ua(e,O)}catch(D){M.warn({err:String(D)},"could not set platform default device")}}let A=R?.gatewayMode??E?.gatewayMode,K=R?.connectors.whatsapp??E?.connectors?.whatsapp,X=R?.connectors.telegram??E?.connectors?.telegram,ie=[K?`whatsapp:${K.linked?"linked":K.status}`:null,X?`telegram:${X.linked?"linked":X.status}`:null].filter(Boolean).join(", ");console.error(`omnish attached to platform (device ${v})`+(A?` \u2014 gatewayMode=${A}`:"")+(ie?` \u2014 ${ie}`:""));let he=()=>{clearInterval(T),y(),b(),g?.(),f?.(),nb(),Kn(),s?.stop(),c.dispose(),t.killAllRunning(),gn().stopAll().catch(()=>{}),console.error(`
|
|
331
|
+
${C(process.stderr,"shutting down\u2026")}`),process.exit(0)};process.on("SIGINT",he),process.on("SIGTERM",he),await new Promise(()=>{})}function _a(e,t){return async n=>{if(t.surface==="whatsapp"&&t.waJid){if(n.kind==="file")await e.sendWaMedia?.(t.waJid,n.spec);else if(n.kind==="files")for(let r of n.specs)await e.sendWaMedia?.(t.waJid,r);else if(n.kind==="texts")for(let r of n.bodies)await e.sendWaText?.(t.waJid,ke(r,"whatsapp").text);else await e.sendWaText?.(t.waJid,ke(n.body,"whatsapp").text);return}if(t.surface==="telegram"&&e.sendTg)if(n.kind==="texts")for(let r of n.bodies)await e.sendTg({kind:"text",body:r});else await e.sendTg(n)}}me();it();G();function Ps(){if(se()){let i=$(),a=Ct(i);return dr(a)?{ok:!1,message:`Fix security errors before starting the gateway.
|
|
332
332
|
|
|
333
333
|
${a.filter(u=>u.severity==="error").map(u=>{let c=[u.message];return u.detail&&c.push(u.detail),u.fixHint&&c.push(`Fix: ${u.fixHint}`),c.join(`
|
|
334
334
|
`)}).join(`
|
|
335
335
|
|
|
336
336
|
`)}`}:{ok:!0}}let e=$(),t=e.gatewayMode,n=t==="whatsapp"||t==="both",r=t==="telegram"||t==="both",o=ve(e);if(r&&!o)return{ok:!1,message:`Telegram enabled (gatewayMode) but no bot token. Set telegramBotToken in config or TELEGRAM_BOT_TOKEN.
|
|
337
|
-
config: ${_}`};if(n&&!nt())return{ok:!1,message:"WhatsApp enabled but no session. Run `omnish link` first."};let s=
|
|
337
|
+
config: ${_}`};if(n&&!nt())return{ok:!1,message:"WhatsApp enabled but no session. Run `omnish link` first."};let s=Ct(e);return dr(s)?{ok:!1,message:`Fix security errors before starting the gateway (or change gatewayMode / token).
|
|
338
338
|
|
|
339
339
|
${s.filter(l=>l.severity==="error").map(l=>{let d=[l.message];return l.detail&&d.push(l.detail),l.fixHint&&d.push(`Fix: ${l.fixHint}`),d.join(`
|
|
340
340
|
`)}).join(`
|
|
341
341
|
|
|
342
|
-
`)}`}:{ok:!0}}G();import
|
|
343
|
-
`))}function
|
|
344
|
-
`));return}let i=
|
|
345
|
-
`));return}if(n==="list"){let r=await
|
|
346
|
-
`))}async function
|
|
347
|
-
`));return}let o=
|
|
348
|
-
`,{mode:384});try{
|
|
349
|
-
`,{mode:384});try{
|
|
350
|
-
`,{mode:384}),r}
|
|
351
|
-
`,{mode:384})}function
|
|
342
|
+
`)}`}:{ok:!0}}it();G();it();import Ls from"node:fs";import Ns from"node:path";me();import{spawn as rb}from"node:child_process";import Up from"node:fs";import{stdout as ob}from"node:process";it();G();rn();var Fa=["tunnelRelayUrl","platformToken","platformDeviceId"],Dp=[{label:"Platform (attached gateway + tunnel)",keys:["tunnelRelayUrl","platformToken","platformDeviceId"]},{label:"Tunnel",keys:["tunnelEnabled","tunnelMaxActive"]},{label:"Gateway",keys:["gatewayMode","commandPrefix","shell"]},{label:"Cluster",keys:["clusterEnabled","clusterRole","clusterLabel","clusterSenderBindings"]},{label:"Telegram",keys:["telegramBotToken"]},{label:"Apps",keys:["appsCols","appsRows","appsFlushMs","appsMinIntervalMs","appsMaxFlushBytes","appsMaxSessions","appsMaxSessionsTotal","appsMaxWaChars","appsLogTailLines","appsSubmitDelayMs","appsClearInput","appsClearInputDelayMs","appsClearInputSequence","appsSkipClearOnPasswordPrompt","appsPasswordPromptHint"]},{label:"Files",keys:["fileSendMaxBytes","fileReceiveMaxBytes","fileInboxSubdir","fileReceiveRootMode","fileReceiveRootPath"]},{label:"Recipes",keys:["recipesAllowDangerousBuiltins","recipesMaxTaskChars","recipesMacroDefaultCommand"]},{label:"Sync / jobs",keys:["syncTimeoutMs","syncMaxBytes","jobLogTailLines"]},{label:"Service / updates",keys:["serviceInstallFromChat","updateCheckEnabled","updateCheckIntervalMs","updateCheckPackageName","updateInfoUrl"]},{label:"Chat LLM fallback",keys:["chatLlmFallbackEnabled","chatLlmShellCommand","chatLlmTimeoutMs","chatLlmMaxInputChars","chatLlmMaxOutputChars","chatLlmNeedsTty","chatLlmWorkDir"]}];function Is(e){let t=[J(e,"omnish config"),w(e,"Manage ~/.omnish/config.json (env vars still override for platform credentials)."),"",J(e,"Usage:"),` ${S(e,"omnish config add <key> <value> [key value ...]")}`,` ${S(e,"omnish config show <key>[,<key>|*]")}`,` ${S(e,"omnish config edit")}`,` ${S(e,"omnish config edit <key> <value>")}`,` ${S(e,"omnish config delete <key>[,<key>]")}`,"",w(e,"Platform aliases: platform_url \u2192 tunnelRelayUrl, platform_token \u2192 platformToken,"),w(e," platform_device_id \u2192 platformDeviceId"),` ${S(e,"omnish config show platform")} ${w(e,"\u2014 attached-mode diagnostics (URL, token, devices)")}`,w(e," Full setup: omnish help platform"),w(e,"add sets/overwrites scalar keys (not array append). show * lists all keys."),""];console.log(t.join(`
|
|
343
|
+
`))}function Hp(e){return e.split(/[,\s]+/).map(t=>t.trim()).filter(Boolean)}function Wa(e){if(e.length===0)return[];let t=e.join(" ");if(t.includes(",")){let n=[];for(let r of t.split(",")){let o=r.trim();if(!o)continue;let s=o.split(/\s+/);if(s.length<2)throw new Error(`Invalid pair "${o}" \u2014 expected "key value"`);n.push({key:s[0],value:s.slice(1).join(" ")})}return n}if(e.length===2)return[{key:e[0],value:e[1]}];if(e.length%2===0){let n=[];for(let r=0;r<e.length;r+=2)n.push({key:e[r],value:e[r+1]});return n}return[{key:e[0],value:e.slice(1).join(" ")}]}function As(e,t){if(e==="clusterSenderBindings")return JSON.stringify(t.clusterSenderBindings);let n=String(t[e]??"");return e==="platformToken"||e==="telegramBotToken"?sn(e,n):n}function Bp(e){return e==="tunnelRelayUrl"?{value:Rr(),source:qn()}:e==="platformToken"?{value:sn(e,na()),source:zn()}:e==="platformDeviceId"?{value:(ra()??"")||"(empty)",source:oa()}:null}function sb(e){if(e!=="platformToken"&&e!=="tunnelRelayUrl")return;let n=$().platformToken.trim()||$t()?.token?.trim()||"";n&&ht({token:n,relayUrl:Rr()})}async function ib(){let e=process.env.VISUAL?.trim()||process.env.EDITOR?.trim()||(process.platform==="win32"?"notepad":"nano"),t=Up.readFileSync(_,"utf8");await new Promise((n,r)=>{let o=rb(e,[_],{stdio:"inherit"});o.on("error",r),o.on("exit",s=>{s===0?n():r(new Error(`Editor exited with code ${s??1}`))})});try{$()}catch(n){throw Up.writeFileSync(_,t,{mode:384}),new Error(`Invalid config after edit: ${n instanceof Error?n.message:String(n)}`)}}async function jp(e){let t=ob,n=process.stderr,r=(e[0]??"").trim().toLowerCase(),o=e.slice(1);if(!r||r==="help"||r==="--help"||r==="-h"){Is(t);return}if(r==="add"||r==="edit"){try{if(r==="edit"&&o.length===0){await ib(),console.log(B(t,`Updated ${_}`));return}let s=Wa(o);if(s.length===0){console.error(C(n,"Expected at least one key/value pair.")),process.exitCode=1;return}for(let{key:i,value:a}of s){let l=go(i);if(!l){console.error(C(n,`Unknown key "${i}". Try: ${Gc().slice(0,8).join(", ")}\u2026 (omnish config show *)`)),process.exitCode=1;return}Pn(l,a),sb(l);let d=$(),u=l==="tunnelRelayUrl"?d.tunnelRelayUrl:Fa.includes(l)?sn(l,String(d[l]??"")):As(l,d);console.log(B(t,`${i} \u2192 ${u}`))}console.log(B(t,_))}catch(s){console.error(C(n,s instanceof Error?s.message:String(s))),process.exitCode=1}return}if(r==="show"){let s=o.join(" ").trim()||"*";if(s==="*"){let l=$(),d=[J(t,"Config"),w(t,_),""];for(let m of Dp){d.push(J(t,m.label));for(let f of m.keys){let h=As(f,l),g=Bp(f);g&&Fa.includes(f)?d.push(` ${S(t,f)}: ${h} ${w(t,`(effective: ${g.value}, source: ${g.source})`)}`):d.push(` ${S(t,f)}: ${h}`)}d.push("")}let u=new Set(Dp.flatMap(m=>m.keys)),c=bi.filter(m=>!u.has(m));if(c.length>0){d.push(J(t,"Other"));for(let m of c)d.push(` ${S(t,m)}: ${As(m,l)}`)}console.log(d.join(`
|
|
344
|
+
`));return}let i=Hp(s),a=$();for(let l of i){let d=go(l);if(!d){console.error(C(n,`Unknown key "${l}".`)),process.exitCode=1;return}let u=As(d,a),c=Bp(d);c&&Fa.includes(d)?console.log(`${l}: ${u} (effective: ${c.value}, source: ${c.source})`):console.log(`${l}: ${u}`)}return}if(r==="delete"){let s=o.join(" ").trim();if(!s){console.error(C(n,"Expected at least one key to delete.")),process.exitCode=1;return}if(s==="*"){console.error(C(n,'Refusing "delete *". List keys explicitly.')),process.exitCode=1;return}try{for(let i of Hp(s)){let a=go(i);if(!a){console.error(C(n,`Unknown key "${i}".`)),process.exitCode=1;return}Jc(a),console.log(B(t,`cleared ${i}`))}console.log(B(t,_))}catch(i){console.error(C(n,i instanceof Error?i.message:String(i))),process.exitCode=1}return}console.error(C(n,`Unknown subcommand "${r}".`)),Is(t),process.exitCode=1}async function Gp(e){let t=se(),n=[];if(n.push(J(e,"platform")),!t){n.push(` ${w(e,"attached:")} ${fe(e,"no")} \u2014 set platform_url + platform_token (omnish config add) or env`);let a=qn(),l=zn();return(a==="env"||l==="env")&&n.push(` ${w(e,"note:")} ${V(e,"partial env override (need URL + token)")}`),n}let r=qn(),o=zn(),s=oa(),i=r==="env"||o==="env"||s==="env"?` ${w(e,"(env overrides config)")}`:"";n.push(` ${w(e,"attached:")} ${S(e,"yes")}${i}`),n.push(` ${w(e,"url:")} ${S(e,t.platformUrl)} ${V(e,`[${r}]`)}`),n.push(` ${w(e,"token:")} ${S(e,sn("platformToken",t.token))} ${V(e,`[${o}]`)}`),t.deviceId&&n.push(` ${w(e,"device:")} ${S(e,t.deviceId)} ${V(e,`[${s}]`)}`);try{let{fetchPlatformAccount:a}=await Promise.resolve().then(()=>(Cr(),vd)),l=await a(t);n.push(` ${w(e,"gatewayMode:")} ${S(e,l.gatewayMode)} ${V(e,"(platform)")}`);let d=c=>{let m=l.connectors[c];return m?m.linked?S(e,"linked"):V(e,m.status):fe(e,"idle")};n.push(` ${w(e,"whatsapp:")} ${d("whatsapp")}`),n.push(` ${w(e,"telegram:")} ${d("telegram")}`);let u=l.routing.onlineCount;n.push(` ${w(e,"routing:")} default=${l.routing.defaultDeviceId??V(e,"(none)")} online=${u}`),t.deviceId&&l.routing.defaultDeviceId&&t.deviceId!==l.routing.defaultDeviceId&&n.push(` ${w(e,"warn:")} ${fe(e,"platform_device_id \u2260 platform defaultDeviceId \u2014 run omnish run or set default on dashboard")}`),u===0&&n.push(` ${w(e,"warn:")} ${fe(e,"no device online on platform")}`)}catch{n.push(` ${w(e,"account:")} ${V(e,"(could not fetch /v1/me \u2014 check token and URL)")}`)}return n}Cr();it();function Kp(){let e=se();return e||(console.error(C(process.stderr,"Set platform_url + platform_token (omnish config add) or OMNISH_PLATFORM_URL + OMNISH_TOKEN.")),process.exitCode=1,null)}function ab(e){let t=e.trim();return t?t.startsWith("wa:")?{kind:"wa",value:t.slice(3).trim()}:t.startsWith("tg:")?{kind:"tg",value:t.slice(3).trim()}:/^\+?\d{8,}$/.test(t.replace(/\s/g,""))?{kind:"wa",value:t}:/^\d+$/.test(t)?{kind:"tg",value:t}:null:null}function Jp(e){return e.replace(/\D/g,"")}async function zp(){let e=Kp();if(!e)return;let t=await hn(e),n=t.connectors.whatsapp,r=t.connectors.telegram;console.log(B(process.stdout,"Platform account")),console.log(` gatewayMode: ${t.gatewayMode}`),console.log(` whatsapp: ${n?.linked?"linked":n?.status??"idle"} (allowlist: ${t.allowFrom.length})`);let o=r?.tokenConfigured?"token saved":"no token";console.log(` telegram: ${r?.linked?"linked":r?.status??"idle"} (${o}, allowlist: ${t.telegramAllowFrom.length})`),console.log(` defaultDeviceId: ${t.defaultDeviceId??"\u2014"}`),console.log(` online devices: ${t.routing.onlineCount}`),t.allowFrom.length&&console.log(` allowFrom: ${t.allowFrom.map(s=>`+${s}`).join(", ")}`),t.telegramAllowFrom.length&&console.log(` telegramAllowFrom: ${t.telegramAllowFrom.join(", ")}`)}async function qp(e){let t=Kp();if(!t)return;let n=(e[0]??"").toLowerCase();if(!n||n==="-h"||n==="--help"){console.log(["Usage:"," omnish platform allow list"," omnish platform allow add wa:+15551234567 tg:123456789"," omnish platform allow set --wa +1555,... --tg 123,...",""].join(`
|
|
345
|
+
`));return}if(n==="list"){let r=await hn(t);console.log(B(process.stdout,"Platform allowlists")),console.log(` WhatsApp (${r.allowFrom.length}): ${r.allowFrom.length?r.allowFrom.map(o=>`+${o}`).join(", "):"(empty \u2014 any sender)"}`),console.log(` Telegram (${r.telegramAllowFrom.length}): ${r.telegramAllowFrom.length?r.telegramAllowFrom.join(", "):"(empty \u2014 any sender)"}`);return}if(n==="add"){let r=await hn(t),o=[...r.allowFrom],s=[...r.telegramAllowFrom];for(let a of e.slice(1)){let l=ab(a);if(!l){console.error(C(process.stderr,`Unrecognized entry: ${a}`)),process.exitCode=1;return}if(l.kind==="wa"){let d=Jp(l.value);d&&!o.includes(d)&&o.push(d)}else{let d=l.value.replace(/\D/g,"");d&&!s.includes(d)&&s.push(d)}}let i=await ss(t,{allowFrom:o,telegramAllowFrom:s});console.log(B(process.stdout,`Allowlists updated (${i.allowFrom.length} WhatsApp, ${i.telegramAllowFrom.length} Telegram).`));return}if(n==="set"){let r,o;for(let a=1;a<e.length;a++){let l=e[a];l==="--wa"&&e[a+1]?r=e[++a].split(",").map(d=>Jp(d.trim())).filter(Boolean):l==="--tg"&&e[a+1]&&(o=e[++a].split(",").map(d=>d.trim().replace(/^tg:/i,"").replace(/\D/g,"")).filter(Boolean))}if(r===void 0&&o===void 0){console.error(C(process.stderr,"Use --wa and/or --tg with comma-separated values.")),process.exitCode=1;return}let s={};r!==void 0&&(s.allowFrom=r),o!==void 0&&(s.telegramAllowFrom=o);let i=await ss(t,s);console.log(B(process.stdout,`Allowlists set (${i.allowFrom.length} WhatsApp, ${i.telegramAllowFrom.length} Telegram).`));return}console.error(C(process.stderr,`Unknown allow subcommand: ${e[0]}`)),process.exitCode=1}async function Yp(e){let t="",n="",r="";for(let o=0;o<e.length;o++){let s=e[o];(s==="--url"||s==="-u")&&e[o+1]?t=e[++o].trim():(s==="--token"||s==="-t")&&e[o+1]?n=e[++o].trim():s==="--device-id"&&e[o+1]&&(r=e[++o].trim())}if(!t||!n){let o=Wa(e);for(let s of o)s.key==="platform_url"&&(t=s.value),s.key==="platform_token"&&(n=s.value),s.key==="platform_device_id"&&(r=s.value)}if(!t||!n){console.error(C(process.stderr,"Usage: omnish platform login --url <url> --token <token> [--device-id <id>]")),process.exitCode=1;return}Pn("tunnelRelayUrl",t.replace(/\/$/,"")),Pn("platformToken",n),r&&Pn("platformDeviceId",r),console.log(B(process.stdout,"Platform credentials saved to config.json.")),console.log(" Run: omnish platform status && omnish run")}import lb from"qrcode-terminal";it();var cb=1e3,ub=120;function Qp(){let e=se();return e||(console.error(C(process.stderr,"Set platform_url + platform_token (omnish config add) or OMNISH_PLATFORM_URL + OMNISH_TOKEN.")),process.exitCode=1,null)}function Da(e){let t=e.replace(/\/$/,"");return/^https?:\/\//i.test(t)?t:`http://${t}`}async function Vp(e){let t=`${Da(e.platformUrl)}/v1/connectors/whatsapp/status`,n=await fetch(t,{headers:{Authorization:`Bearer ${e.token}`}}),r=await n.json().catch(()=>({}));if(!n.ok)throw new Error(r.error||`HTTP ${n.status}`);return r}async function db(e){let t=await fetch(`${Da(e.platformUrl)}/v1/connectors/whatsapp/start`,{method:"POST",headers:{"content-type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({})}),n=await t.json().catch(()=>({}));if(!t.ok)throw new Error(n.error||`HTTP ${t.status}`);return n}function Xp(e){let t=process.stdout,n=w(t,"\xB7".repeat(42));console.log(V(t,"Scan with WhatsApp \u2192 Linked devices")),console.log(n),lb.generate(e,{small:!0}),console.log(n)}var Os="",Ua=!1;function pb(e){let t=e.status??"";return t==="qr"||t==="connecting"||t==="reconnecting"||t==="pairing_restart"}async function mb(e){for(let t=0;t<ub;t++){let n=await Vp(e);if(n.status==="linked"||n.linked)return n;if(n.status==="pairing_restart"&&!Ua&&(Ua=!0,console.log(w(process.stdout,"Finishing WhatsApp link after scan (server restart) \u2014 wait a few seconds\u2026"))),n.qr&&n.qr!==Os&&(Os=n.qr,Xp(n.qr)),!pb(n))throw new Error(n.error||n.statusMessage||`Unexpected status: ${n.status}`);await new Promise(r=>setTimeout(r,cb))}throw new Error("Timed out waiting for WhatsApp to link (scan the QR within ~2 minutes).")}async function Zp(){let e=Qp();if(!e)return;let t=await Vp(e);if(t.status==="linked"||t.linked){console.log(B(process.stdout,"WhatsApp already linked on the platform.")),t.linkedPhoneE164&&(console.log(` Phone: +${t.linkedPhoneE164}`),console.log(` Hint: omnish platform allow add wa:+${t.linkedPhoneE164}`));return}console.log(B(process.stdout,"Starting WhatsApp pairing on the platform\u2026")),Ua=!1,Os="",t=await db(e),t.qr&&(Xp(t.qr),Os=t.qr),t=await mb(e),console.log(B(process.stdout,"WhatsApp linked on the platform.")),t.linkedPhoneE164&&(console.log(` Phone: +${t.linkedPhoneE164}`),console.log(` Next: omnish platform allow add wa:+${t.linkedPhoneE164}`),console.log(" Then: omnish run"))}async function em(){let e=Qp();if(!e)return;let t=await fetch(`${Da(e.platformUrl)}/v1/connectors/whatsapp/unlink`,{method:"POST",headers:{"content-type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({})}),n=await t.json().catch(()=>({}));if(!t.ok){console.error(C(process.stderr,n.error||`HTTP ${t.status}`)),process.exitCode=1;return}console.log(B(process.stdout,`WhatsApp unlinked (status: ${n.status??"idle"}).`))}import fb from"ws";function tm(e,t,n){return new Promise(r=>{let o=new fb(e,{headers:{Authorization:`Bearer ${t}`}}),s=setTimeout(()=>{o.terminate(),r({ok:!1,message:"timeout"})},n);o.once("open",()=>{clearTimeout(s),o.close(),r({ok:!0})}),o.once("unexpected-response",(i,a)=>{clearTimeout(s),r({ok:!1,status:a.statusCode,message:`HTTP ${a.statusCode} ${a.statusMessage}`})}),o.once("error",i=>{clearTimeout(s),r({ok:!1,message:String(i?.message??i)})})})}async function nm(e,t,n=12e3){let r=e.replace(/\/$/,""),o=Yn(r),s=await tm(o,t,n),i,a,l="";for(let d of as(r)){let u=await tm(d,t,n);if(u.ok)return i=new URL(d).pathname,{ok:!0,controlWsOk:s.ok,deviceWsOk:!0,deviceWsPath:i};a=u.status,l=u.message}return a===400?{ok:!1,controlWsOk:s.ok,deviceWsOk:!1,deviceWsStatus:400,error:"Device WebSocket returned HTTP 400 on /platform/device and could not use /control/device. Redeploy the latest relay image (adds /control/device), or route /platform/* to port 8788 in Caddy/EasyPanel."}:{ok:!1,controlWsOk:s.ok,deviceWsOk:!1,deviceWsStatus:a,error:`Device WebSocket failed: ${l}`}}var hb=400,gb=8*1024*1024,yb=2*1024*1024;function wb(e){let t=ne,n=!1,r=!1;for(let o=0;o<e.length;o++){let s=e[o];s==="-h"||s==="--help"?r=!0:s==="--force"?n=!0:(s==="--auth-dir"||s==="--authDir")&&e[o+1]&&(t=Ns.resolve(e[++o]))}return{authDir:t,force:n,help:r}}function bb(e){let t={},n=0,r=0;function o(s,i){let a;try{a=Ls.readdirSync(i,{withFileTypes:!0})}catch{return}for(let l of a){let d=l.name;if(d==="."||d==="..")continue;let u=Ns.join(i,d),m=(s?`${s}/${d}`:d).split(Ns.sep).join("/");if(!l.isSymbolicLink()){if(l.isDirectory())o(m,u);else if(l.isFile()){let f=Ls.readFileSync(u);if(f.length>yb)throw new Error(`file too large: ${m}`);if(n+=f.length,n>gb)throw new Error("total auth size exceeds limit (8 MiB)");if(r+=1,r>hb)throw new Error("too many files (max 400)");t[m]=f.toString("base64")}}}}return o("",e),t}function _s(e){console.log([ue(e,"omnish platform"),w(e,"Attached mode: messengers on the hosted platform; shell on this machine (omnish run)."),"",J(e,"When to use"),w(e," Link WhatsApp/Telegram once on the platform dashboard. Run omnish run on laptops, servers, or containers without local Baileys."),"",J(e,"Prerequisites"),w(e," 1. Platform account token (signup/login on relay dashboard)."),w(e," 2. Messengers linked on the platform (dashboard QR or import-whatsapp)."),w(e," 3. allowFrom / telegramAllowFrom on dashboard Allowlists (Telegram: DM bot /id for your user id)."),"",J(e,"Configure"),` ${S(e,"omnish config add platform_url <url> platform_token <token>")}`,w(e," Optional: platform_device_id <id>"),w(e," Env overrides: OMNISH_PLATFORM_URL, OMNISH_TOKEN, OMNISH_DEVICE_ID"),w(e," (aliases: OMNISH_COMM_LAYER_URL, OMNISH_DEVICE_TOKEN, OMNISH_TUNNEL_*)"),"",J(e,"Workflow"),` ${S(e,"omnish platform login --url <url> --token <t>")} ${w(e,"\u2014 save credentials (or config add)")}`,` ${S(e,"omnish platform status")} ${w(e,"\u2014 account, connectors, allowlists")}`,` ${S(e,"omnish platform allow add tg:<id>")} ${w(e,"\u2014 or dashboard + bot /id")}`,` ${S(e,"omnish platform probe")} ${w(e,"\u2014 test WebSocket routing")}`,` ${S(e,"omnish run")} ${w(e,"\u2014 attach device; expect 'omnish attached to platform'")}`,"",J(e,"Subcommands"),S(e,"omnish platform login --url <url> --token <token> [--device-id <id>]"),w(e," Save platform URL and token to config.json."),"",S(e,"omnish platform status"),w(e," Show gatewayMode, connector status, allowlists, online devices."),"",S(e,"omnish platform allow list|add|set"),w(e," Manage platform allowlists (PUT /v1/me/allowlists)."),"",S(e,"omnish platform probe"),w(e," Test control-plane WebSocket routing (diagnose attached omnish run 400 errors)."),"",S(e,"omnish platform link-whatsapp"),w(e," Pair WhatsApp on the platform (terminal QR + poll until linked)."),"",S(e,"omnish platform unlink-whatsapp"),w(e," Remove platform WhatsApp session and auth files."),"",S(e,"omnish platform import-whatsapp [--auth-dir <path>] [--force]"),w(e," Upload local Baileys auth (after omnish link on this host). Use link-whatsapp or dashboard QR when possible."),w(e," Stop local omnish run before import to avoid WhatsApp session conflicts."),"",w(e,"Standalone omnish link on this host is not used for platform WhatsApp when attached."),w(e,"Docs: docs/guides/platform-reference.md (full API/CLI)"),w(e," docs/guides/platform-attached-mode.md (walkthrough)"),""].join(`
|
|
346
|
+
`))}async function kb(e){let{authDir:t,force:n,help:r}=wb(e);if(r){console.log(["Usage: omnish platform import-whatsapp [--auth-dir <path>] [--force]","","Requires OMNISH_PLATFORM_URL and OMNISH_TOKEN.","Default auth directory: ~/.omnish/auth (Baileys useMultiFileAuthState).","Stop `omnish run` on this machine before importing to avoid WhatsApp session conflicts.",""].join(`
|
|
347
|
+
`));return}let o=se();if(!o){console.error(C(process.stderr,"Set OMNISH_PLATFORM_URL (control plane URL) and OMNISH_TOKEN (from dashboard signup/login).")),process.exitCode=1;return}if(!Ls.existsSync(t)){console.error(C(process.stderr,`Auth directory not found: ${t}`)),process.exitCode=1;return}te();let s=Ns.join(t,"creds.json");if(!Ls.existsSync(s)){console.error(C(process.stderr,`No creds.json in ${t} \u2014 link WhatsApp locally first (omnish link).`)),process.exitCode=1;return}let i;try{i=bb(t)}catch(f){console.error(C(process.stderr,String(f))),process.exitCode=1;return}if(Object.keys(i).length===0){console.error(C(process.stderr,"No files collected (empty auth directory?).")),process.exitCode=1;return}let a=o.platformUrl.replace(/\/$/,""),d=`${/^https?:\/\//i.test(a)?a:`http://${a}`}/v1/connectors/whatsapp/import`,u=await fetch(d,{method:"POST",headers:{"content-type":"application/json",Authorization:`Bearer ${o.token}`},body:JSON.stringify({files:i,force:n})}),c=await u.json().catch(()=>({}));if(!u.ok){console.error(C(process.stderr,c.error||`HTTP ${u.status}`)),process.exitCode=1;return}let m=c.qr?" QR emitted \u2014 open the platform dashboard if you need to scan.":"";console.log(B(process.stdout,`Uploaded Baileys auth. Platform connector status: ${c.status??"unknown"}.${m}`))}async function Sb(){let e=process.stdout,t=process.stderr,n=se();if(!n){console.error(C(t,"Set platform_url + platform_token (omnish config add) or OMNISH_PLATFORM_URL + OMNISH_TOKEN.")),process.exitCode=1;return}console.log(`${ue(e,"Platform probe")} ${w(e,n.platformUrl)}`);let r=await nm(n.platformUrl,n.token);console.log(` ${w(e,"wss /control:")} ${r.controlWsOk?S(e,"ok"):fe(e,"fail")}`);for(let o of["/platform/device","/control/device"]){if(r.ok&&r.deviceWsPath&&r.deviceWsPath!==o){console.log(` ${w(e,`wss ${o}:`)} ${V(e,"skipped (fallback used)")}`);continue}if(r.ok&&r.deviceWsPath===o){console.log(` ${w(e,`wss ${o}:`)} ${S(e,"ok")}`);continue}!r.ok&&o==="/platform/device"&&console.log(` ${w(e,`wss ${o}:`)} ${fe(e,"fail")}${r.deviceWsStatus?` (HTTP ${r.deviceWsStatus})`:""}`),!r.ok&&o==="/control/device"&&console.log(` ${w(e,`wss ${o}:`)} ${fe(e,"fail")}`)}if(r.ok){r.deviceWsPath==="/control/device"&&console.log(w(e," Using /control/device fallback (/platform/* not on control port \u2014 redeploy Caddy when convenient).")),console.log(B(e,"Attached omnish run should be able to connect."));return}console.error(C(t,r.error??"Platform probe failed.")),r.controlWsOk&&!r.deviceWsOk&&console.error(C(t,"Fix: redeploy the latest tunnel-relay image (enables wss /control/device), update omnish CLI, then retry. Also route /platform/* to 8788 when you can (Caddyfile.standalone).")),process.exitCode=1}async function rm(e){let t=(e[0]??"").toLowerCase();if(!t||t==="-h"||t==="--help"){_s(process.stdout);return}if(t==="login"){await Yp(e.slice(1));return}if(t==="status"){await zp();return}if(t==="allow"){await qp(e.slice(1));return}if(t==="probe"){await Sb();return}if(t==="link-whatsapp"){await Zp();return}if(t==="unlink-whatsapp"){await em();return}if(t==="import-whatsapp"){await kb(e.slice(1));return}console.error(C(process.stderr,`Unknown platform subcommand: ${e[0]}`)),_s(process.stderr),process.exitCode=1}G();import im from"node:crypto";import bn from"node:fs";import am from"node:path";function vb(){return im.randomBytes(24).toString("hex")}function om(){return im.randomBytes(32).toString("hex")}function sm(e){try{let t=bn.readFileSync(e,"utf8"),n=JSON.parse(t);if(typeof n.token=="string"&&n.token.length>=16&&typeof n.secret=="string"&&n.secret.length>=16)return{token:n.token,secret:n.secret}}catch{}return null}function xb(){let e=sm(ut);if(e)return e;if(e=sm(rr),e){j(am.dirname(ut)),bn.writeFileSync(ut,JSON.stringify(e,null,2)+`
|
|
348
|
+
`,{mode:384});try{bn.unlinkSync(rr)}catch{}return e}return null}function lm(e){j(am.dirname(ut));let t=xb(),n=(e??"").trim();if(n){let o={token:n,secret:t?.secret??om()};bn.writeFileSync(ut,JSON.stringify(o,null,2)+`
|
|
349
|
+
`,{mode:384});try{bn.existsSync(rr)&&bn.unlinkSync(rr)}catch{}return o}if(t)return t;let r={token:vb(),secret:om()};return bn.writeFileSync(ut,JSON.stringify(r,null,2)+`
|
|
350
|
+
`,{mode:384}),r}me();import Zt from"node:fs";import Eb from"node:http";import Ae from"node:path";import at from"node:process";import{fileURLToPath as Pb}from"node:url";import Ab from"node:os";qe();G();import Ha from"node:crypto";var Ba="omnish_cfg_sess",cm=7*24*60*60*1e3;function ja(e){let t=Date.now()+cm,n=Buffer.from(JSON.stringify({exp:t}),"utf8").toString("base64url"),r=Ha.createHmac("sha256",e).update(n).digest("hex");return`${n}.${r}`}function um(e,t){let n=$b(t??"")[Ba];if(!n||!n.includes("."))return!1;let r=n.lastIndexOf("."),o=n.slice(0,r),s=n.slice(r+1),i=Ha.createHmac("sha256",e).update(o).digest("hex");try{let a=Buffer.from(s,"hex"),l=Buffer.from(i,"hex");if(a.length!==l.length||!Ha.timingSafeEqual(a,l))return!1}catch{return!1}try{let a=JSON.parse(Buffer.from(o,"base64url").toString("utf8"));return!(typeof a.exp!="number"||a.exp<Date.now())}catch{return!1}}function Ga(e){let t=Math.floor(cm/1e3);return`${Ba}=${e}; HttpOnly; Path=/; SameSite=Lax; Max-Age=${t}`}function dm(){return`${Ba}=; HttpOnly; Path=/; SameSite=Lax; Max-Age=0`}function $b(e){let t={};for(let n of e.split(";")){let r=n.indexOf("=");if(r===-1)continue;let o=n.slice(0,r).trim(),s=n.slice(r+1).trim();o&&(t[o]=decodeURIComponent(s))}return t}G();import Ja from"node:fs";import Fs from"node:process";function pm(e){try{return Fs.kill(e,0),!0}catch{return!1}}function mm(e){let t=Date.now()+e;for(;Date.now()<t;);}function Rb(){try{let e=Ja.readFileSync(Hr,"utf8"),t=JSON.parse(e);if(!t||typeof t!="object")return null;let n=t,r=typeof n.pid=="number"?n.pid:Number(n.pid),o=typeof n.port=="number"?n.port:Number(n.port),s=typeof n.host=="string"?n.host:"",i=typeof n.startedAt=="string"?n.startedAt:"";return!Number.isFinite(r)||r<=0||!Number.isFinite(o)||o<=0||o>65535?null:{pid:r,port:o,host:s,startedAt:i}}catch{return null}}function fm(e){Ja.writeFileSync(Hr,`${JSON.stringify(e)}
|
|
351
|
+
`,{mode:384})}function _r(){try{Ja.unlinkSync(Hr)}catch{}}function hm(e){let t=Rb();if(t&&t.port===e&&t.pid!==Fs.pid){if(!pm(t.pid)){_r();return}try{Fs.kill(t.pid,"SIGTERM")}catch{}if(mm(350),pm(t.pid)){try{Fs.kill(t.pid,"SIGKILL")}catch{}mm(100)}_r()}}me();G();import Ka from"node:fs";import Cb from"node:process";function Mb(e){try{return Cb.kill(e,0),!0}catch{return!1}}function Tb(){try{let e=Ka.readFileSync(ce,"utf8").trim(),t=Number.parseInt(e,10);return Number.isFinite(t)&&t>0?t:null}catch{return null}}function Ws(){let e=Tb();return e===null?!1:Mb(e)}var za=class{busy=!1;subscribers=new Set;abort=null;currentSock=null;subscribe(t){return this.subscribers.add(t),()=>{this.subscribers.delete(t)}}emit(t){for(let n of this.subscribers)try{n(t)}catch{}}requestCancel(){this.abort?.abort(),this.currentSock&&(jn(this.currentSock),this.currentSock=null)}beginPairing(t){if(this.busy)throw new Error("Pairing already in progress.");if(Ws())throw new Error("Gateway appears to be running (gateway.pid). Stop `omnish run` or your service before pairing from the browser.");if(!t.force&&nt())throw new Error("WhatsApp session already linked. Use \u201CReplace session\u201D or run `omnish link --force` from the CLI.");te(),t.force&&(Ka.rmSync(ne,{recursive:!0,force:!0}),Ka.mkdirSync(ne,{recursive:!0,mode:448})),this.busy=!0,this.abort=new AbortController;let n=this.abort.signal;(async()=>{try{await dd({authDir:ne,verbose:!1,printQr:!1,signal:n,onQr:r=>this.emit({type:"qr",payload:r}),onRestart515:()=>this.emit({type:"restart"}),onSocketReady:r=>{this.currentSock=r},onSocketClosed:()=>{this.currentSock=null}}),this.emit({type:"open"}),this.emit({type:"done",ok:!0})}catch(r){let o=r instanceof Error?r.message:String(r);o==="Pairing cancelled."?this.emit({type:"error",message:"Cancelled."}):this.emit({type:"error",message:o}),this.emit({type:"done",ok:!1})}finally{this.busy=!1,this.abort=null,this.currentSock=null}})()}},Fr=new za;var ae="application/json; charset=utf-8",Wr=null;function Ib(){_r();let e=Wr;Wr=null,e?e.close(()=>{at.exit(0)}):at.exit(0),setTimeout(()=>at.exit(0),4e3).unref()}function Ob(){let e=at.env.OMNISH_CONFIG_UI_STATIC?.trim(),t=at.env.OMNISH_UI_STATIC?.trim()||e;if(t&&Zt.existsSync(Ae.join(t,"index.html")))return t;let n=Ae.dirname(Pb(import.meta.url)),r=Ae.join(n,"ui");if(Zt.existsSync(Ae.join(r,"index.html")))return r;let o=Ae.join(n,"..","..","dist","ui");if(Zt.existsSync(Ae.join(o,"index.html")))return o;let s=Ae.join(at.cwd(),"dist","ui");if(Zt.existsSync(Ae.join(s,"index.html")))return s;throw new Error("omnish ui static files not found (expected dist/ui/index.html). Run `pnpm build`.")}function Lb(e){let t=Ae.extname(e).toLowerCase();return{".html":"text/html; charset=utf-8",".js":"text/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".ico":"image/x-icon",".woff2":"font/woff2",".json":"application/json; charset=utf-8"}[t]??"application/octet-stream"}function Nb(e,t){let r=decodeURIComponent(t.split("?")[0]??"").replace(/^\/+/,""),o=Ae.normalize(Ae.join(e,r));return!o.startsWith(Ae.normalize(e+Ae.sep))&&o!==Ae.normalize(e)?null:o}async function qa(e,t=512e3){let n=[],r=0;for await(let s of e){if(r+=s.length,r>t)throw new Error("Body too large.");n.push(s)}if(n.length===0)return;let o=Buffer.concat(n).toString("utf8");return JSON.parse(o)}function _b(e){return Gt.includes(e)}function Ya(e){let t=(e.telegramBotToken??"").trim(),n=t.length===0?"":t.length<=8?"(set)":`${t.slice(0,4)}\u2026${t.slice(-4)}`;return{...e,telegramBotToken:n,telegramBotTokenConfigured:!!ve(e),telegramBotTokenEnvOverride:typeof at.env.TELEGRAM_BOT_TOKEN=="string"&&at.env.TELEGRAM_BOT_TOKEN.trim().length>0}}function Fb(){let e=$();return{version:Ze(),dataDir:H,configPath:_,waAuthDir:ne,whatsappLinked:nt(),gatewayPidHint:Zt.existsSync(Ae.join(H,"gateway.pid")),gatewayRunning:Ws(),gatewayLogFile:Ne,gatewayMode:e.gatewayMode,telegramBotTokenMasked:ve(e).length===0?"":Ya(e).telegramBotToken,telegramBotTokenEnvOverride:typeof at.env.TELEGRAM_BOT_TOKEN=="string"&&at.env.TELEGRAM_BOT_TOKEN.trim().length>0}}function Wb(e,t){if(!Array.isArray(e)||!Array.isArray(t))throw new Error("allowFrom and telegramAllowFrom must be arrays of strings.");let n=e.map(a=>String(a).trim()).filter(Boolean),r=t.map(a=>String(a).trim()).filter(Boolean),o=Kr(n).filter(a=>a!=="*"),s=[];for(let a of r){let l=Ee(a);if(!l)throw new Error(`Invalid Telegram allow entry: ${a}`);s.push(l)}let i=$();i.allowFrom=o.sort(),i.telegramAllowFrom=[...new Set(s)].sort(),_e(i)}function Ub(e){return typeof e=="string"?e:typeof e=="boolean"||typeof e=="number"?String(e):JSON.stringify(e)}async function gm(e){let t=Ob(),{meta:n}=e;hm(e.port);let r=Eb.createServer(async(o,s)=>{try{let i=new URL(o.url??"/",`http://${o.headers.host??"localhost"}`),a=i.pathname;if(o.method==="GET"&&a==="/"){let m=i.searchParams.get("token")?.trim();if(m&&m===n.token){let f=ja(n.secret);s.statusCode=302,s.setHeader("Location","/"),s.setHeader("Set-Cookie",Ga(f)),s.end();return}}if(a.startsWith("/api/")){let m=o.headers.cookie,f=um(n.secret,m);if(o.method==="POST"&&a==="/api/session"){let h=await qa(o),g=typeof h?.token=="string"?h.token.trim():"";if(!g||g!==n.token){s.statusCode=401,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"Invalid token."}));return}let y=ja(n.secret);s.statusCode=200,s.setHeader("Content-Type",ae),s.setHeader("Set-Cookie",Ga(y)),s.end(JSON.stringify({ok:!0}));return}if(o.method==="GET"&&a==="/api/me"){s.statusCode=f?200:401,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:f}));return}if(!f){s.statusCode=401,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"Unauthorized."}));return}if(o.method==="GET"&&a==="/api/status"){s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,...Fb()}));return}if(o.method==="GET"&&a==="/api/config"){s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,config:Ya($())}));return}if(o.method==="PUT"&&a==="/api/config"){let h=await qa(o);if(!h||typeof h!="object"){s.statusCode=400,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"Expected JSON object."}));return}let g=h;for(let[y,b]of Object.entries(g))if(b!==void 0&&!(y==="allowFrom"||y==="telegramAllowFrom")){if(y==="telegramBotToken"){let v=typeof b=="string"?b.trim():"";if(!v||v==="(set)"||v.includes("\u2026"))continue;if(!pt(v))throw new Error("Invalid Telegram bot token format.");ho("telegramBotToken",v);continue}if(!_b(y))throw new Error(`Unknown or unsupported config key: ${y}`);ho(y,Ub(b))}if("allowFrom"in g||"telegramAllowFrom"in g){let y=$();Wb("allowFrom"in g?g.allowFrom:y.allowFrom,"telegramAllowFrom"in g?g.telegramAllowFrom:y.telegramAllowFrom)}s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,config:Ya($())}));return}if(o.method==="POST"&&a==="/api/logout"){s.statusCode=200,s.setHeader("Content-Type",ae),s.setHeader("Set-Cookie",dm()),s.end(JSON.stringify({ok:!0}));return}if(o.method==="POST"&&a==="/api/shutdown"){s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0})),setImmediate(()=>{Fr.requestCancel(),Ib()});return}if(o.method==="POST"&&a==="/api/gateway/start"){if(Ws()){s.statusCode=409,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"Gateway already appears to be running (pidfile + live process). Stop it first if you need to restart."}));return}let h=Ps();if(!h.ok){s.statusCode=400,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:h.message}));return}let g=Ne,y=Xo(g);if(!y.ok){s.statusCode=500,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:y.message}));return}s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,pid:y.pid,logFile:g}));return}if(o.method==="POST"&&a==="/api/gateway/stop"){let h=Zo();switch(h.outcome){case"no_pidfile":s.statusCode=400,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"No gateway pidfile \u2014 background gateway does not appear to be running."}));return;case"invalid_pidfile":s.statusCode=400,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"Invalid pidfile (removed)."}));return;case"stale_cleaned":s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,stale:!0,pid:h.pid,message:"Process was not running; stale pidfile removed."}));return;case"sent_signal":s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,pid:h.pid}));return;case"taskkill_ok":s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0,pid:h.pid,taskkill:!0}));return;case"failed":s.statusCode=500,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:h.message}));return}}if(o.method==="GET"&&a==="/api/wa/link/events"){s.writeHead(200,{"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-store",Connection:"keep-alive"}),s.write(`: connected
|
|
352
352
|
|
|
353
|
-
`);let h=
|
|
353
|
+
`);let h=Fr.subscribe(g=>{s.write(`data: ${JSON.stringify(g)}
|
|
354
354
|
|
|
355
|
-
`)});o.on("close",()=>{h()});return}if(o.method==="POST"&&a==="/api/wa/link/start"){let g=(await
|
|
356
|
-
`;return new Promise(o=>{let s=!1,i="";function a(d){s||(s=!0,o(d))}let l=
|
|
357
|
-
`);if(u>=0){let c=i.slice(0,u).trim();try{let m=JSON.parse(c);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.")})})}qe();function
|
|
358
|
-
`)}G();var
|
|
359
|
-
`))}function
|
|
360
|
-
`)}:{error:null,kind:"text",recipientsSent:c.size+m.size}}let n=oe(
|
|
361
|
-
`)};let d=i.size+a.size,u=s.length;return{error:null,kind:"media",recipientsSent:d,filesSent:u,messagesSent:d*u}}async function
|
|
362
|
-
`+
|
|
363
|
-
`)));return}if(e.kind==="texts"){for(let n=0;n<e.bodies.length;n++){let r=ke(e.bodies[n],"whatsapp").text;r.trim()&&(n>0&&console.log(""),console.log(r))}return}let t=ke(e.body,"whatsapp").text;t.trim()&&console.log(t)}async function
|
|
355
|
+
`)});o.on("close",()=>{h()});return}if(o.method==="POST"&&a==="/api/wa/link/start"){let g=(await qa(o))?.force===!0;try{Fr.beginPairing({force:g})}catch(y){let b=String(y),v=b.includes("already in progress")||b.includes("Gateway appears")?409:400;s.statusCode=v,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:b}));return}s.statusCode=202,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0}));return}if(o.method==="POST"&&a==="/api/wa/link/cancel"){Fr.requestCancel(),s.statusCode=200,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!0}));return}s.statusCode=404,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:"Not found."}));return}let l=a==="/"?"index.html":a.replace(/^\/+/,""),d=Nb(t,l),u=Ae.join(t,"index.html");d&&Zt.existsSync(d)&&Zt.statSync(d).isFile()&&(u=d);let c=Zt.readFileSync(u);s.statusCode=200,s.setHeader("Content-Type",Lb(u)),s.setHeader("Cache-Control",Ae.basename(u)==="index.html"?"no-store":"public, max-age=3600"),s.end(c)}catch(i){s.statusCode=500,s.setHeader("Content-Type",ae),s.end(JSON.stringify({ok:!1,error:String(i)}))}});await new Promise((o,s)=>{r.once("error",s),r.listen(e.port,e.host,()=>o())}),Wr=r,fm({pid:at.pid,port:e.port,host:e.host,startedAt:new Date().toISOString()}),r.on("close",()=>{_r(),Wr===r&&(Wr=null)})}function ym(e){let t=Ab.networkInterfaces(),n=[];for(let r of Object.values(t))if(r)for(let o of r)o.family==="IPv4"&&!o.internal&&n.push(`http://${o.address}:${e}/`);return[...new Set(n)].sort()}import Jb from"node:readline";import bm from"node:path";import Te from"node:process";me();qe();G();import Db from"node:net";import Hb from"node:fs";function Bb(){try{let e=Hb.readFileSync(kn,"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 Ur(e){let t=Bb();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)}
|
|
356
|
+
`;return new Promise(o=>{let s=!1,i="";function a(d){s||(s=!0,o(d))}let l=Db.connect({host:t.host,port:t.port},()=>{l.write(r)});l.setTimeout(6e5),l.on("data",d=>{i+=d.toString("utf8");let u=i.indexOf(`
|
|
357
|
+
`);if(u>=0){let c=i.slice(0,u).trim();try{let m=JSON.parse(c);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.")})})}qe();function Qa(e){return e.channel==="all"||e.channel==="whatsapp-all"||e.channel==="telegram-all"}function jb(e){let t=e.trimStart();if(/^--text=/i.test(t)){let n=t.slice(t.indexOf("=")+1).trimEnd();return n.length>0?n:null}if(/^--text(\s+|$)/i.test(t)){let n=t.replace(/^--text\s*/i,"").trim();return n.length>0?n:null}if(/^-t=/i.test(t)){let n=t.slice(t.indexOf("=")+1).trimEnd();return n.length>0?n:null}if(/^-t(\s+|$)/i.test(t)){let n=t.replace(/^-t\s*/i,"").trim();return n.length>0?n:null}}function Gb(e){let t=e.toLowerCase();if(t==="*"||t==="all")return{channel:"all"};if(t==="wa"||t==="whatsapp"||t==="wa:all"||t==="whatsapp:all")return{channel:"whatsapp-all"};if(t==="tg"||t==="telegram"||t==="tg:all"||t==="telegram:all")return{channel:"telegram-all"};if(t.startsWith("tg:")||t.startsWith("telegram:")){let n=Ee(e);if(!n)return null;let r=Number(n);return Number.isFinite(r)?{channel:"telegram",chatId:r}:null}if(t.startsWith("wa:")){let n=e.slice(3).trim();if(!n)return null;let r=n.split(",").map(o=>ee(o.trim())).filter(o=>!!o);return r.length===0?null:{channel:"whatsapp",e164s:r}}if(e.includes(",")){let n=e.split(",").map(r=>ee(r.trim())).filter(r=>!!r);return n.length===0?null:{channel:"whatsapp",e164s:n}}if(e.startsWith("+")){let n=ee(e);return n?{channel:"whatsapp",e164s:[n]}:null}return null}function wm(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=Gb(o);if(!i)return null;let a=jb(s);if(a===null)return null;if(a!==void 0)return{...i,mode:"text",body:a};let l=ws(s);if(!l)return null;let{selectorPart:d,caption:u}=l;return{...i,mode:"media",selectorPart:d,caption:u}}function Va(){return["/sendto wa|tg|* <selectors> [-- caption]","/sendto +E164 or +E164,+E164 <selectors> [-- caption]","/sendto <dest> --text <message> or --text=<msg> or -t <msg>","/sendto tg:<chat_id> <selectors> [-- caption] (compat: single Telegram id)","selectors: file1,file2 or *.mp4 or **/*.mp4 (from current session cwd); a path ./--text sends a file named --text","examples: /sendto wa ./promo.mp4 | /sendto * **/*.mp4 -- Daily clips","examples: /sendto +15551234567 --text Hello | /sendto tg:123 -t=Status OK","examples: /sendto +15550000001,+15550000002 intro.png,deck.pdf -- Launch","Also supports compat aliases: wa:all, whatsapp:all, tg:all, telegram:all.","Requires `omnish run` on this machine."].join(`
|
|
358
|
+
`)}Cr();it();G();var nr="wa:cli:interactive",Kb={onPlainTextLlmFallback(e,t){Wn($(),e,t,async n=>{n.trim()&&console.log(B(Te.stdout,n))})}};function zb(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let s=Ee(t);return s?`tg:${s}`:null}let r=n.startsWith("wa:")?t.slice(3):t,o=ee(r);return o?`wa:${o}`:null}function qb(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=zb(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 Xa(e){let t=Te.cwd(),n=[`${ue(e,"omnish i")} ${w(e,"[options]")}`,V(e,"Interactive shell \u2014 same commands as WhatsApp/Telegram chat."),"",J(e,"Usage:"),` ${S(e,"omnish i [options]")}`,` ${S(e,"omnish interactive [options]")}`,"",J(e,"Options:"),...vt(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=>w(e,r)),"",`${w(e,"Trust:")} ${S(e,"Full local access like your shell; not gated by inbox allowlist.")}`,`${w(e,"Jobs:")} ${S(e,"/bg and /jobs apply only to this REPL session (not the gateway process).")}`,`${w(e,"Files:")} ${S(e,"Use /sendto for files or --text for plain messages through the gateway; plain /send needs a chat peer.")}`,`${w(e,"Gateway:")} ${S(e,"/reload and /updates require omnish run; /sendto requires omnish run for WA/TG delivery.")}`,"",Va(),"",`${w(e,"cwd:")} ${S(e,`session starts at ${t} (change with !cd or ${$().commandPrefix}cd).`)}`];console.log(n.join(`
|
|
359
|
+
`))}function km(e,t){let n=new Set,r=new Set;if(e.channel==="whatsapp-all"||e.channel==="all"){let o=new Set;for(let s of t.allowFrom){let i=ee(String(s));i&&!o.has(i)&&(o.add(i),n.add(i))}}if(e.channel==="telegram-all"||e.channel==="all")for(let o of t.telegramAllowFrom){let s=Ee(String(o));if(!s)continue;let i=Number(s);Number.isFinite(i)&&r.add(i)}if(e.channel==="whatsapp")for(let o of e.e164s)n.add(o);return e.channel==="telegram"&&r.add(e.chatId),{waTargets:n,tgTargets:r}}function Sm(e){let t="No recipients matched the requested /sendto destination.";return Qa(e)?se()?`${t} Check platform dashboard allowlists (or omnish platform status), or use explicit +E164 / tg:<id>.`:`${t} Set allowFrom / telegramAllowFrom in config.json, or use explicit +E164 / tg:<id>.`:t}async function Yb(e){let t=Qa(e)?await ca():$();if(e.mode==="text"){let{waTargets:c,tgTargets:m}=km(e,t);if(c.size===0&&m.size===0)return{error:Sm(e)};let f=[];for(let h of c){let g=await Ur({op:"sendText",channel:"whatsapp",e164:h,text:e.body});g&&f.push(`[wa:${h}] ${g}`)}for(let h of m){let g=await Ur({op:"sendText",channel:"telegram",chatId:h,text:e.body});g&&f.push(`[tg:${h}] ${g}`)}return f.length>0?{error:f.join(`
|
|
360
|
+
`)}:{error:null,kind:"text",recipientsSent:c.size+m.size}}let n=oe(nr).cwd,r=await Er(n,e.selectorPart);if(r.length===0)return{error:`No files matched: ${e.selectorPart}`};let o=await Pr(r);if(!o.ok)return{error:o.error};let s=r.map(c=>qt(c,t.fileSendMaxBytes));for(let c of s)if("error"in c)return{error:c.error};let{waTargets:i,tgTargets:a}=km(e,t);if(i.size===0&&a.size===0)return{error:Sm(e)};let l=[];for(let c of i)for(let m of s){if("error"in m)continue;let f=await Ur({op:"sendMedia",channel:"whatsapp",e164:c,absPath:m.absPath,caption:e.caption});f&&l.push(`[wa:${c}] ${m.displayName}: ${f}`)}for(let c of a)for(let m of s){if("error"in m)continue;let f=await Ur({op:"sendMedia",channel:"telegram",chatId:c,absPath:m.absPath,caption:e.caption});f&&l.push(`[tg:${c}] ${m.displayName}: ${f}`)}if(l.length>0)return{error:l.join(`
|
|
361
|
+
`)};let d=i.size+a.size,u=s.length;return{error:null,kind:"media",recipientsSent:d,filesSent:u,messagesSent:d*u}}async function Qb(e,t,n,r,o,s,i){let a=e.trim();if(!a)return;let l=wm(a);if(l!==null||/^\/sendto(\s|$)/i.test(a)){if(l===null){console.log(C(Te.stderr,`Invalid /sendto.
|
|
362
|
+
`+Va()));return}let c=await Yb(l);if(c.error!==null)console.log(C(Te.stderr,c.error));else if(c.kind==="text")console.log(B(Te.stdout,`Sent text to ${c.recipientsSent} recipient(s).`));else{let m=`Sent ${c.filesSent} file(s) to ${c.recipientsSent} recipient(s) (${c.messagesSent} message(s)).`;console.log(B(Te.stdout,m))}return}let d={peerKey:nr,text:e},u=await tr($(),t,n,r,o,d,s,void 0,i,!1,Kb);u!==null&&await Vb(u)}async function Vb(e){if(e===null)return;if(e.kind==="file"||e.kind==="files"){console.log(B(Te.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(`
|
|
363
|
+
`)));return}if(e.kind==="texts"){for(let n=0;n<e.bodies.length;n++){let r=ke(e.bodies[n],"whatsapp").text;r.trim()&&(n>0&&console.log(""),console.log(r))}return}let t=ke(e.body,"whatsapp").text;t.trim()&&console.log(t)}async function vm(e){let t=qb(e);if(t.error==="help"){Xa(Te.stdout);return}if(t.error&&t.error!==null){console.error(C(Te.stderr,t.error)),console.error(w(Te.stderr,"Try: omnish i --help")),Te.exitCode=1;return}let{senderKey:n,oneShot:r}=t.opts,o=n??nr;te(),ao(nr,Te.cwd());let s=new Et,i=new Map,a=new Map,l=new Map,d=new zt(()=>$(),async(f,h)=>{Te.stdout.write(h),h.endsWith(`
|
|
364
364
|
`)||Te.stdout.write(`
|
|
365
|
-
`)}),u=async f=>{try{await
|
|
366
|
-
`)}),c.prompt()}
|
|
367
|
-
`))}function
|
|
368
|
-
`))}function
|
|
369
|
-
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
|
|
370
|
-
`))}function
|
|
371
|
-
`))}function
|
|
372
|
-
Script: ${o.scriptPath}`,u=$().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(Ce(t,"omnish service status")),console.log(""),console.log(`${w(t,"platform:")} ${S(t,process.platform)}`),console.log(`${w(t,"session:")} ${S(t,i)}`),console.log(`${w(t,"env:")} ${S(t,a)}`),console.log(`${w(t,"data dir:")} ${S(t,H)}`),console.log(`${w(t,"pidfile:")} ${S(t,s)}`),console.log(`${w(t,"default log:")} ${S(t,Ne)}`),console.log(""),console.log(l),console.log(""),console.log(S(t,u));return}if(r==="logs"){let o=e.length>=2?Number.parseInt(e[1],10):80,s=Number.isFinite(o)&&o>0?Math.min(o,
|
|
373
|
-
`),console.warn(
|
|
374
|
-
`,{mode:384})}catch(k){
|
|
375
|
-
`),Q=
|
|
365
|
+
`)}),u=async f=>{try{await Qb(f,s,i,a,l,d,o)}catch(h){console.error(C(Te.stderr,String(h)))}};if(r!==null){await u(r),d.dispose(),s.killAllRunning();return}let c=Jb.createInterface({input:Te.stdin,output:Te.stdout}),m=bm.basename(oe(nr).cwd);c.setPrompt(`${m}> `),c.on("line",f=>{u(f).then(()=>{let h=bm.basename(oe(nr).cwd);c.setPrompt(`${h}> `),c.prompt()})}),c.on("close",()=>{d.dispose(),s.killAllRunning(),Te.stdout.write(`
|
|
366
|
+
`)}),c.prompt()}Xb.setDefaultResultOrder("ipv4first");function Rm(){let e=process.stdout,t=[`${Ce(e,"omnish run")} ${w(e,"[options]")}`,V(e,"Listen for DMs and run shell commands from allowlisted chats."),"",J(e,"Usage:"),` ${S(e,"omnish run [options]")}`,"",J(e,"Options:"),...vt(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: ${Ne}).`},{left:"-vb, --verbose",right:"Baileys/gateway debug logs on stderr (legacy: OMNISH_VERBOSE=1)."},{left:"-h, --help",right:"Show this help."}],r=>w(e,r)),"",`${S(e,"Config reload:")} ${w(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).")}`,""],n=se();n?t.push(J(e,"Attached mode (platform credentials detected):"),` ${w(e,"url:")} ${S(e,n.platformUrl)} ${V(e,`[${qn()}]`)}`,` ${w(e,"token:")} ${S(e,sn("platformToken",n.token))} ${V(e,`[${zn()}]`)}`,w(e," Messengers run on the platform; allowlist is set on the dashboard. Run: omnish platform probe"),""):t.push(w(e,"Platform attached mode: omnish config add platform_url <url> platform_token <token>"),w(e," then omnish platform probe && omnish run \u2014 see omnish help platform"),""),console.log(t.join(`
|
|
367
|
+
`))}function Cm(){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=>w(e,i.left)),r=Math.max(...n.map(co)),o=t.map((i,a)=>ni(" ",r,n[a],S(e,i.right))),s=[`${Ce(e,"omnish link")} ${w(e,"[options]")}`,V(e,"Connect WhatsApp (QR) or save a Telegram bot token."),"",J(e,"Usage:"),` ${S(e,"omnish link [--force]")}`,` ${S(e,"omnish link --tg <bot_token>")}`,"",J(e,"Modes:"),...o,` ${V(e,"Do not combine --tg with --force.")}`,"",J(e,"Options:"),...vt(e," ",[{left:"-f, --force",right:"WhatsApp only: delete saved session before pairing."},{left:"-vb, --verbose",right:"Baileys debug logs on stderr during pairing (legacy: OMNISH_VERBOSE=1)."},{left:"-h, --help",right:"Show this help."}],i=>w(e,i)),"",`${S(e,"Next:")} ${ue(e,"omnish allow tg:<your_user_id>")} ${w(e,"then")} ${ue(e,"omnish run")}`,`${w(e,"Config:")} ${S(e,_)}`,""];se()&&s.push(J(e,"Platform attached mode:"),w(e," omnish link on this host is for standalone only. Link WhatsApp on the platform dashboard or:"),` ${S(e,"omnish platform import-whatsapp")} ${w(e,"(after a local omnish link, with omnish run stopped)")}`,w(e," Telegram: set bot token on the platform dashboard, not --tg here."),""),console.log(s.join(`
|
|
368
|
+
`))}function ek(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==="-vb"||o==="--verbose"){js(!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}
|
|
369
|
+
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 el(){let e=process.stdout,t=`${Ce(e,"omnish")} ${w(e,`v${Ze()}`)}`,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: ${ce})`},{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)"},{left:"ui [options]",right:"Browser setup UI on LAN (token-gated) \u2014 omnish ui --help"},{left:"config <add|show|edit|delete>",right:"Manage config.json (platform URL/token, tunnel, gateway) \u2014 omnish config help"},{left:"platform <subcommand>",right:"Attached mode: configure, probe, import WA \u2014 omnish help platform"},{left:"tunnel <subcommand>",right:"Expose local HTTP/TCP via omnish relay \u2014 omnish tunnel help"}],r=[{left:"-v, --version",right:"Print version and exit."},{left:"-h, --help",right:"Show this help (same as omnish help)."}],o=[t,V(e,"Allowlisted inbox \u2192 your real shell. No AI."),"",J(e,"Usage:"),` ${S(e,"omnish [options] <command> [args...]")}`,"",J(e,"Options:"),...vt(e," ",r,s=>w(e,s)),"",J(e,"Commands:"),...vt(e," ",n,s=>w(e,s)),"",`${w(e,"Config:")} ${S(e,`${_} \u2014 gatewayMode: "whatsapp" | "telegram" | "both"`)}`,`${w(e,"Platform:")} ${S(e,"platform_url + platform_token \u2192 attached omnish run (omnish help platform)")}`,`${w(e,"Verbose:")} ${S(e,"omnish run --verbose (legacy: OMNISH_VERBOSE=1, WHATSVERBOSE=1)")}`,`${w(e,"Env:")} ${S(e,"TELEGRAM_BOT_TOKEN (optional override)")}`,`${w(e,"Data:")} ${S(e,"~/.omnish by default; ~/.whatslive reused if it already exists. OMNISH_HOME overrides.")}`,`${w(e,"See also:")} ${S(e,"https://omnish.dev")}`,""];console.log(o.join(`
|
|
370
|
+
`))}function tk(e){let t=(e??"").trim().toLowerCase(),n=process.stdout;if(!t){el();return}switch(t){case"link":Cm();return;case"run":Rm();return;case"service":Tm();return;case"i":case"interactive":Xa(n);return;case"ui":Em();return;case"config":Is(n);return;case"platform":_s(n);return;default:console.error(C(process.stderr,`No detailed help for "${e}". Try: omnish help`)),process.exitCode=1}}function nk(e){let t=!1,n="",r=!1,o=!1;for(let i=0;i<e.length;i++){let a=e[i]??"";if(a==="-d"||a==="--background")t=!0;else if(a==="-vb"||a==="--verbose")o=!0;else if(a==="--log-file"||a==="--log"){let l=e[++i];l||(console.error(C(process.stderr,"--log-file requires a path.")),process.exit(1)),n=l}else if(a==="--help"||a==="-h")r=!0;else{let l=process.stderr;console.error(C(l,`unknown run option: ${a}`)),console.error(C(l,"Try: omnish run --help")),process.exit(1)}}let s=n.trim()!==""?Za.isAbsolute(n)?n:Za.resolve(process.cwd(),n):Ne;return{background:t,logFile:s,help:r,verbose:o}}function rk(e,t){let n=Xo(e,{verbose:t});n.ok||(console.error(C(process.stderr,n.message)),process.exit(1));let r=process.stdout;console.log(`${B(r,`gateway started in background (pid ${n.pid}).`)} ${w(r,`Log: ${e}`)}`)}function ok(){let e=Zo();switch(e.outcome){case"no_pidfile":console.error(C(process.stderr,`no pidfile at ${ce} \u2014 is a background gateway running?`)),process.exitCode=1;return;case"invalid_pidfile":console.error(C(process.stderr,"invalid pidfile.")),process.exitCode=1;return;case"stale_cleaned":console.log(B(process.stdout,`process ${e.pid} is not running; removing stale pidfile.`));return;case"sent_signal":console.log(B(process.stdout,`sent SIGTERM to gateway (pid ${e.pid}).`));return;case"taskkill_ok":console.log(B(process.stdout,`stopped gateway (pid ${e.pid}) using taskkill.`));return;case"failed":console.error(C(process.stderr,e.message)),process.exitCode=1;return}}function xm(){if(process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{en.readFileSync(ce,"utf8").trim()===String(process.pid)&&en.unlinkSync(ce)}catch{}}function sk(e){return e.length<=8?"(set)":`${e.slice(0,4)}\u2026${e.slice(-4)}`}function ik(){if(!en.existsSync(ce))return"gateway process: not running (no pid file)";let e=en.readFileSync(ce,"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 Mm=120;function Tm(){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 ${Mm}).`},{left:"install",right:"Write user systemd / LaunchAgent unit (needs serviceInstallFromChat=true)."},{left:"uninstall",right:"Remove that unit (same gate as install)."}],n=[`${Ce(e,"omnish service")} ${w(e,"<subcommand>")}`,V(e,"Boot integration, crash restart policy, and logs (same ideas as /service in chat)."),"",J(e,"Usage:"),` ${S(e,"omnish service <subcommand>")}`,"",J(e,"Subcommands:"),...vt(e," ",t,r=>w(e,r)),"",J(e,"Restart and reload:"),` ${S(e,"Process")} ${w(e,"\u2014 Linux user unit: Restart=on-failure, RestartSec=5. macOS: KeepAlive. Full restart loads config from disk.")}`,` ${S(e,"Config live")} ${w(e,"\u2014 allowlisted chat while gateway runs: /reload or /restart")}`,"",`${w(e,"Docs:")} ${S(e,"docs/guides/background-and-boot.md")} ${V(e,"\xB7")} https://omnish.dev`,""];console.log(n.join(`
|
|
371
|
+
`))}function ak(e){let t=process.stdout,n=process.stderr,r=(e[0]??"help").toLowerCase();if(r==="help"||r==="--help"||r==="-h"){Tm();return}if(r==="instructions"){let o=an();if(o.error){console.error(C(n,o.error)),process.exitCode=1;return}console.log(wo(o));return}if(r==="status"){let o=an(),s=(()=>{try{return en.existsSync(ce)?`gateway.pid: ${en.readFileSync(ce,"utf8").trim()}`:"gateway.pid: (missing)"}catch(c){return`gateway.pid: (read error: ${String(c)})`}})(),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}
|
|
372
|
+
Script: ${o.scriptPath}`,u=$().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(Ce(t,"omnish service status")),console.log(""),console.log(`${w(t,"platform:")} ${S(t,process.platform)}`),console.log(`${w(t,"session:")} ${S(t,i)}`),console.log(`${w(t,"env:")} ${S(t,a)}`),console.log(`${w(t,"data dir:")} ${S(t,H)}`),console.log(`${w(t,"pidfile:")} ${S(t,s)}`),console.log(`${w(t,"default log:")} ${S(t,Ne)}`),console.log(""),console.log(l),console.log(""),console.log(S(t,u));return}if(r==="logs"){let o=e.length>=2?Number.parseInt(e[1],10):80,s=Number.isFinite(o)&&o>0?Math.min(o,Mm):80,i=vo(Ne,s);console.log(`${w(t,"file:")} ${S(t,Ne)}`),console.log(`${w(t,"lines:")} ${S(t,String(s))}`),console.log(""),console.log(i);return}if(r==="install"){if(!$().serviceInstallFromChat){console.error(C(n,"Install is disabled. Set serviceInstallFromChat to true in config (same trust as shell), then run again.")),process.exitCode=1;return}let s=bo();s.ok?console.log(B(t,s.detail)):(console.error(C(n,s.detail)),process.exitCode=1);return}if(r==="uninstall"){if(!$().serviceInstallFromChat){console.error(C(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=ko();s.ok?console.log(B(t,s.detail)):(console.error(C(n,s.detail)),process.exitCode=1);return}console.error(C(n,`Unknown subcommand "${r}". Try: omnish service help`)),process.exitCode=1}function lk(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let s=Ee(t);return s?`tg:${s}`:null}let r=n.startsWith("wa:")?t.slice(3):t,o=ee(r);return o?`wa:${o}`:null}async function ck(){let e=null,t=Ps();t.ok||(console.error(C(process.stderr,t.message)),process.exit(1));let n=se();if(n){await Wp(n);return}let r=$(),o=r.gatewayMode,s=o==="whatsapp"||o==="both",i=o==="telegram"||o==="both",a=ve(r),l=Ct(r),d=process.stderr,u=oc(l,"warn");if(u.length>0&&(console.warn(`${B(d,`Security (${u.length} finding(s)):`)}
|
|
373
|
+
`),console.warn(ai(u,d))),process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{en.writeFileSync(ce,`${process.pid}
|
|
374
|
+
`,{mode:384})}catch(k){M.warn({err:String(k)},"could not write gateway pidfile")}let c=(k,x)=>{let L=$();if(!L.clusterEnabled)return k;let F=Xe(),Q=(L.clusterLabel??"").trim()||$m.hostname(),z=null;if(x.startsWith("tg:"))z=x;else if(x){let Ue=ee(x);Ue&&(z=`wa:${Ue}`)}let we=z?Mt(L,z):null;return Kc(k,{nodeId:F,label:Q,role:L.clusterRole,activeNodeId:we?.nodeId??""})},m=new Et,f=new Map,h=new Map,g=new Map,y=null,b={stop:null,sendText:null,sendMedia:null},v=null,E=!1,R=async(k,x)=>{if(k.startsWith("wa:")){let L=k.slice(3);y&&await y.sendText(L,x)}else if(k.startsWith("tg:")){let L=Number(k.slice(3));b.sendText&&Number.isFinite(L)&&await b.sendText(L,p(x))}},P={onPlainTextLlmFallback(k,x){Wn($(),k,x,L=>R(k,L))},sendToPeer:R},T=async(k,x)=>{if(k.startsWith("wa:")){let L=k.slice(3);y&&await y.sendMedia(L,x)}else if(k.startsWith("tg:")){let L=Number(k.slice(3));b.sendMedia&&Number.isFinite(L)&&await b.sendMedia(L,x)}},O=()=>new zt(()=>$(),R),A=O();v=A;let K,X={async reload(){try{M.info("gateway reload requested from chat"),await b.stop?.().catch(()=>{}),b.stop=null,b.sendText=null,b.sendMedia=null;let k=$(),x=k.gatewayMode==="telegram"||k.gatewayMode==="both",L=ve(k);if(x&&L){let z=await Vi(L,()=>$(),K,{decorate:c});b.sendText=z.sendText,b.sendMedia=z.sendMedia,b.stop=z.stop}let F=["Reload complete.",`gatewayMode: ${k.gatewayMode}`,x&&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(`
|
|
375
|
+
`),Q=gs(Mr());return{ok:!0,summary:Q?`${F}
|
|
376
376
|
|
|
377
|
-
Updates (last check): ${Q}`:F}}catch(k){return{ok:!1,error:String(k)}}}};if(K=async(k,x)=>{let
|
|
378
|
-
${C(process.stderr,"shutting down\u2026")}`),process.exit(0)};if(process.on("SIGINT",Y),process.on("SIGTERM",Y),s)for(;!E;){let k=!1,x;try{x=await
|
|
379
|
-
`))}async function
|
|
380
|
-
`));return}await
|
|
381
|
-
`)),o){let h=await
|
|
377
|
+
Updates (last check): ${Q}`:F}}catch(k){return{ok:!1,error:String(k)}}}};if(K=async(k,x)=>{let L=$();await Nr(L,m,f,h,g,k,A,X,k.peerKey,P,_a({sendTg:x},{surface:"telegram"}),{surface:"telegram"})},i){let k=await Vi(a,()=>$(),K,{decorate:c});b.sendText=k.sendText,b.sendMedia=k.sendMedia,b.stop=k.stop}ns({getCfg:()=>$(),getWaOutbound:()=>y,getTgSendMedia:()=>b.sendMedia,getTgSendText:()=>b.sendText});let ie=null;{let k=$();if(k.webhookEnabled){let x=k.webhookToken||Zb.randomBytes(32).toString("hex");k.webhookToken||W({webhookToken:x}),ie=rs({port:k.webhookPort,host:k.webhookHost,token:x},{sendToPeer:R,getDefaultPeerKey:()=>{let F=$();return F.allowFrom.length>0?`wa:${Lt(F.allowFrom[0])}`:F.telegramAllowFrom.length>0?`tg:${F.telegramAllowFrom[0]}`:null}}).stop}}e=ys({getRunningVersion:Ze,getConfig:$,log:M});let he=jo({getConfig:$,sendToPeer:R,sendMediaToPeer:T}),D=io({getConfig:$,sendToPeer:R}),le=!i,Y=()=>{E=!0,he(),D(),e?.(),e=null,ie?.(),xm(),Kn(),b.stop?.().catch(()=>{}),v?.dispose(),m.killAllRunning(),gn().stopAll().catch(()=>{}),console.error(`
|
|
378
|
+
${C(process.stderr,"shutting down\u2026")}`),process.exit(0)};if(process.on("SIGINT",Y),process.on("SIGTERM",Y),s)for(;!E;){let k=!1,x;try{x=await zo({printQr:!1,verbose:vn()}),await fn(qo(x),3e5,"Gateway: timed out waiting for WhatsApp connection (5 min).")}catch(F){console.error(C(process.stderr,`connect failed: ${String(F)}`)),await new Promise(Q=>setTimeout(Q,5e3));continue}y=sd(x,{decorate:c});let L=Zu(x,async F=>{let Q=$(),z=F.fromE164||ee(F.fromJid)||"",we=iu(F),Ue=`wa:${z}`;await Nr(Q,m,f,h,g,we,A,X,Ue,P,_a({sendWaText:(Ie,pe)=>y.sendText(Ie,pe),sendWaMedia:(Ie,pe)=>y.sendMedia(Ie,pe)},{surface:"whatsapp",waJid:F.fromJid}),{surface:"whatsapp"})});if(await new Promise(F=>{let Q=z=>{z.connection==="close"&&(qi(z.lastDisconnect)===mn.loggedOut&&(k=!0),x.ev.off("connection.update",Q),F())};x.ev.on("connection.update",Q)}),L(),le&&(A.dispose(),A=O(),v=A),jn(x),y=null,k&&(console.error(C(process.stderr,"session logged out. Run `omnish link` again.")),he(),e?.(),e=null,xm(),Kn(),b.stop?.().catch(()=>{}),process.exit(1)),E)break;await new Promise(F=>setTimeout(F,3e3))}else for(;!E;)await new Promise(k=>setTimeout(k,500));he(),e?.(),Kn(),b.stop?.().catch(()=>{}),A.dispose()}function uk(e){let t=!1,n="0.0.0.0",r=3789,o;for(let s=0;s<e.length;s++){let i=e[s];if(i==="--help"||i==="-h"){t=!0;continue}if(i==="--host"||i==="-H"){let l=e[++s];l||(console.error(C(process.stderr,"--host requires an address (e.g. 127.0.0.1).")),process.exit(1)),n=l;continue}if(i==="--port"||i==="-p"){let l=e[++s],d=Number.parseInt(l??"",10);Number.isFinite(d)||(console.error(C(process.stderr,"--port requires a number.")),process.exit(1)),r=d;continue}if(i==="--token"||i==="-t"){let l=e[++s];(!l||l.startsWith("-"))&&(console.error(C(process.stderr,"--token requires a secret string.")),process.exit(1)),o=l;continue}let a=process.stderr;console.error(C(a,`unknown ui argument: ${i}`)),console.error(C(a,"Try: omnish ui --help")),process.exit(1)}return{help:t,host:n,port:r,token:o}}function Em(){let e=process.stdout,t=[`${Ce(e,"omnish ui")} ${w(e,"[options]")}`,V(e,"Serve the browser setup panel on your LAN (token-gated). Same trust as editing config on disk."),"",J(e,"Usage:"),` ${S(e,"omnish ui [options]")}`,"",J(e,"Options:"),...vt(e," ",[{left:"--host <addr>",right:"Bind address (default 0.0.0.0 \u2014 reachable on LAN). Use 127.0.0.1 for loopback only."},{left:"--port <n>",right:"TCP port (default 3789)."},{left:"--token <secret>",right:`Set or rotate setup token (saved to ${ut}).`},{left:"-h, --help",right:"This help."}],n=>w(e,n)),"",`${w(e,"Warning:")} ${fe(e,"Listening on all interfaces exposes a remote control panel on your network \u2014 use a trusted LAN.")}`,""];console.log(t.join(`
|
|
379
|
+
`))}async function dk(){let[,,e,...t]=process.argv;if(e==="--version"||e==="-v"||e==="-V"){let n=process.stdout;console.log(`${Ce(n,"omnish")} ${w(n,Ze())}`);return}if(e==="--help"||e==="-h"){el();return}if(e==="help"){tk(t[0]);return}switch(te(),e){case"link":{let n=ek(t);if(n.kind==="help"){Cm();return}if(n.kind==="error"){let r=process.stderr,o=n.message.replace(/^\[omnish\]\s*/,"");console.error(C(r,o)),process.exitCode=1;return}if(n.kind==="tg"){let r=n.token.trim(),o=process.stderr,s=process.stdout;if(!pt(r)){console.error(C(o,"That does not look like a Telegram bot token (expect digits:secret from @BotFather).")),process.exitCode=1;return}Nt(r);let i=nt()?"both":"telegram";Xr(i),console.log([`${ue(s,"Telegram")} ${S(s,"bot token saved to")} ${w(s,_)}`,`${w(s,"gatewayMode:")} ${ue(s,i)}`,"",S(s,"Next:"),` ${w(s,"1.")} ${S(s,"Find your numeric user id (e.g. t.me/userinfobot), then:")} ${ue(s,"omnish allow tg:<id>")}`,` ${w(s,"2.")} ${ue(s,"omnish run")}`,""].join(`
|
|
380
|
+
`));return}await pd({verbose:vn(),force:n.force});return}case"run":{let n=nk(t);if(n.help){Rm();return}if(n.verbose&&js(!0),n.background){rk(n.logFile,n.verbose);return}await ck();return}case"stop":ok();return;case"logout":{try{en.rmSync(ne,{recursive:!0,force:!0}),console.log(B(process.stdout,"Session removed. Run `omnish link` to pair again."))}catch(n){console.error(C(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(C(o,"Usage: omnish allow +<E164> or omnish allow tg:<user_id>")),process.exitCode=1;return}try{let s=Qr(n);console.log(`${w(r,"allowFrom:")} ${S(r,s.allowFrom.join(", ")||"(empty)")}`),console.log(`${w(r,"telegramAllowFrom:")} ${S(r,s.telegramAllowFrom.join(", ")||"(empty)")}`)}catch(s){console.error(C(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(C(o,"Usage: omnish deny +<E164> or omnish deny tg:<user_id>")),process.exitCode=1;return}try{let s=Vr(n);console.log(`${w(r,"allowFrom:")} ${S(r,s.allowFrom.join(", ")||"(empty)")}`),console.log(`${w(r,"telegramAllowFrom:")} ${S(r,s.telegramAllowFrom.join(", ")||"(empty)")}`)}catch(s){console.error(C(o,String(s).replace(/^\[omnish\]\s*/,""))),process.exitCode=1}return}case"i":case"interactive":{await vm(t);return}case"status":{let n=process.stdout,r=$(),o=t.includes("--check-updates"),s=new Et().list(),i=s.filter(h=>h.status==="running").length,a=ve(r),l=Ct(r),d=r.gatewayMode==="whatsapp"||r.gatewayMode==="both",u=r.gatewayMode==="telegram"||r.gatewayMode==="both",c=nt(),m=c?cd(ne):null,f=[];if(f.push(`${Ce(n,"omnish")} ${w(n,Ze())}`,`${w(n,"gatewayMode:")} ${S(n,r.gatewayMode)}`,`${w(n,"data dir:")} ${S(n,Za.dirname(ne))}`,"",`${w(n,"gateway process:")} ${S(n,ik().replace(/^gateway process: /,""))}`,"",Bt(n),ue(n,"whatsapp"),` ${w(n,"in use:")} ${d?S(n,"yes"):fe(n,"no (gatewayMode is telegram-only)")}`),d){let h=c?S(n,`linked (${ne})`):fe(n,"missing \u2014 run omnish link");f.push(` ${w(n,"session:")} ${h}`),c&&m&&f.push(` ${w(n,"linked as:")} ${S(n,m)}`),c&&!m&&f.push(` ${w(n,"linked as:")} ${V(n,"(not in creds yet \u2014 try again after omnish link completes)")}`)}if(f.push(` ${J(n,"Allowed")}`),r.allowFrom.length===0)f.push(` ${V(n,"(none)")}`);else for(let h of r.allowFrom)f.push(` ${w(n,"whatsapp:")} ${S(n,h)}`);if(f.push("",Bt(n),ue(n,"telegram")),f.push(` ${w(n,"in use:")} ${u?S(n,"yes"):fe(n,"no (gatewayMode is whatsapp-only)")}`),u){let h=a?S(n,sk(a)):fe(n,"(none) \u2014 omnish link --tg <token> or TELEGRAM_BOT_TOKEN");f.push(` ${w(n,"bot token:")} ${h}`)}if(f.push(` ${J(n,"Allowed")}`),r.telegramAllowFrom.length===0)f.push(` ${V(n,"(none)")}`);else for(let h of r.telegramAllowFrom)f.push(` ${w(n,"telegram:")} ${S(n,h)}`);if(f.push("",Bt(n),...await Gp(n)),f.push("",Bt(n),`${ue(n,"jobs")} ${w(n,`(recent): ${s.length} total, ${i} running`)}`,ac(l,n)),console.log(f.join(`
|
|
381
|
+
`)),o){let h=await Tr(Ze(),r),g=pr(h);console.log(""),console.log(Bt(n)),console.log(ke(g,"whatsapp").text)}if(r.clusterEnabled){let h=Xe(),g=ge(),y=Object.keys(g.senderBindings).length,b=Object.keys(r.clusterSenderBindings??{}).length;console.log(""),console.log(Bt(n)),console.log(ue(n,"cluster")),console.log(` ${w(n,"\xB7")} ${S(n,`enabled \xB7 label ${r.clusterLabel||$m.hostname()} \xB7 bindings ${y} chat / ${b} default`)}`),console.log(` ${w(n,"node:")} ${S(n,`${h.slice(0,8)}\u2026`)}`)}return}case"commands":{let n=process.stdout,r=$();console.log(tc(Tn(r),n)),console.log(""),console.log(Bt(n)),console.log(S(n,"Keys editable from chat via /config set (same trust as shell):")),console.log(w(n,Gt.join(", "))),console.log(`${w(n,"See also:")} ${S(n,_)}`);return}case"cluster":{let n=process.stdout,r=process.stderr,o=(t[0]??"status").toLowerCase();if(o==="status"){let s=$(),i=Xe();if(console.log(`${w(n,"clusterEnabled:")} ${S(n,String(s.clusterEnabled))}`),console.log(`${w(n,"clusterLabel:")} ${S(n,s.clusterLabel||"(hostname)")}`),console.log(`${w(n,"clusterRole:")} ${S(n,`${s.clusterRole} (informational; no longer used to gate traffic)`)}`),console.log(`${w(n,"node id:")} ${ue(n,i)}`),s.clusterEnabled){let a=ge(),l=Ei(s,null);console.log(""),console.log(S(n,l.wa.replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1"))),console.log(""),console.log(Ti(a,s,null));let d=Object.keys(a.senderBindings).length,u=Object.entries(s.clusterSenderBindings??{});if(d>0){console.log(""),console.log(ue(n,"Chat bindings (cluster-local.json)"));for(let[c,m]of Object.entries(a.senderBindings))console.log(` ${w(n,c)} ${V(n,"->")} ${S(n,`${m.nodeId} (${m.source}, since ${m.sinceIso})`)}`)}if(u.length>0){console.log(""),console.log(ue(n,"Config defaults (clusterSenderBindings)"));for(let[c,m]of u)console.log(` ${w(n,c)} ${V(n,"->")} ${S(n,m)}`)}}else console.log(""),console.log(fe(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(C(r,"Usage: omnish cluster use <senderE164|tg:id> <label-or-id>")),process.exitCode=1;return}let a=lk(s);if(!a){console.error(C(r,`Could not parse sender "${s}". Use +E164 (WhatsApp) or tg:<user_id> (Telegram).`)),process.exitCode=1;return}let{state:l,resolved:d}=su(a,i);if(!d.ok){if(d.reason==="ambiguous-label"){let c=(d.matches??[]).map(m=>`${m.nodeId}(${m.label})`).join(", ");console.error(C(r,`Label "${i}" matches multiple machines: ${c}. Use the 8-character id.`))}else console.error(C(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(`${ue(n,"cluster:")} ${S(n,`${a} -> ${d.peer.nodeId} (${d.peer.label}).`)}`);let u=$();console.log(""),console.log(Ti(l,u,a));return}if(o==="here"){console.error(C(r,"omnish cluster here is no longer available. Use: omnish cluster use <senderE164|tg:id> <label-or-id>")),console.error(C(r,"Or send /c here from the controller's chat on the machine you want to bind.")),process.exitCode=1;return}console.error(C(r,"Usage: omnish cluster [status | use <sender> <label-or-id>]")),process.exitCode=1;return}case"security":{let n=$(),r=Ct(n),o=t.includes("--json");console.log(o?sc(r):ai(r,process.stdout)),dr(r)&&(process.exitCode=1);return}case"service":{ak(t);return}case"config":{await jp(t);return}case"tunnel":{await Ld(t);return}case"platform":{await rm(t);return}case"ui":{let n=uk(t);if(n.help){Em();return}if(!Number.isFinite(n.port)||n.port<1||n.port>65535){console.error(C(process.stderr,"port must be between 1 and 65535.")),process.exitCode=1;return}let r=lm(n.token);await gm({host:n.host,port:n.port,meta:r});let o=process.stdout,s=ym(n.port);console.log(""),console.log(`${Ce(o,"ui")} ${w(o,"listening")}`),console.log(`${w(o,"bind:")} ${S(o,`${n.host}:${n.port}`)}`),console.log(`${w(o,"setup token:")} ${S(o,r.token)}`),console.log(`${w(o,"token file:")} ${V(o,ut)}`),console.log(""),console.log(fe(o,"Anyone on your network who can reach this port needs the token \u2014 do not expose to untrusted Wi\u2011Fi.")),console.log(""),console.log(`${w(o,"Open:")}`),console.log(` ${S(o,`http://127.0.0.1:${n.port}/`)}`);for(let i of s)console.log(` ${S(o,i)}`);console.log(""),console.log(`${w(o,"Quick link (same Wi\u2011Fi):")} ${S(o,`http://127.0.0.1:${n.port}/?token=${encodeURIComponent(r.token)}`)}`),console.log("");return}default:el(),e&&(process.exitCode=1)}}dk().catch(e=>{console.error(C(process.stderr,String(e))),process.exit(1)});
|