omnish 1.3.0 → 1.4.1
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 +31 -0
- package/README.md +3 -2
- package/config.example.json +7 -1
- package/dist/index.js +255 -210
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,104 +1,130 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var dd=Object.defineProperty;var En=(e,t)=>()=>(e&&(t=e(e=0)),t);var pd=(e,t)=>{for(var n in t)dd(e,n,{get:t[n],enumerable:!0})};import md from"node:crypto";import Do from"node:fs";import fd from"node:os";import se from"node:path";function gd(){let e=process.env.OMNISH_HOME?.trim();if(e)return se.resolve(e);let t=fd.homedir(),n=se.join(t,".omnish"),r=se.join(t,".whatslive");try{if(Do.existsSync(n))return n;if(Do.existsSync(r))return r}catch{}return n}function An(e){let t=md.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return se.join(Di,t)}function W(e){Do.mkdirSync(e,{recursive:!0,mode:448})}function V(){W(U),W(X),W(We),W(Di),W(Hi),W(Xe)}var U,X,We,Di,Hi,Ce,ne,Qt,In,Ve,sr,ir,L,ar,lr,cr,Xe,Ho,Bo,Bi,j=En(()=>{"use strict";U=gd(),X=se.join(U,"auth"),We=se.join(U,"jobs"),Di=se.join(U,"apps"),Hi=se.join(U,"logs"),Ce=se.join(Hi,"gateway.log"),ne=se.join(U,"gateway.pid"),Qt=se.join(U,"gateway-control.json"),In=se.join(U,"config-ui.json"),Ve=se.join(U,"ui.json"),sr=se.join(U,"tunnel-auth.json"),ir=se.join(U,"ui-server.json"),L=se.join(U,"config.json"),ar=se.join(U,"shortcuts.json"),lr=se.join(U,"recipes.json"),cr=se.join(U,"recipes-user.json"),Xe=se.join(U,"cowork"),Ho=se.join(Xe,"tasks.json"),Bo=se.join(Xe,"pending-runs.json"),Bi=se.join(Xe,"completions.sqlite")});function zi(e){let t=e.trim();for(;;){let n=t;if(t=t.replace(/^whatsapp:/i,"").trim(),t===n)return t}}function hd(e){let t=zi(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 yd(e){let t=e.match(Wi);if(t)return t[1]??null;let n=e.match(Gi);if(n)return n[1]??null;let r=e.match(Ji);return r?r[1]??null:null}function ji(e){let t=e.replace(/\D/g,"");return t?`+${t}`:""}function Nt(e){return`${e.replace(/\D/g,"")}@s.whatsapp.net`}function q(e){let t=zi(e);if(!t||hd(t))return null;if(Wi.test(t)||Gi.test(t)||Ji.test(t)){let r=yd(t);if(!r)return null;let o=ji(r);return o.length>1?o:null}if(t.includes("@"))return null;let n=ji(t);return n.length>1?n:null}function ur(e){return e.map(t=>String(t).trim()).filter(t=>!!t).map(t=>t==="*"?t:q(t)).filter(t=>!!t)}function dr(e){let t=new Set;for(let n of e){if(n==="*")continue;let r=q(String(n));r&&t.add(r)}return t}function ye(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 pr(e){let t=new Set;for(let n of e){let r=ye(String(n));r&&t.add(r)}return t}function jo(e){let t=e.trim();if(!t)return null;let n=t.toLowerCase();if(n.startsWith("tg:")||n.startsWith("telegram:")){let o=ye(t);return o?{kind:"tg",id:o}:null}let r=q(t);return r?{kind:"wa",normalized:r}:null}function Ki(e,t){let n=q(t);return n?e.has(n):!1}var Wi,Gi,Ji,Ue=En(()=>{"use strict";Wi=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,Gi=/^(\d+)@c\.us$/i,Ji=/^(\d+)@lid$/i});import mr from"node:fs";function wd(e){return e==="downloads"||e==="omnishData"||e==="sessionCwd"||e==="processCwd"||e==="fixed"?e:O.fileReceiveRootMode}function kd(e){return e==="primary"?"primary":"secondary"}function bd(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=q(s.slice(3));l&&(t[`wa:${l}`]=o.slice(0,64));continue}if(i.startsWith("tg:")||i.startsWith("telegram:")){let l=ye(s);l&&(t[`tg:${l}`]=o.slice(0,64));continue}let a=q(s);a&&(t[`wa:${a}`]=o.slice(0,64))}return t}function Pn(e){let t=typeof e.appsFlushMs=="number"&&e.appsFlushMs>=0?e.appsFlushMs:O.appsFlushMs,n=e.gatewayMode==="telegram"||e.gatewayMode==="both"||e.gatewayMode==="whatsapp"?e.gatewayMode:O.gatewayMode,r=typeof e.telegramBotToken=="string"?e.telegramBotToken:O.telegramBotToken,o=Array.isArray(e.telegramAllowFrom)?[...new Set(e.telegramAllowFrom.map(s=>ye(String(s))).filter(s=>!!s))].sort():O.telegramAllowFrom;return{...O,...e,gatewayMode:n,telegramBotToken:r,telegramAllowFrom:o,allowFrom:Array.isArray(e.allowFrom)?ur(e.allowFrom.map(String)).filter(s=>s!=="*"):O.allowFrom,commandPrefix:(()=>{let s=typeof e.commandPrefix=="string"&&e.commandPrefix.length>0?e.commandPrefix:O.commandPrefix;return s==="! "?"!":s})(),syncTimeoutMs:typeof e.syncTimeoutMs=="number"&&e.syncTimeoutMs>0?e.syncTimeoutMs:O.syncTimeoutMs,syncMaxBytes:typeof e.syncMaxBytes=="number"&&e.syncMaxBytes>0?e.syncMaxBytes:O.syncMaxBytes,jobLogTailLines:typeof e.jobLogTailLines=="number"&&e.jobLogTailLines>0?e.jobLogTailLines:O.jobLogTailLines,shell:typeof e.shell=="string"&&e.shell.length>0?e.shell:O.shell,appsCols:typeof e.appsCols=="number"&&e.appsCols>0&&e.appsCols<=500?Math.floor(e.appsCols):O.appsCols,appsRows:typeof e.appsRows=="number"&&e.appsRows>0&&e.appsRows<=200?Math.floor(e.appsRows):O.appsRows,appsFlushMs:t,appsMinIntervalMs:typeof e.appsMinIntervalMs=="number"&&e.appsMinIntervalMs>=0?e.appsMinIntervalMs:O.appsMinIntervalMs,appsMaxFlushBytes:typeof e.appsMaxFlushBytes=="number"&&e.appsMaxFlushBytes>256?Math.floor(e.appsMaxFlushBytes):O.appsMaxFlushBytes,appsMaxSessions:typeof e.appsMaxSessions=="number"&&e.appsMaxSessions>0?Math.min(50,Math.floor(e.appsMaxSessions)):O.appsMaxSessions,appsMaxSessionsTotal:typeof e.appsMaxSessionsTotal=="number"&&e.appsMaxSessionsTotal>0?Math.min(200,Math.floor(e.appsMaxSessionsTotal)):O.appsMaxSessionsTotal,appsMaxWaChars:typeof e.appsMaxWaChars=="number"&&e.appsMaxWaChars>256?Math.floor(e.appsMaxWaChars):O.appsMaxWaChars,appsLogTailLines:typeof e.appsLogTailLines=="number"&&e.appsLogTailLines>0?Math.min(500,Math.floor(e.appsLogTailLines)):O.appsLogTailLines,appsSubmitDelayMs:typeof e.appsSubmitDelayMs=="number"&&e.appsSubmitDelayMs>=0?Math.min(500,Math.floor(e.appsSubmitDelayMs)):O.appsSubmitDelayMs,appsClearInput:typeof e.appsClearInput=="boolean"?e.appsClearInput:O.appsClearInput,appsClearInputDelayMs:typeof e.appsClearInputDelayMs=="number"&&e.appsClearInputDelayMs>=0?Math.min(200,Math.floor(e.appsClearInputDelayMs)):O.appsClearInputDelayMs,appsClearInputSequence:typeof e.appsClearInputSequence=="string"&&e.appsClearInputSequence.length>0?e.appsClearInputSequence.slice(0,200):O.appsClearInputSequence,fileSendMaxBytes:typeof e.fileSendMaxBytes=="number"&&e.fileSendMaxBytes>=0?e.fileSendMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileSendMaxBytes)):O.fileSendMaxBytes,fileReceiveMaxBytes:typeof e.fileReceiveMaxBytes=="number"&&e.fileReceiveMaxBytes>=0?e.fileReceiveMaxBytes===0?0:Math.min(2e9,Math.floor(e.fileReceiveMaxBytes)):O.fileReceiveMaxBytes,fileInboxSubdir:typeof e.fileInboxSubdir=="string"&&e.fileInboxSubdir.length>0&&e.fileInboxSubdir.replace(/[/\\]/g,"").slice(0,80)||O.fileInboxSubdir,fileReceiveRootMode:wd(e.fileReceiveRootMode),fileReceiveRootPath:typeof e.fileReceiveRootPath=="string"?e.fileReceiveRootPath.trim().slice(0,4096):O.fileReceiveRootPath,recipesAllowDangerousBuiltins:typeof e.recipesAllowDangerousBuiltins=="boolean"?e.recipesAllowDangerousBuiltins:O.recipesAllowDangerousBuiltins,recipesMaxTaskChars:typeof e.recipesMaxTaskChars=="number"&&e.recipesMaxTaskChars>=0?e.recipesMaxTaskChars===0?0:Math.min(Number.MAX_SAFE_INTEGER,Math.floor(e.recipesMaxTaskChars)):O.recipesMaxTaskChars,recipesMacroDefaultCommand:typeof e.recipesMacroDefaultCommand=="string"&&e.recipesMacroDefaultCommand.trim().length>0?e.recipesMacroDefaultCommand.trim().slice(0,4096):O.recipesMacroDefaultCommand,clusterEnabled:typeof e.clusterEnabled=="boolean"?e.clusterEnabled:O.clusterEnabled,clusterLabel:typeof e.clusterLabel=="string"?e.clusterLabel.trim().slice(0,128):O.clusterLabel,clusterRole:kd(e.clusterRole),clusterSenderBindings:bd(e.clusterSenderBindings),serviceInstallFromChat:typeof e.serviceInstallFromChat=="boolean"?e.serviceInstallFromChat:O.serviceInstallFromChat,updateCheckEnabled:typeof e.updateCheckEnabled=="boolean"?e.updateCheckEnabled:O.updateCheckEnabled,updateCheckIntervalMs:typeof e.updateCheckIntervalMs=="number"&&e.updateCheckIntervalMs>0?Math.min(6048e5,Math.max(36e5,Math.floor(e.updateCheckIntervalMs))):O.updateCheckIntervalMs,updateCheckPackageName:typeof e.updateCheckPackageName=="string"&&e.updateCheckPackageName.trim().length>0?e.updateCheckPackageName.trim().slice(0,214):O.updateCheckPackageName,updateInfoUrl:typeof e.updateInfoUrl=="string"?e.updateInfoUrl.trim().slice(0,2048):O.updateInfoUrl,chatLlmFallbackEnabled:typeof e.chatLlmFallbackEnabled=="boolean"?e.chatLlmFallbackEnabled:O.chatLlmFallbackEnabled,chatLlmShellCommand:typeof e.chatLlmShellCommand=="string"?e.chatLlmShellCommand.trim().slice(0,8192):O.chatLlmShellCommand,chatLlmTimeoutMs:typeof e.chatLlmTimeoutMs=="number"&&e.chatLlmTimeoutMs>0?Math.min(9e5,Math.floor(e.chatLlmTimeoutMs)):O.chatLlmTimeoutMs,chatLlmMaxInputChars:typeof e.chatLlmMaxInputChars=="number"&&e.chatLlmMaxInputChars>0?Math.min(5e5,Math.floor(e.chatLlmMaxInputChars)):O.chatLlmMaxInputChars,chatLlmMaxOutputChars:typeof e.chatLlmMaxOutputChars=="number"&&e.chatLlmMaxOutputChars>0?Math.min(2e6,Math.floor(e.chatLlmMaxOutputChars)):O.chatLlmMaxOutputChars,chatLlmNeedsTty:typeof e.chatLlmNeedsTty=="boolean"?e.chatLlmNeedsTty:O.chatLlmNeedsTty,chatLlmWorkDir:typeof e.chatLlmWorkDir=="string"?e.chatLlmWorkDir.trim().slice(0,4096):O.chatLlmWorkDir,tunnelEnabled:typeof e.tunnelEnabled=="boolean"?e.tunnelEnabled:O.tunnelEnabled,tunnelRelayUrl:typeof e.tunnelRelayUrl=="string"&&e.tunnelRelayUrl.trim().length>0?e.tunnelRelayUrl.trim().slice(0,2048):O.tunnelRelayUrl,tunnelMaxActive:typeof e.tunnelMaxActive=="number"&&e.tunnelMaxActive>0?Math.min(50,Math.floor(e.tunnelMaxActive)):O.tunnelMaxActive,platformToken:typeof e.platformToken=="string"?e.platformToken.trim():O.platformToken,platformDeviceId:typeof e.platformDeviceId=="string"?e.platformDeviceId.trim().slice(0,128):O.platformDeviceId,webhookEnabled:typeof e.webhookEnabled=="boolean"?e.webhookEnabled:O.webhookEnabled,webhookPort:typeof e.webhookPort=="number"&&e.webhookPort>=0?Math.min(65535,Math.floor(e.webhookPort)):O.webhookPort,webhookHost:typeof e.webhookHost=="string"&&e.webhookHost.trim().length>0?e.webhookHost.trim():O.webhookHost,webhookToken:typeof e.webhookToken=="string"?e.webhookToken.trim():O.webhookToken}}function Y(e){let t=$(),n=Pn({...t,...e});return Re(n),n}function $(){if(V(),!mr.existsSync(L)){let e=Pn({});return Re(e),e}try{let e=mr.readFileSync(L,"utf8"),t=JSON.parse(e);return Pn(t)}catch{return Pn({})}}function Re(e){V();let t=Pn(e);mr.writeFileSync(L,JSON.stringify(t,null,2)+`
|
|
3
|
-
`,{mode:384})}function
|
|
4
|
-
`,{mode:384})
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
var Rm=Object.defineProperty;var Zn=(e,t)=>()=>(e&&(t=e(e=0)),t);var Cm=(e,t)=>{for(var n in t)Rm(e,n,{get:t[n],enumerable:!0})};import Mm from"node:crypto";import _s from"node:fs";import Tm from"node:os";import re from"node:path";function Em(){let e=process.env.OMNISH_HOME?.trim();if(e)return re.resolve(e);let t=Tm.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=Mm.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return re.join(Ya,t)}function j(e){_s.mkdirSync(e,{recursive:!0,mode:448})}function te(){j(H),j(ne),j(tt),j(Ya),j(Qa),j(ut),j(bt)}var H,ne,tt,Ya,Qa,Ne,le,hn,er,ct,_r,Fr,_,Wr,Ur,Dr,ut,Fs,Ws,Va,bt,tr,Hr,G=Zn(()=>{"use strict";H=Em(),ne=re.join(H,"auth"),tt=re.join(H,"jobs"),Ya=re.join(H,"apps"),Qa=re.join(H,"logs"),Ne=re.join(Qa,"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"),Va=re.join(ut,"completions.sqlite"),bt=re.join(H,"watch"),tr=re.join(bt,"rules.json"),Hr=re.join(bt,"events.sqlite")});function nl(e){let t=e.trim();for(;;){let n=t;if(t=t.replace(/^whatsapp:/i,"").trim(),t===n)return t}}function Pm(e){let t=nl(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 Am(e){let t=e.match(Za);if(t)return t[1]??null;let n=e.match(el);if(n)return n[1]??null;let r=e.match(tl);return r?r[1]??null:null}function Xa(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=nl(e);if(!t||Pm(t))return null;if(Za.test(t)||el.test(t)||tl.test(t)){let r=Am(t);if(!r)return null;let o=Xa(r);return o.length>1?o:null}if(t.includes("@"))return null;let n=Xa(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 rl(e,t){let n=ee(t);return n?e.has(n):!1}var Za,el,tl,qe=Zn(()=>{"use strict";Za=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,el=/^(\d+)@c\.us$/i,tl=/^(\d+)@lid$/i});import Jr from"node:fs";function Im(e){return e==="downloads"||e==="omnishData"||e==="sessionCwd"||e==="processCwd"||e==="fixed"?e:N.fileReceiveRootMode}function Om(e){return e==="primary"?"primary":"secondary"}function Lm(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:Im(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:Om(e.clusterRole),clusterSenderBindings:Lm(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 Kr(e){let t=Us(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 zr(e){let t=Us(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 dt(e){let t=e.trim();return/^\d{6,}:[A-Za-z0-9_-]{20,}$/.test(t)}function Ot(e){let t=$();return t.telegramBotToken=e.trim(),_e(t),$()}function gn(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 qr(e){let t=$();return t.gatewayMode=e,_e(t),$()}function Yr(e){let t=$();return t.clusterEnabled=e,_e(t),$()}function nt(){try{return Jr.readdirSync(ne).length>0}catch{return!1}}var N,pe=Zn(()=>{"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 Nm from"pino";function yn(){return process.env.OMNISH_VERBOSE==="1"||process.env.WHATSVERBOSE==="1"}function ol(){return yn()?"info":"silent"}function Ds(e){e?process.env.OMNISH_VERBOSE="1":delete process.env.OMNISH_VERBOSE,M.level=ol()}function sl(){return M.child({module:"baileys"})}var M,be=Zn(()=>{"use strict";M=Nm({level:ol(),base:{app:"omnish"}})});var yd={};Cm(yd,{fetchPlatformAccount:()=>Bn,getAttachedConfig:()=>ta,getAttachedPlatformSnapshot:()=>vy,mergeAttachedPlatformPolicy:()=>gd,parsePlatformMeResponse:()=>fd,setAttachedPlatformSnapshot:()=>Zi,setPlatformDefaultDevice:()=>na,snapshotFromRegisteredAccount:()=>hd,syncAttachedPlatformPolicy:()=>ns,updatePlatformAllowlists:()=>ts});function ea(e){let t=e.replace(/\/$/,"");return/^https?:\/\//i.test(t)?t:`http://${t}`}function ky(e){return e==="telegram"||e==="both"||e==="whatsapp"?e:"whatsapp"}function Sy(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 fd(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:ky(e.gatewayMode),connectors:Sy(e.connectors),defaultDeviceId:o,routing:{defaultDeviceId:o,onlineDeviceIds:r,onlineCount:typeof n?.onlineCount=="number"?n.onlineCount:r.length}}}function hd(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 gd(e,t){return{...e,allowFrom:[...t.allowFrom],telegramAllowFrom:[...t.telegramAllowFrom],gatewayMode:t.gatewayMode}}function Zi(e){es=e}function vy(){return es}function ta(){let e=$();return es?gd(e,es):e}async function Bn(e){let t=await fetch(`${ea(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 fd(n)}async function ts(e,t){let n=await fetch(`${ea(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 na(e,t){let n=await fetch(`${ea(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 ns(e,t){try{let n=await Bn(e);return Zi(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=hd(t);return Zi(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 es,rs=Zn(()=>{"use strict";pe();be();es=null});pe();import Kb from"node:dns";import zb from"node:crypto";import Xt from"node:fs";import za from"node:path";import wm from"node:os";pe();be();import vf from"node:os";import xf from"node:fs";G();import il from"node:crypto";import or from"node:fs";import Hs from"node:os";import wn from"node:path";var _m=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/;function js(e){let t=e.trim().toLowerCase();return _m.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==="."?wn.resolve(t):n==="~"?Hs.homedir():n.startsWith("~/")||n.startsWith("~\\")?wn.join(Hs.homedir(),n.slice(2)):wn.isAbsolute(n)?n:wn.resolve(t,n)}function Qr(e){return wn.join(Hs.homedir(),"Cowork",e)}function Fm(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:Qr(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=or.readFileSync(Fs,"utf8"),t=JSON.parse(e);if(!t||!Array.isArray(t.tasks))return[];let n=[];for(let r of t.tasks){let o=Fm(r);o&&n.push(o)}return n}catch{return[]}}function Oe(e){j(ut);let t={tasks:e},n=wn.join(ut,`.tasks.${process.pid}.${il.randomBytes(4).toString("hex")}.tmp`);or.writeFileSync(n,JSON.stringify(t,null,2)+`
|
|
4
|
+
`,{mode:384}),or.renameSync(n,Fs)}function Ye(e,t,n){let r=t.trim().toLowerCase();return e.find(o=>o.name===r&&o.ownerPeerKey===n)}function sr(){return il.randomBytes(4).toString("hex")}function al(e){j(ut),or.writeFileSync(Ws,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{mode:384})}function ll(e){let t=Bs();t.push(e),al(t)}function Bs(){try{let e=or.readFileSync(Ws,"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 cl(e){if(e<=0)return{batch:[],remainingAfter:Bs().length};let t=Bs();if(t.length===0)return{batch:[],remainingAfter:0};let n=t.slice(0,e),r=t.slice(e);return al(r),{batch:n,remainingAfter:r.length}}G();G();import Wm from"better-sqlite3";var ul=1,dl=200,bn=null;function Um(){j(bt);let e=new Wm(Hr);e.pragma("journal_mode = WAL"),e.exec(`
|
|
6
|
+
CREATE TABLE IF NOT EXISTS watch_meta (
|
|
7
|
+
key TEXT PRIMARY KEY,
|
|
8
|
+
value TEXT NOT NULL
|
|
9
|
+
);
|
|
10
|
+
CREATE TABLE IF NOT EXISTS watch_recent (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
rule_id TEXT NOT NULL,
|
|
13
|
+
rule_name TEXT NOT NULL,
|
|
14
|
+
kind TEXT NOT NULL,
|
|
15
|
+
summary TEXT NOT NULL,
|
|
16
|
+
ts_ms INTEGER NOT NULL
|
|
17
|
+
);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_watch_recent_ts ON watch_recent(ts_ms DESC);
|
|
19
|
+
CREATE TABLE IF NOT EXISTS watch_rule_state (
|
|
20
|
+
rule_id TEXT PRIMARY KEY,
|
|
21
|
+
state_key TEXT NOT NULL,
|
|
22
|
+
updated_at_ms INTEGER NOT NULL
|
|
23
|
+
);
|
|
24
|
+
`);let t=e.prepare("SELECT value FROM watch_meta WHERE key = 'schema_version'").get();return(t?Number(t.value):0)<ul&&e.prepare("INSERT OR REPLACE INTO watch_meta (key, value) VALUES ('schema_version', ?)").run(String(ul)),e}function ir(){return bn||(bn=Um()),bn}function Vr(){ir()}function pl(){if(bn){try{bn.close()}catch{}bn=null}}function ml(e){let t=ir();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>dl&&t.prepare(`DELETE FROM watch_recent WHERE id IN (
|
|
25
|
+
SELECT id FROM watch_recent ORDER BY ts_ms ASC LIMIT ?
|
|
26
|
+
)`).run(n.c-dl)}function fl(e,t){let n=ir(),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 hl(e){return ir().prepare("SELECT state_key FROM watch_rule_state WHERE rule_id = ?").get(e)?.state_key??null}function gl(e,t,n){ir().prepare("INSERT OR REPLACE INTO watch_rule_state (rule_id, state_key, updated_at_ms) VALUES (?, ?, ?)").run(e,t,n)}import Sl from"node:path";import kt from"node:path";function Dm(e,t){let n=kt.normalize(e);for(let r of t){let o=kt.normalize(r);if(n===o||n.startsWith(o+kt.sep))return!0}return!1}function Hm(e,t,n){let r=kt.relative(t,e);if(r.startsWith("..")||kt.isAbsolute(r))return!1;let o=r.split(kt.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 Xr(e,t){if(t.excludePaths.length&&Dm(e,t.excludePaths))return!0;let n=t.path;if(n&&t.excludeGlobs.length){for(let r of t.excludeGlobs)if(Hm(e,n,r))return!0}return!1}function yl(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=kt.relative(e.path,n);!r.startsWith("..")&&!kt.isAbsolute(r)&&t.push(r.split(kt.sep).join("/")+"/**")}catch{}return t}qe();function kn(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:${It(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 wl(e,t,n){return kn(e,t,n)}be();G();import Bm from"node:crypto";import Gs from"node:fs";var jm=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,Gm=1,Js=20;function Zr(e){let t=e.trim().toLowerCase();return jm.test(t)?{ok:!0,name:t}:{ok:!1,error:"Name must be alphanumeric with _ or -, max 32 chars."}}function eo(){return Bm.randomBytes(8).toString("hex")}function Jm(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 Km(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:Jm(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(Km).filter(n=>n!==null)}function qm(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=Gs.readFileSync(tr,"utf8"),t=zm(e),{rules:n,changed:r}=qm(t);return r&&pt(n),n}catch{return[]}}function Ym(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 ar(){let e=Le();return{rules:e,summary:Ym(e)}}function pt(e){j(bt);let n=`${JSON.stringify({version:Gm,rules:e},null,2)}
|
|
27
|
+
`,r=`${tr}.tmp`;Gs.writeFileSync(r,n,{mode:384}),Gs.renameSync(r,tr)}function Ks(){return tr}function Zt(e,t){let n=t.trim().toLowerCase();return e.find(r=>r.name===n)}function bl(e,t){return e.find(n=>n.id===t)}function Sn(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 kl(e,t){let n=t.trim().toLowerCase();return e.filter(r=>r.name!==n)}import Qm from"node:os";import mt from"node:path";var Vm=new Set([".env","id_rsa","id_ed25519","id_ecdsa","known_hosts","credentials.json","secrets.json",".netrc","shadow","passwd"]);function Qe(e){let t=mt.normalize(e),n=t.toLowerCase(),r=Qm.homedir().toLowerCase();if(n.includes(`${mt.sep}.ssh${mt.sep}`)||n.endsWith(`${mt.sep}.ssh`)||n.includes(`${mt.sep}browser${mt.sep}`)&&n.includes("profile")||r&&(n===`${r}/.gnupg`||n.startsWith(`${r}/.gnupg${mt.sep}`))||n.includes(`${mt.sep}keychains${mt.sep}`))return!0;let o=mt.basename(t);return!!(Vm.has(o)||o.startsWith(".env.")||o.endsWith(".pem")||o.endsWith(".key"))}var Xm=["node_modules",".git",".svn",".hg","__pycache__",".cache",".next","dist","build"],Zm=[".tmp",".swp",".swx","~",".part"];function vl(e,t){let n=new Map,r=new Map;function o(u,c){let m=u.split(Sl.sep);for(let h of m)if(Xm.includes(h))return!0;let f=Sl.basename(u);for(let h of Zm)if(f.endsWith(h))return!0;return!!Xr(u,c)}function s(u){let c=bl(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(ml(c),(f.notifyWhen??"always")==="state-change"){if(hl(f.id)===c.stateKey)return;gl(f.id,c.stateKey,c.tsMs)}let g=wl(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 xl(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 $l from"node:fs";import ef from"node:path";import{subscribe as tf}from"@parcel/watcher";var nf=["**/node_modules/**","**/.git/**","**/.svn/**","**/.hg/**","**/__pycache__/**","**/.cache/**"];function rf(e){return e==="create"?"create":e==="delete"?"delete":e==="update"?"update":e}function of(e,t){try{let n=$l.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 Rl(e,t){let n=e.path;if(!n||!$l.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 tf(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=rf(l.type);if(!xl(d,r))continue;let u=ef.resolve(l.path);if(!u.startsWith(n)||Qe(u)||Xr(u,e))continue;let c=of(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:[...nf,...yl(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 mf from"node:os";be();import Lt from"node:fs";function sf(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=Lt.statSync(e);if(u.size<o&&(o=0),u.size<=o)return;let c=Lt.openSync(e,"r");try{let m=u.size-o,f=Buffer.alloc(m);Lt.readSync(c,f,0,m,o),o=u.size;let h=f.toString("utf8");for(let g of h.split(`
|
|
28
|
+
`)){let y=g.trim();y&&t(y)}}finally{Lt.closeSync(c)}l="ok"}catch(u){l=`error: ${String(u)}`}}try{Lt.existsSync(e)&&(o=Lt.statSync(e).size),i=Lt.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 to(e,t){for(let n of e)try{if(Lt.existsSync(n))return sf(n,t)}catch(r){M.debug({path:n,err:String(r)},"watch log-tail skip path")}return null}var af=["/var/log/install.log"];function lf(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 Cl(e,t){return to(af,n=>{let r=lf(n);r&&t({ruleId:e.id,ruleName:e.name,kind:"pkg",stateKey:r.slice(0,200),summary:r,tsMs:Date.now()})})}var cf=["/var/log/dpkg.log","/var/log/apt/history.log"];function uf(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 df(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 Ml(e,t){return to(cf,n=>{let r=uf(n)??df(n);r&&t({ruleId:e.id,ruleName:e.name,kind:"pkg",stateKey:r,summary:r,tsMs:Date.now()})})}import{spawn as pf}from"node:child_process";function Tl(e,t){let n=!1,r="ok",o=0,s=()=>{if(n)return;let a=pf("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 El(e,t){let n=mf.platform();if(n==="win32"){let o=Tl(e,t);return{stop:()=>o.stop(),status:o.status}}if(n==="darwin"){let o=Cl(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=Ml(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 Sf from"node:os";import{spawnSync as Pl}from"node:child_process";var ff=3e4;function hf(e){let t=new Map;for(let n of e){let r=Pl("launchctl",["print",`system/${n}`],{encoding:"utf8",timeout:1e4});if(r.status!==0){let s=process.getuid?.()??501,i=Pl("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 Al(e,t){let n=e.units,r=!1,o="ok",s=new Map,i=()=>{if(r)return;let a=hf(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,ff).unref?.()};return i(),{stop(){r=!0},status:()=>o}}import{spawnSync as Il}from"node:child_process";var gf=3e4;function yf(e){let t=new Map;if(e.length===0)return t;let n=["show",...e,"--property=ActiveState,SubState,UnitFileState","--no-pager"],r=Il("systemctl",n,{encoding:"utf8",timeout:15e3});if(r.status!==0)return t;let o="";for(let s of(r.stdout??"").split(`
|
|
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=Il("systemctl",["is-active",i],{encoding:"utf8",timeout:5e3}),l=(a.stdout??a.stderr??"unknown").trim();t.set(i,l)}return t}function Ol(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=yf(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,gf).unref?.()};return i(),{stop(){r=!0},status:()=>o}}import{spawnSync as wf}from"node:child_process";var bf=3e4;function kf(e){let t=new Map;for(let n of e){let r=wf("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 Ll(e,t){let n=e.units,r=!1,o="ok",s=new Map,i=()=>{if(r)return;let a=kf(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,bf).unref?.()};return i(),{stop(){r=!0},status:()=>o}}function Nl(e,t){let n=Sf.platform();return n==="win32"?Ll(e,t):n==="darwin"?Al(e,t):Ol(e,t)}var Ve=null,Nt=null;function _l(e){let t=e.getConfig();return vl(e,{debounceMs:Math.max(500,t.watchDebounceMs??2e3),maxEventsPerMinute:Math.max(1,t.watchMaxEventsPerMinute??30)})}function $f(e){return e.watchEnabled&&e.watchAutoRestore}var zs=class{deps;pipeline;runtimes=new Map;stopped=!1;constructor(t){this.deps=t,this.pipeline=_l(t)}onEvent=(t,n)=>{this.pipeline.ingest(t,n)};cancelPendingForRule(t){this.pipeline.cancelForRule(t)}async reload(){if(this.pipeline.dispose(),this.pipeline=_l(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,vf.homedir()),o={...t,path:r};if(Qe(r)){t.adapterStatus="denied: sensitive path",this.persistRuleStatus(t);return}if(!xf.existsSync(r)){t.adapterStatus="error: path not found",this.persistRuleStatus(t);return}let s=await Rl(o,i=>this.onEvent(o,i));n={stop:()=>s.stop(),status:s.status}}else if(t.kind==="pkg")n=El(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=Nl(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},pt(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(),pl()}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 Fl(){return Ve}function qs(e){Ve?.cancelPendingForRule(e)}function Rf(){j(bt),Vr()}function Ys(){Nt&&(Ve||(Ve=new zs(Nt)),Ve.reload())}function no(e){Nt=e,Rf();let t=e.getConfig(),{summary:n}=ar();return n.total>0&&M.info({rules:n.total,active:n.active,paused:n.paused,disabled:n.disabled},"watch rules loaded from disk"),$f(t)&&Ys(),()=>{Ve?.stop(),Ve=null,Nt=null}}async function Wl(){return Nt?Nt.getConfig().watchEnabled?(Ys(),Ve?.getRunningCount()??0):(Ve?.stop(),Ve=null,-1):-1}function De(){if(!Nt)return;if(!Nt.getConfig().watchEnabled){Ve?.stop(),Ve=null;return}Ys()}G();pe();G();import Tf from"node:os";import oo from"node:path";G();import Qs from"node:fs";import Dl from"node:os";import _t from"node:path";var Hl=_t.join(H,"sessions.json"),vn=new Map;function Bl(){return{cwd:_t.resolve(Dl.homedir())}}function Cf(e){return e.startsWith("wa:")||e.startsWith("tg:")?e:`wa:${e}`}function Mf(){try{let e=Qs.readFileSync(Hl,"utf8"),t=JSON.parse(e);for(let[n,r]of Object.entries(t)){if(!r||typeof r!="object")continue;let o=Cf(n),i={cwd:typeof r.cwd=="string"&&r.cwd.length>0?_t.resolve(r.cwd):Bl().cwd};r.fileReceiveRoot==="sessionCwd"&&(i.fileReceiveRoot="sessionCwd"),vn.set(o,i)}}catch{}}function jl(){j(H);let e={};for(let[t,n]of vn){let r={cwd:n.cwd};n.fileReceiveRoot==="sessionCwd"&&(r.fileReceiveRoot="sessionCwd"),e[t]=r}Qs.writeFileSync(Hl,JSON.stringify(e,null,2)+`
|
|
30
|
+
`,{mode:384})}var Ul=!1;function Vs(){Ul||(Mf(),Ul=!0)}function oe(e){Vs();let t=vn.get(e);return t||(t=Bl(),vn.set(e,t)),t}function ro(e,t){Vs();let n=_t.resolve(t),r=oe(e);r.cwd=n,vn.set(e,r),jl()}function Gl(e){return oe(e).fileReceiveRoot==="sessionCwd"?"sessionCwd":"default"}function Xs(e,t){Vs();let n=oe(e);t==="default"?delete n.fileReceiveRoot:n.fileReceiveRoot="sessionCwd",vn.set(e,n),jl()}function Jl(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 Kl(e,t){if(t.kind==="home")return _t.resolve(Dl.homedir());let n=t.value.replace(/^['"]|['"]$/g,"");return _t.isAbsolute(n)?_t.normalize(n):_t.resolve(e,n)}function zl(e){try{return Qs.statSync(e).isDirectory()?{ok:!0}:{ok:!1,error:`Not a directory: ${e}`}}catch(t){return{ok:!1,error:String(t)}}}var Ef="Omnish";function ql(){return oo.join(Tf.homedir(),"Downloads",Ef)}function Ft(e,t){let n=oe(t);if(n.fileReceiveRoot==="sessionCwd")return n.cwd;switch(e.fileReceiveRootMode){case"downloads":return ql();case"omnishData":return oo.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(!oo.isAbsolute(r))throw new Error('fileReceiveRootPath must be an absolute path when fileReceiveRootMode is "fixed".');return oo.resolve(r)}default:return ql()}}G();import $t from"node:fs";import Ql from"node:path";import Ht from"node:process";var en="\x1B";function Pf(e){return e.replace(/\u001B\[[\d;]*m/g,"")}function so(e){return Pf(e).length}function Zs(e,t,n,r,o=2){let s=Math.max(0,t-so(n));return`${e}${n}${" ".repeat(s)}${" ".repeat(o)}${r}`}function St(e,t,n,r){if(n.length===0)return[];let o=n.map(i=>r(i.left)),s=Math.max(...o.map(so));return n.map((i,a)=>Zs(t,s,o[a],S(e,i.right)))}var Wt={primary:"#b4ff24",foreground:"#eef2f4",muted:"#8a9199",border:"#2a3139",error:"#ef4444",warn:"#a0e614",warnAlt:"#8cce04"};function Af(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 Ut(e){let t=Af(e);return t?`${en}[38;2;${t.r};${t.g};${t.b}m`:""}function io(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 vt(e,t,n){return!t||!io(e)?n:`${t}${n}${en}[0m`}function J(e,t){return vt(e,`${en}[1m`,t)}function If(e,t){return io(e)?`${Ut(Wt.foreground)}${en}[1m${t}${en}[0m`:t}function V(e,t){return vt(e,`${en}[2m`,t)}function Ce(e,t){return vt(e,`${Ut(Wt.primary)}${en}[1m`,t)}function ce(e,t){return vt(e,Ut(Wt.primary),t)}function S(e,t){return vt(e,Ut(Wt.foreground),t)}function w(e,t){return vt(e,Ut(Wt.muted),t)}function Of(e,t){return vt(e,Ut(Wt.border),t)}function ao(e,t){return vt(e,Ut(Wt.error),t)}function me(e,t){return vt(e,Ut(Wt.warn),t)}function Dt(e,t=60,n="\u2500"){let r=n.repeat(Math.max(1,t));return Of(e,r)}function B(e,t){return io(e)?`${`${w(e,"[")}${ce(e,"omnish")}${w(e,"]")}`} ${t}`:`[omnish] ${t}`}function C(e,t){return io(e)?`${`${ao(e,"[omnish]")}`} ${t}`:`[omnish] ${t}`}function Yl(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("",If(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(`
|
|
31
|
+
`).replace(/^\n+/,"").trimEnd()}pe();G();pe();G();import ei from"node:fs";function xt(){try{let e=ei.readFileSync(_r,"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 ft(e){te(),ei.writeFileSync(_r,JSON.stringify({token:e.token.trim(),...e.relayUrl?{relayUrl:e.relayUrl.trim()}:{}},null,2)+`
|
|
32
|
+
`,{mode:384})}function lo(){try{ei.unlinkSync(_r)}catch{}}function Lf(){return process.env.OMNISH_TOKEN?.trim()||process.env.OMNISH_TUNNEL_TOKEN?.trim()||process.env.OMNISH_DEVICE_TOKEN?.trim()||""}function ht(){let e=Lf();if(e)return e;let t=$().platformToken.trim();return t||(xt()?.token??"")}function ti(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=xt()?.relayUrl?.trim();return r?r.replace(/\/$/,""):e.replace(/\/$/,"")}function rt(e){return ti(e)}var $e="https://tunnel.omnish.dev";function co(e){return(e&4)!==0}function ni(e){return(e&2)!==0}var Vl={error:3,warn:2,info:1};function Xl(e,t){let n=Vl[t];return e.filter(r=>Vl[r.severity]>=n)}function Rt(e,t={}){let n=[],r=t.gatewayMode??e.gatewayMode,o=r==="whatsapp"||r==="both",s=r==="telegram"||r==="both";if(e.allowFrom.includes("*")&&n.push({severity:"error",code:"allow-wildcard",message:'allowFrom contains "*" \u2014 this must never be used; remove it from config immediately.',detail:`Edit ${_} 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.`}),!Ql.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{$t.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?Ql.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(Ht.platform!=="win32"){try{if($t.existsSync(_)){let d=$t.statSync(_);(co(d.mode)||ni(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 Ht.getuid=="function"?Ht.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($t.existsSync(H)){let d=$t.statSync(H);(co(d.mode)||ni(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&&$t.existsSync(tt)){let d=$t.statSync(tt);(co(d.mode)||ni(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($t.existsSync(ne)){let d=$t.statSync(ne);co(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 Ht.env.TELEGRAM_BOT_TOKEN=="string"?Ht.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."}),(Ht.env.OMNISH_TOKEN?.trim()||Ht.env.OMNISH_TUNNEL_TOKEN?.trim()||Ht.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."}),ht()||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 lr(e){return e.some(t=>t.severity==="error")}function Nf(e,t){switch(t){case"error":return ao(e,"[ERROR]");case"warn":return me(e,"[WARN]");case"info":return w(e,"[INFO]")}}function ri(e,t,n,r){if(r.length!==0){t.push(J(e,`${n} (${r.length}):`));for(let o of r)t.push(` ${Nf(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 oi(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 ri(t,i,"Errors",n),ri(t,i,"Warnings",r),ri(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 si(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 Zl(e){return`${JSON.stringify({findings:e,summary:si(e)},null,2)}
|
|
35
|
+
`}function ec(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 tc(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(ao(t,`${r} error(s)`)),o&&i.push(me(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 ue(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 _f(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 Ff(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:_f(e),tg:Ff(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 nc(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 rc(){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 ii(){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 oc(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(`
|
|
12
38
|
`),n.join(`
|
|
13
|
-
`))}function
|
|
39
|
+
`))}function cr(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"),ue(t.join(`
|
|
14
40
|
`),n.join(`
|
|
15
|
-
`))}function
|
|
41
|
+
`))}function sc(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 ic(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 ac(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 ue(t.join(`
|
|
16
42
|
`).trimEnd(),n.join(`
|
|
17
|
-
`).trimEnd())}function
|
|
43
|
+
`).trimEnd())}function ai(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 ue(n.join(`
|
|
18
44
|
`).trimEnd(),r.join(`
|
|
19
|
-
`).trimEnd())}function
|
|
20
|
-
`),n=["<b>Token saved</b>","","telegramBotToken written to config (not echoed).",
|
|
45
|
+
`).trimEnd())}function lc(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
|
+
`),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(`
|
|
21
47
|
`)+`
|
|
22
|
-
`;return
|
|
48
|
+
`;return ue(t.trimEnd(),n.trimEnd())}function cc(){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 uc(e,t,n){let r=t?`
|
|
23
49
|
|
|
24
50
|
${t}`:n?`
|
|
25
51
|
|
|
26
52
|
Start omnish run on the host to apply (or /reload from a running gateway).`:"",o=t?`
|
|
27
53
|
|
|
28
|
-
${
|
|
54
|
+
${q(t)}`:n?`
|
|
29
55
|
|
|
30
56
|
Start omnish run on the host to apply (or /reload from a running gateway).`:"",s=`*gatewayMode saved*
|
|
31
57
|
|
|
32
|
-
"${
|
|
33
|
-
${
|
|
58
|
+
"${Me(e)}"
|
|
59
|
+
${Me(_)}${r}`,i=`<b>gatewayMode saved</b>
|
|
34
60
|
|
|
35
|
-
<code>${
|
|
36
|
-
${
|
|
37
|
-
`),a=["<b>Shortcuts</b>",o,"",...e.map(l=>{let u=`${s?l.scope==="chat"?"[chat] ":"[global] ":""}${l.name}`;return`\u2022 <code>${
|
|
38
|
-
`);return
|
|
61
|
+
<code>${q(e)}</code>
|
|
62
|
+
${q(_)}${o}`;return ue(s,i)}function dc(){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 pc(){return Z([{kind:"title",text:"/deny \u2014 remove from allowlist"},{kind:"p",text:"Same forms as /allow: +E164 or tg:id"}])}function mc(){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 li(){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 ci(){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 ui(){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 fc(e,t){let n=Gl(t),r=oe(t),o="";try{o=Ft(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 hc(){return Z([{kind:"title",text:"Unknown /wa command"},{kind:"p",text:"Send /wa help for setup."}])}function gc(){return Z([{kind:"title",text:"Unknown /tg command"},{kind:"p",text:"Send /tg help or /tg token <botfather_token>."}])}function yc(){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 wc(e){return Z([{kind:"title",text:"Unknown command"},{kind:"p",text:`Try /help or ${e.commandPrefix}<command>.`},{kind:"gap"},...xn(e)])}function bc(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"},...xn(e)])}function kc(){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"},...ii()];return Z(e)}function di(){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 Sc(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
|
+
`),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 ue(i,a)}function ur(e,t,n="chat"){return p(`Shortcut saved: ${e}
|
|
39
65
|
\u2192 ${t}
|
|
40
|
-
(${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 vc(e,t="chat"){return p(`Shortcut removed (${t==="global"?"shared":"this chat"}): ${e}`)}function xc(e){return p(`Unknown shortcut: ${e}`)}function $c(e,t){return p(`Unknown shortcut "${e}" in ${t==="global"?"shared shortcuts":"this chat"}.`)}function pi(e,t,n){let r=n?`
|
|
41
67
|
|
|
42
|
-
${n}`:"";return
|
|
43
|
-
\u2192 ${t}${r}`)}function
|
|
68
|
+
${n}`:"";return p(`${e}
|
|
69
|
+
\u2192 ${t}${r}`)}function Rc(){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: "+Ur},{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 Wf(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 Cc(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)"))),ue(t.join(`
|
|
44
70
|
`).trimEnd(),n.join(`
|
|
45
|
-
`).trimEnd())}function
|
|
46
|
-
`))}function
|
|
47
|
-
`))}function
|
|
71
|
+
`).trimEnd())}function mi(e,t){let n=e.taskEnv??"OMNISH_TASK",r=[`Recipe: ${e.name}`,`Source: ${Wf(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 dr(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 Mc(e,t="chat"){return p(`Recipe removed (${t==="global"?"gateway-shared storage":"this chat"}): ${e}`)}function Tc(e,t){return p(`Unknown recipe "${e}" in ${t==="global"?"gateway-shared storage":"this chat storage"}.`)}function Ec(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 ue(o.join(`
|
|
48
74
|
`).trimEnd(),s.join(`
|
|
49
|
-
`).trimEnd())}function
|
|
50
|
-
/run list`)}function
|
|
51
|
-
`)}function
|
|
52
|
-
`)}function
|
|
53
|
-
`));if(r==="show"){let i=$();return
|
|
75
|
+
`).trimEnd())}function fi(e){return p(`Unknown recipe: ${e}
|
|
76
|
+
/run list`)}function hi(){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 Uf(e){let{errors:t,warns:n,infos:r}=si(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 Pc(e){return Z(Uf(e))}function Ac(){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 Ic(){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 $n(e){let t=e.trim();return t?t.length<=8?"(set)":`${t.slice(0,4)}\u2026${t.slice(-4)}`:"(empty)"}function Oc(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 Lc=new Set(["downloads","omnishData","sessionCwd","processCwd","fixed"]),Bt=["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 Nc(e){return Bt.includes(e)}function Df(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: ${$n(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: ${$n(e.webhookToken)}`,"","*Watch (OS event eye)*",`watchEnabled: ${e.watchEnabled}`,`watchDebounceMs: ${e.watchDebounceMs}`,`watchMaxEventsPerMinute: ${e.watchMaxEventsPerMinute}`,`watchAutoRestore: ${e.watchAutoRestore}`,"",`File: ${_}`].join(`
|
|
77
|
+
`)}function Hf(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($n(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($n(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 _c(e,t){if(!Nc(t))return null;let n=t;if(n==="telegramBotToken")return`telegramBotToken: ${$n(ve(e))}`;if(n==="webhookToken")return`webhookToken: ${$n(e.webhookToken)}`;let r=e[n];return`${t}: ${typeof r=="object"?JSON.stringify(r):String(r)}`}function Bf(e,t){let n=_c(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 uo(e,t){let n=Oc(t),r=!1,o=!1,s=!1;if(e==="telegramBotToken"){if(!dt(n))throw new Error("Invalid bot token format (expect digits:secret from BotFather).");return Ot(n),r=!0,s=!0,{reloadSuggested:r,shellWarning:o,tokenSaved:s}}let i=$();switch(e){case"gatewayMode":{let a=gn(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=Oc(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(!Lc.has(a))throw new Error(`fileReceiveRootMode: ${[...Lc].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 Fc(e,t){let n=e.trim(),r=n.toLowerCase();if(!n||r==="help")return Z(rc());if(r==="keys"||r==="help keys")return p(["*Configurable keys* (/config set)","",Bt.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 ue(Df(i),Hf(i))}let o=n.match(/^get\s+(\S+)\s*$/i);if(o){let i=o[1],a=$(),l=_c(a,i);if(!l)return p(`Unknown key "${i}". /config keys`);let d=Bf(a,i);return ue(`${l}
|
|
54
80
|
|
|
55
|
-
${
|
|
56
|
-
Reload: ${
|
|
57
|
-
Reload failed: ${
|
|
58
|
-
Send /reload while omnish run is active (gatewayMode / Telegram).`:
|
|
59
|
-
Send /reload to pick up changes where applicable.`;let
|
|
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(!Nc(i))return p(`Unknown key "${i}". /config keys`);try{let{reloadSuggested:l,shellWarning:d,tokenSaved:u}=uo(i,a),c="";if(t?.reload&&l){let y=await t.reload();c=y.ok?`
|
|
82
|
+
Reload: ${y.summary}`:`
|
|
83
|
+
Reload failed: ${y.error}`}else l?c=`
|
|
84
|
+
Send /reload while omnish run is active (gatewayMode / Telegram).`:c=`
|
|
85
|
+
Send /reload to pick up changes where applicable.`;let m=d?`
|
|
60
86
|
\u26A0 shell changed \u2014 affects all commands run via omnish.`:"",f=u?`
|
|
61
|
-
telegramBotToken saved (not echoed).`:"",
|
|
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 ue(h,g)}catch(l){return p(`Error: ${String(l)}`)}}return p("Unknown /config command. Try /config help or /config show")}pe();var gi=[...Bt,"platformToken","platformDeviceId"],yi={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 gi)yi[e]=e;function po(e){let t=e.trim().toLowerCase().replace(/-/g,"_");return yi[t]??null}function Wc(){return Object.keys(yi).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 jf(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 Gf(e){return N[e]}function Rn(e,t){let n=jf(t),r=$();switch(e){case"platformToken":return W({platformToken:n});case"platformDeviceId":return W({platformDeviceId:n});case"gatewayMode":{let o=gn(n);if(!o)throw new Error('gatewayMode: "whatsapp", "telegram", or "both"');return r.gatewayMode=o,_e(r),r}case"telegramBotToken":if(!dt(n))throw new Error("telegramBotToken: invalid bot token format");return Ot(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 Uc(e){let t=Gf(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 tn(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}pe();G();import Cn from"node:fs";import Si from"node:os";import pr from"node:path";import jc from"node:crypto";var bi="\u2063omnish/c v1",Jf=/([nlra])=([^\s\]]*)/g;function ot(e){return e.replace(/-/g,"").slice(0,8)}function wi(e){return e.replace(/[\s\]\r\n]/g,"_").slice(0,64)}function Kf(e){let t=wi(ot(e.nodeId)),n=wi(e.label||""),r=e.role==="primary"?"p":"s",o=wi(e.activeNodeId?ot(e.activeNodeId):"");return`${bi} [n=${t} l=${n} r=${r} a=${o}]`}function Dc(e,t){let n=Kf(t);if(e.includes(n))return e;let r=e.replace(/\s+$/,"");return r.length===0?n:`${r}
|
|
62
88
|
|
|
63
|
-
${n}`}function
|
|
64
|
-
`,{mode:384}),t}function
|
|
65
|
-
`,o=
|
|
66
|
-
`);for(let l of a){let
|
|
89
|
+
${n}`}function Hc(e){if(!e||!e.includes(bi))return null;let t=e.indexOf(bi),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(Jf))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 Gc=3,zf="node-id",qf="cluster-local.json",Bc=8;function Jc(){return pr.join(H,qf)}function vi(){return pr.join(H,zf)}function Xe(){j(H);let e=vi();try{if(Cn.existsSync(e)){let n=Cn.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=jc.randomUUID();return Cn.writeFileSync(e,`${t}
|
|
90
|
+
`,{mode:384}),t}function Kc(){return{schemaVersion:Gc,updatedAt:new Date().toISOString(),peers:[],senderBindings:{}}}function Yf(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=Jc();try{let t=Cn.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=Yf(n.senderBindings);return{schemaVersion:Gc,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:new Date().toISOString(),peers:r,senderBindings:o}}catch{return Kc()}}function Qf(e,t){let n=pr.dirname(e);j(n);let r=`${JSON.stringify(t,null,2)}
|
|
91
|
+
`,o=pr.join(n,`.${pr.basename(e)}.tmp.${process.pid}.${jc.randomBytes(4).toString("hex")}`);Cn.writeFileSync(o,r,{mode:384}),Cn.renameSync(o,e)}function $i(e){let t=Jc(),n=Kc();for(let r=0;r<Bc;r++){n=ge(),e(n),n.updatedAt=new Date().toISOString();try{return Qf(t,n),n}catch{}}throw new Error(`Could not write cluster local state after ${Bc} attempts: ${t}`)}function zc(e){return(e.clusterLabel??"").trim()||Si.hostname()}function ye(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function qc(e,t){let n=e.peers.findIndex(r=>r.nodeId===t.nodeId);n>=0?e.peers[n]=t:e.peers.push(t)}function mr(e){return{nodeId:ot(Xe()),label:zc(e),role:e.clusterRole,lastSeenIso:new Date().toISOString()}}function Yc(e,t,n){let r=n.trim();if(!r)return{ok:!1,reason:"not-found"};let o=mr(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 Ct(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=Yc(n,e,o);if(s.ok)return{senderKey:t,nodeId:s.peer.nodeId,sinceIso:new Date(0).toISOString(),source:"config"}}return null}function xi(e,t,n="chat"){let r=$(),o=ge(),s=Yc(o,r,t);if(!s.ok)return{state:o,resolved:s};let i=new Date().toISOString();return{state:$i(l=>{l.senderBindings[e]={senderKey:e,nodeId:s.peer.nodeId,sinceIso:i,source:n},qc(l,{...s.peer,lastSeenIso:i})}),resolved:s}}function Vf(e){let t=null;return{state:$i(r=>{r.senderBindings[e]&&(t=r.senderBindings[e]??null,delete r.senderBindings[e])}),removed:t}}function Qc(e,t){let n=ot(Xe()),r=new Date().toISOString();return $i(o=>{if(qc(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 Vc(e,t){let n=Ct(t,e);return n?n.nodeId===ot(Xe()):!1}function Xf(e,t){let n=mr(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 Xf(e,t)===ot(Xe())}function mo(e,t,n){let r=ot(Xe()),o=["*Computers*",""],s=n?Ct(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,mr(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
|
+
`);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}
|
|
67
93
|
id \`${l.nodeId}\` \xB7 role ${l.role}
|
|
68
94
|
seen ${l.lastSeenIso}`)}return o.push(""),o.push(`Updated: ${e.updatedAt}`),o.join(`
|
|
69
|
-
`)}function
|
|
70
|
-
`);for(let l of a){let
|
|
71
|
-
`)}function
|
|
72
|
-
`),
|
|
73
|
-
`);return{wa:u,tg:
|
|
74
|
-
`),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: ${
|
|
75
|
-
`);return
|
|
76
|
-
`),
|
|
77
|
-
`);return
|
|
78
|
-
`),u=["<b>Bound to this machine.</b>","","Your messages now route here. Other senders are not affected.","",
|
|
79
|
-
`);return
|
|
80
|
-
`),f=[`<b>Bound to ${
|
|
81
|
-
`);return
|
|
95
|
+
`)}function ki(e,t,n){let r=ot(Xe()),o=["<b>Computers</b>",""],s=n?Ct(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,mr(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
|
+
`);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 Ri(e,t,n){return mo(e,t,n??null).replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1")}function Ci(e,t){let n=Xe(),r=ot(n),o=ge(),s=e.clusterRole,i=zc(e),a=t?Ct(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 ${vi()})`,`host: ${Si.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(vi())})`,`host: ${ye(Si.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 Zf(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
|
+
`),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 ue(n,r)}function eh(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 Xc(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)?Zf(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||Yr(!0);let d=ge().senderBindings[n]??null,{state:u,resolved:c}=xi(n,a,"chat");if(!c.ok)return He(u,e)?eh(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.","",mo(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.","",ki(u,e,n)].join(`
|
|
103
|
+
`);return ue(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||Yr(!0);let{state:a,resolved:l}=xi(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.","",mo(a,e,n)].join(`
|
|
104
|
+
`),u=["<b>Bound to this machine.</b>","","Your messages now route here. Other senders are not affected.","",ki(a,e,n)].join(`
|
|
105
|
+
`);return ue(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=Ct(e,n);if(a){if(a.nodeId!==s)return null;let c=[...ge().peers,mr(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
|
+
`),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 ue(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}=Vf(n);if(l){if(l.nodeId!==s)return null}else if(!He(d,e))return null;let u=Ct(e,n),c=u?`
|
|
82
108
|
Config default still applies: \`${u.nodeId}\`.`:`
|
|
83
|
-
No config default is set; nobody will answer until you /c use <label-or-id>.`;return
|
|
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=Ci(e,n);return ue(a.wa,a.tg)}if(o==="list"){let a=ge(),l=n?Ct(e,n):null;if(l){if(l.nodeId!==s)return null}else if(!He(a,e))return null;return ue(mo(a,e,n??null),ki(a,e,n??null))}let i=ge();return He(i,e)?p(`Unknown /c subcommand "${o}". Try /c help`):null}function Zc(e,t){return Yr(!0),xi(e,t,"chat")}qe();be();function th(e){return`wa:${e}`}function Mi(e){return`tg:${e}`}function eu(e){return{peerKey:th(e.fromJid),text:e.text,waMessageId:e.messageId,mediaSavedPath:e.mediaSavedPath,mediaError:e.mediaError}}G();function fo(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(`
|
|
84
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(`
|
|
85
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(`
|
|
86
112
|
`);return process.platform==="linux"?o:process.platform==="darwin"?s:process.platform==="win32"?i:[o,"","---","",s].join(`
|
|
87
|
-
`)}
|
|
113
|
+
`)}G();import{execFileSync as jt}from"node:child_process";import Mn from"node:fs";import hr from"node:os";import st from"node:path";import Fe from"node:process";function nn(){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 tu(e){return/[ "'\\\s]/.test(e)?`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:e}function nh(e){return`Environment="OMNISH_HOME=${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function rh(e){return`[Unit]
|
|
88
114
|
Description=omnish gateway (WhatsApp/Telegram)
|
|
89
115
|
After=network-online.target
|
|
90
116
|
Wants=network-online.target
|
|
91
117
|
|
|
92
118
|
[Service]
|
|
93
119
|
Type=simple
|
|
94
|
-
ExecStart=${`${
|
|
95
|
-
${
|
|
120
|
+
ExecStart=${`${tu(e.nodePath)} ${tu(e.scriptPath)} run`}
|
|
121
|
+
${nh(e.omnishHome)}
|
|
96
122
|
Restart=on-failure
|
|
97
123
|
RestartSec=5
|
|
98
124
|
|
|
99
125
|
[Install]
|
|
100
126
|
WantedBy=default.target
|
|
101
|
-
`}function
|
|
127
|
+
`}function fr(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function oh(e){let t=hr.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=fr(e.nodePath),s=fr(e.scriptPath),i=fr(e.omnishHome),a=fr(n),l=fr(r);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
102
128
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
103
129
|
<plist version="1.0">
|
|
104
130
|
<dict>
|
|
@@ -125,34 +151,34 @@ WantedBy=default.target
|
|
|
125
151
|
<string>${l}</string>
|
|
126
152
|
</dict>
|
|
127
153
|
</plist>
|
|
128
|
-
`}function
|
|
154
|
+
`}function ho(){let e=nn();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(hr.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist");j(st.dirname(t));let n=oh(e);Mn.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(hr.homedir(),".config","systemd","user");j(t);let n=st.join(t,"omnish.service"),r=rh(e);return Mn.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 go(){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(hr.homedir(),"Library/LaunchAgents/dev.omnish.gateway.plist"),n=`gui/${typeof Fe.getuid=="function"?Fe.getuid():0}`;if(Mn.existsSync(e)){try{jt("launchctl",["bootout",n,e],{stdio:"pipe"})}catch{}Mn.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(hr.homedir(),".config","systemd","user","omnish.service");try{jt("systemctl",["--user","disable","--now","omnish.service"],{stdio:"pipe"})}catch{}Mn.existsSync(e)&&Mn.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 nu from"node:fs";var yo=48e3;function wo(e,t){try{if(!nu.existsSync(e))return"(no log file yet \u2014 start with `omnish run -d` or the systemd/LaunchAgent service.)";let n=nu.readFileSync(e),o=(n.length>yo?n.subarray(n.length-yo):n).toString("utf8");return n.length>yo&&(o=`\u2026(truncated to last ${yo} bytes)
|
|
129
155
|
${o}`),o.split(/\r?\n/).slice(-t).join(`
|
|
130
|
-
`).trimEnd()||"(empty)"}catch(n){return`Could not read log: ${String(n)}`}}import
|
|
131
|
-
`,{mode:384})}function
|
|
132
|
-
### `)}function
|
|
133
|
-
`).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
|
|
134
|
-
`).trim();if(!n)throw new Error("Recipe body is empty.");let r=n.match(/^--steps\s+([\s\S]+)$/i);if(r){let
|
|
135
|
-
`)}
|
|
136
|
-
`,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
|
|
137
|
-
`,n++;continue}if(o==="t"){t+=" ",n++;continue}if(o==="\\"){t+="\\",n++;continue}}t+=r}return t}function
|
|
138
|
-
[\u2026+${f.length} chars; /apps since ${r} to read more]`,this.pending.set(t,(this.pending.get(t)??"")+f)}let
|
|
156
|
+
`).trimEnd()||"(empty)"}catch(n){return`Could not read log: ${String(n)}`}}import Gt from"node:fs";import Rh from"node:path";G();import sh from"node:crypto";import Pi from"node:fs";import ih from"node:path";var Ai=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,En="__omnish_recipes_global__",Ii=new Set(["help","list","show","add","set","remove","rm","del","run","r","online"]),Tn=new Map,ru=!1;function ah(){try{let e=Pi.readFileSync(Dr,"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))}Tn.set(n,o)}}catch{}}function lh(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=lh(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 ko(){j(ih.dirname(Dr));let e={};for(let[t,n]of Tn)Object.entries(n).length>0&&(e[t]={...n});Pi.writeFileSync(Dr,JSON.stringify(e,null,2)+`
|
|
157
|
+
`,{mode:384})}function So(){ru||(ah(),ru=!0)}function ou(e){return So(),Tn.get(e)??{}}function Ti(e){So();let t=Tn.get(e);return t||(t={},Tn.set(e,t)),t}function ch(e,t){let n=e.taskEnv??"OMNISH_TASK",r=t.recipesMacroDefaultCommand.trim();return rn(r,n).ok?Be({...e,command:r,promptTemplate:e.command}):e}function uh(e,t){if(e.promptTemplate||rn(e.command,t).ok||!Pn(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 Oi(e,t){let n=Be(e),r=n.taskEnv??"OMNISH_TASK";return!n.promptTemplate&&uh(n,r)&&(n=ch(n,t)),n}function dh(e){try{let t=Pi.readFileSync(Ur,"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(!(!Ai.test(i)||Ii.has(i))&&s&&typeof s=="object"&&typeof s.command=="string"){let l=Oi(s,e),d=on(l);if(!d.ok){console.warn(`[omnish] recipes.json: skipping "${i}": ${d.error}`);continue}r[i]=l}}return r}catch{return{}}}function ph(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 bo(e,t,n){for(let[r,o]of Object.entries(t)){let s=r.toLowerCase();!Ai.test(s)||Ii.has(s)||o.command.trim()&&e.set(s,{...o,name:s,source:n})}}function Ei(e,t){let n=ou(e),r={};for(let[o,s]of Object.entries(n)){let i=Oi(s,t);on(i).ok&&(r[o]=i)}return r}function su(e,t){let n=new Map;return bo(n,ph(t),"builtin"),bo(n,dh(t),"global"),bo(n,Ei(En,t),"shared"),bo(n,Ei(e,t),"peer"),n}function je(e,t,n){let r=n.trim().toLowerCase();return su(e,t).get(r)}function iu(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 Li(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 Ni(e){let t=Li(e);return{scope:t.scope,remainder:t.remainder}}function au(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 mh(e){let t=e.trim().toLowerCase();if(t==="--global"||t==="-g")return"global";if(t==="--chat"||t==="-p")return"chat"}function lu(e){let t=e.trim().match(/^(\S+)\s+(--global|-g|--chat|-p)\s*$/i);if(!t?.[1]||!t[2])return;let n=mh(t[2]);if(n)return{name:t[1],target:n}}function Mt(e,t,n,r){let o=r.trim().toLowerCase(),s=e==="global"?En:t,i=ou(s)[o];if(i===void 0)return;let a=Oi(i,n);if(on(a).ok)return{...a,name:o,source:e==="global"?"shared":"peer"}}function cu(e,t,n){if(n==="merged")return[];let r=n==="global"?En:e,o=n==="global"?"shared":"peer",s=Ei(r,t);return Object.entries(s).map(([i,a])=>({...a,name:i,source:o})).sort((i,a)=>i.name.localeCompare(a.name))}function gt(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return Ai.test(n)?Ii.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 vo(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 Pn(e,t){return e.includes("$")?e.includes(t):!1}function rn(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(!Pn(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 on(e){let t=e.taskEnv??"OMNISH_TASK",n=rn(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 fh(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 _i(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}=fh(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=rn(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=rn(c,o);if(!f.ok)throw new Error(f.error);return Be({command:c,promptTemplate:m})}if(rn(n,o).ok)return Be({command:n});let d=t.trim(),u=rn(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 xo(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 An(e,t,n,r="chat",o){let s=gt(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=on(i);if(!d.ok)throw new Error(d.error)}let a=r==="global"?En:e,l=Ti(a);l[s.normalized]=i,ko()}function uu(e,t,n="chat"){let r=t.trim().toLowerCase(),o=n==="global"?En:e;So();let s=Tn.get(o);return!s||!(r in s)?!1:(delete s[r],ko(),!0)}function Fi(e,t,n,r){let o=gt(t);if(!o.ok)return{ok:!1,error:o.error};let s=o.normalized,i=e,a=En;So();let l=Ti(i),d=Ti(a),u=l[s],c=d[s],m=f=>{let h=Be({...f}),g=on(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],ko(),{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],ko(),{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 du(e,t){let n=[...su(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 $o(e){let t=sh.randomBytes(4).toString("hex");return`r-${e.replace(/[^a-zA-Z0-9_-]/g,"").slice(0,12)}-${t}`.slice(0,32)}function pu(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 mu={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 hh(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 gh(e){let t=e.trim();if(!t)return"";if(t.startsWith("\\"))return hh(t);let n=t.toLowerCase();if(mu[n])return mu[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 Ro(e){let t=e.split(",").map(n=>n.trim()).filter(Boolean);return t.length===0?"":t.map(n=>gh(n)).join("")}var gr="\x1B";function Co(e){let t=e;return t=t.replace(new RegExp(`${gr}\\[[\\d;?]*[ -/]*[@-~]`,"g"),""),t=t.replace(new RegExp(`${gr}\\][^${gr}\\u0007]*(?:\\u0007|${gr}\\\\)`,"g"),""),t=t.replace(new RegExp(`${gr}[@-Z\\\\-_]`,"g"),""),t=t.replace(/\u0007/g,""),t}function yh(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 wh(e,t){return`${e}${t}`}var Mo=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=wh(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=Co(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=yh(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 To=4096,bh=/\[sudo\]\s+password\s+for\s+/i,kh=/passphrase\s+for\s+/i,Sh=/(?:^|\n)\s*(?:Password|password):\s*$/;function Eo(e){let n=Co(e).replace(/\r/g,"").slice(-512);return!!(bh.test(n)||kh.test(n)||Sh.test(n))}G();import vh from"node:fs";import xh from"node:path";import*as fu from"node-pty";var $h=1024*1024,Po=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>$h&&this.ringChunks.length>0;){let n=this.ringChunks.shift();this.ringBytes-=n.length}}static start(t){j(nr(t.peerKey));let n=xh.join(nr(t.peerKey),`${t.name}.log`),r=vh.createWriteStream(n,{flags:"a",mode:384}),o={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor",...t.cwd?{PWD:t.cwd}:{},...t.extraEnv??{}},s=fu.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 Wi(e){return new Promise(t=>setTimeout(t,e))}async function Ao(e,t,n){let r=n.appsSubmitDelayMs,o=n.appsClearInputDelayMs,s=n.appsClearInput!==!1,a=n.appsSkipClearOnPasswordPrompt!==!1&&Eo(e.recentOutputTail(To)),l=s&&!a?Ro(n.appsClearInputSequence||"^A,^K"):"",u=t.replace(/\r\n/g,`
|
|
139
165
|
`).replace(/\r/g,"").split(`
|
|
140
|
-
`);
|
|
141
|
-
`).trimEnd()}catch{return""}}var
|
|
142
|
-
`)}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
|
|
143
|
-
Run queue paused; fix the issue, then /run queue resume.`;this.activeQueuedRunHead.set(t,{sessionName:s,recipeLabel:o.recipeLabel});let
|
|
166
|
+
`);l&&(o>0&&await Wi(o),e.write(l));for(let c of u)c.length>0&&e.write(c),r>0&&await Wi(r),e.write("\r"),l&&(o>0&&await Wi(o),e.write(l))}var Ch=/^[a-zA-Z0-9_-]{1,32}$/;function We(e){return Ch.test(e)?null:"Session name must be 1\u201332 chars: letters, digits, _ or -."}function Pe(e,t){return`${e}:${t}`}function Mh(e){let t=e.lastIndexOf(":");return t<=0?null:{peerKey:e.slice(0,t),name:e.slice(t+1)}}function Th(e,t){return e===0&&(t===0||t==null)}function Eh(e,t){try{let r=Gt.readFileSync(e,"utf8").split(/\r?\n/);return r.slice(Math.max(0,r.length-t)).join(`
|
|
167
|
+
`).trimEnd()}catch{return""}}var Jt=class{constructor(t,n){this.getCfg=t;this.send=n,this.router=new Mo({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 Rh.join(nr(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(To);if(!Eo(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 Ao(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 Ao(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=$o(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
|
+
Run queue paused; fix the issue, then /run queue resume.`;this.activeQueuedRunHead.set(t,{sessionName:s,recipeLabel:o.recipeLabel});let d=i>0?`
|
|
144
170
|
Run queue: started head above; ${i} job(s) still waiting in FIFO.`:`
|
|
145
|
-
Run queue: started head above; no further queued jobs.`;return`${a}${
|
|
146
|
-
Example: /apps start sh bash`;if(this.sessions.has(
|
|
147
|
-
If install skipped native builds: pnpm approve-builds && pnpm install (needs @whiskeysockets/baileys, sharp, protobufjs, esbuild, node-pty).`}return this.sessions.set(
|
|
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=Po.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
|
+
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.
|
|
148
174
|
[cwd: ${a}]
|
|
149
|
-
Plain DMs go to this session until /apps detach. Use >othername text for another session.`}async handleSessionExit(t,n,r){let o=
|
|
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=Th(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=Mh(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)"}
|
|
150
176
|
App sessions:
|
|
151
177
|
${n.join(`
|
|
152
|
-
`)}`}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=
|
|
153
|
-
`)}async sendText(t,n,r){let o=
|
|
154
|
-
`);return await
|
|
155
|
-
[...truncated]`}function
|
|
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=Gt.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
|
+
`)}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 Ao(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=Ro(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(!Gt.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 Eh(s,a)||"(empty log)"}readSince(t,n,r){let o=this.logPath(t,n);try{let i=Gt.statSync(o).size,a=Gt.openSync(o,"r");try{let l=Math.min(r,i),d=i-l,u=Buffer.alloc(d);return d>0&&Gt.readSync(a,u,0,d,l),{text:u.toString("utf8"),nextOffset:i}}finally{Gt.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{Gt.rmSync(s,{force:!0})}catch{}return`Removed "${n}" metadata and log.`}};qe();be();import wr from"node:fs";import br from"node:path";import hu from"node:fs";import gu from"node:path";var Ph=new Set(["jpg","jpeg","png","gif","webp","bmp","tif","tiff","heic","avif"]),Ah=new Set(["mp4","mov","webm","mkv","avi","m4v","3gp"]),Ih=new Set(["mp3","ogg","opus","wav","m4a","flac","aac","wma"]),Io={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 Oh(e){let t=e.replace(/^\./,"").toLowerCase();return Ph.has(t)?{category:"image",mimetype:Io[t]??"image/jpeg"}:Ah.has(t)?{category:"video",mimetype:Io[t]??"video/mp4"}:Ih.has(t)?{category:"audio",mimetype:Io[t]??"audio/mpeg"}:{category:"document",mimetype:Io[t]??"application/octet-stream"}}function Kt(e,t){let n;try{n=hu.realpathSync(e)}catch{return{error:"File not found or unreadable."}}let r;try{r=hu.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=gu.basename(n),s=gu.extname(n).slice(1),{category:i,mimetype:a}=Oh(s);return{absPath:n,category:i,mimetype:a,displayName:o}}import Lh from"node:os";import*as wu from"node-pty";function Nh(e,t){return e.length<=t?e:`${e.slice(0,t)}
|
|
181
|
+
[...truncated]`}function _h(e){if(e===void 0||e===0)return null;let t=Lh.constants.signals;for(let[n,r]of Object.entries(t))if(r===e)return n;return null}function yu(e){try{process.platform==="win32"?e.kill():e.kill("SIGTERM")}catch{e.kill()}}function sn(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=wu.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&&yu(l)},n.timeoutMs),u=l.onData(y=>{i+=y,i.length>n.maxBytes&&(i=Nh(i,n.maxBytes),l&&yu(l))}),c=l.onExit(y=>{f({code:y.exitCode,stdout:i,stderr:"",durationMs:Date.now()-o,timedOut:s,signal:_h(y.signal)})})})}function yr(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 Fh(e,t,n){let r=e;for(let o=0;o<14;o++){let s=yr(r,t,n),i=new Date(s).getDay();if(i>=1&&i<=5)return s;r=s}return yr(r,t,n)}function Wh(e,t,n,r){let o=e;for(let s=0;s<370;s++){let i=yr(o,n,r);if(new Date(i).getDay()===t)return i;o=i}return yr(o,n,r)}function Uh(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 Dh(e,t){return e.kind==="ondemand"||e.kind==="heartbeat"?Number.POSITIVE_INFINITY:e.kind==="daily"?yr(t,e.hour,e.minute):e.kind==="weekdays"?Fh(t,e.hour,e.minute):e.kind==="hourly"?Uh(t,e.minute):Wh(t,e.weekday,e.hour,e.minute)}function Su(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=Dh(e,a);if(l>r)break;i.push(l),a=l}return i}var Hh={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 Ui(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 Bh(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 Oo(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=Ui(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=Ui(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=Bh(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=Hh[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=Ui(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=bu(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=bu(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 bu(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 ku(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 In(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 ${ku(e.intervalMs)} grace ${ku(e.graceMs)}`}}G();be();import jh from"better-sqlite3";var vu=2,zt=null;function xu(){j(ut);let e=new jh(Va);e.pragma("journal_mode = WAL"),e.exec(`
|
|
156
182
|
CREATE TABLE IF NOT EXISTS cowork_meta (
|
|
157
183
|
key TEXT PRIMARY KEY,
|
|
158
184
|
value TEXT NOT NULL
|
|
@@ -171,166 +197,185 @@ ${n.join(`
|
|
|
171
197
|
last_ok INTEGER NOT NULL,
|
|
172
198
|
updated_at_ms INTEGER NOT NULL
|
|
173
199
|
);
|
|
174
|
-
`);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<vu&&(n<2&&e.exec(`
|
|
175
201
|
CREATE TABLE IF NOT EXISTS cowork_task_state (
|
|
176
202
|
task_id TEXT PRIMARY KEY,
|
|
177
203
|
last_ok INTEGER NOT NULL,
|
|
178
204
|
updated_at_ms INTEGER NOT NULL
|
|
179
205
|
);
|
|
180
|
-
`),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(vu))),e}function an(e){zt||(zt=xu()),Jh(e)}function $u(){if(zt){try{zt.close()}catch{}zt=null}}function ln(){return zt||(zt=xu()),zt}function Gh(e){let n=ln().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 Lo(e){let t=Gh(e.id);return t??e.lastCompletedSlotMs}function No(e,t){if(t.length===0)return;let n=ln(),r=n.prepare(`
|
|
181
207
|
INSERT INTO cowork_slot_completion (task_id, slot_ms, kind, completed_at_ms, log_path)
|
|
182
208
|
VALUES (?, ?, ?, ?, ?)
|
|
183
|
-
`);n.transaction(()=>{for(let s of t)r.run(e,s.slotMs,s.kind,s.completedAtMs,s.logPath)})()}function
|
|
184
|
-
`,{mode:384}),Gn.renameSync(n,Ho)}function Tt(e,t,n){let r=t.trim().toLowerCase();return e.find(o=>o.name===r&&o.ownerPeerKey===n)}function Bs(){return _l.randomBytes(4).toString("hex")}function Fl(e){W(Xe),Gn.writeFileSync(Bo,JSON.stringify(e,null,2)+`
|
|
185
|
-
`,{mode:384})}function Ul(e){let t=Ds();t.push(e),Fl(t)}function Ds(){try{let e=Gn.readFileSync(Bo,"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 Dl(e){if(e<=0)return{batch:[],remainingAfter:Ds().length};let t=Ds();if(t.length===0)return{batch:[],remainingAfter:0};let n=t.slice(0,e),r=t.slice(e);return Fl(r),{batch:n,remainingAfter:r.length}}function js(e,t){if(e.startsWith("tg:")){let n=e.slice(3);return pr(t.telegramAllowFrom).has(n)}return Ki(dr(t.allowFrom),e.replace(/^wa:/,""))}var jp=8,Hl=12e4,Bl=10,Wp=1e3;function Gp(e){return e.toISOString().replace(/[:.]/g,"-")}function Jp(e){let t="";for(let n of e)n==="*"?t+="[^/\\\\]*":n==="?"?t+="[^/\\\\]":/[.+^${}()|[\]\\]/.test(n)?t+=`\\${n}`:t+=n;return new RegExp(`^${t}$`)}function zp(e,t,n){let r=dn(e,t),o=zn.dirname(r),s=zn.basename(r);if(o.includes("*")||o.includes("?"))return[];if(!s.includes("*")&&!s.includes("?")){try{let c=Jn.statSync(r);if(c.isFile()&&c.mtimeMs>=n)return[r]}catch{}return[]}let i;try{i=Jn.readdirSync(o)}catch{return[]}let a=Jp(s),l=[];for(let c of i){if(!a.test(c))continue;let u=zn.join(o,c);try{let d=Jn.statSync(u);d.isFile()&&d.mtimeMs>=n&&l.push(u)}catch{}}return l}function jl(e,t,n){let r=Rt(e,t.fileSendMaxBytes);return"error"in r?{ok:!1,displayName:n??zn.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 Wl(e,t,n,r){let o=ee(t.ownerPeerKey),s=t.cwd.trim()?t.cwd:o.cwd,i=dn(t.outputDir,o.cwd);try{Jn.mkdirSync(i,{recursive:!0,mode:448})}catch(S){I.warn({err:String(S),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",c=Date.now(),u=await Bt(e.shell,t.command,{timeoutMs:e.syncTimeoutMs,maxBytes:e.syncMaxBytes,cwd:s}),d=Date.now()-c,p=`${Gp(new Date)}-${t.id}-${l}.log`,f=zn.join(i,p),h=[`cowork task=${t.name} id=${t.id}`,`slot=${a} kind=${l}`,`cwd=${s}`,`exit=${u.code} timedOut=${u.timedOut} durationMs=${d}`,"---",""].join(`
|
|
209
|
+
`);n.transaction(()=>{for(let s of t)r.run(e,s.slotMs,s.kind,s.completedAtMs,s.logPath)})()}function Di(e){ln().prepare("INSERT OR REPLACE INTO cowork_task_state (task_id, last_ok, updated_at_ms) VALUES (?, 1, ?)").run(e,Date.now())}function _o(e){return ln().prepare("SELECT updated_at_ms FROM cowork_task_state WHERE task_id = ?").get(e)?.updated_at_ms??null}function Fo(e){let t=ln().prepare("SELECT last_ok FROM cowork_task_state WHERE task_id = ?").get(e);return t==null?null:t.last_ok===1}function Wo(e,t){ln().prepare("INSERT OR REPLACE INTO cowork_task_state (task_id, last_ok, updated_at_ms) VALUES (?, ?, ?)").run(e,t?1:0,Date.now())}function Jh(e){let n=ln().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{No(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 Hi(e,t){if(e.startsWith("tg:")){let n=e.slice(3);return Gr(t.telegramAllowFrom).has(n)}return rl(jr(t.allowFrom),e.replace(/^wa:/,""))}var Kh=8,Ru=12e4,Cu=10,zh=1e3;function qh(e){return e.toISOString().replace(/[:.]/g,"-")}function Yh(e){let t="";for(let n of e)n==="*"?t+="[^/\\\\]*":n==="?"?t+="[^/\\\\]":/[.+^${}()|[\]\\]/.test(n)?t+=`\\${n}`:t+=n;return new RegExp(`^${t}$`)}function Qh(e,t,n){let r=Ge(e,t),o=br.dirname(r),s=br.basename(r);if(o.includes("*")||o.includes("?"))return[];if(!s.includes("*")&&!s.includes("?")){try{let d=wr.statSync(r);if(d.isFile()&&d.mtimeMs>=n)return[r]}catch{}return[]}let i;try{i=wr.readdirSync(o)}catch{return[]}let a=Yh(s),l=[];for(let d of i){if(!a.test(d))continue;let u=br.join(o,d);try{let c=wr.statSync(u);c.isFile()&&c.mtimeMs>=n&&l.push(u)}catch{}}return l}function Mu(e,t,n){let r=Kt(e,t.fileSendMaxBytes);return"error"in r?{ok:!1,displayName:n??br.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 Tu(e,t,n,r){let o=oe(t.ownerPeerKey),s=t.cwd.trim()?t.cwd:o.cwd,i=Ge(t.outputDir,o.cwd);try{wr.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 sn(e.shell,t.command,{timeoutMs:e.syncTimeoutMs,maxBytes:e.syncMaxBytes,cwd:s}),c=Date.now()-d,m=`${qh(new Date)}-${t.id}-${l}.log`,f=br.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(`
|
|
186
210
|
`)+(u.stdout||"")+(u.stderr?`
|
|
187
211
|
--- stderr ---
|
|
188
|
-
${u.stderr}`:"");try{
|
|
189
|
-
`),
|
|
190
|
-
[...input truncated]`}function
|
|
212
|
+
${u.stderr}`:"");try{wr.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=Fo(t.id);O=k===null||k!==y}Wo(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+$/,""),se=(u.stderr||"").trim(),he=X||(se?`(stderr) ${se}`:"(no output)"),D=R==="state-change"?y?" [recovered]":" [failing]":"",ae=`${t.name}${D} : ${A?`[${A}] `:""}${he}`,Y=n.onDemand?[K,`output: ${he}`]:[ae];if(O){let k=[],x=[],L=d-zh,F=[],Q=new Set;if(Array.isArray(T))for(let de of T){let at;try{at=Qh(de,s,L)}catch(lt){M.warn({err:String(lt),pat:de},"cowork attach glob"),k.push(`attach: ${de} skipped (glob error)`);continue}if(at.length!==0)for(let lt of at)Q.has(lt)||(Q.add(lt),F.push(lt))}if(P){let de=Mu(f,e,`${t.name}-${l}.log`);de.ok?x.push(de.spec):k.push(`attach: ${de.displayName} skipped (${de.reason})`)}let z=0;for(let de of F){if(x.length>=Cu){z+=1;continue}let at=Mu(de,e);at.ok?x.push(at.spec):k.push(`attach: ${at.displayName} skipped (${at.reason})`)}z>0&&k.push(`attached: skipped ${z} file(s) over cap ${Cu}`),k.length>0&&Y.push(...k);let we=Y.join(`
|
|
213
|
+
`),Ue=p(we),Ie=kn(E,t.ownerPeerKey,e);for(let de of Ie){let at=ke(Ue,de.startsWith("tg:")?"telegram":"whatsapp").text;try{await r.sendToPeer(de,at)}catch(lt){M.warn({err:String(lt),pk:de},"cowork notify failed")}for(let lt of x)try{await r.sendMediaToPeer(de,lt)}catch($m){M.warn({err:String($m),pk:de,file:lt.displayName},"cowork media notify failed")}}}return{commandOk:y,logPath:f}}function Uo(e){let t=!1;an(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}=cl(Kh);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(!Hi(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 Tu(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();an(h);let g=Date.now();for(let y of h){if(!y.enabled||y.schedule.kind!=="heartbeat"||!Hi(y.ownerPeerKey,c))continue;let b=_o(y.id);if(b===null)continue;let v=b+y.schedule.intervalMs+y.schedule.graceMs;if(g>v){if(Fo(y.id)===!1)continue;Wo(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=kn(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&&Fo(y.id)===!1){Wo(y.id,!0);let R=`${y.name} [heartbeat recovered]`,P=y.notify,T=kn(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(!Hi(y.ownerPeerKey,c)){M.warn({task:y.name,peer:y.ownerPeerKey},"cowork: skipping scheduled run \u2014 owner no longer on allowlist");continue}let b=Lo(y),v=Su(y.schedule,b,y.createdAtMs,g);if(v.length===0)continue;let E=v[v.length-1],R=g-E>Ru;try{u+=1;let{commandOk:P,logPath:T}=await Tu(c,y,{slotMs:E,catchUp:R,onDemand:!1},e);if(P){let O=Date.now(),A=g-E<=Ru?"on_time":"catch_up";if(v.length===1)No(y.id,[{slotMs:E,kind:A,logPath:T,completedAtMs:O}]);else{let X=v.slice(0,-1).map(se=>({slotMs:se,kind:"coalesced",logPath:null,completedAtMs:O}));X.push({slotMs:E,kind:A,logPath:T,completedAtMs:O}),No(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),$u()}}import Vh from"node:fs";import Eu from"node:path";import{fileURLToPath as Xh}from"node:url";var Do=null;function Ze(){if(Do!==null)return Do;let e=Eu.dirname(Xh(import.meta.url)),t=Eu.join(e,"..","package.json"),n=Vh.readFileSync(t,"utf8"),r=JSON.parse(n);return Do=typeof r.version=="string"&&r.version.trim()?r.version.trim():"0.0.0",Do}be();G();import{spawn as Zh}from"node:child_process";import Pu from"node:fs";import Au from"node:path";var eg=new Set(["PATH","HOME","USER","LOGNAME","SHELL","LANG","LC_ALL","LC_CTYPE","LC_MESSAGES","TMPDIR","TZ"]),tg=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 ng(e,t){let n={OMNISH_PEER_KEY:e,OMNISH_CHAT_MESSAGE:t};for(let r of eg){let o=process.env[r];o!==void 0&&(n[r]=o)}for(let[r,o]of Object.entries(process.env))o&&(r.startsWith("OMNISH_")||tg.has(r))&&(n[r]=o);return n}var Iu=new Map;function rg(e,t){let r=(Iu.get(e)??Promise.resolve()).then(t).catch(o=>{M.warn({peerKey:e,err:String(o)},"chat LLM fallback queue task failed")});Iu.set(e,r)}function og(e){te();let t=e.chatLlmWorkDir.trim();if(t){let r=Au.resolve(t);return j(r),{cwd:r,cleanup:()=>{}}}let n=Pu.mkdtempSync(Au.join(H,"chat-llm-"));return{cwd:n,cleanup:()=>{try{Pu.rmSync(n,{recursive:!0,force:!0})}catch{}}}}function sg(e,t){return e.length<=t?e:`${e.slice(0,t)}
|
|
214
|
+
[...input truncated]`}function ig(e,t){let n=[],r=e.stdout.trimEnd(),o=e.stderr.trimEnd();return r&&n.push(r.length>t?`${r.slice(0,t)}
|
|
191
215
|
[...truncated]`:r),o&&(n.push("\u2014 stderr \u2014"),n.push(o.length>t?`${o.slice(0,t)}
|
|
192
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(`
|
|
193
|
-
`)}function
|
|
194
|
-
[...truncated]`;else{let
|
|
195
|
-
[...truncated]`}try{u?.kill("SIGTERM")}catch{}}};try{u=
|
|
196
|
-
${String(
|
|
197
|
-
${String(
|
|
198
|
-
${String(
|
|
199
|
-
${String(
|
|
200
|
-
`,{mode:384})}function
|
|
201
|
-
`)}var
|
|
202
|
-
[spawn error] ${String(
|
|
203
|
-
`)}catch{}});let
|
|
217
|
+
`)}function Ho(e){let t=e&&typeof e=="object"&&"code"in e?String(e.code):"";return t==="EPIPE"||t==="EOF"}function Ou(e){try{e?.stdin?.end()}catch(t){if(!Ho(t))throw t}}function ag(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
|
+
[...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=Zh(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=>{Ho(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&&!Ho(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}Ou(u)})}catch(b){if(!Ho(b)){m({code:null,stdout:a,stderr:`${l}
|
|
222
|
+
${String(b)}`,durationMs:Date.now()-s,timedOut:i,signal:null});return}Ou(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 lg(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}=og(e);try{let a=sg(n,e.chatLlmMaxInputChars),l=ng(t,a),d=e.chatLlmMaxOutputChars,u;e.chatLlmNeedsTty?u=await sn(e.shell,o,{cwd:s,timeoutMs:e.chatLlmTimeoutMs,maxBytes:d,env:l}):u=await ag(e.shell,o,a,{cwd:s,timeoutMs:e.chatLlmTimeoutMs,maxOutChars:d,env:l});let c=ig(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 On(e,t,n,r){M.info({peerKey:t,len:n.length},"chat LLM fallback enqueued"),rg(t,async()=>{await lg(e,t,n,r),M.info({peerKey:t},"chat LLM fallback completed")})}G();import{spawn as cg}from"node:child_process";import ug from"node:crypto";import ze from"node:fs";import Bi from"node:path";var Lu=64,dg=/^[a-zA-Z0-9._-]+$/;function pg(e){let t=e.trim();return t?t.length>Lu?`Job name must be at most ${Lu} characters.`:dg.test(t)?null:"Job name may only use letters, digits, and . _ -":"Job name must not be empty."}function Nu(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=pg(n);if(i)return{error:i}}return s?{cmd:s,name:n,notify:r}:{error:"Add a shell command after the flags."}}function mg(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 Ln(e,t){ze.writeFileSync(e,JSON.stringify(t,null,2)+`
|
|
224
|
+
`,{mode:384})}function kr(e){try{return JSON.parse(ze.readFileSync(e,"utf8"))}catch{return null}}function _u(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 Tt=class{running=new Map;metaPath(t){return Bi.join(tt,`${t}.meta.json`)}logPath(t){return Bi.join(tt,`${t}.log`)}spawnJob(t,n,r={}){te();let o=ug.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=cg(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 Ln(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=kr(i)??c,g={...h,status:h.status==="killed"?"killed":"done",exitCode:m,signal:f??null,finishedAt:new Date().toISOString()};Ln(i,g),r.onComplete&&r.onComplete(g)}),u.on("error",m=>{this.running.delete(o),a.end(()=>{try{ze.appendFileSync(s,`
|
|
226
|
+
[spawn error] ${String(m)}
|
|
227
|
+
`)}catch{}});let h={...kr(i)??c,status:"done",exitCode:null,signal:null,finishedAt:new Date().toISOString()};Ln(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=kr(Bi.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(`
|
|
204
228
|
`);return s.slice(Math.max(0,s.length-n)).join(`
|
|
205
|
-
`).trimEnd()||"(empty log)"}readSince(t,n){let r=this.logPath(t);if(!
|
|
206
|
-
`).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 mg(this.list(),t)}kill(t){let n=this.metaPath(t),r=kr(n);if(!r)return`Unknown job id: ${t}`;let o=this.running.get(t);if(o&&!o.killed)return o.kill("SIGTERM"),Ln(n,{...r,status:"killed",signal:"SIGTERM"}),`Sent SIGTERM to job ${t} (pid ${r.pid??"?"})`;if(r.pid)try{return process.kill(r.pid,"SIGTERM"),Ln(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=kr(this.metaPath(t));r&&Ln(this.metaPath(t),{...r,status:"killed",signal:"SIGTERM"})}this.running.clear()}};import zg from"node:fs";import{Bot as qg,InputFile as Yg}from"grammy";G();import Fu from"node:fs";import Nn from"node:path";function fg(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"_").slice(0,120)||"unknown"}function hg(e){let r=Nn.basename(e.trim()||"file").replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^\.+/,"").slice(0,180);return r.length>0?r:"file"}function gg(e,t){let n=new Date().toISOString().slice(0,10),r=fg(t);return Nn.join(e,r,n)}function _n(e,t,n){let r=gg(e,t);j(r);let o=hg(n),s=Nn.join(r,o);if(!Fu.existsSync(s))return s;let i=Nn.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=Nn.join(r,d),!Fu.existsSync(s))return s}return Nn.join(r,`${a}-${Date.now()}${i}`)}be();import yg from"node:dns";import wg from"node:https";import{URL as bg}from"node:url";function Fn(e){if(e instanceof Error){let t=e.cause;return t!=null?`${e.message} (${String(t)})`:e.message}return String(e)}be();function Wu(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 kg(e,t){let r=t.split("/").filter(o=>o.length>0).map(encodeURIComponent).join("/");return`https://api.telegram.org/file/bot${e}/${r}`}var Uu="omnish (Telegram bot; https://github.com/labKnowledge/whatsLive)";function Sg(e){let t=new bg(e);return new Promise((n,r)=>{let o=wg.request({hostname:t.hostname,port:t.port||443,path:t.pathname+t.search,method:"GET",headers:{"User-Agent":Uu,Accept:"*/*"},lookup(s,i,a){yg.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 Du(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=kg(e.token,r.file_path),s;try{let i=await fetch(o,{headers:{"User-Agent":Uu,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 Sg(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: ${Fn(i)}; IPv4 fallback: ${Fn(a)}).`}}}return n>0&&s.byteLength>n?{error:`Media too large (max ${n} bytes).`}:{buffer:s}}pe();qe();import{downloadMediaMessage as Rg,extensionForMediaMessage as Cg,getContentType as Bo,isJidGroup as Gu,isLidUser as Mg}from"@whiskeysockets/baileys";import Tg from"node:fs";be();var qt=new Map;function vg(){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 xg(e){!e||typeof e!="string"||(vg(),qt.set(e,Date.now()))}function ji(e){xg(e?.key?.id??void 0)}function $g(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 Hu(e){return!$g(e)}function Eg(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 Pg(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 Ju(e){return[Eg(e),Pg(e)].filter(n=>n.trim().length>0).join(`
|
|
230
|
+
`).trim()}function Gi(e){return e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g,"").replace(/\uFEFF/g,"").trim()}function Ku(e){let t=Bo(e??void 0);return t==="imageMessage"||t==="videoMessage"||t==="audioMessage"||t==="documentMessage"||t==="stickerMessage"}function Ag(e){let t=Bo(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 Bu(e){try{if(!e)return"file.bin";let t=Cg(e);return`file${t&&t.length>0?t.startsWith(".")?t:`.${t}`:".bin"}`}catch{return`${(Bo(e??void 0)??"file").replace("Message","")||"file"}.bin`}}function Ig(e){let t=Bo(e??void 0);if(!t)return Bu(e);let n=e?.[t];return n?.fileName&&typeof n.fileName=="string"&&n.fileName.trim()?n.fileName.trim():Bu(e)}async function ju(e,t,n,r){let o=t.message??void 0;if(!Ku(o))return{};let s=r.fileReceiveMaxBytes,i=Ag(o);if(s>0&&i!==void 0&&i>s)return{error:`Media too large (max ${s} bytes).`};let a;try{a=await Rg(t,"buffer",{},{logger:e.logger,reuploadRequest:e.updateMediaMessage})}catch(c){return M.warn({err:String(c),detail:Fn(c)},"whatsapp downloadMediaMessage failed"),{error:`Could not download media from WhatsApp (${Fn(c)}).`}}if(s>0&&a.length>s)return{error:`Media too large (max ${s} bytes).`};let l;try{l=Ft(r,n)}catch(c){return{error:String(c)}}let d=Ig(o),u=_n(l,n,d);try{Tg.writeFileSync(u,a,{mode:384})}catch{return{error:"Could not write media to inbox."}}return{path:u}}async function Og(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(Mg(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 Lg(e){try{if(!$().clusterEnabled)return;let n=Ju(e.message??void 0);if(!n)return;let r=Hc(n);if(!r)return;let o=e.key?.remoteJid??"",s=null;if(o&&!Gu(o)){let i=ee(o);i&&(s=`wa:${i}`)}Qc(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&&(Lg(o),!Hu(s.id)))continue;let i=s.remoteJid;if(!i||Gu(i)||i.toLowerCase().endsWith("@status")||i==="status@broadcast")continue;let l=Gi(Ju(o.message??void 0)),{fromJid:d,fromE164:u}=await Og(e,s),c=`wa:${d}`,m=Ku(o.message??void 0);if(m&&!l){(async()=>{try{let g=$(),y=await ju(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 ju(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 Bg from"node:fs";import Ng from"node:process";import _g,{DisconnectReason as cn,fetchLatestBaileysVersion as Fg,makeCacheableSignalKeyStore as Wg,useMultiFileAuthState as Ug}from"@whiskeysockets/baileys";import Dg from"qrcode-terminal";G();be();var Hg="0.1.0";function Ji(e){return e?.error?.output?.statusCode}async function jo(e={}){te();let t=e.authDir??ne,n=e.verbose===!0,r=sl(),{state:o,saveCreds:s}=await Ug(t),{version:i}=await Fg(),a=_g({version:i,logger:r,printQRInTerminal:!1,browser:["omnish","cli",Hg],auth:{creds:o.creds,keys:Wg(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=Ng.stdout,f=w(m,"\xB7".repeat(42));console.log(V(m,"Scan with WhatsApp \u2192 Linked devices")),console.log(f),Dg.generate(c,{small:!0}),console.log(f)}if(d==="close"){let m=Ji(u);n&&m===cn.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 Wn(e){try{e.end(new Error("omnish: socket closed"))}catch{e.ws?.close()}}function Ki(e){return e?.output?.statusCode??e?.status??e?.error?.output?.statusCode}function Go(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 un(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 Xu=3500,jg=400,qu=18e4,Yu=9e4,Qu=3e5;function zi(e,t=Xu){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(`
|
|
207
231
|
|
|
208
|
-
`);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 Jo(e){return new Promise(t=>setTimeout(t,e))}async function Vu(e,t){await Promise.race([e,Jo(qu).then(()=>{M.warn({jid:t,ms:qu},"whatsapp outbound self-heal: prior send chain waited too long; continuing")})])}async function Gg(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{let i=await un(e.sendMessage(t,{text:n}),Yu,`whatsapp sendMessage timed out after ${Yu}ms`);ji(i);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await Jo(800*s);continue}throw i}throw o}function Jg(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 Kg(e,t,n,r=3){let o;for(let s=1;s<=r;s+=1)try{let i=await un(e.sendMessage(t,n),Qu,`whatsapp sendMedia timed out after ${Qu}ms`);ji(i);return}catch(i){o=i;let a=String(i);if(/not connected|closed|timed out|timeout/i.test(a)&&s<r){await Jo(800*s);continue}throw i}throw o}function Zu(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=Vu(a,o).then(async()=>{let d=zi(i,Xu);for(let u=0;u<d.length;u+=1)await Gg(e,o,d[u]??""),u<d.length-1&&await Jo(jg)}).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=Bg.readFileSync(s.absPath),a=Jg(s,i),l=n.get(o)??Promise.resolve(),d=Vu(l,o).then(async()=>{await Kg(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 ed(e){let t=e.trim();return t?/^\/id(?:@[\w_]+)?$/i.test(t):!1}function td(e){let t=String(e).replace(/\D/g,"");return`Your Telegram user id: ${t}
|
|
209
233
|
Add to allowlist on this gateway host:
|
|
210
|
-
omnish allow tg:${t}`}var
|
|
211
|
-
`));if(
|
|
212
|
-
${
|
|
213
|
-
`),await
|
|
214
|
-
${
|
|
215
|
-
`)}})}async function
|
|
216
|
-
`));for(let r=1;r<=2;r++)try{await
|
|
217
|
-
${
|
|
218
|
-
`);return}catch(o){if(r===1&&
|
|
219
|
-
${
|
|
220
|
-
${
|
|
221
|
-
`),
|
|
222
|
-
${C(
|
|
223
|
-
${
|
|
234
|
+
omnish allow tg:${t}`}var Qg=400;async function nd(e,t,n,r){let o=t(),s=await Du(e,r.fileId,o.fileReceiveMaxBytes);if("error"in s)return{mediaError:s.error};let i;try{i=Ft(o,n)}catch(l){return{mediaError:String(l)}}let a=_n(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 Vg(e){return new Promise(t=>setTimeout(t,e))}async function qi(e,t,n,r={}){let o=new qg(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,Mi(u)),g=f.parseModeHtml,b=(s.get(u)??Promise.resolve()).then(async()=>{let v=zi(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 Vg(Qg)}}).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 Yg(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=Gi([f,h].filter(Boolean).join(`
|
|
235
|
+
`));if(g&&ed(g)){let T=u.from.id;await o.api.sendMessage(c.id,td(T));return}let y=Wu(m),b=Mi(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 nd(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 nd(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 Xg from"node:fs";import Zg from"node:path";function ey(e){let t=Zg.join(e,"creds.json");try{let n=Xg.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 rd(e){let t=ey(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 zo from"node:fs";import et from"node:process";G();G();import od from"node:fs";var ty="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 Ko(e){let t=String(e).toLowerCase();return t.includes("401")||t.includes("logged out")?!0:Ki(e)===cn.loggedOut}function ny(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 Yi(e){let t=!1;for(let n=0;n<3;n++){if(e.signal?.aborted)throw new Error("Pairing cancelled.");let r=await jo({authDir:e.authDir,printQr:e.printQr===!0,verbose:e.verbose===!0,onQr:e.onQr});e.onSocketReady?.(r);try{let o=un(Go(r),6e5,ty);e.signal?await Promise.race([o,ny(e.signal)]):await o;return}catch(o){if(o instanceof Error&&o.message==="Pairing cancelled.")throw o;if(Ki(o)===cn.restartRequired&&!t){t=!0,e.onRestart515?.(),await new Promise(i=>setTimeout(i,1500));continue}throw o}finally{e.onSocketClosed?.(),Wn(r)}}throw new Error("Pairing failed after restart (515) retries.")}async function sd(e){let t=e.authDir??ne;te();for(let n=1;n<=2;n++)try{await Yi({...e,authDir:t});return}catch(r){if(r instanceof Error&&r.message==="Pairing cancelled.")throw r;if(n===1&&Ko(r)){od.rmSync(t,{recursive:!0,force:!0}),od.mkdirSync(t,{recursive:!0,mode:448});continue}throw r}}async function ry(e,t){let n=et.stdout;console.log(`
|
|
236
|
+
${Ce(n,"omnish link")} ${w(n,"\u2014 QR appears below; scan from WhatsApp \u2192 Linked devices.")}
|
|
237
|
+
`),await Yi({authDir:e,verbose:t,printQr:!0,onRestart515:()=>{console.warn(`
|
|
238
|
+
${B(et.stderr,"WhatsApp requested a restart after pairing (code 515). This is normal. Opening a new connection\u2026")}
|
|
239
|
+
`)}})}async function id(e={}){let t=e.authDir??ne,n=e.verbose===!0;te(),e.force&&(zo.rmSync(t,{recursive:!0,force:!0}),zo.mkdirSync(t,{recursive:!0,mode:448}),console.log(`${me(et.stdout,"Cleared saved session (--force).")} ${w(et.stdout,"Requesting a new QR\u2026")}
|
|
240
|
+
`));for(let r=1;r<=2;r++)try{await ry(t,n),console.log(`
|
|
241
|
+
${ce(et.stdout,"Linked.")} ${S(et.stdout,"Session saved. You can run")} ${ce(et.stdout,"omnish run")} ${S(et.stdout,"now.")}
|
|
242
|
+
`);return}catch(o){if(r===1&&Ko(o)){console.warn(`
|
|
243
|
+
${B(et.stderr,"WhatsApp returned logged-out (401). This often happens after Ctrl+C during link or corrupt auth files.")}
|
|
244
|
+
${B(et.stderr,"Clearing auth dir and retrying once with a fresh QR\u2026")}
|
|
245
|
+
`),zo.rmSync(t,{recursive:!0,force:!0}),zo.mkdirSync(t,{recursive:!0,mode:448});continue}throw Ko(o)&&console.error(`
|
|
246
|
+
${C(et.stderr,"Still failing after a clean auth directory. Try:")}
|
|
247
|
+
${w(et.stderr,` pnpm approve-builds && pnpm install
|
|
224
248
|
(pnpm may have skipped Baileys/sharp/protobuf build scripts.)
|
|
225
249
|
Then: omnish link --force
|
|
226
|
-
`)}`),o}}
|
|
227
|
-
|
|
228
|
-
`)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
250
|
+
`)}`),o}}G();import{spawn as oy,spawnSync as sy}from"node:child_process";import Un from"node:fs";import iy from"node:path";import Dn from"node:process";function qo(e,t={}){te(),j(iy.dirname(e));let n=Dn.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=Un.openSync(e,"a"),s=oy(Dn.execPath,[n,...r],{detached:!0,stdio:["ignore",o,o],env:{...Dn.env,OMNISH_BACKGROUND_GATEWAY:"1"}});return Un.closeSync(o),s.unref(),s.pid?{ok:!0,pid:s.pid}:{ok:!1,message:"Failed to start background gateway."}}function Yo(){if(te(),!Un.existsSync(le))return{outcome:"no_pidfile"};let e=Un.readFileSync(le,"utf8").trim(),t=Number(e);if(!Number.isFinite(t)||t<=0){try{Un.unlinkSync(le)}catch{}return{outcome:"invalid_pidfile"}}try{Dn.kill(t,0)}catch{try{Un.unlinkSync(le)}catch{}return{outcome:"stale_cleaned",pid:t}}try{return Dn.kill(t,"SIGTERM"),{outcome:"sent_signal",pid:t}}catch(n){return Dn.platform==="win32"&&sy("taskkill",["/PID",String(t),"/T"],{windowsHide:!0}).status===0?{outcome:"taskkill_ok",pid:t}:{outcome:"failed",message:`could not signal process: ${String(n)}`}}}import pd from"node:crypto";import Vi from"node:fs";import ay from"node:net";qe();be();G();import ud from"node:fs";var ad=Number(process.env.PLATFORM_INBOUND_MEDIA_MAX_BYTES)>0?Number(process.env.PLATFORM_INBOUND_MEDIA_MAX_BYTES):54525952,ld=50;function cd(e){try{return JSON.parse(e)}catch{return null}}function Vo(e){return e.fileSendMaxBytes<=0?8388608:Math.min(e.fileSendMaxBytes,8388608)}function dd(e){if(ud.statSync(e.absPath).size>8388608)throw new Error(`File too large for attached mode (max ${8388608} bytes).`);let n=ud.readFileSync(e.absPath).toString("base64");return{name:e.displayName,mimetype:e.mimetype,category:e.category,dataBase64:n,...e.caption?{caption:e.caption}:{}}}function Qi(e,t,n,r){return t.kind==="texts"?{body:t.bodies.map(s=>ke(s,r).text).filter(s=>s.trim()).join(`
|
|
251
|
+
|
|
252
|
+
`),...n?{messageId:n}:{}}:t.kind==="text"?{body:ke(t.body,r).text,...n?{messageId:n}:{}}:t.kind==="file"?{...n?{messageId:n}:{},files:[dd(t.spec)]}:{...n?{messageId:n}:{},files:t.specs.map(dd)}}var Sr=null;function ly(){try{let e=Vi.readFileSync(hn,"utf8"),t=JSON.parse(e);return typeof t.token=="string"?t.token:""}catch{return""}}function cy(e){Vi.writeFileSync(hn,JSON.stringify(e,null,2)+`
|
|
253
|
+
`,{mode:384})}function uy(){try{Vi.unlinkSync(hn)}catch{}}async function dy(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()?Vo(n):n.fileSendMaxBytes,i=Kt(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=It(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 py(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=It(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=It(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 my(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||!pd.timingSafeEqual(o,s))return{ok:!1,error:"Unauthorized."}}catch{return{ok:!1,error:"Unauthorized."}}return r.op==="sendMedia"?dy(r,t):r.op==="sendText"?py(r,t):{ok:!1,error:"Unsupported operation."}}function Xo(e){if(Sr)return;let t=pd.randomBytes(32).toString("hex"),n=ay.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=ly();my(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};cy(o),M.info({port:r.port},"gateway control listening")}),n.on("error",r=>{M.error({err:String(r)},"gateway control server error")}),Sr=n}function Hn(){if(Sr){try{Sr.close()}catch{}Sr=null,uy()}}be();import fy from"node:crypto";import hy from"node:http";var gy=256*1024;function yy(e,t){if(!e||!t)return!1;try{let n=Buffer.from(e,"utf8"),r=Buffer.from(t,"utf8");return n.length===r.length&&fy.timingSafeEqual(n,r)}catch{return!1}}function wy(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
|
+
result: ${d}
|
|
257
|
+
branch: ${u}${c?`
|
|
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}
|
|
233
259
|
status: ${l}
|
|
234
|
-
ref: ${
|
|
235
|
-
`)}var Vs=null;function co(e,t){if(Vs)return{stop:()=>{}};let n=cf.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(!df(i??a,e.token)){o.writeHead(401,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Unauthorized"}));return}let c="",u=0;r.on("data",d=>{if(u+=d.length,u>uf){o.writeHead(413,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!1,error:"Payload too large"})),r.destroy();return}c+=d.toString("utf8")}),r.on("end",()=>{let d;try{d=JSON.parse(c)}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&&(d.source=f);let y=typeof d.peerKey=="string"&&d.peerKey||t.getDefaultPeerKey();if(!y){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 h=pf(d);t.sendToPeer(y,h).then(()=>{o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify({ok:!0}))},w=>{I.warn({err:String(w)},"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;I.info({port:o,host:e.host},"webhook receiver listening")}),n.on("error",r=>{I.error({err:String(r)},"webhook receiver error")}),Vs=n,{stop:()=>{try{n.close()}catch{}Vs=null}}}de();import ig from"node:crypto";import yi from"node:fs";Se();import $c from"node:fs";function vc(e){try{return JSON.parse(e)}catch{return null}}function Cc(e){if($c.statSync(e.absPath).size>8388608)throw new Error(`File too large for attached mode (max ${8388608} bytes).`);let n=$c.readFileSync(e.absPath).toString("base64");return{name:e.displayName,mimetype:e.mimetype,category:e.category,dataBase64:n,...e.caption?{caption:e.caption}:{}}}function Rc(e,t,n,r){return t.kind==="text"?{body:Pe(t.body,r).text,...n?{messageId:n}:{}}:t.kind==="file"?{...n?{messageId:n}:{},files:[Cc(t.spec)]}:{...n?{messageId:n}:{},files:t.specs.map(Cc)}}j();fo();Se();import kf from"ws";import yf from"ws";var hf=["/platform/device","/control/device"];function go(e){let t=e.replace(/\/$/,"");return hf.map(n=>{let r=new URL(n,t);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.toString()})}function wf(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 Ac(e,t){let n=go(e),r=null;for(let s of n)try{return{ws:await new Promise((a,l)=>{let c=new yf(s,{headers:{Authorization:`Bearer ${t}`}});c.once("open",()=>a(c)),c.once("error",l)}),pathname:new URL(s).pathname}}catch(i){if(r=i instanceof Error?i:new Error(String(i)),wf(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 ho=class{constructor(t){this.options=t}ws=null;stopped=!1;pingTimer=null;registerResolve=null;registerReject=null;registeredAccount=null;getRegisteredAccount(){return this.registeredAccount}async connect(){let{env:t}=this.options,n=new Promise((a,l)=>{this.registerResolve=a,this.registerReject=l}),{ws:r,pathname:o}=await Ac(t.platformUrl,t.token);this.ws=r,o!=="/platform/device"&&I.info({pathname:o},"platform device websocket connected via fallback path"),r.on("message",a=>{this.handleMessage(a.toString())}),r.on("close",()=>{this.stopped||I.warn("platform device websocket closed")});let s=setTimeout(()=>{this.registerReject?.(new Error("Platform device register timeout (15s)"))},15e3);this.send({type:"register",...t.deviceId?{deviceId:t.deviceId}:{},label:process.env.OMNISH_DEVICE_LABEL?.trim()||"default"});let i=await n;return clearTimeout(s),this.pingTimer=setInterval(()=>{this.send({type:"ping"})},3e4),i}async handleMessage(t){let n=vc(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}n.type==="error"&&(I.warn({message:n.message},"platform error"),this.registerReject?.(new Error(n.message)),this.registerResolve=null,this.registerReject=null)}}sendReply(t,n,r,o){this.send({type:"reply",peerKey:t,...n?{body:n}:{},...r?{messageId:r}:{},...o?.length?{files:o}:{}})}sendRoutedReply(t,n){this.send({type:"reply",peerKey:t,...n})}send(t){this.ws?.readyState===kf.OPEN&&this.ws.send(JSON.stringify(t))}stop(){this.stopped=!0,this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null);try{this.ws?.close()}catch{}this.ws=null}};import si from"node:readline/promises";import{stdin as ii,stdout as xo}from"node:process";de();var bf=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;function Oc(e){let t=e.trim().toLowerCase();return t?t.length>63?"Tunnel name must be at most 63 characters.":bf.test(t)?null:"Tunnel name may only use letters, digits, and hyphens.":"Tunnel name must not be empty."}function Lc(e){let t=Number.parseInt(e,10);return!Number.isInteger(t)||t<1||t>65535?null:t}function Pc(e,t){let n="127.0.0.1",r,o,s=!1,i=[];for(let c=0;c<t.length;c++){let u=t[c];if(u==="--host"){let d=t[++c];if(!d)return{kind:"error",message:"--host requires an address."};n=d;continue}if(u.startsWith("--host=")){n=u.slice(7);continue}if(u==="--relay"){let d=t[++c];if(!d)return{kind:"error",message:"--relay requires a URL."};r=d;continue}if(u.startsWith("--relay=")){r=u.slice(8);continue}if(u==="--name"){let d=t[++c];if(!d)return{kind:"error",message:"--name requires a slug."};o=d;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=Lc(a);if(l===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};if(o){let c=Oc(o);if(c)return{kind:"error",message:c}}return{kind:"expose",options:{kind:e,port:l,host:n,relayUrl:r??"",name:o,background:s}}}function ni(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 c=n[l];if(c==="--email"){o=n[++l];continue}if(c.startsWith("--email=")){o=c.slice(8);continue}if(c==="--phone"){s=n[++l];continue}if(c.startsWith("--phone=")){s=c.slice(8);continue}if(c==="--password"){i=n[++l];continue}if(c.startsWith("--password=")){i=c.slice(11);continue}if(c==="--relay"){a=n[++l];continue}if(c.startsWith("--relay=")){a=c.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 c=0;c<n.length;c++){let u=n[c];if(u==="--token"){o=n[++c];continue}if(u.startsWith("--token=")){o=u.slice(8);continue}if(u==="--email"){s=n[++c];continue}if(u.startsWith("--email=")){s=u.slice(8);continue}if(u==="--phone"){i=n[++c];continue}if(u.startsWith("--phone=")){i=u.slice(8);continue}if(u==="--password"){a=n[++c];continue}if(u.startsWith("--password=")){a=u.slice(11);continue}if(u==="--relay"){l=n[++c];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"?Pc("http",n):r==="tcp"?Pc("tcp",n):{kind:"error",message:`Unknown tunnel subcommand "${t}". Try: omnish tunnel help`}}function Sf(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 Nc(e){let t=e.trim();if(!t||t==="help")return{kind:"help"};let n=Sf(t),r=n[0]?.toLowerCase();if(r==="login"||r==="logout"||r==="status"||r==="signup")return ni(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=Lc(s[2]);if(a===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};let l=s[3],c=s[4]??"127.0.0.1";if(l){let u=Oc(l);if(u)return{kind:"error",message:u}}return{kind:"expose",options:{kind:i,port:a,host:c,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 vf from"ws";import{URL as _c}from"node:url";function Sn(e){let t=new _c(e);return t.protocol=t.protocol==="https:"?"wss:":"ws:",(!t.pathname||t.pathname==="/")&&(t.pathname="/control"),t.toString()}function Fc(e){return new _c("/health",e).toString()}async function yo(e,t,n=1e4){let r=t.trim();if(!r)return{ok:!1,healthOk:!1,controlOk:!1,error:"Tunnel token is missing."};let o=Fc(e),s=!1,i;try{let c=await fetch(o,{method:"GET",signal:AbortSignal.timeout(n)});if(!c.ok)return{ok:!1,healthOk:!1,controlOk:!1,error:`Health HTTP ${c.status} (${o})`};let u=await c.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(c){return{ok:!1,healthOk:!1,controlOk:!1,error:`Health fetch failed: ${String(c)}`}}let a=Sn(e),l=!1;try{await new Promise((c,u)=>{let d=new vf(a,{headers:{Authorization:`Bearer ${r}`}}),p=setTimeout(()=>{d.terminate(),u(new Error("WSS auth timeout"))},n);d.once("message",f=>{clearTimeout(p);try{let y=JSON.parse(f.toString());if(y.type!=="auth_ok"){u(new Error(`Expected auth_ok, got ${y.type??"?"}`));return}d.close(),c()}catch(y){u(y)}}),d.once("error",f=>{clearTimeout(p),u(f)})}),l=!0}catch(c){return{ok:!1,healthOk:!0,healthVersion:i,controlOk:!1,error:`Control WebSocket: ${String(c)}`}}return{ok:!0,healthOk:s,healthVersion:i,controlOk:!0}}import Hc from"node:crypto";import xf from"node:http";import $f from"node:net";import Et from"ws";function wo(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 Uc(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 ri(e){try{let t=JSON.parse(e);return!t||typeof t!="object"||typeof t.type!="string"?null:t}catch{return null}}function vn(e){return JSON.stringify(e)}function Cf(e){let t=Hc.createHash("sha1").update(e,"utf8").digest("hex").slice(0,8);return Number.parseInt(t,16)>>>0}var ko=class{constructor(t){this.opts=t;let n=Hc.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=Sn(this.opts.relayUrl),n=new Et(t,{headers:{Authorization:`Bearer ${this.opts.token}`}});this.ws=n,await new Promise((o,s)=>{let i=c=>{l(),s(c)},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===Et.OPEN&&n.send(vn({type:"ping"}))},3e4),n.send(vn({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=ri(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=ri(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=Uc(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!==Et.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=xf.request(o,a=>{let l=[];a.on("data",c=>l.push(Buffer.isBuffer(c)?c:Buffer.from(c))),a.on("end",()=>{let c=Buffer.concat(l);n.send(vn({type:"http_res",requestId:t.requestId,status:a.statusCode??502,headers:a.headers,...c.length>0?{bodyBase64:c.toString("base64")}:{}})),s()})});i.on("error",a=>{n.send(vn({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!==Et.OPEN)return;let r=Cf(t);this.tcpStreamIds.set(t,r);let o=$f.connect({host:this.opts.expose.host,port:this.opts.expose.port});this.tcpStreams.set(t,o),o.on("data",s=>{n.readyState===Et.OPEN&&n.send(wo(2,r,Buffer.isBuffer(s)?s:Buffer.from(s)))}),o.on("close",()=>{n.readyState===Et.OPEN&&n.send(wo(3,r)),this.tcpStreams.delete(t),this.tcpStreamIds.delete(t)}),o.on("error",()=>{n.readyState===Et.OPEN&&n.send(wo(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===Et.OPEN&&(t.send(vn({type:"unregister",id:this.record.id})),t.close()),this.cleanupTcpStreams(),this.setStatus("stopped")}};var bo=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=tt();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||Je(t.tunnelRelayUrl||be),i=new ko({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 Bc(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 So(e,t){let n=new URL("/auth/signup",e).toString();return Bc(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}function vo(e,t){let n=new URL("/auth/login",e).toString();return Bc(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}var xn=new bo;function zt(){return xn}function Rf(e){let t=[B(e,"omnish tunnel"),g(e,"Expose local HTTP or TCP ports through the omnish relay."),"",B(e,"Usage:"),` ${k(e,"omnish tunnel signup [--email <email>] [--phone <phone>] [--password <pass>] [--relay <url>]")}`,` ${k(e,"omnish tunnel login [--token <token>] [--relay <url>]")}`,` ${k(e,"omnish tunnel login --email <email> --password <pass> [--relay <url>]")}`,` ${k(e,"omnish tunnel logout")}`,` ${k(e,"omnish tunnel status [--relay <url>]")}`,` ${k(e,"omnish tunnel http <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]")}`,` ${k(e,"omnish tunnel tcp <port> [--host <addr>] [--name <slug>] [--relay <url>] [--background]")}`,` ${k(e,"omnish tunnel list")}`,` ${k(e,"omnish tunnel stop <id|slug>")}`,"",g(e,"Secrets live in ~/.omnish/tunnel-auth.json or OMNISH_TUNNEL_TOKEN."),g(e,`Default relay: ${be}`),""];console.log(t.join(`
|
|
236
|
-
`))}async function
|
|
237
|
-
${
|
|
238
|
-
`,{mode:384})}function
|
|
239
|
-
`).replace(/\n/g," ").trim();return t?t.length>
|
|
240
|
-
Script: ${s.scriptPath}`,u=["*Service status*","",`platform: ${
|
|
241
|
-
`),
|
|
242
|
-
`);return
|
|
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 Xi=null;function Zo(e,t){if(Xi)return{stop:()=>{}};let n=hy.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(!yy(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>gy){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=wy(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")}),Xi=n,{stop:()=>{try{n.close()}catch{}Xi=null}}}pe();import Yw from"node:crypto";import Pa from"node:fs";be();import by from"node:fs";function md(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 by.writeFileSync(i,o,{mode:384}),{mediaSavedPath:i}}catch{return{mediaError:"Could not write media to inbox."}}}G();rs();be();import ra from"ws";import $y from"ws";var xy=["/platform/device","/control/device"];function os(e){let t=e.replace(/\/$/,"");return xy.map(n=>{let r=new URL(n,t);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.toString()})}var Ry=Math.ceil(ad*1.4)+512*1024;function Cy(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 wd(e,t){let n=os(e),r=null;for(let s of n)try{return{ws:await new Promise((a,l)=>{let d=new $y(s,{headers:{Authorization:`Bearer ${t}`},maxPayload:Ry});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)),Cy(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 My=1e3,Ty=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 wd(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(My*2**this.reconnectAttempt,Ty);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=cd(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===ra.OPEN){this.sendRaw(t);return}if(this.outboundQueue.length>=ld){M.warn("platform outbound queue full; dropping reply");return}this.outboundQueue.push(t)}flushOutboundQueue(){for(;this.outboundQueue.length>0&&this.ws?.readyState===ra.OPEN;){let t=this.outboundQueue.shift();t&&this.sendRaw(t)}}sendRaw(t){this.ws?.readyState===ra.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 aa from"node:readline/promises";import{stdin as la,stdout as ps}from"node:process";pe();var Ey=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;function kd(e){let t=e.trim().toLowerCase();return t?t.length>63?"Tunnel name must be at most 63 characters.":Ey.test(t)?null:"Tunnel name may only use letters, digits, and hyphens.":"Tunnel name must not be empty."}function Sd(e){let t=Number.parseInt(e,10);return!Number.isInteger(t)||t<1||t>65535?null:t}function bd(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=Sd(a);if(l===null)return{kind:"error",message:"Port must be an integer between 1 and 65535."};if(o){let d=kd(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 oa(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"?bd("http",n):r==="tcp"?bd("tcp",n):{kind:"error",message:`Unknown tunnel subcommand "${t}". Try: omnish tunnel help`}}function Py(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 vd(e){let t=e.trim();if(!t||t==="help")return{kind:"help"};let n=Py(t),r=n[0]?.toLowerCase();if(r==="login"||r==="logout"||r==="status"||r==="signup")return oa(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=Sd(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=kd(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 Ay from"ws";import{URL as xd}from"node:url";function jn(e){let t=new xd(e);return t.protocol=t.protocol==="https:"?"wss:":"ws:",(!t.pathname||t.pathname==="/")&&(t.pathname="/control"),t.toString()}function $d(e){return new xd("/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=$d(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 Ay(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 Md from"node:crypto";import Iy from"node:http";import Oy 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 Rd(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 sa(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=Md.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=Md.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=sa(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=sa(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=Rd(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=Iy.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=Oy.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 Td(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 Td(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 Td(n,{...t.email?{email:t.email}:{},...t.phone?{phone:t.phone}:{},password:t.password})}var Jn=new cs;function dn(){return Jn}function Ny(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 _y(){let e=aa.createInterface({input:la,output:ps});try{return(await e.question("Tunnel token: ")).trim()}finally{e.close()}}async function Ed(e){let t=oa(e),n=ps,r=process.stderr;if(t.kind==="help"){Ny(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=aa.createInterface({input:la,output:ps});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 us(s,{...a?{email:a}:{},...l?{phone:l}:{},password:d});if(!u.ok){console.error(C(r,u.error)),process.exitCode=1;return}ft({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=aa.createInterface({input:la,output:ps});try{let d=t.password||(await l.question("Password: ")).trim(),u=await ds(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}ft({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 _y();if(!i){console.error(C(r,"Tunnel token is required.")),process.exitCode=1;return}ft({token:i,...t.relayUrl?{relayUrl:t.relayUrl}:{}}),console.log(B(n,"Tunnel token saved."));return}if(t.kind==="logout"){lo(),console.log(B(n,"Tunnel token removed."));return}if(t.kind==="status"){let s=t.relayUrl||rt(o.tunnelRelayUrl||$e),i=ht(),a=!!process.env.OMNISH_TUNNEL_TOKEN?.trim(),l=await is(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(Jn.getActiveCount()))}`);return}if(t.kind==="list"){let s=Jn.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 Jn.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 Jn.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 Jn.stop(i.id),a()};process.once("SIGINT",l),process.once("SIGTERM",l)}))}}function Pd(e){let t=e.trim().match(/^(\d+)\.(\d+)\.(\d+)/);return t?[Number(t[1]),Number(t[2]),Number(t[3])]:null}function Ad(e,t){let n=Pd(e),r=Pd(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 Fy="https://registry.npmjs.org",Id=null,ca=0;function vr(){return Id}function Wy(e){let t=e.trim();return t.length<1||t.length>214?!1:!/\s/.test(t)}function Od(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 Uy(e){let t=e.trim(),n=`${Fy}/${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 Dy(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=Od(d)),{message:a,link:l}}catch(t){return{error:`updateInfoUrl: ${String(t)}`}}}function Hy(e){return!Number.isFinite(e)||e<36e5?36e5:e>6048e5?6048e5:Math.floor(e)}async function xr(e,t){let n=Wy(t.updateCheckPackageName)?t.updateCheckPackageName.trim():"omnish",r=await Uy(n),o="version"in r?r.version:null,s="error"in r?r.error:null,i=!1;o&&!s&&(i=Ad(e,o)<0);let a=null,l=null,d=null,u=Od(t.updateInfoUrl);if(u){let m=await Dy(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 Id=c,c}function ms(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 fs(e){let t=!1,n=async()=>{if(t)return;let s=e.getConfig();if(!s.updateCheckEnabled)return;let i=Hy(s.updateCheckIntervalMs),a=Date.now();if(!(ca!==0&&a-ca<i)){ca=a;try{let l=await xr(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)}}pe();pe();function Qt(e){return(e??"").trim()}function By(){return Qt(process.env.OMNISH_PLATFORM_URL)||Qt(process.env.OMNISH_COMM_LAYER_URL)||Qt(process.env.OMNISH_TUNNEL_RELAY)}function jy(){return Qt(process.env.OMNISH_TOKEN)||Qt(process.env.OMNISH_DEVICE_TOKEN)||Qt(process.env.OMNISH_TUNNEL_TOKEN)}function ua(){return ht()}function Kn(){return jy()?"env":$().platformToken.trim()?"config":xt()?.token?"file":"default"}function $r(){let e=$();return ti(e.tunnelRelayUrl||$e)}function zn(){return By()?"env":$().tunnelRelayUrl.trim()?"config":xt()?.relayUrl?.trim()?"file":"default"}function da(){let e=Qt(process.env.OMNISH_DEVICE_ID);if(e)return e;let t=$().platformDeviceId.trim();if(t)return t}function pa(){return Qt(process.env.OMNISH_DEVICE_ID)?"env":$().platformDeviceId.trim()?"config":"default"}function fe(){let e=$r(),t=ua();if(!e||!t)return null;let n=da();return{platformUrl:e.replace(/\/$/,""),token:t,deviceId:n}}import Ld from"node:path";import{glob as Gy,stat as Jy}from"node:fs/promises";function hs(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 Ky(e){return/[*?[]/.test(e)}function zy(e){return e.split(",").map(t=>t.trim()).filter(t=>t.length>0)}async function Rr(e,t){let n=zy(t),r=new Set,o=[];for(let s of n){if(Ky(s)){for await(let a of Gy(s,{cwd:e,withFileTypes:!1})){let l=Ld.resolve(e,a);r.has(l)||(r.add(l),o.push(l))}continue}let i=Ld.resolve(e,s);r.has(i)||(r.add(i),o.push(i))}return o}async function Cr(e){for(let t of e)try{if(!(await Jy(t)).isFile())return{ok:!1,error:`Not a file: ${t}`}}catch{return{ok:!1,error:`File not found: ${t}`}}return{ok:!0}}G();import Fd from"node:fs";import qy from"node:path";var pn="__omnish_shortcuts_global__",Nd=500,Wd=/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/,Yy=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"]),Mr=new Map,_d=!1;function Qy(){try{let e=Fd.readFileSync(Wr,"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())}Mr.set(n,o)}}catch{}}function gs(){j(qy.dirname(Wr));let e={};for(let[t,n]of Mr)Object.entries(n).length>0&&(e[t]={...n});Fd.writeFileSync(Wr,JSON.stringify(e,null,2)+`
|
|
264
|
+
`,{mode:384})}function ys(){_d||(Qy(),_d=!0)}function Vy(e){return Yy.has(e.trim().toLowerCase())}function wt(e){let t=e.trim();if(!t)return{ok:!1,error:"Name is empty."};let n=t.toLowerCase();return Wd.test(n)?Vy(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 ma(e){let t=e.replace(/\r\n/g,`
|
|
265
|
+
`).replace(/\n/g," ").trim();return t?t.length>Nd?{ok:!1,error:`Body too long (max ${Nd} characters).`}:{ok:!0,body:t}:{ok:!1,error:"Body is empty."}}function yt(e,t){ys();let n=Mr.get(e);return!n&&t&&(n={},Mr.set(e,n)),n??{}}function Ud(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 fa(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 ha(e){let t=fa(e);return{scope:t.scope,remainder:t.remainder}}function Dd(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 Xy(e){let t=e.trim().toLowerCase();if(t==="--global"||t==="-g")return"global";if(t==="--chat"||t==="-p")return"chat"}function Hd(e){let t=e.trim().match(/^(\S+)\s+(--global|-g|--chat|-p)\s*$/i);if(!t?.[1]||!t[2])return;let n=Xy(t[2]);if(n)return{name:t[1],target:n}}function Zy(e,t){ys();let n=e,r=yt(n,!1),o=yt(pn,!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 Bd(e,t="merged"){return Zy(e,t)}function ga(e,t){let n=t.trim().toLowerCase(),r=yt(e,!1)[n];return r!==void 0?r:yt(pn,!1)[n]}function ws(e,t){let n=wt(t);if(!n.ok)return;let r=n.normalized,o=yt(e,!1)[r];if(o!==void 0)return{name:r,body:o,scope:"chat"};let s=yt(pn,!1)[r];if(s!==void 0)return{name:r,body:s,scope:"global"}}function Et(e,t,n){let r=n.trim().toLowerCase(),o=e==="global"?pn:t;return yt(o,!1)[r]}function Tr(e,t,n,r="chat"){let o=wt(t);if(!o.ok)throw new Error(o.error);let s=ma(n);if(!s.ok)throw new Error(s.error);let i=r==="global"?pn:e,a=yt(i,!0);a[o.normalized]=s.body,gs()}function jd(e,t,n="chat"){let r=t.trim().toLowerCase(),o=n==="global"?pn:e;ys();let s=Mr.get(o);return!s||!(r in s)?!1:(delete s[r],gs(),!0)}function ya(e,t,n){let r=wt(t);if(!r.ok)return{ok:!1,error:r.error};let o=r.normalized,s=e;ys();let i=yt(s,!0),a=yt(pn,!0),l=i[o],d=a[o];if(n==="global"){if(l!==void 0){let u=ma(l);return u.ok?(a[o]=u.body,delete i[o],gs(),{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=ma(d);return u.ok?(i[o]=u.body,delete a[o],gs(),{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 Gd(e){let t=e.trim();return t.length>0&&!/\s/.test(t)&&Wd.test(t.toLowerCase())}import Jd from"node:fs";var Kd=64,ew=1024*1024;function zd(e){return e.fileReceiveMaxBytes>0?e.fileReceiveMaxBytes:ew}function qd(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>Kd)return{ok:!1,error:`Too many jobs (max ${Kd}).`};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 Yd(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(!Pn(a.command,l))return{ok:!1,error:`Job ${o+1}: recipe "${s}" command must reference "$${l}".`};let d=vo(i,t.recipesMaxTaskChars);if(!d.ok)return{ok:!1,error:`Job ${o+1}: ${d.error}`};let u=a.promptTemplate?xo(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 wa(e,t){let n;try{n=Jd.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:Jd.readFileSync(e,"utf8")}}catch(r){return{ok:!1,error:String(r)}}}G();import Qd from"node:fs";import qn from"node:process";var tw=120;function Pt(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Vd(e){let t=e.trim();return t==="/service"||t.startsWith("/service ")?t.slice(8).trim():null}async function Xd(e,t){let n=t.trim().split(/\s+/),r=(n[0]??"").toLowerCase();if(!t.trim()||r==="help")return Z(nc(e));if(r==="status"){let s=nn(),i=(()=>{try{return Qd.existsSync(le)?`gateway.pid: ${Qd.readFileSync(le,"utf8").trim()}`:"gateway.pid: (missing)"}catch(m){return`gateway.pid: (read error: ${String(m)})`}})(),a=qn.env.OMNISH_BACKGROUND_GATEWAY==="1"?"This process: background gateway (OMNISH_BACKGROUND_GATEWAY=1).":"This process: foreground gateway session.",l=typeof qn.env.OMNISH_HOME=="string"&&qn.env.OMNISH_HOME.trim()?`OMNISH_HOME env: ${qn.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: ${qn.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>${Pt(qn.platform)}</code>`,`<br/><code>${Pt(a)}</code>`,`<br/><code>${Pt(l)}</code>`,`<br/>data dir: <code>${Pt(H)}</code>`,`<br/><code>${Pt(i)}</code>`,`<br/>default log: <code>${Pt(Ne)}</code>`,"",`<pre>${Pt(d)}</pre>`,"",e.serviceInstallFromChat?"Install from chat: enabled.":"Install from chat: off \u2014 <code>/config set serviceInstallFromChat true</code>."].join(`
|
|
268
|
+
`);return ue(u,c)}if(r==="instructions"){let s=nn();if(s.error)return p(s.error);let i=fo(s);return p(`*Install hints*
|
|
243
269
|
|
|
244
|
-
${i}`)}if(r==="logs"){let s=n.length>=2?Number.parseInt(n[1],10):80,i=Number.isFinite(s)&&s>0?Math.min(s,
|
|
245
|
-
${
|
|
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,tw):80,a=wo(Ne,i),l=[`*Gateway log* (last ${i} lines)
|
|
271
|
+
${Ne}
|
|
246
272
|
`,"```",a,"```"].join(`
|
|
247
|
-
`),
|
|
273
|
+
`),d=`<b>Gateway log</b> (last ${i} lines)<br/><code>${Pt(Ne)}</code><pre>${Pt(a)}</pre>`;return ue(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=ho();return p(s.ok?`*Installed*
|
|
248
274
|
${s.detail}`:`*Install failed*
|
|
249
|
-
${s.detail}`)}if(r==="uninstall"){if(!e.serviceInstallFromChat)return
|
|
250
|
-
${s.detail}`)}return
|
|
251
|
-
`))}function
|
|
252
|
-
`)
|
|
253
|
-
`))}
|
|
254
|
-
`))}let
|
|
255
|
-
`))}
|
|
256
|
-
`))}
|
|
257
|
-
`))}if(!
|
|
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=go();return p(`*Uninstall*
|
|
276
|
+
${s.detail}`)}return p("Unknown /service command. Try /service help")}pe();function bs(){let e=fe();return e?.platformUrl?e.platformUrl.replace(/\/$/,""):($().tunnelRelayUrl||$e).trim().replace(/\/$/,"")}function ks(){let e=fe();return e?.token?{Authorization:`Bearer ${e.token}`}:{}}async function Er(e){try{return await e.json()}catch{return{error:`HTTP ${e.status}`}}}function nw(){return`Set platform URL: omnish config add tunnelRelayUrl ${$e} \u2014 publish: omnish platform login`}function ba(){return fe()?.token?{ok:!0}:{ok:!1,error:`Publish requires a platform account token. ${nw()}`}}async function Zd(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=`${bs()}/v1/catalog/trending${n?`?${n}`:""}`,o=await fetch(r,{headers:ks()}),s=await Er(o);return o.ok?s:{error:s.error??`HTTP ${o.status}`}}async function ep(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=`${bs()}/v1/catalog/search?${n}`,o=await fetch(r,{headers:ks()}),s=await Er(o);return o.ok?s:{error:s.error??`HTTP ${o.status}`}}async function tp(e){let t=encodeURIComponent(e.trim()),n=`${bs()}/v1/catalog/${t}`,r=await fetch(n,{headers:ks()}),o=await Er(r);return r.ok?o:{error:o.error??`HTTP ${r.status}`}}async function np(e){let t=encodeURIComponent(e.trim()),n=`${bs()}/v1/catalog/${t}/download`,r=await fetch(n,{method:"POST",headers:ks()}),o=await Er(r);return r.ok?o:{error:o.error??`HTTP ${r.status}`}}async function rp(e){let t=ba();if(!t.ok)return{error:t.error};let n=fe(),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 Er(o);return o.ok?s:{error:s.error??`HTTP ${o.status}`}}function op(e){return e==="global"?"global":"chat"}function sp(e,t,n,r="global"){switch(e.kind){case"recipe":{let o=e.payload,s=Be({...o,dangerous:void 0}),i=on(s);if(!i.ok)return{ok:!1,error:i.error};let a=gt(e.name);if(!a.ok)return{ok:!1,error:a.error};try{An(t,a.normalized,s,op(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=gt(e.name);if(!i.ok)return{ok:!1,error:i.error};try{An(t,i.normalized,s,op(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=wt(e.name);if(!s.ok)return{ok:!1,error:s.error};try{Tr(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:sr(),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 ip(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 ap(e){let{dangerous:t,...n}=e;return Be(n)}var ka=new Map;function Sa(e,t){return`${e}:${t}`}function va(e,t,n){ka.set(Sa(e,t),n)}function lp(e,t){return ka.get(Sa(e,t))}function Ss(e,t,n){let r=Number.parseInt(n,10);if(!Number.isFinite(r)||r<1)return null;let o=ka.get(Sa(e,t));return!o||r>o.length?null:o[r-1].publicId}function mn(e){return!!(e&&typeof e=="object"&&typeof e.error=="string")}function vs(e,t){return`${e.commandPrefix} online ${t}`}function cp(e){let t=o=>vs(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 xs(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: ${vs(n,"<publicId> download")} \u2014 or ${vs(n,"trending <n> download")}`),p(r.join(`
|
|
279
|
+
`))}function up(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("",vs(t,`${e.publicId} download`)),p(n.join(`
|
|
280
|
+
`))}var xa=new Set(["recipe","app","cowork","shortcut"]),rw={commandPrefix:"/run",listScope:"run"},dp={commandPrefix:"/apps",defaultKind:"app",listScope:"apps"},pp={commandPrefix:"/cowork",defaultKind:"cowork",listScope:"cowork"},mp={commandPrefix:"/shortcut",defaultKind:"shortcut",listScope:"shortcut"};function ow(e){if(!e)return;let t=e.toLowerCase();return xa.has(t)?t:void 0}function At(e,t){return`${e.commandPrefix} online ${t}`}function sw(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=ow(t);return t&&!n?{error:`Unknown kind "${t}". Use: recipe, app, cowork, shortcut`}:n}function iw(e,t){if(e.defaultKind){if(t.length>1&&xa.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&&xa.has(t[t.length-1].toLowerCase())&&(n=t.pop().toLowerCase()),{kind:n,query:t.join(" ")}}async function Yn(e,t,n,r){let o=e.trim();if(!o||/^help$/i.test(o))return cp(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=Ss(t,r.listScope,f[1]),!m)return p(`No trending list in this chat \u2014 run ${At(r,"trending")} first, or use ${At(r,"<publicId> download")}.`)}else if(h){if(m=Ss(t,r.listScope,h[2]),!m)return p(`No search list in this chat \u2014 run ${At(r,"search <query>")} first, or use ${At(r,"<publicId> download")}.`)}else if(/^\d+$/.test(d)){if(m=Ss(t,r.listScope,d),!m)return p(`No list item #${d}. Run trending or search first, or use ${At(r,"<publicId> download")}.`)}else m=d;let g=await np(m);if(mn(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=sp(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 tp(i[1]);return mn(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]}.`):up(d,r)}let a=/^trending(?:\s+(\S+))?\s*$/i.exec(o);if(a){let d=sw(r,a[1]);if(typeof d=="object"&&"error"in d)return p(d.error);let u=await Zd(d?{kind:d}:void 0);if(mn(u))return p(`Trending failed: ${u.error}`);va(t,r.listScope,u.items);let c=r.defaultKind?`Trending (${r.defaultKind})`:"Trending";return xs(u.items,c,r)}let l=/^search\s+([\s\S]+)$/i.exec(o);if(l){let d=l[1].trim().split(/\s+/),u=iw(r,d);if("error"in u)return p(u.error);let{kind:c,query:m}=u;if(!m)return p(`Usage: ${At(r,"search <query>")}`);let f=await ep(m,c?{kind:c}:void 0);return mn(f)?p(`Search failed: ${f.error}`):(va(t,r.listScope,f.items),xs(f.items,`Search: ${m}`,r))}if(/^list\s*$/i.test(o)){let d=lp(t,r.listScope);return d?.length?xs(d,"Last list",r):p(`No cached list. ${At(r,"trending")} or ${At(r,"search <query>")}`)}return p(`Unknown ${r.commandPrefix} online command. ${At(r,"help")}`)}async function fp(e,t,n){return Yn(e,t,n,rw)}function Pr(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 aw(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:ap(t)}}function hp(e,t,n,r){let o=Pr(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:aw(i.name,i,o)}:{ok:!1,error:`Unknown recipe "${n}".`}}function gp(e,t,n){let r=Pr(n),o=ws(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 yp(e,t,n){let r=Pr(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:ip(s)}}:{ok:!1,error:`Unknown cowork task "${t}" for this chat.`}}function wp(e,t,n){let r=Pr(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 Qn(e){let t=ba();if(!t.ok)return{ok:!1,error:t.error};let n=await rp(e);if(mn(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 lw(){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 bp(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 cw(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 Sp(e,t,n){let r=e.trim();if(!r||/^help$/i.test(r))return lw();let o=/^online\b([\s\S]*)$/i.exec(r);if(o)return Yn((o[1]??"").trim(),t,n,pp);let s=/^(\S+)\s+publish\b([\s\S]*)$/i.exec(r);if(s){let f=yp(t,s[1],s[2]??"");if(!f.ok)return p(f.error);let h=await Qn(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} ${In(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();an(h);let g=Ye(h,f,t);if(!g)return p(`Unknown task "${f}". /cowork list`);let y=Lo(g),b=[`name: ${g.name}`,`id: ${g.id}`,`schedule: ${In(g.schedule)}`,`enabled: ${g.enabled}`,`notify: ${g.notify}`,`notifyWhen: ${g.notifyWhen??"always"}`];if(g.schedule.kind==="heartbeat"){let v=_o(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=js(h[1]);if(!T.ok)return p(T.error);let O=h[2].split(/\s+/).filter(Boolean),A=Oo(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=Qr(T.name),se={id:sr(),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(se),Oe(K),an(K),Di(se.id),p([`Saved heartbeat task "${T.name}" (${In(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=cw(f);if("error"in g)return p(g.error);let y=js(g.name);if(!y.ok)return p(y.error);let b=Oo(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=Qr(y.name),P={id:sr(),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}" (${In(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?(ll({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();an(h);let g=Ye(h,f,t);return g?g.schedule.kind!=="heartbeat"?p(`"${g.name}" is not a heartbeat task.`):(Di(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 kp(c[1],t,!0);let m=r.match(/^disable\s+(\S+)\s*$/i);return m?kp(m[1],t,!1):/^set$/i.test(i)?mw(r.slice(3).trim(),t):p("Unknown /cowork command. Try /cowork help")}function kp(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 uw(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 dw(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 pw(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 mw(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=Oo(a);return l.ok?(i.schedule=l.schedule,Oe(s),p(`Schedule for "${i.name}": ${In(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=uw(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=dw(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=bp(a);if(l.length!==1)return p("Usage: /cowork set <name> attach on|off");let d=pw(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=bp(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")}pe();import Lw from"node:fs";G();import vp from"node:os";import fw from"node:path";var hw=new Set(["create","delete","rename","update"]);function gw(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 yw(e){let t=e.split(",").map(n=>n.trim().toLowerCase());return t.length===0?!1:t.every(n=>hw.has(n))}function ww(e){return e.split(",").map(t=>t.trim().toLowerCase())}function $a(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,"/")}:fw.isAbsolute(o)||r.startsWith("~")||r.startsWith("./")||r.startsWith("../")?{path:o}:r.startsWith("/")?{path:o}:{glob:r.includes("/")?r:`**/${r}`}}function xp(e,t=vp.homedir()){let n=e.replace(/\s+&&\s+/g," ").trim(),r=gw(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=$a(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=$a(u,c,t);m.path?a.push(m.path):m.glob&&l.push(m.glob),o+=1;continue}if(yw(u)){i=ww(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 Ra(e,t,n=vp.homedir()){let r=$a(e.startsWith("-")?e:`-${e}`,t,n);return!r.path&&!r.glob?{error:"Empty exclude pattern."}:r}import{spawnSync as $s}from"node:child_process";import $p from"node:fs";import bw from"node:os";import kw from"node:path";var Sw=40,vw=10,Rs=15e3,xw=["~/Projects","~/deploy","~/Downloads","~/src","/var/www","/srv"],Rp={linux:"/var/log/dpkg.log (also /var/log/apt/history.log)",darwin:"/var/log/install.log",win32:"Windows Application event log (install/remove)"};function $w(e){return e.startsWith("~/")?kw.join(bw.homedir(),e.slice(2)):e}function Rw(e,t){return t?.trim()?e.toLowerCase().includes(t.trim().toLowerCase()):!0}function Cw(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 Mw(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 Tw(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 Ew(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 Pw(){let e=$s("systemctl",["list-units","--type=service","--all","--no-pager","--plain","--no-legend"],{encoding:"utf8",timeout:Rs});return e.error||e.status!==0?{entries:[],error:"systemctl unavailable \u2014 install systemd or run on Linux."}:{entries:Mw(e.stdout??"")}}function Aw(){let e=$s("launchctl",["list"],{encoding:"utf8",timeout:Rs});return e.error||e.status!==0?{entries:[],error:"launchctl unavailable."}:{entries:Tw(e.stdout??"")}}function Iw(){let e=$s("sc",["query","type=","service","state=","all"],{encoding:"utf8",timeout:Rs,windowsHide:!0});if(!e.error&&e.status===0&&(e.stdout??"").includes("SERVICE_NAME"))return{entries:Ew(e.stdout??"")};let t=$s("powershell",["-NoProfile","-Command","Get-Service | ForEach-Object { $_.Name + ' ' + $_.Status }"],{encoding:"utf8",timeout:Rs,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 Cs(e){let t=e?.limit??Sw,n=e?.filter,r,o=process.platform;if(o==="linux")r=Pw();else if(o==="darwin")r=Aw();else if(o==="win32")r=Iw();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=Cw(r.entries.filter(l=>Rw(l.name,n))),i=s.length,a=i>t;return{entries:s.slice(0,t),truncated:a,totalMatched:i}}function Ow(e,t=vw){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}function Ca(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 Ma(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=Ow(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 Cp(){let e=process.platform,t=e==="linux"?"linux":e==="darwin"?"darwin":"win32",n=["Watch hints",""];n.push("Package log (pkg watches):"),n.push(` ${Rp[t]??Rp.linux}`),n.push("","Filesystem roots that exist on this host:");let r=[];for(let o of xw){let s=$w(o);try{$p.existsSync(s)&&$p.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 Nw(...e){return{replies:e}}function _w(e){let t=e.trim();if(!t)return{};let n=t.split(/\s+/);if(n.length>=2){let s=Zr(n[0]);return s.ok?{ruleName:s.name,filter:n.slice(1).join(" ")}:{filter:t}}let r=n[0],o=Zr(r);if(o.ok){let s=Cs({filter:r,limit:1});if(s.totalMatched===0&&!s.error)return{ruleName:o.name}}return{filter:r}}function Fw(){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 Mp(){return{excludePaths:[],excludeGlobs:[]}}function Ww(e){return e.notify==="self"?`notify=self (${e.ownerPeerKey})`:`notify=${e.notify}`}function Uw(e,t){qs(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 Tp(e,t){let n=e.trim();if(!n||/^help$/i.test(n))return U(Fw());let r=n.split(/\s+/)[0].toLowerCase();if(Vr(),/^hints$/i.test(r))return U(Cp());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=Cs({filter:f});return h.error?U(p(h.error)):h.entries.length===0?U(Ca(h,f)):Nw(Ca(h,f),Ma(h.entries))}if(m==="templates"){let f=u.slice(9).trim(),{ruleName:h,filter:g}=_w(f),y=Cs({filter:g});return y.error?U(p(y.error)):U(Ma(y.entries,h))}return U(p("svc subcommands: list [filter] | templates [ruleName] [filter]"))}if(/^status$/i.test(r)){let u=$(),{summary:c}=ar(),m=[`watchEnabled: ${u.watchEnabled} watchAutoRestore: ${u.watchAutoRestore}`,`debounce: ${u.watchDebounceMs}ms max/min: ${u.watchMaxEventsPerMinute}`,`rules file: ${Ks()} (${c.total} saved, ${c.active} active, ${c.paused} paused, ${c.disabled} disabled)`,`events db: ${Hr}`];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=Fl();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}=ar();return $().watchEnabled?(Wl(),U(p(`Reloading from ${Ks()}: ${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} ${Ww(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=fl(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=Zt(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=Zt(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
|
+
`):"(none)"}`,`excludeGlobs: ${h.excludeGlobs.length?h.excludeGlobs.join(`
|
|
299
|
+
`):"(none)"}`];return U(p(g.join(`
|
|
300
|
+
`)))}if(c==="add"){if(!m)return U(p("Usage: /watch exclude <name> add <pattern>"));let g=Ra(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),pt(Sn(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=Ra(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)),pt(Sn(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=Zr(h);if(!g.ok)return U(p(g.error));let y=Le();if(y.length>=Js)return U(p(`Max ${Js} watch rules on this device.`));if(Zt(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=xp(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(!Lw.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:eo(),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:eo(),name:g.name,ownerPeerKey:t,kind:"pkg",enabled:!0,paused:!1,notify:"self",notifyWhen:"always",path:"",events:[],units:[],...Mp(),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:eo(),name:g.name,ownerPeerKey:t,kind:"svc",enabled:!0,paused:!1,notify:"self",notifyWhen:"always",path:"",events:[],units:R,...Mp(),adapterStatus:"",createdAtMs:Date.now()}}pt(Sn(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=Zt(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 pt(Sn(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=Zt(c,u);return m?(qs(m.id),pt(kl(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=Zt(m,c);if(!f)return U(p(`Unknown rule "${c}".`));Uw(f,u==="stop"?"pause":u),pt(Sn(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"))}pe();function Ep(){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 Ta(e,t,n){let r=vd(e);if(r.kind==="help")return Ep();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 us(l,{...o?{email:o}:{},...s?{phone:s}:{},password:i});return d.ok?(ft({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 ds(l,{...r.email?{email:r.email}:{},...r.phone?{phone:r.phone}:{},password:i});return d.ok?(ft({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?(ft({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 lo(),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=ht(),a=!!process.env.OMNISH_TUNNEL_TOKEN?.trim(),d=!!xt()?.token?.trim(),u=await is(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
|
+
`))}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}
|
|
258
303
|
${s.publicUrl||"(pending)"}
|
|
259
304
|
${s.localHost}:${s.localPort}`).join(`
|
|
260
305
|
|
|
261
|
-
`))}if(r.kind==="stop"){let o=await n.stop(r.target);return o?
|
|
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
|
|
262
307
|
public: ${o.publicUrl}
|
|
263
308
|
local: ${o.localHost}:${o.localPort}
|
|
264
|
-
id: ${o.id}`)}return
|
|
265
|
-
`))}async function
|
|
266
|
-
${
|
|
309
|
+
id: ${o.id}`)}return Ep()}function Ea(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 Dw(e,t){return`${e}:${t}`}function Hw(e,t){return`${e}:apps:${t}`}async function Bw(e,t){let n=e.trim();if(n===""||/^status$/i.test(n)||/^show$/i.test(n)||/^get$/i.test(n)){let a=$();return oc({gatewayMode:a.gatewayMode,authPresent:nt(),tokenSet:!!ve(a),allowN:a.allowFrom.length,tgAllowN:a.telegramAllowFrom.length,updateBrief:ms(vr())})}if(/^help$/i.test(n))return Z(ii());let r=gn(n);if(!r)return kc();qr(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 uc(o.gatewayMode,s,i)}function jw(e){let t=e.trim();if(!dt(t))return cc();let n=Ot(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.'),lc(r)}async function Pp(e,t,n){let r=oe(t),o=Jl(n);if(o!==null){let a=Kl(r.cwd,o),l=zl(a);return l.ok?(ro(t,a),p(`cwd: ${a}`)):p(`cd: ${l.error}`)}let s=await sn(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 Vn(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(yc())):(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&&Gd(g)){let y=ga(m,g);if(y!==void 0)return await Vn(e,t,n,r,o,{...s,text:y},i,a,l,!0,u)}return I(await Pp(e,m,g))}if(/^\/help\s+files$/i.test(c.trim()))return I(ci());if(c==="/help"||c==="help")return I(Z(xn(e)));if(c.startsWith("/")){if(/^\/files(?:\s+help)?$/i.test(c.trim()))return I(ci());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)){Xs(m,"sessionCwd");let F=oe(m).cwd;return I(p(`Inbound files will save under this chat\u2019s session folder:
|
|
311
|
+
${F}
|
|
267
312
|
(layout: \u2026/<peer>/<date>/<file> under that root).
|
|
268
313
|
|
|
269
|
-
Change folder with ${e.commandPrefix}cd \u2026 Send /receive default to use the server config again.`))}return
|
|
270
|
-
Notify on completion: on`:"";return
|
|
271
|
-
[cwd: ${
|
|
272
|
-
/log ${
|
|
273
|
-
/tail ${
|
|
274
|
-
${
|
|
314
|
+
Change folder with ${e.commandPrefix}cd \u2026 Send /receive default to use the server config again.`))}return L.has(k)?(Xs(m,"default"),I(p("Per-chat inbound folder cleared. Uploads now follow fileReceiveRootMode in config.json (/files)."))):I(k==="help"?ui():k==="status"?fc(e,m):ui())}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=vr();return I(L?cr(L):p("No update snapshot yet. Send /updates (live check) once, or enable updateCheckEnabled and wait for the scheduled check."))}let x=await xr(Ze(),$());return I(cr(x))}let y=c.match(/^\/security(?:\s+(\S+))?\s*$/i);if(y){let k=(y[1]??"").toLowerCase(),x=$(),L=Rt(x);return I(k==="help"||k==="?"?Z(Ic()):k==="summary"||k==="brief"?p(ec(L,"Send /security for the full report.")):k==="tips"?Z(Ac()):k===""||k==="full"||k==="report"?Pc(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 Bw(k,a))}if(c==="/config"||c.startsWith("/config ")){let k=c.slice(7).trim();return I(await Fc(k,a))}let v=Vd(c);if(v!==null)return I(await Xd(e,v));let E=Ea(c);if(E!==null){let k=Xc(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(li());let x=hs(k);if(!x)return I(li());let L=oe(m).cwd,F=await Rr(L,x.selectorPart);if(F.length===0)return I(p(`No files matched: ${x.selectorPart}`));let Q=await Cr(F);if(!Q.ok)return I(p(Q.error));let z=fe()?Vo(e):e.fileSendMaxBytes,we=[];for(let Ue of F){let Ie=Kt(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(ac([{label:"allowFrom (WhatsApp)",items:k.allowFrom},{label:"telegramAllowFrom",items:k.telegramAllowFrom}]))}let P=c.match(/^\/allow\b\s+(.+)$/i);if(P)try{let k=Kr(P[1].trim());return I(ai(k))}catch(k){return I(p(String(k)))}if(/^\/allow\b\s*$/i.test(c))return I(dc());let T=c.match(/^\/deny\b\s+(.+)$/i);if(T)try{let k=zr(T[1].trim());return I(ai(k))}catch(k){return I(p(String(k)))}if(/^\/deny\b\s*$/i.test(c))return I(pc());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(jw(Q[1]??"")):x===""||/^help$/i.test(x)?I(Z(ic($()))):I(gc())}if(L)return x===""||/^help$/i.test(x)?I(Z(sc(e))):I(hc())}let A=c.match(/^\/(cowork|cw)\b(?:\s+([\s\S]*))?$/i);if(A){let k=(A[2]??"").trim();return I(await Sp(k,m,e))}let K=c.match(/^\/watch\b(?:\s+([\s\S]*))?$/i);if(K){let k=(K[1]??"").trim(),x=Tp(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 qw(c,m,e,i,r));let X=Gw(c);if(X!==null)return I(await Kw(X,m,e,i,s.mediaSavedPath,u));if(c.startsWith("/bg")){let k=c.slice(3).trim();if(!k)return I(mc());let x=Nu(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 de=_u(Ie);u.sendToPeer(m,de).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
|
+
Notify on completion: on`:"";return I(p(`Job ${we} started.
|
|
316
|
+
[cwd: ${L}]
|
|
317
|
+
/log ${z.name??Q}
|
|
318
|
+
/tail ${z.name??Q}${Ue}`))}if(c==="/tunnels")return I(await Ta("list",e,dn()));let se=c.match(/^\/tunnel\b(?:\s+([\s\S]*))?$/i);if(se){let k=(se[1]??"").trim();return I(await Ta(k||"help",e,dn()))}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
|
+
${x.cmd.slice(0,120)}${x.cmd.length>120?"\u2026":""}`}).join(`
|
|
275
320
|
|
|
276
|
-
`)))}let
|
|
277
|
-
(Gateway-shared recipe exists: /run show --global ${
|
|
278
|
-
(This chat stores an override: /run show --chat ${
|
|
279
|
-
/run remove --global ${
|
|
280
|
-
`))}if(/^queue$/i.test(i))return
|
|
281
|
-
`).trim(),
|
|
282
|
-
(Shared shortcut exists: /shortcut show --global ${
|
|
283
|
-
(This chat overrides the name: /shortcut show --chat ${
|
|
284
|
-
/shortcut remove --global ${
|
|
285
|
-
`,{mode:384})}catch(
|
|
286
|
-
${C(process.stderr,"shutting down\u2026")}`),process.exit(0)};process.on("SIGINT",
|
|
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=Dw(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 ae=c.match(/^\/kill\s+(\S+)\s*$/i);if(ae){let k=ae[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=ga(m,x);if(L!==void 0)return await Vn(e,t,n,r,o,{...s,text:L},i,a,l,!0,u)}}return I(wc(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 Pp(e,m,c)):e.chatLlmFallbackEnabled&&e.chatLlmShellCommand.trim().length>0&&u?.onPlainTextLlmFallback?(u.onPlainTextLlmFallback(m,c),null):I(bc(e))}function Gw(e){return e==="/run"||e.startsWith("/run ")?e.slice(4).trim():e==="/r"||e.startsWith("/r ")?e.slice(2).trim():null}function Jw(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 Kw(e,t,n,r,o,s){let i=e.trim();if(!i||/^help$/i.test(i))return Z(Rc());let a=/^online\b([\s\S]*)$/i.exec(i);if(a)return fp((a[1]??"").trim(),t,n);let l=/^(\S+)\s+publish\b([\s\S]*)$/i.exec(i);if(l){let b=hp(t,n,l[1],l[2]??"");if(!b.ok)return p(b.error);let v=await Qn(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}=au(b);if(E)return p(`Unknown /run list suffix: "${E}". Use: list | list --chat | list -p | list --global | list -g`);if(v==="merged")return Cc(du(t,n));let R=cu(t,n,v);return Ec(R,v)}let u=/^show\b([\s\S]*)$/i.exec(i);if(u){let b=(u[1]??"").trim(),{mode:v,remainder:E}=iu(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 se=je(t,n,P);return se?mi(se):fi(P)}let T=v==="global"?"global":"chat",O=Mt(T,t,n,P);if(O)return mi(O,T==="global"?"From gateway-shared recipes (--global).":"From this chat only (--chat).");let A=T==="chat"&&Mt("global",t,n,P)?`
|
|
322
|
+
(Gateway-shared recipe exists: /run show --global ${P})`:"",K=T==="global"&&Mt("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}=Ni((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=_i(E[2],n.recipesMacroDefaultCommand);An(t,E[1],R,b);let P=gt(E[1]),T=P.ok?P.normalized:E[1].toLowerCase(),O=Mt(b,t,n,T)??je(t,n,T);return O?dr(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}=Li((m[1]??"").trim()),R=lu(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=gt(R.name);if(!O.ok)return p(O.error);let A=Fi(t,O.normalized,R.target,n);if(!A.ok)return p(A.error);if(A.kind==="noop")return p(A.message);let K=Mt(A.target,t,n,O.normalized)??je(t,n,O.normalized);return K?dr(O.normalized,K,A.target):p("Recipe scope update failed.")}let P=v.match(/^(\S+)\s*$/);if(P?.[1]&&E){let O=gt(P[1]);if(!O.ok)return p(O.error);let A=Fi(t,O.normalized,b,n);if(!A.ok)return p(A.error);if(A.kind==="noop")return p(A.message);let K=Mt(A.target,t,n,O.normalized)??je(t,n,O.normalized);return K?dr(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=_i(T[2],n.recipesMacroDefaultCommand);An(t,T[1],O,b);let A=gt(T[1]),K=A.ok?A.normalized:T[1].toLowerCase(),X=Mt(b,t,n,K)??je(t,n,K);return X?dr(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}=Ni((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 uu(t,R,b)?Mc(R,b):b==="chat"&&Mt("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}`):Tc(R,b)}let h=/^queue\s+load\b([\s\S]*)$/i.exec(i);if(h){let b=(h[1]??"").trim(),v=zd(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 Rr(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 se=await Cr(X);if(!se.ok)return p(se.error);let he=wa(X[0],v);if(!he.ok)return p(he.error);E=he.text}else if(o){let A=wa(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=qd(E);if(!P.ok)return p(P.error);let T=Yd(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=Jw(i);if(g){let{recipe:b,task:v,queued:E}=g,R=je(t,n,b);if(!R)return fi(b);if(R.steps&&R.steps.length>0){let X=oe(t).cwd,se=R.steps.length,he=R.steps;if(s?.sendToPeer){let D=s.sendToPeer;(async()=>{let ae=[],Y=!1;for(let x=0;x<he.length;x++){let L=he[x];if(Y){ae.push({index:x,label:L.label??`step ${x+1}`,cmd:L.cmd,exitCode:null,timedOut:!1,skipped:!0,output:""});continue}let F=await sn(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;ae.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=pu(b,ae);await D(t,k)})().catch(()=>{})}return p(`Runbook "${b}" started (${se} steps). Results will be sent when complete.`)}let P=R.taskEnv??"OMNISH_TASK";if(!Pn(R.command,P))return p(`Recipe "${b}" command must reference "$${P}".`);let T=vo(v,n.recipesMaxTaskChars);if(!T.ok)return p(T.error);let O=R.promptTemplate?xo(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=$o(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(di());let o=/^online\b([\s\S]*)$/i.exec(r);if(o)return Yn((o[1]??"").trim(),t,n,mp);let s=/^(\S+)\s+publish\b([\s\S]*)$/i.exec(r);if(s){let c=gp(t,s[1],s[2]??"");if(!c.ok)return p(c.error);let m=await Qn(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}=Dd(c);return f?p(`Unknown /shortcut list suffix: "${f}". Use: list | list --chat | list -p | list --global | list -g`):Sc(Bd(t,m))}let a=/^show\b([\s\S]*)$/i.exec(r);if(a){let c=(a[1]??"").trim(),{mode:m,remainder:f}=Ud(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=ws(t,g);if(!P)return xc(g);let T=P.scope==="global"?"Shared shortcut (all chats use it unless this chat overrides the name).":"This chat only.";return pi(g,P.body,T)}let y=m==="global"?"global":"chat",b=Et(y,t,g);if(b!==void 0)return pi(g,b,y==="global"?"From the shared shortcut list (--global / -g).":"From this chat only (--chat / -p).");let v=y==="chat"&&Et("global",t,g)!==void 0?`
|
|
327
|
+
(Shared shortcut exists: /shortcut show --global ${g})`:"",E=y==="global"&&Et("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}=ha((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{Tr(t,f[1],f[2],c);let h=wt(f[1]),g=h.ok?h.normalized:f[1].trim().toLowerCase(),y=Et(c,t,g)??"";return ur(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}=fa((d[1]??"").trim()),h=Hd(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=wt(h.name);if(!b.ok)return p(b.error);let v=ya(t,b.normalized,h.target);if(!v.ok)return p(v.error);if(v.kind==="noop")return p(v.message);let E=Et(v.target,t,b.normalized)??"";return ur(b.normalized,E,v.target)}let g=m.match(/^(\S+)\s*$/);if(g?.[1]&&f){let b=wt(g[1]);if(!b.ok)return p(b.error);let v=ya(t,b.normalized,c);if(!v.ok)return p(v.error);if(v.kind==="noop")return p(v.message);let E=Et(v.target,t,b.normalized)??"";return ur(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{Tr(t,y[1],y[2],c);let b=wt(y[1]),v=b.ok?b.normalized:y[1].trim().toLowerCase(),E=Et(c,t,v)??"";return ur(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}=ha((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 jd(t,h,c)?vc(h,c):c==="chat"&&Et("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}`):$c(h,c)}return Z(di())}async function qw(e,t,n,r,o){let s=e.slice(5).trim(),i=s.toLowerCase();if(!i||i==="help")return Z(hi());let a=s.match(/^(\S+)\s*(.*)$/s);if(!a)return Z(hi());let l=a[1].toLowerCase(),d=(a[2]??"").trim();if(l==="online")return Yn(d,t,n,dp);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=wp(c,m,u[1]??"");if(!f.ok)return p(f.error);let h=await Qn(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=Hw(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 Ap(e,t,n){return!e.clusterEnabled||Ea(t.trim())!==null?!0:n?Vc(n,e):!1}be();qe();function Ip(){return p("Not allowlisted on this omnish device.")}async function Ar(e,t,n,r,o,s,i,a,l,d,u,c){if((c?.surface??(s.peerKey.startsWith("tg:")?"telegram":"whatsapp"))==="telegram"){let f=Gr(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:Ip()});return}}else{let f=jr(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:Ip()});return}}try{if(!!!(s.mediaSavedPath||s.mediaError)&&!Ap(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 Vn(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 Qw(){if(process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{Pa.readFileSync(le,"utf8").trim()===String(process.pid)&&Pa.unlinkSync(le)}catch{}}async function Op(e){let t=new Tt,n=new Map,r=new Map,o=new Map,s=null,i=new Map,a=async(D,ae)=>{let Y=i.get(D);s?.sendReply(D,ae,Y)},l=async(D,ae)=>{let Y=D.startsWith("tg:")?"telegram":"whatsapp",k=i.get(D),x=Qi(D,{kind:"file",spec:ae},k,Y);s?.sendRoutedReply(D,x)},d=async(D,ae)=>{let Y=i.get(D),k=D.startsWith("tg:")?"telegram":"whatsapp";s?.sendReply(D,ke(p(ae),k).text,Y)},u={onPlainTextLlmFallback(D,ae){On($(),D,ae,Y=>a(D,Y))},sendToPeer:a},c=new Jt(()=>$(),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 ss({env:e,onReplyError:async(D,ae,Y)=>{let k=D.startsWith("tg:")?"telegram":"whatsapp";s?.sendReply(D,ke(p(`Error sending: ${ae}`),k).text,Y)},onMessage:async D=>{let ae=ta(),Y=D.peerKey;i.set(Y,D.messageId);let k=D.surface==="telegram"?"telegram":"whatsapp",x=D.senderE164&&k==="whatsapp"?`wa:${D.senderE164}`:Y;yn()&&M.info({peerKey:Y,senderKey:x,surface:k},"platform inbound message");let L=D.mediaSavedPath,F=D.mediaError;if(D.inboundMedia){let z=md(ae,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 Ar(ae,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=Qi(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{Pa.writeFileSync(le,`${process.pid}
|
|
330
|
+
`,{mode:384})}catch(D){M.warn({err:String(D)},"could not write gateway pidfile")}Xo({getCfg:()=>$(),getWaOutbound:()=>null,getTgSendMedia:()=>null,getTgSendText:()=>null,sendPlatformMedia:l,sendPlatformText:d});let f=null,h=$();if(h.webhookEnabled){let D=h.webhookToken||Yw.randomBytes(32).toString("hex");h.webhookToken||W({webhookToken:D}),f=Zo({port:h.webhookPort,host:h.webhookHost,token:D},{sendToPeer:a,getDefaultPeerKey:()=>null}).stop}let g=fs({getRunningVersion:Ze,getConfig:$,log:M}),y=Uo({getConfig:$,sendToPeer:a,sendMediaToPeer:l}),b=no({getConfig:$,sendToPeer:a}),{deviceId:v,account:E}=await s.connect(),R=await ns(e,E??null),P=5*60*1e3,T=setInterval(()=>{ns(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 na(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,se=[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}`:"")+(se?` \u2014 ${se}`:""));let he=()=>{clearInterval(T),y(),b(),g?.(),f?.(),Qw(),Hn(),s?.stop(),c.dispose(),t.killAllRunning(),dn().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 Aa(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)}}pe();G();function Ms(){if(fe()){let i=$(),a=Rt(i);return lr(a)?{ok:!1,message:`Fix security errors before starting the gateway.
|
|
287
332
|
|
|
288
|
-
${a.filter(u=>u.severity==="error").map(u=>{let
|
|
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(`
|
|
289
334
|
`)}).join(`
|
|
290
335
|
|
|
291
|
-
`)}`}:{ok:!0}}let e=$(),t=e.gatewayMode,n=t==="whatsapp"||t==="both",r=t==="telegram"||t==="both",o=
|
|
292
|
-
config: ${
|
|
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=Rt(e);return lr(s)?{ok:!1,message:`Fix security errors before starting the gateway (or change gatewayMode / token).
|
|
293
338
|
|
|
294
|
-
${s.filter(l=>l.severity==="error").map(l=>{let
|
|
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(`
|
|
295
340
|
`)}).join(`
|
|
296
341
|
|
|
297
|
-
`)}`}:{ok:!0}}
|
|
298
|
-
`))}function
|
|
299
|
-
`));return}let i=
|
|
300
|
-
`));return}if(n==="list"){let r=await
|
|
301
|
-
`))}async function
|
|
302
|
-
`));return}let o=
|
|
303
|
-
`,{mode:384});try{
|
|
304
|
-
`,{mode:384});try{
|
|
305
|
-
`,{mode:384}),r}
|
|
306
|
-
`,{mode:384})}function
|
|
342
|
+
`)}`}:{ok:!0}}G();import As from"node:fs";import Is from"node:path";pe();import{spawn as Vw}from"node:child_process";import Lp from"node:fs";import{stdout as Xw}from"node:process";G();var Ia=["tunnelRelayUrl","platformToken","platformDeviceId"],Np=[{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 Es(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 _p(e){return e.split(/[,\s]+/).map(t=>t.trim()).filter(Boolean)}function Oa(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 Ts(e,t){if(e==="clusterSenderBindings")return JSON.stringify(t.clusterSenderBindings);let n=String(t[e]??"");return e==="platformToken"||e==="telegramBotToken"?tn(e,n):n}function Fp(e){return e==="tunnelRelayUrl"?{value:$r(),source:zn()}:e==="platformToken"?{value:tn(e,ua()),source:Kn()}:e==="platformDeviceId"?{value:(da()??"")||"(empty)",source:pa()}:null}function Zw(e){if(e!=="platformToken"&&e!=="tunnelRelayUrl")return;let n=$().platformToken.trim()||xt()?.token?.trim()||"";n&&ft({token:n,relayUrl:$r()})}async function eb(){let e=process.env.VISUAL?.trim()||process.env.EDITOR?.trim()||(process.platform==="win32"?"notepad":"nano"),t=Lp.readFileSync(_,"utf8");await new Promise((n,r)=>{let o=Vw(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 Lp.writeFileSync(_,t,{mode:384}),new Error(`Invalid config after edit: ${n instanceof Error?n.message:String(n)}`)}}async function Wp(e){let t=Xw,n=process.stderr,r=(e[0]??"").trim().toLowerCase(),o=e.slice(1);if(!r||r==="help"||r==="--help"||r==="-h"){Es(t);return}if(r==="add"||r==="edit"){try{if(r==="edit"&&o.length===0){await eb(),console.log(B(t,`Updated ${_}`));return}let s=Oa(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=po(i);if(!l){console.error(C(n,`Unknown key "${i}". Try: ${Wc().slice(0,8).join(", ")}\u2026 (omnish config show *)`)),process.exitCode=1;return}Rn(l,a),Zw(l);let d=$(),u=l==="tunnelRelayUrl"?d.tunnelRelayUrl:Ia.includes(l)?tn(l,String(d[l]??"")):Ts(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 Np){d.push(J(t,m.label));for(let f of m.keys){let h=Ts(f,l),g=Fp(f);g&&Ia.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(Np.flatMap(m=>m.keys)),c=gi.filter(m=>!u.has(m));if(c.length>0){d.push(J(t,"Other"));for(let m of c)d.push(` ${S(t,m)}: ${Ts(m,l)}`)}console.log(d.join(`
|
|
344
|
+
`));return}let i=_p(s),a=$();for(let l of i){let d=po(l);if(!d){console.error(C(n,`Unknown key "${l}".`)),process.exitCode=1;return}let u=Ts(d,a),c=Fp(d);c&&Ia.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 _p(s)){let a=po(i);if(!a){console.error(C(n,`Unknown key "${i}".`)),process.exitCode=1;return}Uc(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}".`)),Es(t),process.exitCode=1}async function Up(e){let t=fe(),n=[];if(n.push(J(e,"platform")),!t){n.push(` ${w(e,"attached:")} ${me(e,"no")} \u2014 set platform_url + platform_token (omnish config add) or env`);let a=zn(),l=Kn();return(a==="env"||l==="env")&&n.push(` ${w(e,"note:")} ${V(e,"partial env override (need URL + token)")}`),n}let r=zn(),o=Kn(),s=pa(),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,tn("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(()=>(rs(),yd)),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):me(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:")} ${me(e,"platform_device_id \u2260 platform defaultDeviceId \u2014 run omnish run or set default on dashboard")}`),u===0&&n.push(` ${w(e,"warn:")} ${me(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}rs();function Hp(){let e=fe();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 tb(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 Dp(e){return e.replace(/\D/g,"")}async function Bp(){let e=Hp();if(!e)return;let t=await Bn(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 jp(e){let t=Hp();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 Bn(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 Bn(t),o=[...r.allowFrom],s=[...r.telegramAllowFrom];for(let a of e.slice(1)){let l=tb(a);if(!l){console.error(C(process.stderr,`Unrecognized entry: ${a}`)),process.exitCode=1;return}if(l.kind==="wa"){let d=Dp(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 ts(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=>Dp(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 ts(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 Gp(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=Oa(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}Rn("tunnelRelayUrl",t.replace(/\/$/,"")),Rn("platformToken",n),r&&Rn("platformDeviceId",r),console.log(B(process.stdout,"Platform credentials saved to config.json.")),console.log(" Run: omnish platform status && omnish run")}import nb from"qrcode-terminal";var rb=1e3,ob=120;function Jp(){let e=fe();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 Na(e){let t=e.replace(/\/$/,"");return/^https?:\/\//i.test(t)?t:`http://${t}`}async function Kp(e){let t=`${Na(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 sb(e){let t=await fetch(`${Na(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 zp(e){let t=process.stdout,n=w(t,"\xB7".repeat(42));console.log(V(t,"Scan with WhatsApp \u2192 Linked devices")),console.log(n),nb.generate(e,{small:!0}),console.log(n)}var Ps="",La=!1;function ib(e){let t=e.status??"";return t==="qr"||t==="connecting"||t==="reconnecting"||t==="pairing_restart"}async function ab(e){for(let t=0;t<ob;t++){let n=await Kp(e);if(n.status==="linked"||n.linked)return n;if(n.status==="pairing_restart"&&!La&&(La=!0,console.log(w(process.stdout,"Finishing WhatsApp link after scan (server restart) \u2014 wait a few seconds\u2026"))),n.qr&&n.qr!==Ps&&(Ps=n.qr,zp(n.qr)),!ib(n))throw new Error(n.error||n.statusMessage||`Unexpected status: ${n.status}`);await new Promise(r=>setTimeout(r,rb))}throw new Error("Timed out waiting for WhatsApp to link (scan the QR within ~2 minutes).")}async function qp(){let e=Jp();if(!e)return;let t=await Kp(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")),La=!1,Ps="",t=await sb(e),t.qr&&(zp(t.qr),Ps=t.qr),t=await ab(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 Yp(){let e=Jp();if(!e)return;let t=await fetch(`${Na(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 lb from"ws";function Qp(e,t,n){return new Promise(r=>{let o=new lb(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 Vp(e,t,n=12e3){let r=e.replace(/\/$/,""),o=jn(r),s=await Qp(o,t,n),i,a,l="";for(let d of os(r)){let u=await Qp(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 cb=400,ub=8*1024*1024,db=2*1024*1024;function pb(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=Is.resolve(e[++o]))}return{authDir:t,force:n,help:r}}function mb(e){let t={},n=0,r=0;function o(s,i){let a;try{a=As.readdirSync(i,{withFileTypes:!0})}catch{return}for(let l of a){let d=l.name;if(d==="."||d==="..")continue;let u=Is.join(i,d),m=(s?`${s}/${d}`:d).split(Is.sep).join("/");if(!l.isSymbolicLink()){if(l.isDirectory())o(m,u);else if(l.isFile()){let f=As.readFileSync(u);if(f.length>db)throw new Error(`file too large: ${m}`);if(n+=f.length,n>ub)throw new Error("total auth size exceeds limit (8 MiB)");if(r+=1,r>cb)throw new Error("too many files (max 400)");t[m]=f.toString("base64")}}}}return o("",e),t}function Os(e){console.log([ce(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 fb(e){let{authDir:t,force:n,help:r}=pb(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=fe();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(!As.existsSync(t)){console.error(C(process.stderr,`Auth directory not found: ${t}`)),process.exitCode=1;return}te();let s=Is.join(t,"creds.json");if(!As.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=mb(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 hb(){let e=process.stdout,t=process.stderr,n=fe();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(`${ce(e,"Platform probe")} ${w(e,n.platformUrl)}`);let r=await Vp(n.platformUrl,n.token);console.log(` ${w(e,"wss /control:")} ${r.controlWsOk?S(e,"ok"):me(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}:`)} ${me(e,"fail")}${r.deviceWsStatus?` (HTTP ${r.deviceWsStatus})`:""}`),!r.ok&&o==="/control/device"&&console.log(` ${w(e,`wss ${o}:`)} ${me(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 Xp(e){let t=(e[0]??"").toLowerCase();if(!t||t==="-h"||t==="--help"){Os(process.stdout);return}if(t==="login"){await Gp(e.slice(1));return}if(t==="status"){await Bp();return}if(t==="allow"){await jp(e.slice(1));return}if(t==="probe"){await hb();return}if(t==="link-whatsapp"){await qp();return}if(t==="unlink-whatsapp"){await Yp();return}if(t==="import-whatsapp"){await fb(e.slice(1));return}console.error(C(process.stderr,`Unknown platform subcommand: ${e[0]}`)),Os(process.stderr),process.exitCode=1}G();import tm from"node:crypto";import fn from"node:fs";import nm from"node:path";function gb(){return tm.randomBytes(24).toString("hex")}function Zp(){return tm.randomBytes(32).toString("hex")}function em(e){try{let t=fn.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 yb(){let e=em(ct);if(e)return e;if(e=em(er),e){j(nm.dirname(ct)),fn.writeFileSync(ct,JSON.stringify(e,null,2)+`
|
|
348
|
+
`,{mode:384});try{fn.unlinkSync(er)}catch{}return e}return null}function rm(e){j(nm.dirname(ct));let t=yb(),n=(e??"").trim();if(n){let o={token:n,secret:t?.secret??Zp()};fn.writeFileSync(ct,JSON.stringify(o,null,2)+`
|
|
349
|
+
`,{mode:384});try{fn.existsSync(er)&&fn.unlinkSync(er)}catch{}return o}if(t)return t;let r={token:gb(),secret:Zp()};return fn.writeFileSync(ct,JSON.stringify(r,null,2)+`
|
|
350
|
+
`,{mode:384}),r}pe();import Vt from"node:fs";import xb from"node:http";import Ae from"node:path";import it from"node:process";import{fileURLToPath as $b}from"node:url";import Rb from"node:os";qe();G();import _a from"node:crypto";var Fa="omnish_cfg_sess",om=7*24*60*60*1e3;function Wa(e){let t=Date.now()+om,n=Buffer.from(JSON.stringify({exp:t}),"utf8").toString("base64url"),r=_a.createHmac("sha256",e).update(n).digest("hex");return`${n}.${r}`}function sm(e,t){let n=wb(t??"")[Fa];if(!n||!n.includes("."))return!1;let r=n.lastIndexOf("."),o=n.slice(0,r),s=n.slice(r+1),i=_a.createHmac("sha256",e).update(o).digest("hex");try{let a=Buffer.from(s,"hex"),l=Buffer.from(i,"hex");if(a.length!==l.length||!_a.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 Ua(e){let t=Math.floor(om/1e3);return`${Fa}=${e}; HttpOnly; Path=/; SameSite=Lax; Max-Age=${t}`}function im(){return`${Fa}=; HttpOnly; Path=/; SameSite=Lax; Max-Age=0`}function wb(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 Da from"node:fs";import Ls from"node:process";function am(e){try{return Ls.kill(e,0),!0}catch{return!1}}function lm(e){let t=Date.now()+e;for(;Date.now()<t;);}function bb(){try{let e=Da.readFileSync(Fr,"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 cm(e){Da.writeFileSync(Fr,`${JSON.stringify(e)}
|
|
351
|
+
`,{mode:384})}function Ir(){try{Da.unlinkSync(Fr)}catch{}}function um(e){let t=bb();if(t&&t.port===e&&t.pid!==Ls.pid){if(!am(t.pid)){Ir();return}try{Ls.kill(t.pid,"SIGTERM")}catch{}if(lm(350),am(t.pid)){try{Ls.kill(t.pid,"SIGKILL")}catch{}lm(100)}Ir()}}pe();G();import Ha from"node:fs";import kb from"node:process";function Sb(e){try{return kb.kill(e,0),!0}catch{return!1}}function vb(){try{let e=Ha.readFileSync(le,"utf8").trim(),t=Number.parseInt(e,10);return Number.isFinite(t)&&t>0?t:null}catch{return null}}function Ns(){let e=vb();return e===null?!1:Sb(e)}var Ba=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&&(Wn(this.currentSock),this.currentSock=null)}beginPairing(t){if(this.busy)throw new Error("Pairing already in progress.");if(Ns())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&&(Ha.rmSync(ne,{recursive:!0,force:!0}),Ha.mkdirSync(ne,{recursive:!0,mode:448})),this.busy=!0,this.abort=new AbortController;let n=this.abort.signal;(async()=>{try{await sd({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}})()}},Or=new Ba;var ie="application/json; charset=utf-8",Lr=null;function Cb(){Ir();let e=Lr;Lr=null,e?e.close(()=>{it.exit(0)}):it.exit(0),setTimeout(()=>it.exit(0),4e3).unref()}function Mb(){let e=it.env.OMNISH_CONFIG_UI_STATIC?.trim(),t=it.env.OMNISH_UI_STATIC?.trim()||e;if(t&&Vt.existsSync(Ae.join(t,"index.html")))return t;let n=Ae.dirname($b(import.meta.url)),r=Ae.join(n,"ui");if(Vt.existsSync(Ae.join(r,"index.html")))return r;let o=Ae.join(n,"..","..","dist","ui");if(Vt.existsSync(Ae.join(o,"index.html")))return o;let s=Ae.join(it.cwd(),"dist","ui");if(Vt.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 Tb(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 Eb(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 ja(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 Pb(e){return Bt.includes(e)}function Ga(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 it.env.TELEGRAM_BOT_TOKEN=="string"&&it.env.TELEGRAM_BOT_TOKEN.trim().length>0}}function Ab(){let e=$();return{version:Ze(),dataDir:H,configPath:_,waAuthDir:ne,whatsappLinked:nt(),gatewayPidHint:Vt.existsSync(Ae.join(H,"gateway.pid")),gatewayRunning:Ns(),gatewayLogFile:Ne,gatewayMode:e.gatewayMode,telegramBotTokenMasked:ve(e).length===0?"":Ga(e).telegramBotToken,telegramBotTokenEnvOverride:typeof it.env.TELEGRAM_BOT_TOKEN=="string"&&it.env.TELEGRAM_BOT_TOKEN.trim().length>0}}function Ib(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=Br(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 Ob(e){return typeof e=="string"?e:typeof e=="boolean"||typeof e=="number"?String(e):JSON.stringify(e)}async function dm(e){let t=Mb(),{meta:n}=e;um(e.port);let r=xb.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=Wa(n.secret);s.statusCode=302,s.setHeader("Location","/"),s.setHeader("Set-Cookie",Ua(f)),s.end();return}}if(a.startsWith("/api/")){let m=o.headers.cookie,f=sm(n.secret,m);if(o.method==="POST"&&a==="/api/session"){let h=await ja(o),g=typeof h?.token=="string"?h.token.trim():"";if(!g||g!==n.token){s.statusCode=401,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!1,error:"Invalid token."}));return}let y=Wa(n.secret);s.statusCode=200,s.setHeader("Content-Type",ie),s.setHeader("Set-Cookie",Ua(y)),s.end(JSON.stringify({ok:!0}));return}if(o.method==="GET"&&a==="/api/me"){s.statusCode=f?200:401,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:f}));return}if(!f){s.statusCode=401,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!1,error:"Unauthorized."}));return}if(o.method==="GET"&&a==="/api/status"){s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0,...Ab()}));return}if(o.method==="GET"&&a==="/api/config"){s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0,config:Ga($())}));return}if(o.method==="PUT"&&a==="/api/config"){let h=await ja(o);if(!h||typeof h!="object"){s.statusCode=400,s.setHeader("Content-Type",ie),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(!dt(v))throw new Error("Invalid Telegram bot token format.");uo("telegramBotToken",v);continue}if(!Pb(y))throw new Error(`Unknown or unsupported config key: ${y}`);uo(y,Ob(b))}if("allowFrom"in g||"telegramAllowFrom"in g){let y=$();Ib("allowFrom"in g?g.allowFrom:y.allowFrom,"telegramAllowFrom"in g?g.telegramAllowFrom:y.telegramAllowFrom)}s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0,config:Ga($())}));return}if(o.method==="POST"&&a==="/api/logout"){s.statusCode=200,s.setHeader("Content-Type",ie),s.setHeader("Set-Cookie",im()),s.end(JSON.stringify({ok:!0}));return}if(o.method==="POST"&&a==="/api/shutdown"){s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0})),setImmediate(()=>{Or.requestCancel(),Cb()});return}if(o.method==="POST"&&a==="/api/gateway/start"){if(Ns()){s.statusCode=409,s.setHeader("Content-Type",ie),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=Ms();if(!h.ok){s.statusCode=400,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!1,error:h.message}));return}let g=Ne,y=qo(g);if(!y.ok){s.statusCode=500,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!1,error:y.message}));return}s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0,pid:y.pid,logFile:g}));return}if(o.method==="POST"&&a==="/api/gateway/stop"){let h=Yo();switch(h.outcome){case"no_pidfile":s.statusCode=400,s.setHeader("Content-Type",ie),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",ie),s.end(JSON.stringify({ok:!1,error:"Invalid pidfile (removed)."}));return;case"stale_cleaned":s.statusCode=200,s.setHeader("Content-Type",ie),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",ie),s.end(JSON.stringify({ok:!0,pid:h.pid}));return;case"taskkill_ok":s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0,pid:h.pid,taskkill:!0}));return;case"failed":s.statusCode=500,s.setHeader("Content-Type",ie),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
|
|
307
352
|
|
|
308
|
-
`);let
|
|
353
|
+
`);let h=Or.subscribe(g=>{s.write(`data: ${JSON.stringify(g)}
|
|
309
354
|
|
|
310
|
-
`)});o.on("close",()=>{
|
|
311
|
-
`;return new Promise(o=>{let s=!1,i="";function a(
|
|
312
|
-
`);if(u>=0){let
|
|
313
|
-
`)}
|
|
314
|
-
`))}function
|
|
315
|
-
`)}:{error:null,kind:"text",recipientsSent:
|
|
316
|
-
`)};let
|
|
317
|
-
`+
|
|
318
|
-
`)));return}let t=
|
|
319
|
-
`)||
|
|
320
|
-
`)}),u=async f=>{try{await
|
|
321
|
-
`)}),
|
|
322
|
-
`))}function
|
|
323
|
-
`))}function
|
|
324
|
-
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
|
|
325
|
-
`))}function
|
|
326
|
-
`))}function
|
|
327
|
-
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(
|
|
328
|
-
`),console.warn(
|
|
329
|
-
`,{mode:384})}catch(
|
|
330
|
-
`),
|
|
355
|
+
`)});o.on("close",()=>{h()});return}if(o.method==="POST"&&a==="/api/wa/link/start"){let g=(await ja(o))?.force===!0;try{Or.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",ie),s.end(JSON.stringify({ok:!1,error:b}));return}s.statusCode=202,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0}));return}if(o.method==="POST"&&a==="/api/wa/link/cancel"){Or.requestCancel(),s.statusCode=200,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!0}));return}s.statusCode=404,s.setHeader("Content-Type",ie),s.end(JSON.stringify({ok:!1,error:"Not found."}));return}let l=a==="/"?"index.html":a.replace(/^\/+/,""),d=Eb(t,l),u=Ae.join(t,"index.html");d&&Vt.existsSync(d)&&Vt.statSync(d).isFile()&&(u=d);let c=Vt.readFileSync(u);s.statusCode=200,s.setHeader("Content-Type",Tb(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",ie),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())}),Lr=r,cm({pid:it.pid,port:e.port,host:e.host,startedAt:new Date().toISOString()}),r.on("close",()=>{Ir(),Lr===r&&(Lr=null)})}function pm(e){let t=Rb.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 Ub from"node:readline";import fm from"node:path";import Te from"node:process";pe();qe();G();import Lb from"node:net";import Nb from"node:fs";function _b(){try{let e=Nb.readFileSync(hn,"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 Nr(e){let t=_b();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=Lb.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 Fb(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 Wb(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 mm(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=Wb(o);if(!i)return null;let a=Fb(s);if(a===null)return null;if(a!==void 0)return{...i,mode:"text",body:a};let l=hs(s);if(!l)return null;let{selectorPart:d,caption:u}=l;return{...i,mode:"media",selectorPart:d,caption:u}}function Ja(){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
|
+
`)}G();var Xn="wa:cli:interactive",Db={onPlainTextLlmFallback(e,t){On($(),e,t,async n=>{n.trim()&&console.log(B(Te.stdout,n))})}};function Hb(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 Bb(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=Hb(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 Ka(e){let t=Te.cwd(),n=[`${ce(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:"),...St(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.")}`,"",Ja(),"",`${w(e,"cwd:")} ${S(e,`session starts at ${t} (change with !cd or ${$().commandPrefix}cd).`)}`];console.log(n.join(`
|
|
359
|
+
`))}function hm(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}}async function jb(e){let t=$();if(e.mode==="text"){let{waTargets:c,tgTargets:m}=hm(e,t);if(c.size===0&&m.size===0)return{error:"No recipients matched the requested /sendto destination."};let f=[];for(let h of c){let g=await Nr({op:"sendText",channel:"whatsapp",e164:h,text:e.body});g&&f.push(`[wa:${h}] ${g}`)}for(let h of m){let g=await Nr({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(Xn).cwd,r=await Rr(n,e.selectorPart);if(r.length===0)return{error:`No files matched: ${e.selectorPart}`};let o=await Cr(r);if(!o.ok)return{error:o.error};let s=r.map(c=>Kt(c,t.fileSendMaxBytes));for(let c of s)if("error"in c)return{error:c.error};let{waTargets:i,tgTargets:a}=hm(e,t);if(i.size===0&&a.size===0)return{error:"No recipients matched the requested /sendto destination."};let l=[];for(let c of i)for(let m of s){if("error"in m)continue;let f=await Nr({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 Nr({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 Gb(e,t,n,r,o,s,i){let a=e.trim();if(!a)return;let l=mm(a);if(l!==null||/^\/sendto(\s|$)/i.test(a)){if(l===null){console.log(C(Te.stderr,`Invalid /sendto.
|
|
362
|
+
`+Ja()));return}let c=await jb(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:Xn,text:e},u=await Vn($(),t,n,r,o,d,s,void 0,i,!1,Db);u!==null&&await Jb(u)}async function Jb(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 gm(e){let t=Bb(e);if(t.error==="help"){Ka(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??Xn;te(),ro(Xn,Te.cwd());let s=new Tt,i=new Map,a=new Map,l=new Map,d=new Jt(()=>$(),async(f,h)=>{Te.stdout.write(h),h.endsWith(`
|
|
364
|
+
`)||Te.stdout.write(`
|
|
365
|
+
`)}),u=async f=>{try{await Gb(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=Ub.createInterface({input:Te.stdin,output:Te.stdout}),m=fm.basename(oe(Xn).cwd);c.setPrompt(`${m}> `),c.on("line",f=>{u(f).then(()=>{let h=fm.basename(oe(Xn).cwd);c.setPrompt(`${h}> `),c.prompt()})}),c.on("close",()=>{d.dispose(),s.killAllRunning(),Te.stdout.write(`
|
|
366
|
+
`)}),c.prompt()}Kb.setDefaultResultOrder("ipv4first");function bm(){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:"),...St(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=fe();n?t.push(J(e,"Attached mode (platform credentials detected):"),` ${w(e,"url:")} ${S(e,n.platformUrl)} ${V(e,`[${zn()}]`)}`,` ${w(e,"token:")} ${S(e,tn("platformToken",n.token))} ${V(e,`[${Kn()}]`)}`,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 km(){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(so)),o=t.map((i,a)=>Zs(" ",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:"),...St(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:")} ${ce(e,"omnish allow tg:<your_user_id>")} ${w(e,"then")} ${ce(e,"omnish run")}`,`${w(e,"Config:")} ${S(e,_)}`,""];fe()&&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 qb(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"){Ds(!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 qa(){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: ${le})`},{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:"),...St(e," ",r,s=>w(e,s)),"",J(e,"Commands:"),...St(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 Yb(e){let t=(e??"").trim().toLowerCase(),n=process.stdout;if(!t){qa();return}switch(t){case"link":km();return;case"run":bm();return;case"service":vm();return;case"i":case"interactive":Ka(n);return;case"ui":xm();return;case"config":Es(n);return;case"platform":Os(n);return;default:console.error(C(process.stderr,`No detailed help for "${e}". Try: omnish help`)),process.exitCode=1}}function Qb(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 Vb(e,t){let n=qo(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 Xb(){let e=Yo();switch(e.outcome){case"no_pidfile":console.error(C(process.stderr,`no pidfile at ${le} \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 ym(){if(process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{Xt.readFileSync(le,"utf8").trim()===String(process.pid)&&Xt.unlinkSync(le)}catch{}}function Zb(e){return e.length<=8?"(set)":`${e.slice(0,4)}\u2026${e.slice(-4)}`}function ek(){if(!Xt.existsSync(le))return"gateway process: not running (no pid file)";let e=Xt.readFileSync(le,"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 Sm=120;function vm(){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 ${Sm}).`},{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:"),...St(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 tk(e){let t=process.stdout,n=process.stderr,r=(e[0]??"help").toLowerCase();if(r==="help"||r==="--help"||r==="-h"){vm();return}if(r==="instructions"){let o=nn();if(o.error){console.error(C(n,o.error)),process.exitCode=1;return}console.log(fo(o));return}if(r==="status"){let o=nn(),s=(()=>{try{return Xt.existsSync(le)?`gateway.pid: ${Xt.readFileSync(le,"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,Sm):80,i=wo(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=ho();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=go();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 nk(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 rk(){let e=null,t=Ms();t.ok||(console.error(C(process.stderr,t.message)),process.exit(1));let n=fe();if(n){await Op(n);return}let r=$(),o=r.gatewayMode,s=o==="whatsapp"||o==="both",i=o==="telegram"||o==="both",a=ve(r),l=Rt(r),d=process.stderr,u=Xl(l,"warn");if(u.length>0&&(console.warn(`${B(d,`Security (${u.length} finding(s)):`)}
|
|
373
|
+
`),console.warn(oi(u,d))),process.env.OMNISH_BACKGROUND_GATEWAY==="1")try{Xt.writeFileSync(le,`${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()||wm.hostname(),z=null;if(x.startsWith("tg:"))z=x;else if(x){let Ue=ee(x);Ue&&(z=`wa:${Ue}`)}let we=z?Ct(L,z):null;return Dc(k,{nodeId:F,label:Q,role:L.clusterRole,activeNodeId:we?.nodeId??""})},m=new Tt,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){On($(),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 Jt(()=>$(),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 qi(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=ms(vr());return{ok:!0,summary:Q?`${F}
|
|
331
376
|
|
|
332
|
-
Updates (last check): ${
|
|
333
|
-
${C(process.stderr,"shutting down\u2026")}`),process.exit(0)};if(process.on("SIGINT",
|
|
334
|
-
`))}async function
|
|
335
|
-
`));return}await
|
|
336
|
-
`)),o){let
|
|
377
|
+
Updates (last check): ${Q}`:F}}catch(k){return{ok:!1,error:String(k)}}}};if(K=async(k,x)=>{let L=$();await Ar(L,m,f,h,g,k,A,X,k.peerKey,P,Aa({sendTg:x},{surface:"telegram"}),{surface:"telegram"})},i){let k=await qi(a,()=>$(),K,{decorate:c});b.sendText=k.sendText,b.sendMedia=k.sendMedia,b.stop=k.stop}Xo({getCfg:()=>$(),getWaOutbound:()=>y,getTgSendMedia:()=>b.sendMedia,getTgSendText:()=>b.sendText});let se=null;{let k=$();if(k.webhookEnabled){let x=k.webhookToken||zb.randomBytes(32).toString("hex");k.webhookToken||W({webhookToken:x}),se=Zo({port:k.webhookPort,host:k.webhookHost,token:x},{sendToPeer:R,getDefaultPeerKey:()=>{let F=$();return F.allowFrom.length>0?`wa:${It(F.allowFrom[0])}`:F.telegramAllowFrom.length>0?`tg:${F.telegramAllowFrom[0]}`:null}}).stop}}e=fs({getRunningVersion:Ze,getConfig:$,log:M});let he=Uo({getConfig:$,sendToPeer:R,sendMediaToPeer:T}),D=no({getConfig:$,sendToPeer:R}),ae=!i,Y=()=>{E=!0,he(),D(),e?.(),e=null,se?.(),ym(),Hn(),b.stop?.().catch(()=>{}),v?.dispose(),m.killAllRunning(),dn().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 jo({printQr:!1,verbose:yn()}),await un(Go(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=Zu(x,{decorate:c});let L=zu(x,async F=>{let Q=$(),z=F.fromE164||ee(F.fromJid)||"",we=eu(F),Ue=`wa:${z}`;await Ar(Q,m,f,h,g,we,A,X,Ue,P,Aa({sendWaText:(Ie,de)=>y.sendText(Ie,de),sendWaMedia:(Ie,de)=>y.sendMedia(Ie,de)},{surface:"whatsapp",waJid:F.fromJid}),{surface:"whatsapp"})});if(await new Promise(F=>{let Q=z=>{z.connection==="close"&&(Ji(z.lastDisconnect)===cn.loggedOut&&(k=!0),x.ev.off("connection.update",Q),F())};x.ev.on("connection.update",Q)}),L(),ae&&(A.dispose(),A=O(),v=A),Wn(x),y=null,k&&(console.error(C(process.stderr,"session logged out. Run `omnish link` again.")),he(),e?.(),e=null,ym(),Hn(),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?.(),Hn(),b.stop?.().catch(()=>{}),A.dispose()}function ok(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 xm(){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:"),...St(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 ${ct}).`},{left:"-h, --help",right:"This help."}],n=>w(e,n)),"",`${w(e,"Warning:")} ${me(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 sk(){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"){qa();return}if(e==="help"){Yb(t[0]);return}switch(te(),e){case"link":{let n=qb(t);if(n.kind==="help"){km();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(!dt(r)){console.error(C(o,"That does not look like a Telegram bot token (expect digits:secret from @BotFather).")),process.exitCode=1;return}Ot(r);let i=nt()?"both":"telegram";qr(i),console.log([`${ce(s,"Telegram")} ${S(s,"bot token saved to")} ${w(s,_)}`,`${w(s,"gatewayMode:")} ${ce(s,i)}`,"",S(s,"Next:"),` ${w(s,"1.")} ${S(s,"Find your numeric user id (e.g. t.me/userinfobot), then:")} ${ce(s,"omnish allow tg:<id>")}`,` ${w(s,"2.")} ${ce(s,"omnish run")}`,""].join(`
|
|
380
|
+
`));return}await id({verbose:yn(),force:n.force});return}case"run":{let n=Qb(t);if(n.help){bm();return}if(n.verbose&&Ds(!0),n.background){Vb(n.logFile,n.verbose);return}await rk();return}case"stop":Xb();return;case"logout":{try{Xt.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=Kr(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=zr(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 gm(t);return}case"status":{let n=process.stdout,r=$(),o=t.includes("--check-updates"),s=new Tt().list(),i=s.filter(h=>h.status==="running").length,a=ve(r),l=Rt(r),d=r.gatewayMode==="whatsapp"||r.gatewayMode==="both",u=r.gatewayMode==="telegram"||r.gatewayMode==="both",c=nt(),m=c?rd(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,ek().replace(/^gateway process: /,""))}`,"",Dt(n),ce(n,"whatsapp"),` ${w(n,"in use:")} ${d?S(n,"yes"):me(n,"no (gatewayMode is telegram-only)")}`),d){let h=c?S(n,`linked (${ne})`):me(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("",Dt(n),ce(n,"telegram")),f.push(` ${w(n,"in use:")} ${u?S(n,"yes"):me(n,"no (gatewayMode is whatsapp-only)")}`),u){let h=a?S(n,Zb(a)):me(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("",Dt(n),...await Up(n)),f.push("",Dt(n),`${ce(n,"jobs")} ${w(n,`(recent): ${s.length} total, ${i} running`)}`,tc(l,n)),console.log(f.join(`
|
|
381
|
+
`)),o){let h=await xr(Ze(),r),g=cr(h);console.log(""),console.log(Dt(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(Dt(n)),console.log(ce(n,"cluster")),console.log(` ${w(n,"\xB7")} ${S(n,`enabled \xB7 label ${r.clusterLabel||wm.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(Yl(xn(r),n)),console.log(""),console.log(Dt(n)),console.log(S(n,"Keys editable from chat via /config set (same trust as shell):")),console.log(w(n,Bt.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:")} ${ce(n,i)}`),s.clusterEnabled){let a=ge(),l=Ci(s,null);console.log(""),console.log(S(n,l.wa.replace(/\*([^*]+)\*/g,"$1").replace(/`([^`]+)`/g,"$1"))),console.log(""),console.log(Ri(a,s,null));let d=Object.keys(a.senderBindings).length,u=Object.entries(s.clusterSenderBindings??{});if(d>0){console.log(""),console.log(ce(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(ce(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(me(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=nk(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}=Zc(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(`${ce(n,"cluster:")} ${S(n,`${a} -> ${d.peer.nodeId} (${d.peer.label}).`)}`);let u=$();console.log(""),console.log(Ri(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=Rt(n),o=t.includes("--json");console.log(o?Zl(r):oi(r,process.stdout)),lr(r)&&(process.exitCode=1);return}case"service":{tk(t);return}case"config":{await Wp(t);return}case"tunnel":{await Ed(t);return}case"platform":{await Xp(t);return}case"ui":{let n=ok(t);if(n.help){xm();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=rm(n.token);await dm({host:n.host,port:n.port,meta:r});let o=process.stdout,s=pm(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,ct)}`),console.log(""),console.log(me(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:qa(),e&&(process.exitCode=1)}}sk().catch(e=>{console.error(C(process.stderr,String(e))),process.exit(1)});
|