@ooneex/cli 1.8.3 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +184 -261
- package/dist/index.js.map +21 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var
|
|
4
|
-
`),l=a.length;if(l>0&&a.includes("unstyle"))a=[...new Set(["unstyle",...a])].reverse();while(l-- >0)n=s(e.styles[a[l]],n,d);return n},o=(i,a,n)=>{e.styles[i]=t({name:i,codes:a}),(e.keys[n]||(e.keys[n]=[])).push(i),Reflect.defineProperty(e,i,{configurable:!0,enumerable:!0,set(l){e.alias(i,l)},get(){let l=(
|
|
5
|
-
`+s,width:o=80}=t,i=(r+s).match(/[^\S\n]/g)||[];o-=i.length;let a=`.{1,${o}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,n=e.trim(),d=new RegExp(a,"g"),l=n.match(d)||[];if(l=l.map((
|
|
6
|
-
`)r.name="enter";else if(e==="\t")r.name="tab";else if(e==="\b"||e==="\x7F"||e==="\x1B\x7F"||e==="\x1B\b")r.name="backspace",r.meta=e.charAt(0)==="\x1B";else if(e==="\x1B"||e==="\x1B\x1B")r.name="escape",r.meta=e.length===2;else if(e===" "||e==="\x1B ")r.name="space",r.meta=e.length===2;else if(e<="\x1A")r.name=String.fromCharCode(e.charCodeAt(0)+97-1),r.ctrl=!0;else if(e.length===1&&e>="0"&&e<="9")r.name="number";else if(e.length===1&&e>="a"&&e<="z")r.name=e;else if(e.length===1&&e>="A"&&e<="Z")r.name=e.toLowerCase(),r.shift=!0;else if(s=mn.exec(e))r.meta=!0,r.shift=/^[A-Z]$/.test(s[1]);else if(s=pn.exec(e)){let o=[...e];if(o[0]==="\x1B"&&o[1]==="\x1B")r.option=!0;let i=[s[1],s[2],s[4],s[6]].filter(Boolean).join(""),a=(s[3]||s[5]||1)-1;r.ctrl=!!(a&4),r.meta=!!(a&10),r.shift=!!(a&1),r.code=i,r.name=un[i],r.shift=hn(i)||r.shift,r.ctrl=fn(i)||r.ctrl}return r};Ie.listen=(e={},t)=>{let{stdin:s}=e;if(!s||s!==process.stdin&&!s.isTTY)throw Error("Invalid stream passed");let r=ps.createInterface({terminal:!0,input:s});ps.emitKeypressEvents(s,r);let o=new cn((n,d)=>t(n,Ie(n,d),r)),i=s.isRaw;if(s.isTTY)s.setRawMode(!0);return s.on("keypress",o.enqueue),r.resume(),()=>{if(s.isTTY)s.setRawMode(i);s.removeListener("keypress",o.enqueue),o.destroy(),r.pause(),r.close()}};Ie.action=(e,t,s)=>{let r={...ln,...s};if(t.ctrl)return t.action=r.ctrl[t.name],t;if(t.option&&r.option)return t.action=r.option[t.name],t;if(t.shift)return t.action=r.shift[t.name],t;return t.action=r.keys[t.name],t};us.exports=Ie});var fs=w((sp,hs)=>{hs.exports=(e)=>{e.timers=e.timers||{};let t=e.options.timers;if(!t)return;for(let s of Object.keys(t)){let r=t[s];if(typeof r==="number")r={interval:r};yn(e,s,r)}};function yn(e,t,s={}){let r=e.timers[t]={name:t,start:Date.now(),ms:0,tick:0},o=s.interval||120;r.frames=s.frames||[],r.loading=!0;let i=setInterval(()=>{r.ms=Date.now()-r.start,r.tick++,e.render()},o);return r.stop=()=>{r.loading=!1,clearInterval(i)},Reflect.defineProperty(r,"interval",{value:i}),e.once("close",()=>r.stop()),r.stop}});var bs=w((rp,gs)=>{var{define:gn,width:bn}=C();class ys{constructor(e){let t=e.options;gn(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=bn(t.stdout||process.stdout),Object.assign(this,t),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let t=this._color||e[this.status];return typeof t==="function"?t:e.pending}set loading(e){this._loading=e}get loading(){if(typeof this._loading==="boolean")return this._loading;if(this.loadingChoices)return"choices";return!1}get status(){if(this.cancelled)return"cancelled";if(this.submitted)return"submitted";return"pending"}}gs.exports=ys});var ws=w((op,xs)=>{var pt=C(),M=Me(),ut={default:M.noop,noop:M.noop,set inverse(e){this._inverse=e},get inverse(){return this._inverse||pt.inverse(this.primary)},set complement(e){this._complement=e},get complement(){return this._complement||pt.complement(this.primary)},primary:M.cyan,success:M.green,danger:M.magenta,strong:M.bold,warning:M.yellow,muted:M.dim,disabled:M.gray,dark:M.dim.gray,underline:M.underline,set info(e){this._info=e},get info(){return this._info||this.primary},set em(e){this._em=e},get em(){return this._em||this.primary.underline},set heading(e){this._heading=e},get heading(){return this._heading||this.muted.underline},set pending(e){this._pending=e},get pending(){return this._pending||this.primary},set submitted(e){this._submitted=e},get submitted(){return this._submitted||this.success},set cancelled(e){this._cancelled=e},get cancelled(){return this._cancelled||this.danger},set typing(e){this._typing=e},get typing(){return this._typing||this.dim},set placeholder(e){this._placeholder=e},get placeholder(){return this._placeholder||this.primary.dim},set highlight(e){this._highlight=e},get highlight(){return this._highlight||this.inverse}};ut.merge=(e={})=>{if(e.styles&&typeof e.styles.enabled==="boolean")M.enabled=e.styles.enabled;if(e.styles&&typeof e.styles.visible==="boolean")M.visible=e.styles.visible;let t=pt.merge({},ut,e.styles);delete t.merge;for(let s of Object.keys(M))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>M[s]});for(let s of Object.keys(M.styles))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>M[s]});return t};xs.exports=ut});var As=w((ip,Es)=>{var ht=process.platform==="win32",K=Me(),xn=C(),ft={...K.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:K.symbols.check,leftAngle:"\u2039",mark:"\u203B",minus:"\u2212",multiplication:"\xD7",obelus:"\xF7",percent:"%",pilcrow:"\xB6",pilcrow2:"\u2761",pencilUpRight:"\u2710",pencilDownRight:"\u270E",pencilRight:"\u270F",plus:"+",plusMinus:"\xB1",pointRight:"\u261E",rightAngle:"\u203A",section:"\xA7",hexagon:{off:"\u2B21",on:"\u2B22",disabled:"\u2B22"},ballot:{on:"\u2611",off:"\u2610",disabled:"\u2612"},stars:{on:"\u2605",off:"\u2606",disabled:"\u2606"},folder:{on:"\u25BC",off:"\u25B6",disabled:"\u25B6"},prefix:{pending:K.symbols.question,submitted:K.symbols.check,cancelled:K.symbols.cross},separator:{pending:K.symbols.pointerSmall,submitted:K.symbols.middot,cancelled:K.symbols.middot},radio:{off:ht?"( )":"\u25EF",on:ht?"(*)":"\u25C9",disabled:ht?"(|)":"\u24BE"},numbers:["\u24EA","\u2460","\u2461","\u2462","\u2463","\u2464","\u2465","\u2466","\u2467","\u2468","\u2469","\u246A","\u246B","\u246C","\u246D","\u246E","\u246F","\u2470","\u2471","\u2472","\u2473","\u3251","\u3252","\u3253","\u3254","\u3255","\u3256","\u3257","\u3258","\u3259","\u325A","\u325B","\u325C","\u325D","\u325E","\u325F","\u32B1","\u32B2","\u32B3","\u32B4","\u32B5","\u32B6","\u32B7","\u32B8","\u32B9","\u32BA","\u32BB","\u32BC","\u32BD","\u32BE","\u32BF"]};ft.merge=(e)=>{let t=xn.merge({},K.symbols,ft,e.symbols);return delete t.merge,t};Es.exports=ft});var Ns=w((ap,vs)=>{var wn=ws(),En=As(),An=C();vs.exports=(e)=>{e.options=An.merge({},e.options.theme,e.options),e.symbols=En.merge(e.options),e.styles=wn.merge(e.options)}});var Ms=w((Ts,Rs)=>{var Ss=process.env.TERM_PROGRAM==="Apple_Terminal",vn=se(),yt=C(),L=Rs.exports=Ts,gt=!1,re=L.code={bell:"\x07",beep:"\x07",beginning:"\x1B[G",down:"\x1B[J",esc:"\x1B[",getPosition:"\x1B[6n",hide:"\x1B[?25l",line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",restorePosition:"\x1B["+(Ss?"8":"u"),savePosition:"\x1B["+(Ss?"7":"s"),screen:"\x1B[2J",show:"\x1B[?25h",up:"\x1B[1J"},ne=L.cursor={get hidden(){return gt},hide(){return gt=!0,re.hide},show(){return gt=!1,re.show},forward:(e=1)=>`\x1B[${e}C`,backward:(e=1)=>`\x1B[${e}D`,nextLine:(e=1)=>"\x1B[E".repeat(e),prevLine:(e=1)=>"\x1B[F".repeat(e),up:(e=1)=>e?`\x1B[${e}A`:"",down:(e=1)=>e?`\x1B[${e}B`:"",right:(e=1)=>e?`\x1B[${e}C`:"",left:(e=1)=>e?`\x1B[${e}D`:"",to(e,t){return t?`\x1B[${t+1};${e+1}H`:`\x1B[${e+1}G`},move(e=0,t=0){let s="";return s+=e<0?ne.left(-e):e>0?ne.right(e):"",s+=t<0?ne.up(-t):t>0?ne.down(t):"",s},strLen(e){var t=0,s=e.length,r=-1;for(var o=0;o<s;o++)if(r=e.charCodeAt(o),r>=0&&r<=128)t+=1;else t+=2;return t},restore(e={}){let{after:t,cursor:s,initial:r,input:o,prompt:i,size:a,value:n}=e;if(r=yt.isPrimitive(r)?String(r):"",o=yt.isPrimitive(o)?String(o):"",n=yt.isPrimitive(n)?String(n):"",a){let d=L.cursor.up(a)+L.cursor.to(this.strLen(i)),l=o.length-s;if(l>0)d+=L.cursor.left(l);return d}if(n||t){let d=!o&&!!r?-this.strLen(r):-this.strLen(o)+s;if(t)d-=this.strLen(t);if(o===""&&r&&!i.includes(r))d+=this.strLen(r);return L.cursor.move(d)}}},bt=L.erase={screen:re.screen,up:re.up,down:re.down,line:re.line,lineEnd:re.lineEnd,lineStart:re.lineStart,lines(e){let t="";for(let s=0;s<e;s++)t+=L.erase.line+(s<e-1?L.cursor.up(1):"");if(e)t+=L.code.beginning;return t}};L.clear=(e="",t=process.stdout.columns)=>{if(!t)return bt.line+ne.to(0);let s=(i)=>[...vn(i)].length,r=e.split(/\r?\n/),o=0;for(let i of r)o+=1+Math.floor(Math.max(s(i)-1,0)/t);return(bt.line+ne.prevLine()).repeat(o-1)+bt.line+ne.to(0)}});var ue=w((np,_s)=>{var Nn=be("events"),Cs=se(),xt=mt(),Sn=fs(),Tn=bs(),Rn=Ns(),I=C(),de=Ms();class wt extends Nn{constructor(e={}){super();this.name=e.name,this.type=e.type,this.options=e,Rn(this),Sn(this),this.state=new Tn(this),this.initial=[e.initial,e.default].find((t)=>t!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=Cn(this.options.margin),this.setMaxListeners(0),Mn(this)}async keypress(e,t={}){this.keypressed=!0;let s=xt.action(e,xt(e,t),this.options.actions);this.state.keypress=s,this.emit("keypress",e,s),this.emit("state",this.state.clone());let r=this.options[s.action]||this[s.action]||this.dispatch;if(typeof r==="function")return await r.call(this,e,s);this.alert()}alert(){if(delete this.state.alert,this.options.show===!1)this.emit("alert");else this.stdout.write(de.code.beep)}cursorHide(){this.stdout.write(de.cursor.hide());let e=I.onExit(()=>this.cursorShow());this.on("close",()=>{this.cursorShow(),e()})}cursorShow(){this.stdout.write(de.cursor.show())}write(e){if(!e)return;if(this.stdout&&this.state.show!==!1)this.stdout.write(e);this.state.buffer+=e}clear(e=0){let t=this.state.buffer;if(this.state.buffer="",!t&&!e||this.options.show===!1)return;this.stdout.write(de.cursor.down(e)+de.clear(t,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:t,rest:s}=this.sections(),{cursor:r,initial:o="",input:i="",value:a=""}=this,n=this.state.size=s.length,d={after:t,cursor:r,initial:o,input:i,prompt:e,size:n,value:a},l=de.cursor.restore(d);if(l)this.stdout.write(l)}sections(){let{buffer:e,input:t,prompt:s}=this.state;s=Cs(s);let r=Cs(e),o=r.indexOf(s),i=r.slice(0,o),n=r.slice(o).split(`
|
|
7
|
-
`),d=n[0],l=n[n.length-1],u=(s+(t?" "+t:"")).length,
|
|
3
|
+
var ca=Object.create;var{getPrototypeOf:pa,defineProperty:Wt,getOwnPropertyNames:ma}=Object;var ua=Object.prototype.hasOwnProperty;function ha(e){return this[e]}var fa,ya,ee=(e,t,s)=>{var r=e!=null&&typeof e==="object";if(r){var o=t?fa??=new WeakMap:ya??=new WeakMap,i=o.get(e);if(i)return i}s=e!=null?ca(pa(e)):{};let a=t||!e||!e.__esModule?Wt(s,"default",{value:e,enumerable:!0}):s;for(let n of ma(e))if(!ua.call(a,n))Wt(a,n,{get:ha.bind(e,n),enumerable:!0});if(r)o.set(e,a);return a};var x=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var b=function(e,t,s,r){var o=arguments.length,i=o<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,s):r,a;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")i=Reflect.decorate(e,t,s,r);else for(var n=e.length-1;n>=0;n--)if(a=e[n])i=(o<3?a(i):o>3?a(t,s,i):a(t,s))||i;return o>3&&i&&Object.defineProperty(t,s,i),i};var ge=import.meta.require;var Zt=x((Vp,be)=>{var Na=typeof process<"u"&&process.env.TERM_PROGRAM==="Hyper",Sa=typeof process<"u"&&process.platform==="win32",Vt=typeof process<"u"&&process.platform==="linux",nt={ballotDisabled:"\u2612",ballotOff:"\u2610",ballotOn:"\u2611",bullet:"\u2022",bulletWhite:"\u25E6",fullBlock:"\u2588",heart:"\u2764",identicalTo:"\u2261",line:"\u2500",mark:"\u203B",middot:"\xB7",minus:"\uFF0D",multiplication:"\xD7",obelus:"\xF7",pencilDownRight:"\u270E",pencilRight:"\u270F",pencilUpRight:"\u2710",percent:"%",pilcrow2:"\u2761",pilcrow:"\xB6",plusMinus:"\xB1",question:"?",section:"\xA7",starsOff:"\u2606",starsOn:"\u2605",upDownArrow:"\u2195"},Yt=Object.assign({},nt,{check:"\u221A",cross:"\xD7",ellipsisLarge:"...",ellipsis:"...",info:"i",questionSmall:"?",pointer:">",pointerSmall:"\xBB",radioOff:"( )",radioOn:"(*)",warning:"\u203C"}),zt=Object.assign({},nt,{ballotCross:"\u2718",check:"\u2714",cross:"\u2716",ellipsisLarge:"\u22EF",ellipsis:"\u2026",info:"\u2139",questionFull:"\uFF1F",questionSmall:"\uFE56",pointer:Vt?"\u25B8":"\u276F",pointerSmall:Vt?"\u2023":"\u203A",radioOff:"\u25EF",radioOn:"\u25C9",warning:"\u26A0"});be.exports=Sa&&!Na?Yt:zt;Reflect.defineProperty(be.exports,"common",{enumerable:!1,value:nt});Reflect.defineProperty(be.exports,"windows",{enumerable:!1,value:Yt});Reflect.defineProperty(be.exports,"other",{enumerable:!1,value:zt})});var Re=x((Yp,dt)=>{var Ta=(e)=>e!==null&&typeof e==="object"&&!Array.isArray(e),Ra=/[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,Ma=()=>{if(typeof process<"u")return process.env.FORCE_COLOR!=="0";return!1},Qt=()=>{let e={enabled:Ma(),visible:!0,styles:{},keys:{}},t=(i)=>{let a=i.open=`\x1B[${i.codes[0]}m`,n=i.close=`\x1B[${i.codes[1]}m`,d=i.regex=new RegExp(`\\u001b\\[${i.codes[1]}m`,"g");return i.wrap=(l,p)=>{if(l.includes(n))l=l.replace(d,n+a);let u=a+l+n;return p?u.replace(/\r*\n/g,`${n}$&${a}`):u},i},s=(i,a,n)=>{return typeof i==="function"?i(a):i.wrap(a,n)},r=(i,a)=>{if(i===""||i==null)return"";if(e.enabled===!1)return i;if(e.visible===!1)return"";let n=""+i,d=n.includes(`
|
|
4
|
+
`),l=a.length;if(l>0&&a.includes("unstyle"))a=[...new Set(["unstyle",...a])].reverse();while(l-- >0)n=s(e.styles[a[l]],n,d);return n},o=(i,a,n)=>{e.styles[i]=t({name:i,codes:a}),(e.keys[n]||(e.keys[n]=[])).push(i),Reflect.defineProperty(e,i,{configurable:!0,enumerable:!0,set(l){e.alias(i,l)},get(){let l=(p)=>r(p,l.stack);return Reflect.setPrototypeOf(l,e),l.stack=this.stack?this.stack.concat(i):[i],l}})};return o("reset",[0,0],"modifier"),o("bold",[1,22],"modifier"),o("dim",[2,22],"modifier"),o("italic",[3,23],"modifier"),o("underline",[4,24],"modifier"),o("inverse",[7,27],"modifier"),o("hidden",[8,28],"modifier"),o("strikethrough",[9,29],"modifier"),o("black",[30,39],"color"),o("red",[31,39],"color"),o("green",[32,39],"color"),o("yellow",[33,39],"color"),o("blue",[34,39],"color"),o("magenta",[35,39],"color"),o("cyan",[36,39],"color"),o("white",[37,39],"color"),o("gray",[90,39],"color"),o("grey",[90,39],"color"),o("bgBlack",[40,49],"bg"),o("bgRed",[41,49],"bg"),o("bgGreen",[42,49],"bg"),o("bgYellow",[43,49],"bg"),o("bgBlue",[44,49],"bg"),o("bgMagenta",[45,49],"bg"),o("bgCyan",[46,49],"bg"),o("bgWhite",[47,49],"bg"),o("blackBright",[90,39],"bright"),o("redBright",[91,39],"bright"),o("greenBright",[92,39],"bright"),o("yellowBright",[93,39],"bright"),o("blueBright",[94,39],"bright"),o("magentaBright",[95,39],"bright"),o("cyanBright",[96,39],"bright"),o("whiteBright",[97,39],"bright"),o("bgBlackBright",[100,49],"bgBright"),o("bgRedBright",[101,49],"bgBright"),o("bgGreenBright",[102,49],"bgBright"),o("bgYellowBright",[103,49],"bgBright"),o("bgBlueBright",[104,49],"bgBright"),o("bgMagentaBright",[105,49],"bgBright"),o("bgCyanBright",[106,49],"bgBright"),o("bgWhiteBright",[107,49],"bgBright"),e.ansiRegex=Ra,e.hasColor=e.hasAnsi=(i)=>{return e.ansiRegex.lastIndex=0,typeof i==="string"&&i!==""&&e.ansiRegex.test(i)},e.alias=(i,a)=>{let n=typeof a==="string"?e[a]:a;if(typeof n!=="function")throw TypeError("Expected alias to be the name of an existing color (string) or a function");if(!n.stack)Reflect.defineProperty(n,"name",{value:i}),e.styles[i]=n,n.stack=[i];Reflect.defineProperty(e,i,{configurable:!0,enumerable:!0,set(d){e.alias(i,d)},get(){let d=(l)=>r(l,d.stack);return Reflect.setPrototypeOf(d,e),d.stack=this.stack?this.stack.concat(n.stack):n.stack,d}})},e.theme=(i)=>{if(!Ta(i))throw TypeError("Expected theme to be an object");for(let a of Object.keys(i))e.alias(a,i[a]);return e},e.alias("unstyle",(i)=>{if(typeof i==="string"&&i!=="")return e.ansiRegex.lastIndex=0,i.replace(e.ansiRegex,"");return""}),e.alias("noop",(i)=>i),e.none=e.clear=e.noop,e.stripColor=e.unstyle,e.symbols=Zt(),e.define=o,e};dt.exports=Qt();dt.exports.create=Qt});var M=x((_a)=>{var Ca=Object.prototype.toString,D=Re(),Xt=!1,we=new Set,Jt={yellow:"blue",cyan:"red",green:"magenta",black:"white",blue:"yellow",red:"cyan",magenta:"green",white:"black"};_a.longest=(e,t)=>{return e.reduce((s,r)=>Math.max(s,t?r[t].length:r.length),0)};_a.hasColor=(e)=>!!e&&D.hasColor(e);var Me=_a.isObject=(e)=>{return e!==null&&typeof e==="object"&&!Array.isArray(e)};_a.nativeType=(e)=>{return Ca.call(e).slice(8,-1).toLowerCase().replace(/\s/g,"")};_a.isAsyncFn=(e)=>{return _a.nativeType(e)==="asyncfunction"};_a.isPrimitive=(e)=>{return e!=null&&typeof e!=="object"&&typeof e!=="function"};_a.resolve=(e,t,...s)=>{if(typeof t==="function")return t.call(e,...s);return t};_a.scrollDown=(e=[])=>[...e.slice(1),e[0]];_a.scrollUp=(e=[])=>[e.pop(),...e];_a.reorder=(e=[])=>{let t=e.slice();return t.sort((s,r)=>{if(s.index>r.index)return 1;if(s.index<r.index)return-1;return 0}),t};_a.swap=(e,t,s)=>{let r=e.length,o=s===r?0:s<0?r-1:s,i=e[t];e[t]=e[o],e[o]=i};_a.width=(e,t=80)=>{let s=e&&e.columns?e.columns:t;if(e&&typeof e.getWindowSize==="function")s=e.getWindowSize()[0];if(process.platform==="win32")return s-1;return s};_a.height=(e,t=20)=>{let s=e&&e.rows?e.rows:t;if(e&&typeof e.getWindowSize==="function")s=e.getWindowSize()[1];return s};_a.wordWrap=(e,t={})=>{if(!e)return e;if(typeof t==="number")t={width:t};let{indent:s="",newline:r=`
|
|
5
|
+
`+s,width:o=80}=t,i=(r+s).match(/[^\S\n]/g)||[];o-=i.length;let a=`.{1,${o}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,n=e.trim(),d=new RegExp(a,"g"),l=n.match(d)||[];if(l=l.map((p)=>p.replace(/\n$/,"")),t.padEnd)l=l.map((p)=>p.padEnd(o," "));if(t.padStart)l=l.map((p)=>p.padStart(o," "));return s+l.join(r)};_a.unmute=(e)=>{let t=e.stack.find((r)=>D.keys.color.includes(r));if(t)return D[t];if(e.stack.find((r)=>r.slice(2)==="bg"))return D[t.slice(2)];return(r)=>r};_a.pascal=(e)=>e?e[0].toUpperCase()+e.slice(1):"";_a.inverse=(e)=>{if(!e||!e.stack)return e;let t=e.stack.find((r)=>D.keys.color.includes(r));if(t){let r=D["bg"+_a.pascal(t)];return r?r.black:e}let s=e.stack.find((r)=>r.slice(0,2)==="bg");if(s)return D[s.slice(2).toLowerCase()]||e;return D.none};_a.complement=(e)=>{if(!e||!e.stack)return e;let t=e.stack.find((r)=>D.keys.color.includes(r)),s=e.stack.find((r)=>r.slice(0,2)==="bg");if(t&&!s)return D[Jt[t]||t];if(s){let r=s.slice(2).toLowerCase(),o=Jt[r];if(!o)return e;return D["bg"+_a.pascal(o)]||e}return D.none};_a.meridiem=(e)=>{let t=e.getHours(),s=e.getMinutes(),r=t>=12?"pm":"am";t=t%12;let o=t===0?12:t,i=s<10?"0"+s:s;return o+":"+i+" "+r};_a.set=(e={},t="",s)=>{return t.split(".").reduce((r,o,i,a)=>{let n=a.length-1>i?r[o]||{}:s;if(!_a.isObject(n)&&i<a.length-1)n={};return r[o]=n},e)};_a.get=(e={},t="",s)=>{let r=e[t]==null?t.split(".").reduce((o,i)=>o&&o[i],e):e[t];return r==null?s:r};_a.mixin=(e,t)=>{if(!Me(e))return t;if(!Me(t))return e;for(let s of Object.keys(t)){let r=Object.getOwnPropertyDescriptor(t,s);if(hasOwnProperty.call(r,"value"))if(hasOwnProperty.call(e,s)&&Me(r.value)){let o=Object.getOwnPropertyDescriptor(e,s);if(Me(o.value)&&o.value!==r.value)e[s]=_a.merge({},e[s],t[s]);else Reflect.defineProperty(e,s,r)}else Reflect.defineProperty(e,s,r);else Reflect.defineProperty(e,s,r)}return e};_a.merge=(...e)=>{let t={};for(let s of e)_a.mixin(t,s);return t};_a.mixinEmitter=(e,t)=>{let s=t.constructor.prototype;for(let r of Object.keys(s)){let o=s[r];if(typeof o==="function")_a.define(e,r,o.bind(t));else _a.define(e,r,o)}};var Ce=(e,t)=>{if(Xt)return;if(Xt=!0,we.forEach((s)=>s()),e===!0)process.exit(128+t)},jt=Ce.bind(null,!0,15),es=Ce.bind(null,!0,2);_a.onExit=(e)=>{if(we.size===0)process.once("SIGTERM",jt),process.once("SIGINT",es),process.once("exit",Ce);return we.add(e),()=>{if(we.delete(e),we.size===0)process.off("SIGTERM",jt),process.off("SIGINT",es),process.off("exit",Ce)}};_a.define=(e,t,s)=>{Reflect.defineProperty(e,t,{value:s})};_a.defineExport=(e,t,s)=>{let r;Reflect.defineProperty(e,t,{enumerable:!0,configurable:!0,set(o){r=o},get(){return r?r():s()}})}});var is=x((Zp,os)=>{os.exports=({onlyFirst:e=!1}={})=>{let t=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(t,e?void 0:"g")}});var te=x((Qp,as)=>{var en=is();as.exports=(e)=>typeof e==="string"?e.replace(en(),""):e});var ns=x((tn)=>{tn.ctrl={a:"first",b:"backward",c:"cancel",d:"deleteForward",e:"last",f:"forward",g:"reset",i:"tab",k:"cutForward",l:"reset",n:"newItem",m:"cancel",j:"submit",p:"search",r:"remove",s:"save",u:"undo",w:"cutLeft",x:"toggleCursor",v:"paste"};tn.shift={up:"shiftUp",down:"shiftDown",left:"shiftLeft",right:"shiftRight",tab:"prev"};tn.fn={up:"pageUp",down:"pageDown",left:"pageLeft",right:"pageRight",delete:"deleteForward"};tn.option={b:"backward",f:"forward",d:"cutRight",left:"cutLeft",up:"altUp",down:"altDown"};tn.keys={pageup:"pageUp",pagedown:"pageDown",home:"home",end:"end",cancel:"cancel",delete:"deleteForward",backspace:"delete",down:"down",enter:"submit",escape:"cancel",left:"left",space:"space",number:"number",return:"submit",right:"right",tab:"next",up:"up"}});var ls=x((Jp,ds)=>{ds.exports=class{_queue=[];_executing=!1;_jobRunner=null;constructor(t){this._jobRunner=t}enqueue=(...t)=>{this._queue.push(t),this._dequeue()};destroy(){this._queue.length=0,this._jobRunner=null}_dequeue(){if(this._executing||!this._queue.length)return;this._executing=!0,this._jobRunner(...this._queue.shift()),setTimeout(()=>{this._executing=!1,this._dequeue()})}}});var ct=x((jp,ps)=>{var cs=ge("readline"),dn=ns(),ln=ls(),cn=/^(?:\x1b)([a-zA-Z0-9])$/,pn=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,mn={OP:"f1",OQ:"f2",OR:"f3",OS:"f4","[11~":"f1","[12~":"f2","[13~":"f3","[14~":"f4","[[A":"f1","[[B":"f2","[[C":"f3","[[D":"f4","[[E":"f5","[15~":"f5","[17~":"f6","[18~":"f7","[19~":"f8","[20~":"f9","[21~":"f10","[23~":"f11","[24~":"f12","[A":"up","[B":"down","[C":"right","[D":"left","[E":"clear","[F":"end","[H":"home",OA:"up",OB:"down",OC:"right",OD:"left",OE:"clear",OF:"end",OH:"home","[1~":"home","[2~":"insert","[3~":"delete","[4~":"end","[5~":"pageup","[6~":"pagedown","[[5~":"pageup","[[6~":"pagedown","[7~":"home","[8~":"end","[a":"up","[b":"down","[c":"right","[d":"left","[e":"clear","[2$":"insert","[3$":"delete","[5$":"pageup","[6$":"pagedown","[7$":"home","[8$":"end",Oa:"up",Ob:"down",Oc:"right",Od:"left",Oe:"clear","[2^":"insert","[3^":"delete","[5^":"pageup","[6^":"pagedown","[7^":"home","[8^":"end","[Z":"tab"};function un(e){return["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(e)}function hn(e){return["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(e)}var _e=(e="",t={})=>{let s,r={name:t.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:e,raw:e,...t};if(Buffer.isBuffer(e))if(e[0]>127&&e[1]===void 0)e[0]-=128,e="\x1B"+String(e);else e=String(e);else if(e!==void 0&&typeof e!=="string")e=String(e);else if(!e)e=r.sequence||"";if(r.sequence=r.sequence||e||r.name,e==="\r")r.raw=void 0,r.name="return";else if(e===`
|
|
6
|
+
`)r.name="enter";else if(e==="\t")r.name="tab";else if(e==="\b"||e==="\x7F"||e==="\x1B\x7F"||e==="\x1B\b")r.name="backspace",r.meta=e.charAt(0)==="\x1B";else if(e==="\x1B"||e==="\x1B\x1B")r.name="escape",r.meta=e.length===2;else if(e===" "||e==="\x1B ")r.name="space",r.meta=e.length===2;else if(e<="\x1A")r.name=String.fromCharCode(e.charCodeAt(0)+97-1),r.ctrl=!0;else if(e.length===1&&e>="0"&&e<="9")r.name="number";else if(e.length===1&&e>="a"&&e<="z")r.name=e;else if(e.length===1&&e>="A"&&e<="Z")r.name=e.toLowerCase(),r.shift=!0;else if(s=cn.exec(e))r.meta=!0,r.shift=/^[A-Z]$/.test(s[1]);else if(s=pn.exec(e)){let o=[...e];if(o[0]==="\x1B"&&o[1]==="\x1B")r.option=!0;let i=[s[1],s[2],s[4],s[6]].filter(Boolean).join(""),a=(s[3]||s[5]||1)-1;r.ctrl=!!(a&4),r.meta=!!(a&10),r.shift=!!(a&1),r.code=i,r.name=mn[i],r.shift=un(i)||r.shift,r.ctrl=hn(i)||r.ctrl}return r};_e.listen=(e={},t)=>{let{stdin:s}=e;if(!s||s!==process.stdin&&!s.isTTY)throw Error("Invalid stream passed");let r=cs.createInterface({terminal:!0,input:s});cs.emitKeypressEvents(s,r);let o=new ln((n,d)=>t(n,_e(n,d),r)),i=s.isRaw;if(s.isTTY)s.setRawMode(!0);return s.on("keypress",o.enqueue),r.resume(),()=>{if(s.isTTY)s.setRawMode(i);s.removeListener("keypress",o.enqueue),o.destroy(),r.pause(),r.close()}};_e.action=(e,t,s)=>{let r={...dn,...s};if(t.ctrl)return t.action=r.ctrl[t.name],t;if(t.option&&r.option)return t.action=r.option[t.name],t;if(t.shift)return t.action=r.shift[t.name],t;return t.action=r.keys[t.name],t};ps.exports=_e});var us=x((em,ms)=>{ms.exports=(e)=>{e.timers=e.timers||{};let t=e.options.timers;if(!t)return;for(let s of Object.keys(t)){let r=t[s];if(typeof r==="number")r={interval:r};fn(e,s,r)}};function fn(e,t,s={}){let r=e.timers[t]={name:t,start:Date.now(),ms:0,tick:0},o=s.interval||120;r.frames=s.frames||[],r.loading=!0;let i=setInterval(()=>{r.ms=Date.now()-r.start,r.tick++,e.render()},o);return r.stop=()=>{r.loading=!1,clearInterval(i)},Reflect.defineProperty(r,"interval",{value:i}),e.once("close",()=>r.stop()),r.stop}});var ys=x((tm,fs)=>{var{define:yn,width:gn}=M();class hs{constructor(e){let t=e.options;yn(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=gn(t.stdout||process.stdout),Object.assign(this,t),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let t=this._color||e[this.status];return typeof t==="function"?t:e.pending}set loading(e){this._loading=e}get loading(){if(typeof this._loading==="boolean")return this._loading;if(this.loadingChoices)return"choices";return!1}get status(){if(this.cancelled)return"cancelled";if(this.submitted)return"submitted";return"pending"}}fs.exports=hs});var bs=x((sm,gs)=>{var pt=M(),R=Re(),mt={default:R.noop,noop:R.noop,set inverse(e){this._inverse=e},get inverse(){return this._inverse||pt.inverse(this.primary)},set complement(e){this._complement=e},get complement(){return this._complement||pt.complement(this.primary)},primary:R.cyan,success:R.green,danger:R.magenta,strong:R.bold,warning:R.yellow,muted:R.dim,disabled:R.gray,dark:R.dim.gray,underline:R.underline,set info(e){this._info=e},get info(){return this._info||this.primary},set em(e){this._em=e},get em(){return this._em||this.primary.underline},set heading(e){this._heading=e},get heading(){return this._heading||this.muted.underline},set pending(e){this._pending=e},get pending(){return this._pending||this.primary},set submitted(e){this._submitted=e},get submitted(){return this._submitted||this.success},set cancelled(e){this._cancelled=e},get cancelled(){return this._cancelled||this.danger},set typing(e){this._typing=e},get typing(){return this._typing||this.dim},set placeholder(e){this._placeholder=e},get placeholder(){return this._placeholder||this.primary.dim},set highlight(e){this._highlight=e},get highlight(){return this._highlight||this.inverse}};mt.merge=(e={})=>{if(e.styles&&typeof e.styles.enabled==="boolean")R.enabled=e.styles.enabled;if(e.styles&&typeof e.styles.visible==="boolean")R.visible=e.styles.visible;let t=pt.merge({},mt,e.styles);delete t.merge;for(let s of Object.keys(R))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>R[s]});for(let s of Object.keys(R.styles))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>R[s]});return t};gs.exports=mt});var xs=x((rm,ws)=>{var ut=process.platform==="win32",K=Re(),bn=M(),ht={...K.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:K.symbols.check,leftAngle:"\u2039",mark:"\u203B",minus:"\u2212",multiplication:"\xD7",obelus:"\xF7",percent:"%",pilcrow:"\xB6",pilcrow2:"\u2761",pencilUpRight:"\u2710",pencilDownRight:"\u270E",pencilRight:"\u270F",plus:"+",plusMinus:"\xB1",pointRight:"\u261E",rightAngle:"\u203A",section:"\xA7",hexagon:{off:"\u2B21",on:"\u2B22",disabled:"\u2B22"},ballot:{on:"\u2611",off:"\u2610",disabled:"\u2612"},stars:{on:"\u2605",off:"\u2606",disabled:"\u2606"},folder:{on:"\u25BC",off:"\u25B6",disabled:"\u25B6"},prefix:{pending:K.symbols.question,submitted:K.symbols.check,cancelled:K.symbols.cross},separator:{pending:K.symbols.pointerSmall,submitted:K.symbols.middot,cancelled:K.symbols.middot},radio:{off:ut?"( )":"\u25EF",on:ut?"(*)":"\u25C9",disabled:ut?"(|)":"\u24BE"},numbers:["\u24EA","\u2460","\u2461","\u2462","\u2463","\u2464","\u2465","\u2466","\u2467","\u2468","\u2469","\u246A","\u246B","\u246C","\u246D","\u246E","\u246F","\u2470","\u2471","\u2472","\u2473","\u3251","\u3252","\u3253","\u3254","\u3255","\u3256","\u3257","\u3258","\u3259","\u325A","\u325B","\u325C","\u325D","\u325E","\u325F","\u32B1","\u32B2","\u32B3","\u32B4","\u32B5","\u32B6","\u32B7","\u32B8","\u32B9","\u32BA","\u32BB","\u32BC","\u32BD","\u32BE","\u32BF"]};ht.merge=(e)=>{let t=bn.merge({},K.symbols,ht,e.symbols);return delete t.merge,t};ws.exports=ht});var As=x((om,Es)=>{var wn=bs(),xn=xs(),En=M();Es.exports=(e)=>{e.options=En.merge({},e.options.theme,e.options),e.symbols=xn.merge(e.options),e.styles=wn.merge(e.options)}});var Ts=x((Ns,Ss)=>{var vs=process.env.TERM_PROGRAM==="Apple_Terminal",An=te(),ft=M(),P=Ss.exports=Ns,yt=!1,se=P.code={bell:"\x07",beep:"\x07",beginning:"\x1B[G",down:"\x1B[J",esc:"\x1B[",getPosition:"\x1B[6n",hide:"\x1B[?25l",line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",restorePosition:"\x1B["+(vs?"8":"u"),savePosition:"\x1B["+(vs?"7":"s"),screen:"\x1B[2J",show:"\x1B[?25h",up:"\x1B[1J"},ae=P.cursor={get hidden(){return yt},hide(){return yt=!0,se.hide},show(){return yt=!1,se.show},forward:(e=1)=>`\x1B[${e}C`,backward:(e=1)=>`\x1B[${e}D`,nextLine:(e=1)=>"\x1B[E".repeat(e),prevLine:(e=1)=>"\x1B[F".repeat(e),up:(e=1)=>e?`\x1B[${e}A`:"",down:(e=1)=>e?`\x1B[${e}B`:"",right:(e=1)=>e?`\x1B[${e}C`:"",left:(e=1)=>e?`\x1B[${e}D`:"",to(e,t){return t?`\x1B[${t+1};${e+1}H`:`\x1B[${e+1}G`},move(e=0,t=0){let s="";return s+=e<0?ae.left(-e):e>0?ae.right(e):"",s+=t<0?ae.up(-t):t>0?ae.down(t):"",s},strLen(e){var t=0,s=e.length,r=-1;for(var o=0;o<s;o++)if(r=e.charCodeAt(o),r>=0&&r<=128)t+=1;else t+=2;return t},restore(e={}){let{after:t,cursor:s,initial:r,input:o,prompt:i,size:a,value:n}=e;if(r=ft.isPrimitive(r)?String(r):"",o=ft.isPrimitive(o)?String(o):"",n=ft.isPrimitive(n)?String(n):"",a){let d=P.cursor.up(a)+P.cursor.to(this.strLen(i)),l=o.length-s;if(l>0)d+=P.cursor.left(l);return d}if(n||t){let d=!o&&!!r?-this.strLen(r):-this.strLen(o)+s;if(t)d-=this.strLen(t);if(o===""&&r&&!i.includes(r))d+=this.strLen(r);return P.cursor.move(d)}}},gt=P.erase={screen:se.screen,up:se.up,down:se.down,line:se.line,lineEnd:se.lineEnd,lineStart:se.lineStart,lines(e){let t="";for(let s=0;s<e;s++)t+=P.erase.line+(s<e-1?P.cursor.up(1):"");if(e)t+=P.code.beginning;return t}};P.clear=(e="",t=process.stdout.columns)=>{if(!t)return gt.line+ae.to(0);let s=(i)=>[...An(i)].length,r=e.split(/\r?\n/),o=0;for(let i of r)o+=1+Math.floor(Math.max(s(i)-1,0)/t);return(gt.line+ae.prevLine()).repeat(o-1)+gt.line+ae.to(0)}});var me=x((im,Ms)=>{var vn=ge("events"),Rs=te(),bt=ct(),Nn=us(),Sn=ys(),Tn=As(),_=M(),ne=Ts();class wt extends vn{constructor(e={}){super();this.name=e.name,this.type=e.type,this.options=e,Tn(this),Nn(this),this.state=new Sn(this),this.initial=[e.initial,e.default].find((t)=>t!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=Mn(this.options.margin),this.setMaxListeners(0),Rn(this)}async keypress(e,t={}){this.keypressed=!0;let s=bt.action(e,bt(e,t),this.options.actions);this.state.keypress=s,this.emit("keypress",e,s),this.emit("state",this.state.clone());let r=this.options[s.action]||this[s.action]||this.dispatch;if(typeof r==="function")return await r.call(this,e,s);this.alert()}alert(){if(delete this.state.alert,this.options.show===!1)this.emit("alert");else this.stdout.write(ne.code.beep)}cursorHide(){this.stdout.write(ne.cursor.hide());let e=_.onExit(()=>this.cursorShow());this.on("close",()=>{this.cursorShow(),e()})}cursorShow(){this.stdout.write(ne.cursor.show())}write(e){if(!e)return;if(this.stdout&&this.state.show!==!1)this.stdout.write(e);this.state.buffer+=e}clear(e=0){let t=this.state.buffer;if(this.state.buffer="",!t&&!e||this.options.show===!1)return;this.stdout.write(ne.cursor.down(e)+ne.clear(t,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:t,rest:s}=this.sections(),{cursor:r,initial:o="",input:i="",value:a=""}=this,n=this.state.size=s.length,d={after:t,cursor:r,initial:o,input:i,prompt:e,size:n,value:a},l=ne.cursor.restore(d);if(l)this.stdout.write(l)}sections(){let{buffer:e,input:t,prompt:s}=this.state;s=Rs(s);let r=Rs(e),o=r.indexOf(s),i=r.slice(0,o),n=r.slice(o).split(`
|
|
7
|
+
`),d=n[0],l=n[n.length-1],u=(s+(t?" "+t:"")).length,m=u<d.length?d.slice(u+1):"";return{header:i,prompt:d,after:m,rest:n.slice(1),last:l}}async submit(){if(this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit)await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let t=`
|
|
8
8
|
`+this.symbols.pointer+" ";if(typeof e==="string")t+=e.trim();else t+="Invalid input";this.state.error=`
|
|
9
|
-
`+this.styles.danger(t),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit("submit",this.value)}async cancel(e){if(this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==="function")await this.options.onCancel.call(this,this.name,this.value,this);this.emit("cancel",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),t=Math.ceil(e.prompt.length/this.width);if(e.rest)this.write(
|
|
10
|
-
`.repeat(t))}catch(e){}this.emit("close")}start(){if(!this.stop&&this.options.show!==!1)this.stop=
|
|
11
|
-
`:" ",r=[];for(let o=0;o<4;o++){let i=s(o);if(t[o])r.push(i.repeat(t[o]));else r.push("")}return r}_s.exports=wt});var Ds=w((dp,Os)=>{var _n=C(),Is={default(e,t){return t},checkbox(e,t){throw Error("checkbox role is not implemented yet")},editable(e,t){throw Error("editable role is not implemented yet")},expandable(e,t){throw Error("expandable role is not implemented yet")},heading(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||"",t},input(e,t){throw Error("input role is not implemented yet")},option(e,t){return Is.default(e,t)},radio(e,t){throw Error("radio role is not implemented yet")},separator(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||e.symbols.line.repeat(5),t},spacer(e,t){return t}};Os.exports=(e,t={})=>{let s=_n.merge({},Is,t.roles);return s[e]||s.default}});var Ee=w((lp,Us)=>{var In=se(),On=ue(),Dn=Ds(),Oe=C(),{reorder:Et,scrollUp:Bn,scrollDown:Pn,isObject:Bs,swap:Ln}=Oe;class Ls extends On{constructor(e){super(e);this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){if(typeof this.options.initial==="function")this.initial=await this.options.initial.call(this);await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:t,autofocus:s,suggest:r}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach((o)=>o.enabled=!1),typeof r!=="function"&&this.selectable.length===0)throw Error("At least one choice must be selectable");if(Bs(t))t=Object.keys(t);if(Array.isArray(t)){if(s!=null)this.index=this.findIndex(s);t.forEach((o)=>this.enable(this.find(o))),await this.render()}else{if(s!=null)t=s;if(typeof t==="string")t=this.findIndex(t);if(typeof t==="number"&&t>-1)this.index=Math.max(0,Math.min(t,this.choices.length)),this.enable(this.find(this.index))}if(this.isDisabled(this.focused))await this.down()}async toChoices(e,t){this.state.loadingChoices=!0;let s=[],r=0,o=async(i,a)=>{if(typeof i==="function")i=await i.call(this);if(i instanceof Promise)i=await i;for(let n=0;n<i.length;n++){let d=i[n]=await this.toChoice(i[n],r++,a);if(s.push(d),d.choices)await o(d.choices,d)}return s};return o(e,t).then((i)=>{return this.state.loadingChoices=!1,i})}async toChoice(e,t,s){if(typeof e==="function")e=await e.call(this,this);if(e instanceof Promise)e=await e;if(typeof e==="string")e={name:e};if(e.normalized)return e;e.normalized=!0;let r=e.value;if(e=Dn(e.role,this.options)(this,e),typeof e.disabled==="string"&&!e.hint)e.hint=e.disabled,e.disabled=!0;if(e.disabled===!0&&e.hint==null)e.hint="(disabled)";if(e.index!=null)return e;if(e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=t,e.cursor=0,Oe.define(e,"parent",s),e.level=s?s.level+1:1,e.indent==null)e.indent=s?s.indent+" ":e.indent||"";if(e.path=s?s.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),!this.isDisabled(e))this.longest=Math.max(this.longest,In(e.message).length);let i={...e};if(e.reset=(a=i.input,n=i.value)=>{for(let d of Object.keys(i))e[d]=i[d];e.input=a,e.value=n},r==null&&typeof e.initial==="function")e.input=await e.initial.call(this,this.state,e,t);return e}async onChoice(e,t){if(this.emit("choice",e,t,this),typeof e.onChoice==="function")await e.onChoice.call(this,this.state,e,t)}async addChoice(e,t,s){let r=await this.toChoice(e,t,s);return this.choices.push(r),this.index=this.choices.length-1,this.limit=this.choices.length,r}async newItem(e,t,s){let r={name:"New choice name?",editable:!0,newChoice:!0,...e},o=await this.addChoice(r,t,s);return o.updateChoice=()=>{delete o.newChoice,o.name=o.message=o.input,o.input="",o.cursor=0},this.render()}indent(e){if(e.indent==null)return e.level>1?" ".repeat(e.level-1):"";return e.indent}dispatch(e,t){if(this.multiple&&this[t.name])return this[t.name]();this.alert()}focus(e,t){if(typeof t!=="boolean")t=e.enabled;if(t&&!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();return this.index=e.index,e.enabled=t&&!this.isDisabled(e),e}space(){if(!this.multiple)return this.alert();if(!this.focused)return;return this.toggle(this.focused),this.render()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every((t)=>t.enabled);return this.choices.forEach((t)=>t.enabled=!e),this.render()}i(){if(this.choices.length-this.selected.length>this.maxSelected)return this.alert();return this.choices.forEach((e)=>e.enabled=!e.enabled),this.render()}g(){if(!this.choices.some((t)=>!!t.parent))return this.a();let e=this.focused;return this.toggle(e.parent&&!e.choices?e.parent:e),this.render()}toggle(e,t){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(typeof t!=="boolean")t=!e.enabled;if(e.enabled=t,e.choices)e.choices.forEach((r)=>this.toggle(r,t));let s=e.parent;while(s){let r=s.choices.filter((o)=>this.isDisabled(o));s.enabled=r.every((o)=>o.enabled===!0),s=s.parent}return Ps(this,this.choices),this.emit("toggle",e,this),e}enable(e){if(this.selected.length>=this.maxSelected)return this.alert();return e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let t=(s)=>{let r=Number(s);if(r>this.choices.length-1)return this.alert();let o=this.focused,i=this.choices.find((a)=>r===a.index);if(!i.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(i)===-1){let a=Et(this.choices),n=a.indexOf(i);if(o.index>n){let d=a.slice(n,n+this.limit),l=a.filter((c)=>!d.includes(c));this.choices=d.concat(l)}else{let d=n-this.limit+1;this.choices=a.slice(d).concat(a.slice(0,d))}}return this.index=this.choices.indexOf(i),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise((s)=>{let r=this.choices.length,o=this.num,i=(a=!1,n)=>{if(clearTimeout(this.numberTimeout),a)n=t(o);this.num="",s(n)};if(o==="0"||o.length===1&&Number(o+"0")>r)return i(!0);if(Number(o)>r)return i(!1,this.alert());this.numberTimeout=setTimeout(()=>i(!0),this.delay)})}home(){return this.choices=Et(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,t=Et(this.choices);return this.choices=t.slice(e).concat(t.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){if(this.visible.length<=1)return this.alert();return this.up()}next(){if(this.visible.length<=1)return this.alert();return this.down()}right(){if(this.cursor>=this.input.length)return this.alert();return this.cursor++,this.render()}left(){if(this.cursor<=0)return this.alert();return this.cursor--,this.render()}up(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===0)return this.alert();if(e>t&&s===0)return this.scrollUp();if(this.index=(s-1%e+e)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.up();return this.render()}down(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===t-1)return this.alert();if(e>t&&s===t-1)return this.scrollDown();if(this.index=(s+1)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.down();return this.render()}scrollUp(e=0){if(this.choices=Bn(this.choices),this.index=e,this.isDisabled())return this.up();return this.render()}scrollDown(e=this.visible.length-1){if(this.choices=Pn(this.choices),this.index=e,this.isDisabled())return this.down();return this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){if(this.visible.length<=1)return this.alert();if(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled())return this.up();return this.render()}pageDown(){if(this.visible.length>=this.choices.length)return this.alert();if(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled())return this.down();return this.render()}swap(e){Ln(this.choices,this.index,e)}allChoicesAreDisabled(e=this.choices){return e.every((t)=>this.isDisabled(t))}isDisabled(e=this.focused){if(e&&["disabled","collapsed","hidden","completing","readonly"].some((s)=>e[s]===!0))return!0;return e&&e.role==="heading"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every((t)=>this.isEnabled(t));if(e.choices){let t=e.choices.filter((s)=>!this.isDisabled(s));return e.enabled&&t.every((s)=>this.isEnabled(s))}return e.enabled&&!this.isDisabled(e)}isChoice(e,t){return e.name===t||e.index===Number(t)}isSelected(e){if(Array.isArray(this.initial))return this.initial.some((t)=>this.isChoice(e,t));return this.isChoice(e,this.initial)}map(e=[],t="value"){return[].concat(e||[]).reduce((s,r)=>{return s[r]=this.find(r,t),s},{})}filter(e,t){let r=typeof e==="function"?e:(a,n)=>[a.name,n].includes(e),i=(this.options.multiple?this.state._choices:this.choices).filter(r);if(t)return i.map((a)=>a[t]);return i}find(e,t){if(Bs(e))return t?e[t]:e;let r=typeof e==="function"?e:(i,a)=>[i.name,a].includes(e),o=this.choices.find(r);if(o)return t?o[t]:o}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice){if(!e.input)return this.alert();return e.updateChoice(),this.render()}if(this.choices.some((i)=>i.newChoice))return this.alert();let{reorder:t,sort:s}=this.options,r=this.multiple===!0,o=this.selected;if(o===void 0)return this.alert();if(Array.isArray(o)&&t!==!1&&s!==!0)o=Oe.reorder(o);return this.value=r?o.map((i)=>i.name):o.name,super.submit()}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let t of e)if(!this.state._choices.some((s)=>s.name===t.name))this.state._choices.push(t);if(!this._initial&&this.options.initial){this._initial=!0;let t=this.initial;if(typeof t==="string"||typeof t==="number"){let s=this.find(t);if(s)this.initial=s.index,this.focus(s,!0)}}}get choices(){return Ps(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:t,choices:s}=this,r=e.limit||this._limit||t.limit||s.length;return Math.min(r,this.height)}set value(e){super.value=e}get value(){if(typeof super.value!=="string"&&super.value===this.initial)return this.input;return super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];if(e&&this.state.submitted&&this.multiple!==!0)e.enabled=!0;return e}get selectable(){return this.choices.filter((e)=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}}function Ps(e,t){if(t instanceof Promise)return t;if(typeof t==="function"){if(Oe.isAsyncFn(t))return t;t=t.call(e,e)}for(let s of t){if(Array.isArray(s.choices)){let r=s.choices.filter((o)=>!e.isDisabled(o));s.enabled=r.every((o)=>o.enabled===!0)}if(e.isDisabled(s)===!0)delete s.enabled}return t}Us.exports=Ls});var oe=w((cp,ks)=>{var Un=Ee(),At=C();class Gs extends Un{constructor(e){super(e);this.emptyError=this.options.emptyError||"No items were selected"}async dispatch(e,t){if(this.multiple)return this[t.name]?await this[t.name](e,t):await super.dispatch(e,t);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,t){return!this.multiple||this.options.pointer?super.pointer(e,t):""}indicator(e,t){return this.multiple?super.indicator(e,t):""}choiceMessage(e,t){let s=this.resolve(e.message,this.state,e,t);if(e.role==="heading"&&!At.hasColor(s))s=this.styles.strong(s);return this.resolve(s,this.state,e,t)}choiceSeparator(){return":"}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=await this.pointer(e,t),o=await this.indicator(e,t)+(e.pad||""),i=await this.resolve(e.hint,this.state,e,t);if(i&&!At.hasColor(i))i=this.styles.muted(i);let a=this.indent(e),n=await this.choiceMessage(e,t),d=()=>[this.margin[3],a+r+o,n,this.margin[1],i].filter(Boolean).join(" ");if(e.role==="heading")return d();if(e.disabled){if(!At.hasColor(n))n=this.styles.disabled(n);return d()}if(s)n=this.styles.em(n);return d()}async renderChoices(){if(this.state.loading==="choices")return this.styles.warning("Loading choices");if(this.state.submitted)return"";let e=this.visible.map(async(o,i)=>await this.renderChoice(o,i)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));let s=this.margin[0]+t.join(`
|
|
9
|
+
`+this.styles.danger(t),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit("submit",this.value)}async cancel(e){if(this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==="function")await this.options.onCancel.call(this,this.name,this.value,this);this.emit("cancel",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),t=Math.ceil(e.prompt.length/this.width);if(e.rest)this.write(ne.cursor.down(e.rest.length));this.write(`
|
|
10
|
+
`.repeat(t))}catch(e){}this.emit("close")}start(){if(!this.stop&&this.options.show!==!1)this.stop=bt.listen(this,this.keypress.bind(this)),this.once("close",this.stop),this.emit("start",this)}async skip(){if(this.skipped=this.options.skip===!0,typeof this.options.skip==="function")this.skipped=await this.options.skip.call(this,this.name,this.value);return this.skipped}async initialize(){let{format:e,options:t,result:s}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>s.call(this,this.value),typeof t.initial==="function")this.initial=await t.initial.call(this,this);if(typeof t.onRun==="function")await t.onRun.call(this,this);if(typeof t.onSubmit==="function"){let r=t.onSubmit.bind(this),o=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>{return await r(this.name,this.value,this),o()}}await this.start(),await this.render()}render(){throw Error("expected prompt to have a custom render method")}run(){return new Promise(async(e,t)=>{if(this.once("submit",e),this.once("cancel",t),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit("run")})}async element(e,t,s){let{options:r,state:o,symbols:i,timers:a}=this,n=a&&a[e];o.timer=n;let d=r[e]||o[e]||i[e],l=t&&t[e]!=null?t[e]:await d;if(l==="")return l;let p=await this.resolve(l,o,t,s);if(!p&&t&&t[e])return this.resolve(d,o,t,s);return p}async prefix(){let e=await this.element("prefix")||this.symbols,t=this.timers&&this.timers.prefix,s=this.state;if(s.timer=t,_.isObject(e))e=e[s.status]||e.pending;if(!_.hasColor(e))return(this.styles[s.status]||this.styles.pending)(e);return e}async message(){let e=await this.element("message");if(!_.hasColor(e))return this.styles.strong(e);return e}async separator(){let e=await this.element("separator")||this.symbols,t=this.timers&&this.timers.separator,s=this.state;s.timer=t;let r=e[s.status]||e.pending||s.separator,o=await this.resolve(r,s);if(_.isObject(o))o=o[s.status]||o.pending;if(!_.hasColor(o))return this.styles.muted(o);return o}async pointer(e,t){let s=await this.element("pointer",e,t);if(typeof s==="string"&&_.hasColor(s))return s;if(s){let r=this.styles,o=this.index===t,i=o?r.primary:(d)=>d,a=await this.resolve(s[o?"on":"off"]||s,this.state),n=!_.hasColor(a)?i(a):a;return o?n:" ".repeat(a.length)}}async indicator(e,t){let s=await this.element("indicator",e,t);if(typeof s==="string"&&_.hasColor(s))return s;if(s){let r=this.styles,o=e.enabled===!0,i=o?r.success:r.dark,a=s[o?"on":"off"]||s;return!_.hasColor(a)?i(a):a}return""}body(){return null}footer(){if(this.state.status==="pending")return this.element("footer")}header(){if(this.state.status==="pending")return this.element("header")}async hint(){if(this.state.status==="pending"&&!this.isValue(this.state.input)){let e=await this.element("hint");if(!_.hasColor(e))return this.styles.muted(e);return e}}error(e){return!this.state.submitted?e||this.state.error:""}format(e){return e}result(e){return e}validate(e){if(this.options.required===!0)return this.isValue(e);return!0}isValue(e){return e!=null&&e!==""}resolve(e,...t){return _.resolve(this,e,...t)}get base(){return wt.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||_.height(this.stdout,25)}get width(){return this.options.columns||_.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:t}=this.state,s=[t,e].find(this.isValue.bind(this));return this.isValue(s)?s:this.initial}static get prompt(){return(e)=>new this(e).run()}}function Rn(e){let t=(o)=>{return e[o]===void 0||typeof e[o]==="function"},s=["actions","choices","initial","margin","roles","styles","symbols","theme","timers","value"],r=["body","footer","error","header","hint","indicator","message","prefix","separator","skip"];for(let o of Object.keys(e.options)){if(s.includes(o))continue;if(/^on[A-Z]/.test(o))continue;let i=e.options[o];if(typeof i==="function"&&t(o)){if(!r.includes(o))e[o]=i.bind(e)}else if(typeof e[o]!=="function")e[o]=i}}function Mn(e){if(typeof e==="number")e=[e,e,e,e];let t=[].concat(e||[]),s=(o)=>o%2===0?`
|
|
11
|
+
`:" ",r=[];for(let o=0;o<4;o++){let i=s(o);if(t[o])r.push(i.repeat(t[o]));else r.push("")}return r}Ms.exports=wt});var Is=x((am,_s)=>{var Cn=M(),Cs={default(e,t){return t},checkbox(e,t){throw Error("checkbox role is not implemented yet")},editable(e,t){throw Error("editable role is not implemented yet")},expandable(e,t){throw Error("expandable role is not implemented yet")},heading(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||"",t},input(e,t){throw Error("input role is not implemented yet")},option(e,t){return Cs.default(e,t)},radio(e,t){throw Error("radio role is not implemented yet")},separator(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||e.symbols.line.repeat(5),t},spacer(e,t){return t}};_s.exports=(e,t={})=>{let s=Cn.merge({},Cs,t.roles);return s[e]||s.default}});var xe=x((nm,Ps)=>{var _n=te(),In=me(),On=Is(),Ie=M(),{reorder:xt,scrollUp:Dn,scrollDown:Bn,isObject:Os,swap:Pn}=Ie;class Bs extends In{constructor(e){super(e);this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){if(typeof this.options.initial==="function")this.initial=await this.options.initial.call(this);await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:t,autofocus:s,suggest:r}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach((o)=>o.enabled=!1),typeof r!=="function"&&this.selectable.length===0)throw Error("At least one choice must be selectable");if(Os(t))t=Object.keys(t);if(Array.isArray(t)){if(s!=null)this.index=this.findIndex(s);t.forEach((o)=>this.enable(this.find(o))),await this.render()}else{if(s!=null)t=s;if(typeof t==="string")t=this.findIndex(t);if(typeof t==="number"&&t>-1)this.index=Math.max(0,Math.min(t,this.choices.length)),this.enable(this.find(this.index))}if(this.isDisabled(this.focused))await this.down()}async toChoices(e,t){this.state.loadingChoices=!0;let s=[],r=0,o=async(i,a)=>{if(typeof i==="function")i=await i.call(this);if(i instanceof Promise)i=await i;for(let n=0;n<i.length;n++){let d=i[n]=await this.toChoice(i[n],r++,a);if(s.push(d),d.choices)await o(d.choices,d)}return s};return o(e,t).then((i)=>{return this.state.loadingChoices=!1,i})}async toChoice(e,t,s){if(typeof e==="function")e=await e.call(this,this);if(e instanceof Promise)e=await e;if(typeof e==="string")e={name:e};if(e.normalized)return e;e.normalized=!0;let r=e.value;if(e=On(e.role,this.options)(this,e),typeof e.disabled==="string"&&!e.hint)e.hint=e.disabled,e.disabled=!0;if(e.disabled===!0&&e.hint==null)e.hint="(disabled)";if(e.index!=null)return e;if(e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=t,e.cursor=0,Ie.define(e,"parent",s),e.level=s?s.level+1:1,e.indent==null)e.indent=s?s.indent+" ":e.indent||"";if(e.path=s?s.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),!this.isDisabled(e))this.longest=Math.max(this.longest,_n(e.message).length);let i={...e};if(e.reset=(a=i.input,n=i.value)=>{for(let d of Object.keys(i))e[d]=i[d];e.input=a,e.value=n},r==null&&typeof e.initial==="function")e.input=await e.initial.call(this,this.state,e,t);return e}async onChoice(e,t){if(this.emit("choice",e,t,this),typeof e.onChoice==="function")await e.onChoice.call(this,this.state,e,t)}async addChoice(e,t,s){let r=await this.toChoice(e,t,s);return this.choices.push(r),this.index=this.choices.length-1,this.limit=this.choices.length,r}async newItem(e,t,s){let r={name:"New choice name?",editable:!0,newChoice:!0,...e},o=await this.addChoice(r,t,s);return o.updateChoice=()=>{delete o.newChoice,o.name=o.message=o.input,o.input="",o.cursor=0},this.render()}indent(e){if(e.indent==null)return e.level>1?" ".repeat(e.level-1):"";return e.indent}dispatch(e,t){if(this.multiple&&this[t.name])return this[t.name]();this.alert()}focus(e,t){if(typeof t!=="boolean")t=e.enabled;if(t&&!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();return this.index=e.index,e.enabled=t&&!this.isDisabled(e),e}space(){if(!this.multiple)return this.alert();if(!this.focused)return;return this.toggle(this.focused),this.render()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every((t)=>t.enabled);return this.choices.forEach((t)=>t.enabled=!e),this.render()}i(){if(this.choices.length-this.selected.length>this.maxSelected)return this.alert();return this.choices.forEach((e)=>e.enabled=!e.enabled),this.render()}g(){if(!this.choices.some((t)=>!!t.parent))return this.a();let e=this.focused;return this.toggle(e.parent&&!e.choices?e.parent:e),this.render()}toggle(e,t){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(typeof t!=="boolean")t=!e.enabled;if(e.enabled=t,e.choices)e.choices.forEach((r)=>this.toggle(r,t));let s=e.parent;while(s){let r=s.choices.filter((o)=>this.isDisabled(o));s.enabled=r.every((o)=>o.enabled===!0),s=s.parent}return Ds(this,this.choices),this.emit("toggle",e,this),e}enable(e){if(this.selected.length>=this.maxSelected)return this.alert();return e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let t=(s)=>{let r=Number(s);if(r>this.choices.length-1)return this.alert();let o=this.focused,i=this.choices.find((a)=>r===a.index);if(!i.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(i)===-1){let a=xt(this.choices),n=a.indexOf(i);if(o.index>n){let d=a.slice(n,n+this.limit),l=a.filter((p)=>!d.includes(p));this.choices=d.concat(l)}else{let d=n-this.limit+1;this.choices=a.slice(d).concat(a.slice(0,d))}}return this.index=this.choices.indexOf(i),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise((s)=>{let r=this.choices.length,o=this.num,i=(a=!1,n)=>{if(clearTimeout(this.numberTimeout),a)n=t(o);this.num="",s(n)};if(o==="0"||o.length===1&&Number(o+"0")>r)return i(!0);if(Number(o)>r)return i(!1,this.alert());this.numberTimeout=setTimeout(()=>i(!0),this.delay)})}home(){return this.choices=xt(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,t=xt(this.choices);return this.choices=t.slice(e).concat(t.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){if(this.visible.length<=1)return this.alert();return this.up()}next(){if(this.visible.length<=1)return this.alert();return this.down()}right(){if(this.cursor>=this.input.length)return this.alert();return this.cursor++,this.render()}left(){if(this.cursor<=0)return this.alert();return this.cursor--,this.render()}up(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===0)return this.alert();if(e>t&&s===0)return this.scrollUp();if(this.index=(s-1%e+e)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.up();return this.render()}down(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===t-1)return this.alert();if(e>t&&s===t-1)return this.scrollDown();if(this.index=(s+1)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.down();return this.render()}scrollUp(e=0){if(this.choices=Dn(this.choices),this.index=e,this.isDisabled())return this.up();return this.render()}scrollDown(e=this.visible.length-1){if(this.choices=Bn(this.choices),this.index=e,this.isDisabled())return this.down();return this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){if(this.visible.length<=1)return this.alert();if(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled())return this.up();return this.render()}pageDown(){if(this.visible.length>=this.choices.length)return this.alert();if(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled())return this.down();return this.render()}swap(e){Pn(this.choices,this.index,e)}allChoicesAreDisabled(e=this.choices){return e.every((t)=>this.isDisabled(t))}isDisabled(e=this.focused){if(e&&["disabled","collapsed","hidden","completing","readonly"].some((s)=>e[s]===!0))return!0;return e&&e.role==="heading"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every((t)=>this.isEnabled(t));if(e.choices){let t=e.choices.filter((s)=>!this.isDisabled(s));return e.enabled&&t.every((s)=>this.isEnabled(s))}return e.enabled&&!this.isDisabled(e)}isChoice(e,t){return e.name===t||e.index===Number(t)}isSelected(e){if(Array.isArray(this.initial))return this.initial.some((t)=>this.isChoice(e,t));return this.isChoice(e,this.initial)}map(e=[],t="value"){return[].concat(e||[]).reduce((s,r)=>{return s[r]=this.find(r,t),s},{})}filter(e,t){let r=typeof e==="function"?e:(a,n)=>[a.name,n].includes(e),i=(this.options.multiple?this.state._choices:this.choices).filter(r);if(t)return i.map((a)=>a[t]);return i}find(e,t){if(Os(e))return t?e[t]:e;let r=typeof e==="function"?e:(i,a)=>[i.name,a].includes(e),o=this.choices.find(r);if(o)return t?o[t]:o}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice){if(!e.input)return this.alert();return e.updateChoice(),this.render()}if(this.choices.some((i)=>i.newChoice))return this.alert();let{reorder:t,sort:s}=this.options,r=this.multiple===!0,o=this.selected;if(o===void 0)return this.alert();if(Array.isArray(o)&&t!==!1&&s!==!0)o=Ie.reorder(o);return this.value=r?o.map((i)=>i.name):o.name,super.submit()}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let t of e)if(!this.state._choices.some((s)=>s.name===t.name))this.state._choices.push(t);if(!this._initial&&this.options.initial){this._initial=!0;let t=this.initial;if(typeof t==="string"||typeof t==="number"){let s=this.find(t);if(s)this.initial=s.index,this.focus(s,!0)}}}get choices(){return Ds(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:t,choices:s}=this,r=e.limit||this._limit||t.limit||s.length;return Math.min(r,this.height)}set value(e){super.value=e}get value(){if(typeof super.value!=="string"&&super.value===this.initial)return this.input;return super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];if(e&&this.state.submitted&&this.multiple!==!0)e.enabled=!0;return e}get selectable(){return this.choices.filter((e)=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}}function Ds(e,t){if(t instanceof Promise)return t;if(typeof t==="function"){if(Ie.isAsyncFn(t))return t;t=t.call(e,e)}for(let s of t){if(Array.isArray(s.choices)){let r=s.choices.filter((o)=>!e.isDisabled(o));s.enabled=r.every((o)=>o.enabled===!0)}if(e.isDisabled(s)===!0)delete s.enabled}return t}Ps.exports=Bs});var re=x((dm,Us)=>{var Ln=xe(),Et=M();class Ls extends Ln{constructor(e){super(e);this.emptyError=this.options.emptyError||"No items were selected"}async dispatch(e,t){if(this.multiple)return this[t.name]?await this[t.name](e,t):await super.dispatch(e,t);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,t){return!this.multiple||this.options.pointer?super.pointer(e,t):""}indicator(e,t){return this.multiple?super.indicator(e,t):""}choiceMessage(e,t){let s=this.resolve(e.message,this.state,e,t);if(e.role==="heading"&&!Et.hasColor(s))s=this.styles.strong(s);return this.resolve(s,this.state,e,t)}choiceSeparator(){return":"}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=await this.pointer(e,t),o=await this.indicator(e,t)+(e.pad||""),i=await this.resolve(e.hint,this.state,e,t);if(i&&!Et.hasColor(i))i=this.styles.muted(i);let a=this.indent(e),n=await this.choiceMessage(e,t),d=()=>[this.margin[3],a+r+o,n,this.margin[1],i].filter(Boolean).join(" ");if(e.role==="heading")return d();if(e.disabled){if(!Et.hasColor(n))n=this.styles.disabled(n);return d()}if(s)n=this.styles.em(n);return d()}async renderChoices(){if(this.state.loading==="choices")return this.styles.warning("Loading choices");if(this.state.submitted)return"";let e=this.visible.map(async(o,i)=>await this.renderChoice(o,i)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));let s=this.margin[0]+t.join(`
|
|
12
12
|
`),r;if(this.options.choicesHeader)r=await this.resolve(this.options.choicesHeader,this.state);return[r,s].filter(Boolean).join(`
|
|
13
|
-
`)}format(){if(!this.state.submitted||this.state.cancelled)return"";if(Array.isArray(this.selected))return this.selected.map((e)=>this.styles.primary(e.name)).join(", ");return this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:t}=this.state,s="",r=await this.header(),o=await this.prefix(),i=await this.separator(),a=await this.message();if(this.options.promptLine!==!1)s=[o,a,i,""].join(" "),this.state.prompt=s;let n=await this.format(),d=await this.error()||await this.hint(),l=await this.renderChoices(),
|
|
14
|
-
`)),this.write(this.margin[2]),this.restore()}}
|
|
15
|
-
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}}
|
|
16
|
-
`,t)}return super.keypress(e,t)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,t){if(!e||t.ctrl||t.code)return this.alert();this.append(e)}append(e){let{cursor:t,input:s}=this.state;this.input=`${s}`.slice(0,t)+e+`${s}`.slice(t),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:t}=this.state;if(e<=0)return this.alert();this.input=`${t}`.slice(0,e-1)+`${t}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:t}=this.state;if(t[e]===void 0)return this.alert();this.input=`${t}`.slice(0,e)+`${t}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let t=this.input.slice(0,e),s=this.input.slice(e),r=t.split(" ");this.state.clipboard.push(r.pop()),this.input=r.join(" "),this.cursor=this.input.length,this.input+=s,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){if(this.state.prevCursor)this.cursor=this.state.prevCursor,this.state.prevCursor=0;else this.state.prevCursor=this.cursor,this.cursor=0;this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):"";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){if(this.cursor>=this.input.length)return this.alert();return this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();return this.moveCursor(-1),this.render()}isValue(e){return!!e}async format(e=this.value){let t=await this.resolve(this.initial,this.state);if(!this.state.submitted)return
|
|
17
|
-
`)),this.restore()}}
|
|
13
|
+
`)}format(){if(!this.state.submitted||this.state.cancelled)return"";if(Array.isArray(this.selected))return this.selected.map((e)=>this.styles.primary(e.name)).join(", ");return this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:t}=this.state,s="",r=await this.header(),o=await this.prefix(),i=await this.separator(),a=await this.message();if(this.options.promptLine!==!1)s=[o,a,i,""].join(" "),this.state.prompt=s;let n=await this.format(),d=await this.error()||await this.hint(),l=await this.renderChoices(),p=await this.footer();if(n)s+=n;if(d&&!s.includes(d))s+=" "+d;if(e&&!n&&!l.trim()&&this.multiple&&this.emptyError!=null)s+=this.styles.danger(this.emptyError);this.clear(t),this.write([r,s,l,p].filter(Boolean).join(`
|
|
14
|
+
`)),this.write(this.margin[2]),this.restore()}}Us.exports=Ls});var $s=x((lm,ks)=>{var Un=re(),Gn=(e,t)=>{let s=e?new RegExp(e,"ig"):/$^/;return(r)=>{return e?r.replace(s,(o)=>t(o)):r}};class Gs extends Un{constructor(e){super(e);this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:t,input:s}=this.state;return this.input=s.slice(0,t)+e+s.slice(t),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:t}=this.state;if(!t)return this.alert();return this.input=t.slice(0,e-1)+t.slice(e),this.moveCursor(-1),this.complete()}deleteForward(){let{cursor:e,input:t}=this.state;if(t[e]===void 0)return this.alert();return this.input=`${t}`.slice(0,e)+`${t}`.slice(e+1),this.complete()}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,t=this.state._choices){if(typeof this.options.suggest==="function")return this.options.suggest.call(this,e,t);let s=e.toLowerCase();return t.filter((r)=>r.message.toLowerCase().includes(s))}pointer(){return""}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map((e)=>this.styles.primary(e.message)).join(", ");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!=="pending")return super.render();let e=this.options.highlight||this.styles.complement,t=(o,i)=>{if(!o)return o;if(e.stack)return e(o);return e.call(this,o)},s=Gn(this.input,t),r=this.choices;this.choices=r.map((o)=>({...o,message:s(o.message)})),await super.render(),this.choices=r}submit(){if(this.options.multiple)this.value=this.selected.map((e)=>e.name);return super.submit()}}ks.exports=Gs});var vt=x((cm,qs)=>{var At=M();qs.exports=(e,t={})=>{e.cursorHide();let{input:s="",initial:r="",pos:o,showCursor:i=!0,color:a}=t,n=a||e.styles.placeholder,d=At.inverse(e.styles.primary),l=(f)=>d(e.styles.black(f)),p=s,u=" ",m=l(u);if(e.blink&&e.blink.off===!0)l=(f)=>f,m="";if(i&&o===0&&r===""&&s==="")return l(u);if(i&&o===0&&(s===r||s===""))return l(r[0])+n(r.slice(1));r=At.isPrimitive(r)?`${r}`:"",s=At.isPrimitive(s)?`${s}`:"";let c=r&&r.startsWith(s)&&r!==s,h=c?l(r[s.length]):m;if(o!==s.length&&i===!0)p=s.slice(0,o)+l(s[o])+s.slice(o+1),h="";if(i===!1)h="";if(c){let f=e.styles.unstyle(p+h);return p+h+n(r.slice(f.length))}return p+h}});var Oe=x((pm,Ks)=>{var kn=te(),$n=re(),qn=vt();class Ws extends $n{constructor(e){super({...e,multiple:!0});this.type="form",this.initial=this.options.initial,this.align=[this.options.align,"right"].find((t)=>t!=null),this.emptyError="",this.values={}}async reset(e){if(await super.reset(),e===!0)this._index=this.index;return this.index=this._index,this.values={},this.choices.forEach((t)=>t.reset&&t.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let t=this.focused;if(!t)return this.alert();let{cursor:s,input:r}=t;return t.value=t.input=r.slice(0,s)+e+r.slice(s),t.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:t,input:s}=e;return e.value=e.input=s.slice(0,t-1)+s.slice(t),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:t,input:s}=e;if(s[t]===void 0)return this.alert();let r=`${s}`.slice(0,t)+`${s}`.slice(t+1);return e.value=e.input=r,this.render()}right(){let e=this.focused;if(!e)return this.alert();if(e.cursor>=e.input.length)return this.alert();return e.cursor++,this.render()}left(){let e=this.focused;if(!e)return this.alert();if(e.cursor<=0)return this.alert();return e.cursor--,this.render()}space(e,t){return this.dispatch(e,t)}number(e,t){return this.dispatch(e,t)}next(){let e=this.focused;if(!e)return this.alert();let{initial:t,input:s}=e;if(t&&t.startsWith(s)&&s!==t)return e.value=e.input=t,e.cursor=e.value.length,this.render();return super.next()}prev(){let e=this.focused;if(!e)return this.alert();if(e.cursor===0)return super.prev();return e.value=e.input="",e.cursor=0,this.render()}separator(){return""}format(e){return!this.state.submitted?super.format(e):""}pointer(){return""}indicator(e){return e.input?"\u29BF":"\u2299"}async choiceSeparator(e,t){let s=await this.resolve(e.separator,this.state,e,t)||":";return s?" "+this.styles.disabled(s):""}async renderChoice(e,t){await this.onChoice(e,t);let{state:s,styles:r}=this,{cursor:o,initial:i="",name:a,input:n=""}=e,{muted:d,submitted:l,primary:p,danger:u}=r,m=this.index===t,c=e.validate||(()=>!0),h=await this.choiceSeparator(e,t),f=e.message;if(this.align==="right")f=f.padStart(this.longest+1," ");if(this.align==="left")f=f.padEnd(this.longest+1," ");let g=this.values[a]=n||i,y=n?"success":"dark";if(await c.call(e,g,this.state)!==!0)y="danger";let E=r[y],A=E(await this.indicator(e,t))+(e.pad||""),N=this.indent(e),C=()=>[N,A,f+h,n].filter(Boolean).join(" ");if(s.submitted)return f=kn(f),n=l(n),C();if(e.format)n=await e.format.call(this,n,e,t);else{let O=this.styles.muted;n=qn(this,{input:n,initial:i,pos:o,showCursor:m,color:O})}if(!this.isValue(n))n=this.styles.muted(this.symbols.ellipsis);if(e.result)this.values[a]=await e.result.call(this,g,e,t);if(m)f=p(f);if(e.error)n+=(n?" ":"")+u(e.error.trim());else if(e.hint)n+=(n?" ":"")+d(e.hint.trim());return C()}async submit(){return this.value=this.values,super.base.submit.call(this)}}Ks.exports=Ws});var Nt=x((mm,Hs)=>{var Wn=Oe(),Kn=()=>{throw Error("expected prompt to have a custom authenticate method")},Fs=(e=Kn)=>{class t extends Wn{constructor(s){super(s)}async submit(){this.value=await e.call(this,this.values,this.state),super.base.submit.call(this)}static create(s){return Fs(s)}}return t};Hs.exports=Fs()});var zs=x((um,Ys)=>{var Fn=Nt();function Hn(e,t){if(e.username===this.options.username&&e.password===this.options.password)return!0;return!1}var Vs=(e=Hn)=>{let t=[{name:"username",message:"username"},{name:"password",message:"password",format(r){if(this.options.showPassword)return r;return(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(r.length))}}];class s extends Fn.create(e){constructor(r){super({...r,choices:t})}static create(r){return Vs(r)}}return s};Ys.exports=Vs()});var De=x((hm,Qs)=>{var Vn=me(),{isPrimitive:Yn,hasColor:zn}=M();class Zs extends Vn{constructor(e){super(e);this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){if(!this.isValue(e))return this.alert();return this.input=e,this.submit()}format(e){let{styles:t,state:s}=this;return!s.submitted?t.primary(e):t.success(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return Yn(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status==="pending"){let e=await this.element("hint");if(!zn(e))return this.styles.muted(e);return e}}async render(){let{input:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i=this.styles.muted(this.default),a=[s,o,i,r].filter(Boolean).join(" ");this.state.prompt=a;let n=await this.header(),d=this.value=this.cast(e),l=await this.format(d),p=await this.error()||await this.hint(),u=await this.footer();if(p&&!a.includes(p))l+=" "+p;a+=" "+l,this.clear(t),this.write([n,a,u].filter(Boolean).join(`
|
|
15
|
+
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}}Qs.exports=Zs});var js=x((fm,Js)=>{var Zn=De();class Xs extends Zn{constructor(e){super(e);this.default=this.options.default||(this.initial?"(Y/n)":"(y/N)")}}Js.exports=Xs});var sr=x((ym,tr)=>{var Qn=re(),Xn=Oe(),ue=Xn.prototype;class er extends Qn{constructor(e){super({...e,multiple:!0});this.align=[this.options.align,"left"].find((t)=>t!=null),this.emptyError="",this.values={}}dispatch(e,t){let s=this.focused,r=s.parent||{};if(!s.editable&&!r.editable){if(e==="a"||e==="i")return super[e]()}return ue.dispatch.call(this,e,t)}append(e,t){return ue.append.call(this,e,t)}delete(e,t){return ue.delete.call(this,e,t)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?ue.next.call(this):super.next()}prev(){return this.focused.editable?ue.prev.call(this):super.prev()}async indicator(e,t){let s=e.indicator||"",r=e.editable?s:super.indicator(e,t);return await this.resolve(r,this.state,e,t)||""}indent(e){return e.role==="heading"?"":e.editable?" ":" "}async renderChoice(e,t){if(e.indent="",e.editable)return ue.renderChoice.call(this,e,t);return super.renderChoice(e,t)}error(){return""}footer(){return this.state.error}async validate(){let e=!0;for(let t of this.choices){if(typeof t.validate!=="function")continue;if(t.role==="heading")continue;let s=t.parent?this.value[t.parent.name]:this.value;if(t.editable)s=t.value===t.name?t.initial||"":t.value;else if(!this.isDisabled(t))s=t.enabled===!0;if(e=await t.validate(s,this.state),e!==!0)break}if(e!==!0)this.state.error=typeof e==="string"?e:"Invalid Input";return e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some((e)=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let t=e.parent?this.value[e.parent.name]:this.value;if(e.role==="heading"){this.value[e.name]={};continue}if(e.editable)t[e.name]=e.value===e.name?e.initial||"":e.value;else if(!this.isDisabled(e))t[e.name]=e.enabled===!0}return this.base.submit.call(this)}}tr.exports=er});var de=x((gm,or)=>{var Jn=me(),jn=ct(),ed=vt(),{isPrimitive:td}=M();class rr extends Jn{constructor(e){super(e);if(this.initial=td(this.initial)?String(this.initial):"",this.initial)this.cursorHide();this.state.prevCursor=0,this.state.clipboard=[],this.keypressTimeout=this.options.keypressTimeout!==void 0?this.options.keypressTimeout:null}async keypress(e,t=e?jn(e,{}):{}){let s=Date.now(),r=s-this.lastKeypress;this.lastKeypress=s;let o=t.name==="return"||t.name==="enter",i=this.state.prevKeypress,a;if(this.state.prevKeypress=t,this.keypressTimeout!=null&&o){if(r<this.keypressTimeout)return this.submit();this.state.multilineBuffer=this.state.multilineBuffer||"",this.state.multilineBuffer+=e,a=!0,i=null}if(a||this.options.multiline&&o){if(!i||i.name!=="return")return this.append(`
|
|
16
|
+
`,t)}return super.keypress(e,t)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,t){if(!e||t.ctrl||t.code)return this.alert();this.append(e)}append(e){let{cursor:t,input:s}=this.state;this.input=`${s}`.slice(0,t)+e+`${s}`.slice(t),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:t}=this.state;if(e<=0)return this.alert();this.input=`${t}`.slice(0,e-1)+`${t}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:t}=this.state;if(t[e]===void 0)return this.alert();this.input=`${t}`.slice(0,e)+`${t}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let t=this.input.slice(0,e),s=this.input.slice(e),r=t.split(" ");this.state.clipboard.push(r.pop()),this.input=r.join(" "),this.cursor=this.input.length,this.input+=s,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){if(this.state.prevCursor)this.cursor=this.state.prevCursor,this.state.prevCursor=0;else this.state.prevCursor=this.cursor,this.cursor=0;this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):"";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){if(this.cursor>=this.input.length)return this.alert();return this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();return this.moveCursor(-1),this.render()}isValue(e){return!!e}async format(e=this.value){let t=await this.resolve(this.initial,this.state);if(!this.state.submitted)return ed(this,{input:e,initial:t,pos:this.cursor});return this.styles.submitted(e||t)}async render(){let e=this.state.size,t=await this.prefix(),s=await this.separator(),r=await this.message(),o=[t,r,s].filter(Boolean).join(" ");this.state.prompt=o;let i=await this.header(),a=await this.format(),n=await this.error()||await this.hint(),d=await this.footer();if(n&&!a.includes(n))a+=" "+n;o+=" "+a,this.clear(e),this.write([i,o,d].filter(Boolean).join(`
|
|
17
|
+
`)),this.restore()}}or.exports=rr});var ar=x((bm,ir)=>{var sd=(e)=>e.filter((t,s)=>e.lastIndexOf(t)===s),Be=(e)=>sd(e).filter(Boolean);ir.exports=(e,t={},s="")=>{let{past:r=[],present:o=""}=t,i,a;switch(e){case"prev":case"undo":return i=r.slice(0,r.length-1),a=r[r.length-1]||"",{past:Be([s,...i]),present:a};case"next":case"redo":return i=r.slice(1),a=r[0]||"",{past:Be([...i,s]),present:a};case"save":return{past:Be([...r,s]),present:""};case"remove":if(a=Be(r.filter((n)=>n!==s)),o="",a.length)o=a.pop();return{past:a,present:o};default:throw Error(`Invalid action: "${e}"`)}}});var St=x((wm,lr)=>{var rd=de(),nr=ar();class dr extends rd{constructor(e){super(e);let t=this.options.history;if(t&&t.store){let s=t.values||this.initial;this.autosave=!!t.autosave,this.store=t.store,this.data=this.store.get("values")||{past:[],present:s},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){if(!this.store)return this.alert();if(this.data=nr(e,this.data,this.input),!this.data.present)return this.alert();return this.input=this.data.present,this.cursor=this.input.length,this.render()}altUp(){return this.completion("prev")}altDown(){return this.completion("next")}prev(){return this.save(),super.prev()}save(){if(!this.store)return;this.data=nr("save",this.data,this.input),this.store.set("values",this.data)}submit(){if(this.store&&this.autosave===!0)this.save();return super.submit()}}lr.exports=dr});var mr=x((xm,pr)=>{var od=de();class cr extends od{format(){return""}}pr.exports=cr});var fr=x((Em,hr)=>{var id=de();class ur extends id{constructor(e={}){super(e);this.sep=this.options.separator||/, */,this.initial=e.initial||""}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:(t)=>t;return this.list.map(e).join(", ")}async submit(e){let t=this.state.error||await this.validate(this.list,this.state);if(t!==!0)return this.state.error=t,super.submit();return this.value=this.list,super.submit()}get list(){return this.split()}}hr.exports=ur});var br=x((Am,gr)=>{var ad=re();class yr extends ad{constructor(e){super({...e,multiple:!0})}}gr.exports=yr});var Tt=x((vm,xr)=>{var nd=de();class wr extends nd{constructor(e={}){super({style:"number",...e});this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1000,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:"",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){if(!/[-+.]/.test(e)||e==="."&&this.input.includes("."))return this.alert("invalid number");return super.append(e)}number(e){return super.append(e)}next(){if(this.input&&this.input!==this.initial)return this.alert();if(!this.isValue(this.initial))return this.alert();return this.input=this.initial,this.cursor=String(this.initial).length,this.render()}up(e){let t=e||this.minor,s=this.toNumber(this.input);if(s>this.max+t)return this.alert();return this.input=`${s+t}`,this.render()}down(e){let t=e||this.minor,s=this.toNumber(this.input);if(s<this.min-t)return this.alert();return this.input=`${s-t}`,this.render()}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){if(typeof this.options.format==="function")return this.options.format.call(this,e);return this.styles.info(e)}toNumber(e=""){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\.)|(\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find((t)=>this.isValue(t));return this.value=this.toNumber(e||0),super.submit()}}xr.exports=wr});var vr=x((Nm,Ar)=>{var dd=de();class Er extends dd{constructor(e){super(e);this.cursorShow()}format(e=this.input){if(!this.keypressed)return"";return(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length))}}Ar.exports=Er});var Rr=x((Sm,Tr)=>{var ld=te(),cd=xe(),Nr=M();class Sr extends cd{constructor(e={}){super(e);this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||"left"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`
|
|
18
18
|
`;let t=e.startNumber||1;if(typeof this.scale==="number")this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,r)=>({name:r+t}))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let t of this.choices){e=Math.max(e,t.message.length),t.scaleIndex=t.initial||2,t.scale=[];for(let s=0;s<this.scale.length;s++)t.scale.push({index:s})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,t){if(this.multiple)return this[t.name]?await this[t.name](e,t):await super.dispatch(e,t);this.alert()}heading(e,t,s){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;if(e.scaleIndex>=this.scale.length-1)return this.alert();return e.scaleIndex++,this.render()}left(){let e=this.focused;if(e.scaleIndex<=0)return this.alert();return e.scaleIndex--,this.render()}indent(){return""}format(){if(this.state.submitted)return this.choices.map((t)=>this.styles.info(t.index)).join(", ");return""}pointer(){return""}renderScaleKey(){if(this.scaleKey===!1)return"";if(this.state.submitted)return"";return["",...this.scale.map((s)=>` ${s.name} - ${s.message}`)].map((s)=>this.styles.muted(s)).join(`
|
|
19
|
-
`)}renderScaleHeading(e){let t=this.scale.map((n)=>n.name);if(typeof this.options.renderScaleHeading==="function")t=this.options.renderScaleHeading.call(this,e);let s=this.scaleLength-t.join("").length,r=Math.round(s/(t.length-1)),i=t.map((n)=>this.styles.strong(n)).join(" ".repeat(r)),a=" ".repeat(this.widths[0]);return this.margin[3]+a+this.margin[1]+i}scaleIndicator(e,t,s){if(typeof this.options.scaleIndicator==="function")return this.options.scaleIndicator.call(this,e,t,s);let r=e.scaleIndex===t.index;if(t.disabled)return this.styles.hint(this.symbols.radio.disabled);if(r)return this.styles.success(this.symbols.radio.on);return this.symbols.radio.off}renderScale(e,t){let s=e.scale.map((o)=>this.scaleIndicator(e,o,t)),r=this.term==="Hyper"?"":" ";return s.join(r+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=await this.pointer(e,t),o=await e.hint;if(o&&!
|
|
20
|
-
`).map((
|
|
19
|
+
`)}renderScaleHeading(e){let t=this.scale.map((n)=>n.name);if(typeof this.options.renderScaleHeading==="function")t=this.options.renderScaleHeading.call(this,e);let s=this.scaleLength-t.join("").length,r=Math.round(s/(t.length-1)),i=t.map((n)=>this.styles.strong(n)).join(" ".repeat(r)),a=" ".repeat(this.widths[0]);return this.margin[3]+a+this.margin[1]+i}scaleIndicator(e,t,s){if(typeof this.options.scaleIndicator==="function")return this.options.scaleIndicator.call(this,e,t,s);let r=e.scaleIndex===t.index;if(t.disabled)return this.styles.hint(this.symbols.radio.disabled);if(r)return this.styles.success(this.symbols.radio.on);return this.symbols.radio.off}renderScale(e,t){let s=e.scale.map((o)=>this.scaleIndicator(e,o,t)),r=this.term==="Hyper"?"":" ";return s.join(r+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=await this.pointer(e,t),o=await e.hint;if(o&&!Nr.hasColor(o))o=this.styles.muted(o);let i=(c)=>this.margin[3]+c.replace(/\s+$/,"").padEnd(this.widths[0]," "),a=this.newline,n=this.indent(e),d=await this.resolve(e.message,this.state,e,t),l=await this.renderScale(e,t),p=this.margin[1]+this.margin[3];this.scaleLength=ld(l).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-p.length);let m=Nr.wordWrap(d,{width:this.widths[0],newline:a}).split(`
|
|
20
|
+
`).map((c)=>i(c)+this.margin[1]);if(s)l=this.styles.info(l),m=m.map((c)=>this.styles.info(c));if(m[0]+=l,this.linebreak)m.push("");return[n+r,m.join(`
|
|
21
21
|
`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(r,o)=>await this.renderChoice(r,o)),t=await Promise.all(e),s=await this.renderScaleHeading();return this.margin[0]+[s,...t.map((r)=>r.join(" "))].join(`
|
|
22
|
-
`)}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i="";if(this.options.promptLine!==!1)i=[s,o,r,""].join(" "),this.state.prompt=i;let a=await this.header(),n=await this.format(),d=await this.renderScaleKey(),l=await this.error()||await this.hint(),
|
|
23
|
-
`)),!this.state.submitted)this.write(this.margin[2]);this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}}
|
|
24
|
-
`){
|
|
22
|
+
`)}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i="";if(this.options.promptLine!==!1)i=[s,o,r,""].join(" "),this.state.prompt=i;let a=await this.header(),n=await this.format(),d=await this.renderScaleKey(),l=await this.error()||await this.hint(),p=await this.renderChoices(),u=await this.footer(),m=this.emptyError;if(n)i+=n;if(l&&!i.includes(l))i+=" "+l;if(e&&!n&&!p.trim()&&this.multiple&&m!=null)i+=this.styles.danger(m);if(this.clear(t),this.write([a,i,d,p,u].filter(Boolean).join(`
|
|
23
|
+
`)),!this.state.submitted)this.write(this.margin[2]);this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}}Tr.exports=Sr});var Ir=x((Tm,_r)=>{var Mr=te(),pd=(e="")=>{return typeof e==="string"?e.replace(/^['"]|['"]$/g,""):""};class Cr{constructor(e){this.name=e.key,this.field=e.field||{},this.value=pd(e.initial||this.field.initial||""),this.message=e.message||this.name,this.cursor=0,this.input="",this.lines=[]}}var md=async(e={},t={},s=(r)=>r)=>{let r=new Set,o=e.fields||[],i=e.template,a=[],n=[],d=[],l=1;if(typeof i==="function")i=await i();let p=-1,u=()=>i[++p],m=()=>i[p+1],c=(h)=>{h.line=l,a.push(h)};c({type:"bos",value:""});while(p<i.length-1){let h=u();if(/^[^\S\n ]$/.test(h)){c({type:"text",value:h});continue}if(h===`
|
|
24
|
+
`){c({type:"newline",value:h}),l++;continue}if(h==="\\"){h+=u(),c({type:"text",value:h});continue}if((h==="$"||h==="#"||h==="{")&&m()==="{"){let g=u();h+=g;let y={type:"template",open:h,inner:"",close:"",value:h},E;while(E=u()){if(E==="}"){if(m()==="}")E+=u();y.value+=E,y.close=E;break}if(E===":")y.initial="",y.key=y.inner;else if(y.initial!==void 0)y.initial+=E;y.value+=E,y.inner+=E}if(y.template=y.open+(y.initial||y.inner)+y.close,y.key=y.key||y.inner,hasOwnProperty.call(t,y.key))y.initial=t[y.key];y=s(y),c(y),d.push(y.key),r.add(y.key);let A=n.find((N)=>N.name===y.key);if(y.field=o.find((N)=>N.name===y.key),!A)A=new Cr(y),n.push(A);A.lines.push(y.line-1);continue}let f=a[a.length-1];if(f.type==="text"&&f.line===l)f.value+=h;else c({type:"text",value:h})}return c({type:"eos",value:""}),{input:i,tabstops:a,unique:r,keys:d,items:n}};_r.exports=async(e)=>{let t=e.options,s=new Set(t.required===!0?[]:t.required||[]),r={...t.values,...t.initial},{tabstops:o,items:i,keys:a}=await md(t,r),n=Rt("result",e,t),d=Rt("format",e,t),l=Rt("validate",e,t,!0),p=e.isValue.bind(e);return async(u={},m=!1)=>{let c=0;u.required=s,u.items=i,u.keys=a,u.output="";let h=async(E,A,N,C)=>{let O=await l(E,A,N,C);if(O===!1)return"Invalid field "+N.name;return O};for(let E of o){let{value:A,key:N}=E;if(E.type!=="template"){if(A)u.output+=A;continue}if(E.type==="template"){let C=i.find((pe)=>pe.name===N);if(t.required===!0)u.required.add(C.name);let O=[C.input,u.values[C.value],C.value,A].find(p),Ne=(C.field||{}).message||E.inner;if(m){let pe=await h(u.values[N],u,C,c);if(pe&&typeof pe==="string"||pe===!1){u.invalid.set(N,pe);continue}u.invalid.delete(N);let la=await n(u.values[N],u,C,c);u.output+=Mr(la);continue}C.placeholder=!1;let da=A;if(A=await d(A,u,C,c),O!==A)u.values[N]=O,A=e.styles.typing(O),u.missing.delete(Ne);else if(u.values[N]=void 0,O=`<${Ne}>`,A=e.styles.primary(O),C.placeholder=!0,u.required.has(N))u.missing.add(Ne);if(u.missing.has(Ne)&&u.validating)A=e.styles.warning(O);if(u.invalid.has(N)&&u.validating)A=e.styles.danger(O);if(c===u.index)if(da!==A)A=e.styles.underline(A);else A=e.styles.heading(Mr(A));c++}if(A)u.output+=A}let f=u.output.split(`
|
|
25
25
|
`).map((E)=>" "+E),g=i.length,y=0;for(let E of i){if(u.invalid.has(E.name))E.lines.forEach((A)=>{if(f[A][0]!==" ")return;f[A]=u.styles.danger(u.symbols.bullet)+f[A].slice(1)});if(e.isValue(u.values[E.name]))y++}return u.completed=(y/g*100).toFixed(0),u.output=f.join(`
|
|
26
|
-
`),u.output}};function
|
|
27
|
-
`].find((y)=>y!=null),i=await this.prefix(),a=await this.separator(),n=await this.message(),d=[i,n,a].filter(Boolean).join(" ");this.state.prompt=d;let l=await this.header(),
|
|
28
|
-
`;return this.state.error=a,super.submit()}if(t.size)return this.state.error="Required: "+[...t.keys()].join(", "),super.submit();let i=
|
|
26
|
+
`),u.output}};function Rt(e,t,s,r){return(o,i,a,n)=>{if(typeof a.field[e]==="function")return a.field[e].call(t,o,i,a,n);return[r,o].find((d)=>t.isValue(d))}}});var Br=x((Rm,Dr)=>{var ud=te(),hd=Ir(),fd=me();class Or extends fd{constructor(e){super(e);this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await hd(this),await super.initialize()}async reset(e){if(this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0)await this.initialize(),await this.render()}moveCursor(e){let t=this.getItem();this.cursor+=e,t.cursor+=e}dispatch(e,t){if(!t.code&&!t.ctrl&&e!=null&&this.getItem()){this.append(e,t);return}this.alert()}append(e,t){let s=this.getItem(),r=s.input.slice(0,this.cursor),o=s.input.slice(this.cursor);this.input=s.input=`${r}${e}${o}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let t=e.input.slice(this.cursor),s=e.input.slice(0,this.cursor-1);this.input=e.input=`${s}${t}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let t=this.state.completed<100?this.styles.warning:this.styles.success;if(this.state.submitted===!0&&this.state.completed!==100)t=this.styles.danger;return t(`${this.state.completed}% completed`)}async render(){let{index:e,keys:t=[],submitted:s,size:r}=this.state,o=[this.options.newline,`
|
|
27
|
+
`].find((y)=>y!=null),i=await this.prefix(),a=await this.separator(),n=await this.message(),d=[i,n,a].filter(Boolean).join(" ");this.state.prompt=d;let l=await this.header(),p=await this.error()||"",u=await this.hint()||"",m=s?"":await this.interpolate(this.state),c=this.state.key=t[e]||"",h=await this.format(c),f=await this.footer();if(h)d+=" "+h;if(u&&!h&&this.state.completed===0)d+=" "+u;this.clear(r);let g=[l,d,m,f,p.trim()];this.write(g.filter(Boolean).join(o)),this.restore()}getItem(e){let{items:t,keys:s,index:r}=this.state,o=t.find((i)=>i.name===s[r]);if(o&&o.input!=null)this.input=o.input,this.cursor=o.cursor;return o}async submit(){if(typeof this.interpolate!=="function")await this.initialize();await this.interpolate(this.state,!0);let{invalid:e,missing:t,output:s,values:r}=this.state;if(e.size){let a="";for(let[n,d]of e)a+=`Invalid ${n}: ${d}
|
|
28
|
+
`;return this.state.error=a,super.submit()}if(t.size)return this.state.error="Required: "+[...t.keys()].join(", "),super.submit();let i=ud(s).split(`
|
|
29
29
|
`).map((a)=>a.slice(1)).join(`
|
|
30
|
-
`);return this.value={values:r,result:i},super.submit()}}
|
|
31
|
-
`)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let t=await super.toChoices(...e);for(let s of t)s.scale=
|
|
32
|
-
`);if(s)
|
|
33
|
-
`)}format(){if(this.state.submitted)return this.choices.map((t)=>this.styles.info(t.scaleIdx)).join(", ");return""}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i=[s,o,r].filter(Boolean).join(" ");this.state.prompt=i;let a=await this.header(),n=await this.format(),d=await this.error()||await this.hint(),l=await this.renderChoices(),
|
|
34
|
-
`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}}function
|
|
35
|
-
`)),this.write(this.margin[2]),this.restore()}}Hr.exports=Kr});var zr=w((Dp,Yr)=>{var Ed=oe();class Vr extends Ed{constructor(e){super(e);if(typeof this.options.correctChoice!=="number"||this.options.correctChoice<0)throw Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,t){let s=await super.toChoices(e,t);if(s.length<2)throw Error("Please give at least two choices to the user");if(this.options.correctChoice>s.length)throw Error("Please specify the index of the correct answer from the list of choices");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}}Yr.exports=Vr});var Qr=w((Ct)=>{var Zr=C(),S=(e,t)=>{Zr.defineExport(Ct,e,t),Zr.defineExport(Ct,e.toLowerCase(),t)};S("AutoComplete",()=>qs());S("BasicAuth",()=>Qs());S("Confirm",()=>tr());S("Editable",()=>or());S("Form",()=>De());S("Input",()=>Tt());S("Invisible",()=>hr());S("List",()=>gr());S("MultiSelect",()=>wr());S("Numeral",()=>Rt());S("Password",()=>Sr());S("Scale",()=>Cr());S("Select",()=>oe());S("Snippet",()=>Lr());S("Sort",()=>kr());S("Survey",()=>qr());S("Text",()=>Tt());S("Toggle",()=>Fr());S("Quiz",()=>zr())});var Jr=w((Pp,Xr)=>{Xr.exports={ArrayPrompt:Ee(),AuthPrompt:St(),BooleanPrompt:Be(),NumberPrompt:Rt(),StringPrompt:le()}});var ae=w((Lp,eo)=>{var jr=be("assert"),It=be("events"),ie=C();class U extends It{constructor(e,t){super();this.options=ie.merge({},e),this.answers={...t}}register(e,t){if(ie.isObject(e)){for(let r of Object.keys(e))this.register(r,e[r]);return this}jr.equal(typeof t,"function","expected a function");let s=e.toLowerCase();if(t.prototype instanceof this.Prompt)this.prompts[s]=t;else this.prompts[s]=t(this.Prompt,this);return this}async prompt(e=[]){for(let t of[].concat(e))try{if(typeof t==="function")t=await t.call(this);await this.ask(ie.merge({},this.options,t))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){if(typeof e==="function")e=await e.call(this);let t=ie.merge({},this.options,e),{type:s,name:r}=e,{set:o,get:i}=ie;if(typeof s==="function")s=await s.call(this,e,this.answers);if(!s)return this.answers[r];if(s==="number")s="numeral";jr(this.prompts[s],`Prompt "${s}" is not registered`);let a=new this.prompts[s](t),n=i(this.answers,r);if(a.state.answers=this.answers,a.enquirer=this,r)a.on("submit",(l)=>{this.emit("answer",r,l,a),o(this.answers,r,l)});let d=a.emit.bind(a);if(a.emit=(...l)=>{return this.emit.call(this,...l),d(...l)},this.emit("prompt",a,this),t.autofill&&n!=null){if(a.value=a.input=n,t.autofill==="show")await a.submit()}else n=a.value=await a.run();return n}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||ue()}static get prompts(){return Qr()}static get types(){return Jr()}static get prompt(){let e=(t,...s)=>{let r=new this(...s),o=r.emit.bind(r);return r.emit=(...i)=>{return e.emit(...i),o(...i)},r.prompt(t)};return ie.mixinEmitter(e,new It),e}}ie.mixinEmitter(U,new It);var _t=U.prompts;for(let e of Object.keys(_t)){let t=e.toLowerCase(),s=(r)=>new _t[e](r).run();if(U.prompt[t]=s,U[t]=s,!U[e])Reflect.defineProperty(U,e,{get:()=>_t[e]})}var Ae=(e)=>{ie.defineExport(U,e,()=>U.types[e])};Ae("ArrayPrompt");Ae("AuthPrompt");Ae("BooleanPrompt");Ae("NumberPrompt");Ae("StringPrompt");eo.exports=U});var Bi=w((Ut,Gt)=>{(function(e,t){if(typeof Ut==="object"&&typeof Gt==="object")Gt.exports=t();else if(typeof define==="function"&&define.amd)define(function(){return t()});else e.pluralize=t()})(Ut,function(){var e=[],t=[],s={},r={},o={};function i(m){if(typeof m==="string")return new RegExp("^"+m+"$","i");return m}function a(m,h){if(m===h)return h;if(m===m.toLowerCase())return h.toLowerCase();if(m===m.toUpperCase())return h.toUpperCase();if(m[0]===m[0].toUpperCase())return h.charAt(0).toUpperCase()+h.substr(1).toLowerCase();return h.toLowerCase()}function n(m,h){return m.replace(/\$(\d{1,2})/g,function(f,g){return h[g]||""})}function d(m,h){return m.replace(h[0],function(f,g){var y=n(h[1],arguments);if(f==="")return a(m[g-1],y);return a(f,y)})}function l(m,h,f){if(!m.length||s.hasOwnProperty(m))return h;var g=f.length;while(g--){var y=f[g];if(y[0].test(h))return d(h,y)}return h}function c(m,h,f){return function(g){var y=g.toLowerCase();if(h.hasOwnProperty(y))return a(g,y);if(m.hasOwnProperty(y))return a(g,m[y]);return l(y,g,f)}}function u(m,h,f,g){return function(y){var E=y.toLowerCase();if(h.hasOwnProperty(E))return!0;if(m.hasOwnProperty(E))return!1;return l(E,E,f)===E}}function p(m,h,f){var g=h===1?p.singular(m):p.plural(m);return(f?h+" ":"")+g}return p.plural=c(o,r,e),p.isPlural=u(o,r,e),p.singular=c(r,o,t),p.isSingular=u(r,o,t),p.addPluralRule=function(m,h){e.push([i(m),h])},p.addSingularRule=function(m,h){t.push([i(m),h])},p.addUncountableRule=function(m){if(typeof m==="string"){s[m.toLowerCase()]=!0;return}p.addPluralRule(m,"$0"),p.addSingularRule(m,"$0")},p.addIrregularRule=function(m,h){h=h.toLowerCase(),m=m.toLowerCase(),o[m]=h,r[h]=m},[["I","we"],["me","us"],["he","they"],["she","they"],["them","them"],["myself","ourselves"],["yourself","yourselves"],["itself","themselves"],["herself","themselves"],["himself","themselves"],["themself","themselves"],["is","are"],["was","were"],["has","have"],["this","these"],["that","those"],["echo","echoes"],["dingo","dingoes"],["volcano","volcanoes"],["tornado","tornadoes"],["torpedo","torpedoes"],["genus","genera"],["viscus","viscera"],["stigma","stigmata"],["stoma","stomata"],["dogma","dogmata"],["lemma","lemmata"],["schema","schemata"],["anathema","anathemata"],["ox","oxen"],["axe","axes"],["die","dice"],["yes","yeses"],["foot","feet"],["eave","eaves"],["goose","geese"],["tooth","teeth"],["quiz","quizzes"],["human","humans"],["proof","proofs"],["carve","carves"],["valve","valves"],["looey","looies"],["thief","thieves"],["groove","grooves"],["pickaxe","pickaxes"],["passerby","passersby"]].forEach(function(m){return p.addIrregularRule(m[0],m[1])}),[[/s?$/i,"s"],[/[^\u0000-\u007F]$/i,"$0"],[/([^aeiou]ese)$/i,"$1"],[/(ax|test)is$/i,"$1es"],[/(alias|[^aou]us|t[lm]as|gas|ris)$/i,"$1es"],[/(e[mn]u)s?$/i,"$1s"],[/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i,"$1"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1i"],[/(alumn|alg|vertebr)(?:a|ae)$/i,"$1ae"],[/(seraph|cherub)(?:im)?$/i,"$1im"],[/(her|at|gr)o$/i,"$1oes"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i,"$1a"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i,"$1a"],[/sis$/i,"ses"],[/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i,"$1$2ves"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/([^ch][ieo][ln])ey$/i,"$1ies"],[/(x|ch|ss|sh|zz)$/i,"$1es"],[/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i,"$1ices"],[/\b((?:tit)?m|l)(?:ice|ouse)$/i,"$1ice"],[/(pe)(?:rson|ople)$/i,"$1ople"],[/(child)(?:ren)?$/i,"$1ren"],[/eaux$/i,"$0"],[/m[ae]n$/i,"men"],["thou","you"]].forEach(function(m){return p.addPluralRule(m[0],m[1])}),[[/s$/i,""],[/(ss)$/i,"$1"],[/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,"$1fe"],[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i,"$1f"],[/ies$/i,"y"],[/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,"$1ie"],[/\b(mon|smil)ies$/i,"$1ey"],[/\b((?:tit)?m|l)ice$/i,"$1ouse"],[/(seraph|cherub)im$/i,"$1"],[/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,"$1"],[/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,"$1sis"],[/(movie|twelve|abuse|e[mn]u)s$/i,"$1"],[/(test)(?:is|es)$/i,"$1is"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1us"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,"$1um"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,"$1on"],[/(alumn|alg|vertebr)ae$/i,"$1a"],[/(cod|mur|sil|vert|ind)ices$/i,"$1ex"],[/(matr|append)ices$/i,"$1ix"],[/(pe)(rson|ople)$/i,"$1rson"],[/(child)ren$/i,"$1"],[/(eau)x?$/i,"$1"],[/men$/i,"man"]].forEach(function(m){return p.addSingularRule(m[0],m[1])}),["adulthood","advice","agenda","aid","aircraft","alcohol","ammo","analytics","anime","athletics","audio","bison","blood","bream","buffalo","butter","carp","cash","chassis","chess","clothing","cod","commerce","cooperation","corps","debris","diabetes","digestion","elk","energy","equipment","excretion","expertise","firmware","flounder","fun","gallows","garbage","graffiti","hardware","headquarters","health","herpes","highjinks","homework","housework","information","jeans","justice","kudos","labour","literature","machinery","mackerel","mail","media","mews","moose","music","mud","manga","news","only","personnel","pike","plankton","pliers","police","pollution","premises","rain","research","rice","salmon","scissors","series","sewage","shambles","shrimp","software","species","staff","swine","tennis","traffic","transportation","trout","tuna","wealth","welfare","whiting","wildebeest","wildlife","you",/pok[e\u00E9]mon$/i,/[^aeiou]ese$/i,/deer$/i,/fish$/i,/measles$/i,/o[iu]s$/i,/pox$/i,/sheep$/i].forEach(p.addUncountableRule),p})});import{parseArgs as Tm}from"util";import{Exception as na}from"@ooneex/exception";import{TerminalLogger as Rm}from"@ooneex/logger";import{container as ba}from"@ooneex/container";var Te=[];var Ft=(e)=>{let t=null;return Te.find((s)=>{return t=ba.get(s),t.getName()===e}),t};import{homedir as va}from"os";import{join as nt}from"path";import{TerminalLogger as Na}from"@ooneex/logger";import{container as xa,EContainerScope as wa}from"@ooneex/container";var x={command:(e=wa.Singleton)=>{return(t)=>{xa.add(t,e),Te.push(t)}}};var Vt=`#compdef oo ooneex
|
|
30
|
+
`);return this.value={values:r,result:i},super.submit()}}Dr.exports=Or});var Ur=x((Mm,Lr)=>{var yd=re();class Pr extends yd{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0});this.state.hint=[this.options.hint,"(Use <shift>+<up/down> to sort)"].find(this.isValue.bind(this))}indicator(){return""}async renderChoice(e,t){let s=await super.renderChoice(e,t),r=this.symbols.identicalTo+" ",o=this.index===t&&this.sorting?this.styles.muted(r):" ";if(this.options.drag===!1)o="";if(this.options.numbered===!0)return o+`${t+1} - `+s;return o+s}get selected(){return this.choices}submit(){return this.value=this.choices.map((e)=>e.value),super.submit()}}Lr.exports=Pr});var $r=x((Cm,kr)=>{var gd=xe();class Gr extends gd{constructor(e={}){super(e);if(this.emptyError=e.emptyError||"No items were selected",this.term=process.env.TERM_PROGRAM,!this.options.header){let t=["","4 - Strongly Agree","3 - Agree","2 - Neutral","1 - Disagree","0 - Strongly Disagree",""];t=t.map((s)=>this.styles.muted(s)),this.state.header=t.join(`
|
|
31
|
+
`)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let t=await super.toChoices(...e);for(let s of t)s.scale=bd(5,this.options),s.scaleIdx=2;return t}dispatch(){this.alert()}space(){let e=this.focused,t=e.scale[e.scaleIdx],s=t.selected;return e.scale.forEach((r)=>r.selected=!1),t.selected=!s,this.render()}indicator(){return""}pointer(){return""}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;if(e.scaleIdx>=e.scale.length-1)return this.alert();return e.scaleIdx++,this.render()}left(){let e=this.focused;if(e.scaleIdx<=0)return this.alert();return e.scaleIdx--,this.render()}indent(){return" "}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=this.term==="Hyper",o=!r?8:9,i=!r?" ":"",a=this.symbols.line.repeat(o),n=" ".repeat(o+(r?0:1)),d=(E)=>(E?this.styles.success("\u25C9"):"\u25EF")+i,l=t+1+".",p=s?this.styles.heading:this.styles.noop,u=await this.resolve(e.message,this.state,e,t),m=this.indent(e),c=m+e.scale.map((E,A)=>d(A===e.scaleIdx)).join(a),h=(E)=>E===e.scaleIdx?p(E):E,f=m+e.scale.map((E,A)=>h(A)).join(n),g=()=>[l,u].filter(Boolean).join(" "),y=()=>[g(),c,f," "].filter(Boolean).join(`
|
|
32
|
+
`);if(s)c=this.styles.cyan(c),f=this.styles.cyan(f);return y()}async renderChoices(){if(this.state.submitted)return"";let e=this.visible.map(async(s,r)=>await this.renderChoice(s,r)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));return t.join(`
|
|
33
|
+
`)}format(){if(this.state.submitted)return this.choices.map((t)=>this.styles.info(t.scaleIdx)).join(", ");return""}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i=[s,o,r].filter(Boolean).join(" ");this.state.prompt=i;let a=await this.header(),n=await this.format(),d=await this.error()||await this.hint(),l=await this.renderChoices(),p=await this.footer();if(n||!d)i+=" "+n;if(d&&!i.includes(d))i+=" "+d;if(e&&!n&&!l&&this.multiple&&this.type!=="form")i+=this.styles.danger(this.emptyError);this.clear(t),this.write([i,a,l,p].filter(Boolean).join(`
|
|
34
|
+
`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}}function bd(e,t={}){if(Array.isArray(t.scale))return t.scale.map((r)=>({...r}));let s=[];for(let r=1;r<e+1;r++)s.push({i:r,selected:!1});return s}kr.exports=Gr});var Kr=x((_m,Wr)=>{var wd=De();class qr extends wd{async initialize(){await super.initialize(),this.value=this.initial=this.resolve(this.options.initial),this.disabled=this.options.disabled||"no",this.enabled=this.options.enabled||"yes",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e="",t){switch(e.toLowerCase()){case" ":return this.toggle();case"1":case"y":case"t":return this.enable();case"0":case"n":case"f":return this.disable();default:return this.alert()}}format(){let e=(s)=>this.styles.primary.underline(s);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(" / "))}async render(){let{size:e}=this.state,t=await this.header(),s=await this.prefix(),r=await this.separator(),o=await this.message(),i=await this.format(),a=await this.error()||await this.hint(),n=await this.footer(),d=[s,o,r,i].join(" ");if(this.state.prompt=d,a&&!d.includes(a))d+=" "+a;this.clear(e),this.write([t,d,n].filter(Boolean).join(`
|
|
35
|
+
`)),this.write(this.margin[2]),this.restore()}}Wr.exports=qr});var Vr=x((Im,Hr)=>{var xd=re();class Fr extends xd{constructor(e){super(e);if(typeof this.options.correctChoice!=="number"||this.options.correctChoice<0)throw Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,t){let s=await super.toChoices(e,t);if(s.length<2)throw Error("Please give at least two choices to the user");if(this.options.correctChoice>s.length)throw Error("Please specify the index of the correct answer from the list of choices");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}}Hr.exports=Fr});var zr=x((Mt)=>{var Yr=M(),S=(e,t)=>{Yr.defineExport(Mt,e,t),Yr.defineExport(Mt,e.toLowerCase(),t)};S("AutoComplete",()=>$s());S("BasicAuth",()=>zs());S("Confirm",()=>js());S("Editable",()=>sr());S("Form",()=>Oe());S("Input",()=>St());S("Invisible",()=>mr());S("List",()=>fr());S("MultiSelect",()=>br());S("Numeral",()=>Tt());S("Password",()=>vr());S("Scale",()=>Rr());S("Select",()=>re());S("Snippet",()=>Br());S("Sort",()=>Ur());S("Survey",()=>$r());S("Text",()=>St());S("Toggle",()=>Kr());S("Quiz",()=>Vr())});var Qr=x((Dm,Zr)=>{Zr.exports={ArrayPrompt:xe(),AuthPrompt:Nt(),BooleanPrompt:De(),NumberPrompt:Tt(),StringPrompt:de()}});var ie=x((Bm,Jr)=>{var Xr=ge("assert"),_t=ge("events"),oe=M();class L extends _t{constructor(e,t){super();this.options=oe.merge({},e),this.answers={...t}}register(e,t){if(oe.isObject(e)){for(let r of Object.keys(e))this.register(r,e[r]);return this}Xr.equal(typeof t,"function","expected a function");let s=e.toLowerCase();if(t.prototype instanceof this.Prompt)this.prompts[s]=t;else this.prompts[s]=t(this.Prompt,this);return this}async prompt(e=[]){for(let t of[].concat(e))try{if(typeof t==="function")t=await t.call(this);await this.ask(oe.merge({},this.options,t))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){if(typeof e==="function")e=await e.call(this);let t=oe.merge({},this.options,e),{type:s,name:r}=e,{set:o,get:i}=oe;if(typeof s==="function")s=await s.call(this,e,this.answers);if(!s)return this.answers[r];if(s==="number")s="numeral";Xr(this.prompts[s],`Prompt "${s}" is not registered`);let a=new this.prompts[s](t),n=i(this.answers,r);if(a.state.answers=this.answers,a.enquirer=this,r)a.on("submit",(l)=>{this.emit("answer",r,l,a),o(this.answers,r,l)});let d=a.emit.bind(a);if(a.emit=(...l)=>{return this.emit.call(this,...l),d(...l)},this.emit("prompt",a,this),t.autofill&&n!=null){if(a.value=a.input=n,t.autofill==="show")await a.submit()}else n=a.value=await a.run();return n}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||me()}static get prompts(){return zr()}static get types(){return Qr()}static get prompt(){let e=(t,...s)=>{let r=new this(...s),o=r.emit.bind(r);return r.emit=(...i)=>{return e.emit(...i),o(...i)},r.prompt(t)};return oe.mixinEmitter(e,new _t),e}}oe.mixinEmitter(L,new _t);var Ct=L.prompts;for(let e of Object.keys(Ct)){let t=e.toLowerCase(),s=(r)=>new Ct[e](r).run();if(L.prompt[t]=s,L[t]=s,!L[e])Reflect.defineProperty(L,e,{get:()=>Ct[e]})}var Ee=(e)=>{oe.defineExport(L,e,()=>L.types[e])};Ee("ArrayPrompt");Ee("AuthPrompt");Ee("BooleanPrompt");Ee("NumberPrompt");Ee("StringPrompt");Jr.exports=L});var Ii=x((Lt,Ut)=>{(function(e,t){if(typeof Lt==="object"&&typeof Ut==="object")Ut.exports=t();else if(typeof define==="function"&&define.amd)define(function(){return t()});else e.pluralize=t()})(Lt,function(){var e=[],t=[],s={},r={},o={};function i(c){if(typeof c==="string")return new RegExp("^"+c+"$","i");return c}function a(c,h){if(c===h)return h;if(c===c.toLowerCase())return h.toLowerCase();if(c===c.toUpperCase())return h.toUpperCase();if(c[0]===c[0].toUpperCase())return h.charAt(0).toUpperCase()+h.substr(1).toLowerCase();return h.toLowerCase()}function n(c,h){return c.replace(/\$(\d{1,2})/g,function(f,g){return h[g]||""})}function d(c,h){return c.replace(h[0],function(f,g){var y=n(h[1],arguments);if(f==="")return a(c[g-1],y);return a(f,y)})}function l(c,h,f){if(!c.length||s.hasOwnProperty(c))return h;var g=f.length;while(g--){var y=f[g];if(y[0].test(h))return d(h,y)}return h}function p(c,h,f){return function(g){var y=g.toLowerCase();if(h.hasOwnProperty(y))return a(g,y);if(c.hasOwnProperty(y))return a(g,c[y]);return l(y,g,f)}}function u(c,h,f,g){return function(y){var E=y.toLowerCase();if(h.hasOwnProperty(E))return!0;if(c.hasOwnProperty(E))return!1;return l(E,E,f)===E}}function m(c,h,f){var g=h===1?m.singular(c):m.plural(c);return(f?h+" ":"")+g}return m.plural=p(o,r,e),m.isPlural=u(o,r,e),m.singular=p(r,o,t),m.isSingular=u(r,o,t),m.addPluralRule=function(c,h){e.push([i(c),h])},m.addSingularRule=function(c,h){t.push([i(c),h])},m.addUncountableRule=function(c){if(typeof c==="string"){s[c.toLowerCase()]=!0;return}m.addPluralRule(c,"$0"),m.addSingularRule(c,"$0")},m.addIrregularRule=function(c,h){h=h.toLowerCase(),c=c.toLowerCase(),o[c]=h,r[h]=c},[["I","we"],["me","us"],["he","they"],["she","they"],["them","them"],["myself","ourselves"],["yourself","yourselves"],["itself","themselves"],["herself","themselves"],["himself","themselves"],["themself","themselves"],["is","are"],["was","were"],["has","have"],["this","these"],["that","those"],["echo","echoes"],["dingo","dingoes"],["volcano","volcanoes"],["tornado","tornadoes"],["torpedo","torpedoes"],["genus","genera"],["viscus","viscera"],["stigma","stigmata"],["stoma","stomata"],["dogma","dogmata"],["lemma","lemmata"],["schema","schemata"],["anathema","anathemata"],["ox","oxen"],["axe","axes"],["die","dice"],["yes","yeses"],["foot","feet"],["eave","eaves"],["goose","geese"],["tooth","teeth"],["quiz","quizzes"],["human","humans"],["proof","proofs"],["carve","carves"],["valve","valves"],["looey","looies"],["thief","thieves"],["groove","grooves"],["pickaxe","pickaxes"],["passerby","passersby"]].forEach(function(c){return m.addIrregularRule(c[0],c[1])}),[[/s?$/i,"s"],[/[^\u0000-\u007F]$/i,"$0"],[/([^aeiou]ese)$/i,"$1"],[/(ax|test)is$/i,"$1es"],[/(alias|[^aou]us|t[lm]as|gas|ris)$/i,"$1es"],[/(e[mn]u)s?$/i,"$1s"],[/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i,"$1"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1i"],[/(alumn|alg|vertebr)(?:a|ae)$/i,"$1ae"],[/(seraph|cherub)(?:im)?$/i,"$1im"],[/(her|at|gr)o$/i,"$1oes"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i,"$1a"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i,"$1a"],[/sis$/i,"ses"],[/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i,"$1$2ves"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/([^ch][ieo][ln])ey$/i,"$1ies"],[/(x|ch|ss|sh|zz)$/i,"$1es"],[/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i,"$1ices"],[/\b((?:tit)?m|l)(?:ice|ouse)$/i,"$1ice"],[/(pe)(?:rson|ople)$/i,"$1ople"],[/(child)(?:ren)?$/i,"$1ren"],[/eaux$/i,"$0"],[/m[ae]n$/i,"men"],["thou","you"]].forEach(function(c){return m.addPluralRule(c[0],c[1])}),[[/s$/i,""],[/(ss)$/i,"$1"],[/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,"$1fe"],[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i,"$1f"],[/ies$/i,"y"],[/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,"$1ie"],[/\b(mon|smil)ies$/i,"$1ey"],[/\b((?:tit)?m|l)ice$/i,"$1ouse"],[/(seraph|cherub)im$/i,"$1"],[/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,"$1"],[/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,"$1sis"],[/(movie|twelve|abuse|e[mn]u)s$/i,"$1"],[/(test)(?:is|es)$/i,"$1is"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1us"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,"$1um"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,"$1on"],[/(alumn|alg|vertebr)ae$/i,"$1a"],[/(cod|mur|sil|vert|ind)ices$/i,"$1ex"],[/(matr|append)ices$/i,"$1ix"],[/(pe)(rson|ople)$/i,"$1rson"],[/(child)ren$/i,"$1"],[/(eau)x?$/i,"$1"],[/men$/i,"man"]].forEach(function(c){return m.addSingularRule(c[0],c[1])}),["adulthood","advice","agenda","aid","aircraft","alcohol","ammo","analytics","anime","athletics","audio","bison","blood","bream","buffalo","butter","carp","cash","chassis","chess","clothing","cod","commerce","cooperation","corps","debris","diabetes","digestion","elk","energy","equipment","excretion","expertise","firmware","flounder","fun","gallows","garbage","graffiti","hardware","headquarters","health","herpes","highjinks","homework","housework","information","jeans","justice","kudos","labour","literature","machinery","mackerel","mail","media","mews","moose","music","mud","manga","news","only","personnel","pike","plankton","pliers","police","pollution","premises","rain","research","rice","salmon","scissors","series","sewage","shambles","shrimp","software","species","staff","swine","tennis","traffic","transportation","trout","tuna","wealth","welfare","whiting","wildebeest","wildlife","you",/pok[e\u00E9]mon$/i,/[^aeiou]ese$/i,/deer$/i,/fish$/i,/measles$/i,/o[iu]s$/i,/pox$/i,/sheep$/i].forEach(m.addUncountableRule),m})});import{parseArgs as Np}from"util";import{Exception as oa}from"@ooneex/exception";import{TerminalLogger as Sp}from"@ooneex/logger";import{container as ga}from"@ooneex/container";var Se=[];var Kt=(e)=>{let t=null;return Se.find((s)=>{return t=ga.get(s),t.getName()===e}),t};import{homedir as Aa}from"os";import{join as at}from"path";import{TerminalLogger as va}from"@ooneex/logger";import{container as ba,EContainerScope as wa}from"@ooneex/container";var w={command:(e=wa.Singleton)=>{return(t)=>{ba.add(t,e),Se.push(t)}}};var Ft=`#compdef oo ooneex
|
|
36
36
|
|
|
37
37
|
_oo_modules() {
|
|
38
38
|
local -a modules
|
|
@@ -145,7 +145,7 @@ _oo() {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
_oo "$@"
|
|
148
|
-
`;var
|
|
148
|
+
`;var Ht=`#compdef oo ooneex
|
|
149
149
|
|
|
150
150
|
_ooneex_modules() {
|
|
151
151
|
local -a modules
|
|
@@ -258,9 +258,9 @@ _ooneex() {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
_ooneex "$@"
|
|
261
|
-
`;class
|
|
261
|
+
`;class Te{getName(){return"completion:zsh"}getDescription(){return"Install Zsh completion for oo command"}async run(){let e=at(Aa(),".zsh"),t=at(e,"_oo");await Bun.write(t,Ft);let s=at(e,"_ooneex");await Bun.write(s,Ht);let r=new va;r.success(`${t} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),r.success(`${s} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),r.info(`Add the following to your .zshrc if not already present:
|
|
262
262
|
fpath=(~/.zsh $fpath)
|
|
263
|
-
autoload -Uz compinit && compinit`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}
|
|
263
|
+
autoload -Uz compinit && compinit`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Te=b([w.command()],Te);import{join as F}from"path";import{TerminalLogger as Rd}from"@ooneex/logger";import{toPascalCase as Md}from"@ooneex/utils";var jr=ee(ie(),1);import{Assert as Ed,Validation as Ad}from"@ooneex/validation";var vd=1,Nd=/^[a-zA-Z][a-zA-Z0-9-]*$/;class Ae extends Ad{getConstraint(){return Ed(`string >= ${vd}`)}getErrorMessage(){return"Name must start with a letter and contain only letters, numbers, and hyphens"}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(!Nd.test(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid name format"};return{isValid:!0}}}var v=async(e)=>{return(await jr.prompt({type:"input",name:"name",message:e.message,validate:(s)=>{let o=new Ae().validate(s);if(!o.isValid)return o.message||"Controller name is invalid";return!0}})).name};var eo=`import { describe, expect, test } from "bun:test";
|
|
264
264
|
import { {{NAME}}Ai } from "@/ai/{{NAME}}Ai";
|
|
265
265
|
|
|
266
266
|
describe("{{NAME}}Ai", () => {
|
|
@@ -278,7 +278,7 @@ describe("{{NAME}}Ai", () => {
|
|
|
278
278
|
expect(typeof {{NAME}}Ai.prototype.runStream).toBe("function");
|
|
279
279
|
});
|
|
280
280
|
});
|
|
281
|
-
`;var
|
|
281
|
+
`;var to=`import { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from "@ooneex/ai";
|
|
282
282
|
import { inject } from "@ooneex/container";
|
|
283
283
|
|
|
284
284
|
@decorator.ai()
|
|
@@ -296,7 +296,7 @@ export class {{NAME}}Ai implements IAiChat<OpenAiConfigType> {
|
|
|
296
296
|
yield* this.ai.runStream(prompt || "My prompt", config);
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
|
-
`;class
|
|
299
|
+
`;class Pe{getName(){return"make:ai"}getDescription(){return"Generate a new AI class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter name"});t=Md(t).replace(/Ai$/,"");let r=to.replace(/{{NAME}}/g,t),o=s?F("modules",s):".",i=F(o,"src","ai"),a=F(process.cwd(),i),n=F(a,`${t}Ai.ts`);await Bun.write(n,r);let d=eo.replace(/{{NAME}}/g,t),l=F(o,"tests","ai"),p=F(process.cwd(),l),u=F(p,`${t}Ai.spec.ts`);await Bun.write(u,d);let m=new Rd;m.success(`${F(i,t)}Ai.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${F(l,t)}Ai.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/ai"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Pe=b([w.command()],Pe);import{join as H}from"path";import{TerminalLogger as Id}from"@ooneex/logger";import{toPascalCase as Od}from"@ooneex/utils";var so=`import { describe, expect, test } from "bun:test";
|
|
300
300
|
import { {{NAME}}Analytics } from "@/analytics/{{NAME}}Analytics";
|
|
301
301
|
|
|
302
302
|
describe("{{NAME}}Analytics", () => {
|
|
@@ -309,7 +309,7 @@ describe("{{NAME}}Analytics", () => {
|
|
|
309
309
|
expect(typeof {{NAME}}Analytics.prototype.capture).toBe("function");
|
|
310
310
|
});
|
|
311
311
|
});
|
|
312
|
-
`;var
|
|
312
|
+
`;var ro=`import { decorator } from "@ooneex/analytics";
|
|
313
313
|
import type { IAnalytics } from "@ooneex/analytics";
|
|
314
314
|
|
|
315
315
|
type CaptureOptionsType = Record<string, unknown>;
|
|
@@ -320,7 +320,7 @@ export class {{NAME}}Analytics<T extends CaptureOptionsType = CaptureOptionsType
|
|
|
320
320
|
// console.log("Analytics captured:", options);
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
-
`;class
|
|
323
|
+
`;class Le{getName(){return"make:analytics"}getDescription(){return"Generate a new analytics class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter analytics name"});t=Od(t).replace(/Analytics$/,"");let r=ro.replace(/{{NAME}}/g,t),o=s?H("modules",s):".",i=H(o,"src","analytics"),a=H(process.cwd(),i),n=H(a,`${t}Analytics.ts`);await Bun.write(n,r);let d=so.replace(/{{NAME}}/g,t),l=H(o,"tests","analytics"),p=H(process.cwd(),l),u=H(p,`${t}Analytics.spec.ts`);await Bun.write(u,d);let m=new Id;m.success(`${H(i,t)}Analytics.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${H(l,t)}Analytics.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/analytics"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Le=b([w.command()],Le);import{join as T}from"path";import{TerminalLogger as bl}from"@ooneex/logger";import{toKebabCase as wl,toSnakeCase as xl}from"@ooneex/utils";var oo=ee(ie(),1);var io=async(e)=>{let t=new Ae;return(await oo.prompt({type:"input",name:"destination",message:e.message,initial:e.initial||".",validate:(r)=>{let o=t.validate(r);if(!o.isValid)return o.message||"Invalid destination";return!0}})).destination};var ao=`import { RuleConfigSeverity, type UserConfig } from "@commitlint/types";
|
|
324
324
|
|
|
325
325
|
const Configuration: UserConfig = {
|
|
326
326
|
extends: ["@commitlint/config-conventional"],
|
|
@@ -460,7 +460,7 @@ const Configuration: UserConfig = {
|
|
|
460
460
|
};
|
|
461
461
|
|
|
462
462
|
export default Configuration;
|
|
463
|
-
`;var
|
|
463
|
+
`;var no=`# Logs
|
|
464
464
|
logs
|
|
465
465
|
*.log
|
|
466
466
|
npm-debug.log*
|
|
@@ -610,7 +610,7 @@ vite.config.ts.timestamp-*
|
|
|
610
610
|
|
|
611
611
|
# Application
|
|
612
612
|
var/
|
|
613
|
-
`;var
|
|
613
|
+
`;var lo=`import { inject } from "@ooneex/container";
|
|
614
614
|
import { AppEnv } from "@ooneex/app-env";
|
|
615
615
|
import { DataSource } from "typeorm";
|
|
616
616
|
import { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";
|
|
@@ -644,7 +644,7 @@ export class AppDatabase extends TypeormDatabase {
|
|
|
644
644
|
return this.source;
|
|
645
645
|
}
|
|
646
646
|
}
|
|
647
|
-
`;var
|
|
647
|
+
`;var co=`{
|
|
648
648
|
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
649
649
|
"vcs": {
|
|
650
650
|
"enabled": true,
|
|
@@ -723,7 +723,7 @@ export class AppDatabase extends TypeormDatabase {
|
|
|
723
723
|
}
|
|
724
724
|
}
|
|
725
725
|
}
|
|
726
|
-
`;var
|
|
726
|
+
`;var po=`[test]
|
|
727
727
|
coverage = true
|
|
728
728
|
|
|
729
729
|
[workspace]
|
|
@@ -754,7 +754,7 @@ buildDependencies = [
|
|
|
754
754
|
"@swc/core",
|
|
755
755
|
"nx",
|
|
756
756
|
]
|
|
757
|
-
`;var
|
|
757
|
+
`;var mo=`# use the official Bun image
|
|
758
758
|
# see all versions at https://hub.docker.com/r/oven/bun/tags
|
|
759
759
|
FROM oven/bun:1 AS base
|
|
760
760
|
WORKDIR /{{NAME}}
|
|
@@ -801,7 +801,7 @@ COPY --from=prerelease /{{NAME}}/dist .
|
|
|
801
801
|
USER bun
|
|
802
802
|
EXPOSE 3000/tcp
|
|
803
803
|
ENTRYPOINT [ "bun", "run", "index.js" ]
|
|
804
|
-
`;var
|
|
804
|
+
`;var uo=`services:
|
|
805
805
|
# PostgreSQL - Primary relational database
|
|
806
806
|
# Docs: https://www.postgresql.org/docs/
|
|
807
807
|
# Connection: postgresql://ooneex:ooneex@localhost:5432/ooneex
|
|
@@ -835,7 +835,7 @@ ENTRYPOINT [ "bun", "run", "index.js" ]
|
|
|
835
835
|
volumes:
|
|
836
836
|
{{NAME}}_db_data:
|
|
837
837
|
{{NAME}}_redis_data:
|
|
838
|
-
`;var
|
|
838
|
+
`;var It=`# =============================================================================
|
|
839
839
|
# App
|
|
840
840
|
# =============================================================================
|
|
841
841
|
|
|
@@ -1036,7 +1036,7 @@ SYSTEM_USERS=
|
|
|
1036
1036
|
SUPER_ADMIN_USERS=
|
|
1037
1037
|
# Comma-separated admin user emails
|
|
1038
1038
|
ADMIN_USERS=
|
|
1039
|
-
`;var
|
|
1039
|
+
`;var ho=`import { PostHogAnalytics } from "@ooneex/analytics";
|
|
1040
1040
|
import { App } from "@ooneex/app";
|
|
1041
1041
|
import { RedisCache } from "@ooneex/cache";
|
|
1042
1042
|
import { LogtailLogger, ExceptionLogger, TerminalLogger } from "@ooneex/logger";
|
|
@@ -1065,7 +1065,7 @@ const app = new App({
|
|
|
1065
1065
|
});
|
|
1066
1066
|
|
|
1067
1067
|
await app.run();
|
|
1068
|
-
`;var
|
|
1068
|
+
`;var fo=`{
|
|
1069
1069
|
"$schema": "./node_modules/nx/schemas/nx-schema.json",
|
|
1070
1070
|
"targetDefaults": {
|
|
1071
1071
|
"build": {
|
|
@@ -1095,7 +1095,7 @@ await app.run();
|
|
|
1095
1095
|
],
|
|
1096
1096
|
"packageManager": "bun"
|
|
1097
1097
|
}
|
|
1098
|
-
`;var
|
|
1098
|
+
`;var yo=`{
|
|
1099
1099
|
"name": "{{NAME}}",
|
|
1100
1100
|
"scripts": {
|
|
1101
1101
|
"dev": "bun run --filter app dev",
|
|
@@ -1118,7 +1118,7 @@ await app.run();
|
|
|
1118
1118
|
]
|
|
1119
1119
|
}
|
|
1120
1120
|
}
|
|
1121
|
-
`;var
|
|
1121
|
+
`;var go=`# {{NAME}}
|
|
1122
1122
|
|
|
1123
1123
|
A modular, enterprise-grade backend framework built with TypeScript and Bun, powered by the **@ooneex** ecosystem.
|
|
1124
1124
|
|
|
@@ -1274,7 +1274,7 @@ This creates \`.claude/skills/\` in your project with skill guides for each \`ma
|
|
|
1274
1274
|
## License
|
|
1275
1275
|
|
|
1276
1276
|
Proprietary - All rights reserved.
|
|
1277
|
-
`;var
|
|
1277
|
+
`;var bo=`{
|
|
1278
1278
|
"compilerOptions": {
|
|
1279
1279
|
"jsx": "react-jsx",
|
|
1280
1280
|
"lib": ["ES2022", "DOM"],
|
|
@@ -1303,7 +1303,7 @@ Proprietary - All rights reserved.
|
|
|
1303
1303
|
},
|
|
1304
1304
|
"exclude": ["node_modules", ".github", ".husky", ".nx", ".zed", ".vscode"]
|
|
1305
1305
|
}
|
|
1306
|
-
`;var
|
|
1306
|
+
`;var wo=`{
|
|
1307
1307
|
"formatter": "language_server",
|
|
1308
1308
|
"format_on_save": "on",
|
|
1309
1309
|
"languages": {
|
|
@@ -1405,11 +1405,25 @@ Proprietary - All rights reserved.
|
|
|
1405
1405
|
}
|
|
1406
1406
|
}
|
|
1407
1407
|
}
|
|
1408
|
-
`;import{basename as
|
|
1408
|
+
`;import{basename as nl,join as U}from"path";import{TerminalLogger as dl}from"@ooneex/logger";import{toKebabCase as ll,toPascalCase as Ue,trim as cl}from"@ooneex/utils";var xo=ee(ie(),1),he=async(e)=>{return(await xo.prompt({type:"confirm",name:"confirm",message:e.message})).confirm};var ve=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD"];var Eo=ee(ie(),1);import{Assert as Yd,Validation as zd}from"@ooneex/validation";class Ot extends zd{getConstraint(){return Yd("string >= 3")}getErrorMessage(){return`Route method must be one of: ${ve.join(", ")}`}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(r.trim()!==r)return{isValid:!1,message:this.getErrorMessage()||"Invalid route method format"};let o=r.toUpperCase();if(!ve.includes(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid route method"};return{isValid:!0}}}var Ao=async(e)=>{return(await Eo.prompt({type:"select",name:"method",message:e.message,initial:e.initial??0,choices:ve.map((s)=>s),validate:(s)=>{let o=new Ot().validate(s);if(!o.isValid)return o.message||"Route method is invalid";return!0}})).method};var vo=ee(ie(),1);import{Assert as Zd,Validation as Qd}from"@ooneex/validation";var Xd=/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/;class Dt extends Qd{getConstraint(){return Zd("string >= 7")}getErrorMessage(){return"Route name must follow format: namespace.resource.action (e.g., 'api.users.list')"}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(r.trim()!==r)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};if(!Xd.test(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let o=r.split(".");if(o.length!==3)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let[i,a,n]=o;if(!i||!a||!n)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};return{isValid:!0}}}var No=async(e)=>{return(await vo.prompt({type:"input",name:"routeName",message:e.message,validate:(s)=>{let o=new Dt().validate(s);if(!o.isValid)return o.message||"Route name is invalid";return!0}})).routeName};var So=ee(ie(),1);import{Assert as Jd,Validation as jd}from"@ooneex/validation";var el=1,tl=/^\/[\w\-/:]*$/,sl=/^[a-zA-Z0-9\-_]+$/,rl=/^:[a-zA-Z][a-zA-Z0-9]*$/;class Bt extends jd{getConstraint(){return Jd(`string >= ${el}`)}getErrorMessage(){return"Route path must start with '/' and contain only valid segments (e.g., '/users', '/api/users/:id')"}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(r.trim()!==r)return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(!r.startsWith("/"))return{isValid:!1,message:"Route path must start with '/'"};if(r.length>1&&r.endsWith("/"))return{isValid:!1,message:"Route path cannot end with '/' (except for root path)"};if(!tl.test(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(r==="/")return{isValid:!0};let o=r.slice(1).split("/");for(let i of o){if(!i)return{isValid:!1,message:"Route path cannot contain empty segments (double slashes)"};if(i.startsWith(":")){if(!rl.test(i))return{isValid:!1,message:`Invalid parameter segment '${i}'. Parameters must follow format ':paramName' with alphanumeric characters only`}}else if(!sl.test(i))return{isValid:!1,message:`Invalid path segment '${i}'. Segments must contain only letters, numbers, hyphens, and underscores`}}return{isValid:!0}}}var To=async(e)=>{return(await So.prompt({type:"input",name:"path",message:e.message,initial:e.initial??"/",validate:(s)=>{let o=new Bt().validate(s);if(!o.isValid)return o.message||"Route path is invalid";return!0}})).path};var Ro=`import type { ContextType } from "@ooneex/socket";
|
|
1409
1409
|
import { ERole } from "@ooneex/role";
|
|
1410
1410
|
import { Route } from "@ooneex/routing";
|
|
1411
1411
|
import { Assert } from "@ooneex/validation";
|
|
1412
|
-
|
|
1412
|
+
|
|
1413
|
+
export type {{TYPE_NAME}}RouteType = {
|
|
1414
|
+
params: {
|
|
1415
|
+
|
|
1416
|
+
},
|
|
1417
|
+
payload: {
|
|
1418
|
+
|
|
1419
|
+
},
|
|
1420
|
+
queries: {
|
|
1421
|
+
|
|
1422
|
+
},
|
|
1423
|
+
response: {
|
|
1424
|
+
|
|
1425
|
+
},
|
|
1426
|
+
};
|
|
1413
1427
|
|
|
1414
1428
|
@Route.socket("{{ROUTE_PATH}}", {
|
|
1415
1429
|
name: "{{ROUTE_NAME}}",
|
|
@@ -1438,7 +1452,7 @@ export class {{NAME}}Controller {
|
|
|
1438
1452
|
});
|
|
1439
1453
|
}
|
|
1440
1454
|
}
|
|
1441
|
-
`;var
|
|
1455
|
+
`;var Mo=`import { describe, expect, test } from "bun:test";
|
|
1442
1456
|
import { {{NAME}}Controller } from "@/controllers/{{NAME}}Controller";
|
|
1443
1457
|
|
|
1444
1458
|
describe("{{NAME}}Controller", () => {
|
|
@@ -1451,11 +1465,25 @@ describe("{{NAME}}Controller", () => {
|
|
|
1451
1465
|
expect(typeof {{NAME}}Controller.prototype.index).toBe("function");
|
|
1452
1466
|
});
|
|
1453
1467
|
});
|
|
1454
|
-
`;var
|
|
1468
|
+
`;var Co=`import type { ContextType } from "@ooneex/controller";
|
|
1455
1469
|
import { ERole } from "@ooneex/role";
|
|
1456
1470
|
import { Route } from "@ooneex/routing";
|
|
1457
1471
|
import { Assert } from "@ooneex/validation";
|
|
1458
|
-
|
|
1472
|
+
|
|
1473
|
+
export type {{TYPE_NAME}}RouteType = {
|
|
1474
|
+
params: {
|
|
1475
|
+
|
|
1476
|
+
},
|
|
1477
|
+
payload: {
|
|
1478
|
+
|
|
1479
|
+
},
|
|
1480
|
+
queries: {
|
|
1481
|
+
|
|
1482
|
+
},
|
|
1483
|
+
response: {
|
|
1484
|
+
|
|
1485
|
+
},
|
|
1486
|
+
};
|
|
1459
1487
|
|
|
1460
1488
|
@Route.{{ROUTE_METHOD}}("{{ROUTE_PATH}}", {
|
|
1461
1489
|
name: "{{ROUTE_NAME}}",
|
|
@@ -1484,23 +1512,9 @@ export class {{NAME}}Controller {
|
|
|
1484
1512
|
});
|
|
1485
1513
|
}
|
|
1486
1514
|
}
|
|
1487
|
-
`;
|
|
1488
|
-
params: {
|
|
1489
|
-
|
|
1490
|
-
},
|
|
1491
|
-
payload: {
|
|
1492
|
-
|
|
1493
|
-
},
|
|
1494
|
-
queries: {
|
|
1495
|
-
|
|
1496
|
-
},
|
|
1497
|
-
response: {
|
|
1498
|
-
|
|
1499
|
-
},
|
|
1500
|
-
};
|
|
1501
|
-
`;class ye{getName(){return"make:controller"}getDescription(){return"Generate a new controller class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Controller`,o=`import { ${r} } from "./controllers/${r}";
|
|
1515
|
+
`;class fe{getName(){return"make:controller"}getDescription(){return"Generate a new controller class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Controller`,o=`import { ${r} } from "./controllers/${r}";
|
|
1502
1516
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
1503
|
-
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(controllers:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),
|
|
1517
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(controllers:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),p=l?`${l}, ${r}`:r;s=s.replace(n,`$1${p}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:r}=e;if(!t)t=await v({message:"Enter controller name"});if(r===void 0)r=await he({message:"Is this a socket controller?"});t=Ue(t).replace(/Controller$/,"");let{route:o={}}=e,a=(r?Ro:Co).replaceAll("{{NAME}}",t);if(!o.name)o.name=await No({message:"Enter route name (e.g., api.user.create)"});let n=Ue(o.name);if(a=a.replaceAll("{{ROUTE_NAME}}",o.name).replaceAll("{{TYPE_NAME}}",n),!o.path)o.path=await To({message:"Enter route path",initial:"/"});let d=`/${ll(cl(o.path,"/"))}`;if(a=a.replaceAll("{{ROUTE_PATH}}",d),!r&&!o.method)o.method=await Ao({message:"Enter route method"});if(!r&&o.method)a=a.replaceAll("{{ROUTE_METHOD}}",o.method.toLowerCase());let l=s?U("modules",s):".",p=U(l,"src","controllers"),u=U(process.cwd(),p),m=U(u,`${t}Controller.ts`);await Bun.write(m,a);let c=Mo.replace(/{{NAME}}/g,t),h=U(l,"tests","controllers"),f=U(process.cwd(),h),g=U(f,`${t}Controller.spec.ts`);await Bun.write(g,c);let y=s?Ue(s):Ue(nl(process.cwd())),E=U(process.cwd(),l,"src",`${y}Module.ts`);if(await Bun.file(E).exists())await this.addToModule(E,t);let A=new dl;A.success(`${U(p,t)}Controller.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),A.success(`${U(h,t)}Controller.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/controller"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}fe=b([w.command()],fe);import{join as B}from"path";import{TerminalLogger as fl}from"@ooneex/logger";import{toKebabCase as yl,toPascalCase as gl}from"@ooneex/utils";var _o=`import type { ModuleType } from "@ooneex/module";
|
|
1504
1518
|
|
|
1505
1519
|
export const {{NAME}}Module: ModuleType = {
|
|
1506
1520
|
controllers: [],
|
|
@@ -1509,7 +1523,7 @@ export const {{NAME}}Module: ModuleType = {
|
|
|
1509
1523
|
cronJobs: [],
|
|
1510
1524
|
events: [],
|
|
1511
1525
|
};
|
|
1512
|
-
`;var
|
|
1526
|
+
`;var Io=`{
|
|
1513
1527
|
"name": "@module/{{NAME}}",
|
|
1514
1528
|
"description": "",
|
|
1515
1529
|
"version": "0.0.1",
|
|
@@ -1518,7 +1532,7 @@ export const {{NAME}}Module: ModuleType = {
|
|
|
1518
1532
|
"lint": "tsgo --noEmit && bunx biome lint"
|
|
1519
1533
|
}
|
|
1520
1534
|
}
|
|
1521
|
-
`;var
|
|
1535
|
+
`;var Oo=`import { describe, expect, test } from "bun:test";
|
|
1522
1536
|
import { {{NAME}}Module } from "@/{{NAME}}Module";
|
|
1523
1537
|
|
|
1524
1538
|
describe("{{NAME}}Module", () => {
|
|
@@ -1542,7 +1556,7 @@ describe("{{NAME}}Module", () => {
|
|
|
1542
1556
|
expect(Array.isArray({{NAME}}Module.events)).toBe(true);
|
|
1543
1557
|
});
|
|
1544
1558
|
});
|
|
1545
|
-
`;var
|
|
1559
|
+
`;var Do=`{
|
|
1546
1560
|
"extends": "../../tsconfig.json",
|
|
1547
1561
|
"compilerOptions": {
|
|
1548
1562
|
"types": ["@types/bun"],
|
|
@@ -1553,13 +1567,13 @@ describe("{{NAME}}Module", () => {
|
|
|
1553
1567
|
"include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx"],
|
|
1554
1568
|
"exclude": ["node_modules", "dist"]
|
|
1555
1569
|
}
|
|
1556
|
-
`;class
|
|
1570
|
+
`;class ye{getName(){return"make:module"}getDescription(){return"Generate a new module"}async addToAppModule(e,t,s){let r=await Bun.file(e).text(),o=`${t}Module`,i=`@${s}/${o}`,a=`import { ${o} } from "${i}";
|
|
1557
1571
|
`,n=r.lastIndexOf("import "),d=r.indexOf(`
|
|
1558
|
-
`,n);r=`${r.slice(0,d+1)}${a}${r.slice(d+1)}`;let l=["controllers","entities","middlewares","cronJobs","events"];for(let
|
|
1572
|
+
`,n);r=`${r.slice(0,d+1)}${a}${r.slice(d+1)}`;let l=["controllers","entities","middlewares","cronJobs","events"];for(let p of l){let u=new RegExp(`(${p}:\\s*\\[)([^\\]]*)`,"s"),m=r.match(u);if(m){let c=m[2]?.trim(),h=`...${o}.${p}`,f=c?`${c}, ${h}`:h;r=r.replace(u,`$1${f}`)}}await Bun.write(e,r)}async addModuleScope(e,t){let s=await Bun.file(e).text(),r=/("scope-enum":\s*\[\s*RuleConfigSeverity\.Error,\s*"always",\s*\[)([\s\S]*?)(\])/,o=s.match(r);if(o){let i=o[2]?.trim()??"",a=`"${t}"`;if(!i.includes(a)){let n=i?`${i}
|
|
1559
1573
|
${a},`:`
|
|
1560
1574
|
${a},`;s=s.replace(r,`$1${n}
|
|
1561
1575
|
$3`),await Bun.write(e,s)}}}async addPathAlias(e,t){let s=await Bun.file(e).text(),r=JSON.parse(s);r.compilerOptions??={},r.compilerOptions.paths??={},r.compilerOptions.paths[`@${t}/*`]=[`../${t}/src/*`],await Bun.write(e,`${JSON.stringify(r,null,2)}
|
|
1562
|
-
`)}async run(e){let{cwd:t=process.cwd(),silent:s=!1,skipMigrations:r=!1,skipSeeds:o=!1}=e,{name:i}=e;if(!i)i=await v({message:"Enter module name"});let a=
|
|
1576
|
+
`)}async run(e){let{cwd:t=process.cwd(),silent:s=!1,skipMigrations:r=!1,skipSeeds:o=!1}=e,{name:i}=e;if(!i)i=await v({message:"Enter module name"});let a=gl(i).replace(/Module$/,""),n=yl(a),d=B(t,"modules",n),l=B(d,"src"),p=B(d,"tests"),u=_o.replace(/{{NAME}}/g,a),m=Io.replace(/{{NAME}}/g,n),c=Oo.replace(/{{NAME}}/g,a);if(await Bun.write(B(l,`${a}Module.ts`),u),!r)await Bun.write(B(l,"migrations","migrations.ts"),"");if(!o)await Bun.write(B(l,"seeds","seeds.ts"),"");if(await Bun.write(B(d,"package.json"),m),await Bun.write(B(d,"tsconfig.json"),Do),await Bun.write(B(p,`${a}Module.spec.ts`),c),n!=="app"){let g=B(t,"modules","app","src","AppModule.ts");if(await Bun.file(g).exists())await this.addToAppModule(g,a,n);let y=B(t,"modules","app","tsconfig.json");if(await Bun.file(y).exists())await this.addPathAlias(y,n)}let h=B(t,".commitlintrc.ts");if(await Bun.file(h).exists())await this.addModuleScope(h,n);if(!s)new fl().success(`modules/${n} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});await Bun.spawn(["bun","add","@ooneex/module"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}ye=b([w.command()],ye);class Ge{getName(){return"make:app"}getDescription(){return"Generate a new application"}async run(e){let{name:t,destination:s}=e;if(!t)t=await v({message:"Enter application name"});let r=wl(t);if(!s)s=await io({message:"Enter destination path",initial:r});let o=yo.replace(/{{NAME}}/g,r);await Bun.write(T(s,".commitlintrc.ts"),ao),await Bun.write(T(s,".gitignore"),no),await Bun.write(T(s,"biome.jsonc"),co),await Bun.write(T(s,"bunfig.toml"),po),await Bun.write(T(s,"nx.json"),fo),await Bun.write(T(s,"package.json"),o),await Bun.write(T(s,"README.md"),go.replace(/{{NAME}}/g,r)),await Bun.write(T(s,"tsconfig.json"),bo),await Bun.write(T(s,".zed","settings.json"),wo),await new ye().run({name:"app",cwd:s,silent:!0,skipMigrations:!0,skipSeeds:!0});let a=T(s,"modules","app","package.json"),n=await Bun.file(a).json();n.scripts.dev="docker compose up -d && bun --hot run ./src/index.ts",n.scripts.build="bun build ./src/index.ts --outdir ./dist --target bun",await Bun.write(a,JSON.stringify(n,null,2));let d=It.replace(/^DATABASE_URL=/m,'DATABASE_URL="postgresql://ooneex:ooneex@localhost:5432/ooneex"').replace(/^CACHE_REDIS_URL=/m,'CACHE_REDIS_URL="redis://localhost:6379"').replace(/^PUBSUB_REDIS_URL=/m,'PUBSUB_REDIS_URL="redis://localhost:6379"').replace(/^RATE_LIMIT_REDIS_URL=/m,'RATE_LIMIT_REDIS_URL="redis://localhost:6379"').replace(/^DATABASE_REDIS_URL=/m,'DATABASE_REDIS_URL="redis://localhost:6379"');await Bun.write(T(s,"modules","app",".env"),d),await Bun.write(T(s,"modules","app",".env.example"),It),await Bun.write(T(s,"modules","app","src","databases","AppDatabase.ts"),lo),await Bun.write(T(s,"modules","app","src","index.ts"),ho);let l=xl(t),p=uo.replace(/{{NAME}}/g,l);await Bun.write(T(s,"modules","app","docker-compose.yml"),p);let u=mo.replace(/{{NAME}}/g,l);await Bun.write(T(s,"modules","app","Dockerfile"),u),await Bun.write(T(s,"modules","app","var",".gitkeep"),""),await new fe().run({name:"HealthCheck",isSocket:!1,module:"app",route:{name:"api.health.check",path:"/healthcheck",method:"GET"}}),await Bun.spawn(["git","init"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.spawn(["bun","add","@ooneex/analytics","@ooneex/app","@ooneex/app-env","@ooneex/auth","@ooneex/cache","@ooneex/container","@ooneex/database","@ooneex/logger","@ooneex/mailer","@ooneex/middleware","@ooneex/module","@ooneex/rate-limit","@ooneex/role","@ooneex/routing","@ooneex/storage","@ooneex/translation","@ooneex/types","@ooneex/user","@ooneex/utils","@ooneex/validation","@ooneex/controller","pg","apache-arrow","reflect-metadata","typeorm"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.spawn(["bun","add","-D","@biomejs/biome","@commitlint/cli","@commitlint/config-conventional","@commitlint/prompt-cli","@commitlint/types","@nx/js","@nx/workspace","@swc-node/register","@swc/core","@swc/helpers","@types/bun","@types/node","@typescript/native-preview","husky","lint-staged","nx","typescript","undici-types"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.spawn(["bunx","husky","init"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.write(T(s,".husky","pre-commit"),"lint-staged"),await Bun.write(T(s,".husky","commit-msg"),'bunx commitlint --edit "$1"'),new bl().success(`${r} created successfully at ${s}`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Ge=b([w.command()],Ge);import{join as V}from"path";import{TerminalLogger as vl}from"@ooneex/logger";import{toPascalCase as Nl}from"@ooneex/utils";var Bo=`import { describe, expect, test } from "bun:test";
|
|
1563
1577
|
import { {{NAME}}Cache } from "@/cache/{{NAME}}Cache";
|
|
1564
1578
|
|
|
1565
1579
|
describe("{{NAME}}Cache", () => {
|
|
@@ -1587,7 +1601,7 @@ describe("{{NAME}}Cache", () => {
|
|
|
1587
1601
|
expect(typeof {{NAME}}Cache.prototype.has).toBe("function");
|
|
1588
1602
|
});
|
|
1589
1603
|
});
|
|
1590
|
-
`;var
|
|
1604
|
+
`;var Po=`import { CacheException, decorator } from "@ooneex/cache";
|
|
1591
1605
|
import type { ICache } from "@ooneex/cache";
|
|
1592
1606
|
|
|
1593
1607
|
@decorator.cache()
|
|
@@ -1608,7 +1622,7 @@ export class {{NAME}}Cache implements ICache {
|
|
|
1608
1622
|
throw new CacheException(\`Failed to check if key "\${key}" exists: Not implemented\`);
|
|
1609
1623
|
}
|
|
1610
1624
|
}
|
|
1611
|
-
`;class
|
|
1625
|
+
`;class ke{getName(){return"make:cache"}getDescription(){return"Generate a new cache class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter cache name"});t=Nl(t).replace(/Cache$/,"");let r=Po.replace(/{{NAME}}/g,t),o=s?V("modules",s):".",i=V(o,"src","cache"),a=V(process.cwd(),i),n=V(a,`${t}Cache.ts`);await Bun.write(n,r);let d=Bo.replace(/{{NAME}}/g,t),l=V(o,"tests","cache"),p=V(process.cwd(),l),u=V(p,`${t}Cache.spec.ts`);await Bun.write(u,d);let m=new vl;m.success(`${V(i,t)}Cache.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${V(l,t)}Cache.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/cache"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}ke=b([w.command()],ke);import{join as $e}from"path";import{TerminalLogger as Hl}from"@ooneex/logger";var Lo=`---
|
|
1612
1626
|
name: commit
|
|
1613
1627
|
description: Create commit messages grouped by module. Analyzes git changes, groups files under modules/ by module name, and creates separate commits following commitlint conventions. Uses common scope for non-module changes.
|
|
1614
1628
|
---
|
|
@@ -1778,6 +1792,7 @@ Before committing, verify:
|
|
|
1778
1792
|
2. Tests pass for modified modules
|
|
1779
1793
|
3. No debug code or console.logs left in
|
|
1780
1794
|
4. Commit message follows the format exactly
|
|
1795
|
+
5. For Entity class, if property is optional, add \`null\` to its type.
|
|
1781
1796
|
|
|
1782
1797
|
## Handling Special Cases
|
|
1783
1798
|
|
|
@@ -1800,101 +1815,7 @@ Use \`refactor\` for file reorganization:
|
|
|
1800
1815
|
git add modules/product/
|
|
1801
1816
|
git commit -m "refactor(product): Reorganize service file structure"
|
|
1802
1817
|
\`\`\`
|
|
1803
|
-
`;var $o="---\nname: make:ai\ndescription: Generate a new AI class with its test file, then complete the generated code. Use when creating a new AI chat class that uses OpenAI via the @ooneex/ai package.\n---\n\n# Make AI Class\n\nGenerate a new AI class and its test file using the `make:ai` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the AI class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:ai --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/ai/<Name>Ai.ts` - The AI class file (or `modules/<module>/src/ai/<Name>Ai.ts` with `--module`)\n- `tests/ai/<Name>Ai.spec.ts` - The test file (or `modules/<module>/tests/ai/<Name>Ai.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the AI class\n\nEdit `src/ai/<Name>Ai.ts` to complete the implementation:\n\n- Update the prompt in the `run` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Update the prompt in the `runStream` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Add any additional configuration or methods relevant to the AI class purpose\n- Ensure proper typing for the `run<T>()` generic return type\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from \"@ooneex/ai\";\nimport { inject } from \"@ooneex/container\";\n\n@decorator.ai()\nexport class <Name>Ai implements IAiChat<OpenAiConfigType> {\n constructor(@inject(OpenAi) private readonly ai: OpenAi) {}\n\n public async run<T>(prompt?: string, config?: Omit<OpenAiConfigType, \"prompt\">): Promise<T> {\n return this.ai.run<T>(prompt || \"My prompt\", config);\n }\n\n public async *runStream(\n prompt?: string,\n config?: Omit<OpenAiConfigType, \"prompt\" | \"output\">,\n ): AsyncGenerator<string, void, unknown> {\n yield* this.ai.runStream(prompt || \"My prompt\", config);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/ai/<Name>Ai.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, run method, runStream method)\n- Add tests relevant to the specific AI class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Ai } from \"@/ai/<Name>Ai\";\n\ndescribe(\"<Name>Ai\", () => {\n test(\"should have class name ending with 'Ai'\", () => {\n expect(<Name>Ai.name.endsWith(\"Ai\")).toBe(true);\n });\n\n test(\"should have 'run' method\", () => {\n expect(<Name>Ai.prototype.run).toBeDefined();\n expect(typeof <Name>Ai.prototype.run).toBe(\"function\");\n });\n\n test(\"should have 'runStream' method\", () => {\n expect(<Name>Ai.prototype.runStream).toBeDefined();\n expect(typeof <Name>Ai.prototype.runStream).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/ai/<Name>Ai.ts tests/ai/<Name>Ai.spec.ts\n```\n";var Wo="---\nname: make:analytics\ndescription: Generate a new analytics class with its test file, then complete the generated code. Use when creating a new analytics tracking class that uses the @ooneex/analytics package.\n---\n\n# Make Analytics Class\n\nGenerate a new analytics class and its test file using the `make:analytics` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the analytics class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:analytics --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/analytics/<Name>Analytics.ts` - The analytics class file (or `modules/<module>/src/analytics/<Name>Analytics.ts` with `--module`)\n- `tests/analytics/<Name>Analytics.spec.ts` - The test file (or `modules/<module>/tests/analytics/<Name>Analytics.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the analytics class\n\nEdit `src/analytics/<Name>Analytics.ts` to complete the implementation:\n\n- Implement the `capture` method with actual analytics tracking logic\n- Define a proper type for `CaptureOptionsType` instead of `Record<string, unknown>` based on the analytics purpose\n- Add any additional methods or properties relevant to the analytics class purpose\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/analytics\";\nimport type { IAnalytics } from \"@ooneex/analytics\";\n\ntype CaptureOptionsType = Record<string, unknown>;\n\n@decorator.analytics()\nexport class <Name>Analytics<T extends CaptureOptionsType = CaptureOptionsType> implements IAnalytics<T> {\n public capture(options: T): void {\n // console.log(\"Analytics captured:\", options);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/analytics/<Name>Analytics.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, capture method)\n- Add tests relevant to the specific analytics class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Analytics } from \"@/analytics/<Name>Analytics\";\n\ndescribe(\"<Name>Analytics\", () => {\n test(\"should have class name ending with 'Analytics'\", () => {\n expect(<Name>Analytics.name.endsWith(\"Analytics\")).toBe(true);\n });\n\n test(\"should have 'capture' method\", () => {\n expect(<Name>Analytics.prototype.capture).toBeDefined();\n expect(typeof <Name>Analytics.prototype.capture).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/analytics/<Name>Analytics.ts tests/analytics/<Name>Analytics.spec.ts\n```\n";var qo="---\nname: make:cache\ndescription: Generate a new cache adapter class with its test file, then complete the generated code. Use when creating a new cache adapter that implements the ICache interface from @ooneex/cache.\n---\n\n# Make Cache Class\n\nGenerate a new cache class and its test file using the `make:cache` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cache class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cache --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cache/<Name>Cache.ts` - The cache class file (or `modules/<module>/src/cache/<Name>Cache.ts` with `--module`)\n- `tests/cache/<Name>Cache.spec.ts` - The test file (or `modules/<module>/tests/cache/<Name>Cache.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cache class\n\nEdit `src/cache/<Name>Cache.ts` to complete the implementation:\n\n- Implement the `get` method to retrieve cached values by key\n- Implement the `set` method to store values with optional TTL\n- Implement the `delete` method to remove cached entries\n- Implement the `has` method to check key existence\n- Replace the `CacheException` throws with actual cache logic\n- Inject any required dependencies (e.g., Redis client) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { CacheException, decorator } from \"@ooneex/cache\";\nimport type { ICache } from \"@ooneex/cache\";\n\n@decorator.cache()\nexport class <Name>Cache implements ICache {\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n throw new CacheException(`Failed to get key \"${key}\": Not implemented`);\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n throw new CacheException(`Failed to set key \"${key}\": Not implemented`);\n }\n\n public async delete(key: string): Promise<boolean> {\n throw new CacheException(`Failed to delete key \"${key}\": Not implemented`);\n }\n\n public async has(key: string): Promise<boolean> {\n throw new CacheException(`Failed to check if key \"${key}\" exists: Not implemented`);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cache/<Name>Cache.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, get, set, delete, has methods)\n- Add tests relevant to the specific cache class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cache } from \"@/cache/<Name>Cache\";\n\ndescribe(\"<Name>Cache\", () => {\n test(\"should have class name ending with 'Cache'\", () => {\n expect(<Name>Cache.name.endsWith(\"Cache\")).toBe(true);\n });\n\n test(\"should have 'get' method\", () => {\n expect(<Name>Cache.prototype.get).toBeDefined();\n expect(typeof <Name>Cache.prototype.get).toBe(\"function\");\n });\n\n test(\"should have 'set' method\", () => {\n expect(<Name>Cache.prototype.set).toBeDefined();\n expect(typeof <Name>Cache.prototype.set).toBe(\"function\");\n });\n\n test(\"should have 'delete' method\", () => {\n expect(<Name>Cache.prototype.delete).toBeDefined();\n expect(typeof <Name>Cache.prototype.delete).toBe(\"function\");\n });\n\n test(\"should have 'has' method\", () => {\n expect(<Name>Cache.prototype.has).toBeDefined();\n expect(typeof <Name>Cache.prototype.has).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cache/<Name>Cache.ts tests/cache/<Name>Cache.spec.ts\n```\n";var Ko="---\nname: make:controller\ndescription: Generate a new controller class with route type and test file, then complete the generated code. Use when creating a new HTTP or WebSocket controller with routing, validation, and role-based access.\n---\n\n# Make Controller Class\n\nGenerate a new controller class, its route type, and test file using the `make:controller` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the controller class and related files:\n\n```bash\nbunx @ooneex/cli@latest make:controller --name <name> --module <module> --is-socket <true|false> --route.name <route.name> --route.path <route.path> --route.method <route.method>\n```\n\nWhere:\n- `<name>` is the controller name provided by the user\n- `--module` is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root\n- `--is-socket` determines HTTP vs WebSocket controller (defaults to `false`)\n- `--route.name` is the route name using dot notation: `<resource>.<action>` (e.g., `user.create`, `book.list`, `flashcard.delete`)\n- `--route.path` is the route path (e.g., `/api/users`)\n- `--route.method` is the HTTP method (e.g., `get`, `post`, `put`, `patch`, `delete`) \u2014 only for HTTP controllers\n\nThe command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/controllers/<Name>Controller.ts` - The controller class file\n- `src/types/routes/<route.name>.ts` - The route type file\n- `tests/controllers/<Name>Controller.spec.ts` - The test file\n\n### 2. Read the generated files\n\nRead all three generated files to understand the scaffolded code.\n\n### 3. Complete the route type\n\nEdit `src/types/routes/<route.name>.ts` to define the route's type contract.\n\n**Add or remove `params`, `payload`, and `queries` based on context:**\n\n- **`params`** \u2014 Include only when the route path contains dynamic segments (e.g., `/api/users/:id`). Remove entirely for routes with no URL parameters (e.g., `/api/users`).\n- **`payload`** \u2014 Include only for methods that accept a request body (`post`, `put`, `patch`). Remove entirely for `get` and `delete` routes.\n- **`queries`** \u2014 Include only when the route supports query string filtering, pagination, or sorting (e.g., list/search endpoints). Remove entirely when not needed.\n- **`response`** \u2014 Always include.\n\nThe generated route type structure follows this pattern (remove unused sections):\n\n```typescript\n// Example: GET /api/users (list) \u2014 no params, no payload, has queries\nexport type <TypeName>RouteType = {\n queries: {\n\n },\n response: {\n\n },\n};\n\n// Example: POST /api/users (create) \u2014 no params, has payload, no queries\nexport type <TypeName>RouteType = {\n payload: {\n\n },\n response: {\n\n },\n};\n\n// Example: GET /api/users/:id (detail) \u2014 has params, no payload, no queries\nexport type <TypeName>RouteType = {\n params: {\n\n },\n response: {\n\n },\n};\n\n// Example: PUT /api/users/:id (update) \u2014 has params, has payload, no queries\nexport type <TypeName>RouteType = {\n params: {\n\n },\n payload: {\n\n },\n response: {\n\n },\n};\n```\n\n### 4. Complete the controller class\n\nEdit `src/controllers/<Name>Controller.ts` to complete the implementation:\n\n- Set appropriate `roles` for access control\n- Add a meaningful `description` for the route that explains what the endpoint does (e.g., `\"Create a new user account\"`, `\"List all books with pagination\"`)\n- Implement the `index` method with actual controller logic\n- Inject any required dependencies (repositories, services) via the constructor\n\n**Add or remove `params`, `payload`, and `queries` in the `@Route` decorator to match the route type (step 3):**\n\n- **`params`** \u2014 Include with `Assert()` validators only when the route has URL parameters. Remove the `params` key entirely otherwise.\n- **`payload`** \u2014 Include with `Assert({...})` only for `post`, `put`, `patch` methods. Remove the `payload` key entirely for `get` and `delete`.\n- **`queries`** \u2014 Include with `Assert({...})` only when query parameters are expected. Remove the `queries` key entirely otherwise.\n- **`response`** \u2014 Always include with `Assert({...})`.\n\n**HTTP controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\nimport type { <TypeName>RouteType } from \"../types/routes/<route.name>\";\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n params: {\n // id: Assert(\"string\"),\n },\n payload: Assert({\n\n }),\n queries: Assert({\n\n }),\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n // const { id } = context.params;\n\n return context.response.json({\n\n });\n }\n}\n```\n\n**Socket controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\nimport type { <TypeName>RouteType } from \"../types/routes/<route.name>\";\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n params: {\n // id: Assert(\"string\"),\n },\n payload: Assert({\n\n }),\n queries: Assert({\n\n }),\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n // const { id } = context.params;\n\n return context.response.json({\n\n });\n }\n}\n```\n\n### 5. Complete the test file\n\nEdit `tests/controllers/<Name>Controller.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, index method)\n- Add tests relevant to the specific controller behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Controller } from \"@/controllers/<Name>Controller\";\n\ndescribe(\"<Name>Controller\", () => {\n test(\"should have class name ending with 'Controller'\", () => {\n expect(<Name>Controller.name.endsWith(\"Controller\")).toBe(true);\n });\n\n test(\"should have 'index' method\", () => {\n expect(<Name>Controller.prototype.index).toBeDefined();\n expect(typeof <Name>Controller.prototype.index).toBe(\"function\");\n });\n});\n```\n\n### 6. Register the controller in the module\n\nAdd the new controller to the module's `controllers` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Controller } from \"./controllers/<Name>Controller\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [<Name>Controller],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other controllers registered, append the new controller to the existing `controllers` array and add the import alongside existing imports.\n\n### 7. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/controllers/<Name>Controller.ts src/types/routes/<route.name>.ts tests/controllers/<Name>Controller.spec.ts\n```\n\n### 8. Create the service\n\nAfter the controller is created, generate a service class for the controller's business logic using the `make:service` skill:\n\n```\n/make:service --name <Name>\n```\n\nWhere `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the service is `CreateUserService`).\n\n### 9. Create the pubsub event\n\nAfter the service is created, generate a pubsub event class for the controller's domain events using the `make:pubsub` skill:\n\n```\n/make:pubsub --name <Name> --channel <resource>.<action>\n```\n\nWhere:\n- `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the event is `CreateUserEvent`)\n- `<resource>.<action>` follows the same dot notation as the route name (e.g., `user.create`, `book.delete`)\n\nOnce the event is created:\n- Inject the **service** into the **event** via the constructor, and call the service's `execute` method from the event's `handler` method.\n- Inject the **event** into the **controller** via the constructor, and publish the event from the controller's `index` method.\n";var Ho="---\nname: make:cron\ndescription: Generate a new cron job class with its test file, then complete the generated code. Use when creating a new scheduled task that extends the Cron base class from @ooneex/cron.\n---\n\n# Make Cron Class\n\nGenerate a new cron class and its test file using the `make:cron` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cron class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cron --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cron/<Name>Cron.ts` - The cron class file (or `modules/<module>/src/cron/<Name>Cron.ts` with `--module`)\n- `tests/cron/<Name>Cron.spec.ts` - The test file (or `modules/<module>/tests/cron/<Name>Cron.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cron class\n\nEdit `src/cron/<Name>Cron.ts` to complete the implementation:\n\n- Set the appropriate cron schedule in `getTime()` (e.g., `\"every 5 minutes\"`, `\"every 1 hours\"`, `\"every 30 seconds\"`)\n- Set the timezone in `getTimeZone()` if needed, or keep `null` for server timezone\n- Implement the `handler()` method with the actual cron job logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { TimeZoneType } from \"@ooneex/country\";\nimport type { CronTimeType } from \"@ooneex/cron\";\nimport { Cron, decorator } from \"@ooneex/cron\";\n\n@decorator.cron()\nexport class <Name>Cron extends Cron {\n public getTime(): CronTimeType {\n // Examples: \"every 5 minutes\", \"every 1 hours\", \"every 30 seconds\"\n return \"every 1 hours\";\n }\n\n public getTimeZone(): TimeZoneType | null {\n // Return null to use server timezone, or specify a timezone like \"Europe/Paris\"\n return null;\n }\n\n public async handler(): Promise<void> {\n // Implement your cron handler logic here\n // console.log(\"<Name>Cron handler executed\");\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cron/<Name>Cron.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getTime, getTimeZone, handler methods)\n- Add tests relevant to the specific cron class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cron } from \"@/cron/<Name>Cron\";\n\ndescribe(\"<Name>Cron\", () => {\n test(\"should have class name ending with 'Cron'\", () => {\n expect(<Name>Cron.name.endsWith(\"Cron\")).toBe(true);\n });\n\n test(\"should have 'getTime' method\", () => {\n expect(<Name>Cron.prototype.getTime).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTime).toBe(\"function\");\n });\n\n test(\"should have 'getTimeZone' method\", () => {\n expect(<Name>Cron.prototype.getTimeZone).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTimeZone).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Cron.prototype.handler).toBeDefined();\n expect(typeof <Name>Cron.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the cron job in the module\n\nAdd the new cron job to the module's `cronJobs` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Cron } from \"./cron/<Name>Cron\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [<Name>Cron],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other cron jobs registered, append the new cron job to the existing `cronJobs` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cron/<Name>Cron.ts tests/cron/<Name>Cron.spec.ts\n```\n";var Fo="---\nname: make:database\ndescription: Generate a new database class with its test file, then complete the generated code. Use when creating a new database adapter that extends TypeormDatabase from @ooneex/database.\n---\n\n# Make Database Class\n\nGenerate a new database class and its test file using the `make:database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>Database.ts` - The database class file (or `modules/<module>/src/databases/<Name>Database.ts` with `--module`)\n- `tests/databases/<Name>Database.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>Database.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the database class\n\nEdit `src/databases/<Name>Database.ts` to complete the implementation:\n\n- Add entity imports and register them in the `entities` array\n- Adjust the database path if needed (default is `\"var/db\"`)\n- Configure DataSource options as appropriate (type, synchronize, etc.)\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { DataSource } from \"typeorm\";\nimport { TypeormDatabase, DatabaseException, decorator } from \"@ooneex/database\";\n\n@decorator.database()\nexport class <Name>Database extends TypeormDatabase {\n public getSource(database?: string): DataSource {\n database = database || \"var/db\";\n\n this.source = new DataSource({\n synchronize: false,\n entities: [\n // TODO: Load your entities here\n ],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n database,\n type: \"sqlite\",\n });\n\n return this.source;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>Database.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getSource method)\n- Add tests relevant to the specific database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Database } from \"@/databases/<Name>Database\";\n\ndescribe(\"<Name>Database\", () => {\n test(\"should have class name ending with 'Database'\", () => {\n expect(<Name>Database.name.endsWith(\"Database\")).toBe(true);\n });\n\n test(\"should have 'getSource' method\", () => {\n expect(<Name>Database.prototype.getSource).toBeDefined();\n expect(typeof <Name>Database.prototype.getSource).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>Database.ts tests/databases/<Name>Database.spec.ts\n```\n";var Vo="---\nname: make:entity\ndescription: Generate a new TypeORM entity class with its test file, then complete the generated code. Use when creating a new database entity with columns, relations, and table mapping.\n---\n\n# Make Entity Class\n\nGenerate a new entity class and its test file using the `make:entity` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the entity class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:entity --name <name> --module <module> --table-name <table_name>\n```\n\nWhere `<name>` is the name provided by the user. The `--table-name` option is optional \u2014 if omitted, it defaults to the snake_case pluralized form of the name (e.g., `UserProfile` becomes `user_profiles`). The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/entities/<Name>Entity.ts` - The entity class file (or `modules/<module>/src/entities/<Name>Entity.ts` with `--module`)\n- `tests/entities/<Name>Entity.spec.ts` - The test file (or `modules/<module>/tests/entities/<Name>Entity.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the entity class\n\nEdit `src/entities/<Name>Entity.ts` to complete the implementation:\n\n- Add entity-specific columns with appropriate TypeORM decorators (`@Column`)\n- Add relations if needed (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, etc.)\n- Remove any scaffolded columns that are not relevant to the entity\n- Adjust column types, lengths, and constraints as needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { LocaleType } from \"@ooneex/translation\";\nimport { random } from \"@ooneex/utils\";\nimport { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n@Entity({\n name: \"<table_name>\",\n})\nexport class <Name>Entity extends BaseEntity {\n @PrimaryColumn({ name: \"id\", type: \"varchar\", length: 25 })\n id: string = random.nanoid(25);\n\n @Column({\n name: \"is_locked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isLocked?: boolean;\n\n @Column({ name: \"locked_at\", type: \"timestamptz\", nullable: true })\n lockedAt?: Date;\n\n @Column({\n name: \"is_blocked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isBlocked?: boolean;\n\n @Column({ name: \"blocked_at\", type: \"timestamptz\", nullable: true })\n blockedAt?: Date;\n\n @Column({ name: \"block_reason\", type: \"text\", nullable: true })\n blockReason?: string;\n\n @Column({ name: \"is_public\", type: \"boolean\", default: true, nullable: true })\n isPublic?: boolean;\n\n @Column({ name: \"lang\", type: \"varchar\", length: 10, nullable: true })\n lang?: LocaleType;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt?: Date;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt?: Date;\n\n @DeleteDateColumn({ name: \"deleted_at\" })\n deletedAt?: Date;\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/entities/<Name>Entity.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, id, default columns)\n- Add tests for any new entity-specific columns and relations\n- Update tests if scaffolded columns were removed\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Entity } from \"@/entities/<Name>Entity\";\n\ndescribe(\"<Name>Entity\", () => {\n test(\"should have class name ending with 'Entity'\", () => {\n expect(<Name>Entity.name.endsWith(\"Entity\")).toBe(true);\n });\n\n test(\"should have 'id' property with default nanoid\", () => {\n const entity = new <Name>Entity();\n expect(entity.id).toBeDefined();\n expect(typeof entity.id).toBe(\"string\");\n expect(entity.id.length).toBe(25);\n });\n\n test(\"should have 'isLocked' property\", () => {\n const entity = new <Name>Entity();\n expect(\"isLocked\" in entity).toBe(true);\n });\n\n // ... additional property tests\n});\n```\n\n### 5. Register the entity in the module\n\nAdd the new entity to the module's `entities` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Entity } from \"./entities/<Name>Entity\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [<Name>Entity],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other entities registered, append the new entity to the existing `entities` array and add the import alongside existing imports.\n\n### 6. Create a migration for the entity\n\nAfter creating or updating an entity, generate a migration to apply the corresponding schema changes to the database.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:migration\n```\n\nThen read the generated migration file in `src/migrations/` and complete it:\n\n- In the `up` method, write the SQL to create the table (or alter it if updating an existing entity). Include all columns, types, constraints, defaults, and indexes matching the entity definition.\n- In the `down` method, write the reverse SQL to undo the changes (e.g., `DROP TABLE` or `ALTER TABLE DROP COLUMN`).\n- If the migration depends on another migration (e.g., a foreign key referencing another table), add that migration class to the `getDependencies()` return array.\n\nExample `up` method for a new entity:\n\n```typescript\npublic async up(tx: TransactionSQL): Promise<void> {\n await tx`\n CREATE TABLE IF NOT EXISTS <table_name> (\n id VARCHAR(25) PRIMARY KEY,\n is_locked BOOLEAN DEFAULT false,\n locked_at TIMESTAMPTZ,\n is_blocked BOOLEAN DEFAULT false,\n blocked_at TIMESTAMPTZ,\n block_reason TEXT,\n is_public BOOLEAN DEFAULT true,\n lang VARCHAR(10),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n deleted_at TIMESTAMPTZ\n )\n `;\n}\n```\n\n### 7. Create a repository for the entity\n\nAfter creating the entity, generate a repository to handle database operations for it.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name>\n```\n\nWhere `<name>` is the same name used for the entity. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class\n- `tests/repositories/<Name>Repository.spec.ts` - The test file\n\nThen read the generated files and complete the repository implementation:\n\n- Adjust search fields in the `find()` method to match the entity's searchable columns\n- Customize relations loading in `findOne`/`findOneBy` if the entity has relations\n- Add any domain-specific methods relevant to the entity\n- Remove methods that don't apply to the entity\n- Update tests to match the final repository methods\n\n### 8. Lint and format\n\nRun linting and formatting on all generated files:\n\n```bash\nbunx biome check --fix src/entities/<Name>Entity.ts tests/entities/<Name>Entity.spec.ts src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts src/migrations/\n```\n";var Yo="---\nname: make:logger\ndescription: Generate a new logger class with its test file, then complete the generated code. Use when creating a new logger that implements the ILogger interface from @ooneex/logger.\n---\n\n# Make Logger Class\n\nGenerate a new logger class and its test file using the `make:logger` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the logger class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:logger --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/loggers/<Name>Logger.ts` - The logger class file (or `modules/<module>/src/loggers/<Name>Logger.ts` with `--module`)\n- `tests/loggers/<Name>Logger.spec.ts` - The test file (or `modules/<module>/tests/loggers/<Name>Logger.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the logger class\n\nEdit `src/loggers/<Name>Logger.ts` to complete the implementation:\n\n- Implement the `init()` method to set up the logger (e.g., open file handles, configure transports)\n- Implement `log`, `debug`, `info`, `success`, `warn`, and `error` methods with actual logging logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { IException } from \"@ooneex/exception\";\nimport type { ILogger } from \"@ooneex/logger\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator } from \"@ooneex/logger\";\n\n@decorator.logger()\nexport class <Name>Logger implements ILogger {\n public async init(): Promise<void> {\n // Initialize your logger here\n }\n\n public log(message: string, data?: Record<string, ScalarType>): void {\n // Handle general logging\n }\n\n public debug(message: string, data?: Record<string, ScalarType>): void {\n // Handle debug logging\n }\n\n public info(message: string, data?: Record<string, ScalarType>): void {\n // Handle info logging\n }\n\n public success(message: string, data?: Record<string, ScalarType>): void {\n // Handle success logging\n }\n\n public warn(message: string, data?: Record<string, ScalarType>): void {\n // Handle warning logging\n }\n\n public error(message: string | IException, data?: Record<string, ScalarType>): void {\n // Handle error logging\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/loggers/<Name>Logger.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, init, log, debug, info, success, warn, error methods)\n- Add tests relevant to the specific logger class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Logger } from \"@/loggers/<Name>Logger\";\n\ndescribe(\"<Name>Logger\", () => {\n test(\"should have class name ending with 'Logger'\", () => {\n expect(<Name>Logger.name.endsWith(\"Logger\")).toBe(true);\n });\n\n test(\"should have 'init' method\", () => {\n expect(<Name>Logger.prototype.init).toBeDefined();\n expect(typeof <Name>Logger.prototype.init).toBe(\"function\");\n });\n\n test(\"should have 'log' method\", () => {\n expect(<Name>Logger.prototype.log).toBeDefined();\n expect(typeof <Name>Logger.prototype.log).toBe(\"function\");\n });\n\n test(\"should have 'debug' method\", () => {\n expect(<Name>Logger.prototype.debug).toBeDefined();\n expect(typeof <Name>Logger.prototype.debug).toBe(\"function\");\n });\n\n test(\"should have 'info' method\", () => {\n expect(<Name>Logger.prototype.info).toBeDefined();\n expect(typeof <Name>Logger.prototype.info).toBe(\"function\");\n });\n\n test(\"should have 'success' method\", () => {\n expect(<Name>Logger.prototype.success).toBeDefined();\n expect(typeof <Name>Logger.prototype.success).toBe(\"function\");\n });\n\n test(\"should have 'warn' method\", () => {\n expect(<Name>Logger.prototype.warn).toBeDefined();\n expect(typeof <Name>Logger.prototype.warn).toBe(\"function\");\n });\n\n test(\"should have 'error' method\", () => {\n expect(<Name>Logger.prototype.error).toBeDefined();\n expect(typeof <Name>Logger.prototype.error).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/loggers/<Name>Logger.ts tests/loggers/<Name>Logger.spec.ts\n```\n";var zo="---\nname: make:mailer\ndescription: Generate a new mailer class with its template and test files, then complete the generated code. Use when creating a new email sender with JSX template using @ooneex/mailer.\n---\n\n# Make Mailer Class\n\nGenerate a new mailer class, its JSX template, and test files using the `make:mailer` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the mailer class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:mailer --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/mailers/<Name>Mailer.ts` - The mailer class file\n- `src/mailers/<Name>MailerTemplate.tsx` - The JSX email template\n- `tests/mailers/<Name>Mailer.spec.ts` - The mailer test file\n- `tests/mailers/<Name>MailerTemplate.spec.ts` - The template test file\n\n### 2. Read the generated files\n\nRead all four generated files to understand the scaffolded code.\n\n### 3. Complete the mailer class\n\nEdit `src/mailers/<Name>Mailer.ts` to complete the implementation:\n\n- Adjust the `send` method config type if additional parameters are needed\n- Add any pre-send logic (validation, data transformation, etc.)\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { IMailer } from \"@ooneex/mailer\";\nimport { type <Name>MailerPropsType, <Name>MailerTemplate } from \"./<Name>MailerTemplate\";\n\nexport class <Name>Mailer implements IMailer {\n constructor(\n @inject(\"mailer\")\n private readonly mailer: IMailer,\n ) {}\n\n public send = async (config: {\n to: string[];\n subject: string;\n from?: { name: string; address: string };\n data?: <Name>MailerPropsType;\n }): Promise<void> => {\n const { data, ...rest } = config;\n\n await this.mailer.send({\n ...rest,\n content: <Name>MailerTemplate(data),\n });\n };\n}\n```\n\n### 4. Complete the mailer template\n\nEdit `src/mailers/<Name>MailerTemplate.tsx` to complete the implementation:\n\n- Update `<Name>MailerPropsType` with the actual props needed for the email\n- Build the email body using `MailerLayout` components (Header, Body, Footer)\n- Add email content, styling, and dynamic data rendering\n\nThe generated template structure follows this pattern:\n\n```tsx\nimport { MailerLayout } from \"@ooneex/mailer\";\n\nexport type <Name>MailerPropsType = {\n link: string;\n};\n\nexport const <Name>MailerTemplate = (props?: <Name>MailerPropsType) => (\n <MailerLayout>\n <MailerLayout.Header />\n <MailerLayout.Body>\n <a href={props?.link}>Login</a>\n </MailerLayout.Body>\n <MailerLayout.Footer />\n </MailerLayout>\n);\n```\n\n### 5. Complete the test files\n\nEdit `tests/mailers/<Name>Mailer.spec.ts` and `tests/mailers/<Name>MailerTemplate.spec.ts` to add meaningful tests beyond the scaffolded ones.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/mailers/<Name>Mailer.ts src/mailers/<Name>MailerTemplate.tsx tests/mailers/<Name>Mailer.spec.ts tests/mailers/<Name>MailerTemplate.spec.ts\n```\n";var Zo="---\nname: make:middleware\ndescription: Generate a new middleware class with its test file, then complete the generated code. Use when creating a new HTTP or WebSocket middleware that implements IMiddleware from @ooneex/middleware.\n---\n\n# Make Middleware Class\n\nGenerate a new middleware class and its test file using the `make:middleware` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the middleware class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:middleware --name <name> --module <module> --is-socket <true|false>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--is-socket` option determines whether to generate an HTTP middleware or a WebSocket middleware (defaults to `false` if omitted). The command will generate:\n- `src/middlewares/<Name>Middleware.ts` - The middleware class file (or `modules/<module>/src/middlewares/<Name>Middleware.ts` with `--module`)\n- `tests/middlewares/<Name>Middleware.spec.ts` - The test file (or `modules/<module>/tests/middlewares/<Name>Middleware.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the middleware class\n\nEdit `src/middlewares/<Name>Middleware.ts` to complete the implementation:\n\n- Implement the `handler` method with actual middleware logic\n- Add request/response transformations, authentication checks, logging, etc.\n- Inject any required dependencies via the constructor\n\n**HTTP middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n**Socket middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/middlewares/<Name>Middleware.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, handler method)\n- Add tests relevant to the specific middleware behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Middleware } from \"@/middlewares/<Name>Middleware\";\n\ndescribe(\"<Name>Middleware\", () => {\n test(\"should have class name ending with 'Middleware'\", () => {\n expect(<Name>Middleware.name.endsWith(\"Middleware\")).toBe(true);\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Middleware.prototype.handler).toBeDefined();\n expect(typeof <Name>Middleware.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the middleware in the module\n\nAdd the new middleware to the module's `middlewares` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Middleware } from \"./middlewares/<Name>Middleware\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [<Name>Middleware],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other middlewares registered, append the new middleware to the existing `middlewares` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/middlewares/<Name>Middleware.ts tests/middlewares/<Name>Middleware.spec.ts\n```\n";var Qo="---\nname: make:migration\ndescription: Generate a new database migration file, then complete the generated code. Use when creating a new database migration for schema changes using @ooneex/migrations.\n---\n\n# Make Migration\n\nGenerate a new migration file using the `make:migration` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the migration file:\n\n```bash\nbunx @ooneex/cli@latest make:migration --module <module>\n```\n\nThe `--module` option is optional \u2014 if provided, the migration file is generated under `modules/<module>/src/migrations/` instead of `src/migrations/`. The command will:\n- Generate a timestamped migration file in `src/migrations/` (or `modules/<module>/src/migrations/` with `--module`)\n- Add a `migration:up` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated migration file in `src/migrations/` to understand the scaffolded code.\n\n### 3. Complete the migration\n\nEdit the generated migration file to implement:\n\n- The `up` method with the schema changes (create tables, add columns, create indexes, etc.)\n- The `down` method with the reverse operations to undo the migration\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/migrations/\n```\n";var Xo="---\nname: make:permission\ndescription: Generate a new permission class with its test file, then complete the generated code. Use when creating a new permission that extends Permission from @ooneex/permission.\n---\n\n# Make Permission Class\n\nGenerate a new permission class and its test file using the `make:permission` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the permission class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:permission --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/permissions/<Name>Permission.ts` - The permission class file (or `modules/<module>/src/permissions/<Name>Permission.ts` with `--module`)\n- `tests/permissions/<Name>Permission.spec.ts` - The test file (or `modules/<module>/tests/permissions/<Name>Permission.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the permission class\n\nEdit `src/permissions/<Name>Permission.ts` to complete the implementation:\n\n- Implement the `allow()` method with permission rules using `this.ability.can()`\n- Implement the `setUserPermissions()` method with role-based permission logic\n- Define which actions (read, create, update, delete, manage) are allowed on which entities\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, Permission } from \"@ooneex/permission\";\nimport type { IUser } from \"@ooneex/user\";\n\n@decorator.permission()\nexport class <Name>Permission extends Permission {\n public allow(): this {\n // Example: Add permissions using this.ability.can()\n // this.ability.can(\"read\", \"YourEntity\");\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n\n return this;\n }\n\n public setUserPermissions(user: IUser | null): this {\n if (!user) {\n return this;\n }\n\n // Example: Grant full access to admins\n // const { roles } = user;\n // if (roles.includes(ERole.ADMIN)) {\n // this.ability.can(\"manage\", \"all\");\n // return this;\n // }\n\n // Example: Grant specific permissions based on roles\n // for (const role of roles) {\n // if (role === ERole.USER) {\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n // }\n //\n // if (role === ERole.GUEST) {\n // this.ability.can(\"read\", \"YourEntity\", { public: true });\n // }\n // }\n\n return this;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/permissions/<Name>Permission.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, extends Permission, allow, setUserPermissions methods)\n- Add tests relevant to the specific permission rules\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { Permission } from \"@ooneex/permission\";\nimport { <Name>Permission } from \"@/permissions/<Name>Permission\";\n\ndescribe(\"<Name>Permission\", () => {\n test(\"should have class name ending with 'Permission'\", () => {\n expect(<Name>Permission.name.endsWith(\"Permission\")).toBe(true);\n });\n\n test(\"should extend Permission\", () => {\n const permission = new <Name>Permission();\n expect(permission).toBeInstanceOf(Permission);\n });\n\n test(\"should have 'allow' method\", () => {\n expect(<Name>Permission.prototype.allow).toBeDefined();\n expect(typeof <Name>Permission.prototype.allow).toBe(\"function\");\n });\n\n test(\"should have 'setUserPermissions' method\", () => {\n expect(<Name>Permission.prototype.setUserPermissions).toBeDefined();\n expect(typeof <Name>Permission.prototype.setUserPermissions).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the permission in the module\n\nAdd the new permission to the module's `permissions` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Permission } from \"./permissions/<Name>Permission\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [<Name>Permission],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other permissions registered, append the new permission to the existing `permissions` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/permissions/<Name>Permission.ts tests/permissions/<Name>Permission.spec.ts\n```\n";var Jo="---\nname: make:pubsub\ndescription: Generate a new PubSub event class with its test file, then complete the generated code. Use when creating a new publish/subscribe event that extends PubSub from @ooneex/pub-sub.\n---\n\n# Make PubSub Event Class\n\nGenerate a new PubSub event class and its test file using the `make:pubsub` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the PubSub event class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:pubsub --name <name> --module <module> --channel <channel>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--channel` option is optional \u2014 if omitted, it defaults to the kebab-case form of the name (e.g., `UserCreated` becomes `user-created`). The command will generate:\n- `src/events/<Name>Event.ts` - The event class file (or `modules/<module>/src/events/<Name>Event.ts` with `--module`)\n- `tests/events/<Name>Event.spec.ts` - The test file (or `modules/<module>/tests/events/<Name>Event.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the PubSub event class\n\nEdit `src/events/<Name>Event.ts` to complete the implementation:\n\n- Define a proper data type instead of `Record<string, ScalarType>` for the event payload\n- Implement the `handler()` method with actual event handling logic\n- Set the appropriate channel name in `getChannel()`\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator, PubSub, RedisPubSub } from \"@ooneex/pub-sub\";\n\n@decorator.pubSub()\nexport class <Name>Event<Data extends Record<string, ScalarType> = Record<string, ScalarType>> extends PubSub<Data> {\n constructor(\n @inject(RedisPubSub)\n client: RedisPubSub<Data>,\n ) {\n super(client);\n }\n\n public getChannel(): string {\n return \"<channel>\";\n }\n\n public async handler(context: { data: Data; channel: string }): Promise<void> {\n console.log(context);\n // TODO: Implement handler logic here\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/events/<Name>Event.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getChannel, handler, publish, subscribe, unsubscribe, unsubscribeAll methods)\n- Add tests relevant to the specific event behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>PubSub } from \"@/pubsub/<Name>PubSub\";\n\ndescribe(\"<Name>PubSub\", () => {\n test(\"should have class name ending with 'PubSub'\", () => {\n expect(<Name>PubSub.name.endsWith(\"PubSub\")).toBe(true);\n });\n\n test(\"should have 'getChannel' method\", () => {\n expect(<Name>PubSub.prototype.getChannel).toBeDefined();\n expect(typeof <Name>PubSub.prototype.getChannel).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>PubSub.prototype.handler).toBeDefined();\n expect(typeof <Name>PubSub.prototype.handler).toBe(\"function\");\n });\n\n test(\"should have 'publish' method\", () => {\n expect(<Name>PubSub.prototype.publish).toBeDefined();\n expect(typeof <Name>PubSub.prototype.publish).toBe(\"function\");\n });\n\n test(\"should have 'subscribe' method\", () => {\n expect(<Name>PubSub.prototype.subscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.subscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribe' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribeAll' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribeAll).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribeAll).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the event in the module\n\nAdd the new event to the module's `events` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Event } from \"./events/<Name>Event\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [<Name>Event],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other events registered, append the new event to the existing `events` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/events/<Name>Event.ts tests/events/<Name>Event.spec.ts\n```\n";var jo="---\nname: make:repository\ndescription: Generate a new repository class with its test file, then complete the generated code. Use when creating a new TypeORM repository for database operations on an entity.\n---\n\n# Make Repository Class\n\nGenerate a new repository class and its test file using the `make:repository` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the repository class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class file (or `modules/<module>/src/repositories/<Name>Repository.ts` with `--module`)\n- `tests/repositories/<Name>Repository.spec.ts` - The test file (or `modules/<module>/tests/repositories/<Name>Repository.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the repository class\n\nEdit `src/repositories/<Name>Repository.ts` to complete the implementation:\n\n- Verify the entity import path matches the actual entity location\n- Adjust the `find` method's search fields (default searches `name` with `ILike`)\n- Customize relations loading in `findOne`/`findOneBy` if needed\n\n#### Adding methods\n\nLook at the entity's fields, relations, and business context to determine if custom domain-specific methods are needed. For example:\n- A `SessionRepository` might need `revokeSession(sessionId: string)` and `revokeAllUserSessions(userId: string)`\n- A `NotificationRepository` might need `markAsRead(id: string)` and `markAllAsRead(userId: string)`\n- Entities with status fields may need methods like `archive(id: string)` or `activate(id: string)`\n\nRead related entities, services, or actions in the module to understand what operations the repository should support, then add the appropriate methods.\n\n#### Removing methods\n\nRemove scaffolded methods that don't make sense for the entity's context:\n- Remove `createMany`/`updateMany` if the entity is always managed individually (e.g., user profiles, settings)\n- Remove `delete` if the entity uses soft deletes only (use a custom `softDelete` or `archive` method instead)\n- Remove `find` if the entity is only ever accessed by ID or specific criteria (e.g., singleton config entities)\n- Remove `count` if there's no use case for counting records of this entity\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ITypeormDatabase } from \"@ooneex/database\";\nimport { decorator } from \"@ooneex/repository\";\nimport type { FilterResultType } from \"@ooneex/types\";\nimport type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from \"typeorm\";\nimport { ILike } from \"typeorm\";\nimport { <Name>Entity } from \"../entities/<Name>Entity\";\n\n@decorator.repository()\nexport class <Name>Repository {\n constructor(\n @inject(\"database\")\n private readonly database: ITypeormDatabase,\n ) {}\n\n public async open(): Promise<Repository<<Name>Entity>> {\n return await this.database.open(<Name>Entity);\n }\n\n public async close(): Promise<void> {\n await this.database.close();\n }\n\n public async find(\n criteria: FindManyOptions<<Name>Entity> & { page?: number; limit?: number; q?: string },\n ): Promise<FilterResultType<<Name>Entity>> {\n // ... pagination and search logic\n }\n\n public async findOne(id: string): Promise<<Name>Entity | null> { ... }\n public async findOneBy(criteria: FindOptionsWhere<<Name>Entity>): Promise<<Name>Entity | null> { ... }\n public async create(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async createMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async update(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async updateMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async delete(criteria: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<UpdateResult> { ... }\n public async count(criteria?: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<number> { ... }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/repositories/<Name>Repository.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep scaffolded tests for methods that remain in the repository (remove tests for methods that were removed)\n- Add tests for any custom domain-specific methods added to the repository\n- Add tests relevant to the specific repository behavior\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts\n```\n";var ei="---\nname: make:seed\ndescription: Generate a new database seed file, then complete the generated code. Use when creating seed data for populating the database using @ooneex/seeds.\n---\n\n# Make Seed\n\nGenerate a new seed file using the `make:seed` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the seed file:\n\n```bash\nbunx @ooneex/cli@latest make:seed --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, the seed file is generated under `modules/<module>/src/seeds/` instead of `src/seeds/`. The command will:\n- Generate a seed file in `src/seeds/` (or `modules/<module>/src/seeds/` with `--module`)\n- Add a `seed:run` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated seed file in `src/seeds/` to understand the scaffolded code.\n\n### 3. Complete the seed\n\nEdit the generated seed file to implement:\n\n- Import the relevant entity classes\n- Create seed data with hardcoded nanoid values for `id` fields (generate via `bun -e \"import { random } from '@ooneex/utils'; console.log(random.nanoid())\"`)\n- Do NOT use sequential IDs like `\"item-1\"`, `\"item-2\"`\n- Ensure the same entity uses the same ID everywhere it appears\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/seeds/\n```\n";var ti="---\nname: make:service\ndescription: Generate a new service class with its test file, then complete the generated code. Use when creating a new business logic service that implements IService from @ooneex/service.\n---\n\n# Make Service Class\n\nGenerate a new service class and its test file using the `make:service` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the service class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:service --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/services/<Name>Service.ts` - The service class file (or `modules/<module>/src/services/<Name>Service.ts` with `--module`)\n- `tests/services/<Name>Service.spec.ts` - The test file (or `modules/<module>/tests/services/<Name>Service.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the service class\n\nEdit `src/services/<Name>Service.ts` to complete the implementation:\n\n- Define a proper type for `ServiceDataType` instead of `Record<string, unknown>`\n- Implement the `execute()` method with actual business logic\n- Inject any required dependencies (repositories, other services, etc.) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/service\";\nimport type { IService } from \"@ooneex/service\";\n\ntype ServiceDataType = Record<string, unknown>;\n\n@decorator.service()\nexport class <Name>Service<T extends ServiceDataType = ServiceDataType> implements IService<T> {\n public async execute(data?: T): Promise<void> {\n // TODO: Implement service logic\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/services/<Name>Service.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, execute method)\n- Add tests relevant to the specific service behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Service } from \"@/services/<Name>Service\";\n\ndescribe(\"<Name>Service\", () => {\n test(\"should have class name ending with 'Service'\", () => {\n expect(<Name>Service.name.endsWith(\"Service\")).toBe(true);\n });\n\n test(\"should have 'execute' method\", () => {\n expect(<Name>Service.prototype.execute).toBeDefined();\n expect(typeof <Name>Service.prototype.execute).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/services/<Name>Service.ts tests/services/<Name>Service.spec.ts\n```\n";var si="---\nname: make:storage\ndescription: Generate a new storage class with its test file, then complete the generated code. Use when creating a new S3-compatible storage adapter that extends Storage from @ooneex/storage.\n---\n\n# Make Storage Class\n\nGenerate a new storage class and its test file using the `make:storage` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the storage class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:storage --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/storage/<Name>Storage.ts` - The storage class file (or `modules/<module>/src/storage/<Name>Storage.ts` with `--module`)\n- `tests/storage/<Name>Storage.spec.ts` - The test file (or `modules/<module>/tests/storage/<Name>Storage.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the storage class\n\nEdit `src/storage/<Name>Storage.ts` to complete the implementation:\n\n- Set the `bucket` property to the appropriate bucket name\n- Verify the environment variable names match the project configuration (`STORAGE_<NAME_UPPER>_ACCESS_KEY`, `STORAGE_<NAME_UPPER>_SECRET_KEY`, `STORAGE_<NAME_UPPER>_ENDPOINT`, `STORAGE_<NAME_UPPER>_REGION`)\n- Add any additional storage-specific methods if needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { Storage, decorator, StorageException } from \"@ooneex/storage\";\nimport type { S3Options } from \"bun\";\n\n@decorator.storage()\nexport class <Name>Storage extends Storage {\n protected bucket: string;\n private readonly accessKey: string;\n private readonly secretKey: string;\n private readonly endpoint: string;\n private readonly region: string;\n\n constructor(options?: {\n accessKey?: string;\n secretKey?: string;\n endpoint?: string;\n region?: string;\n }) {\n super();\n\n const accessKey = options?.accessKey || Bun.env.STORAGE_<NAME_UPPER>_ACCESS_KEY;\n const secretKey = options?.secretKey || Bun.env.STORAGE_<NAME_UPPER>_SECRET_KEY;\n const endpoint = options?.endpoint || Bun.env.STORAGE_<NAME_UPPER>_ENDPOINT;\n\n // ... validation throws StorageException if missing ...\n\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = endpoint;\n this.region = options?.region || Bun.env.STORAGE_<NAME_UPPER>_REGION || \"auto\";\n }\n\n public getOptions(): S3Options {\n return {\n accessKeyId: this.accessKey,\n secretAccessKey: this.secretKey,\n endpoint: this.endpoint,\n bucket: this.bucket,\n region: this.region,\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/storage/<Name>Storage.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, bucket field, getOptions method)\n- Add tests relevant to the specific storage class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>StorageAdapter } from \"@/storage/<Name>StorageAdapter\";\n\ndescribe(\"<Name>StorageAdapter\", () => {\n test(\"should have class name ending with 'StorageAdapter'\", () => {\n expect(<Name>StorageAdapter.name.endsWith(\"StorageAdapter\")).toBe(true);\n });\n\n test(\"should have 'bucket' field\", () => {\n expect(\"bucket\" in <Name>StorageAdapter.prototype || \"bucket\" in Object.getOwnPropertyNames(<Name>StorageAdapter.prototype)).toBe(true);\n });\n\n test(\"should have 'getOptions' method\", () => {\n expect(<Name>StorageAdapter.prototype.getOptions).toBeDefined();\n expect(typeof <Name>StorageAdapter.prototype.getOptions).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/storage/<Name>Storage.ts tests/storage/<Name>Storage.spec.ts\n```\n";var ri="---\nname: make:vector-database\ndescription: Generate a new vector database class with its test file, then complete the generated code. Use when creating a new vector database that extends VectorDatabase from @ooneex/rag.\n---\n\n# Make Vector Database Class\n\nGenerate a new vector database class and its test file using the `make:vector-database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the vector database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:vector-database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>VectorDatabase.ts` - The vector database class file (or `modules/<module>/src/databases/<Name>VectorDatabase.ts` with `--module`)\n- `tests/databases/<Name>VectorDatabase.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>VectorDatabase.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the vector database class\n\nEdit `src/databases/<Name>VectorDatabase.ts` to complete the implementation:\n\n- Set the `getDatabaseUri()` return value to the actual LanceDB database path\n- Configure the embedding provider and model in `getEmbeddingModel()`\n- Define the custom data fields in `DataType` and map them in `getSchema()`\n- Import the appropriate Apache Arrow types for your schema fields\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { VectorDatabase, decorator } from \"@ooneex/rag\";\nimport type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from \"@ooneex/rag\";\nimport { Utf8 } from \"apache-arrow\";\n\ntype DataType = {\n name: string;\n};\n\n@decorator.vectorDatabase()\nexport class <Name>VectorDatabase extends VectorDatabase<DataType> {\n public getDatabaseUri(): string {\n return \"\";\n }\n\n public getEmbeddingModel(): { provider: EmbeddingProviderType; model: EmbeddingModelType[\"model\"] } {\n return { provider: \"openai\", model: \"text-embedding-ada-002\" };\n }\n\n public getSchema(): { [K in keyof DataType]: FieldValueType } {\n return {\n name: new Utf8(),\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>VectorDatabase.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getDatabaseUri, getEmbeddingModel, getSchema methods)\n- Add tests relevant to the specific vector database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>VectorDatabase } from \"@/databases/<Name>VectorDatabase\";\n\ndescribe(\"<Name>VectorDatabase\", () => {\n test(\"should have class name ending with 'VectorDatabase'\", () => {\n expect(<Name>VectorDatabase.name.endsWith(\"VectorDatabase\")).toBe(true);\n });\n\n test(\"should have 'getDatabaseUri' method\", () => {\n expect(<Name>VectorDatabase.prototype.getDatabaseUri).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getDatabaseUri).toBe(\"function\");\n });\n\n test(\"should have 'getEmbeddingModel' method\", () => {\n expect(<Name>VectorDatabase.prototype.getEmbeddingModel).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getEmbeddingModel).toBe(\"function\");\n });\n\n test(\"should have 'getSchema' method\", () => {\n expect(<Name>VectorDatabase.prototype.getSchema).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getSchema).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>VectorDatabase.ts tests/databases/<Name>VectorDatabase.spec.ts\n```\n";var oi=`---
|
|
1804
|
-
name: optimize
|
|
1805
|
-
description: Optimize a module's codebase for quality, performance, and clean conventions. Enforces arrow functions (except class methods), type/interface naming, removes duplication, and ensures only important tests remain.
|
|
1806
|
-
---
|
|
1807
|
-
|
|
1808
|
-
# Optimize Codebase
|
|
1809
|
-
|
|
1810
|
-
Optimize a module's codebase for quality, performance, and clean conventions.
|
|
1811
|
-
|
|
1812
|
-
## Coding Conventions
|
|
1813
|
-
|
|
1814
|
-
Apply these conventions across all files in the target module:
|
|
1815
|
-
|
|
1816
|
-
- **Arrow functions everywhere** \u2014 use arrow functions for all function expressions, callbacks, standalone functions, and variable declarations. The ONLY exception is class methods, which must use regular method syntax.
|
|
1817
|
-
- **Type naming** \u2014 all type aliases must end with the \`Type\` suffix (e.g., \`UserDataType\`, \`ConfigOptionsType\`). Rename any that don't comply.
|
|
1818
|
-
- **Interface naming** \u2014 all interface names must start with the \`I\` prefix (e.g., \`IUser\`, \`IService\`, \`IRepository\`). Rename any that don't comply.
|
|
1819
|
-
- Always explicitly show visibility on class methods and properties (\`private\`, \`public\`, \`protected\`).
|
|
1820
|
-
|
|
1821
|
-
## Steps
|
|
1822
|
-
|
|
1823
|
-
### 1. Identify the target
|
|
1824
|
-
|
|
1825
|
-
Determine the module to optimize. If the user specifies a module name, work in \`modules/<module>/\`. If no module is specified, ask the user which module to optimize.
|
|
1826
|
-
|
|
1827
|
-
### 2. Read and analyze the module
|
|
1828
|
-
|
|
1829
|
-
Read all source files (\`src/**/*.ts\`) and test files (\`tests/**/*.ts\`) in the target module. Build a full picture of:
|
|
1830
|
-
|
|
1831
|
-
- All types, interfaces, classes, and functions
|
|
1832
|
-
- Dependencies between files
|
|
1833
|
-
- Existing test coverage
|
|
1834
|
-
|
|
1835
|
-
### 3. Enforce naming conventions
|
|
1836
|
-
|
|
1837
|
-
Scan every file and fix:
|
|
1838
|
-
|
|
1839
|
-
- **Types not ending with \`Type\`** \u2014 rename the type and update all references across the module
|
|
1840
|
-
- **Interfaces not starting with \`I\`** \u2014 rename the interface and update all references across the module
|
|
1841
|
-
- **Non-arrow functions** \u2014 convert all function expressions, callbacks, and standalone functions to arrow functions. Do NOT convert class methods.
|
|
1842
|
-
- **Missing visibility modifiers** \u2014 add explicit \`public\`, \`private\`, or \`protected\` to all class methods and properties
|
|
1843
|
-
|
|
1844
|
-
### 4. Remove code duplication
|
|
1845
|
-
|
|
1846
|
-
Identify duplicated or near-duplicated code within the module:
|
|
1847
|
-
|
|
1848
|
-
- Extract shared logic into well-named helper arrow functions or base classes
|
|
1849
|
-
- Consolidate repeated type definitions
|
|
1850
|
-
- Merge similar utility functions
|
|
1851
|
-
- Remove dead code (unused imports, unreachable branches, unused variables)
|
|
1852
|
-
|
|
1853
|
-
### 5. Optimize for performance
|
|
1854
|
-
|
|
1855
|
-
Review and improve:
|
|
1856
|
-
|
|
1857
|
-
- Replace inefficient loops or repeated iterations with single-pass approaches where possible
|
|
1858
|
-
- Use \`Map\`/\`Set\` instead of arrays for lookups when appropriate
|
|
1859
|
-
- Avoid unnecessary object spreads or deep clones
|
|
1860
|
-
- Prefer early returns to reduce nesting
|
|
1861
|
-
- Remove unnecessary \`async\`/\`await\` where a direct return suffices
|
|
1862
|
-
- Eliminate redundant null/undefined checks when the type system already guarantees the value
|
|
1863
|
-
|
|
1864
|
-
### 6. Optimize tests
|
|
1865
|
-
|
|
1866
|
-
Review all test files and restructure:
|
|
1867
|
-
|
|
1868
|
-
- **Remove trivial tests** \u2014 delete tests that only check obvious things (e.g., "class name ends with X", "method exists") unless they serve as smoke tests for generated code
|
|
1869
|
-
- **Keep and improve important tests** \u2014 focus on tests that verify actual business logic, edge cases, error handling, and integration behavior
|
|
1870
|
-
- **Write fewer but more meaningful tests** \u2014 each test should validate a real scenario or invariant, not just existence checks
|
|
1871
|
-
- **Consolidate redundant test cases** \u2014 merge tests that cover the same code path with slightly different inputs into parameterized patterns
|
|
1872
|
-
- **Ensure critical paths are covered** \u2014 every public method with logic should have at least one test covering its happy path and one covering its error/edge case
|
|
1873
|
-
|
|
1874
|
-
### 7. Final cleanup
|
|
1875
|
-
|
|
1876
|
-
- Remove all unused imports
|
|
1877
|
-
- Remove empty files or files with no exports
|
|
1878
|
-
- Ensure consistent formatting
|
|
1879
|
-
|
|
1880
|
-
### 8. Lint and format
|
|
1881
|
-
|
|
1882
|
-
Run linting and formatting on all modified files:
|
|
1883
|
-
|
|
1884
|
-
\`\`\`bash
|
|
1885
|
-
bunx biome check --fix <list of modified files>
|
|
1886
|
-
\`\`\`
|
|
1887
|
-
|
|
1888
|
-
### 9. Run tests
|
|
1889
|
-
|
|
1890
|
-
Run the module's tests to verify nothing is broken:
|
|
1891
|
-
|
|
1892
|
-
\`\`\`bash
|
|
1893
|
-
bun test <module test directory>
|
|
1894
|
-
\`\`\`
|
|
1895
|
-
|
|
1896
|
-
If any test fails, fix the issue and re-run until all tests pass.
|
|
1897
|
-
`;var zl={"make.ai":$o,"make.analytics":Wo,"make.cache":qo,"make.controller":Ko,"make.cron":Ho,"make.database":Fo,"make.entity":Vo,"make.logger":Yo,"make.mailer":zo,"make.middleware":Zo,"make.migration":Qo,"make.permission":Xo,"make.pubsub":Jo,"make.repository":jo,"make.seed":ei,"make.service":ti,"make.storage":si,"make.vector-database":ri,commit:ko,optimize:oi};class qe{getName(){return"make:claude:skill"}getDescription(){return"Generate Claude skills from templates"}async run(){let e=We(".claude","skills"),t=We(process.cwd(),e),s=new Yl;for(let[r,o]of Object.entries(zl)){let i=r.replace(/\./g,"-"),a=We(t,i,"SKILL.md");await Bun.write(a,o),s.success(`${We(e,i,"SKILL.md")} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}}qe=b([x.command()],qe);import{basename as Xl,join as G}from"path";import{TerminalLogger as Jl}from"@ooneex/logger";import{toPascalCase as Lt}from"@ooneex/utils";var ii=`import { describe, expect, test } from "bun:test";
|
|
1818
|
+
`;var Uo="---\nname: make:ai\ndescription: Generate a new AI class with its test file, then complete the generated code. Use when creating a new AI chat class that uses OpenAI via the @ooneex/ai package.\n---\n\n# Make AI Class\n\nGenerate a new AI class and its test file using the `make:ai` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the AI class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:ai --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/ai/<Name>Ai.ts` - The AI class file (or `modules/<module>/src/ai/<Name>Ai.ts` with `--module`)\n- `tests/ai/<Name>Ai.spec.ts` - The test file (or `modules/<module>/tests/ai/<Name>Ai.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the AI class\n\nEdit `src/ai/<Name>Ai.ts` to complete the implementation:\n\n- Update the prompt in the `run` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Update the prompt in the `runStream` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Add any additional configuration or methods relevant to the AI class purpose\n- Ensure proper typing for the `run<T>()` generic return type\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from \"@ooneex/ai\";\nimport { inject } from \"@ooneex/container\";\n\n@decorator.ai()\nexport class <Name>Ai implements IAiChat<OpenAiConfigType> {\n constructor(@inject(OpenAi) private readonly ai: OpenAi) {}\n\n public async run<T>(prompt?: string, config?: Omit<OpenAiConfigType, \"prompt\">): Promise<T> {\n return this.ai.run<T>(prompt || \"My prompt\", config);\n }\n\n public async *runStream(\n prompt?: string,\n config?: Omit<OpenAiConfigType, \"prompt\" | \"output\">,\n ): AsyncGenerator<string, void, unknown> {\n yield* this.ai.runStream(prompt || \"My prompt\", config);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/ai/<Name>Ai.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, run method, runStream method)\n- Add tests relevant to the specific AI class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Ai } from \"@/ai/<Name>Ai\";\n\ndescribe(\"<Name>Ai\", () => {\n test(\"should have class name ending with 'Ai'\", () => {\n expect(<Name>Ai.name.endsWith(\"Ai\")).toBe(true);\n });\n\n test(\"should have 'run' method\", () => {\n expect(<Name>Ai.prototype.run).toBeDefined();\n expect(typeof <Name>Ai.prototype.run).toBe(\"function\");\n });\n\n test(\"should have 'runStream' method\", () => {\n expect(<Name>Ai.prototype.runStream).toBeDefined();\n expect(typeof <Name>Ai.prototype.runStream).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/ai/<Name>Ai.ts tests/ai/<Name>Ai.spec.ts\n```\n";var Go="---\nname: make:analytics\ndescription: Generate a new analytics class with its test file, then complete the generated code. Use when creating a new analytics tracking class that uses the @ooneex/analytics package.\n---\n\n# Make Analytics Class\n\nGenerate a new analytics class and its test file using the `make:analytics` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the analytics class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:analytics --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/analytics/<Name>Analytics.ts` - The analytics class file (or `modules/<module>/src/analytics/<Name>Analytics.ts` with `--module`)\n- `tests/analytics/<Name>Analytics.spec.ts` - The test file (or `modules/<module>/tests/analytics/<Name>Analytics.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the analytics class\n\nEdit `src/analytics/<Name>Analytics.ts` to complete the implementation:\n\n- Implement the `capture` method with actual analytics tracking logic\n- Define a proper type for `CaptureOptionsType` instead of `Record<string, unknown>` based on the analytics purpose\n- Add any additional methods or properties relevant to the analytics class purpose\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/analytics\";\nimport type { IAnalytics } from \"@ooneex/analytics\";\n\ntype CaptureOptionsType = Record<string, unknown>;\n\n@decorator.analytics()\nexport class <Name>Analytics<T extends CaptureOptionsType = CaptureOptionsType> implements IAnalytics<T> {\n public capture(options: T): void {\n // console.log(\"Analytics captured:\", options);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/analytics/<Name>Analytics.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, capture method)\n- Add tests relevant to the specific analytics class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Analytics } from \"@/analytics/<Name>Analytics\";\n\ndescribe(\"<Name>Analytics\", () => {\n test(\"should have class name ending with 'Analytics'\", () => {\n expect(<Name>Analytics.name.endsWith(\"Analytics\")).toBe(true);\n });\n\n test(\"should have 'capture' method\", () => {\n expect(<Name>Analytics.prototype.capture).toBeDefined();\n expect(typeof <Name>Analytics.prototype.capture).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/analytics/<Name>Analytics.ts tests/analytics/<Name>Analytics.spec.ts\n```\n";var ko="---\nname: make:cache\ndescription: Generate a new cache adapter class with its test file, then complete the generated code. Use when creating a new cache adapter that implements the ICache interface from @ooneex/cache.\n---\n\n# Make Cache Class\n\nGenerate a new cache class and its test file using the `make:cache` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cache class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cache --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cache/<Name>Cache.ts` - The cache class file (or `modules/<module>/src/cache/<Name>Cache.ts` with `--module`)\n- `tests/cache/<Name>Cache.spec.ts` - The test file (or `modules/<module>/tests/cache/<Name>Cache.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cache class\n\nEdit `src/cache/<Name>Cache.ts` to complete the implementation:\n\n- Implement the `get` method to retrieve cached values by key\n- Implement the `set` method to store values with optional TTL\n- Implement the `delete` method to remove cached entries\n- Implement the `has` method to check key existence\n- Replace the `CacheException` throws with actual cache logic\n- Inject any required dependencies (e.g., Redis client) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { CacheException, decorator } from \"@ooneex/cache\";\nimport type { ICache } from \"@ooneex/cache\";\n\n@decorator.cache()\nexport class <Name>Cache implements ICache {\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n throw new CacheException(`Failed to get key \"${key}\": Not implemented`);\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n throw new CacheException(`Failed to set key \"${key}\": Not implemented`);\n }\n\n public async delete(key: string): Promise<boolean> {\n throw new CacheException(`Failed to delete key \"${key}\": Not implemented`);\n }\n\n public async has(key: string): Promise<boolean> {\n throw new CacheException(`Failed to check if key \"${key}\" exists: Not implemented`);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cache/<Name>Cache.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, get, set, delete, has methods)\n- Add tests relevant to the specific cache class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cache } from \"@/cache/<Name>Cache\";\n\ndescribe(\"<Name>Cache\", () => {\n test(\"should have class name ending with 'Cache'\", () => {\n expect(<Name>Cache.name.endsWith(\"Cache\")).toBe(true);\n });\n\n test(\"should have 'get' method\", () => {\n expect(<Name>Cache.prototype.get).toBeDefined();\n expect(typeof <Name>Cache.prototype.get).toBe(\"function\");\n });\n\n test(\"should have 'set' method\", () => {\n expect(<Name>Cache.prototype.set).toBeDefined();\n expect(typeof <Name>Cache.prototype.set).toBe(\"function\");\n });\n\n test(\"should have 'delete' method\", () => {\n expect(<Name>Cache.prototype.delete).toBeDefined();\n expect(typeof <Name>Cache.prototype.delete).toBe(\"function\");\n });\n\n test(\"should have 'has' method\", () => {\n expect(<Name>Cache.prototype.has).toBeDefined();\n expect(typeof <Name>Cache.prototype.has).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cache/<Name>Cache.ts tests/cache/<Name>Cache.spec.ts\n```\n";var $o="---\nname: make:controller\ndescription: Generate a new controller class with route type and test file, then complete the generated code. Use when creating a new HTTP or WebSocket controller with routing, validation, and role-based access.\n---\n\n# Make Controller Class\n\nGenerate a new controller class, its route type, and test file using the `make:controller` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the controller class and related files:\n\n```bash\nbunx @ooneex/cli@latest make:controller --name <name> --module <module> --is-socket <true|false> --route.name <route.name> --route.path <route.path> --route.method <route.method>\n```\n\nWhere:\n- `<name>` is the controller name provided by the user\n- `--module` is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root\n- `--is-socket` determines HTTP vs WebSocket controller (defaults to `false`)\n- `--route.name` is the route name using dot notation: `<resource>.<action>` (e.g., `user.create`, `book.list`, `flashcard.delete`)\n- `--route.path` is the route path (e.g., `/api/users`)\n- `--route.method` is the HTTP method (e.g., `get`, `post`, `put`, `patch`, `delete`) \u2014 only for HTTP controllers\n\nThe command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/controllers/<Name>Controller.ts` - The controller class file\n- `src/types/routes/<route.name>.ts` - The route type file (will be moved into the controller file \u2014 see step 3)\n- `tests/controllers/<Name>Controller.spec.ts` - The test file\n\n### 2. Read the generated files\n\nRead all three generated files to understand the scaffolded code.\n\n### 3. Complete the route type\n\n**IMPORTANT: Keep the route type inside the controller file**, not in a separate type file. Define the type directly in `src/controllers/<Name>Controller.ts` above the class definition. Delete the generated `src/types/routes/<route.name>.ts` file if it was created.\n\n**Remove unnecessary `params`, `payload`, and `queries` \u2014 only include what the route actually needs:**\n\n- **`params`** \u2014 Include only when the route path contains dynamic segments (e.g., `/api/users/:id`). Remove entirely for routes with no URL parameters (e.g., `/api/users`).\n- **`payload`** \u2014 Include only for methods that accept a request body (`post`, `put`, `patch`). Remove entirely for `get` and `delete` routes.\n- **`queries`** \u2014 Include only when the route supports query string filtering, pagination, or sorting (e.g., list/search endpoints). Remove entirely when not needed.\n- **`response`** \u2014 Always include.\n\nThe route type structure follows this pattern (remove unused sections):\n\n```typescript\n// Example: GET /api/users (list) \u2014 no params, no payload, has queries\ntype <TypeName>RouteType = {\n queries: {\n\n },\n response: {\n\n },\n};\n\n// Example: POST /api/users (create) \u2014 no params, has payload, no queries\ntype <TypeName>RouteType = {\n payload: {\n\n },\n response: {\n\n },\n};\n\n// Example: GET /api/users/:id (detail) \u2014 has params, no payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n response: {\n\n },\n};\n\n// Example: PUT /api/users/:id (update) \u2014 has params, has payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n payload: {\n\n },\n response: {\n\n },\n};\n```\n\n### 4. Complete the controller class\n\nEdit `src/controllers/<Name>Controller.ts` to complete the implementation:\n\n- Set appropriate `roles` for access control\n- Add a meaningful `description` for the route that explains what the endpoint does (e.g., `\"Create a new user account\"`, `\"List all books with pagination\"`)\n- **Keep the controller thin** \u2014 do NOT put business logic in the controller. Put all logic in the corresponding service and inject the service into the controller via the constructor. The controller's `index` method should only delegate to the service.\n- **Remove unnecessary `params`, `payload`, and `queries`** from both the route type and the `@Route` decorator \u2014 only include what the route actually needs (see step 3 rules).\n\n**Add or remove `params`, `payload`, and `queries` in the `@Route` decorator to match the route type (step 3):**\n\n- **`params`** \u2014 Include with `Assert()` validators only when the route has URL parameters. Remove the `params` key entirely otherwise.\n- **`payload`** \u2014 Include with `Assert({...})` only for `post`, `put`, `patch` methods. Remove the `payload` key entirely for `get` and `delete`.\n- **`queries`** \u2014 Include with `Assert({...})` only when query parameters are expected. Remove the `queries` key entirely otherwise.\n- **`response`** \u2014 Always include with `Assert({...})`.\n\n**HTTP controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n**Socket controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n### 5. Complete the test file\n\nEdit `tests/controllers/<Name>Controller.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, index method)\n- Add tests relevant to the specific controller behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Controller } from \"@/controllers/<Name>Controller\";\n\ndescribe(\"<Name>Controller\", () => {\n test(\"should have class name ending with 'Controller'\", () => {\n expect(<Name>Controller.name.endsWith(\"Controller\")).toBe(true);\n });\n\n test(\"should have 'index' method\", () => {\n expect(<Name>Controller.prototype.index).toBeDefined();\n expect(typeof <Name>Controller.prototype.index).toBe(\"function\");\n });\n});\n```\n\n### 6. Register the controller in the module\n\nAdd the new controller to the module's `controllers` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Controller } from \"./controllers/<Name>Controller\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [<Name>Controller],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other controllers registered, append the new controller to the existing `controllers` array and add the import alongside existing imports.\n\n### 7. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/controllers/<Name>Controller.ts tests/controllers/<Name>Controller.spec.ts\n```\n\n### 8. Create the service\n\nAfter the controller is created, generate a service class for the controller's business logic using the `make:service` skill:\n\n```\n/make:service --name <Name>\n```\n\nWhere `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the service is `CreateUserService`).\n\n### 9. Create the pubsub event\n\nAfter the service is created, generate a pubsub event class for the controller's domain events using the `make:pubsub` skill:\n\n```\n/make:pubsub --name <Name> --channel <resource>.<action>\n```\n\nWhere:\n- `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the event is `CreateUserEvent`)\n- `<resource>.<action>` follows the same dot notation as the route name (e.g., `user.create`, `book.delete`)\n\nOnce the event is created:\n- Inject the **service** into the **event** via the constructor, and call the service's `execute` method from the event's `handler` method.\n- Inject the **event** into the **controller** via the constructor, and publish the event from the controller's `index` method.\n";var qo="---\nname: make:cron\ndescription: Generate a new cron job class with its test file, then complete the generated code. Use when creating a new scheduled task that extends the Cron base class from @ooneex/cron.\n---\n\n# Make Cron Class\n\nGenerate a new cron class and its test file using the `make:cron` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cron class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cron --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cron/<Name>Cron.ts` - The cron class file (or `modules/<module>/src/cron/<Name>Cron.ts` with `--module`)\n- `tests/cron/<Name>Cron.spec.ts` - The test file (or `modules/<module>/tests/cron/<Name>Cron.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cron class\n\nEdit `src/cron/<Name>Cron.ts` to complete the implementation:\n\n- Set the appropriate cron schedule in `getTime()` (e.g., `\"every 5 minutes\"`, `\"every 1 hours\"`, `\"every 30 seconds\"`)\n- Set the timezone in `getTimeZone()` if needed, or keep `null` for server timezone\n- Implement the `handler()` method with the actual cron job logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { TimeZoneType } from \"@ooneex/country\";\nimport type { CronTimeType } from \"@ooneex/cron\";\nimport { Cron, decorator } from \"@ooneex/cron\";\n\n@decorator.cron()\nexport class <Name>Cron extends Cron {\n public getTime(): CronTimeType {\n // Examples: \"every 5 minutes\", \"every 1 hours\", \"every 30 seconds\"\n return \"every 1 hours\";\n }\n\n public getTimeZone(): TimeZoneType | null {\n // Return null to use server timezone, or specify a timezone like \"Europe/Paris\"\n return null;\n }\n\n public async handler(): Promise<void> {\n // Implement your cron handler logic here\n // console.log(\"<Name>Cron handler executed\");\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cron/<Name>Cron.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getTime, getTimeZone, handler methods)\n- Add tests relevant to the specific cron class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cron } from \"@/cron/<Name>Cron\";\n\ndescribe(\"<Name>Cron\", () => {\n test(\"should have class name ending with 'Cron'\", () => {\n expect(<Name>Cron.name.endsWith(\"Cron\")).toBe(true);\n });\n\n test(\"should have 'getTime' method\", () => {\n expect(<Name>Cron.prototype.getTime).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTime).toBe(\"function\");\n });\n\n test(\"should have 'getTimeZone' method\", () => {\n expect(<Name>Cron.prototype.getTimeZone).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTimeZone).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Cron.prototype.handler).toBeDefined();\n expect(typeof <Name>Cron.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the cron job in the module\n\nAdd the new cron job to the module's `cronJobs` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Cron } from \"./cron/<Name>Cron\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [<Name>Cron],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other cron jobs registered, append the new cron job to the existing `cronJobs` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cron/<Name>Cron.ts tests/cron/<Name>Cron.spec.ts\n```\n";var Wo="---\nname: make:database\ndescription: Generate a new database class with its test file, then complete the generated code. Use when creating a new database adapter that extends TypeormDatabase from @ooneex/database.\n---\n\n# Make Database Class\n\nGenerate a new database class and its test file using the `make:database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>Database.ts` - The database class file (or `modules/<module>/src/databases/<Name>Database.ts` with `--module`)\n- `tests/databases/<Name>Database.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>Database.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the database class\n\nEdit `src/databases/<Name>Database.ts` to complete the implementation:\n\n- Add entity imports and register them in the `entities` array\n- Adjust the database path if needed (default is `\"var/db\"`)\n- Configure DataSource options as appropriate (type, synchronize, etc.)\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { DataSource } from \"typeorm\";\nimport { TypeormDatabase, DatabaseException, decorator } from \"@ooneex/database\";\n\n@decorator.database()\nexport class <Name>Database extends TypeormDatabase {\n public getSource(database?: string): DataSource {\n database = database || \"var/db\";\n\n this.source = new DataSource({\n synchronize: false,\n entities: [\n // TODO: Load your entities here\n ],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n database,\n type: \"sqlite\",\n });\n\n return this.source;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>Database.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getSource method)\n- Add tests relevant to the specific database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Database } from \"@/databases/<Name>Database\";\n\ndescribe(\"<Name>Database\", () => {\n test(\"should have class name ending with 'Database'\", () => {\n expect(<Name>Database.name.endsWith(\"Database\")).toBe(true);\n });\n\n test(\"should have 'getSource' method\", () => {\n expect(<Name>Database.prototype.getSource).toBeDefined();\n expect(typeof <Name>Database.prototype.getSource).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>Database.ts tests/databases/<Name>Database.spec.ts\n```\n";var Ko="---\nname: make:entity\ndescription: Generate a new TypeORM entity class with its test file, then complete the generated code. Use when creating a new database entity with columns, relations, and table mapping.\n---\n\n# Make Entity Class\n\nGenerate a new entity class and its test file using the `make:entity` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the entity class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:entity --name <name> --module <module> --table-name <table_name>\n```\n\nWhere `<name>` is the name provided by the user. The `--table-name` option is optional \u2014 if omitted, it defaults to the snake_case pluralized form of the name (e.g., `UserProfile` becomes `user_profiles`). The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/entities/<Name>Entity.ts` - The entity class file (or `modules/<module>/src/entities/<Name>Entity.ts` with `--module`)\n- `tests/entities/<Name>Entity.spec.ts` - The test file (or `modules/<module>/tests/entities/<Name>Entity.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the entity class\n\nEdit `src/entities/<Name>Entity.ts` to complete the implementation:\n\n- Add entity-specific columns with appropriate TypeORM decorators (`@Column`)\n- Add relations if needed (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, etc.)\n- Remove any scaffolded columns that are not relevant to the entity\n- Adjust column types, lengths, and constraints as needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { LocaleType } from \"@ooneex/translation\";\nimport { random } from \"@ooneex/utils\";\nimport { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n@Entity({\n name: \"<table_name>\",\n})\nexport class <Name>Entity extends BaseEntity {\n @PrimaryColumn({ name: \"id\", type: \"varchar\", length: 25 })\n id: string = random.nanoid(25);\n\n @Column({\n name: \"is_locked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isLocked?: boolean;\n\n @Column({ name: \"locked_at\", type: \"timestamptz\", nullable: true })\n lockedAt?: Date;\n\n @Column({\n name: \"is_blocked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isBlocked?: boolean;\n\n @Column({ name: \"blocked_at\", type: \"timestamptz\", nullable: true })\n blockedAt?: Date;\n\n @Column({ name: \"block_reason\", type: \"text\", nullable: true })\n blockReason?: string;\n\n @Column({ name: \"is_public\", type: \"boolean\", default: true, nullable: true })\n isPublic?: boolean;\n\n @Column({ name: \"lang\", type: \"varchar\", length: 10, nullable: true })\n lang?: LocaleType;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt?: Date;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt?: Date;\n\n @DeleteDateColumn({ name: \"deleted_at\" })\n deletedAt?: Date;\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/entities/<Name>Entity.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, id, default columns)\n- Add tests for any new entity-specific columns and relations\n- Update tests if scaffolded columns were removed\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Entity } from \"@/entities/<Name>Entity\";\n\ndescribe(\"<Name>Entity\", () => {\n test(\"should have class name ending with 'Entity'\", () => {\n expect(<Name>Entity.name.endsWith(\"Entity\")).toBe(true);\n });\n\n test(\"should have 'id' property with default nanoid\", () => {\n const entity = new <Name>Entity();\n expect(entity.id).toBeDefined();\n expect(typeof entity.id).toBe(\"string\");\n expect(entity.id.length).toBe(25);\n });\n\n test(\"should have 'isLocked' property\", () => {\n const entity = new <Name>Entity();\n expect(\"isLocked\" in entity).toBe(true);\n });\n\n // ... additional property tests\n});\n```\n\n### 5. Register the entity in the module\n\nAdd the new entity to the module's `entities` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Entity } from \"./entities/<Name>Entity\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [<Name>Entity],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other entities registered, append the new entity to the existing `entities` array and add the import alongside existing imports.\n\n### 6. Create a migration for the entity\n\nAfter creating or updating an entity, generate a migration to apply the corresponding schema changes to the database.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:migration\n```\n\nThen read the generated migration file in `src/migrations/` and complete it:\n\n- In the `up` method, write the SQL to create the table (or alter it if updating an existing entity). Include all columns, types, constraints, defaults, and indexes matching the entity definition.\n- In the `down` method, write the reverse SQL to undo the changes (e.g., `DROP TABLE` or `ALTER TABLE DROP COLUMN`).\n- If the migration depends on another migration (e.g., a foreign key referencing another table), add that migration class to the `getDependencies()` return array.\n\nExample `up` method for a new entity:\n\n```typescript\npublic async up(tx: TransactionSQL): Promise<void> {\n await tx`\n CREATE TABLE IF NOT EXISTS <table_name> (\n id VARCHAR(25) PRIMARY KEY,\n is_locked BOOLEAN DEFAULT false,\n locked_at TIMESTAMPTZ,\n is_blocked BOOLEAN DEFAULT false,\n blocked_at TIMESTAMPTZ,\n block_reason TEXT,\n is_public BOOLEAN DEFAULT true,\n lang VARCHAR(10),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n deleted_at TIMESTAMPTZ\n )\n `;\n}\n```\n\n### 7. Create a repository for the entity\n\nAfter creating the entity, generate a repository to handle database operations for it.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name>\n```\n\nWhere `<name>` is the same name used for the entity. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class\n- `tests/repositories/<Name>Repository.spec.ts` - The test file\n\nThen read the generated files and complete the repository implementation:\n\n- Adjust search fields in the `find()` method to match the entity's searchable columns\n- Customize relations loading in `findOne`/`findOneBy` if the entity has relations\n- Add any domain-specific methods relevant to the entity\n- Remove methods that don't apply to the entity\n- Update tests to match the final repository methods\n\n### 8. Lint and format\n\nRun linting and formatting on all generated files:\n\n```bash\nbunx biome check --fix src/entities/<Name>Entity.ts tests/entities/<Name>Entity.spec.ts src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts src/migrations/\n```\n";var Fo="---\nname: make:logger\ndescription: Generate a new logger class with its test file, then complete the generated code. Use when creating a new logger that implements the ILogger interface from @ooneex/logger.\n---\n\n# Make Logger Class\n\nGenerate a new logger class and its test file using the `make:logger` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the logger class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:logger --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/loggers/<Name>Logger.ts` - The logger class file (or `modules/<module>/src/loggers/<Name>Logger.ts` with `--module`)\n- `tests/loggers/<Name>Logger.spec.ts` - The test file (or `modules/<module>/tests/loggers/<Name>Logger.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the logger class\n\nEdit `src/loggers/<Name>Logger.ts` to complete the implementation:\n\n- Implement the `init()` method to set up the logger (e.g., open file handles, configure transports)\n- Implement `log`, `debug`, `info`, `success`, `warn`, and `error` methods with actual logging logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { IException } from \"@ooneex/exception\";\nimport type { ILogger } from \"@ooneex/logger\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator } from \"@ooneex/logger\";\n\n@decorator.logger()\nexport class <Name>Logger implements ILogger {\n public async init(): Promise<void> {\n // Initialize your logger here\n }\n\n public log(message: string, data?: Record<string, ScalarType>): void {\n // Handle general logging\n }\n\n public debug(message: string, data?: Record<string, ScalarType>): void {\n // Handle debug logging\n }\n\n public info(message: string, data?: Record<string, ScalarType>): void {\n // Handle info logging\n }\n\n public success(message: string, data?: Record<string, ScalarType>): void {\n // Handle success logging\n }\n\n public warn(message: string, data?: Record<string, ScalarType>): void {\n // Handle warning logging\n }\n\n public error(message: string | IException, data?: Record<string, ScalarType>): void {\n // Handle error logging\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/loggers/<Name>Logger.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, init, log, debug, info, success, warn, error methods)\n- Add tests relevant to the specific logger class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Logger } from \"@/loggers/<Name>Logger\";\n\ndescribe(\"<Name>Logger\", () => {\n test(\"should have class name ending with 'Logger'\", () => {\n expect(<Name>Logger.name.endsWith(\"Logger\")).toBe(true);\n });\n\n test(\"should have 'init' method\", () => {\n expect(<Name>Logger.prototype.init).toBeDefined();\n expect(typeof <Name>Logger.prototype.init).toBe(\"function\");\n });\n\n test(\"should have 'log' method\", () => {\n expect(<Name>Logger.prototype.log).toBeDefined();\n expect(typeof <Name>Logger.prototype.log).toBe(\"function\");\n });\n\n test(\"should have 'debug' method\", () => {\n expect(<Name>Logger.prototype.debug).toBeDefined();\n expect(typeof <Name>Logger.prototype.debug).toBe(\"function\");\n });\n\n test(\"should have 'info' method\", () => {\n expect(<Name>Logger.prototype.info).toBeDefined();\n expect(typeof <Name>Logger.prototype.info).toBe(\"function\");\n });\n\n test(\"should have 'success' method\", () => {\n expect(<Name>Logger.prototype.success).toBeDefined();\n expect(typeof <Name>Logger.prototype.success).toBe(\"function\");\n });\n\n test(\"should have 'warn' method\", () => {\n expect(<Name>Logger.prototype.warn).toBeDefined();\n expect(typeof <Name>Logger.prototype.warn).toBe(\"function\");\n });\n\n test(\"should have 'error' method\", () => {\n expect(<Name>Logger.prototype.error).toBeDefined();\n expect(typeof <Name>Logger.prototype.error).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/loggers/<Name>Logger.ts tests/loggers/<Name>Logger.spec.ts\n```\n";var Ho="---\nname: make:mailer\ndescription: Generate a new mailer class with its template and test files, then complete the generated code. Use when creating a new email sender with JSX template using @ooneex/mailer.\n---\n\n# Make Mailer Class\n\nGenerate a new mailer class, its JSX template, and test files using the `make:mailer` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the mailer class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:mailer --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/mailers/<Name>Mailer.ts` - The mailer class file\n- `src/mailers/<Name>MailerTemplate.tsx` - The JSX email template\n- `tests/mailers/<Name>Mailer.spec.ts` - The mailer test file\n- `tests/mailers/<Name>MailerTemplate.spec.ts` - The template test file\n\n### 2. Read the generated files\n\nRead all four generated files to understand the scaffolded code.\n\n### 3. Complete the mailer class\n\nEdit `src/mailers/<Name>Mailer.ts` to complete the implementation:\n\n- Adjust the `send` method config type if additional parameters are needed\n- Add any pre-send logic (validation, data transformation, etc.)\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { IMailer } from \"@ooneex/mailer\";\nimport { type <Name>MailerPropsType, <Name>MailerTemplate } from \"./<Name>MailerTemplate\";\n\nexport class <Name>Mailer implements IMailer {\n constructor(\n @inject(\"mailer\")\n private readonly mailer: IMailer,\n ) {}\n\n public send = async (config: {\n to: string[];\n subject: string;\n from?: { name: string; address: string };\n data?: <Name>MailerPropsType;\n }): Promise<void> => {\n const { data, ...rest } = config;\n\n await this.mailer.send({\n ...rest,\n content: <Name>MailerTemplate(data),\n });\n };\n}\n```\n\n### 4. Complete the mailer template\n\nEdit `src/mailers/<Name>MailerTemplate.tsx` to complete the implementation:\n\n- Update `<Name>MailerPropsType` with the actual props needed for the email\n- Build the email body using `MailerLayout` components (Header, Body, Footer)\n- Add email content, styling, and dynamic data rendering\n\nThe generated template structure follows this pattern:\n\n```tsx\nimport { MailerLayout } from \"@ooneex/mailer\";\n\nexport type <Name>MailerPropsType = {\n link: string;\n};\n\nexport const <Name>MailerTemplate = (props?: <Name>MailerPropsType) => (\n <MailerLayout>\n <MailerLayout.Header />\n <MailerLayout.Body>\n <a href={props?.link}>Login</a>\n </MailerLayout.Body>\n <MailerLayout.Footer />\n </MailerLayout>\n);\n```\n\n### 5. Complete the test files\n\nEdit `tests/mailers/<Name>Mailer.spec.ts` and `tests/mailers/<Name>MailerTemplate.spec.ts` to add meaningful tests beyond the scaffolded ones.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/mailers/<Name>Mailer.ts src/mailers/<Name>MailerTemplate.tsx tests/mailers/<Name>Mailer.spec.ts tests/mailers/<Name>MailerTemplate.spec.ts\n```\n";var Vo="---\nname: make:middleware\ndescription: Generate a new middleware class with its test file, then complete the generated code. Use when creating a new HTTP or WebSocket middleware that implements IMiddleware from @ooneex/middleware.\n---\n\n# Make Middleware Class\n\nGenerate a new middleware class and its test file using the `make:middleware` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the middleware class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:middleware --name <name> --module <module> --is-socket <true|false>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--is-socket` option determines whether to generate an HTTP middleware or a WebSocket middleware (defaults to `false` if omitted). The command will generate:\n- `src/middlewares/<Name>Middleware.ts` - The middleware class file (or `modules/<module>/src/middlewares/<Name>Middleware.ts` with `--module`)\n- `tests/middlewares/<Name>Middleware.spec.ts` - The test file (or `modules/<module>/tests/middlewares/<Name>Middleware.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the middleware class\n\nEdit `src/middlewares/<Name>Middleware.ts` to complete the implementation:\n\n- Implement the `handler` method with actual middleware logic\n- Add request/response transformations, authentication checks, logging, etc.\n- Inject any required dependencies via the constructor\n\n**HTTP middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n**Socket middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/middlewares/<Name>Middleware.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, handler method)\n- Add tests relevant to the specific middleware behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Middleware } from \"@/middlewares/<Name>Middleware\";\n\ndescribe(\"<Name>Middleware\", () => {\n test(\"should have class name ending with 'Middleware'\", () => {\n expect(<Name>Middleware.name.endsWith(\"Middleware\")).toBe(true);\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Middleware.prototype.handler).toBeDefined();\n expect(typeof <Name>Middleware.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the middleware in the module\n\nAdd the new middleware to the module's `middlewares` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Middleware } from \"./middlewares/<Name>Middleware\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [<Name>Middleware],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other middlewares registered, append the new middleware to the existing `middlewares` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/middlewares/<Name>Middleware.ts tests/middlewares/<Name>Middleware.spec.ts\n```\n";var Yo="---\nname: make:migration\ndescription: Generate a new database migration file, then complete the generated code. Use when creating a new database migration for schema changes using @ooneex/migrations.\n---\n\n# Make Migration\n\nGenerate a new migration file using the `make:migration` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the migration file:\n\n```bash\nbunx @ooneex/cli@latest make:migration --module <module>\n```\n\nThe `--module` option is optional \u2014 if provided, the migration file is generated under `modules/<module>/src/migrations/` instead of `src/migrations/`. The command will:\n- Generate a timestamped migration file in `src/migrations/` (or `modules/<module>/src/migrations/` with `--module`)\n- Add a `migration:up` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated migration file in `src/migrations/` to understand the scaffolded code.\n\n### 3. Complete the migration\n\nEdit the generated migration file to implement:\n\n- The `up` method with the schema changes (create tables, add columns, create indexes, etc.)\n- The `down` method with the reverse operations to undo the migration\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/migrations/\n```\n";var zo="---\nname: make:permission\ndescription: Generate a new permission class with its test file, then complete the generated code. Use when creating a new permission that extends Permission from @ooneex/permission.\n---\n\n# Make Permission Class\n\nGenerate a new permission class and its test file using the `make:permission` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the permission class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:permission --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/permissions/<Name>Permission.ts` - The permission class file (or `modules/<module>/src/permissions/<Name>Permission.ts` with `--module`)\n- `tests/permissions/<Name>Permission.spec.ts` - The test file (or `modules/<module>/tests/permissions/<Name>Permission.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the permission class\n\nEdit `src/permissions/<Name>Permission.ts` to complete the implementation:\n\n- Implement the `allow()` method with permission rules using `this.ability.can()`\n- Implement the `setUserPermissions()` method with role-based permission logic\n- Define which actions (read, create, update, delete, manage) are allowed on which entities\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, Permission } from \"@ooneex/permission\";\nimport type { IUser } from \"@ooneex/user\";\n\n@decorator.permission()\nexport class <Name>Permission extends Permission {\n public allow(): this {\n // Example: Add permissions using this.ability.can()\n // this.ability.can(\"read\", \"YourEntity\");\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n\n return this;\n }\n\n public setUserPermissions(user: IUser | null): this {\n if (!user) {\n return this;\n }\n\n // Example: Grant full access to admins\n // const { roles } = user;\n // if (roles.includes(ERole.ADMIN)) {\n // this.ability.can(\"manage\", \"all\");\n // return this;\n // }\n\n // Example: Grant specific permissions based on roles\n // for (const role of roles) {\n // if (role === ERole.USER) {\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n // }\n //\n // if (role === ERole.GUEST) {\n // this.ability.can(\"read\", \"YourEntity\", { public: true });\n // }\n // }\n\n return this;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/permissions/<Name>Permission.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, extends Permission, allow, setUserPermissions methods)\n- Add tests relevant to the specific permission rules\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { Permission } from \"@ooneex/permission\";\nimport { <Name>Permission } from \"@/permissions/<Name>Permission\";\n\ndescribe(\"<Name>Permission\", () => {\n test(\"should have class name ending with 'Permission'\", () => {\n expect(<Name>Permission.name.endsWith(\"Permission\")).toBe(true);\n });\n\n test(\"should extend Permission\", () => {\n const permission = new <Name>Permission();\n expect(permission).toBeInstanceOf(Permission);\n });\n\n test(\"should have 'allow' method\", () => {\n expect(<Name>Permission.prototype.allow).toBeDefined();\n expect(typeof <Name>Permission.prototype.allow).toBe(\"function\");\n });\n\n test(\"should have 'setUserPermissions' method\", () => {\n expect(<Name>Permission.prototype.setUserPermissions).toBeDefined();\n expect(typeof <Name>Permission.prototype.setUserPermissions).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the permission in the module\n\nAdd the new permission to the module's `permissions` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Permission } from \"./permissions/<Name>Permission\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [<Name>Permission],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other permissions registered, append the new permission to the existing `permissions` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/permissions/<Name>Permission.ts tests/permissions/<Name>Permission.spec.ts\n```\n";var Zo="---\nname: make:pubsub\ndescription: Generate a new PubSub event class with its test file, then complete the generated code. Use when creating a new publish/subscribe event that extends PubSub from @ooneex/pub-sub.\n---\n\n# Make PubSub Event Class\n\nGenerate a new PubSub event class and its test file using the `make:pubsub` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the PubSub event class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:pubsub --name <name> --module <module> --channel <channel>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--channel` option is optional \u2014 if omitted, it defaults to the kebab-case form of the name (e.g., `UserCreated` becomes `user-created`). The command will generate:\n- `src/events/<Name>Event.ts` - The event class file (or `modules/<module>/src/events/<Name>Event.ts` with `--module`)\n- `tests/events/<Name>Event.spec.ts` - The test file (or `modules/<module>/tests/events/<Name>Event.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the PubSub event class\n\nEdit `src/events/<Name>Event.ts` to complete the implementation:\n\n- Define a proper data type instead of `Record<string, ScalarType>` for the event payload\n- Implement the `handler()` method with actual event handling logic\n- Set the appropriate channel name in `getChannel()`\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator, PubSub, RedisPubSub } from \"@ooneex/pub-sub\";\n\n@decorator.pubSub()\nexport class <Name>Event<Data extends Record<string, ScalarType> = Record<string, ScalarType>> extends PubSub<Data> {\n constructor(\n @inject(RedisPubSub)\n client: RedisPubSub<Data>,\n ) {\n super(client);\n }\n\n public getChannel(): string {\n return \"<channel>\";\n }\n\n public async handler(context: { data: Data; channel: string }): Promise<void> {\n console.log(context);\n // TODO: Implement handler logic here\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/events/<Name>Event.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getChannel, handler, publish, subscribe, unsubscribe, unsubscribeAll methods)\n- Add tests relevant to the specific event behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>PubSub } from \"@/pubsub/<Name>PubSub\";\n\ndescribe(\"<Name>PubSub\", () => {\n test(\"should have class name ending with 'PubSub'\", () => {\n expect(<Name>PubSub.name.endsWith(\"PubSub\")).toBe(true);\n });\n\n test(\"should have 'getChannel' method\", () => {\n expect(<Name>PubSub.prototype.getChannel).toBeDefined();\n expect(typeof <Name>PubSub.prototype.getChannel).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>PubSub.prototype.handler).toBeDefined();\n expect(typeof <Name>PubSub.prototype.handler).toBe(\"function\");\n });\n\n test(\"should have 'publish' method\", () => {\n expect(<Name>PubSub.prototype.publish).toBeDefined();\n expect(typeof <Name>PubSub.prototype.publish).toBe(\"function\");\n });\n\n test(\"should have 'subscribe' method\", () => {\n expect(<Name>PubSub.prototype.subscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.subscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribe' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribeAll' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribeAll).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribeAll).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the event in the module\n\nAdd the new event to the module's `events` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Event } from \"./events/<Name>Event\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [<Name>Event],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other events registered, append the new event to the existing `events` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/events/<Name>Event.ts tests/events/<Name>Event.spec.ts\n```\n";var Qo="---\nname: make:repository\ndescription: Generate a new repository class with its test file, then complete the generated code. Use when creating a new TypeORM repository for database operations on an entity.\n---\n\n# Make Repository Class\n\nGenerate a new repository class and its test file using the `make:repository` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the repository class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class file (or `modules/<module>/src/repositories/<Name>Repository.ts` with `--module`)\n- `tests/repositories/<Name>Repository.spec.ts` - The test file (or `modules/<module>/tests/repositories/<Name>Repository.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the repository class\n\nEdit `src/repositories/<Name>Repository.ts` to complete the implementation:\n\n- Verify the entity import path matches the actual entity location\n- Adjust the `find` method's search fields (default searches `name` with `ILike`)\n- Customize relations loading in `findOne`/`findOneBy` if needed\n\n#### Adding methods\n\nLook at the entity's fields, relations, and business context to determine if custom domain-specific methods are needed. For example:\n- A `SessionRepository` might need `revokeSession(sessionId: string)` and `revokeAllUserSessions(userId: string)`\n- A `NotificationRepository` might need `markAsRead(id: string)` and `markAllAsRead(userId: string)`\n- Entities with status fields may need methods like `archive(id: string)` or `activate(id: string)`\n\nRead related entities, services, or actions in the module to understand what operations the repository should support, then add the appropriate methods.\n\n#### Removing methods\n\nRemove scaffolded methods that don't make sense for the entity's context:\n- Remove `createMany`/`updateMany` if the entity is always managed individually (e.g., user profiles, settings)\n- Remove `delete` if the entity uses soft deletes only (use a custom `softDelete` or `archive` method instead)\n- Remove `find` if the entity is only ever accessed by ID or specific criteria (e.g., singleton config entities)\n- Remove `count` if there's no use case for counting records of this entity\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ITypeormDatabase } from \"@ooneex/database\";\nimport { decorator } from \"@ooneex/repository\";\nimport type { FilterResultType } from \"@ooneex/types\";\nimport type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from \"typeorm\";\nimport { ILike } from \"typeorm\";\nimport { <Name>Entity } from \"../entities/<Name>Entity\";\n\n@decorator.repository()\nexport class <Name>Repository {\n constructor(\n @inject(\"database\")\n private readonly database: ITypeormDatabase,\n ) {}\n\n public async open(): Promise<Repository<<Name>Entity>> {\n return await this.database.open(<Name>Entity);\n }\n\n public async close(): Promise<void> {\n await this.database.close();\n }\n\n public async find(\n criteria: FindManyOptions<<Name>Entity> & { page?: number; limit?: number; q?: string },\n ): Promise<FilterResultType<<Name>Entity>> {\n // ... pagination and search logic\n }\n\n public async findOne(id: string): Promise<<Name>Entity | null> { ... }\n public async findOneBy(criteria: FindOptionsWhere<<Name>Entity>): Promise<<Name>Entity | null> { ... }\n public async create(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async createMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async update(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async updateMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async delete(criteria: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<UpdateResult> { ... }\n public async count(criteria?: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<number> { ... }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/repositories/<Name>Repository.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep scaffolded tests for methods that remain in the repository (remove tests for methods that were removed)\n- Add tests for any custom domain-specific methods added to the repository\n- Add tests relevant to the specific repository behavior\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts\n```\n";var Xo="---\nname: make:seed\ndescription: Generate a new database seed file, then complete the generated code. Use when creating seed data for populating the database using @ooneex/seeds.\n---\n\n# Make Seed\n\nGenerate a new seed file using the `make:seed` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the seed file:\n\n```bash\nbunx @ooneex/cli@latest make:seed --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, the seed file is generated under `modules/<module>/src/seeds/` instead of `src/seeds/`. The command will:\n- Generate a seed file in `src/seeds/` (or `modules/<module>/src/seeds/` with `--module`)\n- Add a `seed:run` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated seed file in `src/seeds/` to understand the scaffolded code.\n\n### 3. Complete the seed\n\nEdit the generated seed file to implement:\n\n- Import the relevant entity classes\n- Create seed data with hardcoded nanoid values for `id` fields (generate via `bun -e \"import { random } from '@ooneex/utils'; console.log(random.nanoid())\"`)\n- Do NOT use sequential IDs like `\"item-1\"`, `\"item-2\"`\n- Ensure the same entity uses the same ID everywhere it appears\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/seeds/\n```\n";var Jo="---\nname: make:service\ndescription: Generate a new service class with its test file, then complete the generated code. Use when creating a new business logic service that implements IService from @ooneex/service.\n---\n\n# Make Service Class\n\nGenerate a new service class and its test file using the `make:service` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the service class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:service --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/services/<Name>Service.ts` - The service class file (or `modules/<module>/src/services/<Name>Service.ts` with `--module`)\n- `tests/services/<Name>Service.spec.ts` - The test file (or `modules/<module>/tests/services/<Name>Service.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the service class\n\nEdit `src/services/<Name>Service.ts` to complete the implementation:\n\n- Define a proper type for `ServiceDataType` instead of `Record<string, unknown>`\n- Implement the `execute()` method with actual business logic\n- Inject any required dependencies (repositories, other services, etc.) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/service\";\nimport type { IService } from \"@ooneex/service\";\n\ntype ServiceDataType = Record<string, unknown>;\n\n@decorator.service()\nexport class <Name>Service<T extends ServiceDataType = ServiceDataType> implements IService<T> {\n public async execute(data?: T): Promise<void> {\n // TODO: Implement service logic\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/services/<Name>Service.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, execute method)\n- Add tests relevant to the specific service behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Service } from \"@/services/<Name>Service\";\n\ndescribe(\"<Name>Service\", () => {\n test(\"should have class name ending with 'Service'\", () => {\n expect(<Name>Service.name.endsWith(\"Service\")).toBe(true);\n });\n\n test(\"should have 'execute' method\", () => {\n expect(<Name>Service.prototype.execute).toBeDefined();\n expect(typeof <Name>Service.prototype.execute).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/services/<Name>Service.ts tests/services/<Name>Service.spec.ts\n```\n";var jo="---\nname: make:storage\ndescription: Generate a new storage class with its test file, then complete the generated code. Use when creating a new S3-compatible storage adapter that extends Storage from @ooneex/storage.\n---\n\n# Make Storage Class\n\nGenerate a new storage class and its test file using the `make:storage` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the storage class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:storage --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/storage/<Name>Storage.ts` - The storage class file (or `modules/<module>/src/storage/<Name>Storage.ts` with `--module`)\n- `tests/storage/<Name>Storage.spec.ts` - The test file (or `modules/<module>/tests/storage/<Name>Storage.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the storage class\n\nEdit `src/storage/<Name>Storage.ts` to complete the implementation:\n\n- Set the `bucket` property to the appropriate bucket name\n- Verify the environment variable names match the project configuration (`STORAGE_<NAME_UPPER>_ACCESS_KEY`, `STORAGE_<NAME_UPPER>_SECRET_KEY`, `STORAGE_<NAME_UPPER>_ENDPOINT`, `STORAGE_<NAME_UPPER>_REGION`)\n- Add any additional storage-specific methods if needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { Storage, decorator, StorageException } from \"@ooneex/storage\";\nimport type { S3Options } from \"bun\";\n\n@decorator.storage()\nexport class <Name>Storage extends Storage {\n protected bucket: string;\n private readonly accessKey: string;\n private readonly secretKey: string;\n private readonly endpoint: string;\n private readonly region: string;\n\n constructor(options?: {\n accessKey?: string;\n secretKey?: string;\n endpoint?: string;\n region?: string;\n }) {\n super();\n\n const accessKey = options?.accessKey || Bun.env.STORAGE_<NAME_UPPER>_ACCESS_KEY;\n const secretKey = options?.secretKey || Bun.env.STORAGE_<NAME_UPPER>_SECRET_KEY;\n const endpoint = options?.endpoint || Bun.env.STORAGE_<NAME_UPPER>_ENDPOINT;\n\n // ... validation throws StorageException if missing ...\n\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = endpoint;\n this.region = options?.region || Bun.env.STORAGE_<NAME_UPPER>_REGION || \"auto\";\n }\n\n public getOptions(): S3Options {\n return {\n accessKeyId: this.accessKey,\n secretAccessKey: this.secretKey,\n endpoint: this.endpoint,\n bucket: this.bucket,\n region: this.region,\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/storage/<Name>Storage.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, bucket field, getOptions method)\n- Add tests relevant to the specific storage class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>StorageAdapter } from \"@/storage/<Name>StorageAdapter\";\n\ndescribe(\"<Name>StorageAdapter\", () => {\n test(\"should have class name ending with 'StorageAdapter'\", () => {\n expect(<Name>StorageAdapter.name.endsWith(\"StorageAdapter\")).toBe(true);\n });\n\n test(\"should have 'bucket' field\", () => {\n expect(\"bucket\" in <Name>StorageAdapter.prototype || \"bucket\" in Object.getOwnPropertyNames(<Name>StorageAdapter.prototype)).toBe(true);\n });\n\n test(\"should have 'getOptions' method\", () => {\n expect(<Name>StorageAdapter.prototype.getOptions).toBeDefined();\n expect(typeof <Name>StorageAdapter.prototype.getOptions).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/storage/<Name>Storage.ts tests/storage/<Name>Storage.spec.ts\n```\n";var ei="---\nname: make:vector-database\ndescription: Generate a new vector database class with its test file, then complete the generated code. Use when creating a new vector database that extends VectorDatabase from @ooneex/rag.\n---\n\n# Make Vector Database Class\n\nGenerate a new vector database class and its test file using the `make:vector-database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the vector database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:vector-database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>VectorDatabase.ts` - The vector database class file (or `modules/<module>/src/databases/<Name>VectorDatabase.ts` with `--module`)\n- `tests/databases/<Name>VectorDatabase.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>VectorDatabase.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the vector database class\n\nEdit `src/databases/<Name>VectorDatabase.ts` to complete the implementation:\n\n- Set the `getDatabaseUri()` return value to the actual LanceDB database path\n- Configure the embedding provider and model in `getEmbeddingModel()`\n- Define the custom data fields in `DataType` and map them in `getSchema()`\n- Import the appropriate Apache Arrow types for your schema fields\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { VectorDatabase, decorator } from \"@ooneex/rag\";\nimport type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from \"@ooneex/rag\";\nimport { Utf8 } from \"apache-arrow\";\n\ntype DataType = {\n name: string;\n};\n\n@decorator.vectorDatabase()\nexport class <Name>VectorDatabase extends VectorDatabase<DataType> {\n public getDatabaseUri(): string {\n return \"\";\n }\n\n public getEmbeddingModel(): { provider: EmbeddingProviderType; model: EmbeddingModelType[\"model\"] } {\n return { provider: \"openai\", model: \"text-embedding-ada-002\" };\n }\n\n public getSchema(): { [K in keyof DataType]: FieldValueType } {\n return {\n name: new Utf8(),\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>VectorDatabase.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getDatabaseUri, getEmbeddingModel, getSchema methods)\n- Add tests relevant to the specific vector database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>VectorDatabase } from \"@/databases/<Name>VectorDatabase\";\n\ndescribe(\"<Name>VectorDatabase\", () => {\n test(\"should have class name ending with 'VectorDatabase'\", () => {\n expect(<Name>VectorDatabase.name.endsWith(\"VectorDatabase\")).toBe(true);\n });\n\n test(\"should have 'getDatabaseUri' method\", () => {\n expect(<Name>VectorDatabase.prototype.getDatabaseUri).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getDatabaseUri).toBe(\"function\");\n });\n\n test(\"should have 'getEmbeddingModel' method\", () => {\n expect(<Name>VectorDatabase.prototype.getEmbeddingModel).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getEmbeddingModel).toBe(\"function\");\n });\n\n test(\"should have 'getSchema' method\", () => {\n expect(<Name>VectorDatabase.prototype.getSchema).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getSchema).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>VectorDatabase.ts tests/databases/<Name>VectorDatabase.spec.ts\n```\n";var ti="---\nname: optimize\ndescription: Optimize a module's codebase for quality, performance, and clean conventions. Enforces arrow functions (except class methods), type/interface naming, removes duplication, and ensures only important tests remain.\n---\n\n# Optimize Codebase\n\nOptimize a module's codebase for quality, performance, and clean conventions.\n\n## Coding Conventions\n\nApply these conventions across all files in the target module:\n\n- **Arrow functions everywhere** \u2014 use arrow functions for all function expressions, callbacks, standalone functions, and variable declarations. The ONLY exception is class methods, which must use regular method syntax.\n- **Type naming** \u2014 all type aliases must end with the `Type` suffix (e.g., `UserDataType`, `ConfigOptionsType`). Rename any that don't comply.\n- **Interface naming** \u2014 all interface names must start with the `I` prefix (e.g., `IUser`, `IService`, `IRepository`). Rename any that don't comply.\n- **No definite assignment assertions** \u2014 never use `!` on class properties (e.g., `email!: string`). Use a default value or make the property optional (`?`) instead.\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`).\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Identify the target\n\nDetermine the module to optimize. If the user specifies a module name, work in `modules/<module>/`. If no module is specified, ask the user which module to optimize.\n\n### 2. Read and analyze the module\n\nRead all source files (`src/**/*.ts`) and test files (`tests/**/*.ts`) in the target module. Build a full picture of:\n\n- All types, interfaces, classes, and functions\n- Dependencies between files\n- Existing test coverage\n\n### 3. Enforce naming conventions\n\nScan every file and fix:\n\n- **Types not ending with `Type`** \u2014 rename the type and update all references across the module\n- **Interfaces not starting with `I`** \u2014 rename the interface and update all references across the module\n- **Non-arrow functions** \u2014 convert all function expressions, callbacks, and standalone functions to arrow functions. Do NOT convert class methods.\n- **Missing visibility modifiers** \u2014 add explicit `public`, `private`, or `protected` to all class methods and properties\n\n### 4. Remove code duplication\n\nIdentify duplicated or near-duplicated code within the module:\n\n- Extract shared logic into well-named helper arrow functions or base classes\n- Consolidate repeated type definitions\n- Merge similar utility functions\n- Remove dead code (unused imports, unreachable branches, unused variables)\n\n### 5. Optimize for performance\n\nReview and improve:\n\n- Replace inefficient loops or repeated iterations with single-pass approaches where possible\n- Use `Map`/`Set` instead of arrays for lookups when appropriate\n- Avoid unnecessary object spreads or deep clones\n- Prefer early returns to reduce nesting\n- Remove unnecessary `async`/`await` where a direct return suffices\n- Eliminate redundant null/undefined checks when the type system already guarantees the value\n\n### 6. Optimize tests\n\nReview all test files and restructure:\n\n- **Remove trivial tests** \u2014 delete tests that only check obvious things (e.g., \"class name ends with X\", \"method exists\") unless they serve as smoke tests for generated code\n- **Keep and improve important tests** \u2014 focus on tests that verify actual business logic, edge cases, error handling, and integration behavior\n- **Write fewer but more meaningful tests** \u2014 each test should validate a real scenario or invariant, not just existence checks\n- **Consolidate redundant test cases** \u2014 merge tests that cover the same code path with slightly different inputs into parameterized patterns\n- **Ensure critical paths are covered** \u2014 every public method with logic should have at least one test covering its happy path and one covering its error/edge case\n\n### 7. Final cleanup\n\n- Remove all unused imports\n- Remove empty files or files with no exports\n- Ensure consistent formatting\n\n### 8. Lint and format\n\nRun linting and formatting on all modified files:\n\n```bash\nbunx biome check --fix <list of modified files>\n```\n\n### 9. Run tests\n\nRun the module's tests to verify nothing is broken:\n\n```bash\nbun test <module test directory>\n```\n\nIf any test fails, fix the issue and re-run until all tests pass.\n";var Vl={"make.ai":Uo,"make.analytics":Go,"make.cache":ko,"make.controller":$o,"make.cron":qo,"make.database":Wo,"make.entity":Ko,"make.logger":Fo,"make.mailer":Ho,"make.middleware":Vo,"make.migration":Yo,"make.permission":zo,"make.pubsub":Zo,"make.repository":Qo,"make.seed":Xo,"make.service":Jo,"make.storage":jo,"make.vector-database":ei,commit:Lo,optimize:ti};class qe{getName(){return"make:claude:skill"}getDescription(){return"Generate Claude skills from templates"}async run(){let e=$e(".claude","skills"),t=$e(process.cwd(),e),s=new Hl;for(let[r,o]of Object.entries(Vl)){let i=r.replace(/\./g,"-"),a=$e(t,i,"SKILL.md");await Bun.write(a,o),s.success(`${$e(e,i,"SKILL.md")} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}}qe=b([w.command()],qe);import{basename as Zl,join as G}from"path";import{TerminalLogger as Ql}from"@ooneex/logger";import{toPascalCase as Pt}from"@ooneex/utils";var si=`import { describe, expect, test } from "bun:test";
|
|
1898
1819
|
import { {{NAME}}Cron } from "@/cron/{{NAME}}Cron";
|
|
1899
1820
|
|
|
1900
1821
|
describe("{{NAME}}Cron", () => {
|
|
@@ -1917,7 +1838,7 @@ describe("{{NAME}}Cron", () => {
|
|
|
1917
1838
|
expect(typeof {{NAME}}Cron.prototype.handler).toBe("function");
|
|
1918
1839
|
});
|
|
1919
1840
|
});
|
|
1920
|
-
`;var
|
|
1841
|
+
`;var ri=`import type { TimeZoneType } from "@ooneex/country";
|
|
1921
1842
|
import type { CronTimeType } from "@ooneex/cron";
|
|
1922
1843
|
import { Cron, decorator } from "@ooneex/cron";
|
|
1923
1844
|
|
|
@@ -1938,9 +1859,9 @@ export class {{NAME}}Cron extends Cron {
|
|
|
1938
1859
|
// console.log("{{NAME}}Cron handler executed");
|
|
1939
1860
|
}
|
|
1940
1861
|
}
|
|
1941
|
-
`;class
|
|
1862
|
+
`;class We{getName(){return"make:cron"}getDescription(){return"Generate a new cron class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Cron`,o=`import { ${r} } from "./cron/${r}";
|
|
1942
1863
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
1943
|
-
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(cronJobs:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),
|
|
1864
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(cronJobs:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),p=l?`${l}, ${r}`:r;s=s.replace(n,`$1${p}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter cron name"});t=Pt(t).replace(/Cron$/,"");let r=ri.replace(/{{NAME}}/g,t),o=s?G("modules",s):".",i=G(o,"src","cron"),a=G(process.cwd(),i),n=G(a,`${t}Cron.ts`);await Bun.write(n,r);let d=si.replace(/{{NAME}}/g,t),l=G(o,"tests","cron"),p=G(process.cwd(),l),u=G(p,`${t}Cron.spec.ts`);await Bun.write(u,d);let m=s?Pt(s):Pt(Zl(process.cwd())),c=G(process.cwd(),o,"src",`${m}Module.ts`);if(await Bun.file(c).exists())await this.addToModule(c,t);let h=new Ql;h.success(`${G(i,t)}Cron.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),h.success(`${G(l,t)}Cron.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/cron"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}We=b([w.command()],We);import{join as Y}from"path";import{TerminalLogger as jl}from"@ooneex/logger";import{toPascalCase as ec}from"@ooneex/utils";var oi=`import { describe, expect, test } from "bun:test";
|
|
1944
1865
|
import { {{NAME}}Database } from "@/databases/{{NAME}}Database";
|
|
1945
1866
|
|
|
1946
1867
|
describe("{{NAME}}Database", () => {
|
|
@@ -1953,7 +1874,7 @@ describe("{{NAME}}Database", () => {
|
|
|
1953
1874
|
expect(typeof {{NAME}}Database.prototype.getSource).toBe("function");
|
|
1954
1875
|
});
|
|
1955
1876
|
});
|
|
1956
|
-
`;var
|
|
1877
|
+
`;var ii=`import { DataSource } from "typeorm";
|
|
1957
1878
|
import { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";
|
|
1958
1879
|
|
|
1959
1880
|
@decorator.database()
|
|
@@ -1976,7 +1897,7 @@ export class {{NAME}}Database extends TypeormDatabase {
|
|
|
1976
1897
|
return this.source;
|
|
1977
1898
|
}
|
|
1978
1899
|
}
|
|
1979
|
-
`;class
|
|
1900
|
+
`;class Ke{getName(){return"make:database"}getDescription(){return"Generate a new database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter database name"});t=ec(t).replace(/DatabaseAdapter$/,"").replace(/Database$/,"");let r=ii.replace(/{{NAME}}/g,t),o=s?Y("modules",s):".",i=Y(o,"src","databases"),a=Y(process.cwd(),i),n=Y(a,`${t}Database.ts`);await Bun.write(n,r);let d=oi.replace(/{{NAME}}/g,t),l=Y(o,"tests","databases"),p=Y(process.cwd(),l),u=Y(p,`${t}Database.spec.ts`);await Bun.write(u,d);let m=new jl;m.success(`${Y(i,t)}Database.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${Y(l,t)}Database.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/database"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ke=b([w.command()],Ke);import{join as Ci}from"path";import{TerminalLogger as xc}from"@ooneex/logger";var{YAML:_i}=globalThis.Bun;var ni=ee(ie(),1),ai=["clickhouse","elasticsearch","grafana","jaeger","keycloak","libretranslate","maildev","memcached","minio","mongodb","mysql","nats","postgres","prometheus","rabbitmq","redis","temporal","vault"],di=async(e)=>{return(await ni.prompt({type:"autocomplete",name:"service",message:e.message,initial:e.initial,choices:ai.map((s)=>s),validate:(s)=>{if(!ai.includes(s))return"Docker service is invalid";return!0}})).service};var li=`services:
|
|
1980
1901
|
# ClickHouse - Column-oriented OLAP database for analytics
|
|
1981
1902
|
# Docs: https://clickhouse.com/docs
|
|
1982
1903
|
# HTTP API: http://localhost:8123
|
|
@@ -1997,7 +1918,7 @@ export class {{NAME}}Database extends TypeormDatabase {
|
|
|
1997
1918
|
|
|
1998
1919
|
volumes:
|
|
1999
1920
|
clickhouse_data:
|
|
2000
|
-
`;var
|
|
1921
|
+
`;var ci=`services:
|
|
2001
1922
|
# Elasticsearch - Full-text search and analytics engine
|
|
2002
1923
|
# Docs: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
|
|
2003
1924
|
# HTTP API: http://localhost:9200
|
|
@@ -2018,7 +1939,7 @@ volumes:
|
|
|
2018
1939
|
|
|
2019
1940
|
volumes:
|
|
2020
1941
|
elasticsearch_data:
|
|
2021
|
-
`;var
|
|
1942
|
+
`;var pi=`services:
|
|
2022
1943
|
# Grafana - Metrics visualization and dashboards
|
|
2023
1944
|
# Docs: https://grafana.com/docs/grafana/latest/
|
|
2024
1945
|
# Web UI: http://localhost:3000 (ooneex/ooneex)
|
|
@@ -2036,7 +1957,7 @@ volumes:
|
|
|
2036
1957
|
|
|
2037
1958
|
volumes:
|
|
2038
1959
|
grafana_data:
|
|
2039
|
-
`;var
|
|
1960
|
+
`;var mi=`services:
|
|
2040
1961
|
# Jaeger - Distributed tracing system
|
|
2041
1962
|
# Docs: https://www.jaegertracing.io/docs/
|
|
2042
1963
|
# Web UI: http://localhost:16686
|
|
@@ -2050,7 +1971,7 @@ volumes:
|
|
|
2050
1971
|
- "16686:16686"
|
|
2051
1972
|
- "6831:6831/udp"
|
|
2052
1973
|
- "14268:14268"
|
|
2053
|
-
`;var
|
|
1974
|
+
`;var ui=`services:
|
|
2054
1975
|
# Keycloak - Identity and access management
|
|
2055
1976
|
# Docs: https://www.keycloak.org/documentation
|
|
2056
1977
|
# Admin Console: http://localhost:8080 (ooneex/ooneex)
|
|
@@ -2064,7 +1985,7 @@ volumes:
|
|
|
2064
1985
|
- KEYCLOAK_ADMIN=ooneex
|
|
2065
1986
|
- KEYCLOAK_ADMIN_PASSWORD=ooneex
|
|
2066
1987
|
command: start-dev
|
|
2067
|
-
`;var
|
|
1988
|
+
`;var hi=`services:
|
|
2068
1989
|
# LibreTranslate - Self-hosted machine translation API
|
|
2069
1990
|
# Docs: https://libretranslate.com/docs/
|
|
2070
1991
|
# API: http://localhost:4000
|
|
@@ -2091,7 +2012,7 @@ volumes:
|
|
|
2091
2012
|
|
|
2092
2013
|
volumes:
|
|
2093
2014
|
libretranslate_models:
|
|
2094
|
-
`;var
|
|
2015
|
+
`;var fi=`services:
|
|
2095
2016
|
# MailDev - Email testing tool with web UI
|
|
2096
2017
|
# Docs: https://github.com/maildev/maildev
|
|
2097
2018
|
# Web UI: http://localhost:1080
|
|
@@ -2102,7 +2023,7 @@ volumes:
|
|
|
2102
2023
|
ports:
|
|
2103
2024
|
- "1080:1080"
|
|
2104
2025
|
- "1025:1025"
|
|
2105
|
-
`;var
|
|
2026
|
+
`;var yi=`services:
|
|
2106
2027
|
# Memcached - Distributed memory caching system
|
|
2107
2028
|
# Docs: https://memcached.org/
|
|
2108
2029
|
# Connection: localhost:11211
|
|
@@ -2112,7 +2033,7 @@ volumes:
|
|
|
2112
2033
|
restart: "on-failure"
|
|
2113
2034
|
ports:
|
|
2114
2035
|
- "11211:11211"
|
|
2115
|
-
`;var
|
|
2036
|
+
`;var gi=`services:
|
|
2116
2037
|
# MinIO - S3-compatible object storage
|
|
2117
2038
|
# Docs: https://min.io/docs/minio/container/index.html
|
|
2118
2039
|
# API: http://localhost:9000
|
|
@@ -2133,7 +2054,7 @@ volumes:
|
|
|
2133
2054
|
|
|
2134
2055
|
volumes:
|
|
2135
2056
|
minio_data:
|
|
2136
|
-
`;var
|
|
2057
|
+
`;var bi=`services:
|
|
2137
2058
|
# MongoDB - NoSQL document database
|
|
2138
2059
|
# Docs: https://www.mongodb.com/docs/
|
|
2139
2060
|
# Connection: mongodb://ooneex:ooneex@localhost:27017/ooneex
|
|
@@ -2152,7 +2073,7 @@ volumes:
|
|
|
2152
2073
|
|
|
2153
2074
|
volumes:
|
|
2154
2075
|
mongodb_data:
|
|
2155
|
-
`;var
|
|
2076
|
+
`;var wi=`services:
|
|
2156
2077
|
# MySQL - Alternative relational database
|
|
2157
2078
|
# Docs: https://dev.mysql.com/doc/
|
|
2158
2079
|
# Connection: mysql://ooneex:ooneex@localhost:3306/ooneex
|
|
@@ -2172,7 +2093,7 @@ volumes:
|
|
|
2172
2093
|
|
|
2173
2094
|
volumes:
|
|
2174
2095
|
mysql_db:
|
|
2175
|
-
`;var
|
|
2096
|
+
`;var xi=`services:
|
|
2176
2097
|
# NATS - High-performance messaging system with JetStream
|
|
2177
2098
|
# Docs: https://docs.nats.io/
|
|
2178
2099
|
# Client: localhost:4222
|
|
@@ -2185,7 +2106,7 @@ volumes:
|
|
|
2185
2106
|
- "4222:4222"
|
|
2186
2107
|
- "8222:8222"
|
|
2187
2108
|
command: "--jetstream --http_port 8222"
|
|
2188
|
-
`;var
|
|
2109
|
+
`;var Ei=`services:
|
|
2189
2110
|
# Jade - FastAPI REST API to fetch YouTube metadata and download videos or audio via Dockerized microservice.
|
|
2190
2111
|
# API: http://localhost:8000
|
|
2191
2112
|
# Docs: http://localhost:8000/docs
|
|
@@ -2203,7 +2124,7 @@ volumes:
|
|
|
2203
2124
|
|
|
2204
2125
|
volumes:
|
|
2205
2126
|
jade_data:
|
|
2206
|
-
`;var
|
|
2127
|
+
`;var Ai=`services:
|
|
2207
2128
|
# PostgreSQL - Primary relational database
|
|
2208
2129
|
# Docs: https://www.postgresql.org/docs/
|
|
2209
2130
|
# Connection: postgresql://ooneex:ooneex@localhost:5432/ooneex
|
|
@@ -2224,7 +2145,7 @@ volumes:
|
|
|
2224
2145
|
|
|
2225
2146
|
volumes:
|
|
2226
2147
|
postgres_db:
|
|
2227
|
-
`;var
|
|
2148
|
+
`;var vi=`services:
|
|
2228
2149
|
# Prometheus - Metrics collection and monitoring
|
|
2229
2150
|
# Docs: https://prometheus.io/docs/
|
|
2230
2151
|
# Web UI: http://localhost:9090
|
|
@@ -2239,7 +2160,7 @@ volumes:
|
|
|
2239
2160
|
|
|
2240
2161
|
volumes:
|
|
2241
2162
|
prometheus_data:
|
|
2242
|
-
`;var
|
|
2163
|
+
`;var Ni=`services:
|
|
2243
2164
|
# RabbitMQ - Message broker for async processing
|
|
2244
2165
|
# Docs: https://www.rabbitmq.com/docs
|
|
2245
2166
|
# AMQP: amqp://ooneex:ooneex@localhost:5672/ooneex
|
|
@@ -2261,7 +2182,7 @@ volumes:
|
|
|
2261
2182
|
|
|
2262
2183
|
volumes:
|
|
2263
2184
|
rabbitmq_data:
|
|
2264
|
-
`;var
|
|
2185
|
+
`;var Si=`services:
|
|
2265
2186
|
# Redis - In-memory data store for caching and sessions
|
|
2266
2187
|
# Docs: https://redis.io/docs/
|
|
2267
2188
|
# Connection: redis://localhost:6379
|
|
@@ -2276,7 +2197,7 @@ volumes:
|
|
|
2276
2197
|
|
|
2277
2198
|
volumes:
|
|
2278
2199
|
redis_data:
|
|
2279
|
-
`;var
|
|
2200
|
+
`;var Ti=`services:
|
|
2280
2201
|
# Temporal - Workflow orchestration engine
|
|
2281
2202
|
# Docs: https://docs.temporal.io/
|
|
2282
2203
|
# gRPC: localhost:7233
|
|
@@ -2293,7 +2214,7 @@ volumes:
|
|
|
2293
2214
|
- POSTGRES_USER=ooneex
|
|
2294
2215
|
- POSTGRES_PWD=ooneex
|
|
2295
2216
|
- POSTGRES_SEEDS=postgres
|
|
2296
|
-
`;var
|
|
2217
|
+
`;var Ri=`services:
|
|
2297
2218
|
# Vault - Secrets management and encryption
|
|
2298
2219
|
# Docs: https://developer.hashicorp.com/vault/docs
|
|
2299
2220
|
# Web UI: http://localhost:8200 (token: ooneex)
|
|
@@ -2308,20 +2229,20 @@ volumes:
|
|
|
2308
2229
|
- VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200
|
|
2309
2230
|
cap_add:
|
|
2310
2231
|
- IPC_LOCK
|
|
2311
|
-
`;var
|
|
2232
|
+
`;var Mi={clickhouse:li,elasticsearch:ci,grafana:pi,"ooneex-jade":Ei,jaeger:mi,keycloak:ui,libretranslate:hi,maildev:fi,memcached:yi,minio:gi,mongodb:bi,mysql:wi,nats:xi,postgres:Ai,prometheus:vi,rabbitmq:Ni,redis:Si,temporal:Ti,vault:Ri};function Ec(e){let t=e.split(`
|
|
2312
2233
|
`),s=[],r=!1;for(let o of t){if(o.startsWith("services:")){r=!0;continue}if(r){if(o.startsWith("volumes:")||o.startsWith("networks:"))break;s.push(o)}}return s.join(`
|
|
2313
|
-
`)}function
|
|
2314
|
-
volumes:`),h=
|
|
2315
|
-
networks:`),f=-1;if(
|
|
2316
|
-
${
|
|
2317
|
-
${
|
|
2318
|
-
volumes:`)){let y=
|
|
2319
|
-
volumes:`),E=
|
|
2320
|
-
${g}:${E}`}else
|
|
2234
|
+
`)}function Ac(e){let t=_i.parse(e);return t.volumes?Object.keys(t.volumes):[]}class Fe{getName(){return"make:docker"}getDescription(){return"Add a docker service to docker-compose.yml"}async run(e){let{name:t}=e;if(!t)t=await di({message:"Select docker service"});let s=Mi[t],r=Ci(process.cwd(),"docker-compose.yml"),o=new xc,i=Bun.file(r);if(await i.exists()){let d=await i.text(),l=_i.parse(d);if(l.services&&t in l.services){o.warn(`Service "${t}" already exists in docker-compose.yml`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});return}let p=Ec(s),u=Ac(s),m=d,c=m.indexOf(`
|
|
2235
|
+
volumes:`),h=m.indexOf(`
|
|
2236
|
+
networks:`),f=-1;if(c!==-1&&h!==-1)f=Math.min(c,h);else if(c!==-1)f=c;else if(h!==-1)f=h;if(f!==-1)m=`${m.slice(0,f)}
|
|
2237
|
+
${p}${m.slice(f)}`;else m=`${m.trimEnd()}
|
|
2238
|
+
${p}`;for(let g of u)if(!m.includes(` ${g}:`))if(m.includes(`
|
|
2239
|
+
volumes:`)){let y=m.indexOf(`
|
|
2240
|
+
volumes:`),E=m.slice(y+9);m=`${m.slice(0,y+9)}
|
|
2241
|
+
${g}:${E}`}else m=`${m.trimEnd()}
|
|
2321
2242
|
|
|
2322
2243
|
volumes:
|
|
2323
2244
|
${g}:
|
|
2324
|
-
`;await Bun.write(r,
|
|
2245
|
+
`;await Bun.write(r,m)}else await Bun.write(r,s);let a=Ci(process.cwd(),"package.json"),n=Bun.file(a);if(await n.exists()){let d=await n.json();d.scripts=d.scripts||{},d.scripts.docker="docker compose up -d",await Bun.write(a,JSON.stringify(d,null,2))}o.success(`Service "${t}" added to docker-compose.yml`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),o.info("Run 'bun run docker' to start docker containers",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1})}}Fe=b([w.command()],Fe);var Bi=ee(Ii(),1);import{basename as Sc,join as k}from"path";import{TerminalLogger as Tc}from"@ooneex/logger";import{toPascalCase as Gt,toSnakeCase as Rc}from"@ooneex/utils";var Oi=`import { describe, expect, test } from "bun:test";
|
|
2325
2246
|
import { {{NAME}}Entity } from "@/entities/{{NAME}}Entity";
|
|
2326
2247
|
|
|
2327
2248
|
describe("{{NAME}}Entity", () => {
|
|
@@ -2386,16 +2307,16 @@ describe("{{NAME}}Entity", () => {
|
|
|
2386
2307
|
expect("deletedAt" in entity).toBe(true);
|
|
2387
2308
|
});
|
|
2388
2309
|
});
|
|
2389
|
-
`;var
|
|
2310
|
+
`;var Di=`import type { LocaleType } from "@ooneex/translation";
|
|
2390
2311
|
import { random } from "@ooneex/utils";
|
|
2391
|
-
import { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from "typeorm";
|
|
2312
|
+
import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryColumn, UpdateDateColumn } from "typeorm";
|
|
2392
2313
|
|
|
2393
2314
|
@Entity({
|
|
2394
2315
|
name: "{{TABLE_NAME}}",
|
|
2395
2316
|
})
|
|
2396
|
-
export class {{NAME}}Entity
|
|
2397
|
-
@PrimaryColumn({ name: "id", type: "varchar", length:
|
|
2398
|
-
id: string = random.
|
|
2317
|
+
export class {{NAME}}Entity {
|
|
2318
|
+
@PrimaryColumn({ name: "id", type: "varchar", length: 20 })
|
|
2319
|
+
id: string = random.id();
|
|
2399
2320
|
|
|
2400
2321
|
@Column({
|
|
2401
2322
|
name: "is_locked",
|
|
@@ -2437,9 +2358,9 @@ export class {{NAME}}Entity extends BaseEntity {
|
|
|
2437
2358
|
@DeleteDateColumn({ name: "deleted_at" })
|
|
2438
2359
|
deletedAt?: Date;
|
|
2439
2360
|
}
|
|
2440
|
-
`;class
|
|
2361
|
+
`;class He{getName(){return"make:entity"}getDescription(){return"Generate a new entity class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Entity`,o=`import { ${r} } from "./entities/${r}";
|
|
2441
2362
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
2442
|
-
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(entities:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),
|
|
2363
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(entities:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),p=l?`${l}, ${r}`:r;s=s.replace(n,`$1${p}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,tableName:r}=e;if(!t)t=await v({message:"Enter entity name"});if(t=Gt(t).replace(/Entity$/,""),!r)r=Rc(Bi.default(t));let o=Di.replace(/{{NAME}}/g,t).replace(/{{TABLE_NAME}}/g,r),i=s?k("modules",s):".",a=k(i,"src","entities"),n=k(process.cwd(),a),d=k(n,`${t}Entity.ts`);await Bun.write(d,o);let l=Oi.replace(/{{NAME}}/g,t),p=k(i,"tests","entities"),u=k(process.cwd(),p),m=k(u,`${t}Entity.spec.ts`);await Bun.write(m,l);let c=s?Gt(s):Gt(Sc(process.cwd())),h=k(process.cwd(),i,"src",`${c}Module.ts`);if(await Bun.file(h).exists())await this.addToModule(h,t);let f=new Tc;f.success(`${k(a,t)}Entity.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),f.success(`${k(p,t)}Entity.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}He=b([w.command()],He);import{join as z}from"path";import{TerminalLogger as _c}from"@ooneex/logger";import{toPascalCase as Ic}from"@ooneex/utils";var Pi=`import { describe, expect, test } from "bun:test";
|
|
2443
2364
|
import { {{NAME}}Logger } from "@/loggers/{{NAME}}Logger";
|
|
2444
2365
|
|
|
2445
2366
|
describe("{{NAME}}Logger", () => {
|
|
@@ -2482,7 +2403,7 @@ describe("{{NAME}}Logger", () => {
|
|
|
2482
2403
|
expect(typeof {{NAME}}Logger.prototype.error).toBe("function");
|
|
2483
2404
|
});
|
|
2484
2405
|
});
|
|
2485
|
-
`;var
|
|
2406
|
+
`;var Li=`import type { IException } from "@ooneex/exception";
|
|
2486
2407
|
import type { ILogger } from "@ooneex/logger";
|
|
2487
2408
|
import type { ScalarType } from "@ooneex/types";
|
|
2488
2409
|
import { decorator } from "@ooneex/logger";
|
|
@@ -2517,7 +2438,7 @@ export class {{NAME}}Logger implements ILogger {
|
|
|
2517
2438
|
// Handle error logging
|
|
2518
2439
|
}
|
|
2519
2440
|
}
|
|
2520
|
-
`;class
|
|
2441
|
+
`;class Ve{getName(){return"make:logger"}getDescription(){return"Generate a new logger class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter logger name"});t=Ic(t).replace(/Logger$/,"");let r=Li.replace(/{{NAME}}/g,t),o=s?z("modules",s):".",i=z(o,"src","loggers"),a=z(process.cwd(),i),n=z(a,`${t}Logger.ts`);await Bun.write(n,r);let d=Pi.replace(/{{NAME}}/g,t),l=z(o,"tests","loggers"),p=z(process.cwd(),l),u=z(p,`${t}Logger.spec.ts`);await Bun.write(u,d);let m=new _c;m.success(`${z(i,t)}Logger.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${z(l,t)}Logger.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/logger"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ve=b([w.command()],Ve);import{join as I}from"path";import{TerminalLogger as Lc}from"@ooneex/logger";import{toPascalCase as Uc}from"@ooneex/utils";var Ui=`import { describe, expect, test } from "bun:test";
|
|
2521
2442
|
import { {{NAME}}Mailer } from "@/mailers/{{NAME}}Mailer";
|
|
2522
2443
|
|
|
2523
2444
|
describe("{{NAME}}Mailer", () => {
|
|
@@ -2530,7 +2451,7 @@ describe("{{NAME}}Mailer", () => {
|
|
|
2530
2451
|
expect(typeof {{NAME}}Mailer.prototype.send).toBe("function");
|
|
2531
2452
|
});
|
|
2532
2453
|
});
|
|
2533
|
-
`;var
|
|
2454
|
+
`;var Gi=`import { inject } from "@ooneex/container";
|
|
2534
2455
|
import type { IMailer } from "@ooneex/mailer";
|
|
2535
2456
|
import { type {{NAME}}MailerPropsType, {{NAME}}MailerTemplate } from "./{{NAME}}MailerTemplate";
|
|
2536
2457
|
|
|
@@ -2554,7 +2475,7 @@ export class {{NAME}}Mailer implements IMailer {
|
|
|
2554
2475
|
});
|
|
2555
2476
|
}
|
|
2556
2477
|
}
|
|
2557
|
-
`;var
|
|
2478
|
+
`;var ki=`import { describe, expect, test } from "bun:test";
|
|
2558
2479
|
import { {{NAME}}MailerTemplate } from "@/mailers/{{NAME}}MailerTemplate";
|
|
2559
2480
|
|
|
2560
2481
|
describe("{{NAME}}MailerTemplate", () => {
|
|
@@ -2566,7 +2487,7 @@ describe("{{NAME}}MailerTemplate", () => {
|
|
|
2566
2487
|
expect(typeof {{NAME}}MailerTemplate).toBe("function");
|
|
2567
2488
|
});
|
|
2568
2489
|
});
|
|
2569
|
-
`;var
|
|
2490
|
+
`;var $i=`import { MailerLayout } from "@ooneex/mailer";
|
|
2570
2491
|
|
|
2571
2492
|
export type {{NAME}}MailerPropsType = {
|
|
2572
2493
|
link: string;
|
|
@@ -2581,7 +2502,7 @@ export const {{NAME}}MailerTemplate = (props?: {{NAME}}MailerPropsType) => (
|
|
|
2581
2502
|
<MailerLayout.Footer />
|
|
2582
2503
|
</MailerLayout>
|
|
2583
2504
|
);
|
|
2584
|
-
`;class
|
|
2505
|
+
`;class Ye{getName(){return"make:mailer"}getDescription(){return"Generate a new mailer class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter mailer name"});t=Uc(t).replace(/Mailer$/,"");let r=Gi.replace(/{{NAME}}/g,t),o=$i.replace(/{{NAME}}/g,t),i=s?I("modules",s):".",a=I(i,"src","mailers"),n=I(process.cwd(),a),d=I(n,`${t}Mailer.ts`),l=I(n,`${t}MailerTemplate.tsx`);await Bun.write(d,r),await Bun.write(l,o);let p=Ui.replace(/{{NAME}}/g,t),u=ki.replace(/{{NAME}}/g,t),m=I(i,"tests","mailers"),c=I(process.cwd(),m),h=I(c,`${t}Mailer.spec.ts`),f=I(c,`${t}MailerTemplate.spec.ts`);await Bun.write(h,p),await Bun.write(f,u);let g=new Lc;g.success(`${I(a,t)}Mailer.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),g.success(`${I(a,t)}MailerTemplate.tsx created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),g.success(`${I(m,t)}Mailer.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),g.success(`${I(m,t)}MailerTemplate.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/mailer"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ye=b([w.command()],Ye);import{basename as qc,join as $}from"path";import{TerminalLogger as Wc}from"@ooneex/logger";import{toPascalCase as kt}from"@ooneex/utils";var qi=`import type { ContextType } from "@ooneex/socket";
|
|
2585
2506
|
import { decorator, type IMiddleware } from "@ooneex/middleware";
|
|
2586
2507
|
|
|
2587
2508
|
@decorator.middleware()
|
|
@@ -2593,7 +2514,7 @@ export class {{NAME}}Middleware implements IMiddleware {
|
|
|
2593
2514
|
return context
|
|
2594
2515
|
}
|
|
2595
2516
|
}
|
|
2596
|
-
`;var
|
|
2517
|
+
`;var Wi=`import { describe, expect, test } from "bun:test";
|
|
2597
2518
|
import { {{NAME}}Middleware } from "@/middlewares/{{NAME}}Middleware";
|
|
2598
2519
|
|
|
2599
2520
|
describe("{{NAME}}Middleware", () => {
|
|
@@ -2606,7 +2527,7 @@ describe("{{NAME}}Middleware", () => {
|
|
|
2606
2527
|
expect(typeof {{NAME}}Middleware.prototype.handler).toBe("function");
|
|
2607
2528
|
});
|
|
2608
2529
|
});
|
|
2609
|
-
`;var
|
|
2530
|
+
`;var Ki=`import type { ContextType } from "@ooneex/controller";
|
|
2610
2531
|
import { decorator, type IMiddleware } from "@ooneex/middleware";
|
|
2611
2532
|
|
|
2612
2533
|
@decorator.middleware()
|
|
@@ -2618,9 +2539,9 @@ export class {{NAME}}Middleware implements IMiddleware {
|
|
|
2618
2539
|
return context
|
|
2619
2540
|
}
|
|
2620
2541
|
}
|
|
2621
|
-
`;class
|
|
2542
|
+
`;class ze{getName(){return"make:middleware"}getDescription(){return"Generate a new middleware class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Middleware`,o=`import { ${r} } from "./middlewares/${r}";
|
|
2622
2543
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
2623
|
-
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(middlewares:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),
|
|
2544
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(middlewares:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),p=l?`${l}, ${r}`:r;s=s.replace(n,`$1${p}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:r}=e;if(!t)t=await v({message:"Enter middleware name"});if(r===void 0)r=await he({message:"Is this a socket middleware?"});t=kt(t).replace(/Middleware$/,"");let i=(r?qi:Ki).replace(/{{NAME}}/g,t),a=s?$("modules",s):".",n=$(a,"src","middlewares"),d=$(process.cwd(),n),l=$(d,`${t}Middleware.ts`);await Bun.write(l,i);let p=Wi.replace(/{{NAME}}/g,t),u=$(a,"tests","middlewares"),m=$(process.cwd(),u),c=$(m,`${t}Middleware.spec.ts`);await Bun.write(c,p);let h=s?kt(s):kt(qc(process.cwd())),f=$(process.cwd(),a,"src",`${h}Module.ts`);if(await Bun.file(f).exists())await this.addToModule(f,t);let g=new Wc;g.success(`${$(n,t)}Middleware.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),g.success(`${$(u,t)}Middleware.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/middleware"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}ze=b([w.command()],ze);import{join as Ze}from"path";import{TerminalLogger as Fc}from"@ooneex/logger";import{migrationCreate as Hc}from"@ooneex/migrations";var Fi=`#!/usr/bin/env bun
|
|
2624
2545
|
|
|
2625
2546
|
import { migrationUp } from "@ooneex/migrations";
|
|
2626
2547
|
import "@/migrations/migrations";
|
|
@@ -2629,7 +2550,7 @@ await migrationUp({
|
|
|
2629
2550
|
databaseUrl: Bun.env.DATABASE_URL || ":memory:",
|
|
2630
2551
|
tableName: "migrations",
|
|
2631
2552
|
});
|
|
2632
|
-
`;class
|
|
2553
|
+
`;class Qe{getName(){return"make:migration"}getDescription(){return"Generate a new migration file"}async run(e){let{module:t}=e,s=t?Ze("modules",t):".",r=await Hc({dir:Ze(s,"src/migrations")}),o=Ze(process.cwd(),s,"bin","migration","up.ts");if(!await Bun.file(o).exists())await Bun.write(o,Fi);let a=Ze(process.cwd(),"package.json"),n=Bun.file(a);if(await n.exists()){let p=await n.json();p.scripts=p.scripts||{},p.scripts["migration:up"]="bun ./bin/migration/up.ts",await Bun.write(a,JSON.stringify(p,null,2))}let d=new Fc;d.success(`${r} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),d.info("Run 'bun run migration:up' to execute migrations",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1}),await Bun.spawn(["bun","add","--dev","@ooneex/migrations"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Qe=b([w.command()],Qe);import{join as Z}from"path";import{TerminalLogger as zc}from"@ooneex/logger";import{toPascalCase as Zc}from"@ooneex/utils";var Hi=`import { describe, expect, test } from "bun:test";
|
|
2633
2554
|
import { Permission } from "@ooneex/permission";
|
|
2634
2555
|
import { {{NAME}}Permission } from "@/permissions/{{NAME}}Permission";
|
|
2635
2556
|
|
|
@@ -2654,7 +2575,7 @@ describe("{{NAME}}Permission", () => {
|
|
|
2654
2575
|
});
|
|
2655
2576
|
|
|
2656
2577
|
});
|
|
2657
|
-
`;var
|
|
2578
|
+
`;var Vi=`import { decorator, Permission } from "@ooneex/permission";
|
|
2658
2579
|
import type { IUser } from "@ooneex/user";
|
|
2659
2580
|
|
|
2660
2581
|
@decorator.permission()
|
|
@@ -2693,7 +2614,7 @@ export class {{NAME}}Permission extends Permission {
|
|
|
2693
2614
|
return this;
|
|
2694
2615
|
}
|
|
2695
2616
|
}
|
|
2696
|
-
`;class
|
|
2617
|
+
`;class Xe{getName(){return"make:permission"}getDescription(){return"Generate a new permission class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter permission name"});t=Zc(t).replace(/Permission$/,"");let r=Vi.replace(/{{NAME}}/g,t),o=s?Z("modules",s):".",i=Z(o,"src","permissions"),a=Z(process.cwd(),i),n=Z(a,`${t}Permission.ts`);await Bun.write(n,r);let d=Hi.replace(/{{NAME}}/g,t),l=Z(o,"tests","permissions"),p=Z(process.cwd(),l),u=Z(p,`${t}Permission.spec.ts`);await Bun.write(u,d);let m=new zc;m.success(`${Z(i,t)}Permission.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${Z(l,t)}Permission.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/permission"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Xe=b([w.command()],Xe);import{basename as Jc,join as q}from"path";import{TerminalLogger as jc}from"@ooneex/logger";import{toKebabCase as ep,toPascalCase as $t}from"@ooneex/utils";var Yi=`import { describe, expect, test } from "bun:test";
|
|
2697
2618
|
import { {{NAME}}PubSub } from "@/pubsub/{{NAME}}PubSub";
|
|
2698
2619
|
|
|
2699
2620
|
describe("{{NAME}}PubSub", () => {
|
|
@@ -2731,7 +2652,7 @@ describe("{{NAME}}PubSub", () => {
|
|
|
2731
2652
|
expect(typeof {{NAME}}PubSub.prototype.unsubscribeAll).toBe("function");
|
|
2732
2653
|
});
|
|
2733
2654
|
});
|
|
2734
|
-
`;var
|
|
2655
|
+
`;var zi=`import { inject } from "@ooneex/container";
|
|
2735
2656
|
import type { ScalarType } from "@ooneex/types";
|
|
2736
2657
|
import { decorator, PubSub, RedisPubSub } from "@ooneex/pub-sub";
|
|
2737
2658
|
|
|
@@ -2753,27 +2674,27 @@ export class {{NAME}}Event<Data extends Record<string, ScalarType> = Record<stri
|
|
|
2753
2674
|
// TODO: Implement handler logic here
|
|
2754
2675
|
}
|
|
2755
2676
|
}
|
|
2756
|
-
`;class
|
|
2677
|
+
`;class Je{getName(){return"make:pubsub"}getDescription(){return"Generate a new PubSub event class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Event`,o=`import { ${r} } from "./events/${r}";
|
|
2757
2678
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
2758
|
-
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(events:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),
|
|
2759
|
-
`),await this.updateChangelog(n,h,f,
|
|
2760
|
-
`,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1,useSymbol:!1});return}if(e.success(`${o} package(s) released`,void 0,r),await
|
|
2761
|
-
`)[0]??null}catch{return null}}async getCommitsSinceTag(e,t){let s=e?`${e}..HEAD`:"HEAD",r="%H|%an|%s";try{let i=(await
|
|
2762
|
-
`)){let[l,
|
|
2763
|
-
`;for(let h of d){let f=n.get(h);if(!f||f.length===0)continue;
|
|
2679
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(events:\s*\[)([^\]]*)/s,d=s.match(n);if(d){let l=d[2]?.trim(),p=l?`${l}, ${r}`:r;s=s.replace(n,`$1${p}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,channel:r}=e;if(!t)t=await v({message:"Enter name"});if(t=$t(t).replace(/PubSub$/,""),!r)r=ep(t);let o=zi.replace(/{{NAME}}/g,t).replace(/{{CHANNEL}}/g,r),i=s?q("modules",s):".",a=q(i,"src","events"),n=q(process.cwd(),a),d=q(n,`${t}Event.ts`);await Bun.write(d,o);let l=Yi.replace(/{{NAME}}/g,t),p=q(i,"tests","events"),u=q(process.cwd(),p),m=q(u,`${t}Event.spec.ts`);await Bun.write(m,l);let c=s?$t(s):$t(Jc(process.cwd())),h=q(process.cwd(),i,"src",`${c}Module.ts`);if(await Bun.file(h).exists())await this.addToModule(h,t);let f=new jc;f.success(`${q(a,t)}Event.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),f.success(`${q(p,t)}Event.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/pub-sub"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Je=b([w.command()],Je);import{readdir as tp}from"fs/promises";import{join as le}from"path";import{TerminalLogger as sp}from"@ooneex/logger";var{$:ce}=globalThis.Bun;var rp={feat:"Added",fix:"Fixed",refactor:"Changed",perf:"Changed",style:"Changed",docs:"Changed",build:"Changed",ci:"Changed",chore:"Changed",revert:"Removed"};class je{getName(){return"make:release"}getDescription(){return"Release packages with version bump, changelog, and git tag"}async run(){let e=new sp,t=process.cwd(),s=[];for(let{name:a,type:n}of[{name:"packages",type:"package"},{name:"modules",type:"module"}])try{let d=await tp(le(t,a),{withFileTypes:!0});s.push(...d.filter((l)=>l.isDirectory()).map((l)=>({base:le(a,l.name),type:n})))}catch{}let r={showTimestamp:!1,showArrow:!1,useSymbol:!0};if(s.length===0){e.error("No packages or modules found",void 0,r);return}let o=0;for(let a of s){let n=le(t,a.base),d=le(n,"package.json"),l=Bun.file(d);if(!await l.exists())continue;let p=await l.json(),u=await this.getLastTag(p.name),m=await this.getCommitsSinceTag(u,a.base);if(m.length===0)continue;let c=this.determineBumpType(m),h=this.bumpVersion(p.version,c);p.version=h;let f=`${p.name}@${h}`;await Bun.write(d,`${JSON.stringify(p,null,2)}
|
|
2680
|
+
`),await this.updateChangelog(n,h,f,m),await this.gitAdd(le(a.base,"package.json"),le(a.base,"CHANGELOG.md")),await this.gitCommit(`chore(release): ${p.name}@${h}`),await this.gitTag(f,`chore(release): ${p.name}@${h}`),e.success(`${p.name}@${h} released (${c} bump, ${m.length} commit(s))`,void 0,r),o++}if(o===0){e.info(`No packages have unreleased commits
|
|
2681
|
+
`,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1,useSymbol:!1});return}if(e.success(`${o} package(s) released`,void 0,r),await he({message:"Push commits and tags to remote?"}))try{await ce`git push && git push --tags`,e.success("Pushed commits and tags to remote",void 0,r)}catch{e.error("Failed to push to remote",void 0,r)}}async getLastTag(e){try{let s=(await ce`git --no-pager tag --list "${e}@*" --sort=-v:refname`.quiet()).text().trim();if(!s)return null;return s.split(`
|
|
2682
|
+
`)[0]??null}catch{return null}}async getCommitsSinceTag(e,t){let s=e?`${e}..HEAD`:"HEAD",r="%H|%an|%s";try{let i=(await ce`git --no-pager log ${s} --format=${"%H|%an|%s"} -- ${t}`.quiet()).text().trim();if(!i)return[];let a=[],n=/^([a-z]+)\(([^)]+)\):\s*(.+)$/;for(let d of i.split(`
|
|
2683
|
+
`)){let[l,p,...u]=d.split("|"),m=u.join("|");if(!l||!p||!m)continue;let c=m.match(n);if(c){let[,h,f,g]=c;if(h&&f&&g)a.push({hash:l.substring(0,8),type:h,scope:f,subject:g,author:p})}}return a}catch{return[]}}determineBumpType(e){for(let t of e)if(t.type==="feat")return"minor";return"patch"}bumpVersion(e,t){let s=e.split(".").map(Number),[r=0,o=0,i=0]=s;if(t==="minor")return`${r}.${o+1}.0`;return`${r}.${o}.${i+1}`}async getRepoUrl(){try{return(await ce`git --no-pager remote get-url origin`.quiet()).text().trim().replace(/\.git$/,"").replace(/^git@([^:]+):/,"https://$1/")}catch{return null}}async updateChangelog(e,t,s,r){let o=le(e,"CHANGELOG.md"),i=new Date().toISOString().split("T")[0],a=await this.getRepoUrl(),n=new Map;for(let h of r){let f=rp[h.type]??"Changed",g=n.get(f)??[];g.push(h),n.set(f,g)}let d=["Added","Changed","Deprecated","Removed","Fixed","Security"],p=`## ${a?`[${t}](${a}/releases/tag/${s})`:`[${t}]`} - ${i}
|
|
2684
|
+
`;for(let h of d){let f=n.get(h);if(!f||f.length===0)continue;p+=`
|
|
2764
2685
|
### ${h}
|
|
2765
2686
|
|
|
2766
|
-
`;for(let g of f){let y=a?` ([${g.hash}](${a}/commit/${g.hash}))`:"";
|
|
2767
|
-
`}}let u=Bun.file(o),
|
|
2768
|
-
${
|
|
2769
|
-
${
|
|
2770
|
-
${
|
|
2687
|
+
`;for(let g of f){let y=a?` ([${g.hash}](${a}/commit/${g.hash}))`:"";p+=`- ${g.subject} \u2014 ${g.author}${y}
|
|
2688
|
+
`}}let u=Bun.file(o),m="";if(await u.exists())m=await u.text();let c;if(m){let h=m.match(/## \[Unreleased\][^\n]*\n/),f=m.match(/## \[\d+\.\d+\.\d+\]/);if(h){let g=(h.index??0)+h[0].length;c=`${m.slice(0,g)}
|
|
2689
|
+
${p}
|
|
2690
|
+
${m.slice(g)}`}else if(f&&f.index!==void 0)c=`${m.slice(0,f.index)}${p}
|
|
2691
|
+
${m.slice(f.index)}`;else c=`${m.trimEnd()}
|
|
2771
2692
|
|
|
2772
|
-
${
|
|
2773
|
-
`}else
|
|
2693
|
+
${p}
|
|
2694
|
+
`}else c=`# Changelog
|
|
2774
2695
|
|
|
2775
|
-
${
|
|
2776
|
-
`;await Bun.write(o,
|
|
2696
|
+
${p}
|
|
2697
|
+
`;await Bun.write(o,c)}async gitAdd(...e){await ce`git add ${e}`}async gitCommit(e){await ce`git commit --no-verify -m ${e}`}async gitTag(e,t){await ce`git tag -a ${e} -m ${t}`}}je=b([w.command()],je);import{join as Q}from"path";import{TerminalLogger as ap}from"@ooneex/logger";import{toPascalCase as np}from"@ooneex/utils";var Zi=`import { describe, expect, test } from "bun:test";
|
|
2777
2698
|
import { {{NAME}}Repository } from "@/repositories/{{NAME}}Repository";
|
|
2778
2699
|
|
|
2779
2700
|
describe("{{NAME}}Repository", () => {
|
|
@@ -2836,12 +2757,11 @@ describe("{{NAME}}Repository", () => {
|
|
|
2836
2757
|
expect(typeof {{NAME}}Repository.prototype.count).toBe("function");
|
|
2837
2758
|
});
|
|
2838
2759
|
});
|
|
2839
|
-
`;var
|
|
2760
|
+
`;var Qi=`import { inject } from "@ooneex/container";
|
|
2840
2761
|
import type { ITypeormDatabase } from "@ooneex/database";
|
|
2841
2762
|
import { decorator } from "@ooneex/repository";
|
|
2842
2763
|
import type { FilterResultType } from "@ooneex/types";
|
|
2843
2764
|
import type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from "typeorm";
|
|
2844
|
-
import { ILike } from "typeorm";
|
|
2845
2765
|
import { {{NAME}}Entity } from "../entities/{{NAME}}Entity";
|
|
2846
2766
|
|
|
2847
2767
|
@decorator.repository()
|
|
@@ -2873,14 +2793,13 @@ export class {{NAME}}Repository {
|
|
|
2873
2793
|
skip = (page - 1) * take;
|
|
2874
2794
|
}
|
|
2875
2795
|
|
|
2876
|
-
// Apply name search if q parameter is provided
|
|
2877
2796
|
let findOptions = { ...rest, take, ...(skip !== undefined && { skip }) };
|
|
2878
2797
|
if (q) {
|
|
2879
2798
|
findOptions = {
|
|
2880
2799
|
...findOptions,
|
|
2881
2800
|
where: {
|
|
2882
2801
|
...rest.where,
|
|
2883
|
-
name: ILike(\`%\${q}%\`),
|
|
2802
|
+
// name: ILike(\`%\${q}%\`),
|
|
2884
2803
|
},
|
|
2885
2804
|
};
|
|
2886
2805
|
}
|
|
@@ -2892,7 +2811,7 @@ export class {{NAME}}Repository {
|
|
|
2892
2811
|
if (q) {
|
|
2893
2812
|
countWhere = {
|
|
2894
2813
|
...rest.where,
|
|
2895
|
-
name: ILike(\`%\${q}%\`),
|
|
2814
|
+
// name: ILike(\`%\${q}%\`),
|
|
2896
2815
|
};
|
|
2897
2816
|
}
|
|
2898
2817
|
|
|
@@ -2936,12 +2855,16 @@ export class {{NAME}}Repository {
|
|
|
2936
2855
|
return await repository.save(entities, options);
|
|
2937
2856
|
}
|
|
2938
2857
|
|
|
2939
|
-
public async update(entity: {{NAME}}Entity
|
|
2940
|
-
|
|
2858
|
+
public async update(entity: Partial<{{NAME}}Entity> & { id: string }): Promise<UpdateResult> {
|
|
2859
|
+
const repository = await this.open();
|
|
2860
|
+
|
|
2861
|
+
return await repository.update(entity.id, entity);
|
|
2941
2862
|
}
|
|
2942
2863
|
|
|
2943
|
-
public async updateMany(entities: {{NAME}}Entity
|
|
2944
|
-
|
|
2864
|
+
public async updateMany(entities: (Partial<{{NAME}}Entity> & { id: string })[]): Promise<UpdateResult[]> {
|
|
2865
|
+
const repository = await this.open();
|
|
2866
|
+
|
|
2867
|
+
return await Promise.all(entities.map((entity) => repository.update(entity.id, entity)));
|
|
2945
2868
|
}
|
|
2946
2869
|
|
|
2947
2870
|
public async delete(
|
|
@@ -2958,13 +2881,13 @@ export class {{NAME}}Repository {
|
|
|
2958
2881
|
return await repository.count(criteria ? { where: criteria } : {});
|
|
2959
2882
|
}
|
|
2960
2883
|
}
|
|
2961
|
-
`;class
|
|
2884
|
+
`;class et{getName(){return"make:repository"}getDescription(){return"Generate a new repository class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter repository name"});t=np(t).replace(/Repository$/,"");let r=Qi.replace(/{{NAME}}/g,t),o=s?Q("modules",s):".",i=Q(o,"src","repositories"),a=Q(process.cwd(),i),n=Q(a,`${t}Repository.ts`);await Bun.write(n,r);let d=Zi.replace(/{{NAME}}/g,t),l=Q(o,"tests","repositories"),p=Q(process.cwd(),l),u=Q(p,`${t}Repository.spec.ts`);await Bun.write(u,d);let m=new ap;m.success(`${Q(i,t)}Repository.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${Q(l,t)}Repository.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/repository"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}et=b([w.command()],et);import{join as tt}from"path";import{TerminalLogger as lp}from"@ooneex/logger";import{seedCreate as cp}from"@ooneex/seeds";var Xi=`#!/usr/bin/env bun
|
|
2962
2885
|
|
|
2963
2886
|
import { seedRun } from "@ooneex/seeds";
|
|
2964
2887
|
import "@/seeds/seeds";
|
|
2965
2888
|
|
|
2966
2889
|
await seedRun();
|
|
2967
|
-
`;class
|
|
2890
|
+
`;class st{getName(){return"make:seed"}getDescription(){return"Generate a new seed file"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter seed name"});let r=s?tt("modules",s):".",o=await cp({name:t,dir:tt(r,"src/seeds")}),i=tt(process.cwd(),r,"bin","seed","run.ts");if(!await Bun.file(i).exists())await Bun.write(i,Xi);let n=tt(process.cwd(),"package.json"),d=Bun.file(n);if(await d.exists()){let u=await d.json();u.scripts=u.scripts||{},u.scripts["seed:run"]="bun ./bin/seed/run.ts",await Bun.write(n,JSON.stringify(u,null,2))}let l=new lp;l.success(`${o} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),l.info("Run 'bun run seed:run' to execute seeds",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1}),await Bun.spawn(["bun","add","--dev","@ooneex/seeds"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}st=b([w.command()],st);import{join as X}from"path";import{TerminalLogger as up}from"@ooneex/logger";import{toPascalCase as hp}from"@ooneex/utils";var Ji=`import { describe, expect, test } from "bun:test";
|
|
2968
2891
|
import { {{NAME}}Service } from "@/services/{{NAME}}Service";
|
|
2969
2892
|
|
|
2970
2893
|
describe("{{NAME}}Service", () => {
|
|
@@ -2977,7 +2900,7 @@ describe("{{NAME}}Service", () => {
|
|
|
2977
2900
|
expect(typeof {{NAME}}Service.prototype.execute).toBe("function");
|
|
2978
2901
|
});
|
|
2979
2902
|
});
|
|
2980
|
-
`;var
|
|
2903
|
+
`;var ji=`import { decorator } from "@ooneex/service";
|
|
2981
2904
|
import type { IService } from "@ooneex/service";
|
|
2982
2905
|
|
|
2983
2906
|
type ServiceDataType = Record<string, unknown>;
|
|
@@ -2988,7 +2911,7 @@ export class {{NAME}}Service<T extends ServiceDataType = ServiceDataType> implem
|
|
|
2988
2911
|
// TODO: Implement service logic
|
|
2989
2912
|
}
|
|
2990
2913
|
}
|
|
2991
|
-
`;class
|
|
2914
|
+
`;class rt{getName(){return"make:service"}getDescription(){return"Generate a new service class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter service name"});t=hp(t).replace(/Service$/,"");let r=ji.replace(/{{NAME}}/g,t),o=s?X("modules",s):".",i=X(o,"src","services"),a=X(process.cwd(),i),n=X(a,`${t}Service.ts`);await Bun.write(n,r);let d=Ji.replace(/{{NAME}}/g,t),l=X(o,"tests","services"),p=X(process.cwd(),l),u=X(p,`${t}Service.spec.ts`);await Bun.write(u,d);let m=new up;m.success(`${X(i,t)}Service.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${X(l,t)}Service.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/service"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}rt=b([w.command()],rt);import{join as J}from"path";import{TerminalLogger as gp}from"@ooneex/logger";import{toPascalCase as bp,toSnakeCase as wp}from"@ooneex/utils";var ea=`import { describe, expect, test } from "bun:test";
|
|
2992
2915
|
import { {{NAME}}StorageAdapter } from "@/storage/{{NAME}}StorageAdapter";
|
|
2993
2916
|
|
|
2994
2917
|
describe("{{NAME}}StorageAdapter", () => {
|
|
@@ -3005,7 +2928,7 @@ describe("{{NAME}}StorageAdapter", () => {
|
|
|
3005
2928
|
expect(typeof {{NAME}}StorageAdapter.prototype.getOptions).toBe("function");
|
|
3006
2929
|
});
|
|
3007
2930
|
});
|
|
3008
|
-
`;var
|
|
2931
|
+
`;var ta=`import { Storage, decorator, StorageException } from "@ooneex/storage";
|
|
3009
2932
|
import type { S3Options } from "bun";
|
|
3010
2933
|
|
|
3011
2934
|
@decorator.storage()
|
|
@@ -3060,7 +2983,7 @@ export class {{NAME}}Storage extends Storage {
|
|
|
3060
2983
|
};
|
|
3061
2984
|
}
|
|
3062
2985
|
}
|
|
3063
|
-
`;class
|
|
2986
|
+
`;class ot{getName(){return"make:storage"}getDescription(){return"Generate a new storage class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter storage name"});t=bp(t).replace(/Storage$/,"");let r=wp(t).toUpperCase(),o=ta.replace(/{{NAME}}/g,t).replace(/{{NAME_UPPER}}/g,r),i=s?J("modules",s):".",a=J(i,"src","storage"),n=J(process.cwd(),a),d=J(n,`${t}Storage.ts`);await Bun.write(d,o);let l=ea.replace(/{{NAME}}/g,t),p=J(i,"tests","storage"),u=J(process.cwd(),p),m=J(u,`${t}Storage.spec.ts`);await Bun.write(m,l);let c=new gp;c.success(`${J(a,t)}Storage.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${J(p,t)}Storage.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/storage"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}ot=b([w.command()],ot);import{join as j}from"path";import{TerminalLogger as Ap}from"@ooneex/logger";import{toPascalCase as vp}from"@ooneex/utils";var sa=`import { describe, expect, test } from "bun:test";
|
|
3064
2987
|
import { {{NAME}}VectorDatabase } from "@/databases/{{NAME}}VectorDatabase";
|
|
3065
2988
|
|
|
3066
2989
|
describe("{{NAME}}VectorDatabase", () => {
|
|
@@ -3083,7 +3006,7 @@ describe("{{NAME}}VectorDatabase", () => {
|
|
|
3083
3006
|
expect(typeof {{NAME}}VectorDatabase.prototype.getSchema).toBe("function");
|
|
3084
3007
|
});
|
|
3085
3008
|
});
|
|
3086
|
-
`;var
|
|
3009
|
+
`;var ra=`import { VectorDatabase, decorator } from "@ooneex/rag";
|
|
3087
3010
|
import type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from "@ooneex/rag";
|
|
3088
3011
|
import { Utf8 } from "apache-arrow";
|
|
3089
3012
|
|
|
@@ -3107,8 +3030,8 @@ export class {{NAME}}VectorDatabase extends VectorDatabase<DataType> {
|
|
|
3107
3030
|
};
|
|
3108
3031
|
}
|
|
3109
3032
|
}
|
|
3110
|
-
`;class
|
|
3111
|
-
`),process.exit(1);var
|
|
3112
|
-
`),process.exit(1);var
|
|
3033
|
+
`;class it{getName(){return"make:vector-database"}getDescription(){return"Generate a new vector database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter vector database name"});t=vp(t).replace(/VectorDatabase$/,"").replace(/Database$/,"");let r=ra.replace(/{{NAME}}/g,t),o=s?j("modules",s):".",i=j(o,"src","databases"),a=j(process.cwd(),i),n=j(a,`${t}VectorDatabase.ts`);await Bun.write(n,r);let d=sa.replace(/{{NAME}}/g,t),l=j(o,"tests","databases"),p=j(process.cwd(),l),u=j(p,`${t}VectorDatabase.spec.ts`);await Bun.write(u,d);let m=new Ap;m.success(`${j(i,t)}VectorDatabase.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${j(l,t)}VectorDatabase.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),await Bun.spawn(["bun","add","@ooneex/rag"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}it=b([w.command()],it);var{values:W,positionals:Tp}=Np({args:Bun.argv,options:{name:{type:"string"},"route-name":{type:"string"},"route-path":{type:"string"},"route-method":{type:"string"},"is-socket":{type:"boolean"},dir:{type:"string"},channel:{type:"string"},"table-name":{type:"string"},module:{type:"string"},destination:{type:"string"}},strict:!1,allowPositionals:!0}),qt=new Sp,ia=Tp[2];if(!ia)qt.error(`Command name is required
|
|
3034
|
+
`),process.exit(1);var aa=Kt(ia);if(!aa)qt.info(`No commands found
|
|
3035
|
+
`),process.exit(1);var Rp={name:W.name,dir:W.dir,channel:W.channel,isSocket:W["is-socket"],tableName:W["table-name"],module:W.module,destination:W.destination,route:{name:W["route-name"],path:W["route-path"],method:W["route-method"]}};try{await aa.run(Rp)}catch(e){let t=e instanceof oa?e:new oa(e instanceof Error?e:String(e));qt.error(t,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1}),process.exit(1)}
|
|
3113
3036
|
|
|
3114
|
-
//# debugId=
|
|
3037
|
+
//# debugId=6D3A3A873965FB0D64756E2164756E21
|