@lunora/cli 1.0.0-alpha.141 → 1.0.0-alpha.143

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.d.mts CHANGED
@@ -144,7 +144,7 @@ interface ImportCommandOptions {
144
144
  logger: Logger;
145
145
  prod?: boolean;
146
146
  /**
147
- * Wrap each line as `{table:<name>,doc:<line>}`. Use when the source NDJSON
147
+ * Wrap each line as `{table:<name>,doc:<line>}`. Use when the source NDJSON
148
148
  * is bare docs from a single table — Convex's `convex import --table users`
149
149
  * shape.
150
150
  */
@@ -161,7 +161,7 @@ interface ImportCommandResult {
161
161
  inserted: number;
162
162
  }
163
163
  /**
164
- * Stream an NDJSON file — or a `npx convex export --path &lt;dir>` directory — in
164
+ * Stream an NDJSON file — or a `npx convex export --path <dir>` directory — in
165
165
  * chunks, POSTing each batch to `/_lunora/admin/import`. The line buffer stays
166
166
  * bounded by `batchSize`, so a multi-GiB source imports without buffering
167
167
  * everything in memory.
@@ -345,13 +345,13 @@ interface DeployCommandOptions {
345
345
  /**
346
346
  * Confirm a production data migration triggered via `--migrate` (the
347
347
  * `migrate up --prod` confirmation the standalone command requires). Without
348
- * it a `--migrate --migrate-url &lt;prod>` deploy refuses to run the migration.
348
+ * it a `--migrate --migrate-url <prod>` deploy refuses to run the migration.
349
349
  */
350
350
  migrateYes?: boolean;
351
351
  /**
352
352
  * Emit the bundled worker to this directory via `wrangler deploy --outdir`
353
353
  * (paired with `dryRun` by `lunora build`). Also writes esbuild metadata to
354
- * `&lt;outDir>/bundle-meta.json`. When unset, no artifact is written.
354
+ * `<outDir>/bundle-meta.json`. When unset, no artifact is written.
355
355
  */
356
356
  outDir?: string;
357
357
  /**
@@ -408,7 +408,7 @@ interface DeployCommandResult {
408
408
  * The `.dev.vars`-shaped filename (never a full path, never a value) a
409
409
  * secret minted during this run was recorded into, when the missing-
410
410
  * secret gate minted one — `.dev.vars` for the default environment, or a
411
- * `.dev.vars.&lt;env>` sibling for an explicit `--env`. `undefined` when
411
+ * `.dev.vars.<env>` sibling for an explicit `--env`. `undefined` when
412
412
  * nothing was minted this run.
413
413
  */
414
414
  mintedSecretsFile?: string;
@@ -638,7 +638,7 @@ declare const runDevCommand: (options: DevCommandOptions) => Promise<{
638
638
  plan: DevCommandPlan;
639
639
  }>;
640
640
  type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
641
- /** True when `manager` is on PATH — probed by running `&lt;manager> --version`. Injectable for tests. */
641
+ /** True when `manager` is on PATH — probed by running `<manager> --version`. Injectable for tests. */
642
642
  type PackageManagerProbe = (manager: PackageManager) => boolean;
643
643
  /** Supported CI providers. */
644
644
  type CiProvider = "github" | "gitlab";
@@ -901,12 +901,12 @@ interface InitCommandOptions {
901
901
  logger: Logger;
902
902
  name?: string;
903
903
  /**
904
- * Local directory holding create-vite bases (one `template-&lt;id>/` subdir per
904
+ * Local directory holding create-vite bases (one `template-<id>/` subdir per
905
905
  * framework). When set with `vite`, the overlay copies the base from disk
906
906
  * instead of fetching `create-vite` over the network — offline mode + tests.
907
907
  */
908
908
  overlayBaseFrom?: string;
909
- /** Probe for which package managers are installed (tests). Defaults to a real `&lt;pm> --version` check. */
909
+ /** Probe for which package managers are installed (tests). Defaults to a real `<pm> --version` check. */
910
910
  packageManagerProbe?: PackageManagerProbe;
911
911
  /**
912
912
  * Inject the offer's prompts (tests). When set, the offer is treated as
@@ -926,7 +926,7 @@ interface InitCommandOptions {
926
926
  registrySource?: string;
927
927
  /**
928
928
  * Override the remote source giget downloads from. Default:
929
- * `gh:anolilab/lunora/templates/&lt;templateType>#&lt;ref>`, where `&lt;ref>` is
929
+ * `gh:anolilab/lunora/templates/<templateType>#<ref>`, where `<ref>` is
930
930
  * the `ref` option when set, else derived from the CLI version (pre-release
931
931
  * channels → their branch, stable → `main`). Tests typically use `from`
932
932
  * instead to skip the network.
@@ -1022,7 +1022,7 @@ type InsertSchemaExtensionResult = {
1022
1022
  reason: "already-applied" | "invalid-identifier" | "no-define-schema" | "non-object-argument";
1023
1023
  };
1024
1024
  /**
1025
- * Append `.extend(&lt;key>.extension)` and a managed import to an existing
1025
+ * Append `.extend(<key>.extension)` and a managed import to an existing
1026
1026
  * `lunora/schema.ts`. Idempotent: a second call for the same `key` returns
1027
1027
  * `already-applied` and leaves the text unchanged.
1028
1028
  * @param source the current `lunora/schema.ts` contents
package/dist/index.d.ts CHANGED
@@ -144,7 +144,7 @@ interface ImportCommandOptions {
144
144
  logger: Logger;
145
145
  prod?: boolean;
146
146
  /**
147
- * Wrap each line as `{table:&lt;name>,doc:&lt;line>}`. Use when the source NDJSON
147
+ * Wrap each line as `{table:<name>,doc:<line>}`. Use when the source NDJSON
148
148
  * is bare docs from a single table — Convex's `convex import --table users`
149
149
  * shape.
150
150
  */
@@ -161,7 +161,7 @@ interface ImportCommandResult {
161
161
  inserted: number;
162
162
  }
163
163
  /**
164
- * Stream an NDJSON file — or a `npx convex export --path &lt;dir>` directory — in
164
+ * Stream an NDJSON file — or a `npx convex export --path <dir>` directory — in
165
165
  * chunks, POSTing each batch to `/_lunora/admin/import`. The line buffer stays
166
166
  * bounded by `batchSize`, so a multi-GiB source imports without buffering
167
167
  * everything in memory.
@@ -345,13 +345,13 @@ interface DeployCommandOptions {
345
345
  /**
346
346
  * Confirm a production data migration triggered via `--migrate` (the
347
347
  * `migrate up --prod` confirmation the standalone command requires). Without
348
- * it a `--migrate --migrate-url &lt;prod>` deploy refuses to run the migration.
348
+ * it a `--migrate --migrate-url <prod>` deploy refuses to run the migration.
349
349
  */
350
350
  migrateYes?: boolean;
351
351
  /**
352
352
  * Emit the bundled worker to this directory via `wrangler deploy --outdir`
353
353
  * (paired with `dryRun` by `lunora build`). Also writes esbuild metadata to
354
- * `&lt;outDir>/bundle-meta.json`. When unset, no artifact is written.
354
+ * `<outDir>/bundle-meta.json`. When unset, no artifact is written.
355
355
  */
356
356
  outDir?: string;
357
357
  /**
@@ -408,7 +408,7 @@ interface DeployCommandResult {
408
408
  * The `.dev.vars`-shaped filename (never a full path, never a value) a
409
409
  * secret minted during this run was recorded into, when the missing-
410
410
  * secret gate minted one — `.dev.vars` for the default environment, or a
411
- * `.dev.vars.&lt;env>` sibling for an explicit `--env`. `undefined` when
411
+ * `.dev.vars.<env>` sibling for an explicit `--env`. `undefined` when
412
412
  * nothing was minted this run.
413
413
  */
414
414
  mintedSecretsFile?: string;
@@ -638,7 +638,7 @@ declare const runDevCommand: (options: DevCommandOptions) => Promise<{
638
638
  plan: DevCommandPlan;
639
639
  }>;
640
640
  type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
641
- /** True when `manager` is on PATH — probed by running `&lt;manager> --version`. Injectable for tests. */
641
+ /** True when `manager` is on PATH — probed by running `<manager> --version`. Injectable for tests. */
642
642
  type PackageManagerProbe = (manager: PackageManager) => boolean;
643
643
  /** Supported CI providers. */
644
644
  type CiProvider = "github" | "gitlab";
@@ -901,12 +901,12 @@ interface InitCommandOptions {
901
901
  logger: Logger;
902
902
  name?: string;
903
903
  /**
904
- * Local directory holding create-vite bases (one `template-&lt;id>/` subdir per
904
+ * Local directory holding create-vite bases (one `template-<id>/` subdir per
905
905
  * framework). When set with `vite`, the overlay copies the base from disk
906
906
  * instead of fetching `create-vite` over the network — offline mode + tests.
907
907
  */
908
908
  overlayBaseFrom?: string;
909
- /** Probe for which package managers are installed (tests). Defaults to a real `&lt;pm> --version` check. */
909
+ /** Probe for which package managers are installed (tests). Defaults to a real `<pm> --version` check. */
910
910
  packageManagerProbe?: PackageManagerProbe;
911
911
  /**
912
912
  * Inject the offer's prompts (tests). When set, the offer is treated as
@@ -926,7 +926,7 @@ interface InitCommandOptions {
926
926
  registrySource?: string;
927
927
  /**
928
928
  * Override the remote source giget downloads from. Default:
929
- * `gh:anolilab/lunora/templates/&lt;templateType>#&lt;ref>`, where `&lt;ref>` is
929
+ * `gh:anolilab/lunora/templates/<templateType>#<ref>`, where `<ref>` is
930
930
  * the `ref` option when set, else derived from the CLI version (pre-release
931
931
  * channels → their branch, stable → `main`). Tests typically use `from`
932
932
  * instead to skip the network.
@@ -1022,7 +1022,7 @@ type InsertSchemaExtensionResult = {
1022
1022
  reason: "already-applied" | "invalid-identifier" | "no-define-schema" | "non-object-argument";
1023
1023
  };
1024
1024
  /**
1025
- * Append `.extend(&lt;key>.extension)` and a managed import to an existing
1025
+ * Append `.extend(<key>.extension)` and a managed import to an existing
1026
1026
  * `lunora/schema.ts`. Idempotent: a second call for the same `key` returns
1027
1027
  * `already-applied` and leaves the text unchanged.
1028
1028
  * @param source the current `lunora/schema.ts` contents
@@ -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.141",
3
+ "version": "1.0.0-alpha.143",
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",
@@ -52,16 +52,16 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@bomb.sh/tab": "0.0.21",
55
- "@lunora/advisor": "1.0.0-alpha.66",
56
- "@lunora/bindings": "1.0.0-alpha.19",
57
- "@lunora/codegen": "1.0.0-alpha.89",
58
- "@lunora/config": "1.0.0-alpha.117",
59
- "@lunora/container": "1.0.0-alpha.22",
60
- "@lunora/d1": "1.0.0-alpha.62",
61
- "@lunora/errors": "1.0.0-alpha.13",
62
- "@lunora/mcp": "1.0.0-alpha.56",
63
- "@lunora/runtime": "1.0.0-alpha.52",
64
- "@lunora/seed": "1.0.0-alpha.61",
55
+ "@lunora/advisor": "1.0.0-alpha.67",
56
+ "@lunora/bindings": "1.0.0-alpha.20",
57
+ "@lunora/codegen": "1.0.0-alpha.90",
58
+ "@lunora/config": "1.0.0-alpha.119",
59
+ "@lunora/container": "1.0.0-alpha.23",
60
+ "@lunora/d1": "1.0.0-alpha.63",
61
+ "@lunora/errors": "1.0.0-alpha.14",
62
+ "@lunora/mcp": "1.0.0-alpha.57",
63
+ "@lunora/runtime": "1.0.0-alpha.53",
64
+ "@lunora/seed": "1.0.0-alpha.62",
65
65
  "@visulima/cerebro": "3.0.0",
66
66
  "@visulima/error": "6.0.0",
67
67
  "@visulima/fs": "5.0.5",