UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands

20 lines (18 loc) 19.2 kB
import{existsSync as g,readFileSync as m,writeFileSync as h,mkdirSync as k,mkdtempSync as ee,rmSync as O}from"node:fs";import{dirname as w,join as l,relative as P}from"@visulima/path";import{DEV_VARS_FILE as te,parseDevVariableEntries as re,findWranglerFile as ne,readWranglerJsonc as oe}from"@lunora/config";import{modify as q,applyEdits as L,parse as se}from"jsonc-parser";import{fileURLToPath as ie}from"node:url";import{LunoraError as v}from"@lunora/errors";import{i as ae}from"./tui-prompts-CCt3jm1k.mjs";import{collectCatalog as ce,buildRegistryIndex as ue}from"./buildRegistryIndex-DwySASBu.mjs";import{insertSchemaExtension as fe}from"./insertSchemaExtension-DZReBZ4_.mjs";import{createHash as de}from"node:crypto";import{tmpdir as le}from"node:os";import{downloadTemplate as pe}from"giget";import ge from"./parseManifest-x3WsxKHz.mjs";const me="alpha",W="main",$e=new Set(["alpha","beta","next"]),he=/^[\w./@-]+$/,ye=e=>!e.includes("..")&&he.test(e),z=()=>{try{let e=w(ie(import.meta.url));for(let t=0;t<6;t+=1){const r=l(e,"package.json");if(g(r)){const o=JSON.parse(m(r,"utf8"));if(o.name==="@lunora/cli"&&typeof o.version=="string")return o.version}const n=w(e);if(n===e)break;e=n}}catch{}return"0.0.0"},M=e=>{if(e==="0.0.0")return me;const t=e.split("+")[0]??e,r=t.indexOf("-");if(r!==-1){const[n]=t.slice(r+1).split(".");if(n!==void 0&&$e.has(n))return n}return W},U=e=>{if(e!==void 0&&e.length>0){if(!ye(e))throw new v("INTERNAL",`invalid --ref "${e}" — a ref may contain letters, digits, ".", "_", "-", "/", "@" and must not contain "..".`);return e}return M(z())},j="anolilab/lunora",V=/^[0-9a-f]{40}$/iu,B=String.raw`\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)+)?(?:\+[0-9A-Za-z.-]+)?`,ve=new RegExp(String.raw`^v?${B}$`,"u"),we=new RegExp(String.raw`^(?:@[\w.-]+\/)?[\w.-]+@${B}$`,"u"),be=e=>V.test(e)||ve.test(e)||we.test(e),Se=()=>{const e=process.env.GITHUB_TOKEN??process.env.GH_TOKEN;return e!==void 0&&e.length>0?{authorization:`Bearer ${e}`}:{}},ke=async e=>{try{const t=await fetch(`https://api.github.com/repos/${j}/commits/${encodeURIComponent(e)}`,{headers:{accept:"application/vnd.github+json","user-agent":"lunora-cli",...Se()},signal:AbortSignal.timeout(1e4)});if(!t.ok)return;const r=await t.json();return typeof r.sha=="string"&&V.test(r.sha)?r.sha:void 0}catch{return}},je=async(e,t)=>{const r=U(e);if(be(r))return r;const n=await ke(r);return n===void 0?(t.warn(`could not pin ${j}#${r} to a commit — fetching the UNPINNED branch (set GITHUB_TOKEN if rate-limited).`),r):(t.info(`pinned ${j}#${r}${n}`),n)},xe="latest",Ne=(e=z())=>{const t=M(e);return t===W?xe:t},Oe="https://registry.npmjs.org",Re=()=>{const e=process.env.npm_config_registry,t=e!==void 0&&e.length>0?e:Oe;return t.endsWith("/")?t.slice(0,-1):t},Ae=async(e,t)=>{try{const r=await fetch(`${Re()}/${e.replaceAll("/","%2F")}`,{headers:{accept:"application/vnd.npm.install-v1+json"},signal:AbortSignal.timeout(1e4)});return r.ok?(await r.json())["dist-tags"]?.[t]:void 0}catch{return}},kt=async(e,t)=>{const r=new Map;return await Promise.all([...new Set(e)].map(async n=>{const o=await Ae(n,t);o!==void 0&&r.set(n,o)})),r},Ee=e=>{if(!e.startsWith("workspace:"))return e;const t=e.slice(10);return t===""||t==="*"||t==="^"||t==="~"?Ne():t},Te=new Set(["@lunora/client","@lunora/do","@lunora/ratelimit","@lunora/runtime","@lunora/server","@lunora/values"]),_e=/(['"])@lunora\/(client|do|ratelimit|runtime|server|values)(\/[^'"]*)?\1/gu,Je=e=>{const t=l(e,"package.json");if(!g(t))return!1;try{const r=JSON.parse(m(t,"utf8"));return r.dependencies?.lunorash!==void 0||r.devDependencies?.lunorash!==void 0}catch{return!1}},De=e=>e.replaceAll(_e,(t,r,n,o)=>`${r}lunorash/${n}${o??""}${r}`),R=(e,t,r,n="dependencies",o=!1)=>{const s=Object.entries(e);if(s.length===0)return[];const c=l(t,"package.json");if(!g(c))return r.warn(`package.json not found at ${c} — skipping dependency updates`),[];let a=m(c,"utf8");const i=JSON.parse(a),u=[];for(const[f,d]of s){if(o&&Te.has(f)){r.info(`dep provided by the lunorash umbrella, skipping: ${f}`);continue}if(i.dependencies?.[f]!==void 0||i.devDependencies?.[f]!==void 0){r.info(`dep already present: ${f}`);continue}const p=q(a,[n,f],Ee(d),{formattingOptions:{insertSpaces:!0,tabSize:4}});a=L(a,p),u.push(f)}return u.length>0&&(h(c,a,"utf8"),r.success(`added ${String(u.length)} ${n==="devDependencies"?"devDependency(ies)":"dependency(ies)"} to package.json: ${u.join(", ")}`)),u},Ie=(e,t,r)=>{if(e.length===0)return[];const n=l(t,te),o=g(n)?m(n,"utf8"):"",s=new Set(re(o).map(u=>u.key)),c=[],a=[],i=[];for(const u of e)u.secret&&a.push(u.name),!s.has(u.name)&&(u.description&&i.push(`# ${u.description}`),i.push(`${u.name}=${u.secret?"":u.value??""}`),c.push(u.name));if(c.length>0){const u=o===""||o.endsWith(` `)?o:`${o} `;h(n,`${u}${i.join(` `)} `,"utf8"),r.success(`scaffolded ${String(c.length)} env var(s) into .dev.vars: ${c.join(", ")}`)}return a.length>0&&r.info(`set secret value(s) locally in .dev.vars, then for production: ${a.map(u=>`wrangler secret put ${u}`).join("; ")}`),c},A=new Set(["ai","analytics_engine_datasets","browser","d1_databases","durable_objects","hyperdrive","kv_namespaces","mtls_certificates","queues","r2_buckets","send_email","services","vars","vectorize","version_metadata","workflows"]),Pe=(e,t,r)=>{if(e.length===0)return[];const n=["wrangler.jsonc","wrangler.json"].map(i=>l(t,i)).find(i=>g(i));if(!n)return r.warn("wrangler.jsonc not found — skipping binding updates"),[];let o=m(n,"utf8");const s=[],c=i=>Array.isArray(i),a=i=>{let u=se(o);for(const f of i){if(typeof u!="object"||u===null)return;u=u[f]}return u};for(const i of e){const u=i.path[0];if(u===void 0||!A.has(u)){r.warn(`skipping binding "${i.path.join(".")}" — only resource bindings (${[...A].join(", ")}) may be written, not exec/entrypoint keys`);continue}let{value:f}=i;if(c(f)){const p=a(i.path);if(c(p)){const $=new Set(p.map(y=>JSON.stringify(y)));f=[...p,...f.filter(y=>!$.has(JSON.stringify(y)))]}}const d=q(o,[...i.path],f,{formattingOptions:{insertSpaces:!0,tabSize:4}});d.length!==0&&(o=L(o,d),s.push(i.path.join(".")))}return s.length>0&&(h(n,o,"utf8"),r.success(`applied ${String(s.length)} binding(s) to ${n}: ${s.join(", ")}`)),s},qe=(e,t,r,n=!1)=>{const o=[],s=[];return e.deps&&o.push(...R(e.deps,t,r,"dependencies",n)),e.devDependencies&&o.push(...R(e.devDependencies,t,r,"devDependencies",n)),e.bindings&&s.push(...Pe(e.bindings,t,r)),e.envVars&&Ie(e.envVars,t,r),{bindings:s,deps:o}},Le=async(e,t)=>{const r=e.some(({manifest:i})=>Object.keys(i.deps??{}).length>0||Object.keys(i.devDependencies??{}).length>0),n=e.some(({manifest:i})=>(i.bindings??[]).length>0),o=t.source!==void 0&&t.source.length>0;if(!r&&!n&&!o||t.yes)return!0;const s=[];r&&s.push("add dependencies to package.json"),n&&s.push("write wrangler.jsonc bindings"),o&&s.push(`come from a non-default source (${String(t.source)})`);const c=s.join(", ");if(!process.stdin.isTTY&&t.confirm===void 0)return t.logger.error(`add: stdin is not a TTY and the requested items ${c} — re-run with --yes to confirm`),!1;const a=await(t.confirm??ae)(`The requested items ${c}. Continue?`);return a||t.logger.info("add: aborted"),a},S=1,We=".lunora-registry.json",F=e=>l(e,"lunora",We),ze=e=>typeof e!="object"||e===null||!("items"in e)?!1:typeof e.items=="object"&&e.items!==null,x=e=>de("sha256").update(e).digest("hex"),Me=e=>{const t=F(e);if(!g(t))return{items:{},version:S};try{const r=JSON.parse(m(t,"utf8"));if(ze(r))return{items:r.items,version:S}}catch{}return{items:{},version:S}},Ue=(e,t)=>{h(F(e),`${JSON.stringify(t,void 0,2)} `,"utf8")},E=(e,t,r,n)=>{const o=e.items[t],s=o??{files:{}};o===void 0&&(e.items[t]=s),s.files[r]=x(n)},Ve=(e,t,r)=>e.items[t]?.files[r],T=e=>e===""?[]:e.split(` `),Be=(e,t)=>{const r=T(e),n=T(t);let o=0;for(;o<r.length&&o<n.length&&r[o]===n[o];)o+=1;let s=r.length,c=n.length;for(;s>o&&c>o&&r[s-1]===n[c-1];)s-=1,c-=1;if(o===s&&o===c)return[];const a=[];for(let i=Math.max(0,o-3);i<o;i+=1)a.push(` ${r[i]??""}`);for(let i=o;i<s;i+=1)a.push(`- ${r[i]??""}`);for(let i=o;i<c;i+=1)a.push(`+ ${n[i]??""}`);for(let i=c;i<Math.min(n.length,c+3);i+=1)a.push(` ${n[i]??""}`);return a},Fe=/\.[cm]?[jt]sx?$/u,H=(e,t,r)=>{const n=m(l(e,t.from),"utf8");return r&&Fe.test(t.to)?De(n):n},He=(e,t,r,n,o,s,c)=>{const a=l(n,"lunora","schema.ts");if(s)return o.info(`~ would merge .extend(${t}.extension) into lunora/schema.ts (and create ${e.to} if absent)`),{kind:"skipped",path:a};const i=l(n,e.to);g(i)||(k(w(i),{recursive:!0}),h(i,H(r,e,c),"utf8"));const u=c?"lunorash/server":"@lunora/server",f=g(a)?m(a,"utf8"):`import { defineSchema } from "${u}"; export const schema = defineSchema({}); `,d=fe(f,t);if(d.ok)return k(w(a),{recursive:!0}),h(a,d.text,"utf8"),o.success(`merged .extend(${t}.extension) into lunora/schema.ts`),{kind:"written",path:a};if(d.reason==="already-applied")return o.warn(`lunora/schema.ts already extends "${t}" — skipping`),{kind:"skipped",path:a};throw d.reason==="invalid-identifier"?new v("INTERNAL",`schema-extension item "${t}" is not a valid JS identifier — it is spliced into lunora/schema.ts as \`import { ${t} }\` / \`.extend(${t}.extension)\`. Rename the item to a valid identifier (no leading digit, no "-").`):new v("INTERNAL",`schema-extension merge failed for "${t}": ${d.reason}`)},Ge=(e,t,r,n,o)=>{const s=Be(t,r);if(s.length===0){o.info(`= ${e.to} (unchanged)`);return}o.info(`${n?"~":"+"} ${e.to}`);for(const c of s)o.info(` ${c}`)},Ze=(e,t,r,n,o,s,c,a)=>{const i=l(n,e.to),u=H(r,e,a),f=g(i),d=f?m(i,"utf8"):"",p=X=>(k(w(i),{recursive:!0}),h(i,u,"utf8"),E(s,t,e.to,u),o.success(`${X}: ${e.to}`),{kind:"written",path:i});if(c.diff)return Ge(e,d,u,f,o),{kind:"skipped",path:i};if(!f)return p("write");const $=x(d);if($===x(u))return E(s,t,e.to,u),o.warn(`skip (exists): ${e.to}`),{kind:"skipped",path:i};if(c.overwrite)return p("overwrite");const y=Ve(s,t,e.to);return y===void 0?(o.warn(`skip (exists, untracked): ${e.to} — refusing to overwrite a file lunora didn't add (use --overwrite to force)`),{kind:"skipped",path:i}):y===$?p("update"):(h(`${i}.new`,u,"utf8"),o.warn(`conflict: ${e.to} has local edits and an upstream update — wrote ${e.to}.new (use --overwrite to take theirs)`),{kind:"skipped",path:i})},Ce=(e,t,r,n,o,s,c={},a=!1)=>e.merge==="schema-extension"?He(e,t,r,n,o,c.diff===!0,a):Ze(e,t,r,n,o,s,c,a),_=["src/server.ts","src/server/index.ts","src/server/index.tsx","src/index.ts","src/worker.ts"],Ke=e=>{const t=ne(e);if(t===void 0)return;const{parsed:r}=oe(t);return typeof r?.main=="string"?r.main:void 0},Ye=e=>{const t=Ke(e),r=t===void 0?_:[t,..._];for(const n of r){const o=l(e,n);if(!g(o))continue;const s=m(o,"utf8");if(!s.includes("createShardDO(")){if(n===t)break;continue}return{entryPath:o,main:n,source:s}}},Qe=(e,t,r)=>{const n=P(w(e),l(t,"lunora",r)).replaceAll("\\","/");return n.startsWith(".")?n:`./${n}`},Xe=(e,t)=>{for(const r of e){const n=`Add \`export * from "${`./lunora/${r.module}.js`}"\` to your worker entry`,o=r.comment?` (${r.comment})`:"";t.warn(`${n}${o}`)}return 0},et=(e,t,r,n)=>{const o=[];for(const s of e){const c=Qe(t,r,s.module),a=c.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`);new RegExp(String.raw`export\s+\*\s+from\s+["']${a}\.js["']`,"u").test(n)||(s.comment&&o.push(` // ${s.comment}`),o.push(`export * from "${c}.js";`))}return o},tt=(e,t,r,n)=>{if(e.length===0)return 0;const o=Ye(t);if(o===void 0)return Xe(e,r);const s=et(e,o.entryPath,t,o.source);if(s.length===0)return 0;if(n){for(const a of s)a!==""&&r.info(`~ entrypoint: ${a}`);return s.length}const c=o.source.endsWith(` `)?"":` `;return h(o.entryPath,`${o.source}${c}${s.join(` `)} `,"utf8"),r.success(`wrote ${String(s.length)} entrypoint re-export(s) to ${P(t,o.entryPath)}`),s.length},J=(e,t,r,n={})=>{const o=[],s=[],c=[],a=[],i=Me(t),u=Je(t);for(const{directory:f,manifest:d}of e){for(const $ of d.files){const y=Ce($,d.name,f,t,r,i,n,u);(y.kind==="written"?o:s).push(y.path)}if(d.entrypointReexports!==void 0&&tt(d.entrypointReexports,t,r,n.diff===!0),n.diff)continue;const p=qe(d,t,r,u);c.push(...p.deps),a.push(...p.bindings)}return!n.diff&&Object.keys(i.items).length>0&&Ue(t,i),{bindings:a,deps:c,skipped:s,written:o}},G="gh:anolilab/lunora/registry",D=/^[A-Za-z0-9][\w-]*$/u,rt=e=>{if(!D.test(e))throw new v("INTERNAL",`invalid registry item name "${e}" — names must match ${D.source} (letters, digits, "-", "_"; no path separators or "..")`)},nt=e=>e.includes("..")?!1:e.startsWith("gh:")||e.startsWith("github:")||e.startsWith("https://"),ot=e=>e.from===void 0&&e.source!==void 0&&e.source.length>0&&!e.allowUnsafeSource&&!nt(e.source),N=(e,t)=>ot(t)?`${e}: refusing --source ${String(t.source)} — only gh:, github:, or https:// sources are allowed (and may not contain ".."). Re-run with --allow-unsafe-source if you really want this.`:void 0,Z=async(e,t,r)=>{const n=ee(l(le(),`lunora-${t}-fetch-`)),o=l(n,t);r.info(`fetching ${e}`);try{const s=await pe(e,{cwd:n,dir:o,force:!0,install:!1,silent:!0});return r.info(s.commit?`resolved ${s.source} @ ${s.commit}`:`resolved ${s.source}`),{cleanup:()=>{O(n,{force:!0,recursive:!0})},directory:o}}catch(s){throw O(n,{force:!0,recursive:!0}),s}},I=new WeakMap,C=async e=>{const t=I.get(e);if(t!==void 0)return t;const r=e.source!==void 0&&e.source.length>0?Promise.resolve(U(e.ref)):je(e.ref,e.logger);return I.set(e,r),r},K=async(e,t)=>{if(rt(e),t.from!==void 0){const n=l(t.from,e);if(!g(n))throw new v("INTERNAL",`registry item not found in local source: ${n}`);return{cleanup:()=>{},directory:n}}const r=t.source??G;return Z(`${r}/${e}#${await C(t)}`,"item",t.logger)},st=async e=>{if(e.from!==void 0){if(!g(e.from))throw new v("INTERNAL",`registry root not found: ${e.from}`);return{cleanup:()=>{},root:e.from}}const t=e.source??G,{cleanup:r,directory:n}=await Z(`${t}#${await C(e)}`,"registry",e.logger);return{cleanup:r,root:n}},Y=(e,t)=>{const r=JSON.parse(m(l(e,"registry.json"),"utf8"));return ge(r,t)},it=async(e,t)=>{const r=[],n=[],o=new Set,s=new Set,c=async a=>{if(o.has(a))return;if(s.has(a))throw new v("INTERNAL",`cyclic registry dependency detected at "${a}"`);s.add(a);const{cleanup:i,directory:u}=await K(a,t);n.push(i);const f=Y(u,a);for(const d of f.requires??[])await c(d);s.delete(a),o.add(a),r.push({directory:u,manifest:f})};try{for(const a of e)await c(a)}catch(a){for(const i of n)i();throw a}return{cleanups:n,items:r}},b=()=>({bindings:[],code:0,deps:[],skipped:[],written:[]}),jt=(e,t,r,n,o)=>e.bindings?{...e,bindings:e.bindings.map(s=>{if(s.path[0]!==t||!Array.isArray(s.value))return s;const c=s.value;return{...s,value:c.map(a=>typeof a=="object"&&a!==null&&a[r.key]===r.value?{...a,[n]:o}:a)}})}:e,Q=(e,t)=>{const r=t.title??t.description;e.info(`plan: ${t.name}${r?` — ${r}`:""}`);for(const n of t.files)e.info(` file ${n.to} (${n.merge})`);for(const[n,o]of Object.entries(t.deps??{}))e.info(` dep ${n}@${o}`);for(const[n,o]of Object.entries(t.devDependencies??{}))e.info(` dev ${n}@${o}`);for(const n of t.bindings??[])e.info(` bind ${n.path.join(".")} = ${JSON.stringify(n.value)}`);for(const n of t.envVars??[]){const o=n.secret?" (secret)":` = ${JSON.stringify(n.value??"")}`;e.info(` env ${n.name}${o}`)}for(const n of t.entrypointReexports??[]){const o=`./lunora/${n.module}`,s=n.comment?` // ${n.comment}`:"";e.info(` entry ${o}${s}`)}},at=e=>{const t=e.map(({manifest:r})=>({bindings:(r.bindings??[]).map(n=>({path:n.path.join("."),value:n.value})),deps:Object.keys(r.deps??{}),devDependencies:Object.keys(r.devDependencies??{}),entrypointReexports:(r.entrypointReexports??[]).map(n=>({module:n.module,...n.comment?{comment:n.comment}:{}})),envVars:(r.envVars??[]).map(n=>({name:n.name,...n.secret?{secret:!0}:{value:n.value??""}})),files:r.files.map(n=>({merge:n.merge,to:n.to})),name:r.name,requires:r.requires??[],title:r.title}));process.stdout.write(`${JSON.stringify({items:t},void 0,2)} `)},ct=(e,t,r,n,o)=>{o.success(`add complete: ${String(r)} written, ${String(n)} skipped`),o.info("next steps:"),o.info(" lunora codegen # regenerate _generated/ so the new tables/functions appear"),t.length>0&&o.info(" pnpm install # install newly-added dependencies");for(const{manifest:s}of e)s.docs&&o.info(`${s.name}: ${s.docs}`)},ut=async e=>{const t=b(),r=N("list",e);if(r)return e.logger.error(r),{...t,code:1};let n=()=>{};try{const o=await st(e);n=o.cleanup;const s=ce(o.root);if(e.json)return process.stdout.write(`${JSON.stringify(s,void 0,2)} `),t;e.logger.info(`available registry items (${String(s.length)}):`);for(const c of s)e.logger.info(` ${c.name}${c.description?` — ${c.description}`:""}`);return t}catch(o){return e.logger.error(`list failed: ${o instanceof Error?o.message:String(o)}`),{...t,code:1}}finally{n()}},xt=async e=>{const t=e.cwd??process.cwd(),r=b();if(e.list)return ut(e);if(e.names.length===0)return e.logger.error("add requires at least one item name. Usage: lunora registry add <name> [...names]"),{...r,code:1};const n=N("add",e);if(n)return e.logger.error(n),{...r,code:1};let o=[];try{const{cleanups:s,items:c}=await it(e.names,e);o=s;const{transformManifest:a}=e,i=a?c.map($=>({...$,manifest:a($.manifest)})):c;for(const{manifest:$}of i)Q(e.logger,$);if(e.json&&at(i),e.dryRun)return e.logger.info("dry-run: stopping before any files are written"),r;if(e.diff)return J(i,t,e.logger,{diff:!0}),e.logger.info("diff: preview only — re-run without --diff to apply"),r;if(!await Le(i,e))return{...r,code:1};const{bindings:u,deps:f,skipped:d,written:p}=J(i,t,e.logger,{overwrite:e.overwrite});return ct(i,f,p.length,d.length,e.logger),{bindings:u,code:0,deps:f,skipped:d,written:p}}catch(s){return e.logger.error(`add failed: ${s instanceof Error?s.message:String(s)}`),{...r,code:1}}finally{for(const s of o)s()}},Nt=async e=>{const t=b();if(e.names.length===0)return e.logger.error("view requires an item name. Usage: lunora registry view <name>"),{...t,code:1};const r=N("view",e);if(r)return e.logger.error(r),{...t,code:1};const n=[];try{for(const o of e.names){const{cleanup:s,directory:c}=await K(o,e);n.push(s);const a=Y(c,o);Q(e.logger,a);for(const i of a.files){e.logger.info(`--- ${i.to} (${i.merge}) ---`);const u=m(l(c,i.from),"utf8");for(const f of u.split(` `))e.logger.info(f)}}return t}catch(o){return e.logger.error(`view failed: ${o instanceof Error?o.message:String(o)}`),{...t,code:1}}finally{for(const o of n)o()}},Ot=async e=>{const t=b(),r=e.from;if(r===void 0)return e.logger.error("registry build requires --from <registry root>"),{...t,code:1};if(!g(r))return e.logger.error(`registry root not found: ${r}`),{...t,code:1};const n=ue(r),o=e.out??l(r,"index.json");if(e.check){const s=g(o)?JSON.parse(m(o,"utf8")):{items:[]};return JSON.stringify(s.items??[])!==JSON.stringify(n.items)?(e.logger.error(`registry: ${o} is stale — run \`lunora registry build\` to regenerate it`),{...t,code:1}):(e.logger.success(`registry: ${o} is up to date (${String(n.items.length)} items)`),t)}return h(o,`${JSON.stringify({$schema:"./schema/registry.schema.json",...n},void 0,4)} `,"utf8"),e.logger.success(`registry: wrote ${o} (${String(n.items.length)} items)`),t};export{Ne as L,xt as M,kt as P,ut as R,je as b,jt as d,U as g,Nt as k,Ot as q};