@lunora/cli 1.0.0-alpha.142 → 1.0.0-alpha.144

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.
@@ -1 +1 @@
1
- import{existsSync as g,readFileSync as m}from"node:fs";import{join as h}from"node:path";import{isPlaceholderValue as v,DEV_VARS_FILE as p,parseDevVariableEntries as w,discoverSchemaInfo as $,inferLunoraBindings as x}from"@lunora/config";import{findWranglerFile as y,readWranglerJsonc as b,validateWranglerConfig as S}from"@lunora/config/cloudflare";import{i as _}from"../packem_shared/command-Bjv4VmYA.mjs";import{o as N,p as R}from"../packem_shared/vectorize-metadata-BvZbbqUD.mjs";const k=/(?:KEY|PASSWORD|SECRET|TOKEN)$/u,A=a=>{const e=a.trim();if(e==="")return!0;const n=e.toLowerCase();return n.includes("replace")||n.startsWith("<")&&n.endsWith(">")},j=a=>{const e=y(a);if(e===void 0)return{parsed:void 0,path:void 0};const{parsed:n}=b(e);return{parsed:n,path:e}},O=(a,e,n)=>{if(e===void 0){n.push({fix:"Run `lunora init` (or `lunora dev`) to scaffold and reconcile wrangler.jsonc.",level:"fail",message:"wrangler.jsonc not found."});return}if(a===void 0){n.push({fix:`Check ${e} is valid JSONC.`,level:"fail",message:`Could not parse ${e}.`});return}const r=S(a).errors.find(t=>t.includes("SHARD"));r===void 0?n.push({level:"pass",message:"wrangler.jsonc present with a SHARD durable-object binding."}):n.push({fix:"Run `lunora dev` to auto-reconcile, or add the binding manually.",level:"fail",message:r})},D=(a,e)=>{const{info:n}=$(a,"lunora");for(const r of n?.vectorMetadata??[]){const t=R(r.kind);if(t===void 0){e.push({fix:"Filter on a string, number or boolean column, or drop it from `metadata`.",level:"warn",message:`vector index "${r.index}" declares metadata "${r.property}", whose type Vectorize cannot filter on.`});continue}e.push({fix:`wrangler ${N({index:r.index,property:r.property,type:t}).join(" ")}`,level:"info",message:`vector index "${r.index}" filters on metadata "${r.property}" — that needs a Vectorize metadata index (\`lunora deploy\` creates it).`})}},E=(a,e)=>{if(a===void 0)return;const n=(a.d1_databases??[]).filter(Boolean);for(const r of n){const t=typeof r.database_id=="string"?r.database_id:"";if(A(t)){const o=typeof r.binding=="string"&&r.binding.length>0?r.binding:"<unnamed>";e.push({fix:"Run `wrangler d1 create <name>` and paste the returned database_id into wrangler.jsonc.",level:"fail",message:`D1 binding "${o}" has a placeholder database_id ("${t||"<empty>"}").`})}}},L=(a,e)=>{if(a===void 0)return;const n=(a.send_email??[]).filter(Boolean);for(const r of n){const t=typeof r.destination_address=="string"?r.destination_address:"";if(t!==""&&v(t)){const o=typeof r.name=="string"&&r.name.length>0?r.name:"send_email";e.push({fix:"Set destination_address to a verified Cloudflare Email Routing address.",level:"warn",message:`send_email binding "${o}" has a placeholder destination_address ("${t}").`})}}},I=(a,e)=>{const n=h(a,p);if(!g(n))return;let r;try{r=m(n,"utf8")}catch{return}const t=w(r).filter(o=>k.test(o.key)&&v(o.value)).map(o=>o.key);t.length>0&&e.push({fix:"Run `lunora dev` to auto-generate secrets, or fill them in by hand.",level:"warn",message:`${p} has unfilled secret value(s): ${t.join(", ")}.`})},C=a=>{const e=process.env.LUNORA_ADMIN_TOKEN;e===void 0||e.trim()===""?a.push({fix:"Set LUNORA_ADMIN_TOKEN (env or `.dev.vars`) to enable admin RPCs / studio.",level:"info",message:"LUNORA_ADMIN_TOKEN is not set."}):a.push({level:"pass",message:"LUNORA_ADMIN_TOKEN is set."})},W=async(a,e)=>{let n;try{({containers:n}=await x({projectRoot:a}))}catch{return}for(const r of n)r.exported?e.push({level:"pass",message:`container "${r.exportName}" is exported by the worker entry.`}):e.push({fix:'Add `export * from "./lunora/_generated/containers"` to your worker entry (or re-run `vis generate lunora-container`).',level:"fail",message:`container "${r.exportName}" is declared but ${r.className} is not exported by the worker entry.`})},M=/^[\^~><= ]+/u,z=/^(?<core>\d+\.\d+\.\d+)(?:-(?<channel>[a-z]+)\.(?<counter>\d+))?$/u,F=a=>{const e=a.replace(M,"").trim(),n=z.exec(e);if(!n?.groups)return;const{channel:r,core:t,counter:o}=n.groups;return{channel:r??"",core:t??"",counter:o===void 0?void 0:Number.parseInt(o,10),raw:e}},K=(a,e)=>{const n=h(a,"package.json");if(!g(n))return;let r;try{r=JSON.parse(m(n,"utf8"))}catch{return}const t={...r.devDependencies,...r.dependencies},o=[];for(const[s,i]of Object.entries(t)){if(s!=="lunorash"&&!s.startsWith("@lunora/"))continue;const f=F(i);f&&o.push({name:s,version:f})}if(o.length<2)return;const d=s=>s.map(i=>`${i.name}@${i.version.raw}`).join(", "),u=new Set(o.map(s=>s.version.core)),c=new Set(o.map(s=>s.version.channel));if(u.size>1){e.push({fix:'Run `pnpm update "@lunora/*" lunorash` (or `npm`/`yarn` equivalent) so every Lunora package moves to the same release.',level:"warn",message:`Lunora packages span ${String(u.size)} different versions: ${d(o)}.`});return}if(c.size>1){e.push({fix:"Pick one channel (all stable, or all alpha/beta) and update the odd package out.",level:"warn",message:`Lunora packages mix release channels (${[...c].map(s=>s===""?"stable":s).join(" + ")}): ${d(o)}.`});return}const l=o.map(s=>s.version.counter).filter(s=>s!==void 0);if(l.length>1){const s=Math.min(...l),i=Math.max(...l);e.push({level:"info",message:l.length===o.length&&s===i?`Lunora packages are all at ${[...c][0]??""}.${String(i)}.`:`Lunora pre-release counters span ${String(s)}–${String(i)}: ${d(o)}.`})}},T=async a=>{const e=a.cwd??process.cwd(),n=[],{parsed:r,path:t}=j(e);return O(r,t,n),E(r,n),L(r,n),I(e,n),C(n),K(e,n),D(e,n),await W(e,n),{code:n.some(o=>o.level==="fail")?1:0,findings:n}},V={fail:"FAIL",info:"INFO",pass:"PASS",warn:"WARN"},P=(a,e)=>{e.info("lunora doctor — project preflight");for(const t of a.findings){const o=`[${V[t.level]}] ${t.message}`;t.level==="fail"?e.error(o):t.level==="warn"?e.warn(o):e.info(o),t.fix!==void 0&&t.level!=="pass"&&e.info(` fix: ${t.fix}`)}const n=a.findings.filter(t=>t.level==="fail").length,r=a.findings.filter(t=>t.level==="warn").length;n>0?e.error(`${String(n)} failure(s), ${String(r)} warning(s).`):r>0?e.warn(`0 failures, ${String(r)} warning(s).`):e.success("all checks passed.")},G=_(async({cwd:a,logger:e})=>{const n=await T({cwd:a});return P(n,e),{code:n.code}});export{G as execute,T as runDoctor};
1
+ import{existsSync as g,readFileSync as m}from"node:fs";import{join as h}from"node:path";import{isPlaceholderValue as v,DEV_VARS_FILE as p,parseDevVariableEntries as w,discoverSchemaInfo as $,inferLunoraBindings as x}from"@lunora/config";import{findWranglerFile as y,readWranglerJsonc as b,validateWranglerConfig as S,collectExportGaps as k}from"@lunora/config/cloudflare";import{i as _}from"../packem_shared/command-Bjv4VmYA.mjs";import{o as N,p as R}from"../packem_shared/vectorize-metadata-BvZbbqUD.mjs";const A=/(?:KEY|PASSWORD|SECRET|TOKEN)$/u,j=o=>{const e=o.trim();if(e==="")return!0;const n=e.toLowerCase();return n.includes("replace")||n.startsWith("<")&&n.endsWith(">")},O=o=>{const e=y(o);if(e===void 0)return{parsed:void 0,path:void 0};const{parsed:n}=b(e);return{parsed:n,path:e}},E=(o,e,n)=>{if(e===void 0){n.push({fix:"Run `lunora init` (or `lunora dev`) to scaffold and reconcile wrangler.jsonc.",level:"fail",message:"wrangler.jsonc not found."});return}if(o===void 0){n.push({fix:`Check ${e} is valid JSONC.`,level:"fail",message:`Could not parse ${e}.`});return}const t=S(o).errors.find(a=>a.includes("SHARD"));t===void 0?n.push({level:"pass",message:"wrangler.jsonc present with a SHARD durable-object binding."}):n.push({fix:"Run `lunora dev` to auto-reconcile, or add the binding manually.",level:"fail",message:t})},L=(o,e)=>{const{info:n}=$(o,"lunora");for(const t of n?.vectorMetadata??[]){const a=R(t.kind);if(a===void 0){e.push({fix:"Filter on a string, number or boolean column, or drop it from `metadata`.",level:"warn",message:`vector index "${t.index}" declares metadata "${t.property}", whose type Vectorize cannot filter on.`});continue}e.push({fix:`wrangler ${N({index:t.index,property:t.property,type:a}).join(" ")}`,level:"info",message:`vector index "${t.index}" filters on metadata "${t.property}" — that needs a Vectorize metadata index (\`lunora deploy\` creates it).`})}},D=(o,e)=>{if(o===void 0)return;const n=(o.d1_databases??[]).filter(Boolean);for(const t of n){const a=typeof t.database_id=="string"?t.database_id:"";if(j(a)){const r=typeof t.binding=="string"&&t.binding.length>0?t.binding:"<unnamed>";e.push({fix:"Run `wrangler d1 create <name>` and paste the returned database_id into wrangler.jsonc.",level:"fail",message:`D1 binding "${r}" has a placeholder database_id ("${a||"<empty>"}").`})}}},I=(o,e)=>{if(o===void 0)return;const n=(o.send_email??[]).filter(Boolean);for(const t of n){const a=typeof t.destination_address=="string"?t.destination_address:"";if(a!==""&&v(a)){const r=typeof t.name=="string"&&t.name.length>0?t.name:"send_email";e.push({fix:"Set destination_address to a verified Cloudflare Email Routing address.",level:"warn",message:`send_email binding "${r}" has a placeholder destination_address ("${a}").`})}}},C=(o,e)=>{const n=h(o,p);if(!g(n))return;let t;try{t=m(n,"utf8")}catch{return}const a=w(t).filter(r=>A.test(r.key)&&v(r.value)).map(r=>r.key);a.length>0&&e.push({fix:"Run `lunora dev` to auto-generate secrets, or fill them in by hand.",level:"warn",message:`${p} has unfilled secret value(s): ${a.join(", ")}.`})},W=o=>{const e=process.env.LUNORA_ADMIN_TOKEN;e===void 0||e.trim()===""?o.push({fix:"Set LUNORA_ADMIN_TOKEN (env or `.dev.vars`) to enable admin RPCs / studio.",level:"info",message:"LUNORA_ADMIN_TOKEN is not set."}):o.push({level:"pass",message:"LUNORA_ADMIN_TOKEN is set."})},M=async(o,e)=>{let n;try{n=await x({projectRoot:o})}catch{return}const t=k(n),a=[...n.containers.map(r=>({...r,kind:"container"})),...n.workflows.map(r=>({...r,kind:"workflow"})),...n.agents.map(r=>({...r,kind:"agent"}))];for(const r of a.filter(l=>l.exported))e.push({level:"pass",message:`${r.kind} "${r.exportName}" is exported by the worker entry.`});for(const r of t)e.push({fix:`Add \`export * from "./lunora/_generated/${r.module}"\` to your worker entry (or re-run \`vis generate lunora-${r.kind}\`).`,level:"fail",message:`${r.kind} "${r.exportName}" is declared but ${r.className} is not exported by the worker entry.`})},z=/^[\^~><= ]+/u,F=/^(?<core>\d+\.\d+\.\d+)(?:-(?<channel>[a-z]+)\.(?<counter>\d+))?$/u,K=o=>{const e=o.replace(z,"").trim(),n=F.exec(e);if(!n?.groups)return;const{channel:t,core:a,counter:r}=n.groups;return{channel:t??"",core:a??"",counter:r===void 0?void 0:Number.parseInt(r,10),raw:e}},T=(o,e)=>{const n=h(o,"package.json");if(!g(n))return;let t;try{t=JSON.parse(m(n,"utf8"))}catch{return}const a={...t.devDependencies,...t.dependencies},r=[];for(const[s,i]of Object.entries(a)){if(s!=="lunorash"&&!s.startsWith("@lunora/"))continue;const u=K(i);u&&r.push({name:s,version:u})}if(r.length<2)return;const l=s=>s.map(i=>`${i.name}@${i.version.raw}`).join(", "),f=new Set(r.map(s=>s.version.core)),c=new Set(r.map(s=>s.version.channel));if(f.size>1){e.push({fix:'Run `pnpm update "@lunora/*" lunorash` (or `npm`/`yarn` equivalent) so every Lunora package moves to the same release.',level:"warn",message:`Lunora packages span ${String(f.size)} different versions: ${l(r)}.`});return}if(c.size>1){e.push({fix:"Pick one channel (all stable, or all alpha/beta) and update the odd package out.",level:"warn",message:`Lunora packages mix release channels (${[...c].map(s=>s===""?"stable":s).join(" + ")}): ${l(r)}.`});return}const d=r.map(s=>s.version.counter).filter(s=>s!==void 0);if(d.length>1){const s=Math.min(...d),i=Math.max(...d);e.push({level:"info",message:d.length===r.length&&s===i?`Lunora packages are all at ${[...c][0]??""}.${String(i)}.`:`Lunora pre-release counters span ${String(s)}–${String(i)}: ${l(r)}.`})}},V=async o=>{const e=o.cwd??process.cwd(),n=[],{parsed:t,path:a}=O(e);return E(t,a,n),D(t,n),I(t,n),C(e,n),W(n),T(e,n),L(e,n),await M(e,n),{code:n.some(r=>r.level==="fail")?1:0,findings:n}},P={fail:"FAIL",info:"INFO",pass:"PASS",warn:"WARN"},B=(o,e)=>{e.info("lunora doctor — project preflight");for(const a of o.findings){const r=`[${P[a.level]}] ${a.message}`;a.level==="fail"?e.error(r):a.level==="warn"?e.warn(r):e.info(r),a.fix!==void 0&&a.level!=="pass"&&e.info(` fix: ${a.fix}`)}const n=o.findings.filter(a=>a.level==="fail").length,t=o.findings.filter(a=>a.level==="warn").length;n>0?e.error(`${String(n)} failure(s), ${String(t)} warning(s).`):t>0?e.warn(`0 failures, ${String(t)} warning(s).`):e.success("all checks passed.")},Q=_(async({cwd:o,logger:e})=>{const n=await V({cwd:o});return B(n,e),{code:n.code}});export{Q as execute,V as runDoctor};
@@ -1,4 +1,4 @@
1
- import{runCodegen as h}from"@lunora/codegen";import{collectWranglerSecretVariables as A}from"@lunora/config/cloudflare";import{n as y,t as S}from"../packem_shared/advisory-gate-yaOOyUQl.mjs";import{r as C}from"../packem_shared/api-spec-BENwiyUa.mjs";import{i as D}from"../packem_shared/command-Bjv4VmYA.mjs";import{i as T}from"../packem_shared/deploy-target-Dvr9vxpR.mjs";import{i as k,d as b,s as j,r as x}from"../packem_shared/output-format-D7cKB-O5.mjs";import{a as R}from"../packem_shared/platform-diagnostics-C4TFj5Pu.mjs";const v=3,O=r=>{const s=r.cwd??process.cwd(),i=x(r.format),e=j(r.format,r.logger),d=k("codegen",r.format);if(d!==void 0)return r.logger.error(d),{advisories:[],cronTriggers:[],error:d,failedAdvisories:0,outputDirectory:""};const l=S(r),a=T(s,r.target);if(a.target===void 0)return r.logger.error(a.error??"unknown deploy target"),{advisories:[],cronTriggers:[],error:a.error??"unknown deploy target",failedAdvisories:0,outputDirectory:""};const{target:u}=a,o=h({apiSpec:r.apiSpec,projectRoot:s,target:u,wranglerVariables:A(s)}),g={advisories:o.advisories.map(t=>({detail:t.detail,level:t.level,name:t.name,remediation:t.remediation})),cronTriggers:o.cronTriggers,failedAdvisories:0,outputDirectory:o.outputDirectory};if(e.success(`codegen wrote dataModel.ts, api.ts, server.ts to ${o.outputDirectory}`),o.advisories.length>0){const t=o.advisories.length,w=o.advisories.map(n=>` [${n.level}] ${n.name} — ${n.detail}
2
- ↳ ${n.remediation}`);e.warn(`${t.toString()} schema ${t===1?"advisory":"advisories"}:
3
- ${w.join(`
4
- `)}`)}const m=R(o.platformDiagnostics,e);m!==void 0&&(g.error=m);const{errorAdvisories:c,names:f,shouldBlock:$}=y(g.advisories,l);$&&e.error(`${c.length.toString()} ERROR-level ${c.length===1?"advisory":"advisories"} (${f.join(", ")}). Codegen wrote its output; this exit code is the gate. Pass --no-strict-advisories to downgrade it to a warning.`),o.cronTriggers.length>v&&e.warn(`${o.cronTriggers.length.toString()} distinct cron expressions declared — Cloudflare allows at most ${v.toString()} Cron Triggers per Worker. Consolidate schedules (jobs can share one expression) or move finer-grained work to Durable Object alarms via @lunora/scheduler (runAfter/runAt).`);const p={...g,failedAdvisories:l?c.length:0};return i&&b(p),p},F=D(({cwd:r,logger:s,options:i})=>{const e=O({apiSpec:C(i.apiSpec),cwd:r,format:i.format,logger:s,strictAdvisories:i.strictAdvisories,target:i.target});return{code:e.error===void 0&&e.failedAdvisories===0?0:1}});export{F as execute,O as runCodegenCommand};
1
+ import{runCodegen as y}from"@lunora/codegen";import{inferLunoraBindings as A}from"@lunora/config";import{collectWranglerSecretVariables as x,collectExportGaps as S}from"@lunora/config/cloudflare";import{n as b,t as C}from"../packem_shared/advisory-gate-yaOOyUQl.mjs";import{r as D}from"../packem_shared/api-spec-BENwiyUa.mjs";import{i as k}from"../packem_shared/command-Bjv4VmYA.mjs";import{i as T}from"../packem_shared/deploy-target-Dvr9vxpR.mjs";import{i as j,d as R,s as v,r as B}from"../packem_shared/output-format-D7cKB-O5.mjs";import{a as E}from"../packem_shared/platform-diagnostics-C4TFj5Pu.mjs";const u=3,L=r=>{const i=r.cwd??process.cwd(),o=B(r.format),e=v(r.format,r.logger),d=j("codegen",r.format);if(d!==void 0)return r.logger.error(d),{advisories:[],cronTriggers:[],error:d,failedAdvisories:0,outputDirectory:""};const g=C(r),a=T(i,r.target);if(a.target===void 0)return r.logger.error(a.error??"unknown deploy target"),{advisories:[],cronTriggers:[],error:a.error??"unknown deploy target",failedAdvisories:0,outputDirectory:""};const{target:f}=a,t=y({apiSpec:r.apiSpec,projectRoot:i,target:f,wranglerVariables:x(i)}),c={advisories:t.advisories.map(s=>({detail:s.detail,level:s.level,name:s.name,remediation:s.remediation})),cronTriggers:t.cronTriggers,failedAdvisories:0,outputDirectory:t.outputDirectory};if(e.success(`codegen wrote dataModel.ts, api.ts, server.ts to ${t.outputDirectory}`),t.advisories.length>0){const s=t.advisories.length,h=t.advisories.map(n=>` [${n.level}] ${n.name} — ${n.detail}
2
+ ↳ ${n.remediation}`);e.warn(`${s.toString()} schema ${s===1?"advisory":"advisories"}:
3
+ ${h.join(`
4
+ `)}`)}const p=E(t.platformDiagnostics,e);p!==void 0&&(c.error=p);const{errorAdvisories:l,names:w,shouldBlock:$}=b(c.advisories,g);$&&e.error(`${l.length.toString()} ERROR-level ${l.length===1?"advisory":"advisories"} (${w.join(", ")}). Codegen wrote its output; this exit code is the gate. Pass --no-strict-advisories to downgrade it to a warning.`),t.cronTriggers.length>u&&e.warn(`${t.cronTriggers.length.toString()} distinct cron expressions declared — Cloudflare allows at most ${u.toString()} Cron Triggers per Worker. Consolidate schedules (jobs can share one expression) or move finer-grained work to Durable Object alarms via @lunora/scheduler (runAfter/runAt).`);const m={...c,failedAdvisories:g?l.length:0};return o&&R(m),m},N=async(r,i)=>{let o;try{o=S(await A({projectRoot:r}))}catch{return}for(const e of o)i.warn(`${e.kind} "${e.exportName}" is declared but ${e.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/${e.module}"\` so wrangler can provision its binding. Until then it deploys with nothing to run.`)},q=k(async({cwd:r,logger:i,options:o})=>{const e=L({apiSpec:D(o.apiSpec),cwd:r,format:o.format,logger:i,strictAdvisories:o.strictAdvisories,target:o.target});return e.outputDirectory!==""&&await N(r,v(o.format,i)),{code:e.error===void 0&&e.failedAdvisories===0?0:1}});export{q as execute,L as runCodegenCommand};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/cli",
3
- "version": "1.0.0-alpha.142",
3
+ "version": "1.0.0-alpha.144",
4
4
  "description": "The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -54,10 +54,10 @@
54
54
  "@bomb.sh/tab": "0.0.21",
55
55
  "@lunora/advisor": "1.0.0-alpha.67",
56
56
  "@lunora/bindings": "1.0.0-alpha.20",
57
- "@lunora/codegen": "1.0.0-alpha.90",
58
- "@lunora/config": "1.0.0-alpha.118",
57
+ "@lunora/codegen": "1.0.0-alpha.91",
58
+ "@lunora/config": "1.0.0-alpha.120",
59
59
  "@lunora/container": "1.0.0-alpha.23",
60
- "@lunora/d1": "1.0.0-alpha.63",
60
+ "@lunora/d1": "1.0.0-alpha.64",
61
61
  "@lunora/errors": "1.0.0-alpha.14",
62
62
  "@lunora/mcp": "1.0.0-alpha.57",
63
63
  "@lunora/runtime": "1.0.0-alpha.53",