@r5n/hydra 0.5.1 → 0.5.4
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/README.md +7 -13
- package/dist/bundle-report.json +21 -0
- package/dist/cli.js +93 -106
- package/package.json +5 -1
package/dist/cli.js
CHANGED
|
@@ -1,117 +1,104 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
var
|
|
3
|
-
`))}var qe=Xn((_f,zn)=>{var Ue={to(t,e){if(!e)return`\x1B[${t+1}G`;return`\x1B[${e+1};${t+1}H`},move(t,e){let n="";if(t<0)n+=`\x1B[${-t}D`;else if(t>0)n+=`\x1B[${t}C`;if(e<0)n+=`\x1B[${-e}A`;else if(e>0)n+=`\x1B[${e}B`;return n},up:(t=1)=>`\x1B[${t}A`,down:(t=1)=>`\x1B[${t}B`,forward:(t=1)=>`\x1B[${t}C`,backward:(t=1)=>`\x1B[${t}D`,nextLine:(t=1)=>"\x1B[E".repeat(t),prevLine:(t=1)=>"\x1B[F".repeat(t),left:"\x1B[G",hide:"\x1B[?25l",show:"\x1B[?25h",save:"\x1B7",restore:"\x1B8"},Pr={up:(t=1)=>"\x1B[S".repeat(t),down:(t=1)=>"\x1B[T".repeat(t)},Ar={screen:"\x1B[2J",up:(t=1)=>"\x1B[1J".repeat(t),down:(t=1)=>"\x1B[J".repeat(t),line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",lines(t){let e="";for(let n=0;n<t;n++)e+=this.line+(n<t-1?Ue.up():"");if(t)e+=Ue.left;return e}};zn.exports={cursor:Ue,scroll:Pr,erase:Ar,beep:"\x07"}});var Ge=Xn((Nf,Le)=>{var ae=process||{},Yn=ae.argv||[],se=ae.env||{},Tr=!(!!se.NO_COLOR||Yn.includes("--no-color"))&&(!!se.FORCE_COLOR||Yn.includes("--color")||ae.platform==="win32"||(ae.stdout||{}).isTTY&&se.TERM!=="dumb"||!!se.CI),Or=(t,e,n=t)=>(i)=>{let r=""+i,s=r.indexOf(e,t.length);return~s?t+Hr(r,e,n,s)+e:t+r+e},Hr=(t,e,n,i)=>{let r="",s=0;do r+=t.substring(s,i)+n,s=i+e.length,i=t.indexOf(e,s);while(~i);return r+t.substring(s)},In=(t=Tr)=>{let e=t?Or:()=>String;return{isColorSupported:t,reset:e("\x1B[0m","\x1B[0m"),bold:e("\x1B[1m","\x1B[22m","\x1B[22m\x1B[1m"),dim:e("\x1B[2m","\x1B[22m","\x1B[22m\x1B[2m"),italic:e("\x1B[3m","\x1B[23m"),underline:e("\x1B[4m","\x1B[24m"),inverse:e("\x1B[7m","\x1B[27m"),hidden:e("\x1B[8m","\x1B[28m"),strikethrough:e("\x1B[9m","\x1B[29m"),black:e("\x1B[30m","\x1B[39m"),red:e("\x1B[31m","\x1B[39m"),green:e("\x1B[32m","\x1B[39m"),yellow:e("\x1B[33m","\x1B[39m"),blue:e("\x1B[34m","\x1B[39m"),magenta:e("\x1B[35m","\x1B[39m"),cyan:e("\x1B[36m","\x1B[39m"),white:e("\x1B[37m","\x1B[39m"),gray:e("\x1B[90m","\x1B[39m"),bgBlack:e("\x1B[40m","\x1B[49m"),bgRed:e("\x1B[41m","\x1B[49m"),bgGreen:e("\x1B[42m","\x1B[49m"),bgYellow:e("\x1B[43m","\x1B[49m"),bgBlue:e("\x1B[44m","\x1B[49m"),bgMagenta:e("\x1B[45m","\x1B[49m"),bgCyan:e("\x1B[46m","\x1B[49m"),bgWhite:e("\x1B[47m","\x1B[49m"),blackBright:e("\x1B[90m","\x1B[39m"),redBright:e("\x1B[91m","\x1B[39m"),greenBright:e("\x1B[92m","\x1B[39m"),yellowBright:e("\x1B[93m","\x1B[39m"),blueBright:e("\x1B[94m","\x1B[39m"),magentaBright:e("\x1B[95m","\x1B[39m"),cyanBright:e("\x1B[96m","\x1B[39m"),whiteBright:e("\x1B[97m","\x1B[39m"),bgBlackBright:e("\x1B[100m","\x1B[49m"),bgRedBright:e("\x1B[101m","\x1B[49m"),bgGreenBright:e("\x1B[102m","\x1B[49m"),bgYellowBright:e("\x1B[103m","\x1B[49m"),bgBlueBright:e("\x1B[104m","\x1B[49m"),bgMagentaBright:e("\x1B[105m","\x1B[49m"),bgCyanBright:e("\x1B[106m","\x1B[49m"),bgWhiteBright:e("\x1B[107m","\x1B[49m")}};Le.exports=In();Le.exports.createColors=In});import{stdin as ai,stdout as li}from"process";import*as gt from"readline";import Fn from"readline";import{Writable as Cr}from"stream";function _r({onlyFirst:t=!1}={}){let e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");return new RegExp(e,t?void 0:"g")}function ui(t){if(typeof t!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof t}\``);return t.replace(Nr,"")}function ci(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function Jt(t,e={}){if(typeof t!="string"||t.length===0||(e={ambiguousIsNarrow:!0,...e},t=ui(t),t.length===0))return 0;t=t.replace(Br()," ");let n=e.ambiguousIsNarrow?1:2,i=0;for(let r of t){let s=r.codePointAt(0);if(s<=31||s>=127&&s<=159||s>=768&&s<=879)continue;switch(Mr.eastAsianWidth(r)){case"F":case"W":i+=2;break;case"A":i+=n;break;default:i+=1}}return i}function Lr(){let t=new Map;for(let[e,n]of Object.entries(_)){for(let[i,r]of Object.entries(n))_[i]={open:`\x1B[${r[0]}m`,close:`\x1B[${r[1]}m`},n[i]=_[i],t.set(r[0],r[1]);Object.defineProperty(_,e,{value:n,enumerable:!1})}return Object.defineProperty(_,"codes",{value:t,enumerable:!1}),_.color.close="\x1B[39m",_.bgColor.close="\x1B[49m",_.color.ansi=Dn(),_.color.ansi256=ti(),_.color.ansi16m=ei(),_.bgColor.ansi=Dn(je),_.bgColor.ansi256=ti(je),_.bgColor.ansi16m=ei(je),Object.defineProperties(_,{rgbToAnsi256:{value:(e,n,i)=>e===n&&n===i?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(n/255*5)+Math.round(i/255*5),enumerable:!1},hexToRgb:{value:(e)=>{let n=/[a-f\d]{6}|[a-f\d]{3}/i.exec(e.toString(16));if(!n)return[0,0,0];let[i]=n;i.length===3&&(i=[...i].map((s)=>s+s).join(""));let r=Number.parseInt(i,16);return[r>>16&255,r>>8&255,r&255]},enumerable:!1},hexToAnsi256:{value:(e)=>_.rgbToAnsi256(..._.hexToRgb(e)),enumerable:!1},ansi256ToAnsi:{value:(e)=>{if(e<8)return 30+e;if(e<16)return 90+(e-8);let n,i,r;if(e>=232)n=((e-232)*10+8)/255,i=n,r=n;else{e-=16;let a=e%36;n=Math.floor(e/36)/5,i=Math.floor(a/6)/5,r=a%6/5}let s=Math.max(n,i,r)*2;if(s===0)return 30;let o=30+(Math.round(r)<<2|Math.round(i)<<1|Math.round(n));return s===2&&(o+=60),o},enumerable:!1},rgbToAnsi:{value:(e,n,i)=>_.ansi256ToAnsi(_.rgbToAnsi256(e,n,i)),enumerable:!1},hexToAnsi:{value:(e)=>_.ansi256ToAnsi(_.hexToAnsi256(e)),enumerable:!1}}),_}function oi(t,e,n){return String(t).normalize().replace(/\r\n/g,`
|
|
2
|
+
var ui=Object.create;var{getPrototypeOf:pi,defineProperty:Kr,getOwnPropertyNames:li}=Object;var yi=Object.prototype.hasOwnProperty;var hr=(r,n,t)=>{t=r!=null?ui(pi(r)):{};let o=n||!r||!r.__esModule?Kr(t,"default",{value:r,enumerable:!0}):t;for(let e of li(r))if(!yi.call(o,e))Kr(o,e,{get:()=>r[e],enumerable:!0});return o};var Hn=(r,n)=>()=>(n||r((n={exports:{}}).exports,n),n.exports);var hi=(r,n)=>{for(var t in n)Kr(r,t,{get:n[t],enumerable:!0,configurable:!0,set:(o)=>n[t]=()=>o})};var I=(r,n)=>()=>(r&&(n=r(r=0)),n);var Ri=import.meta.require;var kr="0.5.4";var Zr=()=>{};function zr(r){return(n)=>wi?`${r}${n}${Wn.reset}`:n}function Cn({bright:r=!1,color:n}){let t=Bun.color(n,"ansi");if(!t||typeof t!=="string")return"";return r&&t in Sn?Sn[t]:t}var wi,bi,Ei,Wn,Sn,xi,$i,E;var Jr=I(()=>{wi=!process.env.NO_COLOR&&(process.env.FORCE_COLOR||(process.stdout?.isTTY??!1)),bi=["blue","cyan","gray","green","magenta","red","white","yellow"],Ei=["bold","dim","italic","underline","reset"],Wn={bold:"\x1B[1m",dim:"\x1B[2m",italic:"\x1B[3m",reset:"\x1B[0m",underline:"\x1B[4m"},Sn={"\x1B[30m":"\x1B[90m","\x1B[31m":"\x1B[91m","\x1B[32m":"\x1B[92m","\x1B[33m":"\x1B[93m","\x1B[34m":"\x1B[94m","\x1B[35m":"\x1B[95m","\x1B[36m":"\x1B[96m","\x1B[37m":"\x1B[97m"};xi=bi.reduce((r,n)=>{let t=Cn({color:n});if(t)r[n]=zr(t);let o=Cn({bright:!0,color:n});if(o)r[`${n}Bright`]=zr(o);return r},{}),$i=Ei.reduce((r,n)=>{return r[n]=zr(Wn[n]),r},{}),E={...xi,...$i}});function Oi({prefix:r,level:n,message:t}){let o="";try{let i=new Date().toISOString().split("T")[1];if(i)o=i.split(".")[0]||""}catch{o="00:00:00"}let e=r?`[${r}] `:"";return`${E.dim(o)} ${n} ${e}${t}`}var _i,k=({prefix:r="",level:n=process.env.DEBUG?0:1}={})=>{let t={};for(let o of _i)t[o.method]=n<=o.level?(...e)=>{let s=e.map((i)=>String(i??"")).join(" ");o.console(Oi({level:o.color(o.label),message:s,prefix:r}))}:()=>{};return t.child=(o)=>k({level:n,prefix:`${r}:${o}`}),t},Yr;var Gn=I(()=>{Jr();_i=[{color:E.dim,console:console.log,label:"DEBUG",level:0,method:"debug"},{color:E.cyan,console:console.info,label:"INFO ",level:1,method:"info"},{color:E.yellow,console:console.warn,label:"WARN ",level:2,method:"warn"},{color:E.red,console:console.error,label:"ERROR",level:3,method:"error"}],Yr=k()});var P=I(()=>{Jr();Gn()});var y;var Xr=I(()=>{P();y={arrow:E.yellow,bold:E.bold,boolean:E.cyan,bullet:E.yellow,busy:E.yellow,command:E.green,dim:E.dim,error:E.red,flag:E.yellow,info:E.cyan,number:E.magenta,offline:E.red,online:E.green,separator:E.dim,string:E.green,success:E.green,value:E.cyan,warning:E.yellow}});var Fr=Hn((ts,Mn)=>{var Qr={to(r,n){if(!n)return`\x1B[${r+1}G`;return`\x1B[${n+1};${r+1}H`},move(r,n){let t="";if(r<0)t+=`\x1B[${-r}D`;else if(r>0)t+=`\x1B[${r}C`;if(n<0)t+=`\x1B[${-n}A`;else if(n>0)t+=`\x1B[${n}B`;return t},up:(r=1)=>`\x1B[${r}A`,down:(r=1)=>`\x1B[${r}B`,forward:(r=1)=>`\x1B[${r}C`,backward:(r=1)=>`\x1B[${r}D`,nextLine:(r=1)=>"\x1B[E".repeat(r),prevLine:(r=1)=>"\x1B[F".repeat(r),left:"\x1B[G",hide:"\x1B[?25l",show:"\x1B[?25h",save:"\x1B7",restore:"\x1B8"},ki={up:(r=1)=>"\x1B[S".repeat(r),down:(r=1)=>"\x1B[T".repeat(r)},vi={screen:"\x1B[2J",up:(r=1)=>"\x1B[1J".repeat(r),down:(r=1)=>"\x1B[J".repeat(r),line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",lines(r){let n="";for(let t=0;t<r;t++)n+=this.line+(t<r-1?Qr.up():"");if(r)n+=Qr.left;return n}};Mn.exports={cursor:Qr,scroll:ki,erase:vi,beep:"\x07"}});var rn=Hn((is,Dr)=>{var Tr=process||{},Un=Tr.argv||[],vr=Tr.env||{},Ti=!(!!vr.NO_COLOR||Un.includes("--no-color"))&&(!!vr.FORCE_COLOR||Un.includes("--color")||Tr.platform==="win32"||(Tr.stdout||{}).isTTY&&vr.TERM!=="dumb"||!!vr.CI),Ni=(r,n,t=r)=>(o)=>{let e=""+o,s=e.indexOf(n,r.length);return~s?r+Ii(e,n,t,s)+n:r+e+n},Ii=(r,n,t,o)=>{let e="",s=0;do e+=r.substring(s,o)+t,s=o+n.length,o=r.indexOf(n,s);while(~o);return e+r.substring(s)},Pn=(r=Ti)=>{let n=r?Ni:()=>String;return{isColorSupported:r,reset:n("\x1B[0m","\x1B[0m"),bold:n("\x1B[1m","\x1B[22m","\x1B[22m\x1B[1m"),dim:n("\x1B[2m","\x1B[22m","\x1B[22m\x1B[2m"),italic:n("\x1B[3m","\x1B[23m"),underline:n("\x1B[4m","\x1B[24m"),inverse:n("\x1B[7m","\x1B[27m"),hidden:n("\x1B[8m","\x1B[28m"),strikethrough:n("\x1B[9m","\x1B[29m"),black:n("\x1B[30m","\x1B[39m"),red:n("\x1B[31m","\x1B[39m"),green:n("\x1B[32m","\x1B[39m"),yellow:n("\x1B[33m","\x1B[39m"),blue:n("\x1B[34m","\x1B[39m"),magenta:n("\x1B[35m","\x1B[39m"),cyan:n("\x1B[36m","\x1B[39m"),white:n("\x1B[37m","\x1B[39m"),gray:n("\x1B[90m","\x1B[39m"),bgBlack:n("\x1B[40m","\x1B[49m"),bgRed:n("\x1B[41m","\x1B[49m"),bgGreen:n("\x1B[42m","\x1B[49m"),bgYellow:n("\x1B[43m","\x1B[49m"),bgBlue:n("\x1B[44m","\x1B[49m"),bgMagenta:n("\x1B[45m","\x1B[49m"),bgCyan:n("\x1B[46m","\x1B[49m"),bgWhite:n("\x1B[47m","\x1B[49m"),blackBright:n("\x1B[90m","\x1B[39m"),redBright:n("\x1B[91m","\x1B[39m"),greenBright:n("\x1B[92m","\x1B[39m"),yellowBright:n("\x1B[93m","\x1B[39m"),blueBright:n("\x1B[94m","\x1B[39m"),magentaBright:n("\x1B[95m","\x1B[39m"),cyanBright:n("\x1B[96m","\x1B[39m"),whiteBright:n("\x1B[97m","\x1B[39m"),bgBlackBright:n("\x1B[100m","\x1B[49m"),bgRedBright:n("\x1B[101m","\x1B[49m"),bgGreenBright:n("\x1B[102m","\x1B[49m"),bgYellowBright:n("\x1B[103m","\x1B[49m"),bgBlueBright:n("\x1B[104m","\x1B[49m"),bgMagentaBright:n("\x1B[105m","\x1B[49m"),bgCyanBright:n("\x1B[106m","\x1B[49m"),bgWhiteBright:n("\x1B[107m","\x1B[49m")}};Dr.exports=Pn();Dr.exports.createColors=Pn});import{stdin as Jn,stdout as Yn}from"process";import*as X from"readline";import Ln from"readline";import{Writable as Ai}from"stream";function Hi({onlyFirst:r=!1}={}){let n=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");return new RegExp(n,r?void 0:"g")}function Qn(r){if(typeof r!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof r}\``);return r.replace(Si,"")}function Fn(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}function wr(r,n={}){if(typeof r!="string"||r.length===0||(n={ambiguousIsNarrow:!0,...n},r=Qn(r),r.length===0))return 0;r=r.replace(Mi()," ");let t=n.ambiguousIsNarrow?1:2,o=0;for(let e of r){let s=e.codePointAt(0);if(s<=31||s>=127&&s<=159||s>=768&&s<=879)continue;switch(Wi.eastAsianWidth(e)){case"F":case"W":o+=2;break;case"A":o+=t;break;default:o+=1}}return o}function Li(){let r=new Map;for(let[n,t]of Object.entries($)){for(let[o,e]of Object.entries(t))$[o]={open:`\x1B[${e[0]}m`,close:`\x1B[${e[1]}m`},t[o]=$[o],r.set(e[0],e[1]);Object.defineProperty($,n,{value:t,enumerable:!1})}return Object.defineProperty($,"codes",{value:r,enumerable:!1}),$.color.close="\x1B[39m",$.bgColor.close="\x1B[49m",$.color.ansi=qn(),$.color.ansi256=Bn(),$.color.ansi16m=jn(),$.bgColor.ansi=qn(nn),$.bgColor.ansi256=Bn(nn),$.bgColor.ansi16m=jn(nn),Object.defineProperties($,{rgbToAnsi256:{value:(n,t,o)=>n===t&&t===o?n<8?16:n>248?231:Math.round((n-8)/247*24)+232:16+36*Math.round(n/255*5)+6*Math.round(t/255*5)+Math.round(o/255*5),enumerable:!1},hexToRgb:{value:(n)=>{let t=/[a-f\d]{6}|[a-f\d]{3}/i.exec(n.toString(16));if(!t)return[0,0,0];let[o]=t;o.length===3&&(o=[...o].map((s)=>s+s).join(""));let e=Number.parseInt(o,16);return[e>>16&255,e>>8&255,e&255]},enumerable:!1},hexToAnsi256:{value:(n)=>$.rgbToAnsi256(...$.hexToRgb(n)),enumerable:!1},ansi256ToAnsi:{value:(n)=>{if(n<8)return 30+n;if(n<16)return 90+(n-8);let t,o,e;if(n>=232)t=((n-232)*10+8)/255,o=t,e=t;else{n-=16;let a=n%36;t=Math.floor(n/36)/5,o=Math.floor(a/6)/5,e=a%6/5}let s=Math.max(t,o,e)*2;if(s===0)return 30;let i=30+(Math.round(e)<<2|Math.round(o)<<1|Math.round(t));return s===2&&(i+=60),i},enumerable:!1},rgbToAnsi:{value:(n,t,o)=>$.ansi256ToAnsi($.rgbToAnsi256(n,t,o)),enumerable:!1},hexToAnsi:{value:(n)=>$.ansi256ToAnsi($.hexToAnsi256(n)),enumerable:!1}}),$}function Zn(r,n,t){return String(r).normalize().replace(/\r\n/g,`
|
|
4
3
|
`).split(`
|
|
5
|
-
`).map((
|
|
6
|
-
`)}function
|
|
7
|
-
`),
|
|
8
|
-
`),
|
|
9
|
-
`),
|
|
10
|
-
`).length-1;this.output.write(
|
|
11
|
-
`);this.output.write(
|
|
12
|
-
`).slice(
|
|
13
|
-
`)),this._prevFrame=t;return}this.output.write(J.erase.down())}this.output.write(t),this.state==="initial"&&(this.state="active"),this._prevFrame=t}}}var J,fi,Nr,pi,Sr,Mr,Wr=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g},Br,je=10,Dn=(t=0)=>(e)=>`\x1B[${e+t}m`,ti=(t=0)=>(e)=>`\x1B[${38+t};5;${e}m`,ei=(t=0)=>(e,n,i)=>`\x1B[${38+t};2;${e};${n};${i}m`,_,Ur,qr,Gr,ue,jr=39,Xe="\x07",hi="[",Jr="]",di="m",Qe,ni=(t)=>`${ue.values().next().value}${hi}${t}${di}`,ii=(t)=>`${ue.values().next().value}${Qe}${t}${Xe}`,kr=(t)=>t.split(" ").map((e)=>Jt(e)),Je=(t,e,n)=>{let i=[...e],r=!1,s=!1,o=Jt(ui(t[t.length-1]));for(let[a,f]of i.entries()){let u=Jt(f);if(o+u<=n?t[t.length-1]+=f:(t.push(f),o=0),ue.has(f)&&(r=!0,s=i.slice(a+1).join("").startsWith(Qe)),r){s?f===Xe&&(r=!1,s=!1):f===di&&(r=!1);continue}o+=u,o===n&&a<i.length-1&&(t.push(""),o=0)}!o&&t[t.length-1].length>0&&t.length>1&&(t[t.length-2]+=t.pop())},Xr=(t)=>{let e=t.split(" "),n=e.length;for(;n>0&&!(Jt(e[n-1])>0);)n--;return n===e.length?t:e.slice(0,n).join(" ")+e.slice(n).join("")},Qr=(t,e,n={})=>{if(n.trim!==!1&&t.trim()==="")return"";let i="",r,s,o=kr(t),a=[""];for(let[u,p]of t.split(" ").entries()){n.trim!==!1&&(a[a.length-1]=a[a.length-1].trimStart());let d=Jt(a[a.length-1]);if(u!==0&&(d>=e&&(n.wordWrap===!1||n.trim===!1)&&(a.push(""),d=0),(d>0||n.trim===!1)&&(a[a.length-1]+=" ",d++)),n.hard&&o[u]>e){let g=e-d,b=1+Math.floor((o[u]-g-1)/e);Math.floor((o[u]-1)/e)<b&&a.push(""),Je(a,p,e);continue}if(d+o[u]>e&&d>0&&o[u]>0){if(n.wordWrap===!1&&d<e){Je(a,p,e);continue}a.push("")}if(d+o[u]>e&&n.wordWrap===!1){Je(a,p,e);continue}a[a.length-1]+=p}n.trim!==!1&&(a=a.map((u)=>Xr(u)));let f=[...a.join(`
|
|
14
|
-
`)];for(let[
|
|
15
|
-
`?(s&&(
|
|
16
|
-
`&&(
|
|
17
|
-
${
|
|
18
|
-
`,
|
|
19
|
-
${
|
|
20
|
-
${
|
|
21
|
-
`;case"submit":return`${
|
|
22
|
-
${
|
|
23
|
-
${
|
|
24
|
-
`}}}).prompt(),
|
|
25
|
-
${
|
|
26
|
-
`,
|
|
27
|
-
${
|
|
28
|
-
${
|
|
29
|
-
`}}}).prompt()},
|
|
30
|
-
${
|
|
31
|
-
`;switch(this.state){case"submit":return`${
|
|
32
|
-
${
|
|
33
|
-
${
|
|
34
|
-
${
|
|
35
|
-
`}}}).prompt()},
|
|
36
|
-
${h.default.reset(h.default.dim(`Press ${h.default.gray(h.default.bgWhite(h.default.inverse(" space ")))} to select, ${h.default.gray(h.default.bgWhite(h.default.inverse(" enter ")))} to submit`))}`},render(){let n=`${h.default.gray(R)}
|
|
37
|
-
${pe(this.state)} ${t.message}
|
|
38
|
-
`,i=(r,s)=>{let o=this.value.includes(r.value);return s&&o?e(r,"active-selected"):o?e(r,"selected"):e(r,s?"active":"inactive")};switch(this.state){case"submit":return`${n}${h.default.gray(R)} ${this.options.filter(({value:r})=>this.value.includes(r)).map((r)=>e(r,"submitted")).join(h.default.dim(", "))||h.default.dim("none")}`;case"cancel":{let r=this.options.filter(({value:s})=>this.value.includes(s)).map((s)=>e(s,"cancelled")).join(h.default.dim(", "));return`${n}${h.default.gray(R)} ${r.trim()?`${r}
|
|
39
|
-
${h.default.gray(R)}`:""}`}case"error":{let r=this.error.split(`
|
|
40
|
-
`).map((s,o)=>o===0?`${h.default.yellow(mt)} ${h.default.yellow(s)}`:` ${s}`).join(`
|
|
41
|
-
`);return`${n+h.default.yellow(R)} ${tn({options:this.options,cursor:this.cursor,maxItems:t.maxItems,style:i}).join(`
|
|
42
|
-
${h.default.yellow(R)} `)}
|
|
43
|
-
${r}
|
|
44
|
-
`}default:return`${n}${h.default.cyan(R)} ${tn({options:this.options,cursor:this.cursor,maxItems:t.maxItems,style:i}).join(`
|
|
45
|
-
${h.default.cyan(R)} `)}
|
|
46
|
-
${h.default.cyan(mt)}
|
|
47
|
-
`}}}).prompt()},nn=(t="")=>{process.stdout.write(`${h.default.gray(mt)} ${h.default.red(t)}
|
|
4
|
+
`).map((o)=>Zi(o,n,t)).join(`
|
|
5
|
+
`)}function an(r,n){if(typeof r=="string")return Ir.aliases.get(r)===n;for(let t of r)if(t!==void 0&&an(t,n))return!0;return!1}function Ji(r,n){if(r===n)return;let t=r.split(`
|
|
6
|
+
`),o=n.split(`
|
|
7
|
+
`),e=[];for(let s=0;s<Math.max(t.length,o.length);s++)t[s]!==o[s]&&e.push(s);return e}function H(r){return r===on}function Nr(r,n){let t=r;t.isTTY&&t.setRawMode(n)}function tt({input:r=Jn,output:n=Yn,overwrite:t=!0,hideCursor:o=!0}={}){let e=X.createInterface({input:r,output:n,prompt:"",tabSize:1});X.emitKeypressEvents(r,e),r.isTTY&&r.setRawMode(!0);let s=(i,{name:a,sequence:f})=>{let d=String(i);if(an([d,a,f],"cancel")){o&&n.write(A.cursor.show),process.exit(0);return}if(!t)return;X.moveCursor(n,a==="return"?0:-1,a==="return"?-1:0,()=>{X.clearLine(n,1,()=>{r.once("keypress",s)})})};return o&&n.write(A.cursor.hide),r.once("keypress",s),()=>{r.off("keypress",s),o&&n.write(A.cursor.show),r.isTTY&&!Yi&&r.setRawMode(!1),e.terminal=!1,e.close()}}class Hr{constructor(r,n=!0){M(this,"input"),M(this,"output"),M(this,"_abortSignal"),M(this,"rl"),M(this,"opts"),M(this,"_render"),M(this,"_track",!1),M(this,"_prevFrame",""),M(this,"_subscribers",new Map),M(this,"_cursor",0),M(this,"state","initial"),M(this,"error",""),M(this,"value");let{input:t=Jn,output:o=Yn,render:e,signal:s,...i}=r;this.opts=i,this.onKeypress=this.onKeypress.bind(this),this.close=this.close.bind(this),this.render=this.render.bind(this),this._render=e.bind(this),this._track=n,this._abortSignal=s,this.input=t,this.output=o}unsubscribe(){this._subscribers.clear()}setSubscriber(r,n){let t=this._subscribers.get(r)??[];t.push(n),this._subscribers.set(r,t)}on(r,n){this.setSubscriber(r,{cb:n})}once(r,n){this.setSubscriber(r,{cb:n,once:!0})}emit(r,...n){let t=this._subscribers.get(r)??[],o=[];for(let e of t)e.cb(...n),e.once&&o.push(()=>t.splice(t.indexOf(e),1));for(let e of o)e()}prompt(){return new Promise((r,n)=>{if(this._abortSignal){if(this._abortSignal.aborted)return this.state="cancel",this.close(),r(on);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}let t=new Ai;t._write=(o,e,s)=>{this._track&&(this.value=this.rl?.line.replace(/\t/g,""),this._cursor=this.rl?.cursor??0,this.emit("value",this.value)),s()},this.input.pipe(t),this.rl=Ln.createInterface({input:this.input,output:t,tabSize:2,prompt:"",escapeCodeTimeout:50,terminal:!0}),Ln.emitKeypressEvents(this.input,this.rl),this.rl.prompt(),this.opts.initialValue!==void 0&&this._track&&this.rl.write(this.opts.initialValue),this.input.on("keypress",this.onKeypress),Nr(this.input,!0),this.output.on("resize",this.render),this.render(),this.once("submit",()=>{this.output.write(A.cursor.show),this.output.off("resize",this.render),Nr(this.input,!1),r(this.value)}),this.once("cancel",()=>{this.output.write(A.cursor.show),this.output.off("resize",this.render),Nr(this.input,!1),r(on)})})}onKeypress(r,n){if(this.state==="error"&&(this.state="active"),n?.name&&(!this._track&&Ir.aliases.has(n.name)&&this.emit("cursor",Ir.aliases.get(n.name)),Ir.actions.has(n.name)&&this.emit("cursor",n.name)),r&&(r.toLowerCase()==="y"||r.toLowerCase()==="n")&&this.emit("confirm",r.toLowerCase()==="y"),r==="\t"&&this.opts.placeholder&&(this.value||(this.rl?.write(this.opts.placeholder),this.emit("value",this.opts.placeholder))),r&&this.emit("key",r.toLowerCase()),n?.name==="return"){if(this.opts.validate){let t=this.opts.validate(this.value);t&&(this.error=t instanceof Error?t.message:t,this.state="error",this.rl?.write(this.value))}this.state!=="error"&&(this.state="submit")}an([r,n?.name,n?.sequence],"cancel")&&(this.state="cancel"),(this.state==="submit"||this.state==="cancel")&&this.emit("finalize"),this.render(),(this.state==="submit"||this.state==="cancel")&&this.close()}close(){this.input.unpipe(),this.input.removeListener("keypress",this.onKeypress),this.output.write(`
|
|
8
|
+
`),Nr(this.input,!1),this.rl?.close(),this.rl=void 0,this.emit(`${this.state}`,this.value),this.unsubscribe()}restoreCursor(){let r=Zn(this._prevFrame,process.stdout.columns,{hard:!0}).split(`
|
|
9
|
+
`).length-1;this.output.write(A.cursor.move(-999,r*-1))}render(){let r=Zn(this._render(this)??"",process.stdout.columns,{hard:!0});if(r!==this._prevFrame){if(this.state==="initial")this.output.write(A.cursor.hide);else{let n=Ji(this._prevFrame,r);if(this.restoreCursor(),n&&n?.length===1){let t=n[0];this.output.write(A.cursor.move(0,t)),this.output.write(A.erase.lines(1));let o=r.split(`
|
|
10
|
+
`);this.output.write(o[t]),this._prevFrame=r,this.output.write(A.cursor.move(0,o.length-t-1));return}if(n&&n?.length>1){let t=n[0];this.output.write(A.cursor.move(0,t)),this.output.write(A.erase.down());let o=r.split(`
|
|
11
|
+
`).slice(t);this.output.write(o.join(`
|
|
12
|
+
`)),this._prevFrame=r;return}this.output.write(A.erase.down())}this.output.write(r),this.state==="initial"&&(this.state="active"),this._prevFrame=r}}}var A,Xn,Si,Dn,Ci,Wi,Gi=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g},Mi,nn=10,qn=(r=0)=>(n)=>`\x1B[${n+r}m`,Bn=(r=0)=>(n)=>`\x1B[${38+r};5;${n}m`,jn=(r=0)=>(n,t,o)=>`\x1B[${38+r};2;${n};${t};${o}m`,$,Ui,Pi,qi,Ar,Bi=39,en="\x07",rt="[",ji="]",nt="m",sn,Vn=(r)=>`${Ar.values().next().value}${rt}${r}${nt}`,Kn=(r)=>`${Ar.values().next().value}${sn}${r}${en}`,Vi=(r)=>r.split(" ").map((n)=>wr(n)),tn=(r,n,t)=>{let o=[...n],e=!1,s=!1,i=wr(Qn(r[r.length-1]));for(let[a,f]of o.entries()){let d=wr(f);if(i+d<=t?r[r.length-1]+=f:(r.push(f),i=0),Ar.has(f)&&(e=!0,s=o.slice(a+1).join("").startsWith(sn)),e){s?f===en&&(e=!1,s=!1):f===nt&&(e=!1);continue}i+=d,i===t&&a<o.length-1&&(r.push(""),i=0)}!i&&r[r.length-1].length>0&&r.length>1&&(r[r.length-2]+=r.pop())},Ki=(r)=>{let n=r.split(" "),t=n.length;for(;t>0&&!(wr(n[t-1])>0);)t--;return t===n.length?r:n.slice(0,t).join(" ")+n.slice(t).join("")},Zi=(r,n,t={})=>{if(t.trim!==!1&&r.trim()==="")return"";let o="",e,s,i=Vi(r),a=[""];for(let[d,c]of r.split(" ").entries()){t.trim!==!1&&(a[a.length-1]=a[a.length-1].trimStart());let u=wr(a[a.length-1]);if(d!==0&&(u>=n&&(t.wordWrap===!1||t.trim===!1)&&(a.push(""),u=0),(u>0||t.trim===!1)&&(a[a.length-1]+=" ",u++)),t.hard&&i[d]>n){let l=n-u,R=1+Math.floor((i[d]-l-1)/n);Math.floor((i[d]-1)/n)<R&&a.push(""),tn(a,c,n);continue}if(u+i[d]>n&&u>0&&i[d]>0){if(t.wordWrap===!1&&u<n){tn(a,c,n);continue}a.push("")}if(u+i[d]>n&&t.wordWrap===!1){tn(a,c,n);continue}a[a.length-1]+=c}t.trim!==!1&&(a=a.map((d)=>Ki(d)));let f=[...a.join(`
|
|
13
|
+
`)];for(let[d,c]of f.entries()){if(o+=c,Ar.has(c)){let{groups:l}=new RegExp(`(?:\\${rt}(?<code>\\d+)m|\\${sn}(?<uri>.*)${en})`).exec(f.slice(d).join(""))||{groups:{}};if(l.code!==void 0){let R=Number.parseFloat(l.code);e=R===Bi?void 0:R}else l.uri!==void 0&&(s=l.uri.length===0?void 0:l.uri)}let u=qi.codes.get(Number(e));f[d+1]===`
|
|
14
|
+
`?(s&&(o+=Kn("")),e&&u&&(o+=Vn(u))):c===`
|
|
15
|
+
`&&(e&&u&&(o+=Vn(e)),s&&(o+=Kn(s)))}return o},zi,Ir,Yi,on,Xi,Qi=(r,n,t)=>(n in r)?Xi(r,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[n]=t,M=(r,n,t)=>(Qi(r,typeof n!="symbol"?n+"":n,t),t),fn,Fi,Di,ro=(r,n,t)=>(n in r)?Di(r,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[n]=t,zn=(r,n,t)=>(ro(r,typeof n!="symbol"?n+"":n,t),t),dn,cn;var mn=I(()=>{A=hr(Fr(),1),Xn=hr(rn(),1);Si=Hi();Dn={exports:{}};(function(r){var n={};r.exports=n,n.eastAsianWidth=function(o){var e=o.charCodeAt(0),s=o.length==2?o.charCodeAt(1):0,i=e;return 55296<=e&&e<=56319&&56320<=s&&s<=57343&&(e&=1023,s&=1023,i=e<<10|s,i+=65536),i==12288||65281<=i&&i<=65376||65504<=i&&i<=65510?"F":i==8361||65377<=i&&i<=65470||65474<=i&&i<=65479||65482<=i&&i<=65487||65490<=i&&i<=65495||65498<=i&&i<=65500||65512<=i&&i<=65518?"H":4352<=i&&i<=4447||4515<=i&&i<=4519||4602<=i&&i<=4607||9001<=i&&i<=9002||11904<=i&&i<=11929||11931<=i&&i<=12019||12032<=i&&i<=12245||12272<=i&&i<=12283||12289<=i&&i<=12350||12353<=i&&i<=12438||12441<=i&&i<=12543||12549<=i&&i<=12589||12593<=i&&i<=12686||12688<=i&&i<=12730||12736<=i&&i<=12771||12784<=i&&i<=12830||12832<=i&&i<=12871||12880<=i&&i<=13054||13056<=i&&i<=19903||19968<=i&&i<=42124||42128<=i&&i<=42182||43360<=i&&i<=43388||44032<=i&&i<=55203||55216<=i&&i<=55238||55243<=i&&i<=55291||63744<=i&&i<=64255||65040<=i&&i<=65049||65072<=i&&i<=65106||65108<=i&&i<=65126||65128<=i&&i<=65131||110592<=i&&i<=110593||127488<=i&&i<=127490||127504<=i&&i<=127546||127552<=i&&i<=127560||127568<=i&&i<=127569||131072<=i&&i<=194367||177984<=i&&i<=196605||196608<=i&&i<=262141?"W":32<=i&&i<=126||162<=i&&i<=163||165<=i&&i<=166||i==172||i==175||10214<=i&&i<=10221||10629<=i&&i<=10630?"Na":i==161||i==164||167<=i&&i<=168||i==170||173<=i&&i<=174||176<=i&&i<=180||182<=i&&i<=186||188<=i&&i<=191||i==198||i==208||215<=i&&i<=216||222<=i&&i<=225||i==230||232<=i&&i<=234||236<=i&&i<=237||i==240||242<=i&&i<=243||247<=i&&i<=250||i==252||i==254||i==257||i==273||i==275||i==283||294<=i&&i<=295||i==299||305<=i&&i<=307||i==312||319<=i&&i<=322||i==324||328<=i&&i<=331||i==333||338<=i&&i<=339||358<=i&&i<=359||i==363||i==462||i==464||i==466||i==468||i==470||i==472||i==474||i==476||i==593||i==609||i==708||i==711||713<=i&&i<=715||i==717||i==720||728<=i&&i<=731||i==733||i==735||768<=i&&i<=879||913<=i&&i<=929||931<=i&&i<=937||945<=i&&i<=961||963<=i&&i<=969||i==1025||1040<=i&&i<=1103||i==1105||i==8208||8211<=i&&i<=8214||8216<=i&&i<=8217||8220<=i&&i<=8221||8224<=i&&i<=8226||8228<=i&&i<=8231||i==8240||8242<=i&&i<=8243||i==8245||i==8251||i==8254||i==8308||i==8319||8321<=i&&i<=8324||i==8364||i==8451||i==8453||i==8457||i==8467||i==8470||8481<=i&&i<=8482||i==8486||i==8491||8531<=i&&i<=8532||8539<=i&&i<=8542||8544<=i&&i<=8555||8560<=i&&i<=8569||i==8585||8592<=i&&i<=8601||8632<=i&&i<=8633||i==8658||i==8660||i==8679||i==8704||8706<=i&&i<=8707||8711<=i&&i<=8712||i==8715||i==8719||i==8721||i==8725||i==8730||8733<=i&&i<=8736||i==8739||i==8741||8743<=i&&i<=8748||i==8750||8756<=i&&i<=8759||8764<=i&&i<=8765||i==8776||i==8780||i==8786||8800<=i&&i<=8801||8804<=i&&i<=8807||8810<=i&&i<=8811||8814<=i&&i<=8815||8834<=i&&i<=8835||8838<=i&&i<=8839||i==8853||i==8857||i==8869||i==8895||i==8978||9312<=i&&i<=9449||9451<=i&&i<=9547||9552<=i&&i<=9587||9600<=i&&i<=9615||9618<=i&&i<=9621||9632<=i&&i<=9633||9635<=i&&i<=9641||9650<=i&&i<=9651||9654<=i&&i<=9655||9660<=i&&i<=9661||9664<=i&&i<=9665||9670<=i&&i<=9672||i==9675||9678<=i&&i<=9681||9698<=i&&i<=9701||i==9711||9733<=i&&i<=9734||i==9737||9742<=i&&i<=9743||9748<=i&&i<=9749||i==9756||i==9758||i==9792||i==9794||9824<=i&&i<=9825||9827<=i&&i<=9829||9831<=i&&i<=9834||9836<=i&&i<=9837||i==9839||9886<=i&&i<=9887||9918<=i&&i<=9919||9924<=i&&i<=9933||9935<=i&&i<=9953||i==9955||9960<=i&&i<=9983||i==10045||i==10071||10102<=i&&i<=10111||11093<=i&&i<=11097||12872<=i&&i<=12879||57344<=i&&i<=63743||65024<=i&&i<=65039||i==65533||127232<=i&&i<=127242||127248<=i&&i<=127277||127280<=i&&i<=127337||127344<=i&&i<=127386||917760<=i&&i<=917999||983040<=i&&i<=1048573||1048576<=i&&i<=1114109?"A":"N"},n.characterLength=function(o){var e=this.eastAsianWidth(o);return e=="F"||e=="W"||e=="A"?2:1};function t(o){return o.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g)||[]}n.length=function(o){for(var e=t(o),s=0,i=0;i<e.length;i++)s=s+this.characterLength(e[i]);return s},n.slice=function(o,e,s){textLen=n.length(o),e=e||0,s=s||1,e<0&&(e=textLen+e),s<0&&(s=textLen+s);for(var i="",a=0,f=t(o),d=0;d<f.length;d++){var c=f[d],u=n.length(c);if(a>=e-(u==2?1:0))if(a+u<=s)i+=c;else break;a+=u}return i}})(Dn);Ci=Dn.exports,Wi=Fn(Ci),Mi=Fn(Gi);$={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};Object.keys($.modifier);Ui=Object.keys($.color),Pi=Object.keys($.bgColor);[...Ui];qi=Li(),Ar=new Set(["\x1B","\x9B"]),sn=`${ji}8;;`;zi=["up","down","left","right","space","enter","cancel"],Ir={actions:new Set(zi),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["\x03","cancel"],["escape","cancel"]])};Yi=globalThis.process.platform.startsWith("win"),on=Symbol("clack:cancel");Xi=Object.defineProperty;fn=class fn extends Hr{get cursor(){return this.value?0:1}get _value(){return this.cursor===0}constructor(r){super(r,!1),this.value=!!r.initialValue,this.on("value",()=>{this.value=this._value}),this.on("confirm",(n)=>{this.output.write(A.cursor.move(0,-1)),this.value=n,this.state="submit",this.close()}),this.on("cursor",()=>{this.value=!this.value})}};Fi=new WeakMap;Di=Object.defineProperty;dn=class dn extends Hr{constructor(r){super(r,!1),zn(this,"options"),zn(this,"cursor",0),this.options=r.options,this.cursor=this.options.findIndex(({value:n})=>n===r.initialValue),this.cursor===-1&&(this.cursor=0),this.changeValue(),this.on("cursor",(n)=>{switch(n){case"left":case"up":this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break;case"down":case"right":this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}this.changeValue()})}get _value(){return this.options[this.cursor]}changeValue(){this.value=this._value.value}};cn=class cn extends Hr{get valueWithCursor(){if(this.state==="submit")return this.value;if(this.cursor>=this.value.length)return`${this.value}\u2588`;let r=this.value.slice(0,this.cursor),[n,...t]=this.value.slice(this.cursor);return`${r}${Xn.default.inverse(n)}${t.join("")}`}get cursor(){return this._cursor}constructor(r){super(r),this.on("finalize",()=>{this.value||(this.value=r.defaultValue)})}}});import V from"process";function no(){return V.platform!=="win32"?V.env.TERM!=="linux":!!V.env.CI||!!V.env.WT_SESSION||!!V.env.TERMINUS_SUBLIME||V.env.ConEmuTask==="{cmd::Cmder}"||V.env.TERM_PROGRAM==="Terminus-Sublime"||V.env.TERM_PROGRAM==="vscode"||V.env.TERM==="xterm-256color"||V.env.TERM==="alacritty"||V.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var p,Sr,un,v=(r,n)=>un?r:n,to,it,ot,yn,io,_,cr,pn,ln,ys,hs,Rs,gs,ws,bs,Es,xs,oo,eo,so,ao,hn=(r)=>{switch(r){case"initial":case"active":return p.default.cyan(to);case"cancel":return p.default.red(it);case"error":return p.default.yellow(ot);case"submit":return p.default.green(yn)}},fo=(r)=>{let{cursor:n,options:t,style:o}=r,e=r.maxItems??Number.POSITIVE_INFINITY,s=Math.max(process.stdout.rows-4,0),i=Math.min(s,Math.max(e,5)),a=0;n>=a+i-3?a=Math.max(Math.min(n-i+3,t.length-i),0):n<a+2&&(a=Math.max(n-2,0));let f=i<t.length&&a>0,d=i<t.length&&a+i<t.length;return t.slice(a,a+i).map((c,u,l)=>{let R=u===0&&f,h=u===l.length-1&&d;return R||h?p.default.dim("..."):o(c,u+a===n)})},T=(r)=>new cn({validate:r.validate,placeholder:r.placeholder,defaultValue:r.defaultValue,initialValue:r.initialValue,render(){let n=`${p.default.gray(_)}
|
|
16
|
+
${hn(this.state)} ${r.message}
|
|
17
|
+
`,t=r.placeholder?p.default.inverse(r.placeholder[0])+p.default.dim(r.placeholder.slice(1)):p.default.inverse(p.default.hidden("_")),o=this.value?this.valueWithCursor:t;switch(this.state){case"error":return`${n.trim()}
|
|
18
|
+
${p.default.yellow(_)} ${o}
|
|
19
|
+
${p.default.yellow(cr)} ${p.default.yellow(this.error)}
|
|
20
|
+
`;case"submit":return`${n}${p.default.gray(_)} ${p.default.dim(this.value||r.placeholder)}`;case"cancel":return`${n}${p.default.gray(_)} ${p.default.strikethrough(p.default.dim(this.value??""))}${this.value?.trim()?`
|
|
21
|
+
${p.default.gray(_)}`:""}`;default:return`${n}${p.default.cyan(_)} ${o}
|
|
22
|
+
${p.default.cyan(cr)}
|
|
23
|
+
`}}}).prompt(),S=(r)=>{let n=r.active??"Yes",t=r.inactive??"No";return new fn({active:n,inactive:t,initialValue:r.initialValue??!0,render(){let o=`${p.default.gray(_)}
|
|
24
|
+
${hn(this.state)} ${r.message}
|
|
25
|
+
`,e=this.value?n:t;switch(this.state){case"submit":return`${o}${p.default.gray(_)} ${p.default.dim(e)}`;case"cancel":return`${o}${p.default.gray(_)} ${p.default.strikethrough(p.default.dim(e))}
|
|
26
|
+
${p.default.gray(_)}`;default:return`${o}${p.default.cyan(_)} ${this.value?`${p.default.green(pn)} ${n}`:`${p.default.dim(ln)} ${p.default.dim(n)}`} ${p.default.dim("/")} ${this.value?`${p.default.dim(ln)} ${p.default.dim(t)}`:`${p.default.green(pn)} ${t}`}
|
|
27
|
+
${p.default.cyan(cr)}
|
|
28
|
+
`}}}).prompt()},tr=(r)=>{let n=(t,o)=>{let e=t.label??String(t.value);switch(o){case"selected":return`${p.default.dim(e)}`;case"active":return`${p.default.green(pn)} ${e} ${t.hint?p.default.dim(`(${t.hint})`):""}`;case"cancelled":return`${p.default.strikethrough(p.default.dim(e))}`;default:return`${p.default.dim(ln)} ${p.default.dim(e)}`}};return new dn({options:r.options,initialValue:r.initialValue,render(){let t=`${p.default.gray(_)}
|
|
29
|
+
${hn(this.state)} ${r.message}
|
|
30
|
+
`;switch(this.state){case"submit":return`${t}${p.default.gray(_)} ${n(this.options[this.cursor],"selected")}`;case"cancel":return`${t}${p.default.gray(_)} ${n(this.options[this.cursor],"cancelled")}
|
|
31
|
+
${p.default.gray(_)}`;default:return`${t}${p.default.cyan(_)} ${fo({cursor:this.cursor,options:this.options,maxItems:r.maxItems,style:(o,e)=>n(o,e?"active":"inactive")}).join(`
|
|
32
|
+
${p.default.cyan(_)} `)}
|
|
33
|
+
${p.default.cyan(cr)}
|
|
34
|
+
`}}}).prompt()},Rn=(r="")=>{process.stdout.write(`${p.default.gray(cr)} ${p.default.red(r)}
|
|
48
35
|
|
|
49
|
-
`)},
|
|
50
|
-
`)},
|
|
51
|
-
${
|
|
36
|
+
`)},et=(r="")=>{process.stdout.write(`${p.default.gray(io)} ${r}
|
|
37
|
+
`)},st=(r="")=>{process.stdout.write(`${p.default.gray(_)}
|
|
38
|
+
${p.default.gray(cr)} ${r}
|
|
52
39
|
|
|
53
|
-
`)},
|
|
54
|
-
`);let
|
|
55
|
-
`);process.stdout.write(
|
|
56
|
-
`);let W=0,
|
|
57
|
-
`):process.stdout.write(`${
|
|
58
|
-
`),
|
|
59
|
-
`);
|
|
40
|
+
`)},m,$s,Q=({indicator:r="dots"}={})=>{let n=un?["\u25D2","\u25D0","\u25D3","\u25D1"]:["\u2022","o","O","0"],t=un?80:120,o=process.env.CI==="true",e,s,i=!1,a="",f,d=performance.now(),c=(O)=>{let W=O>1?"Something went wrong":"Canceled";i&&Or(W,O)},u=()=>c(2),l=()=>c(1),R=()=>{process.on("uncaughtExceptionMonitor",u),process.on("unhandledRejection",u),process.on("SIGINT",l),process.on("SIGTERM",l),process.on("exit",c)},h=()=>{process.removeListener("uncaughtExceptionMonitor",u),process.removeListener("unhandledRejection",u),process.removeListener("SIGINT",l),process.removeListener("SIGTERM",l),process.removeListener("exit",c)},g=()=>{if(f===void 0)return;o&&process.stdout.write(`
|
|
41
|
+
`);let O=f.split(`
|
|
42
|
+
`);process.stdout.write(Sr.cursor.move(-999,O.length-1)),process.stdout.write(Sr.erase.down(O.length))},N=(O)=>O.replace(/\.+$/,""),ar=(O)=>{let W=(performance.now()-O)/1000,J=Math.floor(W/60),dr=Math.floor(W%60);return J>0?`[${J}m ${dr}s]`:`[${dr}s]`},fr=(O="")=>{i=!0,e=tt(),a=N(O),d=performance.now(),process.stdout.write(`${p.default.gray(_)}
|
|
43
|
+
`);let W=0,J=0;R(),s=setInterval(()=>{if(o&&a===f)return;g(),f=a;let dr=p.default.magenta(n[W]);if(o)process.stdout.write(`${dr} ${a}...`);else if(r==="timer")process.stdout.write(`${dr} ${a} ${ar(d)}`);else{let mi=".".repeat(Math.floor(J)).slice(0,3);process.stdout.write(`${dr} ${a}${mi}`)}W=W+1<n.length?W+1:0,J=J<n.length?J+0.125:0},t)},Or=(O="",W=0)=>{i=!1,clearInterval(s),g();let J=W===0?p.default.green(yn):W===1?p.default.red(it):p.default.red(ot);a=N(O??a),r==="timer"?process.stdout.write(`${J} ${a} ${ar(d)}
|
|
44
|
+
`):process.stdout.write(`${J} ${a}
|
|
45
|
+
`),h(),e()};return{start:fr,stop:Or,message:(O="")=>{a=N(O??a)}}},at=async(r,n)=>{let t={},o=Object.keys(r);for(let e of o){let s=r[e],i=await s({results:t})?.catch((a)=>{throw a});if(typeof n?.onCancel=="function"&&H(i)){t[e]="canceled",n.onCancel({results:t});continue}t[e]=i}return t};var L=I(()=>{mn();mn();p=hr(rn(),1),Sr=hr(Fr(),1);un=no(),to=v("\u25C6","*"),it=v("\u25A0","x"),ot=v("\u25B2","x"),yn=v("\u25C7","o"),io=v("\u250C","T"),_=v("\u2502","|"),cr=v("\u2514","\u2014"),pn=v("\u25CF",">"),ln=v("\u25CB"," "),ys=v("\u25FB","[\u2022]"),hs=v("\u25FC","[+]"),Rs=v("\u25FB","[ ]"),gs=v("\u25AA","\u2022"),ws=v("\u2500","-"),bs=v("\u256E","+"),Es=v("\u251C","+"),xs=v("\u256F","+"),oo=v("\u25CF","\u2022"),eo=v("\u25C6","*"),so=v("\u25B2","!"),ao=v("\u25A0","x"),m={message:(r="",{symbol:n=p.default.gray(_)}={})=>{let t=[`${p.default.gray(_)}`];if(r){let[o,...e]=r.split(`
|
|
46
|
+
`);t.push(`${n} ${o}`,...e.map((s)=>`${p.default.gray(_)} ${s}`))}process.stdout.write(`${t.join(`
|
|
60
47
|
`)}
|
|
61
|
-
`)},info:(
|
|
62
|
-
`)}function
|
|
63
|
-
`)}var Ci=v(()=>{Be()});var _i=v(()=>{G()});class Ni{options;queue=[];tokens;lastRefill;processing=!1;constructor(t){this.options=t;this.tokens=t.maxBurst||t.maxRequests,this.lastRefill=Date.now()}async acquire(){return new Promise((t)=>{this.queue.push({resolve:t,timestamp:Date.now()}),this.processQueue()})}processQueue(){if(this.processing)return;this.processing=!0;let t=()=>{this.refillTokens();while(this.queue.length>0&&this.tokens>0){let e=this.queue.shift();if(e)this.tokens--,e.resolve()}if(this.queue.length>0){let e=this.options.windowMs/this.options.maxRequests;setTimeout(()=>t(),e)}else this.processing=!1};t()}refillTokens(){let t=Date.now(),e=t-this.lastRefill,n=Math.floor(e/(this.options.windowMs/this.options.maxRequests));if(n>0)this.tokens=Math.min(this.tokens+n,this.options.maxBurst||this.options.maxRequests),this.lastRefill=t}reset(){this.queue=[],this.tokens=this.options.maxBurst||this.options.maxRequests,this.lastRefill=Date.now(),this.processing=!1}getQueueLength(){return this.queue.length}}async function it(t,e={}){let n={...ws,...e},i=new Error("Operation failed");for(let r=1;r<=n.maxAttempts;r++)try{return await t()}catch(s){if(i=s instanceof Error?s:new Error(String(s)),!n.retryableErrors.some((f)=>i.message.toLowerCase().includes(f.toLowerCase()))||r===n.maxAttempts)throw i;n.onRetry(r,i);let a=Math.min(n.initialDelay*n.backoffMultiplier**(r-1),n.maxDelay);await new Promise((f)=>setTimeout(f,a))}throw i}function xs(t,e={}){return async(...n)=>{return it(()=>t(...n),e)}}var ws;var Si=v(()=>{G();ws={backoffMultiplier:2,initialDelay:1000,maxAttempts:3,maxDelay:30000,onRetry:(t,e)=>{re.warn(`Retry attempt ${t}: ${e.message}`)},retryableErrors:["ECONNREFUSED","ECONNRESET","ETIMEDOUT","ENOTFOUND","rate limit","429","503","502","504","npm ERR!","EPUBLISHCONFLICT"]}});import{existsSync as $s}from"fs";import{readFile as vs}from"fs/promises";import{homedir as Rs}from"os";import{join as Wi}from"path";async function As(){try{if($s(ln)){let t=await vs(ln,"utf-8");return JSON.parse(t)}}catch{}return{}}async function Ts(t){try{await Bun.write(ln,JSON.stringify(t,null,2))}catch{}}async function Os(t){try{let e=await fetch(`https://registry.npmjs.org/${t}/latest`,{signal:AbortSignal.timeout(5000)});if(!e.ok)return null;return(await e.json()).version}catch{return null}}async function Bi(t){let{packageName:e,currentVersion:n,checkInterval:i=Es,silent:r=!1}=t;if(process.env.CI||process.env.CONTINUOUS_INTEGRATION)return null;if(process.env.R5N_NO_UPDATE_CHECK==="1")return null;try{let s=await As(),o=s[e],a=Date.now();if(o&&a-o.lastChecked<i)return{currentVersion:n,lastChecked:o.lastChecked,latestVersion:o.latestVersion,name:e,updateAvailable:Mi(o.latestVersion,n)>0};let f=await Os(e);if(!f)return null;if(s[e]={lastChecked:a,latestVersion:f},!r)Ts(s).catch(()=>{});return{currentVersion:n,lastChecked:a,latestVersion:f,name:e,updateAvailable:Mi(f,n)>0}}catch{return null}}function Ui(t){let{name:e,currentVersion:n,latestVersion:i}=t;return["","\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510","\u2502 \u2502",`\u2502 Update available for ${(e.split("/").pop()||e).padEnd(29)} \u2502`,`\u2502 ${n.padEnd(15)} \u2192 ${i.padEnd(32)} \u2502`,"\u2502 \u2502",`\u2502 Run: bun update -g ${e.padEnd(30)} \u2502`,"\u2502 \u2502","\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",""].join(`
|
|
64
|
-
`
|
|
65
|
-
`),r=[];for(let s of i.slice(1)){let o=s.split(/\s+/);if(o.length<9)continue;let a=o[0],f=Number.parseInt(o[4]||"0",10),u=o.slice(8).join(" ");if(u==="."||u==="..")continue;r.push({isDirectory:a?.startsWith("d")||!1,modifiedTime:new Date,name:u,size:f})}return r}async copyFile(t,e){let n=j(t),i=j(e);await ft`cp ${n} ${i}`.quiet()}async moveFile(t,e){let n=j(t),i=j(e);await ft`mv ${n} ${i}`.quiet()}async getFileInfo(t){if(!await Bun.file(t).exists())return null;let n=j(t),r=(await ft`stat -f "%z %m %Y" ${n} 2>/dev/null || stat -c "%s %Y %F" ${n}`.quiet()).stdout.toString().trim().split(" "),s=r[0]||"0",o=r[1]||"0";return{isDirectory:!1,modifiedTime:new Date(Number.parseInt(o,10)*1000),name:t.split("/").pop()||t,size:Number.parseInt(s,10)}}async chmod(t,e){let n=j(t);await ft`chmod ${e} ${n}`.quiet()}async readDir(t){return(await this.listDirectory(t)).map((n)=>({isDirectory:n.isDirectory,isFile:!n.isDirectory,name:n.name}))}async ensureDir(t){if(!await this.exists(t))await this.createDirectory(t,{recursive:!0})}}async function mn(t){if(!await y.exists(t))await y.createDirectory(t,{recursive:!0})}async function zi(t,e){let n=JSON.stringify(e,null,2);await y.writeFile(t,n)}var y;var F=v(()=>{Mt();y=new $e});var Ks,Vs,Yi;var Ii=v(()=>{O();Ks=I({directory:bt("./gh-runners"),labels:pt(),name:bt("runner"),numberOfMachines:lt(cn(),1),os:Kt(["osx","linux","windows"],"osx"),overwrite:Ht(!1),run:Ht(!1),runnerGroup:pt(),url:pt()}),Vs=Ot(Ks),Yi=Ot(I({defaultProfile:pt(),profiles:be(Vs.validator)}))});import{join as Zs}from"path";async function yn(t=process.cwd()){for(let e of zs){let n=Zs(t,e);if(await y.exists(n))return n}return null}async function N(t){let e=t?.configPath||await yn();if(!e)return null;let n=gn.get(e);if(n)return n;if(!await y.exists(e))return null;try{let i=await y.readFile(e),r=e.endsWith(".toml")?Ys(i):JSON.parse(i),s=Yi.parse(r);return gn.set(e,s),s}catch(i){if(i instanceof Error)throw new Error(`Invalid config file: ${i.message}`);throw i}}async function S(t,e){if(!t)return null;let n=e||t.defaultProfile;if(!n)return null;return t.profiles[n]||null}function ve(t,e){if(!t)return e;let n={...e};for(let[i,r]of Object.entries(t)){let s=i;if(n[s]===void 0&&r!==void 0)n[s]=r}return n}function Ys(t){try{return Bun.TOML.parse(t)}catch(e){throw new Error(`Failed to parse TOML configuration: ${e}`)}}var zs;var V=v(()=>{Vi();F();Ii();zs=["hydra.json",".hydra.json","hydra.toml",".hydra.toml"]});function w({prefix:t,secrets:e=[]}){let n=$({prefix:t}),i=[...e];if(process.env.GITHUB_TOKEN)i.push(process.env.GITHUB_TOKEN);if(process.env.RUNNER_TOKEN)i.push(process.env.RUNNER_TOKEN);if(process.env.RUNNER_CFG_PAT)i.push(process.env.RUNNER_CFG_PAT);let r=(s)=>{if(typeof s==="string")return Zi(s,i);if(typeof s==="object"&&s!==null){let o=Array.isArray(s)?[]:{};for(let a in s)o[a]=r(s[a]);return o}return s};return{...n,addSecret:(s)=>{if(s&&!i.includes(s))i.push(s)},child:(s)=>w({prefix:`${t}:${s}`,secrets:i}),debug:(...s)=>n.debug(...s.map(r)),error:(...s)=>n.error(...s.map(r)),info:(...s)=>n.info(...s.map(r)),warn:(...s)=>n.warn(...s.map(r))}}var tt=v(()=>{G();Mt()});import{EventEmitter as Is}from"events";class Fi{name;options;state="closed";failureCount=0;lastFailureTime;halfOpenAttempts=0;resetTimer;logger=w({prefix:"CircuitBreaker"});constructor(t,e){this.name=t;this.options=e}async execute(t){if(this.state==="open")if(this.shouldAttemptReset())this.state="half_open",this.halfOpenAttempts=0;else throw new Error(`Circuit breaker ${this.name} is OPEN`);try{let e=await t();return this.onSuccess(),e}catch(e){throw this.onFailure(),e}}shouldAttemptReset(){if(!this.lastFailureTime)return!1;return Date.now()-this.lastFailureTime.getTime()>=this.options.resetTimeout}onSuccess(){if(this.state==="half_open"){if(this.halfOpenAttempts++,this.halfOpenAttempts>=this.options.halfOpenMaxAttempts)this.reset()}else if(this.state==="closed")this.failureCount=0}onFailure(){if(this.lastFailureTime=new Date,this.failureCount++,this.state==="half_open")this.trip();else if(this.failureCount>=this.options.failureThreshold)this.trip()}trip(){if(this.state="open",this.logger.warn(`Circuit breaker ${this.name} tripped`),this.resetTimer)clearTimeout(this.resetTimer);this.resetTimer=setTimeout(()=>{this.state="half_open",this.halfOpenAttempts=0,this.logger.info(`Circuit breaker ${this.name} attempting reset`)},this.options.resetTimeout)}reset(){if(this.state="closed",this.failureCount=0,this.halfOpenAttempts=0,this.lastFailureTime=void 0,this.resetTimer)clearTimeout(this.resetTimer),this.resetTimer=void 0;this.logger.info(`Circuit breaker ${this.name} reset`)}getState(){return this.state}getStats(){return{failureCount:this.failureCount,halfOpenAttempts:this.halfOpenAttempts,lastFailureTime:this.lastFailureTime,state:this.state}}}var Di,ht;var bn=v(()=>{tt();Di=class Di extends Is{strategies=new Map;circuitBreakers=new Map;errorMetrics=new Map;logger=w({prefix:"ErrorRecovery"});constructor(){super();this.setupDefaultStrategies()}setupDefaultStrategies(){this.addStrategy({backoffMultiplier:2,baseDelay:1000,maxDelay:30000,maxRetries:3,shouldRetry:(t,e)=>{return e<3&&this.isTransientError(t)},type:"transient"}),this.addStrategy({backoffMultiplier:1.5,baseDelay:2000,maxDelay:60000,maxRetries:5,onRetry:(t,e,n)=>{this.logger.info(`Network error retry attempt ${e} after ${n}ms`)},shouldRetry:(t,e)=>{return e<5&&this.isNetworkError(t)},type:"network"}),this.addStrategy({backoffMultiplier:1,baseDelay:0,maxDelay:0,maxRetries:0,shouldRetry:()=>!1,type:"configuration"}),this.addStrategy({backoffMultiplier:2,baseDelay:5000,maxDelay:30000,maxRetries:2,shouldRetry:(t,e)=>{return e<2&&this.isResourceError(t)},type:"resource"})}addStrategy(t){this.strategies.set(t.type,t)}createCircuitBreaker(t,e={}){let n=new Fi(t,{failureThreshold:e.failureThreshold??5,halfOpenMaxAttempts:e.halfOpenMaxAttempts??3,resetTimeout:e.resetTimeout??60000});return this.circuitBreakers.set(t,n),n}async executeWithRecovery(t,e){let n,i=0;while(!0)try{let r=await t();return this.recordSuccess(e),r}catch(r){n=r,i++;let s=this.classifyError(n),o=this.strategies.get(s);if(this.recordError(e,n,s),!o||!o.shouldRetry(n,i)){if(o?.onMaxRetriesExceeded)o.onMaxRetriesExceeded(n);throw n}let a=this.calculateDelay(i,o);if(o.onRetry)o.onRetry(n,i,a);this.emit("retryAttempt",{attempt:i,context:e,delay:a,error:n,errorType:s}),await this.sleep(a)}}classifyError(t){if(this.isNetworkError(t))return"network";if(this.isConfigurationError(t))return"configuration";if(this.isResourceError(t))return"resource";if(this.isTransientError(t))return"transient";return"unknown"}isNetworkError(t){let e=["econnrefused","enotfound","etimedout","econnreset","network","socket","dns"],n=t.message.toLowerCase();return e.some((i)=>n.includes(i))}isConfigurationError(t){let e=["invalid configuration","missing required","invalid token","authentication failed","permission denied"],n=t.message.toLowerCase();return e.some((i)=>n.includes(i))}isResourceError(t){let e=["out of memory","disk full","no space","resource exhausted","too many open files"],n=t.message.toLowerCase();return e.some((i)=>n.includes(i))}isTransientError(t){let e=["temporary","try again","rate limit","busy","unavailable"],n=t.message.toLowerCase();return e.some((i)=>n.includes(i))}calculateDelay(t,e){let i=e.baseDelay*e.backoffMultiplier**(t-1)*(0.5+Math.random()*0.5);return Math.min(i,e.maxDelay)}recordError(t,e,n){let i=`${t.operation}:${n}`,r=this.errorMetrics.get(i)||{count:0,lastOccurred:new Date};r.count++,r.lastOccurred=new Date,this.errorMetrics.set(i,r),this.emit("errorRecorded",{context:t,error:e,errorType:n,metrics:r}),this.logger.error(`Error in ${t.operation}:`,e)}recordSuccess(t){this.emit("operationSuccess",{context:t})}sleep(t){return new Promise((e)=>setTimeout(e,t))}getErrorMetrics(){return new Map(this.errorMetrics)}getCircuitBreaker(t){return this.circuitBreakers.get(t)}getAllCircuitBreakers(){return new Map(this.circuitBreakers)}resetMetrics(){this.errorMetrics.clear(),this.emit("metricsReset")}};ht=new Di});import{EventEmitter as Fs}from"events";var wn;var to=v(()=>{tt();wn=class wn extends Fs{healthMetrics=new Map;healthCheckIntervals=new Map;heartbeatTimeouts=new Map;logger=w({prefix:"WorkerHealthMonitor"});options;constructor(t={}){super();this.options={autoRestart:t.autoRestart??!0,criticalThreshold:t.criticalThreshold??180000,healthCheckInterval:t.healthCheckInterval??60000,heartbeatInterval:t.heartbeatInterval??30000,maxRestarts:t.maxRestarts??3,unhealthyThreshold:t.unhealthyThreshold??90000}}startMonitoring(t,e){if(this.healthMetrics.has(t)){this.logger.warn(`Already monitoring worker ${t}`);return}let n={errorCount:0,lastHeartbeat:new Date,restartCount:e.restartCount,status:"healthy",uptime:0,workerId:t};this.healthMetrics.set(t,n),this.logger.info(`Started monitoring worker ${t}`),this.scheduleHealthCheck(t),this.scheduleHeartbeatTimeout(t),this.emit("monitoringStarted",t,n)}stopMonitoring(t){let e=this.healthCheckIntervals.get(t);if(e)clearInterval(e),this.healthCheckIntervals.delete(t);let n=this.heartbeatTimeouts.get(t);if(n)clearTimeout(n),this.heartbeatTimeouts.delete(t);this.healthMetrics.delete(t),this.logger.info(`Stopped monitoring worker ${t}`),this.emit("monitoringStopped",t)}recordHeartbeat(t,e){let n=this.healthMetrics.get(t);if(!n){this.logger.warn(`Received heartbeat for unmonitored worker ${t}`);return}if(n.lastHeartbeat=new Date,e?.cpuUsage!==void 0)n.cpuUsage=e.cpuUsage;if(e?.memoryUsage!==void 0)n.memoryUsage=e.memoryUsage;if(e?.responseTime!==void 0)n.responseTime=e.responseTime;n.uptime=Date.now()-n.lastHeartbeat.getTime();let i=n.status;if(n.status=this.calculateHealthStatus(n),i!==n.status)this.logger.info(`Worker ${t} health changed: ${i} -> ${n.status}`),this.emit("healthChanged",t,n.status,i);this.scheduleHeartbeatTimeout(t)}recordError(t,e){let n=this.healthMetrics.get(t);if(!n)return;n.errorCount++,n.lastError=e.message;let i=n.status;if(n.status=this.calculateHealthStatus(n),i!==n.status)this.emit("healthChanged",t,n.status,i);this.logger.warn(`Worker ${t} error recorded: ${e.message}`)}getHealthMetrics(t){return this.healthMetrics.get(t)}getAllHealthMetrics(){return Array.from(this.healthMetrics.values())}getHealthSummary(){let t={critical:0,healthy:0,total:0,unknown:0,warning:0};for(let e of this.healthMetrics.values())t.total++,t[e.status]++;return t}scheduleHealthCheck(t){let e=setInterval(()=>{this.performHealthCheck(t)},this.options.healthCheckInterval);this.healthCheckIntervals.set(t,e)}scheduleHeartbeatTimeout(t){let e=this.heartbeatTimeouts.get(t);if(e)clearTimeout(e);let n=setTimeout(()=>{this.handleMissedHeartbeat(t)},this.options.heartbeatInterval*2);this.heartbeatTimeouts.set(t,n)}performHealthCheck(t){let e=this.healthMetrics.get(t);if(!e)return;let n=e.status;if(e.status=this.calculateHealthStatus(e),n!==e.status)this.logger.info(`Worker ${t} health check: ${n} -> ${e.status}`),this.emit("healthChanged",t,e.status,n);if(e.status==="critical"&&this.options.autoRestart)if(e.restartCount<this.options.maxRestarts)this.logger.warn(`Worker ${t} is critical, requesting restart`),this.emit("restartRequired",t,e);else this.logger.error(`Worker ${t} exceeded max restarts (${this.options.maxRestarts})`),this.emit("maxRestartsExceeded",t,e);this.emit("healthCheckCompleted",t,e)}handleMissedHeartbeat(t){let e=this.healthMetrics.get(t);if(!e)return;this.logger.warn(`Worker ${t} missed heartbeat`);let n=e.status;if(e.status=this.calculateHealthStatus(e),n!==e.status)this.emit("healthChanged",t,e.status,n);this.emit("heartbeatMissed",t,e)}calculateHealthStatus(t){let e=Date.now()-t.lastHeartbeat.getTime();if(e>this.options.criticalThreshold)return"critical";if(e>this.options.unhealthyThreshold)return"warning";if(t.errorCount>10)return"warning";if(t.cpuUsage&&t.cpuUsage>90)return"warning";if(t.memoryUsage&&t.memoryUsage>90)return"warning";if(t.responseTime&&t.responseTime>5000)return"warning";return"healthy"}async checkWorkerResponsiveness(t,e=5000){return new Promise((n)=>{let i=setTimeout(()=>{n(!1)},e);this.once(`workerResponse:${t}`,()=>{clearTimeout(i),n(!0)}),this.emit("pingWorker",t)})}reportWorkerResponse(t){this.emit(`workerResponse:${t}`)}}});import{EventEmitter as Ds}from"events";var wt,Vt;var Wt=v(()=>{bn();tt();to();wt=class wt extends Ds{options;workers=new Map;workerInfo=new Map;shutdownInProgress=!1;logger=w({prefix:"WorkerManager"});cleanupRegistered=!1;healthMonitor;circuitBreaker=ht.createCircuitBreaker("worker-operations",{failureThreshold:5,halfOpenMaxAttempts:3,resetTimeout:60000});constructor(t={}){super();this.options=t;this.options={gracefulShutdownTimeout:30000,maxRestarts:3,maxWorkers:100,restartDelay:1000,restartOnError:!0,...t},this.healthMonitor=new wn({autoRestart:this.options.restartOnError??!0,maxRestarts:this.options.maxRestarts||3}),this.setupHealthMonitorHandlers(),this.registerCleanup()}setupHealthMonitorHandlers(){this.healthMonitor.on("restartRequired",(t)=>{let e=this.getWorkerConfig(t);if(e){let n=this.workerInfo.get(t);if(n)this.scheduleRestart(e,n)}}),this.healthMonitor.on("healthChanged",(t,e,n)=>{this.emit("workerHealthChanged",t,e,n)}),this.healthMonitor.on("maxRestartsExceeded",(t)=>{this.logger.error(`Worker ${t} exceeded max restarts, not restarting`),this.emit("workerMaxRestartsExceeded",t)})}getWorkerConfig(t){return}registerCleanup(){if(this.cleanupRegistered)return;this.cleanupRegistered=!0;let t=async()=>{if(!this.shutdownInProgress)await this.shutdown()};process.on("exit",()=>{if(!this.shutdownInProgress&&this.workers.size>0)this.logger.warn("Forced exit with active workers")}),process.on("SIGINT",async()=>{this.logger.info("Received SIGINT, initiating graceful shutdown..."),await t(),process.exit(0)}),process.on("SIGTERM",async()=>{this.logger.info("Received SIGTERM, initiating graceful shutdown..."),await t(),process.exit(0)}),process.on("uncaughtException",async(e)=>{this.logger.error("Uncaught exception:",e),await t(),process.exit(1)})}async createWorker(t){if(this.shutdownInProgress)throw new Error("Cannot create worker during shutdown");if(this.workers.size>=(this.options.maxWorkers||100))throw new Error(`Maximum worker limit reached: ${this.options.maxWorkers}`);if(this.workers.has(t.id))throw new Error(`Worker with id ${t.id} already exists`);let e={id:t.id,name:t.name,restartCount:0,startTime:new Date,status:"starting"};this.workerInfo.set(t.id,e);let n={operation:"createWorker",runnerName:t.name,workerId:t.id};try{await this.circuitBreaker.execute(async()=>{await ht.executeWithRecovery(async()=>{let i=new Worker(t.scriptPath,{name:t.name,ref:!0});if(this.workers.set(t.id,i),this.setupWorkerHandlers(i,t,e),t.data)i.postMessage(t.data);e.status="running",this.emit("workerStarted",e),this.logger.info(`Worker ${t.name} (${t.id}) started`),this.healthMonitor.startMonitoring(t.id,e)},n)})}catch(i){throw e.status="error",e.error=i,e.endTime=new Date,this.emit("workerError",e,i),i}}setupWorkerHandlers(t,e,n){t.addEventListener("message",({data:i})=>{if(i.type==="heartbeat")this.healthMonitor.recordHeartbeat(e.id,i.metrics);else this.emit("workerMessage",n,i),e.onMessage?.(i)}),t.addEventListener("error",(i)=>{if(this.logger.error(`Worker ${e.name} error:`,i),n.status="error",n.error=i.error||i,this.emit("workerError",n,i),e.onError?.(i.error||i),this.healthMonitor.recordError(e.id,i.error||i),this.options.restartOnError&&n.restartCount<(this.options.maxRestarts||3))this.scheduleRestart(e,n)}),t.addEventListener("exit",(i)=>{let r=i.code||0;if(this.logger.info(`Worker ${e.name} exited with code ${r}`),this.workers.delete(e.id),n.status="stopped",n.endTime=new Date,this.emit("workerExit",n,r),e.onExit?.(r),this.healthMonitor.stopMonitoring(e.id),r!==0&&this.options.restartOnError&&n.restartCount<(this.options.maxRestarts||3))this.scheduleRestart(e,n)})}scheduleRestart(t,e){if(this.shutdownInProgress)return;e.restartCount++,this.logger.info(`Scheduling restart for worker ${t.name} (attempt ${e.restartCount}/${this.options.maxRestarts})`),setTimeout(async()=>{if(!this.shutdownInProgress)try{await this.createWorker(t)}catch(n){this.logger.error(`Failed to restart worker ${t.name}:`,n)}},this.options.restartDelay)}async terminateWorker(t,e=!1){let n=this.workers.get(t),i=this.workerInfo.get(t);if(!n||!i)throw new Error(`Worker ${t} not found`);if(i.status="stopping",this.emit("workerStopping",i),!e)n.postMessage({type:"shutdown"}),await new Promise((r)=>{let s=setTimeout(()=>{this.logger.warn(`Worker ${i.name} did not shutdown gracefully, terminating...`),n.terminate(),r()},this.options.gracefulShutdownTimeout);n.addEventListener("exit",()=>{clearTimeout(s),r()})});else n.terminate();this.workers.delete(t),i.status="stopped",i.endTime=new Date,this.workerInfo.delete(t),this.healthMonitor.stopMonitoring(t)}async shutdown(){if(this.shutdownInProgress)return;this.shutdownInProgress=!0,this.logger.info(`Shutting down ${this.workers.size} workers...`),this.emit("shutdown");let t=[];for(let[e]of this.workers)t.push(this.terminateWorker(e).catch((n)=>{this.logger.error(`Error terminating worker ${e}:`,n)}));await Promise.all(t),this.workers.clear(),this.workerInfo.clear(),this.logger.info("All workers terminated"),this.emit("shutdownComplete")}getWorkerInfo(t){return this.workerInfo.get(t)}getAllWorkerInfo(){return Array.from(this.workerInfo.values())}getWorkerCount(){return this.workers.size}getActiveWorkerCount(){return Array.from(this.workerInfo.values()).filter((t)=>t.status==="running").length}hasWorker(t){return this.workers.has(t)}isShuttingDown(){return this.shutdownInProgress}getWorkerHealth(t){return this.healthMonitor.getHealthMetrics(t)}getAllWorkerHealth(){return this.healthMonitor.getAllHealthMetrics()}getHealthSummary(){return this.healthMonitor.getHealthSummary()}};Vt=new wt});async function oo(t){try{let e=`${t}/hooks`;await Bun.$`mkdir -p ${e}`.quiet(),await Bun.write(`${e}/pre.sh`,vn.preHook),await Bun.$`chmod +x ${e}/pre.sh`.quiet(),await Bun.write(`${e}/post.sh`,vn.postHook),await Bun.$`chmod +x ${e}/post.sh`.quiet(),await Bun.write(`${t}/.runner-env`,vn.runnerEnv),io.debug(`Created runner hooks and environment for ${t}`)}catch(e){throw io.error("Failed to create runner files:",e),e}}var io,vn;var ro=v(()=>{O();io=$({prefix:"runner-templates"}),vn={postHook:`git reset --hard && git clean --force -df
|
|
48
|
+
`)},info:(r)=>{m.message(r,{symbol:p.default.blue(oo)})},success:(r)=>{m.message(r,{symbol:p.default.green(eo)})},step:(r)=>{m.message(r,{symbol:p.default.green(yn)})},warn:(r)=>{m.message(r,{symbol:p.default.yellow(so)})},warning:(r)=>{m.warn(r)},error:(r)=>{m.message(r,{symbol:p.default.red(ao)})}},$s=`${p.default.gray(_)} `});var gn=()=>{};var As;var ft=I(()=>{L();P();gn();As=k({prefix:"cli-core"}).child("error")});var Ss;var dt=I(()=>{Ss=new Uint32Array(65536)});var ct=I(()=>{dt()});async function mr(r,n={}){let{fallback:t,logLevel:o="warn",message:e="Operation failed gracefully"}=n;try{return await r()}catch(s){let i=s instanceof Error?s.message:String(s);if(mt[o](`${e}: ${i}`),t)try{await t()}catch(a){mt.error(`Fallback also failed: ${a instanceof Error?a.message:String(a)}`)}return}}var mt;var ut=I(()=>{P();mt=k({prefix:"cli-core"}).child("graceful")});function pt(r){let n=[];if(n.push(y.bold(`${r.name} - ${r.description}`)),n.push(""),n.push(y.bold("USAGE")),n.push(` ${r.usage}`),n.push(""),r.options&&r.options.length>0){n.push(y.bold("OPTIONS"));for(let t of r.options){let o=t.type?t.type==="boolean"?y.boolean("[boolean]"):t.type==="string"?y.string("[string]"):t.type==="number"?y.number("[number]"):`[${t.type}]`:"",e=t.default!==void 0?y.dim(`(default: ${t.default})`):"",s=t.required?y.error("(required)"):"",i=[t.description,o,e,s].filter(Boolean);n.push(` ${y.flag(t.flags.padEnd(26))} ${i.join(" ")}`)}n.push("")}if(r.examples&&r.examples.length>0){n.push(y.bold("EXAMPLES"));for(let t of r.examples)n.push(y.dim(` # ${t.description}`)),n.push(` ${y.value(t.command)}`),n.push("")}if(r.sections&&r.sections.length>0)for(let t of r.sections){if(n.push(y.bold(t.title)),typeof t.content==="string")n.push(t.content);else n.push(...t.content);n.push("")}if(r.notes&&r.notes.length>0){n.push(y.bold("NOTES"));for(let t of r.notes)n.push(` - ${t}`);n.push("")}if(n[n.length-1]==="")n.pop();return n.join(`
|
|
49
|
+
`)}function lt(r,n,t,o){let e=[];e.push(y.bold(r)),e.push(""),e.push(y.bold("USAGE")),e.push(` ${n}`),e.push(""),e.push(y.bold("COMMANDS"));let s=Math.max(...t.map((i)=>i.name.length));for(let i of t)e.push(` ${y.command(i.name.padEnd(s+2))} ${i.description}`);if(o)e.push(""),e.push(o);return e.join(`
|
|
50
|
+
`)}var yt=I(()=>{Xr()});var ht=I(()=>{P()});async function Cr(r,n={}){let t={...co,...n},o=new Error("Operation failed");for(let e=1;e<=t.maxAttempts;e++)try{return await r()}catch(s){if(o=s instanceof Error?s:new Error(String(s)),!t.retryableErrors.some((f)=>o.message.toLowerCase().includes(f.toLowerCase()))||e===t.maxAttempts)throw o;t.onRetry(e,o);let a=Math.min(t.initialDelay*t.backoffMultiplier**(e-1),t.maxDelay);await new Promise((f)=>setTimeout(f,a))}throw o}var co;var Rt=I(()=>{P();co={backoffMultiplier:2,initialDelay:1000,maxAttempts:3,maxDelay:30000,onRetry:(r,n)=>{Yr.warn(`Retry attempt ${r}: ${n.message}`)},retryableErrors:["ECONNREFUSED","ECONNRESET","ETIMEDOUT","ENOTFOUND","rate limit","429","503","502","504","npm ERR!","EPUBLISHCONFLICT"]}});import{homedir as mo}from"os";import{join as gt}from"path";var uo,Qs;var wt=I(()=>{uo=gt(mo(),".r5n","cache"),Qs=gt(uo,"update-check.json")});var Y=(r)=>{return r.map=(n)=>Y((t)=>n(r(t))),r.or=(n)=>Y((t)=>{try{return r(t)}catch(o){return n(t)}}),r},Wr=()=>"bad banditype"(),bt=(r)=>Y((n)=>r.includes(n)?n:Wr()),Gr=(r)=>Y((n)=>typeof n===typeof r?n:Wr()),br=()=>Gr(""),Et=()=>Gr(0),xt=()=>Gr(!0),$t=()=>Gr(),_t=(r)=>Y((n)=>n instanceof r?n:Wr()),wn=(r)=>_t(Object).map((n)=>{let t={};for(let o in n){let e=r(n[o]);e!==void 0&&(t[o]=e)}return t}),ur=(r)=>_t(Object).map((n)=>{let t={};for(let o in r){let e=r[o](n[o]);e!==void 0&&(t[o]=e)}return t});function po(r,n){return Y((t)=>{try{return r(t)}catch{try{return n(t)}catch{throw new Error("No matching schema in union")}}})}function ir(r,n){return(t)=>{if(t===void 0)return n;return r(t)}}function Ot(){return Y((r)=>{let n=Et()(r);if(!Number.isInteger(n)||n<=0)throw new Error("Must be a positive integer");return n})}function kt(){return Y((r)=>{let n=br()(r);try{return new URL(n),n}catch{throw new Error("Must be a valid URL")}})}function vt(r,n){return Y((t)=>{let o=br()(t);if(!r.test(o))throw new Error(n||`Must match pattern ${r}`);return o})}function Er(r){return{parse(n){try{return r(n)}catch(t){throw new Error(t instanceof Error?t.message:"Validation failed")}},safeParse(n){try{return{data:r(n),success:!0}}catch(t){return{error:t instanceof Error?t:new Error("Validation failed"),success:!1}}},validator:r}}function F(){return po($t(),br())}function or(r){return ir(br(),r)}function pr(r){return ir(xt(),r)}function Mr(r,n){return ir(bt(r),n)}var Tt=()=>{};var Nt=()=>{};var G=I(()=>{Xr();ft();gn();ct();ut();yt();ht();Rt();wt();Tt();Nt()});var Z={};hi(Z,{help:()=>Br});function Br(r){if(r&&Vt[r]){console.info(pt(Vt[r]));return}let n=[{description:"Initialize a new Hydra configuration file",name:"init"},{description:"Create and register new GitHub runner machines",name:"create"},{description:"Check runner health and diagnose issues",name:"health"},{description:"Remove GitHub runner machines",name:"remove"},{description:"Start existing GitHub runner machines",name:"run"},{description:"Check the status of GitHub runner machines",name:"status"},{description:"Generate runner configuration templates",name:"template"},{description:"Validate configuration file",name:"validate"},{description:"Watch and auto-restart runners on failure",name:"watch"},{description:"Migrate configuration to latest format",name:"migrate"},{description:"Run performance benchmarks to test CLI performance",name:"benchmark"},{description:"Show this help message",name:"help"}];console.info(lt(`Hydra@${kr} - GitHub self-hosted runner manager`,"hydra <command> [options]",n,"Use hydra <command> --help for more information about a command."))}var Vt;var j=I(()=>{G();Zr();Vt={benchmark:{description:"Run performance benchmarks to test CLI performance",examples:[{command:"hydra benchmark",description:"Run full benchmark suite"},{command:"hydra benchmark --quick",description:"Run quick benchmark (1 iteration)"},{command:"hydra benchmark --startup-only",description:"Test only CLI startup time"},{command:"hydra benchmark --memory-only",description:"Test only memory usage"},{command:"hydra benchmark --worker-only",description:"Test only worker spawn performance"},{command:"hydra benchmark --iterations=10",description:"Run with 10 iterations"}],name:"hydra benchmark",notes:["Tests startup time, worker spawn time, memory usage, and command execution","Targets: startup <100ms, worker spawn <50ms, memory <100MB","Exit code 0 if score \u226570%, 1 if performance is below threshold"],options:[{description:"Number of benchmark iterations",flags:"--iterations",type:"number"},{description:"Number of workers to test",flags:"--workers",type:"number"},{description:"Test only CLI startup time",flags:"--startup-only",type:"boolean"},{description:"Test only memory usage",flags:"--memory-only",type:"boolean"},{description:"Test only worker spawn performance",flags:"--worker-only",type:"boolean"},{description:"Run quick benchmark (1 iteration)",flags:"--quick",type:"boolean"}],usage:"hydra benchmark [options]"},create:{description:"Create and register new GitHub runner machines",examples:[{command:"hydra create -t TOKEN -u https://github.com/org/repo",description:"Create a single runner"},{command:"hydra create -t TOKEN -u URL -m 3",description:"Create 3 runners"},{command:"hydra create -t TOKEN -u URL -l docker,gpu",description:"Create runner with labels"},{command:"hydra create -p production",description:"Create using production profile"}],name:"hydra create",notes:["Requires a GitHub personal access token with repo scope","Creates runners in ./gh-runners by default","Use --run to immediately start runners after creation"],options:[{description:"GitHub personal access token",flags:"-t, --token",type:"string"},{description:"Repository or organization URL",flags:"-u, --url",type:"string"},{description:"Runner name prefix",flags:"-n, --name",type:"string"},{description:"Number of machines to create",flags:"-m, --numberOfMachines",type:"number"},{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Runner labels (comma-separated)",flags:"-l, --labels",type:"string"},{description:"Runner group",flags:"-g, --runnerGroup",type:"string"},{description:"Operating system",flags:"-s, --os",type:"string"},{description:"Overwrite existing runners",flags:"-f, --overwrite",type:"boolean"},{description:"Start runners after creation",flags:"-r, --run",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra create [options]"},health:{description:"Check runner health and diagnose issues",examples:[{command:"hydra health",description:"Check health of all runners"},{command:"hydra health --fix",description:"Auto-fix common issues"},{command:"hydra health -p production",description:"Check health using profile"}],name:"hydra health",notes:["Checks runner registration, connectivity, and configuration","Use --fix to automatically resolve common issues","Exit code 0 if healthy, 1 if issues found"],options:[{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Auto-fix common issues",flags:"--fix",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra health [options]"},init:{description:"Initialize a new Hydra configuration file",examples:[{command:"hydra init",description:"Create hydra.json interactively"},{command:"hydra init --toml",description:"Create hydra.toml instead"}],name:"hydra init",options:[{description:"Use TOML format instead of JSON",flags:"--toml",type:"boolean"}],usage:"hydra init [options]"},migrate:{description:"Migrate configuration to latest format",examples:[{command:"hydra migrate",description:"Migrate configuration"},{command:"hydra migrate --dry-run",description:"Preview changes without applying"}],name:"hydra migrate",options:[{description:"Preview changes without applying",flags:"--dry-run",type:"boolean"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra migrate [options]"},remove:{description:"Remove GitHub runner machines",examples:[{command:"hydra remove -t TOKEN -u https://github.com/org/repo",description:"Remove all runners"},{command:"hydra remove -t TOKEN -u URL -m 2",description:"Remove 2 runners"},{command:"hydra remove -t TOKEN -u URL --force",description:"Force remove without confirmation"},{command:"hydra remove -p production",description:"Remove using production profile"}],name:"hydra remove",notes:["Requires a GitHub personal access token with repo scope","Removes runners from GitHub and deletes local files","Use --force to skip confirmation prompt"],options:[{description:"GitHub personal access token",flags:"-t, --token",type:"string"},{description:"Repository or organization URL",flags:"-u, --url",type:"string"},{description:"Number of machines to remove",flags:"-m, --numberOfMachines",type:"number"},{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Force removal without confirmation",flags:"-f, --force",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra remove [options]"},run:{description:"Start existing GitHub runner machines",examples:[{command:"hydra run -t TOKEN -u https://github.com/org/repo",description:"Start all runners"},{command:"hydra run -t TOKEN -u URL -m 2",description:"Start 2 runners"},{command:"hydra run -p production",description:"Start using production profile"}],name:"hydra run",notes:["Requires a GitHub personal access token with repo scope","Runners must be created first using 'hydra create'","Runs in foreground, use Ctrl+C to stop"],options:[{description:"GitHub personal access token",flags:"-t, --token",type:"string"},{description:"Repository or organization URL",flags:"-u, --url",type:"string"},{description:"Runner name prefix",flags:"-n, --name",type:"string"},{description:"Number of machines to run",flags:"-m, --numberOfMachines",type:"number"},{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Runner labels (comma-separated)",flags:"-l, --labels",type:"string"},{description:"Runner group",flags:"-g, --runnerGroup",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra run [options]"},status:{description:"Check the status of GitHub runner machines",examples:[{command:"hydra status",description:"Show status of all runners"},{command:"hydra status --json",description:"Output status as JSON"},{command:"hydra status -p production",description:"Check status using profile"}],name:"hydra status",notes:["Shows runner registration status and current state","Use --json for machine-readable output"],options:[{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Output as JSON",flags:"--json",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra status [options]"},template:{description:"Generate runner configuration templates",examples:[{command:"hydra template",description:"Generate default template"},{command:"hydra template --type docker",description:"Generate Docker runner template"}],name:"hydra template",options:[{description:"Template type",flags:"--type",type:"string"},{description:"Output file path",flags:"-o, --output",type:"string"}],usage:"hydra template [options]"},validate:{description:"Validate configuration file",examples:[{command:"hydra validate",description:"Validate hydra.json"},{command:"hydra validate -c custom.toml",description:"Validate custom config file"}],name:"hydra validate",options:[{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra validate [options]"},watch:{description:"Watch and auto-restart runners on failure",examples:[{command:"hydra watch",description:"Watch all runners"},{command:"hydra watch -p production",description:"Watch using profile"}],name:"hydra watch",notes:["Monitors runners and restarts them if they fail","Runs in foreground, use Ctrl+C to stop"],options:[{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra watch [options]"}}});Zr();class Rr extends Error{code;severity;context;originalError;timestamp;recoveryStrategy;constructor(r,n,t="medium",o={},e){super(r);if(this.name="HydraError",this.code=n,this.severity=t,this.context=o,this.originalError=e,this.timestamp=new Date,this.recoveryStrategy=w.getRecoveryStrategy(n),e?.stack)this.stack=`${this.stack}
|
|
51
|
+
Caused by: ${e.stack}`}toJSON(){return{code:this.code,context:this.context,message:this.message,name:this.name,originalError:this.originalError?.message,recoveryStrategy:this.recoveryStrategy,severity:this.severity,timestamp:this.timestamp.toISOString()}}}class w{static instance=null;errorHistory=[];maxHistorySize=100;constructor(){}static getInstance(){if(!w.instance)w.instance=new w;return w.instance}static getRecoveryStrategy(r){switch(r){case"NETWORK_ERROR":return{canRecover:!0,maxRetries:3,recoveryAction:"retry_with_backoff",retryable:!0,retryDelay:2000,userAction:"Check your network connection and try again"};case"CONFIG_ERROR":return{canRecover:!0,retryable:!1,userAction:"Fix the configuration file and try again. Use 'hydra validate' to check your config"};case"VALIDATION_ERROR":return{canRecover:!0,retryable:!1,userAction:"Correct the validation errors and try again"};case"FILE_SYSTEM_ERROR":return{canRecover:!0,retryable:!1,userAction:"Check file permissions and disk space, then try again"};case"AUTHENTICATION_ERROR":return{canRecover:!0,retryable:!1,userAction:"Check your GitHub token and repository permissions"};case"WORKER_ERROR":return{canRecover:!0,maxRetries:2,recoveryAction:"restart_worker",retryable:!0,retryDelay:1000,userAction:"Worker will be restarted automatically"};case"GITHUB_API_ERROR":return{canRecover:!0,maxRetries:3,recoveryAction:"retry_with_exponential_backoff",retryable:!0,retryDelay:5000,userAction:"GitHub API rate limit may be exceeded. Please wait and try again"};case"TEMPLATE_ERROR":return{canRecover:!0,retryable:!1,userAction:"Check template syntax and dependencies, then try again"};case"MIGRATION_ERROR":return{canRecover:!1,retryable:!1,userAction:"Manual intervention required. Check migration logs and contact support"};case"RUNNER_ERROR":return{canRecover:!0,maxRetries:2,recoveryAction:"recreate_runner",retryable:!0,retryDelay:3000,userAction:"Runner will be recreated automatically"};case"PERMISSION_ERROR":return{canRecover:!0,retryable:!1,userAction:"Check file/directory permissions and run with appropriate privileges"};case"DEPENDENCY_ERROR":return{canRecover:!0,retryable:!1,userAction:"Install missing dependencies and try again"};case"COMMAND_ERROR":return{canRecover:!0,retryable:!1,userAction:"Check command syntax and arguments, then try again"};default:return{canRecover:!1,retryable:!1,userAction:"An unexpected error occurred. Please report this issue"}}}static createError(r,n,t="medium",o={},e){return new Rr(r,n,t,o,e)}static handleError(r,n={}){let t=w.getInstance();if(r instanceof Rr)return t.recordError(r),r;let o;if(r instanceof Error){let e=w.classifyError(r),s=w.getSeverityFromCode(e);o=new Rr(r.message,e,s,n,r)}else o=new Rr(String(r),"UNKNOWN_ERROR","medium",n);return t.recordError(o),o}static classifyError(r){let n=r.message.toLowerCase(),t=r.stack?.toLowerCase()||"";if(n.includes("network")||n.includes("connection")||n.includes("timeout"))return"NETWORK_ERROR";if(n.includes("config")||n.includes("configuration"))return"CONFIG_ERROR";if(n.includes("validation")||n.includes("invalid")||n.includes("schema"))return"VALIDATION_ERROR";if(n.includes("enoent")||n.includes("permission")||n.includes("access denied"))return"FILE_SYSTEM_ERROR";if(n.includes("auth")||n.includes("token")||n.includes("unauthorized"))return"AUTHENTICATION_ERROR";if(n.includes("worker")||t.includes("worker"))return"WORKER_ERROR";if(n.includes("github")||n.includes("api")||n.includes("rate limit"))return"GITHUB_API_ERROR";if(n.includes("template"))return"TEMPLATE_ERROR";if(n.includes("migration")||n.includes("migrate"))return"MIGRATION_ERROR";if(n.includes("runner"))return"RUNNER_ERROR";if(n.includes("permission")||n.includes("eperm"))return"PERMISSION_ERROR";if(n.includes("dependency")||n.includes("missing")||n.includes("not found"))return"DEPENDENCY_ERROR";if(n.includes("command")||n.includes("unknown"))return"COMMAND_ERROR";return"UNKNOWN_ERROR"}static getSeverityFromCode(r){switch(r){case"MIGRATION_ERROR":case"PERMISSION_ERROR":return"critical";case"AUTHENTICATION_ERROR":case"CONFIG_ERROR":case"DEPENDENCY_ERROR":return"high";case"NETWORK_ERROR":case"GITHUB_API_ERROR":case"WORKER_ERROR":case"RUNNER_ERROR":return"medium";default:return"low"}}static formatError(r){let{code:n,message:t,severity:o,context:e,recoveryStrategy:s}=r,i=`\u274C ${t}`;if(e.command)i+=`
|
|
52
|
+
Command: ${e.command}`;if(e.operation)i+=`
|
|
53
|
+
Operation: ${e.operation}`;if(e.profile)i+=`
|
|
54
|
+
Profile: ${e.profile}`;if(e.directory)i+=`
|
|
55
|
+
Directory: ${e.directory}`;if(e.machineIndex!==void 0)i+=`
|
|
56
|
+
Machine: ${e.machineIndex}`;if(i+=`
|
|
57
|
+
Code: ${n}`,i+=`
|
|
58
|
+
Severity: ${o.toUpperCase()}`,s.userAction)i+=`
|
|
59
|
+
|
|
60
|
+
\uD83D\uDCA1 ${s.userAction}`;return i}static formatDebugError(r){return JSON.stringify(r.toJSON(),null,2)}recordError(r){if(this.errorHistory.unshift(r),this.errorHistory.length>this.maxHistorySize)this.errorHistory=this.errorHistory.slice(0,this.maxHistorySize)}getErrorHistory(){return[...this.errorHistory]}getErrorStats(){return this.errorHistory.reduce((r,n)=>{return r[n.code]=(r[n.code]||0)+1,r},{})}clearHistory(){this.errorHistory=[]}}import{dirname as go,join as wo}from"path";import{fileURLToPath as bo}from"url";import{parseArgs as Eo}from"util";import{performance as lr}from"perf_hooks";P();G();function Ur(){let r=import.meta.path,n=r.substring(0,r.lastIndexOf("/"));return n.substring(0,n.lastIndexOf("/"))}var lo=ur({directory:or(`${process.cwd()}/gh-runners`),labels:F(),name:or("runner"),numberOfMachines:ir(vt(/^\d+$/,"Number of machines must be a positive integer"),"1"),os:Mr(["osx","linux","windows"],"osx"),overwrite:pr(!1),run:pr(!1),token:or(process.env.GITHUB_PERSONAL_ACCESS_TOKEN??""),url:kt()}),wa=Er(lo);function U(r){return r.replace(/[^a-zA-Z0-9\-_./\s]/g,"")}function It(r,n){let t=r;for(let o of n)if(o&&o.length>0){let e=o.length>8?`${o.slice(0,2)}${"*".repeat(o.length-4)}${o.slice(-2)}`:"*".repeat(o.length),s=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");t=t.replace(new RegExp(s,"g"),e)}return t=t.replace(/ghp_[a-zA-Z0-9]{36}/g,"ghp_************************************"),t=t.replace(/github_pat_[a-zA-Z0-9_]{82}/g,"github_pat_**********************************"),t=t.replace(/\b[A-Z]{20,}\b/g,(o)=>{return`${o.slice(0,2)}${"*".repeat(o.length-4)}${o.slice(-2)}`}),t}function x({prefix:r,secrets:n=[]}){let t=k({prefix:r}),o=[...n];if(process.env.GITHUB_TOKEN)o.push(process.env.GITHUB_TOKEN);if(process.env.RUNNER_TOKEN)o.push(process.env.RUNNER_TOKEN);if(process.env.RUNNER_CFG_PAT)o.push(process.env.RUNNER_CFG_PAT);let e=(s)=>{if(typeof s==="string")return It(s,o);if(typeof s==="object"&&s!==null){let i=Array.isArray(s)?[]:{};for(let a in s)i[a]=e(s[a]);return i}return s};return{...t,addSecret:(s)=>{if(s&&!o.includes(s))o.push(s)},child:(s)=>x({prefix:`${r}:${s}`,secrets:o}),debug:(...s)=>t.debug(...s.map(e)),error:(...s)=>t.error(...s.map(e)),info:(...s)=>t.info(...s.map(e)),warn:(...s)=>t.warn(...s.map(e))}}class Pr{metrics={};startTimes=new Map;logger=x({prefix:"Performance"});thresholds;defaultThresholds={commandExecutionTime:5000,memoryUsage:104857600,startupTime:100,workerSpawnTime:50};constructor(r={}){this.thresholds={...this.defaultThresholds,...r}}startTimer(r){this.startTimes.set(r,lr.now())}endTimer(r){let n=this.startTimes.get(r);if(!n)throw new Error(`Timer ${r} was not started`);let t=lr.now()-n;return this.startTimes.delete(r),t}measureStartupTime(){let r=lr.now()-process.uptime()*1000;return this.metrics.startupTime=r,this.logger.debug(`Startup time: ${r.toFixed(2)}ms`),r}measureWorkerSpawn(r){return new Promise((n)=>{let t=lr.now();setTimeout(()=>{let e=lr.now()-t;if(!this.metrics.workerSpawnTimes)this.metrics.workerSpawnTimes=[];this.metrics.workerSpawnTimes.push(e),this.logger.debug(`Worker ${r} spawn time: ${e.toFixed(2)}ms`),n(e)},0)})}measureMemoryUsage(){let r=process.memoryUsage();this.metrics.memoryUsage=r;let n=(r.heapUsed/1024/1024).toFixed(2),t=(r.rss/1024/1024).toFixed(2);return this.logger.debug(`Memory usage - Heap: ${n}MB, RSS: ${t}MB`),r}async measureCommandExecution(r,n){this.startTimer(`command_${r}`);try{let t=await n(),o=this.endTimer(`command_${r}`);return this.metrics.commandExecutionTime=o,this.logger.debug(`Command ${r} execution time: ${o.toFixed(2)}ms`),{executionTime:o,result:t}}catch(t){throw this.endTimer(`command_${r}`),t}}getMetrics(){return{commandExecutionTime:this.metrics.commandExecutionTime||0,memoryUsage:this.metrics.memoryUsage||process.memoryUsage(),startupTime:this.metrics.startupTime||0,timestamp:Date.now(),workerSpawnTimes:this.metrics.workerSpawnTimes||[]}}generateReport(){let r=this.getMetrics(),n=[];if(n.push({name:"Startup Time",passed:r.startupTime<=this.thresholds.startupTime,threshold:this.thresholds.startupTime,unit:"ms",value:r.startupTime}),r.workerSpawnTimes.length>0){let s=r.workerSpawnTimes.reduce((a,f)=>a+f,0)/r.workerSpawnTimes.length,i=Math.max(...r.workerSpawnTimes);n.push({name:"Average Worker Spawn Time",passed:s<=this.thresholds.workerSpawnTime,threshold:this.thresholds.workerSpawnTime,unit:"ms",value:s}),n.push({name:"Max Worker Spawn Time",passed:i<=this.thresholds.workerSpawnTime*2,threshold:this.thresholds.workerSpawnTime*2,unit:"ms",value:i})}if(n.push({name:"Memory Usage (Heap Used)",passed:r.memoryUsage.heapUsed<=this.thresholds.memoryUsage,threshold:this.thresholds.memoryUsage,unit:"bytes",value:r.memoryUsage.heapUsed}),n.push({name:"Memory Usage (RSS)",passed:r.memoryUsage.rss<=this.thresholds.memoryUsage*1.5,threshold:this.thresholds.memoryUsage*1.5,unit:"bytes",value:r.memoryUsage.rss}),r.commandExecutionTime>0)n.push({name:"Command Execution Time",passed:r.commandExecutionTime<=this.thresholds.commandExecutionTime,threshold:this.thresholds.commandExecutionTime,unit:"ms",value:r.commandExecutionTime});let t=n.filter((s)=>s.passed).length,o=n.length,e=Math.round(t/o*100);return{duration:lr.now(),results:n,summary:{failed:o-t,passed:t,score:e,total:o},timestamp:r.timestamp}}logReport(r){this.logger.info("=== Performance Report ==="),this.logger.info(`Timestamp: ${new Date(r.timestamp).toISOString()}`),this.logger.info(`Duration: ${r.duration.toFixed(2)}ms`),this.logger.info(`Score: ${r.summary.score}% (${r.summary.passed}/${r.summary.total} passed)`),this.logger.info(`
|
|
61
|
+
Results:`);for(let n of r.results){let t=n.passed?"\u2705 PASS":"\u274C FAIL",o=n.unit==="bytes"?`${(n.value/1024/1024).toFixed(2)}MB`:`${n.value.toFixed(2)}${n.unit}`,e=n.unit==="bytes"?`${(n.threshold/1024/1024).toFixed(2)}MB`:`${n.threshold.toFixed(2)}${n.unit}`;this.logger.info(` ${t} ${n.name}: ${o} (threshold: ${e})`)}}reset(){this.metrics={},this.startTimes.clear()}}function bn(r){if(r===0)return"0 B";let n=["B","KB","MB","GB"],t=Math.floor(Math.log(r)/Math.log(1024));return`${(r/1024**t).toFixed(2)} ${n[t]}`}function Lr(r){if(r<1000)return`${r.toFixed(2)}ms`;let n=r/1000;if(n<60)return`${n.toFixed(2)}s`;return`${(n/60).toFixed(2)}m`}var ka=new Pr;import{EventEmitter as Ro}from"events";import{performance as St}from"perf_hooks";G();var yo=ur({directory:or("./gh-runners"),labels:F(),name:or("runner"),numberOfMachines:ir(Ot(),1),os:Mr(["osx","linux","windows"],"osx"),overwrite:pr(!1),run:pr(!1),runnerGroup:F(),token:F(),url:F()}),ho=Er(yo),At=Er(ur({defaultProfile:F(),profiles:wn(ho.validator)})),xr;((c)=>{c.INIT="init";c.START="start";c.STOP="stop";c.SHUTDOWN="shutdown";c.SUCCESS="success";c.ERROR="error";c.PROGRESS="progress";c.STATUS="status";c.HEARTBEAT="heartbeat";c.LOG="log"})(xr||={});function qr(r){if(!r||typeof r!=="object"||r===null)return!1;let n=r;return typeof n.type==="string"&&Object.values(xr).includes(n.type)}function Ht(r){if(!r||typeof r!=="object"||r===null)return!1;let n=r;return typeof n.machineCwd==="string"&&typeof n.token==="string"&&typeof n.url==="string"&&typeof n.index==="number"&&(n.name===void 0||typeof n.name==="string")&&(n.labels===void 0||typeof n.labels==="string")&&(n.runnerGroup===void 0||typeof n.runnerGroup==="string")}class er extends Ro{options;workers=new Map;workerInfo=new Map;shutdownInProgress=!1;logger=x({prefix:"WorkerManager"});cleanupRegistered=!1;constructor(r={}){super();this.options=r;this.options={gracefulShutdownTimeout:30000,maxRestarts:3,restartDelay:1000,restartOnError:!0,...r},this.registerCleanup()}registerCleanup(){if(this.cleanupRegistered)return;this.cleanupRegistered=!0;let r=async()=>{if(!this.shutdownInProgress)await this.shutdown()};process.on("exit",()=>{if(!this.shutdownInProgress&&this.workers.size>0)this.logger.warn("Forced exit with active workers")}),process.on("SIGINT",async()=>{this.logger.info("Received SIGINT, initiating graceful shutdown..."),await r(),process.exit(0)}),process.on("SIGTERM",async()=>{this.logger.info("Received SIGTERM, initiating graceful shutdown..."),await r(),process.exit(0)}),process.on("uncaughtException",async(n)=>{this.logger.error("Uncaught exception:",n),await r(),process.exit(1)})}async createWorker(r){if(this.shutdownInProgress)throw new Error("Cannot create worker during shutdown");if(this.workers.size>=(this.options.maxWorkers||100))throw new Error(`Maximum worker limit reached: ${this.options.maxWorkers}`);if(this.workers.has(r.id))throw new Error(`Worker with id ${r.id} already exists`);let n=St.now(),t={id:r.id,name:r.name,restartCount:0,startTime:new Date,status:"starting"};this.workerInfo.set(r.id,t);try{let o=new Worker(r.scriptPath,{name:r.name,ref:!0});this.workers.set(r.id,o);let e=St.now()-n;if(t.spawnTime=e,this.setupWorkerHandlers(o,r,t),r.data){let s={data:r.data,timestamp:Date.now(),type:"init"};o.postMessage(s)}t.status="running",this.emit("workerStarted",t),this.emit("workerSpawned",{spawnTime:e,workerId:r.id}),this.logger.info(`Worker ${r.name} (${r.id}) started in ${e.toFixed(2)}ms`)}catch(o){throw t.status="error",t.error=o,t.endTime=new Date,this.emit("workerError",t,o),o}}setupWorkerHandlers(r,n,t){r.addEventListener("message",({data:o})=>{if(qr(o))this.emit("workerMessage",t,o),n.onMessage?.(o);else this.logger.warn(`Received invalid message from worker ${n.name}:`,o)}),r.addEventListener("error",(o)=>{if(this.logger.error(`Worker ${n.name} error:`,o),t.status="error",t.error=o.error||o,this.emit("workerError",t,o),n.onError?.(o.error||o),this.options.restartOnError&&t.restartCount<(this.options.maxRestarts||3))this.scheduleRestart(n,t)}),r.addEventListener("messageerror",(o)=>{this.logger.error(`Worker ${n.name} message error:`,o),t.status="error",t.error=new Error("Worker message error"),this.emit("workerError",t,o),n.onError?.(new Error("Worker message error"))})}scheduleRestart(r,n){let t=this.options.restartDelay||1000;n.restartCount++,this.logger.info(`Scheduling restart for worker ${r.name} (attempt ${n.restartCount}/${this.options.maxRestarts}) in ${t}ms`),setTimeout(async()=>{if(!this.shutdownInProgress)try{await this.createWorker(r)}catch(o){this.logger.error(`Failed to restart worker ${r.name}:`,o)}},t)}async stopWorker(r,n=!1){let t=this.workers.get(r),o=this.workerInfo.get(r);if(!t||!o)throw new Error(`Worker ${r} not found`);if(o.status="stopping",this.emit("workerStopping",o),n)t.terminate(),this.workers.delete(r),o.status="stopped",o.endTime=new Date,this.emit("workerStopped",o);else{let e={data:{graceful:!0},timestamp:Date.now(),type:"shutdown"};t.postMessage(e),await new Promise((s)=>{let i=setTimeout(()=>{this.logger.warn(`Worker ${o.name} did not stop gracefully, terminating...`),t.terminate(),s()},this.options.gracefulShutdownTimeout||30000);t.addEventListener("exit",()=>{clearTimeout(i),s()})})}}async shutdown(){if(this.shutdownInProgress)return;this.shutdownInProgress=!0,this.logger.info(`Shutting down ${this.workers.size} workers...`);let r=Array.from(this.workers.keys()).map((n)=>this.stopWorker(n).catch((t)=>{this.logger.error(`Error stopping worker ${n}:`,t)}));await Promise.all(r),this.workers.clear(),this.workerInfo.clear(),this.logger.info("All workers shut down")}getWorkerInfo(r){return this.workerInfo.get(r)}getAllWorkerInfo(){return Array.from(this.workerInfo.values())}getWorkerCount(){return this.workers.size}isShuttingDown(){return this.shutdownInProgress}}var xo=bo(import.meta.url),$o=go(xo),C=x({prefix:"Benchmark"});async function Ct(){let{values:r}=Eo({allowPositionals:!0,args:process.argv.slice(2),options:{help:{short:"h",type:"boolean"},iterations:{default:"3",type:"string"},"memory-only":{type:"boolean"},quick:{type:"boolean"},"startup-only":{type:"boolean"},"worker-only":{type:"boolean"},workers:{default:"3",type:"string"}}});if(r.help){console.log(`
|
|
62
|
+
Usage: hydra benchmark [options]
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
--iterations=N Number of benchmark iterations (default: 3)
|
|
66
|
+
--workers=N Number of workers to test (default: 3)
|
|
67
|
+
--startup-only Test only CLI startup time
|
|
68
|
+
--memory-only Test only memory usage
|
|
69
|
+
--worker-only Test only worker spawn performance
|
|
70
|
+
--quick Run a quick benchmark (1 iteration)
|
|
71
|
+
--help, -h Show this help message
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
hydra benchmark
|
|
75
|
+
hydra benchmark --iterations=5 --workers=10
|
|
76
|
+
hydra benchmark --quick
|
|
77
|
+
hydra benchmark --startup-only
|
|
78
|
+
`);return}let n=r.quick?1:Number.parseInt(r.iterations),t=Number.parseInt(r.workers),o=new Pr({commandExecutionTime:1000,memoryUsage:104857600,startupTime:100,workerSpawnTime:50});C.info("Starting Hydra CLI Performance Benchmark...");try{if(r["startup-only"])await Wt(o,n);else if(r["memory-only"])await Gt(o);else if(r["worker-only"])await Mt(o,t);else await _o(o,n,t);let e=o.generateReport();if(o.logReport(e),e.summary.score<70)C.warn("Performance score is below acceptable threshold (70%)"),process.exit(1);else if(e.summary.score>=95)C.info("Excellent performance! \uD83D\uDE80");else if(e.summary.score>=85)C.info("Good performance! \uD83D\uDC4D")}catch(e){C.error("Benchmark failed:",e),process.exit(1)}}async function Wt(r,n){C.info(`Running startup benchmark (${n} iterations)...`);let t=0;for(let e=0;e<n;e++)if(r.startTimer("startup"),await new Promise((s)=>{setTimeout(()=>{let i=r.endTimer("startup");t+=i,s(i)},10)}),e<n-1)await new Promise((s)=>setTimeout(s,50));let o=t/n;r.getMetrics().startupTime=o,C.info(`Average startup time: ${Lr(o)}`)}async function Gt(r){C.info("Running memory usage benchmark..."),global.gc?.(),await new Promise((t)=>setTimeout(t,100));let n=r.measureMemoryUsage();C.info(`Heap used: ${bn(n.heapUsed)}`),C.info(`RSS memory: ${bn(n.rss)}`)}async function Mt(r,n){C.info(`Running worker spawn benchmark (${n} workers)...`);let t=new er,o=[];t.on("workerSpawned",({spawnTime:e})=>{o.push(e)});try{let e=[];for(let a=0;a<n;a++){let f=t.createWorker({data:{index:a,machineCwd:process.cwd(),token:"benchmark-token",url:"https://github.com/test/repo"},id:`benchmark-worker-${a}`,name:`BenchmarkWorker${a}`,scriptPath:wo($o,"../runner-worker.ts")});e.push(f),await new Promise((d)=>setTimeout(d,10))}await Promise.all(e),r.getMetrics().workerSpawnTimes=o;let s=o.reduce((a,f)=>a+f,0)/o.length,i=Math.max(...o);C.info(`Average worker spawn time: ${Lr(s)}`),C.info(`Max worker spawn time: ${Lr(i)}`)}finally{await t.shutdown()}}async function _o(r,n,t){C.info(`Running full benchmark suite (${n} iterations, ${t} workers)...`),await Wt(r,Math.min(n,3)),await new Promise((o)=>setTimeout(o,100)),await Gt(r),await new Promise((o)=>setTimeout(o,100)),await Mt(r,Math.min(t,3)),C.info("Full benchmark suite completed")}L();import{homedir as Ho}from"os";import{join as So}from"path";import{parseArgs as Co}from"util";var{$:Zt}=globalThis.Bun;import{join as Oo}from"path";var{$:K}=globalThis.Bun;class Ut{async exists(r){try{return(await K`test -e ${r}`.quiet().nothrow()).exitCode===0}catch{return!1}}async readFile(r){let n=Bun.file(r);if(!await n.exists())throw new Error(`File not found: ${r}`);return n.text()}async writeFile(r,n){await Bun.write(r,n)}async deleteFile(r){let n=U(r);await K`rm -f ${n}`.quiet()}async createDirectory(r,n){let t=U(r);if(n?.recursive)await K`mkdir -p ${t}`.quiet();else await K`mkdir ${t}`.quiet()}async deleteDirectory(r,n){let t=U(r);if(n?.recursive)await K`rm -rf ${t}`.quiet();else await K`rmdir ${t}`.quiet()}async listDirectory(r){let n=U(r),o=(await K`ls -la ${n}`.quiet()).stdout.toString().trim().split(`
|
|
79
|
+
`),e=[];for(let s of o.slice(1)){let i=s.split(/\s+/);if(i.length<9)continue;let a=i[0],f=Number.parseInt(i[4]||"0",10),d=i.slice(8).join(" ");if(d==="."||d==="..")continue;e.push({isDirectory:a?.startsWith("d")||!1,modifiedTime:new Date,name:d,size:f})}return e}async copyFile(r,n){let t=U(r),o=U(n);await K`cp ${t} ${o}`.quiet()}async moveFile(r,n){let t=U(r),o=U(n);await K`mv ${t} ${o}`.quiet()}async getFileInfo(r){if(!await Bun.file(r).exists())return null;let t=U(r),e=(await K`stat -f "%z %m %Y" ${t} 2>/dev/null || stat -c "%s %Y %F" ${t}`.quiet()).stdout.toString().trim().split(" "),s=e[0]||"0",i=e[1]||"0";return{isDirectory:!1,modifiedTime:new Date(Number.parseInt(i,10)*1000),name:r.split("/").pop()||r,size:Number.parseInt(s,10)}}async chmod(r,n){let t=U(r);await K`chmod ${n} ${t}`.quiet()}async readDir(r){return(await this.listDirectory(r)).map((t)=>({isDirectory:t.isDirectory,isFile:!t.isDirectory,name:t.name}))}async ensureDir(r){if(!await this.exists(r))await this.createDirectory(r,{recursive:!0})}}var b=new Ut;async function En(r){if(!await b.exists(r))await b.createDirectory(r,{recursive:!0})}var ko=["hydra.json",".hydra.json","hydra.toml",".hydra.toml"];async function xn(r=process.cwd()){for(let n of ko){let t=Oo(r,n);if(await b.exists(t))return t}return null}async function q(r){let n=r?.configPath||await xn();if(!n)return null;if(!await b.exists(n))return null;try{let t=await b.readFile(n),o=n.endsWith(".toml")?vo(t):JSON.parse(t);return At.parse(o)}catch(t){if(t instanceof Error)throw new Error(`Invalid config file: ${t.message}`);throw t}}async function B(r,n){if(!r)return null;let t=n||r.defaultProfile;if(!t)return null;return r.profiles[t]||null}function Pt(r,n){if(!r)return n;let t={...n};for(let[o,e]of Object.entries(r)){let s=o;if(t[s]===void 0&&e!==void 0)t[s]=e}return t}function vo(r){try{return Bun.TOML.parse(r)}catch(n){throw new Error(`Failed to parse TOML configuration: ${n}`)}}G();var Lt=k({prefix:"runner-templates"}),$n={postHook:`git reset --hard && git clean --force -df
|
|
66
80
|
`,preHook:`export BUN_INSTALL_CACHE_DIR=./.bun/cache
|
|
67
81
|
`,runnerEnv:`ACTIONS_RUNNER_HOOK_JOB_STARTED=./hooks/pre.sh
|
|
68
82
|
ACTIONS_RUNNER_HOOK_JOB_COMPLETED=./hooks/post.sh
|
|
69
|
-
`}});var
|
|
70
|
-
${b}`});if(k(m)||!m)throw new Error("Token is required to create runners");t.info("Opening GitHub runner settings..."),await Zt`open ${b}`.quiet();let x=await A({message:"Enter the runner registration token:",placeholder:"AXXXXXXXXXXXXXXXXXXXXXXXXX",validate:(M)=>{if(!M||M.trim().length===0)return"Token is required";return}});if(k(x))throw new Error("Token is required to create runners");p=x.trim()}if(t=w({prefix:"createMachines",secrets:[p]}),t.info(`Creating ${r} runners in ${i}`),t.debug(`OS: ${s}, Name: ${a}, Labels: ${f||"none"}`),await y.exists(i))if(n)t.warn(`Directory ${i} exists, removing...`),await y.deleteDirectory(i,{recursive:!0});else throw new Error(`Directory ${i} already exists`);let g=await ya({directory:i,os:s});if(await ba({directory:i,numberOfMachines:r,overwrite:n,runnerBase:g}),!o){t.info("Runners created but not started");return}await wa({directory:i,labels:f,name:a,numberOfMachines:r,runnerGroup:u,token:p,url:d})}function ga(t){try{let e=new URL(t),n=e.pathname.split("/").filter(Boolean);if(e.hostname==="github.com"||e.hostname==="www.github.com"){if(n[0]==="orgs"&&n[1])return`https://github.com/organizations/${n[1]}/settings/actions/runners/new`;if(n.length>=2)return`https://github.com/${n[0]}/${n[1]}/settings/actions/runners/new`}else{if(n[0]==="orgs"&&n[1])return`${e.origin}/organizations/${n[1]}/settings/actions/runners/new`;if(n.length>=2)return`${e.origin}/${n[0]}/${n[1]}/settings/actions/runners/new`}return t}catch{return t}}async function ma(){let{values:t}=da({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},labels:{short:"l",type:"string"},name:{default:"runner",short:"n",type:"string"},numberOfMachines:{default:"1",short:"m",type:"string"},os:{default:"osx",short:"s",type:"string"},overwrite:{default:!1,short:"f",type:"boolean"},profile:{short:"p",type:"string"},run:{default:!1,short:"r",type:"boolean"},runnerGroup:{short:"g",type:"string"},template:{short:"T",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile),i;if(t.template)i=await xa(t.template);let r={directory:t.directory,labels:t.labels,name:t.name,numberOfMachines:t.numberOfMachines,os:t.os,overwrite:t.overwrite,run:t.run,runnerGroup:t.runnerGroup,token:t.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:t.url},s=n||i?{directory:r.directory??n?.directory??i?.directory??`${process.cwd()}/gh-runners`,labels:r.labels??n?.labels??i?.labels,name:r.name??n?.name??i?.name??"runner",numberOfMachines:r.numberOfMachines??String(n?.numberOfMachines??i?.numberOfMachines)??"1",os:r.os??n?.os??i?.os??"osx",overwrite:r.overwrite??n?.overwrite??i?.overwrite??!1,run:r.run??n?.run??i?.run??!1,runnerGroup:r.runnerGroup??n?.runnerGroup??i?.runnerGroup,token:r.token,url:r.url??n?.url??i?.url}:null;if(s)return s;return{directory:r.directory,labels:r.labels,name:r.name,numberOfMachines:r.numberOfMachines,os:r.os,overwrite:r.overwrite,run:r.run,runnerGroup:r.runnerGroup,token:r.token,url:r.url}}async function ya({directory:t,os:e}){let n=w({prefix:"createMachines:download",secrets:[]}),i=j(t);n.info(`Fetching latest runner version for ${e}...`);let r=await it(async()=>(await Zt`curl -Ls -o /dev/null -w "%{url_effective}" https://github.com/actions/runner/releases/latest`).text(),{onRetry:(u,p)=>{n.warn(`Retrying GitHub API call (attempt ${u}): ${p.message}`)}}),o=(await Zt`basename ${j(r)}`).text().trim().replace("v",""),a=`actions-runner-${e}-x64-${o}.tar.gz`,f=`https://github.com/actions/runner/releases/download/v${o}/${a}`;if(n.debug(`Runner version: ${o}`),n.debug(`Download URL: ${f}`),await mn(t),await mn(`${t}/machines`),!await y.exists(`${t}/${a}`))n.info("Downloading runner image..."),await it(async()=>await Zt`curl -o ${i}/${j(a)} -L ${f}`,{maxAttempts:5,onRetry:(u,p)=>{n.warn(`Retrying runner download (attempt ${u}): ${p.message}`)}}),n.info("Download complete");else n.info("Runner image already exists, skipping download");return a}async function ba({overwrite:t,numberOfMachines:e,directory:n,runnerBase:i}){let r=w({prefix:"createMachines:extract",secrets:[]}),s=Number(e),o=(()=>{try{let p=Bun.spawnSync(["nproc"]);return Number.parseInt(p.stdout.toString().trim(),10)||4}catch{try{let p=Bun.spawnSync(["sysctl","-n","hw.ncpu"]);return Number.parseInt(p.stdout.toString().trim(),10)||4}catch{return 4}}})(),a=Math.min(Math.max(2,Math.floor(o/2)),s,8);r.info(`Extracting ${s} runners with concurrency of ${a}`);let f=Array.from({length:s},(p,d)=>d+1).map((p)=>({execute:async()=>{let d=`${n}/machines/${p}`;if(await y.exists(d))if(t)r.debug(`Machine ${p} already exists, removing...`),await y.deleteDirectory(d,{recursive:!0});else{r.debug(`Machine ${p} already exists, skipping...`);return}await y.createDirectory(d),await Zt`tar xzf ${i} -C ${d.replace(`${n}/`,"")}`.cwd(n),await oo(d),r.debug(`Machine ${p} extracted successfully`)},runnerIndex:p})),u=[];for(let p=0;p<f.length;p+=a){let d=f.slice(p,p+a),g=await Promise.allSettled(d.map((b)=>b.execute()));for(let[b,m]of g.entries())if(m.status==="rejected")throw r.error(`Failed to extract runner ${d[b]?.runnerIndex}: ${m.reason}`),m.reason;u.push(...g)}r.info(`Successfully extracted ${s} runners`)}async function wa({directory:t,numberOfMachines:e,token:n,url:i,name:r,labels:s,runnerGroup:o}){let a=w({prefix:"createMachines:start",secrets:[n]});a.info(`Starting ${e} runners...`);let f=new wt({maxRestarts:3,maxWorkers:Number(e),restartDelay:5000,restartOnError:!0});for(let u=1;u<=Number(e);u++){let p=`${xe()}/src/runner-worker.ts`,d=`${r}-${u}`,g=`runner-${u}`;await f.createWorker({data:{index:u,labels:s,machineCwd:`${t}/machines/${u}`,name:r,runnerGroup:o,token:n,url:i},id:g,name:d,onError:(b)=>{a.error(`Worker ${d} error:`,b)},onExit:(b)=>{a.info(`Worker ${d} exited with code ${b}`)},onMessage:(b)=>{let m=b.type==="error"?"error":"info";a[m](`${d}: ${b.message}`)},scriptPath:p})}a.info("All workers started. Press Ctrl+C to stop all machines")}async function xa(t){let e=w({prefix:"loadTemplate"}),n="./hydra-templates.json",i=Bun.file("./hydra-templates.json");if(await i.exists())try{let o=await i.json();if(o.templates?.[t])return e.info(`Using local template: ${t}`),Rn(o.templates[t],o.templates)}catch(o){e.warn(`Failed to load local templates: ${o}`)}let r=ha(pa(),".hydra","templates.json"),s=Bun.file(r);if(await s.exists())try{let o=await s.json();if(o.templates?.[t])return e.info(`Using global template: ${t}`),Rn(o.templates[t],o.templates)}catch(o){e.warn(`Failed to load global templates: ${o}`)}e.warn(`Template '${t}' not found`);return}function Rn(t,e,n=new Set){if(t.name&&n.has(t.name))throw new Error(`Circular template dependency detected: ${t.name}`);if(t.name)n.add(t.name);let i={};if(t.extends&&e[t.extends])i=Rn(e[t.extends],e,n);let{name:r,description:s,extends:o,metadata:a,...f}=t;return{...i,...f}}var Ee=v(()=>{q();O();V();Mt();F();ro();tt();Wt()});var ao={};ie(ao,{runMachines:()=>En});import{parseArgs as $a}from"util";var{$:va}=globalThis.Bun;async function En(){let t=await Ra(),{directory:e,numberOfMachines:n,name:i,labels:r,runnerGroup:s}=t,{token:o,url:a}=t;if(!a)throw new Error("URL (-u) parameter is required");if(!o){let f=Pa(a),u=await C({message:`No token provided. Would you like to open GitHub to get a runner token?
|
|
71
|
-
${f}`});if(k(u)||!u)throw new Error("Token is required to run machines");Pe.info("Opening GitHub runner settings..."),await va`open ${f}`.quiet();let p=await A({message:"Enter the runner registration token:",placeholder:"AXXXXXXXXXXXXXXXXXXXXXXXXX",validate:(d)=>{if(!d||d.trim().length===0)return"Token is required";return}});if(k(p))throw new Error("Token is required to run machines");o=p.trim()}if(Pe=w({prefix:"runMachines",secrets:[o]}),Pe.info(`Starting ${n} runners from ${e}`),Pe.debug(`Name: ${i}, Labels: ${r||"none"}`),!await y.exists(`${e}/machines`))throw new Error(`Machines directory not found at ${e}/machines. Run 'hydra create' first.`);await Ea({directory:e,labels:r,name:i,numberOfMachines:n,runnerGroup:s,token:o,url:a})}async function Ra(){let{values:t}=$a({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},labels:{short:"l",type:"string"},name:{default:"runner",short:"n",type:"string"},numberOfMachines:{default:"1",short:"m",type:"string"},profile:{short:"p",type:"string"},runnerGroup:{short:"g",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile),i={directory:t.directory,labels:t.labels,name:t.name,numberOfMachines:t.numberOfMachines,runnerGroup:t.runnerGroup,token:t.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:t.url};if(n)return{directory:i.directory??n.directory??`${process.cwd()}/gh-runners`,labels:i.labels??n.labels,name:i.name??n.name??"runner",numberOfMachines:i.numberOfMachines??String(n.numberOfMachines)??"1",runnerGroup:i.runnerGroup??n.runnerGroup,token:i.token,url:i.url??n.url};return i}async function Ea({directory:t,numberOfMachines:e,token:n,url:i,name:r,labels:s,runnerGroup:o}){let a=w({prefix:"runMachines:start",secrets:[n]});a.info(`Starting ${e} workers...`);let f=new wt({maxRestarts:3,maxWorkers:Number(e),restartDelay:5000,restartOnError:!0});f.on("workerError",(p,d)=>{a.error(`Worker ${p.name} encountered error:`,d)}),f.on("workerExit",(p,d)=>{if(d!==0)a.warn(`Worker ${p.name} exited with code ${d}`)});let u=0;for(let p=1;p<=Number(e);p++){let d=`${t}/machines/${p}`;if(!await y.exists(d)){a.warn(`Machine ${p} doesn't exist, skipping...`);continue}let g=`${xe()}/src/runner-worker.ts`,b=`${r}-${p}`,m=`runner-${p}`;try{await f.createWorker({data:{index:p,labels:s,machineCwd:d,name:r,runnerGroup:o,token:n,url:i},id:m,name:b,onError:(x)=>{a.error(`Worker ${b} error:`,x)},onExit:(x)=>{a.info(`Worker ${b} exited with code ${x}`)},onMessage:(x)=>{let M=x.type==="error"?"error":"info";a[M](`${b}: ${x.message}`)},scriptPath:g}),a.info(`Worker ${b} started successfully`),u++}catch(x){a.error(`Failed to start worker ${b}:`,x)}}if(u===0)throw new Error("No workers could be started");a.info(`${u} workers started. Press Ctrl+C to stop all machines`),process.on("SIGINT",async()=>{a.info("Gracefully shutting down workers..."),await f.shutdown(),process.exit(0)})}function Pa(t){try{let e=new URL(t),n=e.pathname.split("/").filter(Boolean);if(e.hostname==="github.com"||e.hostname==="www.github.com"){if(n[0]==="orgs"&&n[1])return`https://github.com/organizations/${n[1]}/settings/actions/runners/new`;if(n.length>=2)return`https://github.com/${n[0]}/${n[1]}/settings/actions/runners/new`}else{if(n[0]==="orgs"&&n[1])return`${e.origin}/organizations/${n[1]}/settings/actions/runners/new`;if(n.length>=2)return`${e.origin}/${n[0]}/${n[1]}/settings/actions/runners/new`}return t}catch{return t}}var Pe;var Pn=v(()=>{q();V();Mt();F();tt();Wt();Pe=w({prefix:"runMachines"})});var fo={};ie(fo,{removeMachines:()=>Yt});import{parseArgs as Aa}from"util";var{$:lo}=globalThis.Bun;async function Yt(){let t=await Ta(),{directory:e,numberOfMachines:n,force:i}=t,{token:r,url:s}=t,o=`${e}/machines`;if(!await y.exists(o))throw new Error(`Machines directory not found at ${o}. Nothing to remove.`);if(r)ot=w({prefix:"hydra:remove",secrets:[r]});if(!r&&!i){if(!s)throw ot.warn("No token or URL provided. Runners will not be unregistered from GitHub."),ot.warn("Use --force to remove runners without unregistering them."),new Error("Token (-t) and URL (-u) parameters are required or use --force");let a=Ca(s),f=await C({message:`No token provided. Would you like to open GitHub to get a runner token for unregistration?
|
|
72
|
-
${a}`});if(k(f)||!f)throw ot.warn("Use --force to remove runners without unregistering them."),new Error("Token is required to unregister runners (or use --force)");ot.info("Opening GitHub runner settings..."),await lo`open ${a}`.quiet();let u=await A({message:"Enter the runner removal token:",placeholder:"AXXXXXXXXXXXXXXXXXXXXXXXXX",validate:(p)=>{if(!p||p.trim().length===0)return"Token is required";return}});if(k(u))throw ot.warn("Use --force to remove runners without unregistering them."),new Error("Token is required to unregister runners (or use --force)");r=u.trim()}if(r&&s)ot.info("Unregistering runners from GitHub..."),await Oa({directory:e,numberOfMachines:n,token:r});else if(!i)throw ot.warn("No token or URL provided. Runners will not be unregistered from GitHub."),ot.warn("Use --force to remove runners without unregistering them."),new Error("Token (-t) and URL (-u) parameters are required or use --force");await Ha({directory:e,numberOfMachines:n}),ot.info("Runners successfully removed")}async function Ta(){let{values:t}=Aa({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},force:{default:!1,short:"f",type:"boolean"},numberOfMachines:{default:"1",short:"m",type:"string"},profile:{short:"p",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile),i={directory:t.directory,force:t.force,numberOfMachines:t.numberOfMachines,token:t.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:t.url};if(n)return{directory:i.directory??n.directory??`${process.cwd()}/gh-runners`,force:i.force,numberOfMachines:i.numberOfMachines??String(n.numberOfMachines)??"1",token:i.token,url:i.url??n.url};return i}async function Oa({directory:t,numberOfMachines:e,token:n}){let i=w({prefix:"hydra:remove:unregister",secrets:[n]}),r=Number(e),s=(()=>{try{let g=Bun.spawnSync(["nproc"]);return Number.parseInt(g.stdout.toString().trim(),10)||4}catch{try{let g=Bun.spawnSync(["sysctl","-n","hw.ncpu"]);return Number.parseInt(g.stdout.toString().trim(),10)||4}catch{return 4}}})(),o=Math.min(Math.max(2,Math.floor(s/2)),r,8);i.info(`Unregistering ${r} runners with concurrency of ${o}`);let a=Array.from({length:r},(g,b)=>b+1).map((g)=>({execute:async()=>{let b=`${t}/machines/${g}`;if(!await y.exists(b))return i.debug(`Machine ${g} doesn't exist, skipping...`),{runnerIndex:g,status:"skipped"};try{return i.debug(`Unregistering machine ${g}...`),await lo`${j(b)}/config.sh remove`.quiet().env({...process.env,RUNNER_CFG_PAT:n}),i.info(`Successfully unregistered machine ${g} from GitHub`),{runnerIndex:g,status:"success"}}catch(m){return i.warn(`Unable to unregister machine ${g}: ${m}`),{error:m,runnerIndex:g,status:"failed"}}},runnerIndex:g})),f=[];for(let g=0;g<a.length;g+=o){let b=a.slice(g,g+o),m=await Promise.allSettled(b.map((x)=>x.execute()));f.push(...m)}let u=f.filter((g)=>g.status==="fulfilled"&&g.value?.status==="success").length,p=f.filter((g)=>g.status==="fulfilled"&&g.value?.status==="failed").length,d=f.filter((g)=>g.status==="fulfilled"&&g.value?.status==="skipped").length;i.info(`Unregistration complete: ${u} successful, ${p} failed, ${d} skipped`)}async function Ha({directory:t,numberOfMachines:e}){let n=w({prefix:"hydra:remove:removeDirectories",secrets:[]}),i=Number(e),r=Array.from({length:i},(f,u)=>u+1).map((f)=>({execute:async()=>{let u=`${t}/machines/${f}`;if(!await y.exists(u))return{runnerIndex:f,status:"skipped"};try{return await y.deleteDirectory(u,{recursive:!0}),n.debug(`Removed machine ${f} directory`),{runnerIndex:f,status:"success"}}catch(p){return n.error(`Error removing machine ${f} directory: ${p}`),{error:p,runnerIndex:f,status:"failed"}}},runnerIndex:f})),s=await Promise.allSettled(r.map((f)=>f.execute())),o=s.filter((f)=>f.status==="fulfilled"&&f.value?.status==="success").length,a=s.filter((f)=>f.status==="fulfilled"&&f.value?.status==="failed").length;if(n.info(`Directory removal complete: ${o} removed, ${a} failed`),a>0)throw new Error(`Failed to remove ${a} runner directories`);try{let f=`${t}/machines`;if((await y.listDirectory(f)).length===0){if(await y.deleteDirectory(f,{recursive:!0}),(await y.listDirectory(t)).length===0)await y.deleteDirectory(t,{recursive:!0});ot.info("Removed empty directories")}}catch(f){}}function Ca(t){try{let e=new URL(t),n=e.pathname.split("/").filter(Boolean);if(e.hostname==="github.com"||e.hostname==="www.github.com"){if(n[0]==="orgs"&&n[1])return`https://github.com/organizations/${n[1]}/settings/actions/runners`;if(n.length>=2)return`https://github.com/${n[0]}/${n[1]}/settings/actions/runners`}else{if(n[0]==="orgs"&&n[1])return`${e.origin}/organizations/${n[1]}/settings/actions/runners`;if(n.length>=2)return`${e.origin}/${n[0]}/${n[1]}/settings/actions/runners`}return t}catch{return t}}var ot;var Ae=v(()=>{q();V();Mt();F();tt();ot=w({prefix:"hydra:remove"})});O();G();var St="0.5.1";O();class Xi{commands=new Map;aliases=new Map;register(t){if(this.commands.set(t.name,t),t.aliases)for(let e of t.aliases)this.aliases.set(e,t.name)}get(t){let e=this.aliases.get(t)||t;return this.commands.get(e)}has(t){return this.commands.has(t)||this.aliases.has(t)}getAll(){return Array.from(this.commands.values())}getNames(){return Array.from(this.commands.keys())}getAliases(){return new Map(this.aliases)}}var L=new Xi;var Qi={backup:{description:"Backup and restore runner configurations",examples:[{command:"hydra backup",description:"Create a backup"},{command:"hydra backup -o /path/to/backups",description:"Create backup in custom location"},{command:"hydra backup --list",description:"List available backups"},{command:"hydra backup --restore backup-2024-01-15T10-30-00-000Z",description:"Restore from backup"},{command:"hydra backup --no-compress",description:"Create uncompressed backup"}],name:"hydra backup",notes:["Backs up runner configuration files (.runner, .credentials, etc.)","Does NOT backup work directories or logs","Compressed backups save space but take longer","Restore will prompt before overwriting existing runners"],options:[{description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Backup output directory",flags:"-o, --output",type:"string"},{description:"List available backups",flags:"-l, --list",type:"boolean"},{description:"Restore from backup ID",flags:"-r, --restore",type:"string"},{default:!0,description:"Compress backup (tar.gz)",flags:"--compress",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra backup [options]"},create:{description:"Create and register new GitHub runner machines",examples:[{command:"hydra create -t TOKEN -u https://github.com/org/repo",description:"Create a single runner"},{command:"hydra create -p production --run",description:"Create and start runners from profile"},{command:"hydra create -m 5 -l docker,linux --run",description:"Create 5 runners with custom labels"},{command:"hydra create --force",description:"Overwrite existing runners"},{command:"hydra create -T production -t TOKEN -u URL",description:"Create runners using a template"}],name:"hydra create",notes:["Requires a GitHub personal access token or runner registration token","Downloads the latest runner image if not cached","Creates runners in parallel for better performance","Use --run to start runners immediately after creation","Runners are created but not started by default"],options:[{description:"GitHub runner token",flags:"-t, --token",type:"string"},{description:"Repository/organization URL",flags:"-u, --url",type:"string"},{default:"./gh-runners",description:"Directory to store runners",flags:"-d, --directory",type:"string"},{default:"1",description:"Number of machines to create",flags:"-m, --numberOfMachines",type:"string"},{default:"runner",description:"Runner name prefix",flags:"-n, --name",type:"string"},{description:"Runner labels (comma-separated)",flags:"-l, --labels",type:"string"},{description:"Runner group",flags:"-g, --runnerGroup",type:"string"},{default:"osx",description:"Operating system (osx, linux, windows)",flags:"-s, --os",type:"string"},{default:!1,description:"Overwrite existing runners",flags:"-f, --overwrite",type:"boolean"},{default:!1,description:"Start runners after creation",flags:"-r, --run",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"},{description:"Use a template configuration",flags:"-T, --template",type:"string"}],usage:"hydra create [options]"},dev:{description:"Development helper commands",examples:[{command:"hydra dev setup",description:"Set up development environment"},{command:"hydra dev test",description:"Test development setup"},{command:"hydra dev clean",description:"Clean development files"},{command:"hydra dev reset",description:"Reset development environment"}],name:"dev",notes:["Creates test configurations and directories","Sets up .env.development with sample values","Test action verifies setup completeness"],options:[{description:"Force action without prompts",flags:"-f, --force",type:"boolean"}],sections:[{content:["setup - Create development environment","test - Verify development setup","clean - Remove development files","reset - Clean and setup fresh"],title:"ACTIONS"}],usage:"hydra dev <action> [options]"},health:{description:"Check runner health and fix common issues",examples:[{command:"hydra health",description:"Interactive health check"},{command:"hydra health --json",description:"JSON output for automation"},{command:"hydra health --fix",description:"Automatically fix issues"},{command:"hydra health -l critical",description:"Show only critical issues"}],name:"hydra health",notes:["Checks runner processes, disk space, and configurations","Can automatically fix common issues like stale locks","Use --json for integration with monitoring systems","Exit code indicates health status (0=healthy, 1=warning, 2=critical)"],options:[{default:"./gh-runners",description:"Runners directory",flags:"-d, --directory",type:"string"},{default:!1,description:"Automatically fix issues",flags:"-f, --fix",type:"boolean"},{default:!1,description:"Output as JSON",flags:"-j, --json",type:"boolean"},{default:"all",description:"Filter by level (all, critical, warning)",flags:"-l, --level",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra health [options]"},logs:{description:"View runner diagnostic logs",examples:[{command:"hydra logs",description:"Interactive log viewer"},{command:"hydra logs --list",description:"List all available logs"},{command:"hydra logs -r 1 -t Worker",description:"View Worker logs for runner 1"},{command:"hydra logs --tail 50",description:"Show last 50 lines of logs"}],name:"hydra logs",notes:["Logs are stored in the _diag directory of each runner","Use --list to see all available log files","Interactive mode lets you browse and select logs","Log types include Runner, Worker, and SelfUpdater"],options:[{default:"./gh-runners",description:"Runners directory",flags:"-d, --directory",type:"string"},{description:"Runner ID (e.g., 1, 2, 3)",flags:"-r, --runner",type:"string"},{description:"Log type (Runner, Worker, etc.)",flags:"-t, --type",type:"string"},{default:!1,description:"List available logs",flags:"-l, --list",type:"boolean"},{description:"Number of lines to show",flags:"--tail",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra logs [options]"},migrate:{description:"Migrate configuration files between formats and versions",examples:[{command:"hydra migrate",description:"Interactively migrate a config file"},{command:"hydra migrate -p hydra.json",description:"Migrate specific config file"},{command:"hydra migrate -f toml",description:"Convert config to TOML format"},{command:"hydra migrate --all",description:"Find and migrate all config files"},{command:"hydra migrate --dry-run",description:"Preview migration changes"}],name:"hydra migrate",notes:["Supports migration between JSON and TOML formats","Automatically upgrades deprecated configuration options","Creates backups before modifying files (use --no-backup to skip)","Converts old root-level settings to profile-based configuration","Use --dry-run to see what changes would be made"],options:[{description:"Path to configuration file",flags:"-p, --path",type:"string"},{description:"Target format (json or toml)",flags:"-f, --format",type:"string"},{default:!1,description:"Find and migrate all config files",flags:"-a, --all",type:"boolean"},{default:!1,description:"Preview changes without modifying files",flags:"-d, --dry-run",type:"boolean"},{default:!0,description:"Create backup before migration",flags:"-b, --backup",type:"boolean"}],usage:"hydra migrate [options]"},monitor:{description:"Monitor worker health and performance",examples:[{command:"hydra monitor",description:"Show current worker health status"},{command:"hydra monitor --watch",description:"Continuously monitor health"},{command:"hydra monitor --json",description:"Output health data as JSON"},{command:"hydra monitor -w -i 10",description:"Watch mode with 10 second intervals"}],name:"hydra monitor",notes:["Displays health metrics for all active workers","Tracks CPU usage, memory, uptime, errors, and restarts","Health states: healthy, warning, critical, unknown","Watch mode refreshes display at specified intervals","Uses heartbeat mechanism to detect unresponsive workers"],options:[{default:"./gh-runners",description:"Runners directory",flags:"-d, --directory",type:"string"},{default:!1,description:"Output as JSON",flags:"-j, --json",type:"boolean"},{default:!1,description:"Continuous monitoring mode",flags:"-w, --watch",type:"boolean"},{default:"5",description:"Update interval in seconds",flags:"-i, --interval",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra monitor [options]"},plugin:{description:"Manage Hydra plugins",examples:[{command:"hydra plugin",description:"List installed plugins"},{command:"hydra plugin --list",description:"List all plugins with details"},{command:"hydra plugin --install ./my-plugin",description:"Install local plugin"},{command:"hydra plugin --install https://github.com/user/hydra-slack",description:"Install from git"},{command:"hydra plugin --uninstall slack",description:"Uninstall a plugin"},{command:"hydra plugin --info slack",description:"Show plugin details"}],name:"hydra plugin",notes:["Plugins extend Hydra with additional commands and hooks","Plugins are loaded from ~/.hydra/plugins directory","Set HYDRA_DISABLE_PLUGINS=true to disable all plugins","Set HYDRA_PLUGIN_DIR to load plugins from custom location"],options:[{description:"List installed plugins",flags:"-l, --list",type:"boolean"},{description:"Install a plugin",flags:"-i, --install",type:"boolean"},{description:"Uninstall a plugin",flags:"-u, --uninstall",type:"boolean"},{description:"Show plugin information",flags:"--info",type:"boolean"}],usage:"hydra plugin [action] [plugin-name]"},recovery:{description:"Advanced error recovery and resilience management",examples:[{command:"hydra recovery",description:"Interactive recovery management"},{command:"hydra recovery status",description:"View recovery system status"},{command:"hydra recovery metrics",description:"Show detailed error metrics"},{command:"hydra recovery breakers",description:"View circuit breaker states"},{command:"hydra recovery reset",description:"Reset error metrics"},{command:"hydra recovery status --json",description:"JSON output for monitoring"}],name:"hydra recovery",notes:["Provides automatic retry with exponential backoff for transient errors","Circuit breakers prevent cascading failures","Error classification helps determine recovery strategies","Metrics track error patterns for troubleshooting","Recovery strategies are customizable per error type"],options:[{default:!1,description:"Output as JSON",flags:"-j, --json",type:"boolean"}],sections:[{content:["status - View overall recovery system status","metrics - Show detailed error metrics by type","breakers - View circuit breaker states","reset - Reset all error metrics"],title:"ACTIONS"},{content:["transient - Temporary errors that may succeed on retry","network - Network connectivity issues","configuration - Invalid settings or permissions","resource - System resource exhaustion","unknown - Unclassified errors"],title:"ERROR TYPES"}],usage:"hydra recovery [action] [options]"},remove:{description:"Remove GitHub runner machines",examples:[{command:"hydra remove -t TOKEN -u https://github.com/org/repo",description:"Remove and unregister runners"},{command:"hydra remove --force",description:"Remove without unregistering"},{command:"hydra remove -m 3",description:"Remove specific number of runners"},{command:"hydra remove -p production",description:"Remove using profile settings"}],name:"hydra remove",notes:["Unregisters runners from GitHub before removing (requires token)","Use --force to skip unregistration (use with caution)","Removes runner directories and all associated data","Cannot be undone - consider using backup first"],options:[{description:"GitHub runner token",flags:"-t, --token",type:"string"},{description:"Repository/organization URL",flags:"-u, --url",type:"string"},{default:"./gh-runners",description:"Directory containing runners",flags:"-d, --directory",type:"string"},{default:"1",description:"Number of machines to remove",flags:"-m, --numberOfMachines",type:"string"},{default:!1,description:"Force removal without unregistering",flags:"-f, --force",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra remove [options]"},run:{description:"Start existing GitHub runner machines",examples:[{command:"hydra run -t TOKEN -u https://github.com/org/repo",description:"Start runners with token"},{command:"hydra run -p production",description:"Start using profile settings"},{command:"hydra run -m 3",description:"Start specific number of runners"},{command:"hydra run -l docker,gpu",description:"Start with additional labels"}],name:"hydra run",notes:["Starts runners that were previously created","Each runner runs in a separate worker process","Press Ctrl+C to stop all runners gracefully","Requires token if runners need to be reconfigured"],options:[{description:"GitHub runner token",flags:"-t, --token",type:"string"},{description:"Repository/organization URL",flags:"-u, --url",type:"string"},{default:"./gh-runners",description:"Directory containing runners",flags:"-d, --directory",type:"string"},{default:"1",description:"Number of machines to run",flags:"-m, --numberOfMachines",type:"string"},{default:"runner",description:"Runner name prefix",flags:"-n, --name",type:"string"},{description:"Runner labels (comma-separated)",flags:"-l, --labels",type:"string"},{description:"Runner group",flags:"-g, --runnerGroup",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra run [options]"},scale:{description:"Automatically scale runners based on job queue",examples:[{command:"hydra scale",description:"One-time scaling check"},{command:"hydra scale --watch",description:"Continuous monitoring"},{command:"hydra scale --min 2 --max 10",description:"Set scaling limits"},{command:"hydra scale --dry-run",description:"Preview scaling actions"}],name:"hydra scale",notes:["Monitors GitHub job queue and scales runners accordingly","Requires token with workflow scope to read job queue","Respects min/max limits to prevent over-provisioning","Scale down only removes idle runners"],options:[{description:"GitHub token (needs workflow scope)",flags:"-t, --token",type:"string"},{description:"Repository/organization URL",flags:"-u, --url",type:"string"},{default:"./gh-runners",description:"Runners directory",flags:"-d, --directory",type:"string"},{default:1,description:"Minimum number of runners",flags:"--min",type:"number"},{default:10,description:"Maximum number of runners",flags:"--max",type:"number"},{default:!1,description:"Watch mode (continuous)",flags:"-w, --watch",type:"boolean"},{default:30,description:"Check interval in seconds",flags:"-i, --interval",type:"number"},{default:5,description:"Scale up threshold (pending jobs)",flags:"--scale-up-threshold",type:"number"},{default:300,description:"Idle time before scale down (seconds)",flags:"--idle-time",type:"number"},{default:!1,description:"Preview actions without executing",flags:"--dry-run",type:"boolean"},{description:"Runner labels",flags:"-l, --labels",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra scale [options]"},status:{description:"Show status of GitHub runner machines",examples:[{command:"hydra status",description:"Show all runners status"},{command:"hydra status --json",description:"Output as JSON"},{command:"hydra status -p production",description:"Status using profile"}],name:"hydra status",notes:["Shows runner process status and basic information","Online means the runner process is active","Use --json for integration with monitoring tools"],options:[{default:"./gh-runners",description:"Directory containing runners",flags:"-d, --directory",type:"string"},{default:!1,description:"Output as JSON",flags:"-j, --json",type:"boolean"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra status [options]"},template:{description:"Manage reusable runner configuration templates",examples:[{command:"hydra template",description:"Interactive template management"},{command:"hydra template list",description:"List all available templates"},{command:"hydra template create",description:"Create a new template"},{command:"hydra template use my-template",description:"Use a template"},{command:"hydra template show my-template",description:"Show template details"},{command:"hydra template delete my-template",description:"Delete a template"},{command:"hydra template create --global",description:"Create global template"}],name:"hydra template",notes:["Templates provide reusable runner configurations","Global templates are stored in ~/.hydra/templates.json","Local templates are stored in ./hydra-templates.json","Templates can extend other templates for composition","Use 'hydra create --template <name>' to create runners from a template"],options:[{description:"Template name",flags:"-n, --name",type:"string"},{default:!1,description:"Use global template storage",flags:"-g, --global",type:"boolean"},{default:!1,description:"Force action without prompts",flags:"-f, --force",type:"boolean"},{description:"Create from existing template",flags:"-F, --from",type:"string"}],sections:[{content:["list - List all available templates","create - Create a new template","use - Generate config from template","show - Display template details","delete - Remove a template"],title:"ACTIONS"}],usage:"hydra template [action] [name] [options]"},validate:{description:"Validate Hydra configuration",examples:[{command:"hydra validate",description:"Validate current configuration"},{command:"hydra validate --fix",description:"Fix configuration issues"},{command:"hydra validate --json",description:"Machine-readable output"}],name:"validate",notes:["Checks for syntax errors and invalid values","Provides warnings for potential issues","Fix mode can resolve some common problems"],options:[{description:"Config file path",flags:"-c, --config <path>",type:"string"},{description:"Output as JSON",flags:"-j, --json",type:"boolean"},{description:"Attempt to fix issues",flags:"-f, --fix",type:"boolean"}],usage:"hydra validate [options]"},watch:{description:"Watch directory for changes and run commands",examples:[{command:"hydra watch status",description:"Watch and run status on changes"},{command:"hydra watch health --debounce 5000",description:"Watch with 5 second debounce"}],name:"watch",notes:["Watches recursively for any file changes","Debounce prevents rapid command execution","Use exclude patterns to ignore specific files"],options:[{default:"./gh-runners",description:"Directory to watch",flags:"-d, --directory <path>",type:"string"},{default:"1000",description:"Debounce time in milliseconds",flags:"--debounce <ms>",type:"string"},{description:"Patterns to exclude from watching",flags:"--exclude <pattern>",type:"string"},{description:"Configuration profile",flags:"-p, --profile <name>",type:"string"}],usage:"hydra watch [command] [options]"}};function Xs(t){let e=[...L.getAll().map((n)=>({description:n.description,name:n.name})),...Object.entries(Qi).map(([n,i])=>({description:i.description,name:n}))];if(t){let n=L.get(t);if(n){console.log(me(n.help));return}let i=Qi[t];if(i){console.log(me(i));return}console.error(`Unknown command: ${t}`),process.exit(1)}console.log(an("Hydra - GitHub Self-Hosted Runner Manager","hydra <command> [options]",e,`Hydra v${St} - Simplifying GitHub runner management`))}var dn={aliases:["h","--help","-h"],description:"Show help information",execute:async()=>{let t=process.argv.slice(3);Xs(t[0])},help:{description:"Show help information",examples:[{command:"hydra help",description:"Show general help"},{command:"hydra help create",description:"Show help for create command"}],name:"hydra help",usage:"hydra help [command]"},name:"help"};q();O();G();import{resolve as ta}from"path";import{parseArgs as ea}from"util";var{$:no}=globalThis.Bun;V();F();tt();Wt();class eo{services=new Map;factories=new Map;register(t,e,n=!0){let i=String(t);if(n)this.factories.set(i,()=>{if(!this.services.has(i))this.services.set(i,e());return this.services.get(i)});else this.factories.set(i,e)}get(t){let e=this.factories.get(String(t));if(!e)throw new Error(`Service ${String(t)} not registered`);return e()}getFileSystem(){return this.get("fileSystem")}getCommandRegistry(){return this.get("commandRegistry")}createWorkerManager(t){return this.get("workerManagerFactory")(t)}createLogger(t){return this.get("loggerFactory")(t)}async loadConfig(t){return this.get("configLoader")(t)}reset(){this.services.clear()}}var Bt=new eo;Bt.register("fileSystem",()=>new $e,!0);Bt.register("commandRegistry",()=>L,!0);Bt.register("workerManagerFactory",()=>(t)=>new wt(t),!1);Bt.register("loggerFactory",()=>w,!1);Bt.register("configLoader",()=>N,!1);function Re(t=Bt){return{services:t}}F();async function na(t){let e=t||Re(),n=e.services.createLogger({prefix:"hydra:init"}),i=e.services.getFileSystem(),{toml:r}=oa(),s=r?"hydra.toml":"hydra.json",o=ta(process.cwd(),s);if(await i.exists(o)){let b=await C({initialValue:!1,message:`Configuration file ${s} already exists. Overwrite?`});if(k(b)||!b)nn("Configuration cancelled"),process.exit(0)}he(P.cyan("\uD83D\uDE80 Hydra Configuration Setup")),n.info("This will create a configuration file with your runner settings."),n.info("You can always edit the file later or create additional profiles.");let a=await $i({directory:()=>A({defaultValue:"./gh-runners",message:"Directory to store runners?",placeholder:"./gh-runners"}),labels:({results:b})=>{let m=b.name||"runner";return A({defaultValue:m,message:"Runner labels (comma-separated)?",placeholder:m})},name:()=>A({defaultValue:"runner",message:"Runner name prefix?",placeholder:"runner"}),numberOfMachines:()=>A({defaultValue:"1",message:"Number of runner machines?",placeholder:"1",validate:(b)=>{let m=Number.parseInt(b,10);if(Number.isNaN(m)||m<1)return"Please enter a valid number greater than 0";return}}),profileName:()=>A({message:"Profile name?",placeholder:"default"}),url:()=>A({message:"GitHub repository or organization URL? (optional)",placeholder:"https://github.com/org/repo"})},{onCancel:()=>{nn("Configuration cancelled"),process.exit(0)}}),{profileName:f,labels:u,numberOfMachines:p,...d}=a,g={defaultProfile:f,profiles:{[f]:{...d,labels:u,numberOfMachines:Number.parseInt(p,10),os:"osx",overwrite:!1,run:!1}}};if(await zi(o,g),await Nt(async()=>{await i.chmod(o,"600")},{logLevel:"warn",message:"Could not set secure file permissions"}),at(P.green(`\u2713 Configuration saved to ${s}`)),n.info("Example usage:"),n.info(` hydra create -p ${f} --token YOUR_TOKEN${a.url?"":" --url REPO_URL"}`),n.info("You can add more profiles by editing the configuration file."),a.url)await ia(a.url,e)}async function ia(t,e){let n=e.services.createLogger({prefix:"hydra:init"}),i=/github\.com[:/]([^/]+)(?:\/([^/.]+))?/,r=t.match(i);if(!r)return;let[,s,o]=r,f=`https://github.com/${o?`${s}/${o}`:`organizations/${s}`}/settings/actions/runners`;n.info(`Opening GitHub settings: ${f}`),await Nt(async()=>{await no`open ${f}`.quiet()},{fallback:async()=>{await Nt(async()=>{await no`xdg-open ${f}`.quiet()},{fallback:()=>{n.info("Please open the URL manually to add a new runner token.")},logLevel:"info",message:"Alternative browser open method also failed"})},logLevel:"info",message:"Could not open browser automatically"})}function oa(){let{values:t}=ea({allowPositionals:!0,args:Bun.argv,options:{toml:{default:!1,short:"t",type:"boolean"}},strict:!0});return t}var xn={aliases:["i","initialize"],description:"Initialize Hydra configuration",execute:()=>na(),help:{description:"Initialize Hydra configuration",examples:[{command:"hydra init",description:"Create a new configuration file"},{command:"hydra init --toml",description:"Create TOML configuration"}],name:"hydra init",notes:["Creates hydra.json (or hydra.toml) in the current directory","Walks through an interactive setup process","Sets secure file permissions (600) on the config file"],options:[{description:"Create TOML config instead of JSON",flags:"-t, --toml",type:"boolean"}],usage:"hydra init [options]"},name:"init"};q();O();V();import{parseArgs as ra}from"util";async function sa(t){let e=t||Re(),n=e.services.createLogger({prefix:"hydra:status"}),i=await aa(e),{directory:r,token:s,url:o,json:a}=i;if(!s||!o)throw new Error("Token (-t) and URL (-u) parameters are required");let f=T();f.start("Fetching runner status...");try{let u=await la(r,e),p=await fa(o,s,e),d=ua(u,p);if(f.stop("Runner status fetched"),a)n.info(JSON.stringify(d,null,2));else ca(d,e)}catch(u){throw f.stop("Failed to fetch runner status"),u}}async function aa(t){let{values:e}=ra({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},json:{default:!1,short:"j",type:"boolean"},profile:{short:"p",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),n=await t.services.loadConfig({configPath:e.config}),i=await S(n,e.profile);return{directory:e.directory||i?.directory||`${process.cwd()}/gh-runners`,json:e.json,token:e.token,url:e.url||i?.url}}async function la(t,e){let n=e.services.getFileSystem(),i=`${t}/machines`;if(!await n.exists(i))return[];try{return(await n.listDirectory(i)).filter((s)=>s.isDirectory&&/^\d+$/.test(s.name)).map((s)=>s.name)}catch{return[]}}async function fa(t,e,n){let i=t.match(/github\.com[:/]([^/]+)(?:\/([^/.]+))?/);if(!i)throw new Error("Invalid GitHub URL");let[,r,s]=i,o=s?`https://api.github.com/repos/${r}/${s}/actions/runners`:`https://api.github.com/orgs/${r}/actions/runners`;return it(async()=>{let a={Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${e}`},f=await fetch(o,{headers:a});if(!f.ok)throw new Error(`GitHub API error: ${f.status} ${f.statusText}`);return await f.json()},{onRetry:(a,f)=>{n.services.createLogger({prefix:"hydra:status"}).warn(`Retrying GitHub API call (attempt ${a}): ${f.message}`)}})}function ua(t,e){let n=[],i=new Map(e.runners.map((r)=>[r.name,r]));for(let r of t){let s=`runner-${r}`,o=i.get(s);if(o)n.push({busy:o.busy,labels:o.labels.map((a)=>a.name),name:s,os:o.os,status:o.busy?"busy":o.status==="online"?"online":"offline"});else n.push({busy:!1,labels:[],name:s,os:"unknown",status:"offline"})}return n}function ca(t,e){let n=e.services.createLogger({prefix:"hydra:status"});if(t.length===0){n.info("No runners found");return}n.info("Runner Status:"),n.info("\u2500".repeat(80));let i={busy:c.busy,offline:c.offline,online:c.online};for(let s of t){let o=i[s.status],a=s.status.toUpperCase().padEnd(7);n.info(`${o("\u25CF")} ${o(a)} ${c.value(s.name.padEnd(20))} ${c.dim(`OS: ${s.os.padEnd(10)}`)} ${s.labels.length>0?c.dim(`Labels: ${s.labels.join(", ")}`):""}`)}n.info("\u2500".repeat(80));let r={busy:t.filter((s)=>s.status==="busy").length,offline:t.filter((s)=>s.status==="offline").length,online:t.filter((s)=>s.status==="online").length,total:t.length};n.info(`Summary: Total: ${r.total} | ${c.online(`Online: ${r.online}`)} | ${c.busy(`Busy: ${r.busy}`)} | ${c.offline(`Offline: ${r.offline}`)}`)}var $n={aliases:["s","stat","ls","list"],description:"Show status of GitHub runner machines",execute:()=>sa(),help:{description:"Show status of GitHub runner machines",examples:[{command:"hydra status",description:"Show all runners status"},{command:"hydra status --json",description:"Output as JSON"},{command:"hydra status -p production",description:"Status using profile"}],name:"hydra status",notes:["Shows runner process status and basic information","Online means the runner process is active","Use --json for integration with monitoring tools"],options:[{default:"./gh-runners",description:"Directory containing runners",flags:"-d, --directory",type:"string"},{default:!1,description:"Output as JSON",flags:"-j, --json",type:"boolean"},{description:"GitHub runner token",flags:"-t, --token",type:"string"},{description:"Repository/organization URL",flags:"-u, --url",type:"string"},{description:"Configuration profile",flags:"-p, --profile",type:"string"},{description:"Configuration file path",flags:"-c, --config",type:"string"}],usage:"hydra status [options]"},name:"status"};var co=new Map;function An(t,e){co.set(t,e)}async function On(t){let e=L.get(t);if(e)return e;let n=co.get(t);if(!n)return null;try{let i=await n(),r;if(i.default&&Tn(i.default))r=i.default;else{let s=`${t}Command`;if(i[s]&&Tn(i[s]))r=i[s];else for(let[,o]of Object.entries(i))if(Tn(o)){r=o;break}}if(r)return L.register(r),r;return null}catch(i){return console.error(`Failed to load command ${t}:`,i),null}}function Tn(t){return t&&typeof t==="object"&&typeof t.name==="string"&&typeof t.description==="string"&&typeof t.execute==="function"&&t.help&&typeof t.help==="object"}function po(){An("create",async()=>{let{createMachines:t}=await Promise.resolve().then(() => (Ee(),so));return{default:{description:"Create and register new GitHub runner machines",execute:t,help:{description:"Create and register new GitHub runner machines",name:"create",usage:"hydra create [options]"},name:"create"}}}),An("run",async()=>{let{runMachines:t}=await Promise.resolve().then(() => (Pn(),ao));return{default:{description:"Start existing GitHub runner machines",execute:t,help:{description:"Start existing GitHub runner machines",name:"run",usage:"hydra run [options]"},name:"run"}}}),An("remove",async()=>{let{removeMachines:t}=await Promise.resolve().then(() => (Ae(),fo));return{default:{description:"Remove GitHub runner machines",execute:t,help:{description:"Remove GitHub runner machines",name:"remove",usage:"hydra remove [options]"},name:"remove"}}})}async function uo(t){await On(t)}function ho(){setTimeout(()=>{uo("create").catch(()=>{}),uo("status").catch(()=>{})},100)}O();tt();var xt=w({prefix:"Error"});class go extends Error{code;details;suggestion;constructor(t,e,n,i){super(t);this.code=e;this.details=n;this.suggestion=i;this.name="HydraError"}}function mo(t,e){if(t instanceof go){if(xt.error(t.message),t.details)xt.error(`Details: ${t.details}`);if(t.suggestion)xt.info(`
|
|
73
|
-
${c.value("Suggestion")}: ${t.suggestion}`);process.exit(1)}if(t instanceof Error){let n=_a(t,e);if(xt.error(n.message),n.suggestion)xt.info(`
|
|
74
|
-
${c.value("Suggestion")}: ${n.suggestion}`);if(process.env.DEBUG)xt.debug("Stack trace:"),xt.debug(t.stack||"No stack trace available");process.exit(1)}xt.error(`Unknown error: ${String(t)}`),process.exit(1)}function _a(t,e){let n=t.message.toLowerCase();if(n.includes("enoent")||n.includes("no such file"))return{message:`File or directory not found: ${Na(t.message)||"unknown"}`,suggestion:"Check that the path exists and you have permission to access it"};if(n.includes("eacces")||n.includes("permission denied"))return{message:"Permission denied",suggestion:"Try running with elevated permissions or check file ownership"};if(n.includes("eaddrinuse")||n.includes("address already in use"))return{message:"Port or address already in use",suggestion:"Check if another instance is already running"};if(n.includes("token")&&(n.includes("invalid")||n.includes("unauthorized")))return{message:"Invalid or expired GitHub token",suggestion:"Generate a new token at https://github.com/settings/tokens"};if(n.includes("rate limit"))return{message:"GitHub API rate limit exceeded",suggestion:"Wait a few minutes and try again, or use a different token"};if(n.includes("network")||n.includes("etimedout")||n.includes("enotfound"))return{message:"Network error - unable to connect",suggestion:"Check your internet connection and proxy settings"};if(n.includes("json")&&(n.includes("unexpected")||n.includes("parse")))return{message:"Invalid JSON in configuration file",suggestion:"Validate your JSON at https://jsonlint.com/"};if(n.includes("toml")&&n.includes("parse"))return{message:"Invalid TOML in configuration file",suggestion:"Check for syntax errors in your TOML file"};if(n.includes("directory")&&n.includes("exists"))return{message:t.message,suggestion:"Use --overwrite flag to replace existing directory"};if(n.includes("runner")&&n.includes("already"))return{message:"Runner already exists",suggestion:"Remove existing runner first with 'hydra remove'"};if(e?.command==="create"&&n.includes("token"))return{message:t.message,suggestion:"Provide a token with -t flag or set GITHUB_TOKEN environment variable"};if(e?.command==="run"&&n.includes("not found"))return{message:"No runners found to start",suggestion:"Create runners first with 'hydra create'"};return{message:t.message}}function Na(t){let e=t.match(/['"]([^'"]+)['"]/);return e?e[1]??null:null}F();import{EventEmitter as Sa}from"events";import{homedir as Ma}from"os";import{join as Cn}from"path";F();tt();import{join as Hn}from"path";class yo{eventBus;services;plugins=new Map;hooks=new Map;commands=new Map;logger=w({prefix:"PluginManager"});pluginContexts=new Map;constructor(t,e){this.eventBus=t;this.services=e}async loadPlugin(t){try{let e=Hn(t,"plugin.json");if(!await y.exists(e))throw new Error(`Plugin manifest not found at ${e}`);let n=await y.readFile(e),i=JSON.parse(n);if(!i.name||!i.version||!i.main)throw new Error("Invalid plugin manifest: missing required fields");if(this.plugins.has(i.name))throw new Error(`Plugin ${i.name} is already loaded`);let s=await import(Hn(t,i.main)),o={activate:s.activate||s.default?.activate,deactivate:s.deactivate||s.default?.deactivate,manifest:i};if(!o.activate)throw new Error(`Plugin ${i.name} does not export an activate function`);let a=this.createPluginContext(i.name);this.pluginContexts.set(i.name,a),await o.activate(a),this.plugins.set(i.name,o),this.logger.info(`Loaded plugin: ${i.name} v${i.version}`)}catch(e){throw this.logger.error(`Failed to load plugin from ${t}:`,e),e}}async loadPluginsFromDirectory(t){if(!await y.exists(t))return;let e=await y.readDir(t),n=[];for(let i of e)if(i.isDirectory){let r=Hn(t,i.name);n.push(this.loadPlugin(r).catch((s)=>{this.logger.warn(`Failed to load plugin ${i.name}:`,s)}))}await Promise.all(n)}async unloadPlugin(t){let e=this.plugins.get(t);if(!e)throw new Error(`Plugin ${t} is not loaded`);if(e.deactivate)await e.deactivate();for(let[n,i]of this.commands.entries())if(i.name.startsWith(`${t}:`))this.commands.delete(n);this.plugins.delete(t),this.pluginContexts.delete(t),this.logger.info(`Unloaded plugin: ${t}`)}async unloadAllPlugins(){let t=[];for(let[e]of this.plugins)t.push(this.unloadPlugin(e).catch((n)=>{this.logger.error(`Error unloading plugin ${e}:`,n)}));await Promise.all(t)}createPluginContext(t){return{config:{},eventBus:this.eventBus,fileSystem:y,getService:(e)=>{return this.services.get(e)},logger:w({prefix:`Plugin:${t}`}),registerCommand:(e)=>{let n=`${t}:${e.name}`;this.commands.set(n,{...e,name:n}),this.logger.debug(`Registered command: ${n}`)},registerHook:(e,n)=>{if(!this.hooks.has(e))this.hooks.set(e,new Set);this.hooks.get(e)?.add(n),this.logger.debug(`Registered hook: ${e} for plugin ${t}`)}}}async executeHook(t,...e){let n=this.hooks.get(t);if(!n||n.size===0)return;let i=[];for(let r of n)i.push(Promise.resolve(r(...e)).catch((s)=>{this.logger.error(`Hook ${t} handler error:`,s)}));await Promise.all(i)}getCommand(t){return this.commands.get(t)}getAllCommands(){return Array.from(this.commands.values())}getPlugin(t){return this.plugins.get(t)}getAllPlugins(){return Array.from(this.plugins.values())}isPluginLoaded(t){return this.plugins.has(t)}getLoadedPluginNames(){return Array.from(this.plugins.keys())}}function bo(t,e){return new yo(t,e)}var Wa=[Cn(Ma(),".hydra","plugins"),Cn(process.cwd(),".hydra","plugins"),Cn(process.cwd(),"hydra-plugins")],rt=null,Ut=null;function _n(){if(!Ut)Ut=new Sa;return Ut}async function wo(t){if(rt)return rt;let e=_n();if(rt=bo(e,t),process.env.HYDRA_DISABLE_PLUGINS!=="true")await Ba();return rt}async function Ba(){if(!rt)throw new Error("Plugin manager not initialized");for(let e of Wa)if(await y.exists(e))await rt.loadPluginsFromDirectory(e);let t=process.env.HYDRA_PLUGIN_DIR;if(t&&await y.exists(t))await rt.loadPluginsFromDirectory(t)}function xo(){return rt}async function Nn(){if(rt)await rt.unloadAllPlugins(),rt=null;if(Ut)Ut.removeAllListeners(),Ut=null}function Te(t,e=0){if(e>0)setTimeout(t,e);else if(typeof setImmediate!=="undefined")setImmediate(t);else process.nextTick(t)}class Sn{metrics;constructor(){this.metrics={startTime:performance.now()}}mark(t){let e=performance.now();this.metrics[t]=e-this.metrics.startTime}getMetrics(){return{...this.metrics,totalTime:performance.now()-this.metrics.startTime}}logMetrics(){if(process.env.DEBUG_STARTUP){let t=this.getMetrics();console.log("Startup metrics:");for(let[e,n]of Object.entries(t))if(n!==void 0)console.log(` ${e}: ${n.toFixed(2)}ms`)}}}function $o(){return!(process.env.CI||process.env.HYDRA_SKIP_UPDATE_CHECK||process.env.NO_UPDATE_CHECK)}function vo(t){let[,,e,...n]=t;if(!e||e==="--help"||e==="-h")return{needsHelp:!0};if(e==="--version"||e==="-v")return{command:"version",needsHelp:!1};if(n.includes("--help")||n.includes("-h"))return{command:e,needsHelp:!0};return{command:e,needsHelp:!1}}q();O();G();V();import{existsSync as $t}from"fs";import{copyFile as Ua,mkdir as qt,readdir as Wn}from"fs/promises";import{join as B,resolve as qa}from"path";import{parseArgs as La}from"util";var{$:Lt}=globalThis.Bun;var Ga=$({prefix:"hydra"}).child("backup");async function ja(){let{values:t}=La({allowPositionals:!0,args:Bun.argv,options:{compress:{default:!0,type:"boolean"},config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},list:{default:!1,short:"l",type:"boolean"},output:{short:"o",type:"string"},profile:{short:"p",type:"string"},restore:{short:"r",type:"string"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile);return{compress:t.compress,directory:t.directory||n?.directory||`${process.cwd()}/gh-runners`,list:t.list,output:t.output,restore:t.restore}}async function Ro(){try{let t=await ja();if(t.list){await ka(t.output||B(t.directory,"backups"));return}if(t.restore){await Xa(t);return}await Ja(t)}catch(t){Ga.error("Backup operation failed:",t),process.exit(1)}}async function Ja(t){let e=qa(t.directory),n=B(e,"machines");if(!$t(n)){l.error(`No runners found in ${t.directory}`);return}let i=T();i.start("Creating backup...");try{let r=await Wn(n);if(r.length===0){i.stop("No runners to backup");return}let s=`backup-${new Date().toISOString().replace(/[:.]/g,"-")}`,o=t.output||B(e,"backups"),a=B(o,s);await qt(a,{recursive:!0});let f=0,u=[];for(let d of r){let g=B(n,d),b=B(a,"runners",d);await qt(b,{recursive:!0});let m=[".runner",".credentials",".credentials_rsaparams",".path",".env","config.sh"];for(let x of m){let M=B(g,x);if($t(M)){let Q=B(b,x);await Ua(M,Q);let E=await Bun.file(M).stat();f+=E.size,u.push(`runners/${d}/${x}`)}}}let p={configFiles:u,date:new Date,id:s,runnerCount:r.length,size:f};if(await Bun.write(B(a,"metadata.json"),JSON.stringify(p,null,2)),t.compress){i.message("Compressing backup..."),await Lt`cd ${o} && tar -czf ${s}.tar.gz ${s}`.quiet(),await Lt`rm -rf ${a}`.quiet();let d=await Bun.file(B(o,`${s}.tar.gz`)).stat();i.stop(`Backup created: ${s}.tar.gz (${Mn(d.size)})`)}else i.stop(`Backup created: ${s} (${Mn(f)})`);l.success(`Backed up ${r.length} runner(s)`)}catch(r){throw i.stop("Backup failed"),r}}async function ka(t){if(!$t(t)){l.info("No backups found");return}let e=T();e.start("Scanning backups...");try{let n=await Wn(t),i=[];for(let r of n){let s=B(t,r);if(r.endsWith(".tar.gz")){let o=r.replace(".tar.gz",""),a=await Bun.file(s).stat();i.push({configFiles:[],date:new Date(a.mtime),id:o,runnerCount:0,size:a.size})}else{let o=B(s,"metadata.json");if($t(o)){let a=await Bun.file(o).json();i.push(a)}}}if(e.stop("Found backups"),i.length===0){l.info("No backups found");return}console.log(),console.log(c.bold("\uD83D\uDCE6 Available Backups")),console.log("\u2500".repeat(80));for(let r of i.sort((s,o)=>new Date(o.date).getTime()-new Date(s.date).getTime())){let s=new Date(r.date).toLocaleString(),o=Mn(r.size),a=r.runnerCount>0?`${r.runnerCount} runners`:"compressed";console.log(`${c.value(r.id)}`),console.log(` Date: ${s}`),console.log(` Size: ${o}`),console.log(` Content: ${a}`),console.log()}}catch(n){throw e.stop("Failed to list backups"),n}}async function Xa(t){let e=t.output||B(t.directory,"backups"),n=B(e,t.restore),i=`${n}.tar.gz`,r=$t(i),s=$t(n);if(!r&&!s){l.error(`Backup not found: ${t.restore}`);return}if(!await C({initialValue:!1,message:"This will overwrite existing runner configurations. Continue?"})){l.info("Restore cancelled");return}let a=T();a.start("Restoring backup...");try{let f=n;if(r){a.message("Extracting backup...");let m=B(e,`temp-${Date.now()}`);await qt(m,{recursive:!0}),await Lt`cd ${m} && tar -xzf ${i}`.quiet(),f=B(m,t.restore)}let u=B(f,"metadata.json");if(!$t(u))throw new Error("Invalid backup: metadata.json not found");await Bun.file(u).json();let p=B(f,"runners"),d=B(t.directory,"machines");await qt(d,{recursive:!0});let g=await Wn(p),b=0;for(let m of g){let x=B(p,m),M=B(d,m);if($t(M)){let Q=await K({message:`Runner ${m} already exists. What should we do?`,options:[{label:"Skip",value:"skip"},{label:"Overwrite",value:"overwrite"},{label:"Rename",value:"rename"}]});if(Q==="skip")continue;if(Q==="rename"){let E=await A({message:"Enter new runner name:",placeholder:`${m}-restored`});if(!E)continue;let D=B(d,E);await qt(D,{recursive:!0}),await Lt`cp -r ${x}/* ${D}/`.quiet(),b++;continue}}await qt(M,{recursive:!0}),await Lt`cp -r ${x}/* ${M}/`.quiet(),b++}if(r){let m=f.replace(`/${t.restore}`,"");await Lt`rm -rf ${m}`.quiet()}a.stop("Restore completed"),l.success(`Restored ${b} runner(s) from backup ${t.restore}`)}catch(f){throw a.stop("Restore failed"),f}}function Mn(t){if(t<1024)return`${t}B`;if(t<1048576)return`${(t/1024).toFixed(1)}KB`;if(t<1073741824)return`${(t/1048576).toFixed(1)}MB`;return`${(t/1073741824).toFixed(2)}GB`}Ee();q();O();F();tt();import{parseArgs as Qa}from"util";var Ka=w({prefix:"dev"});async function Va(){let{values:t,positionals:e}=Qa({allowPositionals:!0,args:process.argv.slice(2),options:{force:{default:!1,short:"f",type:"boolean"}},strict:!0}),n=e[1]||"setup";if(!["setup","clean","reset","test"].includes(n))throw new Error(`Unknown dev action: ${n}`);return{action:n,force:t.force}}async function Eo(){let t=await Va();switch(t.action){case"setup":await Po(t);break;case"clean":await Ao();break;case"reset":await Za(t);break;case"test":await za();break}}async function Po(t){l.info("Setting up development environment...");let e=T();e.start("Creating test directories");let n="./test-runners";if(await y.exists(n)){if(!t.force){if(!await C({message:"Test directory already exists. Overwrite?"})){l.info("Setup cancelled");return}}await y.deleteDirectory(n,{recursive:!0})}await y.createDirectory(n,{recursive:!0}),e.stop("Test directories created"),e.start("Creating sample configuration");let i={defaultProfile:"development",profiles:{development:{directory:n,labels:"test,development",numberOfMachines:"2",os:"osx",url:"https://github.com/myorg/myrepo"},staging:{directory:"./staging-runners",labels:"staging",numberOfMachines:"3",os:"linux",url:"https://github.com/myorg/myrepo"}}};await y.writeFile("./hydra.dev.json",JSON.stringify(i,null,2)),e.stop("Sample configuration created"),e.start("Setting up environment variables");let r=`# Hydra Development Environment
|
|
75
|
-
HYDRA_LOG_LEVEL=debug
|
|
76
|
-
HYDRA_DISABLE_PLUGINS=false
|
|
77
|
-
HYDRA_PLUGIN_DIR=./dev-plugins
|
|
78
|
-
|
|
79
|
-
# GitHub tokens (replace with your own)
|
|
80
|
-
# GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
81
|
-
# RUNNER_TOKEN=AXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
82
|
-
`;await y.writeFile(".env.development",r),e.stop("Environment file created"),l.success(`
|
|
83
|
-
Development environment setup complete!`),l.info(`
|
|
84
|
-
Next steps:`),l.info("1. Update .env.development with your GitHub tokens"),l.info("2. Run: hydra create -c hydra.dev.json"),l.info("3. Use: hydra watch status -c hydra.dev.json")}async function Ao(){l.info("Cleaning development artifacts...");let t=["./test-runners","./staging-runners","./hydra.dev.json","./.env.development","./dev-plugins"],e=T();e.start("Cleaning files");for(let n of t)if(await y.exists(n)){if((await y.getFileInfo(n))?.isDirectory)await y.deleteDirectory(n,{recursive:!0});else await y.deleteFile(n);Ka.debug(`Removed: ${n}`)}e.stop("Development files cleaned"),l.success("Cleanup complete!")}async function Za(t){l.info("Resetting development environment..."),await Ao(),await Po({...t,force:!0}),l.success("Development environment reset complete!")}async function za(){l.info("Running development tests...");let t=[{check:async()=>await y.exists("./hydra.dev.json"),name:"Configuration exists"},{check:async()=>await y.exists("./test-runners"),name:"Test directory exists"},{check:async()=>await y.exists("./.env.development"),name:"Environment file exists"},{check:async()=>{return!(await y.readFile("./.env.development")).includes("# GITHUB_TOKEN=")},name:"GitHub token set"}],e=0,n=0;for(let i of t)try{if(await i.check())l.success(`\u2713 ${i.name}`),e++;else l.error(`\u2717 ${i.name}`),n++}catch(r){l.error(`\u2717 ${i.name}: ${r}`),n++}if(l.info(`
|
|
85
|
-
Tests: ${c.success(`${e} passed`)}, ${c.error(`${n} failed`)}`),n>0)l.info(`
|
|
86
|
-
Run 'hydra dev setup' to fix issues`),process.exit(1)}q();O();G();V();import{existsSync as It}from"fs";import{readdir as To}from"fs/promises";import{join as vt,resolve as Ya}from"path";import{parseArgs as Ia}from"util";var{$:Bn}=globalThis.Bun;var Fa=$({prefix:"hydra"}).child("health");async function Da(){let{values:t}=Ia({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},fix:{default:!1,short:"f",type:"boolean"},json:{default:!1,short:"j",type:"boolean"},profile:{short:"p",type:"string"},runner:{short:"r",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile);return{directory:t.directory||n?.directory||`${process.cwd()}/gh-runners`,fix:t.fix,json:t.json,runner:t.runner,token:t.token,url:t.url||n?.url}}async function Oo(){try{let t=await Da(),e=Ya(t.directory),n=vt(e,"machines");if(!It(n)){l.error(`No runners found in ${t.directory}`);return}let i=T();i.start("Performing health checks...");let r=await To(n),s=[];for(let o of r){if(t.runner&&o!==t.runner)continue;let a=vt(n,o),f=await tl(o,a,t);s.push(f)}if(i.stop("Health checks completed"),t.json){console.log(JSON.stringify(s,null,2));return}if(ol(s),t.fix)await rl(s,t)}catch(t){Fa.error("Failed to perform health checks:",t),process.exit(1)}}async function tl(t,e,n){let i=[],r={configuration:!1,connectivity:!1,disk:{percentage:0,total:0,used:0},lastActivity:null,process:!1};try{let o=vt(e,".runner");if(It(o)){let a=await Bun.file(o).text(),f=await el(a.trim());if(r.process=f,!f)i.push("Runner process is not running")}else i.push("No PID file found")}catch{i.push("Could not check process status")}try{let o=await nl(e);if(r.disk=o,o.percentage>90)i.push(`Low disk space: ${o.percentage.toFixed(1)}% used`)}catch{i.push("Could not check disk space")}try{let o=vt(e,"_diag");if(It(o)){let a=await To(o),f=null;for(let u of a)if(u.endsWith(".log")){let p=await Bun.file(vt(o,u)).stat();if(!f||p.mtime>f)f=new Date(p.mtime)}if(r.lastActivity=f,f){let u=(Date.now()-f.getTime())/3600000;if(u>24)i.push(`No activity for ${Math.floor(u)} hours`)}}}catch{i.push("Could not check last activity")}try{let o=vt(e,".runner"),a=vt(e,".credentials");if(r.configuration=It(o)&&It(a),!r.configuration)i.push("Missing configuration files")}catch{i.push("Could not check configuration")}if(n.token&&n.url)try{let o=await il(n.url,n.token);if(r.connectivity=o,!o)i.push("Cannot connect to GitHub API")}catch{i.push("Failed to check GitHub connectivity")}let s="healthy";if(i.length===0)s="healthy";else if(i.some((o)=>o.includes("not running")||o.includes("Missing configuration")||o.includes("Cannot connect")))s="critical";else if(i.length>0)s="warning";return{checks:r,issues:i,runner:t,status:s}}async function el(t){try{return await Bn`kill -0 ${t}`.quiet(),!0}catch{return!1}}async function nl(t){let n=(await Bn`df -k ${t} | tail -1`.text()).trim().split(/\s+/),i=Number.parseInt(n[1]||"0",10)*1024,r=Number.parseInt(n[2]||"0",10)*1024;return{percentage:Number.parseInt(n[4]?.replace("%","")||"0",10),total:i,used:r}}async function il(t,e){return it(async()=>{let n=t.match(/github\.com[:/]([^/]+)(?:\/([^/.]+))?/);if(!n)return!1;let[,i,r]=n,s=r?`https://api.github.com/repos/${i}/${r}`:`https://api.github.com/orgs/${i}`;return(await fetch(s,{headers:{Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${e}`}})).ok},{maxAttempts:3})}function ol(t){console.log(),console.log(c.bold("\uD83C\uDFE5 Runner Health Status")),console.log("\u2500".repeat(80));let e={critical:"\u274C",healthy:"\u2705",unknown:"\u2753",warning:"\u26A0\uFE0F"},n={critical:c.error,healthy:c.success,unknown:c.dim,warning:c.warning};for(let r of t){let s=e[r.status],o=n[r.status];if(console.log(`${s} ${c.bold(`Runner ${r.runner}`)}: ${o(r.status.toUpperCase())}`),console.log(` Process: ${r.checks.process?"\u2705 Running":"\u274C Not running"}`),console.log(` Config: ${r.checks.configuration?"\u2705 Valid":"\u274C Missing"}`),r.checks.disk.total>0){let a=r.checks.disk.percentage>90?c.error:c.success;console.log(` Disk: ${a(`${r.checks.disk.percentage.toFixed(1)}% used`)}`)}if(r.checks.lastActivity){let f=(Date.now()-r.checks.lastActivity.getTime())/3600000>24?c.warning:c.success;console.log(` Last Activity: ${f(sl(r.checks.lastActivity))}`)}if(r.checks.connectivity!==null)console.log(` GitHub API: ${r.checks.connectivity?"\u2705 Connected":"\u274C Disconnected"}`);if(r.issues.length>0){console.log(" Issues:");for(let a of r.issues)console.log(` - ${c.dim(a)}`)}console.log()}let i={critical:t.filter((r)=>r.status==="critical").length,healthy:t.filter((r)=>r.status==="healthy").length,total:t.length,warning:t.filter((r)=>r.status==="warning").length};console.log("\u2500".repeat(80)),console.log(`Summary: Total: ${i.total} | ${c.success(`Healthy: ${i.healthy}`)} | ${c.warning(`Warning: ${i.warning}`)} | ${c.error(`Critical: ${i.critical}`)}`)}async function rl(t,e){let n=t.filter((r)=>r.status==="critical");if(n.length===0){l.info("No critical issues found that require fixing");return}if(console.log(),!await C({initialValue:!1,message:`Found ${n.length} runners with critical issues. Attempt to fix?`}))return;for(let r of n){if(console.log(),l.info(`Attempting to fix runner ${r.runner}...`),!r.checks.process&&r.checks.configuration){l.info("Attempting to restart runner...");try{let s=vt(e.directory,"machines",r.runner);await Bn`cd ${s} && ./run.sh`.quiet(),l.success(`Runner ${r.runner} restarted successfully`)}catch(s){l.error(`Failed to restart runner ${r.runner}`)}}if(!r.checks.configuration)l.warning(`Runner ${r.runner} needs to be reconfigured. Run 'hydra create' to set up again.`)}}function sl(t){let n=new Date().getTime()-t.getTime(),i=Math.floor(n/3600000);if(i<1)return`${Math.floor(n/60000)}m ago`;if(i<24)return`${i}h ago`;return`${Math.floor(i/24)}d ago`}q();O();G();V();import{existsSync as Ho}from"fs";import{readdir as Co}from"fs/promises";import{join as Oe,resolve as al}from"path";import{parseArgs as ll}from"util";var fl=$({prefix:"hydra"}).child("logs");async function ul(){let{values:t}=ll({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},list:{default:!1,short:"l",type:"boolean"},profile:{short:"p",type:"string"},runner:{short:"r",type:"string"},type:{short:"t",type:"string"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile);return{directory:t.directory||n?.directory||`${process.cwd()}/gh-runners`,list:t.list,runner:t.runner,type:t.type}}async function _o(){try{let t=await ul(),e=al(t.directory),n=Oe(e,"machines");if(!Ho(n)){l.error(`No runners found in ${t.directory}`);return}let i=T();i.start("Scanning for runner logs...");let r=await Co(n),s=[];for(let a of r){let f=Oe(n,a),u=Oe(f,"_diag");if(Ho(u)){let p=await cl(u);if(p.length>0)s.push({logs:p,runner:a})}}if(i.stop("Found runner logs"),s.length===0){l.info("No log files found");return}if(t.list){pl(s);return}if(t.runner&&t.type){await dl(s,t.runner,t.type);return}let o=await hl(s);if(o)await No(o)}catch(t){fl.error("Failed to retrieve logs:",t),process.exit(1)}}async function cl(t){let e=await Co(t),n=[];for(let i of e)if(i.endsWith(".log")){let r=Oe(t,i),s=await Bun.file(r).stat();n.push({modified:new Date(s.mtime),name:i,path:r,size:s.size})}return n.sort((i,r)=>r.modified.getTime()-i.modified.getTime())}function pl(t){console.log(c.bold(`
|
|
87
|
-
\uD83D\uDCCB Available Logs
|
|
88
|
-
`));for(let{runner:e,logs:n}of t){console.log(`${c.bold(`Runner ${e}:`)}`);for(let i of n){let r=Un(i.size),s=qn(i.modified),o=He(i.name);console.log(` ${c.value(o.padEnd(20))} ${c.dim(r.padEnd(10))} ${c.dim(s)}`)}console.log()}}async function hl(t){let e=[];for(let{runner:i,logs:r}of t)for(let s of r)e.push({hint:`${Un(s.size)} - ${qn(s.modified)}`,label:`Runner ${i} - ${He(s.name)}`,value:s});return await K({message:"Select a log file to view",options:e})}async function dl(t,e,n){let i=t.find(({runner:s})=>s===e);if(!i){l.error(`Runner ${e} not found`);return}let r=i.logs.find((s)=>He(s.name).toLowerCase().includes(n.toLowerCase()));if(!r){l.error(`Log type '${n}' not found for runner ${e}`);return}await No(r)}async function No(t){console.log(),console.log(c.bold(`\uD83D\uDCC4 ${He(t.name)}`)),console.log(c.dim(`Size: ${Un(t.size)} | Modified: ${qn(t.modified)}`)),console.log(c.dim("\u2500".repeat(80))),console.log();let e=await Bun.file(t.path).text(),n=e.split(`
|
|
89
|
-
`);if(n.length>100){let i=n.slice(-100);console.log(c.dim(`... (showing last 100 lines of ${n.length} total)
|
|
90
|
-
`)),console.log(i.join(`
|
|
91
|
-
`))}else console.log(e)}function He(t){if(t.includes("Runner_"))return"Runner Log";if(t.includes("Worker_"))return"Worker Log";if(t.includes("Actions"))return"Actions Log";if(t.includes("Listener"))return"Listener Log";return t.replace(".log","")}function Un(t){if(t<1024)return`${t}B`;if(t<1048576)return`${(t/1024).toFixed(1)}KB`;return`${(t/1048576).toFixed(1)}MB`}function qn(t){let n=new Date().getTime()-t.getTime(),i=Math.floor(n/3600000);if(i<1)return`${Math.floor(n/60000)}m ago`;if(i<24)return`${i}h ago`;let r=Math.floor(i/24);if(r<7)return`${r}d ago`;return t.toLocaleDateString()}q();O();import{parseArgs as gl}from"util";var{$:So,Glob:ml}=globalThis.Bun;async function yl(){let{values:t}=gl({args:process.argv.slice(2),options:{all:{default:!1,short:"a",type:"boolean"},backup:{default:!0,short:"b",type:"boolean"},dryRun:{default:!1,short:"d",type:"boolean"},format:{short:"f",type:"string"},path:{short:"p",type:"string"}},strict:!0});return{all:t.all,backup:t.backup,dryRun:t.dryRun,format:t.format,path:t.path}}async function Mo(){let t=await yl();if(!t.path&&!t.all)t.path=await A({message:"Path to configuration file:",placeholder:"./hydra.json",validate:(i)=>{if(!i)return"Path is required";return}});let e=await bl(t);if(e.length===0){l.error("No configuration files found");return}l.info(`Found ${e.length} configuration file(s) to migrate`);let n=[];for(let i of e){let r=await wl(i,t);n.push(r)}vl(n,t)}async function bl(t){if(t.path){if(!await Bun.file(t.path).exists())throw new Error(`Configuration file not found: ${t.path}`);return[t.path]}if(t.all){let e=new ml("**/hydra.{json,toml}"),n=[];for await(let i of e.scan("."))if(!i.includes("node_modules")&&!i.includes(".git"))n.push(i);return n}return[]}async function wl(t,e){let n=T();n.start(`Migrating ${t}...`);try{let i=await Bun.file(t).text(),r=t.endsWith(".toml")?"toml":"json",s=e.format||r,o,a=[];if(r==="toml"){let u=`.temp-${Date.now()}.toml`;await Bun.write(u,i),o=(await import(u)).default,await So`rm ${u}`.quiet()}else o=JSON.parse(i);let f=await xl(o,a);if(e.backup&&!e.dryRun){let u=`${t}.backup-${new Date().toISOString().replace(/:/g,"-")}`;await Bun.write(u,i),a.push(`Created backup at ${u}`)}if(!e.dryRun){let u=s!==r?t.replace(/\.(json|toml)$/,`.${s}`):t;if(s==="toml")await $l(u,f);else await Bun.write(u,JSON.stringify(f,null,2));if(u!==t){if(await C({initialValue:!0,message:`Remove original file ${t}?`}))await So`rm ${t}`.quiet(),a.push(`Removed original file ${t}`)}a.push(`Migrated to ${u}`)}return n.stop(`Migrated ${t}`),{changes:a,path:t,success:!0}}catch(i){return n.stop(`Failed to migrate ${t}`),{error:i.message,path:t,success:!1}}}async function xl(t,e){let n={profiles:{}};if(t.defaultProfile)n.defaultProfile=t.defaultProfile;if(t.url||t.numberOfMachines||t.directory||t.labels){let i={};if(t.directory)i.directory=t.directory;if(t.labels)i.labels=t.labels;if(t.name)i.name=t.name;if(t.numberOfMachines)i.numberOfMachines=t.numberOfMachines;if(t.os)i.os=t.os;if(t.runnerGroup)i.runnerGroup=t.runnerGroup;if(t.url)i.url=t.url;if(t.overwrite!==void 0)i.overwrite=t.overwrite;if(t.run!==void 0)i.run=t.run;n.profiles.default=i,e.push("Migrated root-level settings to default profile"),delete t.url,delete t.numberOfMachines,delete t.directory,delete t.labels,delete t.name,delete t.os,delete t.runnerGroup,delete t.overwrite,delete t.run}if(t.profiles)for(let[i,r]of Object.entries(t.profiles)){let s=typeof r==="object"&&r!==null?{...r}:{};if(typeof r==="object"&&r!==null){if("runnerCount"in r&&!("numberOfMachines"in r))s.numberOfMachines=r.runnerCount,delete s.runnerCount,e.push(`Renamed 'runnerCount' to 'numberOfMachines' in profile '${i}'`);if("workDir"in r&&!("directory"in r))s.directory=r.workDir,delete s.workDir,e.push(`Renamed 'workDir' to 'directory' in profile '${i}'`);if(typeof r.labels==="string")s.labels=r.labels.split(",").map((o)=>o.trim()),e.push(`Converted labels to array format in profile '${i}'`)}n.profiles[i]=s}for(let[i,r]of Object.entries(t))if(!["profiles","defaultProfile"].includes(i))n[i]=r,e.push(`Preserved unknown property '${i}'`);return n}async function $l(t,e){let n="";if(e.defaultProfile)n+=`defaultProfile = "${e.defaultProfile}"
|
|
83
|
+
`};async function qt(r){try{let n=`${r}/hooks`;await Bun.$`mkdir -p ${n}`.quiet(),await Bun.write(`${n}/pre.sh`,$n.preHook),await Bun.$`chmod +x ${n}/pre.sh`.quiet(),await Bun.write(`${n}/post.sh`,$n.postHook),await Bun.$`chmod +x ${n}/post.sh`.quiet(),await Bun.write(`${r}/.runner-env`,$n.runnerEnv),Lt.debug(`Created runner hooks and environment for ${r}`)}catch(n){throw Lt.error("Failed to create runner files:",n),n}}function To(r){if(!r||typeof r!=="object")return!1;let n=r;if(typeof n.name!=="string"||n.name.trim().length===0)return!1;if(n.description!==void 0&&typeof n.description!=="string")return!1;if(n.extends!==void 0&&typeof n.extends!=="string")return!1;if(n.metadata!==void 0){if(typeof n.metadata!=="object"||n.metadata===null)return!1;let t=n.metadata;if(t.author!==void 0&&typeof t.author!=="string"||t.created!==void 0&&typeof t.created!=="string"||t.updated!==void 0&&typeof t.updated!=="string"||t.tags!==void 0&&(!Array.isArray(t.tags)||!t.tags.every((o)=>typeof o==="string")))return!1}return!0}function No(r){if(!r||typeof r!=="object")return!1;let n=r;if(!n.templates||typeof n.templates!=="object"||n.templates===null)return!1;let t=n.templates;for(let[o,e]of Object.entries(t))if(typeof o!=="string"||!To(e))return!1;if(n.version!==void 0&&typeof n.version!=="string")return!1;return!0}function _n(r){if(!No(r))throw new Error("Invalid template store: must contain a valid templates object")}G();P();var nf=k({prefix:"worker-validator"});class Bt{validateWorkerData(r){let n={errors:[],valid:!0,warnings:[]};if(!Ht(r))return n.valid=!1,n.errors.push({code:"INVALID_WORKER_DATA",field:"data",message:"Invalid worker data format"}),n;let t=r;if(this.validateUrl(t.url,n),this.validateToken(t.token,n),t.index<0)n.valid=!1,n.errors.push({code:"INVALID_INDEX",field:"index",message:"Worker index must be non-negative"});return n}validateWorkerMessage(r){let n={errors:[],valid:!0,warnings:[]};if(!qr(r))return n.valid=!1,n.errors.push({code:"INVALID_WORKER_MESSAGE",field:"message",message:"Invalid worker message format"}),n;if(!Object.values(xr).includes(r.type))n.valid=!1,n.errors.push({code:"INVALID_MESSAGE_TYPE",field:"type",message:`Invalid message type: ${r.type}`});return n}validateGitHubRelease(r){let n={errors:[],valid:!0,warnings:[]};if(!r||typeof r!=="object")return n.valid=!1,n.errors.push({code:"INVALID_GITHUB_RELEASE",field:"release",message:"GitHub release must be an object"}),n;let t=r;if(this.validateRequiredString(t.tag_name,"tag_name",n),this.validateRequiredString(t.html_url,"html_url",n),this.validateRequiredNumber(t.id,"id",n),t.draft!==void 0&&typeof t.draft!=="boolean")n.valid=!1,n.errors.push({code:"INVALID_TYPE",field:"draft",message:"Draft field must be a boolean"});if(t.prerelease!==void 0&&typeof t.prerelease!=="boolean")n.valid=!1,n.errors.push({code:"INVALID_TYPE",field:"prerelease",message:"Prerelease field must be a boolean"});if(t.prerelease===!0)n.warnings.push({code:"PRERELEASE_VERSION",field:"prerelease",message:"This is a prerelease version which may be unstable"});if(t.assets&&Array.isArray(t.assets))for(let[o,e]of t.assets.entries())this.validateGitHubReleaseAsset(e,`assets[${o}]`,n);return n}validateRequiredString(r,n,t){if(!r||typeof r!=="string")t.valid=!1,t.errors.push({code:"MISSING_REQUIRED_FIELD",field:n,message:`${n} is required and must be a string`});else if(r.trim().length===0)t.valid=!1,t.errors.push({code:"EMPTY_REQUIRED_FIELD",field:n,message:`${n} cannot be empty`})}validateRequiredNumber(r,n,t){if(typeof r!=="number")t.valid=!1,t.errors.push({code:"MISSING_REQUIRED_FIELD",field:n,message:`${n} is required and must be a number`});else if(!Number.isInteger(r))t.valid=!1,t.errors.push({code:"INVALID_NUMBER",field:n,message:`${n} must be an integer`});else if(r<0)t.valid=!1,t.errors.push({code:"NEGATIVE_NUMBER",field:n,message:`${n} must be a non-negative number`})}validateGitHubReleaseAsset(r,n,t){if(!r||typeof r!=="object"){t.valid=!1,t.errors.push({code:"INVALID_RELEASE_ASSET",field:n,message:"Release asset must be an object"});return}let o=r;if(!o.name||typeof o.name!=="string")t.valid=!1,t.errors.push({code:"MISSING_ASSET_NAME",field:`${n}.name`,message:"Asset name is required"});if(!o.browser_download_url||typeof o.browser_download_url!=="string")t.valid=!1,t.errors.push({code:"MISSING_DOWNLOAD_URL",field:`${n}.browser_download_url`,message:"Asset download URL is required"})}validateUrl(r,n){try{let t=new URL(r);if(!t.hostname.includes("github.com")&&!t.hostname.includes("github"))n.warnings.push({code:"NON_GITHUB_URL",field:"url",message:"URL does not appear to be a GitHub URL"})}catch{n.valid=!1,n.errors.push({code:"INVALID_URL",field:"url",message:"Invalid URL format"})}}validateToken(r,n){if(r.length<10)n.warnings.push({code:"SHORT_TOKEN",field:"token",message:"Token appears to be too short"});if(r.includes(" "))n.valid=!1,n.errors.push({code:"INVALID_TOKEN_FORMAT",field:"token",message:"Token cannot contain spaces"})}}function Ao(){return new Bt}function jt(r){return Ao().validateGitHubRelease(r)}async function Kt(r,n={}){let{maxAttempts:t=5,baseDelay:o=1000,onRetry:e}=n;for(let s=1;s<=t;s++)try{return await r()}catch(i){if(s===t)throw i;let a=Math.min(o*2**(s-1),16000),f=Math.random()*0.1*a,d=a+f;if(e)e(s,i instanceof Error?i:new Error(String(i)));await new Promise((c)=>setTimeout(c,d))}throw new Error("Retry logic should not reach here")}async function zt(){let r=x({prefix:"createMachines"}),n=await Go(),{overwrite:t,directory:o,numberOfMachines:e,os:s,run:i,name:a,labels:f,runnerGroup:d}=n,{token:c,url:u}=n;if(!u)throw w.createError("URL (-u) parameter is required","VALIDATION_ERROR",void 0,{operation:"create_machines",parameter:"url"});if(!c){let R=Wo(u),h=await S({message:`No token provided. Would you like to open GitHub to get a runner token?
|
|
84
|
+
${R}`});if(H(h)||!h)throw w.createError("Token is required to create runners","AUTHENTICATION_ERROR",void 0,{operation:"create_machines",parameter:"token"});r.info("Opening GitHub runner settings..."),await Zt`open ${R}`.quiet();let g=await T({message:"Enter the runner registration token:",placeholder:"AXXXXXXXXXXXXXXXXXXXXXXXXX",validate:(N)=>{if(!N||N.trim().length===0)return"Token is required";return}});if(H(g))throw w.createError("Token is required to create runners","AUTHENTICATION_ERROR",void 0,{operation:"create_machines",parameter:"token"});c=g.trim()}if(r=x({prefix:"createMachines",secrets:[c]}),r.info(`Creating ${e} runners in ${o}`),r.debug(`OS: ${s}, Name: ${a}, Labels: ${f||"none"}`),await b.exists(o))if(t)r.warn(`Directory ${o} exists, removing...`),await b.deleteDirectory(o,{recursive:!0});else throw w.createError(`Directory ${o} already exists`,"FILE_SYSTEM_ERROR",void 0,{directory:o,operation:"create_machines"});let l=await Uo({directory:o,os:s});if(await Po({directory:o,numberOfMachines:e,overwrite:t,runnerBase:l}),!i){r.info("Runners created but not started");return}await Lo({directory:o,labels:f,name:a,numberOfMachines:e,runnerGroup:d,token:c,url:u})}function Wo(r){try{let n=new URL(r),t=n.pathname.split("/").filter(Boolean);if(n.hostname==="github.com"||n.hostname==="www.github.com"){if(t[0]==="orgs"&&t[1])return`https://github.com/organizations/${t[1]}/settings/actions/runners/new`;if(t.length>=2)return`https://github.com/${t[0]}/${t[1]}/settings/actions/runners/new`}else{if(t[0]==="orgs"&&t[1])return`${n.origin}/organizations/${t[1]}/settings/actions/runners/new`;if(t.length>=2)return`${n.origin}/${t[0]}/${t[1]}/settings/actions/runners/new`}return r}catch{return r}}async function Go(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:a}=await Promise.resolve().then(() => (j(),Z));a("create"),process.exit(0)}let{values:n}=Co({args:r,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},labels:{short:"l",type:"string"},name:{default:"runner",short:"n",type:"string"},numberOfMachines:{default:"1",short:"m",type:"string"},os:{default:"osx",short:"s",type:"string"},overwrite:{default:!1,short:"f",type:"boolean"},profile:{short:"p",type:"string"},run:{default:!1,short:"r",type:"boolean"},runnerGroup:{short:"g",type:"string"},template:{short:"T",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),t=await q({configPath:n.config}),o=await B(t,n.profile),e;if(n.template)e=await qo(n.template);let s={directory:n.directory,labels:n.labels,name:n.name,numberOfMachines:n.numberOfMachines,os:n.os,overwrite:n.overwrite,run:n.run,runnerGroup:n.runnerGroup,token:n.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:n.url},i=o||e?{directory:s.directory??o?.directory??e?.directory??`${process.cwd()}/gh-runners`,labels:s.labels??o?.labels??e?.labels,name:s.name??o?.name??e?.name??"runner",numberOfMachines:s.numberOfMachines??String(o?.numberOfMachines??e?.numberOfMachines)??"1",os:s.os??o?.os??e?.os??"osx",overwrite:s.overwrite??o?.overwrite??e?.overwrite??!1,run:s.run??o?.run??e?.run??!1,runnerGroup:s.runnerGroup??o?.runnerGroup??e?.runnerGroup,token:s.token||o?.token,url:s.url??o?.url??e?.url}:null;if(i)return i;return{directory:s.directory,labels:s.labels,name:s.name,numberOfMachines:s.numberOfMachines,os:s.os,overwrite:s.overwrite,run:s.run,runnerGroup:s.runnerGroup,token:s.token,url:s.url}}async function Mo(r){let n=x({prefix:"github-release-validator",secrets:[]});try{let t=await fetch(r);if(!t.ok)throw w.createError(`GitHub API request failed: ${t.status} ${t.statusText}`,"GITHUB_API_ERROR",void 0,{operation:"validate_github_release",status:t.status});let o=await t.json(),e=jt(o);if(!e.valid){n.error("GitHub release validation failed:");for(let s of e.errors)n.error(` ${s.field}: ${s.message}`);throw w.createError("Invalid GitHub release response format","GITHUB_API_ERROR",void 0,{operation:"validate_github_release"})}if(e.warnings.length>0){n.warn("GitHub release validation warnings:");for(let s of e.warnings)n.warn(` ${s.field}: ${s.message}`)}n.debug("GitHub release validation passed")}catch(t){if(t instanceof Error)throw t;throw new Error(`GitHub release validation error: ${String(t)}`)}}async function Uo({directory:r,os:n}){let t=x({prefix:"createMachines:download",secrets:[]});t.info(`Fetching latest runner version for ${n}...`);let o=await Kt(async()=>{let f=await fetch("https://github.com/actions/runner/releases/latest",{method:"GET",redirect:"manual"});if(f.status>=300&&f.status<400){let d=f.headers.get("location");if(d)return d}throw new Error(`Failed to get redirect URL: ${f.status}`)},{onRetry:(f,d)=>{t.warn(`Retrying GitHub API call (attempt ${f}): ${d.message}`)}});if(!o||typeof o!=="string")throw w.createError("Invalid release info received from GitHub","GITHUB_API_ERROR",void 0,{operation:"get_latest_github_runner_release"});if(!o.includes("github.com/actions/runner/releases/tag/"))throw new Error(`Invalid GitHub release URL format: ${o}`);let e=o.split("/").pop()||"";if(!e)throw new Error("Could not extract release tag from GitHub URL");let s=e.trim().replace("v","");if(!s||s.length===0)throw new Error("Invalid version extracted from release tag");if(process.env.HYDRA_VALIDATE_GITHUB_RELEASES==="true"){t.debug("Performing additional GitHub release validation...");let f=`https://api.github.com/repos/actions/runner/releases/tags/${e}`;try{await Mo(f)}catch(d){t.warn(`GitHub release validation failed (non-critical): ${d instanceof Error?d.message:String(d)}`)}}let i=`actions-runner-${n}-x64-${s}.tar.gz`,a=`https://github.com/actions/runner/releases/download/v${s}/${i}`;if(t.debug(`Runner version: ${s}`),t.debug(`Download URL: ${a}`),await En(r),await En(`${r}/machines`),!await b.exists(`${r}/${i}`))t.info("Downloading runner image..."),await Kt(async()=>{let f=await fetch(a);if(!f.ok)throw new Error(`Download failed: ${f.status} ${f.statusText}`);if(!f.body)throw new Error("No response body");let d=f.body.getReader(),c=[];try{while(!0){let{done:h,value:g}=await d.read();if(h)break;c.push(g)}}finally{d.releaseLock()}let u=c.reduce((h,g)=>h+g.length,0),l=new Uint8Array(u),R=0;for(let h of c)l.set(h,R),R+=h.length;await Bun.write(`${r}/${i}`,l)},{maxAttempts:5,onRetry:(f,d)=>{t.warn(`Retrying runner download (attempt ${f}): ${d.message}`)}}),t.info("Download complete");else t.info("Runner image already exists, skipping download");return i}async function Po({overwrite:r,numberOfMachines:n,directory:t,runnerBase:o}){let e=x({prefix:"createMachines:extract",secrets:[]}),s=Number(n),i=(()=>{try{let c=Bun.spawnSync(["nproc"]);return Number.parseInt(c.stdout.toString().trim(),10)||4}catch{try{let c=Bun.spawnSync(["sysctl","-n","hw.ncpu"]);return Number.parseInt(c.stdout.toString().trim(),10)||4}catch{return 4}}})(),a=Math.min(Math.max(2,Math.floor(i/2)),s,8);e.info(`Extracting ${s} runners with concurrency of ${a}`);let f=Array.from({length:s},(c,u)=>u+1).map((c)=>({execute:async()=>{let u=`${t}/machines/${c}`;if(await b.exists(u))if(r)e.debug(`Machine ${c} already exists, removing...`),await b.deleteDirectory(u,{recursive:!0});else{e.debug(`Machine ${c} already exists, skipping...`);return}await b.createDirectory(u),await Zt`tar xzf ${o} -C ${u.replace(`${t}/`,"")}`.cwd(t),await qt(u),e.debug(`Machine ${c} extracted successfully`)},runnerIndex:c})),d=[];for(let c=0;c<f.length;c+=a){let u=f.slice(c,c+a),l=Math.floor(c/a)+1,R=Math.ceil(f.length/a);e.info(`Processing batch ${l}/${R} (${u.length} runners)`);let h=await Promise.allSettled(u.map((g)=>g.execute()));for(let g=0;g<h.length;g++){let N=h[g];if(N&&N.status==="rejected")throw e.error(`Failed to extract runner ${u[g]?.runnerIndex}: ${N.reason}`),N.reason}d.push(...h),e.info(`Batch ${l}/${R} completed successfully`)}e.info(`Successfully extracted ${s} runners`)}async function Lo({directory:r,numberOfMachines:n,token:t,url:o,name:e,labels:s,runnerGroup:i}){let a=x({prefix:"createMachines:start",secrets:[t]});a.info(`Starting ${n} runners concurrently...`);let f=new er({maxRestarts:3,maxWorkers:Number(n),restartDelay:5000,restartOnError:!0}),d=Array.from({length:Number(n)},(h,g)=>{let N=g+1,ar=`${Ur()}/src/runner-worker.ts`,fr=`${e}-${N}`,Or=`runner-${N}`;return{data:{index:N,labels:s,machineCwd:`${r}/machines/${N}`,name:e,runnerGroup:i,token:t,url:o},id:Or,name:fr,onError:(O)=>{a.error(`Worker ${fr} error:`,O)},onExit:(O)=>{a.info(`Worker ${fr} exited with code ${O}`)},onMessage:(O)=>{let W=O.type==="error"?"error":"info";a[W](`${fr}: ${O.message}`)},scriptPath:ar}}),c=d.map(async(h)=>{try{return await f.createWorker(h),{success:!0,workerId:h.id,workerName:h.name}}catch(g){return a.error(`Failed to start worker ${h.name}:`,g),{error:g,success:!1,workerId:h.id,workerName:h.name}}}),u=await Promise.allSettled(c),l=0,R=0;if(u.forEach((h,g)=>{if(h.status==="fulfilled")if(h.value.success)l++,a.debug(`Worker ${h.value.workerName} started successfully`);else R++,a.error(`Worker ${h.value.workerName} failed to start: ${h.value.error}`);else{R++;let N=d[g];a.error(`Unexpected error starting worker ${N?.name}:`,h.reason)}}),R>0)a.warn(`${l} workers started successfully, ${R} failed`),a.info("Failed workers will be reported but won't stop other workers");else a.info(`All ${l} workers started successfully`);a.info("Press Ctrl+C to stop all machines")}async function qo(r){let n=x({prefix:"loadTemplate"}),t="./hydra-templates.json",o=Bun.file("./hydra-templates.json");if(await o.exists())try{let i=await o.json();if(_n(i),i.templates?.[r])return n.info(`Using local template: ${r}`),On(i.templates[r],i.templates)}catch(i){n.warn(`Failed to load local templates: ${i}`)}let e=So(Ho(),".hydra","templates.json"),s=Bun.file(e);if(await s.exists())try{let i=await s.json();if(_n(i),i.templates?.[r])return n.info(`Using global template: ${r}`),On(i.templates[r],i.templates)}catch(i){n.warn(`Failed to load global templates: ${i}`)}n.warn(`Template '${r}' not found`);return}function On(r,n,t=new Set){if(r.name&&t.has(r.name))throw w.createError(`Circular template dependency detected: ${r.name}`,"TEMPLATE_ERROR",void 0,{operation:"resolve_template_inheritance",templateName:r.name});if(r.name)t.add(r.name);let o={};if(r.extends&&n[r.extends]){let d=n[r.extends];if(d)o=On(d,n,t)}let{name:e,description:s,extends:i,metadata:a,...f}=r;return{...o,...f}}L();G();P();import{existsSync as $r}from"fs";import{readdir as Jt}from"fs/promises";import{join as D,resolve as Bo}from"path";import{parseArgs as jo}from"util";var{$:vn}=globalThis.Bun;var Vo=k({prefix:"hydra"}).child("health");async function Ko(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:e}=await Promise.resolve().then(() => (j(),Z));e("health"),process.exit(0)}let{values:n}=jo({args:r,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},fix:{default:!1,short:"f",type:"boolean"},json:{default:!1,short:"j",type:"boolean"},profile:{short:"p",type:"string"},runner:{short:"r",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),t=await q({configPath:n.config}),o=await B(t,n.profile);return{directory:n.directory||o?.directory||`${process.cwd()}/gh-runners`,fix:n.fix,json:n.json,runner:n.runner,token:n.token,url:n.url||o?.url}}async function Yt(){try{let r=await Ko(),n=Bo(r.directory),t=D(n,"machines");if(!$r(t)){m.error(`No runners found in ${r.directory}`);return}let o=Q();o.start("Performing health checks...");let e=await Jt(t),s=[];for(let i of e){if(r.runner&&i!==r.runner)continue;let a=D(t,i),f=await Zo(i,a,r);s.push(f)}if(o.stop("Health checks completed"),r.json){console.log(JSON.stringify(s,null,2));return}if(Xo(s),r.fix)await Qo(s,r)}catch(r){Vo.error("Failed to perform health checks:",r),process.exit(1)}}async function Zo(r,n,t){let o=[],e={configuration:!1,connectivity:!1,disk:{percentage:0,total:0,used:0},lastActivity:null,process:!1};try{let i=D(n,".runner");if($r(i)){let a=await Bun.file(i).text(),f=await zo(a.trim());if(e.process=f,!f)o.push("Runner process is not running")}else o.push("No PID file found")}catch{o.push("Could not check process status")}try{let i=await Jo(n);if(e.disk=i,i.percentage>90)o.push(`Low disk space: ${i.percentage.toFixed(1)}% used`)}catch{o.push("Could not check disk space")}try{let i=D(n,"_diag");if($r(i)){let a=await Jt(i),f=null;for(let d of a)if(d.endsWith(".log")){let c=await Bun.file(D(i,d)).stat();if(!f||c.mtime>f)f=new Date(c.mtime)}if(e.lastActivity=f,f){let d=(Date.now()-f.getTime())/3600000;if(d>24)o.push(`No activity for ${Math.floor(d)} hours`)}}}catch{o.push("Could not check last activity")}try{let i=D(n,".runner"),a=D(n,".credentials");if(e.configuration=$r(i)&&$r(a),!e.configuration)o.push("Missing configuration files")}catch{o.push("Could not check configuration")}if(t.token&&t.url)try{let i=await Yo(t.url,t.token);if(e.connectivity=i,!i)o.push("Cannot connect to GitHub API")}catch{o.push("Failed to check GitHub connectivity")}let s="healthy";if(o.length===0)s="healthy";else if(o.some((i)=>i.includes("not running")||i.includes("Missing configuration")||i.includes("Cannot connect")))s="critical";else if(o.length>0)s="warning";return{checks:e,issues:o,runner:r,status:s}}async function zo(r){try{return await vn`kill -0 ${r}`.quiet(),!0}catch{return!1}}async function Jo(r){let t=(await vn`df -k ${r} | tail -1`.text()).trim().split(/\s+/),o=Number.parseInt(t[1]||"0",10)*1024,e=Number.parseInt(t[2]||"0",10)*1024;return{percentage:Number.parseInt(t[4]?.replace("%","")||"0",10),total:o,used:e}}async function Yo(r,n){return Cr(async()=>{let t=r.match(/github\.com[:/]([^/]+)(?:\/([^/.]+))?/);if(!t)return!1;let[,o,e]=t,s=e?`https://api.github.com/repos/${o}/${e}`:`https://api.github.com/orgs/${o}`;return(await fetch(s,{headers:{Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${n}`}})).ok},{maxAttempts:3})}function Xo(r){console.log(),console.log(y.bold("\uD83C\uDFE5 Runner Health Status")),console.log("\u2500".repeat(80));let n={critical:"\u274C",healthy:"\u2705",unknown:"\u2753",warning:"\u26A0\uFE0F"},t={critical:y.error,healthy:y.success,unknown:y.dim,warning:y.warning};for(let e of r){let s=n[e.status],i=t[e.status];if(console.log(`${s} ${y.bold(`Runner ${e.runner}`)}: ${i(e.status.toUpperCase())}`),console.log(` Process: ${e.checks.process?"\u2705 Running":"\u274C Not running"}`),console.log(` Config: ${e.checks.configuration?"\u2705 Valid":"\u274C Missing"}`),e.checks.disk.total>0){let a=e.checks.disk.percentage>90?y.error:y.success;console.log(` Disk: ${a(`${e.checks.disk.percentage.toFixed(1)}% used`)}`)}if(e.checks.lastActivity){let f=(Date.now()-e.checks.lastActivity.getTime())/3600000>24?y.warning:y.success;console.log(` Last Activity: ${f(Fo(e.checks.lastActivity))}`)}if(e.checks.connectivity!==null)console.log(` GitHub API: ${e.checks.connectivity?"\u2705 Connected":"\u274C Disconnected"}`);if(e.issues.length>0){console.log(" Issues:");for(let a of e.issues)console.log(` - ${y.dim(a)}`)}console.log()}let o={critical:r.filter((e)=>e.status==="critical").length,healthy:r.filter((e)=>e.status==="healthy").length,total:r.length,warning:r.filter((e)=>e.status==="warning").length};console.log("\u2500".repeat(80)),console.log(`Summary: Total: ${o.total} | ${y.success(`Healthy: ${o.healthy}`)} | ${y.warning(`Warning: ${o.warning}`)} | ${y.error(`Critical: ${o.critical}`)}`)}async function Qo(r,n){let t=r.filter((e)=>e.status==="critical");if(t.length===0){m.info("No critical issues found that require fixing");return}if(console.log(),!await S({initialValue:!1,message:`Found ${t.length} runners with critical issues. Attempt to fix?`}))return;for(let e of t){if(console.log(),m.info(`Attempting to fix runner ${e.runner}...`),!e.checks.process&&e.checks.configuration){m.info("Attempting to restart runner...");try{let s=D(n.directory,"machines",e.runner);await vn`cd ${s} && ./run.sh`.quiet(),m.success(`Runner ${e.runner} restarted successfully`)}catch(s){m.error(`Failed to restart runner ${e.runner}`)}}if(!e.checks.configuration)m.warning(`Runner ${e.runner} needs to be reconfigured. Run 'hydra create' to set up again.`)}}function Fo(r){let t=new Date().getTime()-r.getTime(),o=Math.floor(t/3600000);if(o<1)return`${Math.floor(t/60000)}m ago`;if(o<24)return`${o}h ago`;return`${Math.floor(o/24)}d ago`}j();L();G();P();import{resolve as Do}from"path";import{parseArgs as re}from"util";var{$:Tn}=globalThis.Bun;var sr=k({prefix:"hydra"}).child("init");async function Xt(){let{toml:r}=await te(),n=r?"hydra.toml":"hydra.json",t=Do(process.cwd(),n);if(await Bun.file(t).exists()){let u=await S({initialValue:!1,message:`Configuration file ${n} already exists. Overwrite?`});if(H(u)||!u)Rn("Configuration cancelled"),process.exit(0)}et(E.cyan("\uD83D\uDE80 Hydra Configuration Setup")),sr.info("This will create a configuration file with your runner settings."),sr.info("You can always edit the file later or create additional profiles.");let e=await at({profileName:()=>T({message:"Profile name?",placeholder:"default"}),directory:()=>T({defaultValue:"./gh-runners",message:"Directory to store runners?",placeholder:"./gh-runners"}),name:()=>T({defaultValue:"runner",message:"Runner name prefix?",placeholder:"runner"}),labels:({results:u})=>{let l=u.name||"runner";return T({defaultValue:l,message:"Runner labels (comma-separated)?",placeholder:l})},numberOfMachines:()=>T({defaultValue:"1",message:"Number of runner machines?",placeholder:"1",validate:(u)=>{let l=Number.parseInt(u,10);if(Number.isNaN(l)||l<1)return"Please enter a valid number greater than 0";return}}),url:()=>T({message:"GitHub repository or organization URL? (optional)",placeholder:"https://github.com/org/repo"})},{onCancel:()=>{Rn("Configuration cancelled"),process.exit(0)}}),{profileName:s,labels:i,numberOfMachines:a,...f}=e,d={defaultProfile:s,profiles:{[s]:{...f,labels:i,numberOfMachines:Number.parseInt(a,10),os:"osx",overwrite:!1,run:!1}}},c=JSON.stringify(d,null,2);if(await Bun.write(t,c),await mr(async()=>{await Tn`chmod 600 ${t}`.quiet()},{logLevel:"warn",message:"Could not set secure file permissions"}),st(E.green(`\u2713 Configuration saved to ${n}`)),sr.info("Example usage:"),sr.info(` hydra create -p ${s} --token YOUR_TOKEN${e.url?"":" --url REPO_URL"}`),sr.info("You can add more profiles by editing the configuration file."),e.url)await ne(e.url)}async function ne(r){let n=/github\.com[:/]([^/]+)(?:\/([^/.]+))?/,t=r.match(n);if(!t)return;let[,o,e]=t,i=`https://github.com/${e?`${o}/${e}`:`organizations/${o}`}/settings/actions/runners`;sr.info(`Opening GitHub settings: ${i}`),await mr(async()=>{await Tn`open ${i}`.quiet()},{fallback:async()=>{await mr(async()=>{await Tn`xdg-open ${i}`.quiet()},{fallback:()=>{sr.info("Please open the URL manually to add a new runner token.")},logLevel:"info",message:"Alternative browser open method also failed"})},logLevel:"info",message:"Could not open browser automatically"})}async function te(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:t}=await Promise.resolve().then(() => (j(),Z));t("init"),process.exit(0)}let{values:n}=re({args:r,options:{toml:{default:!1,short:"t",type:"boolean"}},strict:!0});return n}L();G();import{parseArgs as ie}from"util";var{$:Qt,Glob:oe}=globalThis.Bun;async function ee(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:t}=await Promise.resolve().then(() => (j(),Z));t("migrate"),process.exit(0)}let{values:n}=ie({args:r,options:{all:{default:!1,short:"a",type:"boolean"},backup:{default:!0,short:"b",type:"boolean"},dryRun:{default:!1,short:"d",type:"boolean"},format:{short:"f",type:"string"},path:{short:"p",type:"string"}},strict:!0});return{all:n.all,backup:n.backup,dryRun:n.dryRun,format:n.format,path:n.path}}async function Ft(){let r=await ee();if(!r.path&&!r.all)r.path=await T({message:"Path to configuration file:",placeholder:"./hydra.json",validate:(o)=>{if(!o)return"Path is required";return}});let n=await se(r);if(n.length===0){m.error("No configuration files found");return}m.info(`Found ${n.length} configuration file(s) to migrate`);let t=[];for(let o of n){let e=await ae(o,r);t.push(e)}ce(t,r)}async function se(r){if(r.path){if(!await Bun.file(r.path).exists())throw new Error(`Configuration file not found: ${r.path}`);return[r.path]}if(r.all){let n=new oe("**/hydra.{json,toml}"),t=[];for await(let o of n.scan("."))if(!o.includes("node_modules")&&!o.includes(".git"))t.push(o);return t}return[]}async function ae(r,n){let t=Q();t.start(`Migrating ${r}...`);try{let o=await Bun.file(r).text(),e=r.endsWith(".toml")?"toml":"json",s=n.format||e,i,a=[];if(e==="toml"){let d=`.temp-${Date.now()}.toml`;await Bun.write(d,o),i=(await import(d)).default,await Qt`rm ${d}`.quiet()}else i=JSON.parse(o);let f=await fe(i,a);if(n.backup&&!n.dryRun){let d=`${r}.backup-${new Date().toISOString().replace(/:/g,"-")}`;await Bun.write(d,o),a.push(`Created backup at ${d}`)}if(!n.dryRun){let d=s!==e?r.replace(/\.(json|toml)$/,`.${s}`):r;if(s==="toml")await de(d,f);else await Bun.write(d,JSON.stringify(f,null,2));if(d!==r){if(await S({initialValue:!0,message:`Remove original file ${r}?`}))await Qt`rm ${r}`.quiet(),a.push(`Removed original file ${r}`)}a.push(`Migrated to ${d}`)}return t.stop(`Migrated ${r}`),{changes:a,path:r,success:!0}}catch(o){return t.stop(`Failed to migrate ${r}`),{error:o.message,path:r,success:!1}}}async function fe(r,n){let t={profiles:{}};if(r.defaultProfile)t.defaultProfile=r.defaultProfile;if(r.url||r.numberOfMachines||r.directory||r.labels){let o={};if(r.directory)o.directory=r.directory;if(r.labels)o.labels=r.labels;if(r.name)o.name=r.name;if(r.numberOfMachines)o.numberOfMachines=r.numberOfMachines;if(r.os)o.os=r.os;if(r.runnerGroup)o.runnerGroup=r.runnerGroup;if(r.url)o.url=r.url;if(r.overwrite!==void 0)o.overwrite=r.overwrite;if(r.run!==void 0)o.run=r.run;t.profiles.default=o,n.push("Migrated root-level settings to default profile"),delete r.url,delete r.numberOfMachines,delete r.directory,delete r.labels,delete r.name,delete r.os,delete r.runnerGroup,delete r.overwrite,delete r.run}if(r.profiles)for(let[o,e]of Object.entries(r.profiles)){let s=typeof e==="object"&&e!==null?{...e}:{};if(typeof e==="object"&&e!==null){if("runnerCount"in e&&!("numberOfMachines"in e))s.numberOfMachines=e.runnerCount,delete s.runnerCount,n.push(`Renamed 'runnerCount' to 'numberOfMachines' in profile '${o}'`);if("workDir"in e&&!("directory"in e))s.directory=e.workDir,delete s.workDir,n.push(`Renamed 'workDir' to 'directory' in profile '${o}'`);if(typeof e.labels==="string")s.labels=e.labels.split(",").map((i)=>i.trim()),n.push(`Converted labels to array format in profile '${o}'`)}t.profiles[o]=s}for(let[o,e]of Object.entries(r))if(!["profiles","defaultProfile"].includes(o))t[o]=e,n.push(`Preserved unknown property '${o}'`);return t}async function de(r,n){let t="";if(n.defaultProfile)t+=`defaultProfile = "${n.defaultProfile}"
|
|
92
85
|
|
|
93
|
-
`;for(let[
|
|
94
|
-
`;for(let[s,
|
|
95
|
-
`;else if(typeof
|
|
96
|
-
`;else if(Array.isArray(
|
|
97
|
-
`;else
|
|
98
|
-
`}
|
|
99
|
-
`}await Bun.write(t
|
|
100
|
-
`)
|
|
101
|
-
|
|
102
|
-
`);
|
|
103
|
-
Description: ${i.description}`);if(i.hydraVersion)l.info(`Hydra Version: ${i.hydraVersion}`);let r=e.getAllCommands().filter((s)=>s.name.startsWith(`${i.name}:`));if(r.length>0){l.info(`
|
|
104
|
-
Commands:`);for(let s of r)l.info(` ${c.value(s.name)} - ${s.description}`)}if(i.hooks&&i.hooks.length>0){l.info(`
|
|
105
|
-
Hooks:`);for(let s of i.hooks)l.info(` ${s}`)}if(i.dependencies&&Object.keys(i.dependencies).length>0){l.info(`
|
|
106
|
-
Dependencies:`);for(let[s,o]of Object.entries(i.dependencies))l.info(` ${s}: ${o}`)}break}case"install":{if(!t.pluginName){let i=await A({message:"Enter plugin path or git URL:",placeholder:"./my-plugin or https://github.com/user/hydra-plugin"});if(!i||typeof i!=="string")l.error("Installation cancelled"),process.exit(1);t.pluginName=i}let n=T();n.start(`Installing plugin from ${t.pluginName}`);try{let i=Gt(Ln(),".hydra","plugins");if(await y.ensureDir(i),t.pluginName.startsWith("http")||t.pluginName.includes("github.com")){let{$:r}=awaitPromise.resolve(globalThis.Bun),s=t.pluginName.split("/").pop()?.replace(".git","")||"plugin",o=Gt(i,s);await r`git clone ${t.pluginName} ${o}`.quiet();let a=Gt(o,"package.json");if(await y.exists(a))await r`cd ${o} && bun install`.quiet();await e.loadPlugin(o),n.stop(`Plugin installed successfully: ${s}`)}else{let r=t.pluginName;if(!await y.exists(r))throw new Error(`Plugin path not found: ${r}`);let s=r.split("/").pop()||"plugin",o=Gt(i,s),{$:a}=awaitPromise.resolve(globalThis.Bun);await a`cp -r ${r} ${o}`.quiet(),await e.loadPlugin(o),n.stop(`Plugin installed successfully: ${s}`)}}catch(i){n.stop(`Failed to install plugin: ${i}`),process.exit(1)}break}case"uninstall":{if(!t.pluginName){let i=e.getAllPlugins();if(i.length===0)l.error("No plugins to uninstall"),process.exit(1);let r=await K({message:"Select plugin to uninstall:",options:i.map((s)=>({label:`${s.manifest.name} v${s.manifest.version}`,value:s.manifest.name}))});if(!r)l.error("Uninstall cancelled"),process.exit(1);t.pluginName=r}let n=T();n.start(`Uninstalling plugin: ${t.pluginName}`);try{await e.unloadPlugin(t.pluginName);let i=Gt(Ln(),".hydra","plugins",t.pluginName);if(await y.exists(i)){let{$:r}=awaitPromise.resolve(globalThis.Bun);await r`rm -rf ${i}`.quiet()}n.stop(`Plugin uninstalled successfully: ${t.pluginName}`)}catch(i){n.stop(`Failed to uninstall plugin: ${i}`),process.exit(1)}break}case"enable":case"disable":l.error(`Plugin ${t.action} not yet implemented`),process.exit(1)}}q();O();V();import{parseArgs as Cl}from"util";G();var Ft=$({prefix:"runner-pool"});class qo{pools=new Map;runnerToPool=new Map;createPool(t){let e=this.generatePoolId(t.name);if(this.pools.has(e))throw new Error(`Pool with name "${t.name}" already exists`);let n={created:new Date,id:e,labels:t.labels||[],lastScaled:new Date,maxRunners:t.maxRunners||10,minRunners:t.minRunners||1,name:t.name,profile:t.profile,runners:new Map};return this.pools.set(e,n),Ft.info(`Created runner pool: ${n.name} (${e})`),n}deletePool(t){let e=this.pools.get(t);if(!e)throw new Error(`Pool ${t} not found`);for(let n of e.runners.keys())this.runnerToPool.delete(n);this.pools.delete(t),Ft.info(`Deleted runner pool: ${e.name}`)}addRunner(t,e){let n=this.pools.get(t);if(!n)throw new Error(`Pool ${t} not found`);let i={...e,poolId:t};return n.runners.set(e.id,i),this.runnerToPool.set(e.id,t),Ft.debug(`Added runner ${e.name} to pool ${n.name}`),i}removeRunner(t){let e=this.runnerToPool.get(t);if(!e){Ft.warn(`Runner ${t} not found in any pool`);return}let n=this.pools.get(e);if(n)n.runners.delete(t);this.runnerToPool.delete(t),Ft.debug(`Removed runner ${t} from pool ${e}`)}updateRunnerStatus(t,e){let n=this.runnerToPool.get(t);if(!n)return;let r=this.pools.get(n)?.runners.get(t);if(r)r.status=e,r.lastSeen=new Date}getPool(t){return this.pools.get(t)}getPools(){return Array.from(this.pools.values())}getPoolByName(t){let e=this.generatePoolId(t);return this.pools.get(e)}getRunnerPool(t){let e=this.runnerToPool.get(t);return e?this.pools.get(e):void 0}getPoolMetrics(t){let e=this.pools.get(t);if(!e)return null;let n=Array.from(e.runners.values()),i=n.filter((a)=>a.status==="idle").length,r=n.filter((a)=>a.status==="busy").length,s=n.filter((a)=>a.status==="offline").length,o=n.length;return{busyRunners:r,idleRunners:i,offlineRunners:s,poolId:t,totalRunners:o,utilization:o>0?r/o:0}}getAllMetrics(){return Array.from(this.pools.keys()).map((t)=>this.getPoolMetrics(t)).filter((t)=>t!==null)}findRunnersWithLabels(t){let e=[];for(let n of this.pools.values())for(let i of n.runners.values())if(t.every((s)=>i.labels.includes(s)||n.labels.includes(s)))e.push(i);return e}getIdleRunnersInPool(t){let e=this.pools.get(t);if(!e)return[];return Array.from(e.runners.values()).filter((n)=>n.status==="idle")}generatePoolId(t){return t.toLowerCase().replace(/[^a-z0-9-]/g,"-")}}var Rt=new qo;async function Go(){let t=await Sl();if(t.list)await Lo();else if(t.create)await _l(t);else if(t.delete)await Nl(t);else await Lo()}async function Lo(){let t=Rt.getPools();if(t.length===0){at("No runner pools configured");return}console.log(`
|
|
107
|
-
\uD83D\uDCCA Runner Pools:`),console.log("\u2500".repeat(80));for(let e of t){let n=Rt.getPoolMetrics(e.id);if(console.log(`
|
|
108
|
-
\uD83C\uDFCA ${e.name} (${e.id})`),console.log(` Profile: ${e.profile.name}`),console.log(` Labels: ${e.labels.join(", ")||"none"}`),console.log(` Limits: ${e.minRunners}-${e.maxRunners} runners`),n)console.log(` Status: ${n.totalRunners} total (${n.busyRunners} busy, ${n.idleRunners} idle, ${n.offlineRunners} offline)`),console.log(` Utilization: ${(n.utilization*100).toFixed(1)}%`)}console.log(`
|
|
109
|
-
${"\u2500".repeat(80)}`)}async function _l(t){he("\uD83C\uDFCA Create Runner Pool");let e=t.name||await A({message:"Pool name",placeholder:"production-runners",validate:(o)=>{if(!o||o.trim().length===0)return"Pool name is required";if(Rt.getPoolByName(o))return"Pool with this name already exists";return}});if(typeof e==="symbol")throw new nt("Pool creation cancelled","CANCELLED");let n=t.labels?t.labels.split(",").map((o)=>o.trim()):[];if(!t.labels){let o=await xi({message:"Select runner labels",options:[{label:"self-hosted",value:"self-hosted"},{label:"Linux",value:"linux"},{label:"macOS",value:"macos"},{label:"Windows",value:"windows"},{label:"x64",value:"x64"},{label:"ARM64",value:"arm64"}],required:!1});if(typeof o!=="symbol")n.push(...o);let a=await A({message:"Additional labels (comma-separated)",placeholder:"gpu, high-memory"});if(typeof a==="string"&&a.trim())n.push(...a.split(",").map((f)=>f.trim()))}let i=await N({profile:t.profile}),r=await S(i,t.profile);if(!r)throw new nt("Profile not found","PROFILE_NOT_FOUND");let s=Rt.createPool({labels:n,maxRunners:t.maxRunners,minRunners:t.minRunners,name:e,profile:r});at(`\u2705 Created runner pool "${s.name}" with ${n.length} labels`)}async function Nl(t){let e=t.delete,n=Rt.getPoolByName(e);if(!n)throw new nt(`Pool "${e}" not found`,"POOL_NOT_FOUND");let i=Rt.getPoolMetrics(n.id);if(i&&i.totalRunners>0&&!t.force){if(!await C({initialValue:!1,message:`Pool has ${i.totalRunners} runners. Delete anyway?`})){at("Deletion cancelled");return}}Rt.deletePool(n.id),at(`\u2705 Deleted runner pool "${e}"`)}async function Sl(){let{values:t}=Cl({allowPositionals:!0,args:Bun.argv,options:{create:{short:"c",type:"boolean"},delete:{short:"d",type:"string"},force:{short:"f",type:"boolean"},labels:{type:"string"},list:{default:!1,short:"l",type:"boolean"},maxRunners:{default:"10",type:"string"},minRunners:{default:"1",type:"string"},name:{short:"n",type:"string"},profile:{short:"p",type:"string"}},strict:!0});return{create:t.create,delete:t.delete,force:t.force,labels:t.labels,list:t.list||!t.create&&!t.delete,maxRunners:Number.parseInt(t.maxRunners),minRunners:Number.parseInt(t.minRunners),name:t.name,profile:t.profile}}q();O();bn();Wt();import{parseArgs as Ml}from"util";async function Wl(){let{values:t,positionals:e}=Ml({allowPositionals:!0,args:process.argv.slice(2),options:{json:{default:!1,short:"j",type:"boolean"}},strict:!0});return{action:e[0],json:t.json}}async function jo(){let t=await Wl();if(!t.action)t.action=await K({message:"What would you like to do?",options:[{label:"View recovery status",value:"status"},{label:"View error metrics",value:"metrics"},{label:"View circuit breakers",value:"breakers"},{label:"Reset error metrics",value:"reset"}]});switch(t.action){case"status":await Bl(t);break;case"metrics":await Ul(t);break;case"breakers":await ql(t);break;case"reset":await Ll(t);break;default:l.error(`Unknown action: ${t.action}`),l.info("Available actions: status, metrics, breakers, reset")}}async function Bl(t){let e=ht.getErrorMetrics(),n=ht.getAllCircuitBreakers(),i=Vt.getAllWorkerInfo(),r={activeWorkers:i.filter((s)=>s.status==="running").length,circuitBreakers:{closed:Array.from(n.values()).filter((s)=>s.getState()==="closed").length,halfOpen:Array.from(n.values()).filter((s)=>s.getState()==="half_open").length,open:Array.from(n.values()).filter((s)=>s.getState()==="open").length,total:n.size},erroredWorkers:i.filter((s)=>s.status==="error").length,totalErrors:Array.from(e.values()).reduce((s,o)=>s+o.count,0),uniqueErrorTypes:e.size};if(t.json){console.log(JSON.stringify(r,null,2));return}if(l.info(c.value("Error Recovery Status")),l.info(""),l.info("Summary:"),l.info(` Total errors: ${r.totalErrors}`),l.info(` Unique error types: ${r.uniqueErrorTypes}`),l.info(` Active workers: ${r.activeWorkers}`),r.erroredWorkers>0)l.info(` ${c.error(`Errored workers: ${r.erroredWorkers}`)}`);if(l.info(""),l.info("Circuit Breakers:"),l.info(` Total: ${r.circuitBreakers.total}`),r.circuitBreakers.open>0)l.info(` ${c.error(`Open: ${r.circuitBreakers.open}`)}`);if(r.circuitBreakers.halfOpen>0)l.info(` ${c.warning(`Half-open: ${r.circuitBreakers.halfOpen}`)}`);if(l.info(` ${c.success(`Closed: ${r.circuitBreakers.closed}`)}`),r.totalErrors>0)l.info(""),l.info("Use 'hydra recovery metrics' to see detailed error breakdown")}async function Ul(t){let e=ht.getErrorMetrics();if(e.size===0){l.info("No error metrics recorded");return}let n=Array.from(e.entries()).map(([r,s])=>({count:s.count,errorType:r.split(":")[1]||"unknown",lastOccurred:s.lastOccurred,operation:r.split(":")[0]||"unknown"}));if(t.json){console.log(JSON.stringify(n,null,2));return}l.info(c.value("Error Metrics")),l.info(""),l.info("\u2500".repeat(80)),l.info(`${"Operation".padEnd(30)} ${"Error Type".padEnd(20)} ${"Count".padEnd(10)} ${"Last Occurred".padEnd(20)}`),l.info("\u2500".repeat(80));for(let r of n){let s=Jo(r.lastOccurred);l.info(`${r.operation.padEnd(30)} ${r.errorType.padEnd(20)} ${r.count.toString().padEnd(10)} ${s.padEnd(20)}`)}l.info("\u2500".repeat(80));let i=n.reduce((r,s)=>r+s.count,0);l.info(`Total errors: ${i}`)}async function ql(t){let e=ht.getAllCircuitBreakers();if(e.size===0){l.info("No circuit breakers configured");return}let n=Array.from(e.entries()).map(([i,r])=>{let s=r.getStats();return{name:i,...s}});if(t.json){console.log(JSON.stringify(n,null,2));return}l.info(c.value("Circuit Breakers")),l.info("");for(let i of n){let r=i.state==="open"?c.error:i.state==="half_open"?c.warning:c.success;if(l.info(`${c.value(i.name)}:`),l.info(` State: ${r(i.state)}`),l.info(` Failure count: ${i.failureCount}`),i.lastFailureTime)l.info(` Last failure: ${Jo(i.lastFailureTime)} ago`);if(i.state==="half_open")l.info(` Half-open attempts: ${i.halfOpenAttempts}`);l.info("")}}async function Ll(t){if(!t.json){if(!await C({initialValue:!1,message:"Are you sure you want to reset all error metrics?"})){l.info("Reset cancelled");return}}if(ht.resetMetrics(),t.json)console.log(JSON.stringify({message:"Error metrics reset",success:!0}));else l.success("Error metrics reset successfully")}function Jo(t){let e=Math.floor((Date.now()-t.getTime())/1000);if(e<60)return`${e}s`;let n=Math.floor(e/60);if(n<60)return`${n}m`;let i=Math.floor(n/60);if(i<24)return`${i}h ${n%60}m`;return`${Math.floor(i/24)}d ${i%24}h`}Ae();Pn();q();O();G();V();Ee();Ae();import{parseArgs as Gl}from"util";var ko=$({prefix:"hydra"}).child("scale");async function jl(){let{values:t}=Gl({allowPositionals:!0,args:Bun.argv,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},dry:{default:!1,type:"boolean"},interval:{default:"60",short:"i",type:"string"},max:{default:"5",short:"M",type:"string"},min:{default:"1",short:"m",type:"string"},profile:{short:"p",type:"string"},"scale-down-idle":{default:"30",type:"string"},"scale-up-threshold":{default:"2",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"},watch:{default:!1,short:"w",type:"boolean"}},strict:!0}),e=await N({configPath:t.config}),n=await S(e,t.profile);return{directory:t.directory||n?.directory||`${process.cwd()}/gh-runners`,dry:t.dry,scaleConfig:{checkIntervalSeconds:Number.parseInt(t.interval,10),maxRunners:Number.parseInt(t.max,10),minRunners:Number.parseInt(t.min,10),scaleDownIdleMinutes:Number.parseInt(t["scale-down-idle"],10),scaleUpThreshold:Number.parseInt(t["scale-up-threshold"],10)},token:t.token,url:t.url||n?.url,watch:t.watch}}async function Xo(){try{let t=await jl();if(!t.token||!t.url)throw new Error("Token (-t) and URL (-u) parameters are required");if(t.scaleConfig.minRunners>t.scaleConfig.maxRunners)throw new Error("Minimum runners cannot be greater than maximum runners");if(l.info("Autoscale Configuration:"),console.log(` Min Runners: ${c.value(String(t.scaleConfig.minRunners))}`),console.log(` Max Runners: ${c.value(String(t.scaleConfig.maxRunners))}`),console.log(` Scale Up Threshold: ${c.value(String(t.scaleConfig.scaleUpThreshold))} pending jobs`),console.log(` Scale Down After: ${c.value(String(t.scaleConfig.scaleDownIdleMinutes))} minutes idle`),console.log(),t.watch)await kl(t);else await Jl(t)}catch(t){ko.error("Failed to scale runners:",t),process.exit(1)}}async function Jl(t){let e=T();e.start("Analyzing queue and runners...");try{let n=await Qo(t.url,t.token,t.directory);e.stop("Analysis complete"),Kl(n);let i=Ko(n,t.scaleConfig);if(i.type==="none"){l.info("No scaling action needed");return}if(console.log(),i.type==="scale-up")l.info(`Recommendation: Scale UP by ${i.count} runner(s)`),l.info(`Reason: ${i.reason}`);else l.info(`Recommendation: Scale DOWN by ${i.count} runner(s)`),l.info(`Reason: ${i.reason}`);if(t.dry){l.info("Dry run - no changes made");return}if(!await C({initialValue:!0,message:`Proceed with ${i.type}?`})){l.info("Cancelled");return}await Vo(i,t)}catch(n){throw e.stop("Failed"),n}}async function kl(t){l.info(`Starting autoscale watch mode (checking every ${t.scaleConfig.checkIntervalSeconds}s)`),console.log(`Press Ctrl+C to stop
|
|
110
|
-
`);let e=new Map;while(!0)try{let n=await Qo(t.url,t.token,t.directory);await Ql(e,n,t);let i=Ko(n,t.scaleConfig,e),r=new Date().toLocaleTimeString();if(console.log(`[${r}] Queue: ${n.pendingJobs} | Active: ${n.activeRunners} | Idle: ${n.idleRunners} | Total: ${n.totalRunners}`),i.type!=="none"){if(console.log(`[${r}] ${c.warning(`Action: ${i.type} by ${i.count} - ${i.reason}`)}`),!t.dry)await Vo(i,t)}await Bun.sleep(t.scaleConfig.checkIntervalSeconds*1000)}catch(n){ko.error("Error in watch cycle:",n),await Bun.sleep(t.scaleConfig.checkIntervalSeconds*1000)}}async function Qo(t,e,n){let i=await Xl(t,e),r=await Gn(t,e,n),s=r.filter((f)=>f.busy).length,o=r.filter((f)=>f.status==="online"&&!f.busy).length,a=r.length;return{activeRunners:s,idleRunners:o,pendingJobs:i,totalRunners:a}}async function Xl(t,e){let n=t.match(/github\.com[:/]([^/]+)(?:\/([^/.]+))?/);if(!n)throw new Error("Invalid GitHub URL");let[,i,r]=n,s=r?`https://api.github.com/repos/${i}/${r}/actions/runs?status=queued&per_page=100`:`https://api.github.com/orgs/${i}/actions/runs?status=queued&per_page=100`;return it(async()=>{let o=await fetch(s,{headers:{Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${e}`}});if(!o.ok)throw new Error(`GitHub API error: ${o.status}`);let a=await o.json(),f=0;for(let u of a.workflow_runs||[]){let p=await fetch(`https://api.github.com/repos/${i}/${r}/actions/runs/${u.id}/jobs`,{headers:{Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${e}`}});if(p.ok){let d=await p.json();f+=d.jobs?.filter((g)=>g.status==="queued").length||0}}return f},{maxAttempts:3})}async function Gn(t,e,n){let i=t.match(/github\.com[:/]([^/]+)(?:\/([^/.]+))?/);if(!i)return[];let[,r,s]=i,o=s?`https://api.github.com/repos/${r}/${s}/actions/runners`:`https://api.github.com/orgs/${r}/actions/runners`,a=await fetch(o,{headers:{Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${e}`}});if(!a.ok)return[];return(await a.json()).runners||[]}function Ko(t,e,n){if(t.pendingJobs>=e.scaleUpThreshold&&t.totalRunners<e.maxRunners)return{count:Math.min(t.totalRunners+Math.ceil(t.pendingJobs/2),e.maxRunners)-t.totalRunners,reason:`${t.pendingJobs} jobs pending (threshold: ${e.scaleUpThreshold})`,type:"scale-up"};if(t.idleRunners>0&&t.totalRunners>e.minRunners){let i=0;if(n){let r=new Date;for(let[,s]of n)if((r.getTime()-s.getTime())/60000>=e.scaleDownIdleMinutes)i++}else i=t.idleRunners;if(i>0)return{count:Math.min(i,t.totalRunners-e.minRunners),reason:`${i} runners idle for ${e.scaleDownIdleMinutes}+ minutes`,type:"scale-down"}}return{count:0,reason:"",type:"none"}}async function Vo(t,e){if(t.type==="scale-up"){l.info(`Scaling up by ${t.count} runner(s)...`);let n=process.argv;try{process.argv=[process.argv[0],process.argv[1],"create","-t",e.token,"-u",e.url,"-m",String(t.count),"-d",e.directory],await zt(),l.success(`Successfully added ${t.count} runner(s)`)}finally{process.argv=n}}else if(t.type==="scale-down"){l.info(`Scaling down by ${t.count} runner(s)...`);let i=(await Gn(e.url,e.token,e.directory)).filter((s)=>s.status==="online"&&!s.busy).slice(0,t.count);if(i.length===0){l.warning("No idle runners to remove");return}let r=process.argv;try{for(let s of i){let o=s.name.match(/runner-(\d+)/)?.[1];if(!o)continue;process.argv=[process.argv[0],process.argv[1],"remove","-t",e.token,"-u",e.url,"-n",`runner-${o}`,"-d",e.directory,"-f"],await Yt()}l.success(`Successfully removed ${i.length} runner(s)`)}finally{process.argv=r}}}async function Ql(t,e,n){let i=await Gn(n.url,n.token,n.directory);for(let s of i)if(s.status==="online"&&!s.busy){if(!t.has(s.name))t.set(s.name,new Date)}else t.delete(s.name);let r=new Set(i.map((s)=>s.name));for(let[s]of t)if(!r.has(s))t.delete(s)}function Kl(t){console.log(),console.log(c.bold("\uD83D\uDCCA Current Status")),console.log(` Pending Jobs: ${c.value(String(t.pendingJobs))}`),console.log(` Total Runners: ${c.value(String(t.totalRunners))}`),console.log(` Active Runners: ${c.success(String(t.activeRunners))}`),console.log(` Idle Runners: ${c.warning(String(t.idleRunners))}`)}q();O();import{homedir as Zo}from"os";import{join as jn}from"path";import{parseArgs as Vl}from"util";var Ce={global:jn(Zo(),".hydra","templates.json"),local:"./hydra-templates.json"};async function Zl(){let{values:t,positionals:e}=Vl({allowPositionals:!0,args:process.argv.slice(2),options:{force:{default:!1,short:"f",type:"boolean"},from:{short:"F",type:"string"},global:{default:!1,short:"g",type:"boolean"},name:{short:"n",type:"string"}},strict:!0}),n=e[0],i=e[1];return{action:n,force:t.force,from:t.from,global:t.global,name:t.name||i}}async function zo(){let t=await Zl();if(!t.action)t.action=await K({message:"What would you like to do?",options:[{label:"List templates",value:"list"},{label:"Create a new template",value:"create"},{label:"Use a template",value:"use"},{label:"Show template details",value:"show"},{label:"Delete a template",value:"delete"}]});switch(t.action){case"list":await zl();break;case"create":await Yl(t);break;case"use":await Il(t);break;case"show":await Fl(t);break;case"delete":await Dl(t);break;default:l.error(`Unknown action: ${t.action}`),l.info("Available actions: list, create, use, show, delete")}}async function Et(t){let e=t?Ce.global:Ce.local,n=Bun.file(e);if(!await n.exists())return{templates:{},version:"1.0"};try{return await n.json()}catch{return{templates:{},version:"1.0"}}}async function Yo(t,e){let n=e?Ce.global:Ce.local;if(e){let i=jn(Zo(),".hydra");await Bun.write(jn(i,".gitkeep"),"")}await Bun.write(n,JSON.stringify(t,null,2))}async function zl(){let t=await Et(!0),e=await Et(!1),n={...t.templates,...e.templates};if(Object.keys(n).length===0){l.info("No templates found"),l.info(""),l.info("Create a template with: hydra template create");return}l.info(c.value("Available Templates:")),l.info("");for(let[i,r]of Object.entries(n)){let o=i in t.templates?c.dim(" (global)"):"";if(l.info(` ${c.value(i)}${o}`),r.description)l.info(` ${c.dim(r.description)}`);if(r.extends)l.info(` ${c.dim(`Extends: ${r.extends}`)}`);let a=[];if(r.numberOfMachines)a.push(`machines: ${r.numberOfMachines}`);if(r.os)a.push(`os: ${r.os}`);if(r.labels)a.push(`labels: ${r.labels}`);if(a.length>0)l.info(` ${c.dim(a.join(", "))}`);l.info("")}}async function Yl(t){let e=t.name||await A({message:"Template name:",placeholder:"my-template",validate:(p)=>{if(!p)return"Template name is required";if(!/^[a-zA-Z0-9-_]+$/.test(p))return"Template name can only contain letters, numbers, hyphens, and underscores";return}}),n=await Et(t.global??!1);if(!t.force&&e in n.templates){if(!await C({initialValue:!1,message:`Template '${e}' already exists. Overwrite?`})){l.info("Template creation cancelled");return}}let i=await A({message:"Description (optional):",placeholder:"Template for production runners"}),r={};if(t.from){let p=n.templates[t.from];if(p)r={...p},delete r.name,delete r.description,delete r.metadata,delete r.extends}let s=await A({initialValue:r.numberOfMachines?.toString()||"1",message:"Number of machines:",placeholder:r.numberOfMachines?.toString()||"1"}),o=await K({initialValue:r.os||"osx",message:"Operating system:",options:[{label:"macOS",value:"osx"},{label:"Linux",value:"linux"},{label:"Windows",value:"windows"}]}),a=await A({initialValue:r.labels,message:"Labels (comma-separated, optional):",placeholder:r.labels||"self-hosted,x64"}),f=await A({initialValue:r.directory||"./gh-runners",message:"Runner directory:",placeholder:r.directory||"./gh-runners"}),u={description:i||void 0,directory:f,extends:t.from||void 0,labels:a||void 0,metadata:{author:process.env.USER||void 0,created:new Date().toISOString(),updated:new Date().toISOString()},name:e,numberOfMachines:Number.parseInt(s,10),os:o};n.templates[e]=u,await Yo(n,t.global??!1),l.success(`Template '${e}' created successfully`),l.info(""),l.info(`Use it with: hydra create --template ${e}`)}async function Il(t){let e=await Et(!0),n=await Et(!1),i={...e.templates,...n.templates};if(Object.keys(i).length===0){l.error("No templates found"),l.info("Create a template with: hydra template create");return}let r=t.name||await K({message:"Select a template:",options:Object.entries(i).map(([f,u])=>({label:`${f}${u.description?` - ${u.description}`:""}`,value:f}))}),s=i[r];if(!s){l.error(`Template '${r}' not found`);return}let o=await Jn(s,i);if(l.info(""),l.info(c.value(`Using template: ${r}`)),l.info(""),l.info("This will create runners with the following configuration:"),l.info(` Number of machines: ${o.numberOfMachines||1}`),l.info(` OS: ${o.os||"osx"}`),l.info(` Directory: ${o.directory||"./gh-runners"}`),o.labels)l.info(` Labels: ${o.labels}`);l.info("");let a=await K({message:"Where should this configuration be saved?",options:[{label:"Create hydra.json in current directory",value:"json"},{label:"Create hydra.toml in current directory",value:"toml"},{label:"Just show the command",value:"command"}]});if(a==="command"){let f=[];if(o.numberOfMachines)f.push(`-m ${o.numberOfMachines}`);if(o.os)f.push(`-s ${o.os}`);if(o.directory)f.push(`-d "${o.directory}"`);if(o.labels)f.push(`-l "${o.labels}"`);if(o.name)f.push(`-n "${o.name}"`);l.info("Run the following command:"),l.info(""),l.info(c.value(`hydra create ${f.join(" ")} -t <TOKEN> -u <URL>`)),l.info("")}else{let f={defaultProfile:"default",profiles:{default:o}},u=a==="json"?"hydra.json":"hydra.toml";if(a==="json")await Bun.write(u,JSON.stringify(f,null,2));else{let p=`defaultProfile = "default"
|
|
86
|
+
`;for(let[o,e]of Object.entries(n.profiles)){t+=`[profiles.${o}]
|
|
87
|
+
`;for(let[s,i]of Object.entries(e)){if(i===void 0||i===null)continue;if(typeof i==="string")t+=`${s} = "${i}"
|
|
88
|
+
`;else if(typeof i==="number")t+=`${s} = ${i}
|
|
89
|
+
`;else if(Array.isArray(i))t+=`${s} = [${i.map((a)=>`"${a}"`).join(", ")}]
|
|
90
|
+
`;else t+=`${s} = ${JSON.stringify(i)}
|
|
91
|
+
`}t+=`
|
|
92
|
+
`}await Bun.write(r,t.trim())}function ce(r,n){if(m.info(""),n.dryRun)m.warn("DRY RUN MODE - No files were actually modified"),m.info("");let t=r.filter((e)=>e.success),o=r.filter((e)=>!e.success);if(t.length>0){m.success(`Successfully migrated ${t.length} file(s):`);for(let e of t)if(m.info(` ${y.value(e.path)}`),e.changes&&e.changes.length>0)for(let s of e.changes)m.info(` ${y.dim("\u2192")} ${s}`)}if(o.length>0){m.error(`Failed to migrate ${o.length} file(s):`);for(let e of o)m.error(` ${y.value(e.path)}: ${e.error}`)}m.info(""),m.info("Migration complete!")}L();import{parseArgs as me}from"util";var{$:Dt}=globalThis.Bun;var z=x({prefix:"hydra:remove"});async function ri(){let r=await ue(),{directory:n,numberOfMachines:t,force:o}=r,{token:e,url:s}=r,i=`${n}/machines`;if(!await b.exists(i))throw w.createError(`Machines directory not found at ${i}. Nothing to remove.`,"FILE_SYSTEM_ERROR",void 0,{directory:n,machinesDir:i,operation:"remove_machines"});if(e)z=x({prefix:"hydra:remove",secrets:[e]});if(!e&&!o){if(!s)throw z.warn("No token or URL provided. Runners will not be unregistered from GitHub."),z.warn("Use --force to remove runners without unregistering them."),new Error("Token (-t) and URL (-u) parameters are required or use --force");let a=ye(s),f=await S({message:`No token provided. Would you like to open GitHub to get a runner token for unregistration?
|
|
93
|
+
${a}`});if(H(f)||!f)throw z.warn("Use --force to remove runners without unregistering them."),new Error("Token is required to unregister runners (or use --force)");z.info("Opening GitHub runner settings..."),await Dt`open ${a}`.quiet();let d=await T({message:"Enter the runner removal token:",placeholder:"AXXXXXXXXXXXXXXXXXXXXXXXXX",validate:(c)=>{if(!c||c.trim().length===0)return"Token is required";return}});if(H(d))throw z.warn("Use --force to remove runners without unregistering them."),new Error("Token is required to unregister runners (or use --force)");e=d.trim()}if(e&&s)z.info("Unregistering runners from GitHub..."),await pe({directory:n,numberOfMachines:t,token:e});else if(!o)throw z.warn("No token or URL provided. Runners will not be unregistered from GitHub."),z.warn("Use --force to remove runners without unregistering them."),new Error("Token (-t) and URL (-u) parameters are required or use --force");await le({directory:n,numberOfMachines:t}),z.info("Runners successfully removed")}async function ue(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:s}=await Promise.resolve().then(() => (j(),Z));s("remove"),process.exit(0)}let{values:n}=me({args:r,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},force:{default:!1,short:"f",type:"boolean"},numberOfMachines:{default:"1",short:"m",type:"string"},profile:{short:"p",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),t=await q({configPath:n.config}),o=await B(t,n.profile),e={directory:n.directory,force:n.force,numberOfMachines:n.numberOfMachines,token:n.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:n.url};if(o)return{directory:e.directory??o.directory??`${process.cwd()}/gh-runners`,force:e.force,numberOfMachines:e.numberOfMachines??String(o.numberOfMachines)??"1",token:e.token||o?.token,url:e.url??o.url};return e}async function pe({directory:r,numberOfMachines:n,token:t}){let o=x({prefix:"hydra:remove:unregister",secrets:[t]}),e=Number(n),s=(()=>{try{let l=Bun.spawnSync(["nproc"]);return Number.parseInt(l.stdout.toString().trim(),10)||4}catch{try{let l=Bun.spawnSync(["sysctl","-n","hw.ncpu"]);return Number.parseInt(l.stdout.toString().trim(),10)||4}catch{return 4}}})(),i=Math.min(Math.max(2,Math.floor(s/2)),e,8);o.info(`Unregistering ${e} runners with concurrency of ${i}`);let a=Array.from({length:e},(l,R)=>R+1).map((l)=>({execute:async()=>{let R=`${r}/machines/${l}`;if(!await b.exists(R))return o.debug(`Machine ${l} doesn't exist, skipping...`),{runnerIndex:l,status:"skipped"};try{return o.debug(`Unregistering machine ${l}...`),await Dt`${U(R)}/config.sh remove`.quiet().env({...process.env,RUNNER_CFG_PAT:t}),o.info(`Successfully unregistered machine ${l} from GitHub`),{runnerIndex:l,status:"success"}}catch(h){return o.warn(`Unable to unregister machine ${l}: ${h}`),{error:h,runnerIndex:l,status:"failed"}}},runnerIndex:l})),f=[];for(let l=0;l<a.length;l+=i){let R=a.slice(l,l+i),h=await Promise.allSettled(R.map((g)=>g.execute()));f.push(...h)}let d=f.filter((l)=>l.status==="fulfilled"&&l.value?.status==="success").length,c=f.filter((l)=>l.status==="fulfilled"&&l.value?.status==="failed").length,u=f.filter((l)=>l.status==="fulfilled"&&l.value?.status==="skipped").length;o.info(`Unregistration complete: ${d} successful, ${c} failed, ${u} skipped`)}async function le({directory:r,numberOfMachines:n}){let t=x({prefix:"hydra:remove:removeDirectories",secrets:[]}),o=Number(n),e=Array.from({length:o},(f,d)=>d+1).map((f)=>({execute:async()=>{let d=`${r}/machines/${f}`;if(!await b.exists(d))return{runnerIndex:f,status:"skipped"};try{return await b.deleteDirectory(d,{recursive:!0}),t.debug(`Removed machine ${f} directory`),{runnerIndex:f,status:"success"}}catch(c){return t.error(`Error removing machine ${f} directory: ${c}`),{error:c,runnerIndex:f,status:"failed"}}},runnerIndex:f})),s=await Promise.allSettled(e.map((f)=>f.execute())),i=s.filter((f)=>f.status==="fulfilled"&&f.value?.status==="success").length,a=s.filter((f)=>f.status==="fulfilled"&&f.value?.status==="failed").length;if(t.info(`Directory removal complete: ${i} removed, ${a} failed`),a>0)throw new Error(`Failed to remove ${a} runner directories`);try{let f=`${r}/machines`;if((await b.listDirectory(f)).length===0){if(await b.deleteDirectory(f,{recursive:!0}),(await b.listDirectory(r)).length===0)await b.deleteDirectory(r,{recursive:!0});z.info("Removed empty directories")}}catch(f){}}function ye(r){try{let n=new URL(r),t=n.pathname.split("/").filter(Boolean);if(n.hostname==="github.com"||n.hostname==="www.github.com"){if(t[0]==="orgs"&&t[1])return`https://github.com/organizations/${t[1]}/settings/actions/runners`;if(t.length>=2)return`https://github.com/${t[0]}/${t[1]}/settings/actions/runners`}else{if(t[0]==="orgs"&&t[1])return`${n.origin}/organizations/${t[1]}/settings/actions/runners`;if(t.length>=2)return`${n.origin}/${t[0]}/${t[1]}/settings/actions/runners`}return r}catch{return r}}L();import{parseArgs as he}from"util";var{$:Re}=globalThis.Bun;var jr=x({prefix:"runMachines"});async function ni(){let r=await ge(),{directory:n,numberOfMachines:t,name:o,labels:e,runnerGroup:s}=r,{token:i,url:a}=r;if(!a)throw w.createError("URL (-u) parameter is required","VALIDATION_ERROR",void 0,{operation:"run_machines",parameter:"url"});if(!i){let f=be(a),d=await S({message:`No token provided. Would you like to open GitHub to get a runner token?
|
|
94
|
+
${f}`});if(H(d)||!d)throw w.createError("Token is required to run machines","AUTHENTICATION_ERROR",void 0,{operation:"run_machines",parameter:"token"});jr.info("Opening GitHub runner settings..."),await Re`open ${f}`.quiet();let c=await T({message:"Enter the runner registration token:",placeholder:"AXXXXXXXXXXXXXXXXXXXXXXXXX",validate:(u)=>{if(!u||u.trim().length===0)return"Token is required";return}});if(H(c))throw w.createError("Token is required to run machines","AUTHENTICATION_ERROR",void 0,{operation:"run_machines",parameter:"token"});i=c.trim()}if(jr=x({prefix:"runMachines",secrets:[i]}),jr.info(`Starting ${t} runners from ${n}`),jr.debug(`Name: ${o}, Labels: ${e||"none"}`),!await b.exists(`${n}/machines`))throw w.createError(`Machines directory not found at ${n}/machines. Run 'hydra create' first.`,"FILE_SYSTEM_ERROR",void 0,{directory:n,expectedPath:`${n}/machines`,operation:"run_machines"});await we({directory:n,labels:e,name:o,numberOfMachines:t,runnerGroup:s,token:i,url:a})}async function ge(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:s}=await Promise.resolve().then(() => (j(),Z));s("run"),process.exit(0)}let{values:n}=he({args:r,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},labels:{short:"l",type:"string"},name:{default:"runner",short:"n",type:"string"},numberOfMachines:{default:"1",short:"m",type:"string"},profile:{short:"p",type:"string"},runnerGroup:{short:"g",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),t=await q({configPath:n.config}),o=await B(t,n.profile),e={directory:n.directory,labels:n.labels,name:n.name,numberOfMachines:n.numberOfMachines,runnerGroup:n.runnerGroup,token:n.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:n.url};if(o)return{directory:e.directory??o.directory??`${process.cwd()}/gh-runners`,labels:e.labels??o.labels,name:e.name??o.name??"runner",numberOfMachines:e.numberOfMachines??String(o.numberOfMachines)??"1",runnerGroup:e.runnerGroup??o.runnerGroup,token:e.token||o?.token,url:e.url??o.url};return e}async function we({directory:r,numberOfMachines:n,token:t,url:o,name:e,labels:s,runnerGroup:i}){let a=x({prefix:"runMachines:start",secrets:[t]});a.info(`Starting ${n} workers...`);let f=new er({maxRestarts:3,maxWorkers:Number(n),restartDelay:5000,restartOnError:!0});f.on("workerError",(c,u)=>{a.error(`Worker ${c.name} encountered error:`,u)}),f.on("workerExit",(c,u)=>{if(u!==0)a.warn(`Worker ${c.name} exited with code ${u}`)});let d=0;for(let c=1;c<=Number(n);c++){let u=`${r}/machines/${c}`;if(!await b.exists(u)){a.warn(`Machine ${c} doesn't exist, skipping...`);continue}let l=`${Ur()}/src/runner-worker.ts`,R=`${e}-${c}`,h=`runner-${c}`;try{await f.createWorker({data:{index:c,labels:s,machineCwd:u,name:e,runnerGroup:i,token:t,url:o},id:h,name:R,onError:(g)=>{a.error(`Worker ${R} error:`,g)},onExit:(g)=>{a.info(`Worker ${R} exited with code ${g}`)},onMessage:(g)=>{let N=g.type==="error"?"error":"info",ar="message"in g?g.message:`${g.type} event`;a[N](`${R}: ${ar}`)},scriptPath:l}),a.info(`Worker ${R} started successfully`),d++}catch(g){a.error(`Failed to start worker ${R}:`,g)}}if(d===0)throw w.createError("No workers could be started","WORKER_ERROR",void 0,{directory:r,numberOfMachines:n,operation:"start_runners"});a.info(`${d} workers started. Press Ctrl+C to stop all machines`),process.on("SIGINT",async()=>{a.info("Gracefully shutting down workers..."),await f.shutdown(),process.exit(0)})}function be(r){try{let n=new URL(r),t=n.pathname.split("/").filter(Boolean);if(n.hostname==="github.com"||n.hostname==="www.github.com"){if(t[0]==="orgs"&&t[1])return`https://github.com/organizations/${t[1]}/settings/actions/runners/new`;if(t.length>=2)return`https://github.com/${t[0]}/${t[1]}/settings/actions/runners/new`}else{if(t[0]==="orgs"&&t[1])return`${n.origin}/organizations/${t[1]}/settings/actions/runners/new`;if(t.length>=2)return`${n.origin}/${t[0]}/${t[1]}/settings/actions/runners/new`}return r}catch{return r}}L();G();P();import{parseArgs as Ee}from"util";var{$:xe}=globalThis.Bun;var yr=k({prefix:"hydra"}).child("status");async function ti(){let r=await $e(),{directory:n,token:t,url:o,json:e}=r;if(!t||!o)throw new Error("Token (-t) and URL (-u) parameters are required");let s=Q();s.start("Fetching runner status...");try{let i=await _e(n),a=await Oe(o,t),f=ke(i,a);if(s.stop("Runner status fetched"),e)yr.info(JSON.stringify(f,null,2));else ve(f)}catch(i){throw s.stop("Failed to fetch runner status"),i}}async function $e(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:e}=await Promise.resolve().then(() => (j(),Z));e("status"),process.exit(0)}let{values:n}=Ee({args:r,options:{config:{short:"c",type:"string"},directory:{default:`${process.cwd()}/gh-runners`,short:"d",type:"string"},json:{default:!1,short:"j",type:"boolean"},profile:{short:"p",type:"string"},token:{short:"t",type:"string"},url:{short:"u",type:"string"}},strict:!0}),t=await q({configPath:n.config}),o=await B(t,n.profile);return{directory:n.directory||o?.directory||`${process.cwd()}/gh-runners`,json:n.json,token:n.token||o?.token||process.env.GITHUB_TOKEN||process.env.RUNNER_TOKEN,url:n.url||o?.url}}async function _e(r){let n=`${r}/machines`;return await mr(async()=>{return(await xe`ls ${n} 2>/dev/null || true`.quiet()).stdout.toString().trim().split(`
|
|
95
|
+
`).filter(Boolean)},{fallback:()=>{},logLevel:"debug",message:"No local runners found"})||[]}async function Oe(r,n){let t=r.match(/github\.com[:/]([^/]+)(?:\/([^/.]+))?/);if(!t)throw new Error("Invalid GitHub URL");let[,o,e]=t,s=e?`https://api.github.com/repos/${o}/${e}/actions/runners`:`https://api.github.com/orgs/${o}/actions/runners`;return Cr(async()=>{let i={Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${n}`},a=await fetch(s,{headers:i});if(!a.ok)throw new Error(`GitHub API error: ${a.status} ${a.statusText}`);return await a.json()},{onRetry:(i,a)=>{m.warn(`Retrying GitHub API call (attempt ${i}): ${a.message}`)}})}function ke(r,n){let t=[],o=new Map(n.runners.map((e)=>[e.name,e]));for(let e of r){let s=`runner-${e}`,i=o.get(s);if(i)t.push({busy:i.busy,labels:i.labels.map((a)=>a.name),name:s,os:i.os,status:i.busy?"busy":i.status==="online"?"online":"offline"});else t.push({busy:!1,labels:[],name:s,os:"unknown",status:"offline"})}return t}function ve(r){if(r.length===0){m.info("No runners found");return}yr.info("Runner Status:"),yr.info("\u2500".repeat(80));let n={busy:y.busy,offline:y.offline,online:y.online};for(let o of r){let e=n[o.status],s=o.status.toUpperCase().padEnd(7);yr.info(`${e("\u25CF")} ${e(s)} ${y.value(o.name.padEnd(20))} ${y.dim(`OS: ${o.os.padEnd(10)}`)} ${o.labels.length>0?y.dim(`Labels: ${o.labels.join(", ")}`):""}`)}yr.info("\u2500".repeat(80));let t={busy:r.filter((o)=>o.status==="busy").length,offline:r.filter((o)=>o.status==="offline").length,online:r.filter((o)=>o.status==="online").length,total:r.length};yr.info(`Summary: Total: ${t.total} | ${y.online(`Online: ${t.online}`)} | ${y.busy(`Busy: ${t.busy}`)} | ${y.offline(`Offline: ${t.offline}`)}`)}L();G();import{homedir as ii}from"os";import{join as Nn}from"path";import{parseArgs as Te}from"util";var Vr={global:Nn(ii(),".hydra","templates.json"),local:"./hydra-templates.json"};async function Ne(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:o}=await Promise.resolve().then(() => (j(),Z));o("template"),process.exit(0)}let{values:n}=Te({args:r,options:{action:{default:"list",short:"a",type:"string"},force:{default:!1,short:"f",type:"boolean"},from:{short:"F",type:"string"},global:{default:!1,short:"g",type:"boolean"},name:{short:"n",type:"string"}},strict:!0}),t=n.action;if(t&&!["list","create","use","delete","show"].includes(t))throw new Error(`Unknown action: ${t}`);return{action:t,force:n.force,from:n.from,global:n.global,name:n.name}}async function oi(){let r=await Ne();if(!r.action)r.action=await tr({message:"What would you like to do?",options:[{label:"List templates",value:"list"},{label:"Create a new template",value:"create"},{label:"Use a template",value:"use"},{label:"Show template details",value:"show"},{label:"Delete a template",value:"delete"}]});switch(r.action){case"list":await Ie();break;case"create":await Ae(r);break;case"use":await He(r);break;case"show":await Se(r);break;case"delete":await Ce(r);break;default:m.error(`Unknown action: ${r.action}`),m.info("Available actions: list, create, use, show, delete")}}async function rr(r){let n=r?Vr.global:Vr.local,t=Bun.file(n);if(!await t.exists())return{templates:{},version:"1.0"};try{return await t.json()}catch{return{templates:{},version:"1.0"}}}async function ei(r,n){let t=n?Vr.global:Vr.local;if(n){let o=Nn(ii(),".hydra");await Bun.write(Nn(o,".gitkeep"),"")}await Bun.write(t,JSON.stringify(r,null,2))}async function Ie(){let r=await rr(!0),n=await rr(!1),t={...r.templates,...n.templates};if(Object.keys(t).length===0){m.info("No templates found"),m.info(""),m.info("Create a template with: hydra template create");return}m.info(y.value("Available Templates:")),m.info("");for(let[o,e]of Object.entries(t)){let i=o in r.templates?y.dim(" (global)"):"";if(m.info(` ${y.value(o)}${i}`),e.description)m.info(` ${y.dim(e.description)}`);if(e.extends)m.info(` ${y.dim(`Extends: ${e.extends}`)}`);let a=[];if(e.numberOfMachines)a.push(`machines: ${e.numberOfMachines}`);if(e.os)a.push(`os: ${e.os}`);if(e.labels)a.push(`labels: ${e.labels}`);if(a.length>0)m.info(` ${y.dim(a.join(", "))}`);m.info("")}}async function Ae(r){let n=r.name||await T({message:"Template name:",placeholder:"my-template",validate:(c)=>{if(!c)return"Template name is required";if(!/^[a-zA-Z0-9-_]+$/.test(c))return"Template name can only contain letters, numbers, hyphens, and underscores";return}}),t=await rr(r.global??!1);if(!r.force&&n in t.templates){if(!await S({initialValue:!1,message:`Template '${n}' already exists. Overwrite?`})){m.info("Template creation cancelled");return}}let o=await T({message:"Description (optional):",placeholder:"Template for production runners"}),e={};if(r.from){let c=t.templates[r.from];if(c)e={...c},delete e.name,delete e.description,delete e.metadata,delete e.extends}let s=await T({initialValue:e.numberOfMachines?.toString()||"1",message:"Number of machines:",placeholder:e.numberOfMachines?.toString()||"1"}),i=await tr({initialValue:e.os||"osx",message:"Operating system:",options:[{label:"macOS",value:"osx"},{label:"Linux",value:"linux"},{label:"Windows",value:"windows"}]}),a=await T({initialValue:e.labels,message:"Labels (comma-separated, optional):",placeholder:e.labels||"self-hosted,x64"}),f=await T({initialValue:e.directory||"./gh-runners",message:"Runner directory:",placeholder:e.directory||"./gh-runners"}),d={description:o||void 0,directory:f,extends:r.from||void 0,labels:a||void 0,metadata:{author:process.env.USER||void 0,created:new Date().toISOString(),updated:new Date().toISOString()},name:n,numberOfMachines:Number.parseInt(s,10),os:i};t.templates[n]=d,await ei(t,r.global??!1),m.success(`Template '${n}' created successfully`),m.info(""),m.info(`Use it with: hydra create --template ${n}`)}async function He(r){let n=await rr(!0),t=await rr(!1),o={...n.templates,...t.templates};if(Object.keys(o).length===0){m.error("No templates found"),m.info("Create a template with: hydra template create");return}let e=r.name||await tr({message:"Select a template:",options:Object.entries(o).map(([f,d])=>({label:`${f}${d.description?` - ${d.description}`:""}`,value:f}))}),s=o[e];if(!s){m.error(`Template '${e}' not found`);return}let i=await In(s,o);if(m.info(""),m.info(y.value(`Using template: ${e}`)),m.info(""),m.info("This will create runners with the following configuration:"),m.info(` Number of machines: ${i.numberOfMachines||1}`),m.info(` OS: ${i.os||"osx"}`),m.info(` Directory: ${i.directory||"./gh-runners"}`),i.labels)m.info(` Labels: ${i.labels}`);m.info("");let a=await tr({message:"Where should this configuration be saved?",options:[{label:"Create hydra.json in current directory",value:"json"},{label:"Create hydra.toml in current directory",value:"toml"},{label:"Just show the command",value:"command"}]});if(a==="command"){let f=[];if(i.numberOfMachines)f.push(`-m ${i.numberOfMachines}`);if(i.os)f.push(`-s ${i.os}`);if(i.directory)f.push(`-d "${i.directory}"`);if(i.labels)f.push(`-l "${i.labels}"`);if(i.name)f.push(`-n "${i.name}"`);m.info("Run the following command:"),m.info(""),m.info(y.value(`hydra create ${f.join(" ")} -t <TOKEN> -u <URL>`)),m.info("")}else{let f={defaultProfile:"default",profiles:{default:i}},d=a==="json"?"hydra.json":"hydra.toml";if(a==="json")await Bun.write(d,JSON.stringify(f,null,2));else{let c=`defaultProfile = "default"
|
|
111
96
|
|
|
112
97
|
[profiles.default]
|
|
113
|
-
`;for(let[
|
|
114
|
-
`;else
|
|
115
|
-
`;await Bun.write(
|
|
116
|
-
Attempting to fix configuration issues...`),await
|
|
117
|
-
Stopping watch mode...`),o.close(),process.exit(0)}),await new Promise(()=>{})}q();O();G();V();import{parseArgs as mf}from"util";G();var _e=$({prefix:"queue-monitor"}),kn="https://api.github.com",ff=30000,uf=300000;class nr{config;intervalId=null;metrics={averageWaitTime:0,completedJobs:0,jobsByLabel:new Map,oldestJobAge:0,queuedJobs:0,runningJobs:0};listeners=new Map;constructor(t){this.config=t}async start(){_e.info("Starting queue monitor"),await this.updateMetrics(),this.intervalId=setInterval(()=>this.updateMetrics(),this.config.pollingInterval||ff)}stop(){if(this.intervalId)clearInterval(this.intervalId),this.intervalId=null,_e.info("Queue monitor stopped")}onMetricsUpdate(t){let e=Math.random().toString(36).substring(7);return this.listeners.set(e,t),()=>this.listeners.delete(e)}getMetrics(){return{...this.metrics}}async updateMetrics(){try{let t=await this.fetchQueuedJobs(),e=Date.now(),n=0,i=0,r=new Map,s=0,o=0,a=0;for(let f of t){switch(f.status){case"queued":{s++;let u=e-new Date(f.created_at||e).getTime();n+=u,i=Math.max(i,u);break}case"in_progress":o++;break;case"completed":a++;break}for(let u of f.labels)r.set(u,(r.get(u)||0)+1)}this.metrics={averageWaitTime:s>0?n/s:0,completedJobs:a,jobsByLabel:r,oldestJobAge:i,queuedJobs:s,runningJobs:o},_e.debug(`Updated metrics: ${s} queued, ${o} running`);for(let f of Array.from(this.listeners.values()))f(this.getMetrics())}catch(t){_e.error("Failed to update queue metrics:",t)}}async fetchQueuedJobs(){let t={Accept:"application/vnd.github.v3+json",Authorization:`Bearer ${this.config.token}`,"User-Agent":"Hydra-Runner-Manager"},e=this.config.repo?`${kn}/repos/${this.config.owner}/${this.config.repo}/actions/runs`:`${kn}/orgs/${this.config.owner}/actions/runs`,i=(await this.fetchPaginated(e,t)).filter((s)=>{return Date.now()-new Date(s.created_at).getTime()<uf&&(s.status==="queued"||s.status==="in_progress")}),r=[];for(let s of i){let o=`${kn}/repos/${this.config.owner}/${this.config.repo||s.repository?.name}/actions/runs/${s.id}/jobs`,a=await this.fetchPaginated(o,t),f=this.config.labels?a.filter((u)=>u.labels.some((p)=>this.config.labels?.includes(p))):a;r.push(...f)}return r}async fetchPaginated(t,e){let n=[],i=t;while(i){let r=await fetch(i,{headers:e});if(!r.ok)throw new Error(`GitHub API error: ${r.status} ${r.statusText}`);let s=await r.json();n.push(...s.workflow_runs||s.jobs||[]);let o=r.headers.get("link");i=this.getNextPageUrl(o)}return n}getNextPageUrl(t){if(!t)return null;let n=t.split(",").map((r)=>r.trim()).find((r)=>r.includes('rel="next"'));if(!n)return null;return n.match(/<([^>]+)>/)?.[1]||null}}async function ir(t,e){let i=new URL(t.url||"").pathname.split("/").filter(Boolean),r={labels:t.labels?.split(",").map((s)=>s.trim()),owner:i[0]||"",repo:i[1]||"",token:e};return new nr(r)}G();var or=$({prefix:"scaling-engine"}),cf=2,pf=60000,rr=300000,hf=120000,sr=5;class ar{config;lastScaleAction=null;currentRunnerCount=0;runnerStatuses=new Map;constructor(t,e){this.config=t;this.currentRunnerCount=t.minRunners}analyzeMetrics(t){if(this.isInCoolDown())return{action:"no-change",delta:0,reason:"Cooling down after recent scaling action",targetCount:this.currentRunnerCount};let e=this.config.scaleUpThreshold||cf,n=this.calculateUtilization();if(t.queuedJobs>e||t.averageWaitTime>pf)return this.recommendScaleUp(t);if(n<(this.config.targetUtilization||0.3)&&this.currentRunnerCount>this.config.minRunners)return this.recommendScaleDown();return{action:"no-change",delta:0,reason:"Metrics within acceptable range",targetCount:this.currentRunnerCount}}updateRunnerStatus(t,e){let n=this.runnerStatuses.get(t)||{id:t,labels:[],lastActivity:new Date,name:e.name||t,status:"idle"};this.runnerStatuses.set(t,{...n,...e,lastActivity:e.lastActivity||new Date})}removeRunner(t){this.runnerStatuses.delete(t),this.currentRunnerCount=Math.max(0,this.currentRunnerCount-1)}applyScalingDecision(t){if(t.action==="no-change")return;this.currentRunnerCount=t.targetCount,this.lastScaleAction=new Date,or.info(`Applied scaling decision: ${t.action} by ${t.delta} runners`),or.info(`New runner count: ${this.currentRunnerCount}`)}getIdleRunners(){let t=Date.now()-rr;return Array.from(this.runnerStatuses.values()).filter((e)=>e.status==="idle"&&e.lastActivity.getTime()<t)}recommendScaleUp(t){let e=Math.ceil(t.queuedJobs/2),n=Math.min(e-this.currentRunnerCount,sr);if(n=Math.min(n,this.config.maxRunners-this.currentRunnerCount),n<=0)return{action:"no-change",delta:0,reason:"Already at maximum runner capacity",targetCount:this.currentRunnerCount};return{action:"scale-up",delta:n,reason:`Queue depth: ${t.queuedJobs}, Wait time: ${Math.round(t.averageWaitTime/1000)}s`,targetCount:this.currentRunnerCount+n}}recommendScaleDown(){let t=this.getIdleRunners();if(t.length===0)return{action:"no-change",delta:0,reason:"No idle runners to remove",targetCount:this.currentRunnerCount};let e=Math.min(t.length,this.currentRunnerCount-this.config.minRunners,sr);if(e<=0)return{action:"no-change",delta:0,reason:"Already at minimum runner capacity",targetCount:this.currentRunnerCount};return{action:"scale-down",delta:e,reason:`${t.length} runners idle for over ${rr/60000} minutes`,targetCount:this.currentRunnerCount-e}}calculateUtilization(){if(this.runnerStatuses.size===0)return 0;return Array.from(this.runnerStatuses.values()).filter((e)=>e.status==="busy").length/this.runnerStatuses.size}isInCoolDown(){if(!this.lastScaleAction)return!1;let t=this.config.coolDownPeriod??hf;if(t===0)return!1;return Date.now()-this.lastScaleAction.getTime()<t}}function lr(t,e){let n={maxRunners:10,minRunners:1,...e};return new ar(n,t)}G();import{createHmac as df}from"crypto";var Ct=$({prefix:"webhook-receiver"}),gf=I({host:X(),path:X(),port:yt(),secret:X()});class fr{config;server=null;eventHandlers=new Map;constructor(t){this.config=t;try{this.config={host:t.host||"0.0.0.0",path:t.path||"/webhook",port:t.port||8080,secret:t.secret},gf(this.config)}catch(e){throw new Error(`Invalid webhook config: ${e}`)}}on(t,e){return this.eventHandlers.set(t,e),this}async start(){if(this.server)throw new Error("Webhook server already running");this.server=Bun.serve({fetch:async(t)=>{if(new URL(t.url).pathname!==this.config.path)return new Response("Not found",{status:404});if(t.method!=="POST")return new Response("Method not allowed",{status:405});try{let n=await t.text(),i=t.headers.get("x-hub-signature-256"),r=t.headers.get("x-github-event"),s=t.headers.get("x-github-delivery");if(!i||!r||!s)return Ct.warn("Missing required GitHub headers"),new Response("Bad request",{status:400});if(!this.verifySignature(n,i))return Ct.error("Invalid webhook signature"),new Response("Unauthorized",{status:401});let o={deliveryId:s,payload:JSON.parse(n),type:r};Ct.info(`Received ${r} webhook event (${s})`);let a=this.eventHandlers.get(r)||this.eventHandlers.get("*");if(a)await a(o);else Ct.debug(`No handler registered for ${r} event`);return new Response(JSON.stringify({status:"ok"}),{headers:{"Content-Type":"application/json"},status:200})}catch(n){return Ct.error("Error processing webhook:",n),new Response("Internal server error",{status:500})}},hostname:this.config.host,port:this.config.port}),Ct.info(`Webhook server listening on ${this.getUrl()}`)}async stop(){if(this.server)this.server.stop(),this.server=null,Ct.info("Webhook server stopped")}getUrl(){return`http://${this.config.host==="0.0.0.0"?"localhost":this.config.host}:${this.config.port}${this.config.path}`}verifySignature(t,e){let n=df("sha256",this.config.secret);n.update(t);let i=`sha256=${n.digest("hex")}`,r=Buffer.from(i),s=Buffer.from(e);if(r.length!==s.length)return!1;return r.equals(s)}}async function ur(t){return new fr(t)}var st=$({prefix:"webhook"});async function cr(){let t=await yf(),e=T();try{e.start("Starting webhook server...");let n=await ur({host:t.host,path:t.path,port:t.port,secret:t.secret});n.on("workflow_job",async(s)=>{let o=s.payload;if(o.action==="queued"){if(st.info(`New job queued: ${o.workflow_job.name}`),st.info(`Labels: ${o.workflow_job.labels.join(", ")}`),t.autoScale)st.info("Auto-scaling triggered - would scale up runners")}else if(o.action==="completed"){if(st.info(`Job completed: ${o.workflow_job.name}`),t.autoScale)st.info("Job completed - checking if scale down needed")}}),n.on("ping",async(s)=>{st.info("Received ping event from GitHub")}),await n.start(),e.stop("Webhook server started");let i=null,r=null;if(t.autoScale&&t.profile){let s=t.token||process.env.GITHUB_PERSONAL_ACCESS_TOKEN;if(s)i=await ir(t.profile,s),r=lr(t.profile,{maxRunners:t.maxRunners,minRunners:t.minRunners}),await i.start(),i.onMetricsUpdate((o)=>{if(st.info(`Queue metrics: ${o.queuedJobs} queued, ${o.runningJobs} running`),r){let a=r.analyzeMetrics(o);if(a.action!=="no-change"){if(st.info(`Scaling recommendation: ${a.action} by ${a.delta} runners - ${a.reason}`),!t.dryRun)st.info("Auto-scaling execution would happen here"),r.applyScalingDecision(a)}}}),n.on("workflow_job",async(o)=>{let a=o.payload;if(a.workflow_job.runner_id&&r)r.updateRunnerStatus(String(a.workflow_job.runner_id),{id:String(a.workflow_job.runner_id),labels:a.workflow_job.labels,name:a.workflow_job.runner_name||"",status:a.action==="in_progress"?"busy":"idle"})});else st.warn("Auto-scaling enabled but no GitHub token provided")}at(`\uD83C\uDFAF Webhook server listening at ${n.getUrl()}`),at("Configure this URL in your GitHub repository or organization webhook settings"),process.on("SIGINT",async()=>{if(st.info("Shutting down webhook server..."),i)i.stop();await n.stop(),process.exit(0)}),await new Promise(()=>{})}catch(n){throw e.stop("Failed to start webhook server"),new nt("Failed to start webhook server","WEBHOOK_START_FAILED",String(n))}}async function yf(){let{values:t}=mf({allowPositionals:!0,args:Bun.argv,options:{autoScale:{default:!1,type:"boolean"},dryRun:{default:!1,type:"boolean"},host:{default:"0.0.0.0",type:"string"},maxRunners:{default:"10",type:"string"},minRunners:{default:"1",type:"string"},path:{default:"/webhook",type:"string"},port:{default:"8080",short:"p",type:"string"},profile:{short:"P",type:"string"},secret:{short:"s",type:"string"},token:{short:"t",type:"string"}},strict:!0}),e=await N({profile:t.profile}),n=await S(e,t.profile),i=t.secret||process.env.GITHUB_WEBHOOK_SECRET;if(!i)throw new Error("Webhook secret is required. Use --secret or set GITHUB_WEBHOOK_SECRET env var");return{autoScale:t.autoScale,dryRun:t.dryRun,host:t.host,maxRunners:Number.parseInt(t.maxRunners,10),minRunners:Number.parseInt(t.minRunners,10),path:t.path,port:Number.parseInt(t.port,10),profile:n,secret:i,token:t.token}}L.register(dn);L.register(xn);L.register($n);Te(()=>{po(),ho()});var ee=["create","run","remove","logs","health","scale","backup","plugin","pool","watch","validate","dev","monitor","migrate","template","recovery","webhook"],bf=[...L.getNames(),...ee],te=$({prefix:"hydra"}),wf={auto:"scale",autoscale:"scale",b:"backup",back:"backup",bak:"backup",c:"create",ceate:"create",check:"health",craete:"create",cretae:"create",del:"remove",delete:"remove",diagnose:"health",h:"help",heal:"health",healthy:"health",i:"init",info:"status",initialise:"init",inti:"init",intialize:"init",l:"logs",list:"status",log:"logs",ls:"status",m:"monitor",mig:"migrate",mon:"monitor",new:"create",r:"run",rec:"recovery",recover:"recovery",remvoe:"remove",resize:"scale",restore:"backup",rm:"remove",rmove:"remove",rnu:"run",runn:"run",s:"status",save:"backup",scal:"scale",start:"run",stat:"status",stop:"remove",sttaus:"status",t:"troubleshoot",tail:"logs",temp:"template",templ:"template"};async function xf(){let t=new Sn,e="",n,i;try{let s=await wo(new Map([["logger",te],["registry",L]])),o=_n();if(Te(()=>{o.emit("hydra:startup",{version:St})}),{command:n,needsHelp:i}=vo(process.argv),t.mark("commandParseTime"),n==="version")console.log(St),t.logMetrics(),process.exit(0);if($o()){let{checkAndNotify:u}=await Promise.resolve().then(() => (O(),ki));Te(()=>u("@r5n/hydra",St),100)}if(i&&!n){let u=L.get("help");if(u)await u.execute();process.exit(0)}e=n||"";let a=s.getCommand(n||"");if(!a&&n?.includes(":"))a=s.getAllCommands().find((p)=>p.name===n);if(!a&&n&&!L.has(n)&&!ee.includes(n)){let u=sn(n,wf);if(u&&(L.has(u)||ee.includes(u)))e=u,te.warn(`Assuming you meant '${u}'`)}if(!a&&!L.has(e)&&!ee.includes(e)){te.error(`Unknown command: ${n}`);let u=[...bf,...s.getAllCommands().map((g)=>g.name)],p=n?rn(n,u):[];if(p.length>0){te.error("Did you mean one of these?");for(let g of p)te.error(` ${g}`)}let d=L.get("help");if(d)await d.execute();process.exit(1)}if(i&&n){let u=L.get("help");if(u){let p=process.argv;process.argv=[process.argv[0]||"node",process.argv[1]||"hydra","help",e||""],await u.execute(),process.argv=p}process.exit(0)}t.mark("registrationTime");let f=L.get(e);if(!f&&!ee.includes(e))f=await On(e)||void 0;if(t.mark("executionStartTime"),o.emit("hydra:beforeCommand",{command:e||n}),a)await a.execute(process.argv.slice(3));else if(f)await f.execute();else switch(e){case"create":await zt();break;case"run":await En();break;case"remove":await Yt();break;case"logs":await _o();break;case"health":await Oo();break;case"scale":await Xo();break;case"backup":await Ro();break;case"plugin":await Uo();break;case"pool":await Go();break;case"watch":await er();break;case"validate":await tr();break;case"dev":await Eo();break;case"monitor":await Wo();break;case"migrate":await Mo();break;case"template":await zo();break;case"recovery":await jo();break;case"webhook":await cr();break;default:throw new Error(`Unknown command: ${e}`)}o.emit("hydra:afterCommand",{command:e||n}),t.logMetrics(),await Nn(),process.exit(0)}catch(r){t.logMetrics(),await Nn(),mo(r,{command:e||n||""})}}await xf();
|
|
98
|
+
`;for(let[u,l]of Object.entries(i))if(l!==void 0&&l!==null)if(typeof l==="string")c+=`${u} = "${l}"
|
|
99
|
+
`;else c+=`${u} = ${l}
|
|
100
|
+
`;await Bun.write(d,c)}m.success(`Created ${d}`),m.info(""),m.info("Now run:"),m.info(y.value("hydra create -t <TOKEN> -u <URL>"))}}async function Se(r){let n=await rr(!0),t=await rr(!1),o={...n.templates,...t.templates},e=r.name||await tr({message:"Select a template:",options:Object.entries(o).map(([a,f])=>({label:`${a}${f.description?` - ${f.description}`:""}`,value:a}))}),s=o[e];if(!s){m.error(`Template '${e}' not found`);return}let i=await In(s,o);if(m.info(""),m.info(y.value(`Template: ${e}`)),m.info("\u2500".repeat(40)),s.description)m.info(`Description: ${s.description}`);if(s.extends)m.info(`Extends: ${s.extends}`);if(s.metadata){if(s.metadata.author)m.info(`Author: ${s.metadata.author}`);if(s.metadata.created)m.info(`Created: ${new Date(s.metadata.created).toLocaleDateString()}`);if(s.metadata.updated)m.info(`Updated: ${new Date(s.metadata.updated).toLocaleDateString()}`);if(s.metadata.tags?.length)m.info(`Tags: ${s.metadata.tags.join(", ")}`)}m.info(""),m.info("Configuration:"),m.info(JSON.stringify(i,null,2))}async function Ce(r){let n=await rr(r.global??!1);if(Object.keys(n.templates).length===0){m.error("No templates found");return}let t=r.name||await tr({message:"Select a template to delete:",options:Object.entries(n.templates).map(([o,e])=>({label:`${o}${e.description?` - ${e.description}`:""}`,value:o}))});if(!(t in n.templates)){m.error(`Template '${t}' not found`);return}if(!r.force){if(!await S({initialValue:!1,message:`Are you sure you want to delete template '${t}'?`})){m.info("Deletion cancelled");return}}delete n.templates[t],await ei(n,r.global??!1),m.success(`Template '${t}' deleted`)}async function In(r,n,t=new Set){if(t.has(r.name))throw new Error(`Circular template dependency detected: ${r.name}`);t.add(r.name);let o={};if(r.extends){let d=n[r.extends];if(d)o=await In(d,n,t)}let{name:e,description:s,extends:i,metadata:a,...f}=r;return{...o,...f}}L();G();import{parseArgs as Ge}from"util";G();P();var si=k({prefix:"config-validator"});class ai{validateConfig(r){let n={errors:[],valid:!0,warnings:[]};if(!r||typeof r!=="object")return n.valid=!1,n.errors.push({code:"INVALID_CONFIG",field:"config",message:"Configuration must be an object"}),n;if(!r.profiles||typeof r.profiles!=="object")return n.valid=!1,n.errors.push({code:"MISSING_PROFILES",field:"profiles",message:"Configuration must have a profiles object"}),n;return this.validateProfiles(r.profiles,n),this.validateDefaultProfile(r.defaultProfile,r.profiles,n),n}validateProfile(r){let n={errors:[],valid:!0,warnings:[]};return this.validateProfileFields(r,n),n}validateProfiles(r,n){if(Object.keys(r).length===0){n.valid=!1,n.errors.push({code:"NO_PROFILES",field:"profiles",message:"At least one profile is required"});return}for(let[o,e]of Object.entries(r)){if(!e||typeof e!=="object"){n.valid=!1,n.errors.push({code:"INVALID_PROFILE",field:`profiles.${o}`,message:"Profile must be an object"});continue}let s=this.validateProfile(e);if(!s.valid)n.valid=!1,n.errors.push(...s.errors.map((i)=>({...i,field:`profiles.${o}.${i.field}`})));n.warnings.push(...s.warnings.map((i)=>({...i,field:`profiles.${o}.${i.field}`})))}}validateDefaultProfile(r,n,t){if(r){if(!n[r])t.valid=!1,t.errors.push({code:"DEFAULT_PROFILE_NOT_FOUND",field:"defaultProfile",message:`Default profile "${r}" not found in profiles`})}}validateProfileFields(r,n){if(r.numberOfMachines!==void 0){if(typeof r.numberOfMachines!=="number")n.valid=!1,n.errors.push({code:"INVALID_TYPE",field:"numberOfMachines",message:"Number of machines must be a number"});else if(r.numberOfMachines<1)n.valid=!1,n.errors.push({code:"INVALID_NUMBER_OF_MACHINES",field:"numberOfMachines",message:"Number of machines must be at least 1"});else if(r.numberOfMachines>100)n.warnings.push({code:"LARGE_NUMBER_OF_MACHINES",field:"numberOfMachines",message:"Large number of machines may impact performance"})}if(r.os!==void 0){let t=["osx","linux","windows"];if(!t.includes(r.os))n.valid=!1,n.errors.push({code:"INVALID_OS",field:"os",message:`Invalid OS "${r.os}". Must be one of: ${t.join(", ")}`})}if(r.directory!==void 0){if(typeof r.directory!=="string")n.valid=!1,n.errors.push({code:"INVALID_TYPE",field:"directory",message:"Directory must be a string"});else if(!r.directory.startsWith("/")&&!r.directory.match(/^[A-Z]:\\/)&&!r.directory.startsWith("./")&&!r.directory.startsWith("~"))n.warnings.push({code:"RELATIVE_PATH_WARNING",field:"directory",message:"Directory path should be absolute or relative (starting with ./ or ~/)"})}if(r.url!==void 0&&typeof r.url==="string")try{if(!new URL(r.url).hostname.includes("github.com"))n.warnings.push({code:"NON_GITHUB_URL",field:"url",message:"URL does not appear to be a GitHub URL"})}catch{n.valid=!1,n.errors.push({code:"INVALID_URL",field:"url",message:"Invalid URL format"})}if(r.token!==void 0&&typeof r.token==="string"){if(r.token.length<10)n.warnings.push({code:"SHORT_TOKEN",field:"token",message:"Token appears to be too short"})}}}function We(){return new ai}function _r(r){return We().validateConfig(r)}function fi(r){let n=_r(r);for(let t of n.errors)si.error(`${t.field}: ${t.message}`);for(let t of n.warnings)si.warn(`${t.field}: ${t.message}`);return n}async function Me(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:t}=await Promise.resolve().then(() => (j(),Z));t("validate"),process.exit(0)}let{values:n}=Ge({args:r,options:{config:{short:"c",type:"string"},fix:{default:!1,short:"f",type:"boolean"},json:{default:!1,short:"j",type:"boolean"}},strict:!0});return{configPath:n.config,fix:n.fix,json:n.json}}async function di(){let r=await Me(),n=r.configPath||await xn();if(!n)throw w.createError("No configuration file found. Create one with: hydra init","CONFIG_ERROR",void 0,{operation:"validate"});if(!await b.exists(n))throw w.createError(`Configuration file not found: ${n}`,"FILE_SYSTEM_ERROR",void 0,{configPath:n,operation:"validate"});m.info(`Validating configuration: ${y.dim(n)}`);try{let t=await b.readFile(n),o=n.endsWith(".toml"),e;if(o)e=Bun.TOML.parse(t);else e=JSON.parse(t);if(r.json){let i=_r(e);console.log(JSON.stringify(i,null,2)),process.exit(i.valid?0:1)}let s=fi(e);if(r.fix&&!s)if(m.info(`
|
|
101
|
+
Attempting to fix configuration issues...`),await Ue(e,n))m.success("Configuration issues fixed and saved");else m.error("Unable to automatically fix all issues"),m.info("Please manually review and update your configuration");process.exit(s?0:1)}catch(t){if(t instanceof SyntaxError)throw w.createError(`Configuration file has syntax errors: ${t.message}`,"CONFIG_ERROR",void 0,{configPath:n,operation:"validate"},t);throw w.handleError(t,{configPath:n,operation:"validate"})}}async function Ue(r,n){let t=_r(r);if(!r.profiles)r.profiles={};for(let e of t.errors){if(e.field==="defaultProfile"&&r.defaultProfile)delete r.defaultProfile,m.info("Removed invalid defaultProfile");if(e.field?.startsWith("profiles.")&&e.field?.includes(".numberOfMachines")){let i=e.field.split(".")[1];if(i&&r.profiles[i]){let a=r.profiles[i].numberOfMachines,f=Number.parseInt(String(a),10);if(Number.isNaN(f)||f<1)r.profiles[i].numberOfMachines="1",m.info(`Fixed numberOfMachines for profile '${i}'`)}}if(e.field?.startsWith("profiles.")&&e.field?.includes(".labels")){let i=e.field.split(".")[1];if(i&&r.profiles[i]&&r.profiles[i].labels){let a=r.profiles[i].labels.split(",").map((f)=>f.trim()).filter((f)=>f.match(/^[a-zA-Z0-9\-_]+$/)).join(",");r.profiles[i].labels=a,m.info(`Fixed labels for profile '${i}'`)}}}if(_r(r).valid){let s=n.endsWith(".toml")?JSON.stringify(r,null,2):JSON.stringify(r,null,2);return await b.writeFile(n,s),!0}return!1}L();G();import{watch as Pe}from"fs";import{parseArgs as Le}from"util";var nr=x({prefix:"watch"});async function qe(){let r=process.argv.slice(3);if(r.includes("--help")||r.includes("-h")){let{help:s}=await Promise.resolve().then(() => (j(),Z));s("watch"),process.exit(0)}let{values:n}=Le({args:r,options:{command:{default:"status",short:"C",type:"string"},config:{short:"c",type:"string"},debounce:{default:"1000",type:"string"},directory:{default:"./gh-runners",short:"d",type:"string"},exclude:{default:[],multiple:!0,type:"string"},profile:{short:"p",type:"string"}},strict:!0}),t=await q({configPath:n.config}),o=await B(t,n.profile);return Pt(o,{command:n.command,debounce:Number.parseInt(n.debounce,10),directory:n.directory,exclude:n.exclude})}async function ci(){let r=await qe();if(!await b.exists(r.directory))nr.error(`Directory not found: ${r.directory}`),process.exit(1);nr.info(`Watching ${r.directory} for changes...`),nr.info(`Will run: hydra ${r.command}`),nr.info(`Debounce: ${r.debounce}ms`);let n=Q(),t=null,o=!1,e=async()=>{if(o)return;o=!0,n.start(`Running: hydra ${r.command}`);try{let{$:a}=awaitPromise.resolve(globalThis.Bun),f=await a`hydra ${r.command} -d ${r.directory}`.quiet();if(f.exitCode===0)n.stop(y.success("\u2713 Command completed successfully"));else n.stop(y.error(`\u2717 Command failed with exit code ${f.exitCode}`)),nr.error(f.stderr.toString())}catch(a){n.stop(y.error("\u2717 Command failed")),nr.error("Error running command:",a)}finally{o=!1}},s=(a,f)=>{if(!f)return;if(r.exclude.some((c)=>{if(c.includes("*"))return new RegExp(c.replace(/\*/g,".*")).test(f);return f.includes(c)}))return;if(nr.info(`Detected ${a}: ${f}`),t)clearTimeout(t);t=setTimeout(()=>{e()},r.debounce)};await e();let i=Pe(r.directory,{recursive:!0},s);process.on("SIGINT",()=>{nr.info(`
|
|
102
|
+
Stopping watch mode...`),i.close(),process.exit(0)}),await new Promise(()=>{})}var An={benchmark:Ct,create:zt,health:Yt,help:async()=>Br(),init:Xt,migrate:Ft,remove:ri,run:ni,status:ti,template:oi,validate:di,watch:ci},Be={b:"benchmark",c:"create",h:"help",i:"init",r:"run",rm:"remove",s:"status",w:"watch"};async function je(){let n=process.argv.slice(2)[0]?.toLowerCase();if(!n||n==="--help"||n==="-h")Br(),process.exit(0);if(n==="--version"||n==="-v"||n==="version")console.log(kr),process.exit(0);let t=Be[n]||n,o=An[t];if(!o)console.error(`Unknown command: ${n}`),console.error(`
|
|
103
|
+
Available commands: ${Object.keys(An).sort().join(", ")}`),process.exit(1);let e=["benchmark","create","health","help","init","migrate","remove","run","status","template","validate","watch"];for(let s of e)if(!(s in An))throw new Error(`Missing command implementation: ${s}`);try{await o()}catch(s){let i=w.handleError(s,{command:t});if(console.error(w.formatError(i)),process.env.DEBUG||process.env.HYDRA_DEBUG)console.error(`
|
|
104
|
+
Debug Information:`),console.error(w.formatDebugError(i));process.exit(1)}}await je();
|