@lunora/cli
Version:
The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands
2 lines (1 loc) • 3.85 kB
JavaScript
import{readdirSync as w,lstatSync as R,existsSync as T}from"node:fs";import{join as v,basename as $}from"node:path";import{pathToFileURL as O}from"node:url";import{d as _}from"../packem_shared/command-DwC11Cwe.mjs";import{v as N,i as g,p as E,l as x}from"../packem_shared/output-format-DfogXx0p.mjs";const c=".eval.ts",b=new Set([".git","_generated","dist","node_modules"]),p=(e,s=[])=>{let r;try{r=w(e)}catch{return s}for(const t of r){const o=v(e,t);let n;try{n=R(o)}catch{continue}if(n.isDirectory()){if(b.has(t))continue;p(o,s)}else n.isFile()&&t.endsWith(c)&&s.push(o)}return s.toSorted((t,o)=>t.localeCompare(o))},L=e=>typeof e=="object"&&e!==null&&typeof e.run=="function",S=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=1,I="evals",A='"lunora eval" needs native TypeScript execution — run Node ≥23.6, or a TS loader/transform (tracked in plans/245-eval-runner-design.md §8.3)',D=/unknown file extension ".ts"/i,y=e=>e instanceof Error?e.code==="ERR_UNKNOWN_FILE_EXTENSION"?!0:D.test(e.message):!1,m=e=>$(e,c),M=e=>({average:e.result?.average,error:e.error,items:e.result?.items,name:e.name,passed:e.passed,path:e.path,threshold:e.threshold}),F=e=>({code:e.code,error:e.error,evals:e.evals.map(s=>M(s))}),i=(e,s,r)=>{e.error(r);const t={code:1,error:r,evals:[]};return g(s)&&E(F(t)),t},U=(e,s,r)=>{if(!T(e))return r.info(`eval: no "${s}" directory — nothing to run`),[];const t=p(e);return t.length===0&&r.info(`eval: no ${c} files found under "${s}"`),t},C=async e=>{const r=(await import(O(e).href)).default;if(!L(r))throw new Error("does not default-export an eval module (expected `{ run(): Promise<EvalResult>, name?, threshold? }`)");return r},J=async(e,s)=>{let r;try{r=await C(e)}catch(n){if(y(n))throw n;return{error:n instanceof Error?n.message:String(n),name:m(e),passed:!1,path:e}}const t=r.name??m(e);if(r.threshold!==void 0&&!S(r.threshold))return{error:`invalid \`threshold\` export: must be a number in [0, 1] — received ${JSON.stringify(r.threshold)}`,name:t,passed:!1,path:e};const o=r.threshold??s;try{const n=await r.run(),l=o===void 0||n.average>=o;return{name:t,passed:l,path:e,result:n,threshold:o}}catch(n){return{error:n instanceof Error?n.message:String(n),name:t,passed:!1,path:e,threshold:o}}},W=async(e,s)=>{const r=[];for(const t of e)r.push(await J(t,s));return r},H=e=>{if(e.error!==void 0)return`ERROR: ${e.error}`;const s=e.passed?"pass":"FAIL",r=e.result?.items.length??0;return`${s} (${String(r)} cases)`},V=e=>{if(e.length===0)return[];const s=Math.max(4,...e.map(t=>t.name.length)),r=[`${"NAME".padEnd(s)} SCORE THRESHOLD STATUS`];for(const t of e){const o=t.result===void 0?"—":t.result.average.toFixed(3),n=t.threshold===void 0?"—":t.threshold.toFixed(3);r.push(`${t.name.padEnd(s)} ${o.padEnd(6)} ${n.padEnd(9)} ${H(t)}`)}return r},X=async e=>{const s=e.cwd??process.cwd(),r=x(e.format,e.logger),t=N("eval",e.format);if(t!==void 0)return e.logger.error(t),{code:1,error:t,evals:[]};if(e.threshold!==void 0&&!S(e.threshold))return i(r,e.format,`eval: --threshold must be a number in [0, 1] — received "${String(e.threshold)}"`);const o=e.dir??I,n=v(s,o),l=U(n,o,r);let d;try{d=await W(l,e.threshold)}catch(a){if(!y(a))throw a;return i(r,e.format,A)}if(e.threshold!==void 0&&d.length===0){const a=`eval: --threshold ${String(e.threshold)} was set but 0 eval files were discovered under "${o}" — nothing was gated`;return i(r,e.format,a)}for(const a of V(d))r.info(a);const h=d.filter(a=>!a.passed),f=h.length>0?1:0;f===0?r.success(`eval: ${String(d.length)} eval(s) passed`):r.error(`eval: ${String(h.length)}/${String(d.length)} eval(s) failed`);const u={code:f,evals:d};return g(e.format)&&E(F(u)),u},z=_(async({cwd:e,logger:s,options:r})=>({code:(await X({cwd:e,dir:r.dir,format:r.format,logger:s,threshold:r.threshold})).code}));export{z as execute,X as runEvalCommand};