@lunora/cli 1.0.0-alpha.471 → 1.0.0-alpha.473
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,6 +1,8 @@
|
|
|
1
|
-
import{readServiceBindings as
|
|
2
|
-
${
|
|
3
|
-
${
|
|
4
|
-
${
|
|
5
|
-
${
|
|
6
|
-
`)),n.length>0&&o.write(n),o.pipe(r),r.pipe(o)});o.setTimeout(Nr,()=>o.destroy()),o.on("error",()=>r.destroy()),r.on("error",()=>o.destroy())},Wr=async e=>{const r=e.host??"127.0.0.1",n=r==="127.0.0.1"||r==="localhost"||r==="::1",t=new URL(e.workerOrigin);let o=F(e.logger,import.meta.url),i=I(import.meta.url);const l=je(e.cwd,()=>Buffer.from(Ne({adminToken:n?Me(e.cwd):void 0,basePath:"/",dataEditable:n,rulesInstalled:B(e.cwd).installed,runAsIdentity:n,schemaEditable:n,scriptSrc:"/studio.js",styleHref:"/styles.css"}))),s=(c,d,f,g,y)=>{Ke(c,d,f,g,y,i)},a=(c,d,f)=>{c.statusCode=d,c.setHeader("Content-Type","text/plain"),c.end(f)},u=(c,d,f,g)=>{if(n){Ve(c,d,f,e.cwd,{apiSpec:e.apiSpec,lazyFunctions:k(e.lazyFunctions)});return}a(d,403,g)},b=(c,d,f)=>{const g=c==="/styles.css",y=Be(c);if(!g&&!y)return!1;const S=I(import.meta.url);if(S!==i&&(o=F(e.logger,import.meta.url),i=S),o===void 0)return a(f,501,"Lunora studio assets not found — install and build @lunora/studio."),!0;if(g)return s(d,f,o.styles,"text/css; charset=utf-8","styles.css"),!0;const p=c.slice(c.lastIndexOf("/")+1),_=ze(p,import.meta.url);return _===void 0?(a(f,404,"Not found"),!0):(s(d,f,_,Ge(p),p),!0)};l();const w=tr((c,d)=>{const f=L(c.url??"/");if(n){const y=j(c,e.logger);if(y!==void 0){a(d,403,y);return}}if(f.startsWith(x)){if(!n){a(d,403,"Lunora studio: the worker admin proxy is only available on a loopback bind.");return}U(c,d,t);return}if(f===We){u(c,d,Xe,"Lunora schema editing is only available on loopback hosts in dev.");return}if(f===He){u(c,d,Je,"Lunora policy scaffolding is only available on loopback hosts in dev.");return}if(f===xe){u(c,d,Ye,"Lunora data seeding is only available on loopback hosts in dev.");return}if(b(f,c,d))return;const g=c.headers["sec-fetch-mode"];if(n&&typeof g=="string"&&g!=="navigate"){U(c,d,t);return}Ue(d,l())});return w.on("upgrade",(c,d,f)=>{if(!n||j(c,e.logger)!==void 0){d.destroy();return}L(c.url??"").startsWith(x)?Mr(c,d,f,t):d.destroy()}),await new Promise((c,d)=>{w.once("error",f=>{f.code==="EADDRINUSE"?d(new Error(`studio port ${String(e.port)} is already in use — pass a different port with --port, or stop the process using it`,{cause:f})):d(f)}),w.listen(e.port,r,()=>{c()})}),{close:()=>new Promise(c=>{w.close(()=>{c()})}),url:`http://${r==="0.0.0.0"||r==="::"?"localhost":r}:${String(e.port)}`}},Hr=async e=>{const{cwd:r,logger:n,origin:t,signal:o}=e,i=e.probe??dr,l=cr(e.readyTimeoutMs),s=Date.now()+l,a=()=>o.aborted;for(;!a()&&Date.now()<s;){let u=!1;try{u=await i(t,o)}catch{}if(a()||Date.now()>=s)break;if(u)return z(r,{readyAt:new Date().toISOString()},{expectedPid:process.pid}),ce(r)?.readyAt!==void 0;try{await sr(lr,void 0,{signal:o})}catch{}}return a()||n.warn(`server did not answer on ${t} within ${String(Math.round(l/1e3))}s — .lunora/dev.json will have no readyAt, so anything polling for readiness will keep waiting. The server itself is unaffected; raise LUNORA_DEV_READY_TIMEOUT_MS if it is just slow to boot.`),!1},xr=(e,r,n,t)=>{e.info(""),e.success("Lunora dev"),e.info(` ➜ Worker: ${r.workerOrigin}`),n!==void 0&&e.info(` ➜ Studio: ${n}`),r.runsCodegenWatch&&e.info(" ➜ Codegen: watching lunora/"),t!==void 0&&e.info(` ➜ Supervisor: ${t} (needs) · ${J} (status)`),r.remote.enabled&&(r.remote.bindings.length>0?e.info(` ➜ Remote: ${r.remote.bindings.join(", ")} → deployed worker`):r.remote.reason!==void 0&&e.warn(` ➜ Remote: requested but inactive (${r.remote.reason}) — running fully local`));for(const o of r.remote.withheld)e.warn(` ➜ ${Ce(o)}`);e.info("")},Ur=(e,r)=>{B(r).installed||!Pe()||(e.info(` ⓘ ${Re}`),e.info(""))},Vr=async(e,r,n)=>{let t;try{t=me(await we({cache:n,projectRoot:r,schemaDir:he(r)}))}catch{}if(t!==void 0)try{const i=(e.ensureExample??ye)(r,t);if(i.length>0){const l=t.map(s=>s.includes(":")?`${s.replace(":"," (")})`:s);e.logger.info(`Updated .dev.vars.example with secrets for: ${l.join(", ")} (${i.join(", ")})`)}}catch{}(await(e.ensureEnv??Se)({confirm:ir(),cwd:r,info:i=>{e.logger.info(i)}})).status==="declined"&&!pe()&&e.logger.info(`hint: ${$} was not scaffolded (non-interactive run). Copy ${Ee} → ${$} and fill in secrets, or run \`lunora dev\` in an interactive terminal to scaffold automatically.`);try{(e.fillSecrets??be)({cwd:r,secretSources:t,info:i=>{e.logger.info(i)}})}catch{}},Br=(e,r,n,t,o)=>{if(e.flavor!=="wrangler")return;t!==void 0&&z(r,{studioUrl:t});let i;try{i=kr(r,n)}catch{}return xr(n,e,t,o),i},zr=(e,r)=>{const n=Number(process.env[T]),t=ge(r,{background:process.env[G]==="1",logFile:process.env[ve],mode:"cli",pid:process.pid,startedAt:new Date().toISOString(),url:e.workerOrigin},Number.isInteger(n)&&n>0?{supersedePid:n}:void 0);return t.ok?void 0:t.existing},Gr=e=>{const{cwd:r,destination:n,logger:t,plan:o}=e,i=n!==void 0,l=n??_e,s=Ae({destination:l,dev:{...o.flavor==="wrangler"?{origin:o.workerOrigin}:{},statusFile:J},logger:i?t:{...t,success:()=>{},warn:()=>{}},projectRoot:r});return s.error!==void 0?i?s:(t.debug?.(`skipped the default binding manifest: ${s.error}`),{}):{written:l}},Xr=async(e,r,n,t)=>{if(r.studioEnabled)try{return await(e.startStudio??Wr)({apiSpec:e.apiSpec,lazyFunctions:k(e.lazyFunctions),cwd:n,logger:{warnOnce:o=>{t.warn(o)}},port:r.studioPort,workerOrigin:r.workerOrigin})}catch(o){t.warn(`studio server failed to start (${o instanceof Error?o.message:String(o)}) — continuing without it`);return}},Jr=e=>{const r=[e.runsCodegenWatch?"codegen watch":void 0,e.studioEnabled?"studio":void 0].filter(t=>t!==void 0);return`--no-worker: not starting wrangler. ${r.length>0?`${r.join(" + ")} running`:"nothing else to run"}; your task runner owns the worker on ${e.workerOrigin}.`},Yr=(e,r,n,t,o)=>{if(!(e.sidecar===void 0||!br(r)))try{V({apiSpec:r.apiSpec,lazyFunctions:k(r.lazyFunctions),lunoraDirectory:"lunora",projectRoot:n,target:o,...Y(n)})}catch(i){t.warn(`codegen (pre-sidecar) failed: ${i instanceof Error?i.message:String(i)} — the framework dev server will retry`)}},Kr=e=>e.flavor==="vite"?"starting vite dev (worker + studio + codegen run inside Vite via @lunora/vite)":`starting ${e.wrangler.tag} dev + studio`,Qr=(e,r)=>{e.ipv4LoopbackForced&&r.info("no IPv6 loopback (::1) on this host — binding the worker to 127.0.0.1 (--ip) so wrangler dev doesn't crash. Pin `dev.ip` in wrangler.jsonc to override.")},Zr=async(e,r,n,t)=>{if(e.celldSession!==!0||e.workerEnabled)return!0;try{for(const o of await(r.writeCelldProjection??ke)({projectRoot:n}))t.warn(o);return!0}catch(o){return t.error(`could not write the celld projection: ${o instanceof Error?o.message:String(o)}`),!1}},qr=async(e,r,n,t,o)=>{try{return e.celldSession===!0?await _r({logger:o,port:e.workerPort,projectRoot:t,start:r.startCelldSession}):n(e.wrangler,o)}catch(i){o.error(`could not start the worker: ${i instanceof Error?i.message:String(i)}`);return}},et=async(e,r,n)=>{const t=await(e.startHyperdrive??Te)({onWarning:o=>{n.warn(o)},projectRoot:r});return t!==void 0&&t.bindings.length>0&&n.info(`Hyperdrive ${t.bindings.join(", ")}: embedded Postgres (PGlite), data in .wrangler/state/lunora-pglite. Set CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_<BINDING> to use your own.`),t},rt=async e=>{const{logger:r}=e,n=ue(),t=e.cwd??process.cwd(),o=e.flavor??vr(t),i=er(t,e.target);if(i.target===void 0)throw new Error(i.error??"unknown deploy target");const{target:l}=i,s=mr(l,o,r);s==="wrangler"&&await Pr(t,r,void 0,l,void 0,n);const a=await wr({...e,flavor:s,target:l}),u={remoteCleanup:a.remote.cleanup,serviceConfigCleanup:a.serviceConfigCleanup};try{const b=Number(process.env[T]),w=X(t);if(w!==void 0&&w.pid!==process.pid&&w.pid!==b)return C(r,w),{code:0,plan:a};const c=zr(a,t);if(c!==void 0)return C(r,c),{code:0,plan:a};(a.flavor==="vite"||a.flavor==="framework-worker")&&(a.wrangler.env={...a.wrangler.env,[T]:String(process.pid)}),a.workerEnabled&&l==="cloudflare"&&(u.hyperdrive=await et(e,t,r)),await Vr(e,t,n),r.info(Kr(a)),hr(r,t),Qr(a,r),a.runsCodegenWatch&&(u.codegen=(e.startCodegen??Lr)({apiSpec:e.apiSpec,lazyFunctions:k(e.lazyFunctions),jsonLogs:e.jsonLogs,logger:r,projectRoot:t,target:l})),u.studio=await Xr(e,a,t,r);const d=Gr({cwd:t,destination:e.emitBindings,logger:r,plan:a});if(d.error!==void 0)return r.error(d.error),{code:R.USAGE,plan:a};await u.codegen?.ready;const f=u.studio?.url;a.frameworkHint!==void 0&&r.warn(a.frameworkHint);const g=()=>{a.flavor==="wrangler"&&(u.readyProbe=new AbortController,Hr({cwd:t,logger:r,origin:a.workerOrigin,probe:e.probeReady,signal:u.readyProbe.signal}))};if(!await Zr(a,e,t,r))return{code:R.FAILURE,plan:a};if(!a.workerEnabled)return g(),r.info(Jr(a)),u.tunnel=M({cwd:t,logger:r,plan:a,tunnel:e.tunnel}),{code:await(e.waitForInterrupt??yr)(r),plan:a};Yr(a,e,t,r,l);const y=e.startWorker??Sr,S=await qr(a,e,y,t,r);if(S===void 0)return{code:R.FAILURE,plan:a};const p=a.sidecar===void 0?void 0:y(a.sidecar,r);return g(),u.containerLogs=Br(a,t,r,f,d.written),u.tunnel=M({cwd:t,logger:r,plan:a,tunnel:e.tunnel}),Ur(r,t),{code:await pr(S,p,r),plan:a}}finally{u.readyProbe?.abort(),fe(t,process.pid),await Er(u)}},tt=e=>({codegen:e.codegen===!1?!1:void 0,studio:e.studio===!1?!1:void 0,worker:e.worker===!1?!1:void 0}),nt=e=>{if(e.local===!0&&e.remote===!0)return"`--local` and `--remote` are mutually exclusive — pass at most one.";const{entries:r,invalid:n}=Q(e.allowMail);if(n.length>0)return`\`--allow-mail\` takes email addresses or '*@domain' — not ${n.map(t=>`"${t}"`).join(", ")}.`;if(r.length>0&&e.tunnel!==!0)return"`--allow-mail` only applies to a tunnel — add `--tunnel`."},ot=e=>e.tunnel===!0?{allowMail:Q(e.allowMail).entries}:void 0,Dt=qe(async({argument:e,cwd:r,logger:n,options:t})=>{const o=t.json===!0,i=ur({cwd:r,json:o,lines:t.lines,logger:n,subcommand:e[0]});if(i!==void 0)return i;const l=process.env[G]==="1",s=l?void 0:de(),a=o||s!==void 0;a&&rr(),s!==void 0&&t.background!==!0&&n.info(`AI agent detected (${s.name} via ${s.variable}) — starting the dev server in background mode with JSON logs. Set LUNORA_AGENT_MODE=0 to opt out.`);const u=nt(t);if(u!==void 0)return n.error(`dev: ${u}`),{code:R.USAGE};const b=ot(t),w=t.local===!0?!1:De({configPreference:le(r),envValue:process.env.LUNORA_REMOTE,flag:t.remote});if(!l&&(t.background===!0||s!==void 0)){const c=X(r);return c!==void 0?(C(n,c),{code:0}):(b?.allowMail.length===0&&fr(n),gr({cwd:r,jsonLogs:a,logger:n,options:t,remote:w}))}return rt({apiSpec:$e(t.apiSpec),cwd:r,emitBindings:t.emitBindings,inspectorPort:t.inspectorPort,lazyFunctions:k(t.lazyFunctions),jsonLogs:a,local:t.local,logger:n,port:t.port,remote:w,target:t.target,tunnel:b,workerPort:t.workerPort,...tt(t)})});export{nt as devFlagConflict,Dt as execute,tt as negatableDevFlags,rt as runDevCommand};
|
|
1
|
+
import{projectConfigCandidatePaths as F,readServiceBindings as ge,createCodegenProject as ve,refreshCodegenProject as me,findTsconfig as he,PROJECT_CONFIG_FILENAMES as we,runCodegen as ee}from"@lunora/codegen";import{runPostCodegenHook as ye,resolveLazyFunctions as P,detectAgentRules as te,updateDevServerState as re,readDevServerState as pe,DEV_DAEMON_ENV as ne,detectAiAgent as Se,readProjectRemotePreference as Ee,readLiveDevServerState as oe,createDiscoveryCache as be,DEV_HANDOFF_ENV as I,clearDevServerState as _e,claimDevServerState as ke,DEV_LOG_FILE_ENV as Pe,secretSourcesFromBindings as De,inferLunoraBindings as Te,resolveSchemaDirectory as Re,ensureDevVarsExample as $e,ensureDevVariables as Ce,isInteractive as Ae,DEV_VARS_FILE as H,DEV_VARS_EXAMPLE_FILE as Oe,fillDevSecrets as Fe,DEV_BINDINGS_FILE as Ie,DEV_STATE_FILE as ae,writeCelldDevProjection as Le,claimAgentRulesHint as je,AGENT_RULES_HINT as Ne}from"@lunora/config";import{wranglerCodegenInputs as ie,resolveRemoteEnabled as Me,startLocalHyperdrive as We,describeWithheld as He}from"@lunora/config/cloudflare";import{p as xe}from"../packem_shared/api-spec-lYyq4vL6.mjs";import{w as Ue}from"../packem_shared/binding-manifest-file-CQ1eQYy1.mjs";import{createHash as Ve}from"node:crypto";import{existsSync as N,watch as L,readFileSync as se,statSync as Be}from"node:fs";import{join as k,dirname as M}from"node:path";import{STUDIO_WRITE_TEMP_SUFFIX as ze,consumeStudioWrite as x,loadStudioAssets as U,studioAssetsStamp as V,createStudioDocumentCache as Ge,renderStudioHtml as Xe,resolveAdminToken as Je,requestPathname as B,transportRejectionReason as z,SCHEMA_EDIT_ENDPOINT as Ye,POLICY_SCAFFOLD_ENDPOINT as Ke,SEED_ENDPOINT as Qe,sendStudioDocument as Ze,serveJsonHandler as qe,isStandaloneModulePath as et,readStandaloneAsset as tt,assetContentType as rt,handleSchemaEditRequest as nt,handlePolicyScaffoldRequest as ot,handleSeedRequest as at,sendStudioAsset as it}from"@lunora/config/studio-host";import{ts as G}from"ts-morph";import{a as st}from"../packem_shared/codegen-error-AmH54ofi.mjs";import{a as ct}from"../packem_shared/platform-diagnostics-Cn2g6Jh-.mjs";import{d as dt}from"../packem_shared/command-BpMv2n0o.mjs";import{a as lt}from"../packem_shared/deploy-target-resolve-BTCW1Iv4.mjs";import{EXIT_CODE as $}from"../packem_shared/EXIT_CODE-DQVhSE-1.mjs";import{forceJsonLogging as ut}from"../packem_shared/createLogger-4TujevyB.mjs";import{createServer as ft,request as gt}from"node:http";import{connect as vt}from"node:net";import{pipeline as mt}from"node:stream";import{c as ht}from"../packem_shared/tui-prompts-B3YwUhGw.mjs";import{setTimeout as wt}from"node:timers/promises";import{r as yt,d as pt,P as St,a as Et,b as j,c as bt,s as _t,n as ce,e as kt,f as Pt,g as Dt,h as Tt,i as X,w as Rt,j as $t,k as Ct,t as At,l as Ot,m as Ft,o as It}from"../packem_shared/plan-pog5AvMk.mjs";import{b as Lt}from"./handler.mjs";const jt=100,Nt=/(?:\.[cm]?[jt]sx?|(?:^|[/\\])tsconfig(?:\..+)?\.json)$/u,O=300,J=/[/\\]/u,Y=e=>{try{return se(e,"utf8")}catch{return""}},Mt=e=>{try{const{mtimeMs:t,size:n}=Be(e);return`${String(t)}:${String(n)}`}catch{return""}},Wt=["pnpm-lock.yaml","package-lock.json","yarn.lock","bun.lock","node_modules/.modules.yaml","node_modules/.package-lock.json","node_modules/.yarn-integrity"],de=e=>{const t=M(e);return t===e?[e]:[e,...de(t)]},Ht=e=>{const t={...G.sys,onUnRecoverableConfigFileDiagnostic:()=>{},readDirectory:()=>[]},n=G.getParsedCommandLineOfConfigFile(e,{},t);return n===void 0?"":JSON.stringify(n.options)},xt=(e,t)=>{const n=he(t),o=[...new Set([...F(t),...we.map(s=>k(e,s))])].map(s=>`${s}
|
|
2
|
+
${Y(s)}`),a=de(e).flatMap(s=>Wt.map(i=>`${k(s,i)}
|
|
3
|
+
${Mt(k(s,i))}`));return[n===void 0?"":`${n}
|
|
4
|
+
${Y(n)}
|
|
5
|
+
${Ht(n)}`,...o,...a].join("\0")},Ut=(e,t)=>{let n,r;return{drop:()=>{n=void 0},get:()=>{const o=xt(e,t);return n===void 0||o!==r?(r=o,n=ve(t)):me(n,t),n}}},Vt=(e,t,n,r)=>{const{apiSpec:o,lazyFunctions:a,logger:d,projectRoot:s,target:i}=e;try{const f=ee({apiSpec:o,lazyFunctions:P(a),lunoraDirectory:t,project:r.get(),projectRoot:s,target:i,...ie(s)});d.success(`codegen: wrote ${t}/_generated (${n})`),ct(f.platformDiagnostics,d)}catch(f){return r.drop(),d.error(st(f,n)),!1}return!0},K=e=>{const t=Ve("sha256");for(const n of e){if(t.update(n).update("\0"),N(n)){t.update("present\0");try{t.update(se(n))}catch{t.update("unreadable")}}else t.update("absent");t.update("\0")}return t.digest("hex")},Q=e=>e instanceof Error?e.stack??e.message:String(e),Bt=(e,t,n)=>{const r=[];for(const o of new Set([...e].map(a=>M(a))))if(N(o))try{const a=L(o,(d,s)=>{typeof s!="string"?t(void 0):e.has(k(o,s))&&t(s)});a.on("error",d=>{n(`codegen watch: stopped watching ${o} for lunora.config changes
|
|
6
|
+
${Q(d)}`),a.close()}),r.push(a)}catch(a){n(`codegen watch: could not watch ${o} for lunora.config changes
|
|
7
|
+
${Q(a)}`)}return r},zt=e=>{const t=e.lunoraDirectory??"lunora",n=k(e.projectRoot,t),r=e.debounceMs??jt;let o=!1,a=!1,d=!1,s,i=0,f;const E=F(n);let m=Promise.resolve();const c=Ut(e.projectRoot,n);let l;const g=new Promise(u=>{l=u}),h=(u,v)=>{o||(s={codegen:v||s?.codegen===!0,reason:u},!a&&(a=!0,m=(async()=>{try{for(;s!==void 0;){const w=s;if(s=void 0,w.codegen&&(f=K(E)),!(w.codegen&&!Vt(e,t,w.reason,c))){d=!0;try{(await ye({cwd:e.projectRoot,logger:e.logger,spawner:e.spawner,stdoutToStderr:e.jsonLogs})).ran&&(i=Date.now())}finally{d=!1}}}}catch(w){e.logger.error(`codegen watch: ${w instanceof Error?w.message:String(w)}`)}finally{a=!1,l()}})()))};h("startup",!0);const p=u=>(e.logger.warn(`codegen watch unavailable (${u}) — schema edits will NOT auto-regenerate. Run \`lunora codegen\` manually after each edit.`),{close:()=>(o=!0,s=void 0,m),ready:g,watchAvailable:!1});let y,b;if(!N(n))return p(`no such directory: ${n}`);const _=new Set;let D=!1;const T=(u,v)=>{if(d||Date.now()-i<O){y&&(clearTimeout(y),y=void 0);let w=!1;for(const S of[..._,u])S!==void 0&&x(S)&&(w=!0);_.clear(),D=!1,w&&h(`change: ${v}`,!1);return}u===void 0?D=!0:_.add(u),y&&clearTimeout(y),y=setTimeout(()=>{const w=[..._].map(fe=>x(fe)),S=D||w.includes(!1);_.clear(),D=!1,h(`change: ${v}`,S)},r)},C=[],A=[],le=new Set(F(n));let R;const W=u=>{if(!o){if(!d&&Date.now()-i>=O){clearTimeout(R),(u===void 0||K(E)!==f)&&T(void 0,u??"?");return}clearTimeout(R),R=setTimeout(()=>{W(u)},O)}};try{b=L(n,{recursive:!0},(u,v)=>{if(typeof v!="string"){T(void 0,"?");return}v.split(J).includes("_generated")||v.endsWith(ze)||T(k(n,v),v)});for(const u of ge(e.projectRoot).services)if(u.rpcEntrypoint!==void 0){const v=L(M(u.wranglerPath),{recursive:!0},(w,S)=>{typeof S=="string"&&Nt.test(S)&&!S.split(J).includes("node_modules")&&T(void 0,S)});v.on("error",w=>{e.logger.warn(`codegen watch: stopped watching service "${u.name}" (${w.message})`),v.close()}),C.push(v)}A.push(...Bt(le,u=>{W(u)},u=>{e.logger.warn(u)}))}catch(u){b?.close();for(const v of C)v.close();for(const v of A)v.close();return p(u instanceof Error?u.message:String(u))}const ue=b;return{close:()=>{o=!0,s=void 0,y&&clearTimeout(y),clearTimeout(R),ue.close();for(const u of C)u.close();for(const u of A)u.close();return m},ready:g,watchAvailable:!0}},Z="/_lunora",Gt=3e4,q=(e,t,n,r=Gt)=>{const o=gt({headers:{...e.headers,host:n.host},hostname:n.hostname,method:e.method,path:e.url,port:n.port},a=>{o.setTimeout(0),t.writeHead(a.statusCode??502,a.headers),mt(a,t,()=>{})});o.setTimeout(r,()=>{o.destroy(new Error(`no response within ${String(r)}ms`))}),o.on("error",a=>{if(t.headersSent){t.destroy();return}t.statusCode=a.message.startsWith("no response within")?504:502,t.end(`lunora dev: worker unreachable (${a.message})`)}),t.on("close",()=>{t.writableFinished||o.destroy()}),e.pipe(o)},Xt=5e3,Jt=(e,t,n,r)=>{const o=vt({host:r.hostname,port:Number(r.port)},()=>{o.setTimeout(0);const a=[`${e.method??"GET"} ${e.url??"/"} HTTP/1.1`];for(const[d,s]of Object.entries(e.headers))if(d!=="host")for(const i of Array.isArray(s)?s:[s])i!==void 0&&a.push(`${d}: ${i}`);a.push(`host: ${r.host}`,"",""),o.write(a.join(`\r
|
|
8
|
+
`)),n.length>0&&o.write(n),o.pipe(t),t.pipe(o)});o.setTimeout(Xt,()=>o.destroy()),o.on("error",()=>t.destroy()),t.on("error",()=>o.destroy())},Yt=async e=>{const t=e.host??"127.0.0.1",n=t==="127.0.0.1"||t==="localhost"||t==="::1",r=new URL(e.workerOrigin);let o=U(e.logger,import.meta.url),a=V(import.meta.url);const d=Ge(e.cwd,()=>Buffer.from(Xe({adminToken:n?Je(e.cwd):void 0,basePath:"/",dataEditable:n,rulesInstalled:te(e.cwd).installed,runAsIdentity:n,schemaEditable:n,scriptSrc:"/studio.js",styleHref:"/styles.css"}))),s=(c,l,g,h,p)=>{it(c,l,g,h,p,a)},i=(c,l,g)=>{c.statusCode=l,c.setHeader("Content-Type","text/plain"),c.end(g)},f=(c,l,g,h)=>{if(n){qe(c,l,g,e.cwd,{apiSpec:e.apiSpec,lazyFunctions:P(e.lazyFunctions)});return}i(l,403,h)},E=(c,l,g)=>{const h=c==="/styles.css",p=et(c);if(!h&&!p)return!1;const y=V(import.meta.url);if(y!==a&&(o=U(e.logger,import.meta.url),a=y),o===void 0)return i(g,501,"Lunora studio assets not found — install and build @lunora/studio."),!0;if(h)return s(l,g,o.styles,"text/css; charset=utf-8","styles.css"),!0;const b=c.slice(c.lastIndexOf("/")+1),_=tt(b,import.meta.url);return _===void 0?(i(g,404,"Not found"),!0):(s(l,g,_,rt(b),b),!0)};d();const m=ft((c,l)=>{const g=B(c.url??"/");if(n){const p=z(c,e.logger);if(p!==void 0){i(l,403,p);return}}if(g.startsWith(Z)){if(!n){i(l,403,"Lunora studio: the worker admin proxy is only available on a loopback bind.");return}q(c,l,r);return}if(g===Ye){f(c,l,nt,"Lunora schema editing is only available on loopback hosts in dev.");return}if(g===Ke){f(c,l,ot,"Lunora policy scaffolding is only available on loopback hosts in dev.");return}if(g===Qe){f(c,l,at,"Lunora data seeding is only available on loopback hosts in dev.");return}if(E(g,c,l))return;const h=c.headers["sec-fetch-mode"];if(n&&typeof h=="string"&&h!=="navigate"){q(c,l,r);return}Ze(l,d())});return m.on("upgrade",(c,l,g)=>{if(!n||z(c,e.logger)!==void 0){l.destroy();return}B(c.url??"").startsWith(Z)?Jt(c,l,g,r):l.destroy()}),await new Promise((c,l)=>{m.once("error",g=>{g.code==="EADDRINUSE"?l(new Error(`studio port ${String(e.port)} is already in use — pass a different port with --port, or stop the process using it`,{cause:g})):l(g)}),m.listen(e.port,t,()=>{c()})}),{close:()=>new Promise(c=>{m.close(()=>{c()})}),url:`http://${t==="0.0.0.0"||t==="::"?"localhost":t}:${String(e.port)}`}},Kt=async e=>{const{cwd:t,logger:n,origin:r,signal:o}=e,a=e.probe??pt,d=yt(e.readyTimeoutMs),s=Date.now()+d,i=()=>o.aborted;for(;!i()&&Date.now()<s;){let f=!1;try{f=await a(r,o)}catch{}if(i()||Date.now()>=s)break;if(f)return re(t,{readyAt:new Date().toISOString()},{expectedPid:process.pid}),pe(t)?.readyAt!==void 0;try{await wt(St,void 0,{signal:o})}catch{}}return i()||n.warn(`server did not answer on ${r} within ${String(Math.round(d/1e3))}s — .lunora/dev.json will have no readyAt, so anything polling for readiness will keep waiting. The server itself is unaffected; raise LUNORA_DEV_READY_TIMEOUT_MS if it is just slow to boot.`),!1},Qt=(e,t,n,r)=>{e.info(""),e.success("Lunora dev"),e.info(` ➜ Worker: ${t.workerOrigin}`),n!==void 0&&e.info(` ➜ Studio: ${n}`),t.runsCodegenWatch&&e.info(" ➜ Codegen: watching lunora/"),r!==void 0&&e.info(` ➜ Supervisor: ${r} (needs) · ${ae} (status)`),t.remote.enabled&&(t.remote.bindings.length>0?e.info(` ➜ Remote: ${t.remote.bindings.join(", ")} → deployed worker`):t.remote.reason!==void 0&&e.warn(` ➜ Remote: requested but inactive (${t.remote.reason}) — running fully local`));for(const o of t.remote.withheld)e.warn(` ➜ ${He(o)}`);e.info("")},Zt=(e,t)=>{te(t).installed||!je()||(e.info(` ⓘ ${Ne}`),e.info(""))},qt=async(e,t,n)=>{let r;try{r=De(await Te({cache:n,projectRoot:t,schemaDir:Re(t)}))}catch{}if(r!==void 0)try{const a=(e.ensureExample??$e)(t,r);if(a.length>0){const d=r.map(s=>s.includes(":")?`${s.replace(":"," (")})`:s);e.logger.info(`Updated .dev.vars.example with secrets for: ${d.join(", ")} (${a.join(", ")})`)}}catch{}(await(e.ensureEnv??Ce)({confirm:ht(),cwd:t,info:a=>{e.logger.info(a)}})).status==="declined"&&!Ae()&&e.logger.info(`hint: ${H} was not scaffolded (non-interactive run). Copy ${Oe} → ${H} and fill in secrets, or run \`lunora dev\` in an interactive terminal to scaffold automatically.`);try{(e.fillSecrets??Fe)({cwd:t,secretSources:r,info:a=>{e.logger.info(a)}})}catch{}},er=(e,t,n,r,o)=>{if(e.flavor!=="wrangler")return;r!==void 0&&re(t,{studioUrl:r});let a;try{a=It(t,n)}catch{}return Qt(n,e,r,o),a},tr=(e,t)=>{const n=Number(process.env[I]),r=ke(t,{background:process.env[ne]==="1",logFile:process.env[Pe],mode:"cli",pid:process.pid,startedAt:new Date().toISOString(),url:e.workerOrigin},Number.isInteger(n)&&n>0?{supersedePid:n}:void 0);return r.ok?void 0:r.existing},rr=e=>{const{cwd:t,destination:n,logger:r,plan:o}=e,a=n!==void 0,d=n??Ie,s=Ue({destination:d,dev:{...o.flavor==="wrangler"?{origin:o.workerOrigin}:{},statusFile:ae},logger:a?r:{...r,success:()=>{},warn:()=>{}},projectRoot:t});return s.error!==void 0?a?s:(r.debug?.(`skipped the default binding manifest: ${s.error}`),{}):{written:d}},nr=async(e,t,n,r)=>{if(t.studioEnabled)try{return await(e.startStudio??Yt)({apiSpec:e.apiSpec,lazyFunctions:P(e.lazyFunctions),cwd:n,logger:{warnOnce:o=>{r.warn(o)}},port:t.studioPort,workerOrigin:t.workerOrigin})}catch(o){r.warn(`studio server failed to start (${o instanceof Error?o.message:String(o)}) — continuing without it`);return}},or=e=>{const t=[e.runsCodegenWatch?"codegen watch":void 0,e.studioEnabled?"studio":void 0].filter(r=>r!==void 0);return`--no-worker: not starting wrangler. ${t.length>0?`${t.join(" + ")} running`:"nothing else to run"}; your task runner owns the worker on ${e.workerOrigin}.`},ar=(e,t,n,r,o)=>{if(!(e.sidecar===void 0||!Ot(t)))try{ee({apiSpec:t.apiSpec,lazyFunctions:P(t.lazyFunctions),lunoraDirectory:"lunora",projectRoot:n,target:o,...ie(n)})}catch(a){r.warn(`codegen (pre-sidecar) failed: ${a instanceof Error?a.message:String(a)} — the framework dev server will retry`)}},ir=e=>e.flavor==="vite"?"starting vite dev (worker + studio + codegen run inside Vite via @lunora/vite)":`starting ${e.wrangler.tag} dev + studio`,sr=(e,t)=>{e.ipv4LoopbackForced&&t.info("no IPv6 loopback (::1) on this host — binding the worker to 127.0.0.1 (--ip) so wrangler dev doesn't crash. Pin `dev.ip` in wrangler.jsonc to override.")},cr=async(e,t,n,r)=>{if(e.celldSession!==!0||e.workerEnabled)return!0;try{for(const o of await(t.writeCelldProjection??Le)({projectRoot:n}))r.warn(o);return!0}catch(o){return r.error(`could not write the celld projection: ${o instanceof Error?o.message:String(o)}`),!1}},dr=async(e,t,n,r,o)=>{try{return e.celldSession===!0?await Ft({logger:o,port:e.workerPort,projectRoot:r,start:t.startCelldSession}):n(e.wrangler,o)}catch(a){o.error(`could not start the worker: ${a instanceof Error?a.message:String(a)}`);return}},lr=async(e,t,n)=>{const r=await(e.startHyperdrive??We)({onWarning:o=>{n.warn(o)},projectRoot:t});return r!==void 0&&r.bindings.length>0&&n.info(`Hyperdrive ${r.bindings.join(", ")}: embedded Postgres (PGlite), data in .wrangler/state/lunora-pglite. Set CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_<BINDING> to use your own.`),r},ur=async e=>{const{logger:t}=e,n=be(),r=e.cwd??process.cwd(),o=e.flavor??kt(r),a=lt(r,e.target);if(a.target===void 0)throw new Error(a.error??"unknown deploy target");const{target:d}=a,s=Pt(d,o,t);s==="wrangler"&&await Lt(r,t,void 0,d,void 0,n);const i=await Dt({...e,flavor:s,target:d}),f={remoteCleanup:i.remote.cleanup,serviceConfigCleanup:i.serviceConfigCleanup};try{const E=Number(process.env[I]),m=oe(r);if(m!==void 0&&m.pid!==process.pid&&m.pid!==E)return j(t,m),{code:0,plan:i};const c=tr(i,r);if(c!==void 0)return j(t,c),{code:0,plan:i};(i.flavor==="vite"||i.flavor==="framework-worker")&&(i.wrangler.env={...i.wrangler.env,[I]:String(process.pid)}),i.workerEnabled&&d==="cloudflare"&&(f.hyperdrive=await lr(e,r,t)),await qt(e,r,n),t.info(ir(i)),Tt(t,r),sr(i,t),i.runsCodegenWatch&&(f.codegen=(e.startCodegen??zt)({apiSpec:e.apiSpec,lazyFunctions:P(e.lazyFunctions),jsonLogs:e.jsonLogs,logger:t,projectRoot:r,target:d})),f.studio=await nr(e,i,r,t);const l=rr({cwd:r,destination:e.emitBindings,logger:t,plan:i});if(l.error!==void 0)return t.error(l.error),{code:$.USAGE,plan:i};await f.codegen?.ready;const g=f.studio?.url;i.frameworkHint!==void 0&&t.warn(i.frameworkHint);const h=()=>{i.flavor==="wrangler"&&(f.readyProbe=new AbortController,Kt({cwd:r,logger:t,origin:i.workerOrigin,probe:e.probeReady,signal:f.readyProbe.signal}))};if(!await cr(i,e,r,t))return{code:$.FAILURE,plan:i};if(!i.workerEnabled)return h(),t.info(or(i)),f.tunnel=X({cwd:r,logger:t,plan:i,tunnel:e.tunnel}),{code:await(e.waitForInterrupt??Rt)(t),plan:i};ar(i,e,r,t,d);const p=e.startWorker??$t,y=await dr(i,e,p,r,t);if(y===void 0)return{code:$.FAILURE,plan:i};const b=i.sidecar===void 0?void 0:p(i.sidecar,t);return h(),f.containerLogs=er(i,r,t,g,l.written),f.tunnel=X({cwd:r,logger:t,plan:i,tunnel:e.tunnel}),Zt(t,r),{code:await Ct(y,b,t),plan:i}}finally{f.readyProbe?.abort(),_e(r,process.pid),await At(f)}},fr=e=>({codegen:e.codegen===!1?!1:void 0,studio:e.studio===!1?!1:void 0,worker:e.worker===!1?!1:void 0}),gr=e=>{if(e.local===!0&&e.remote===!0)return"`--local` and `--remote` are mutually exclusive — pass at most one.";const{entries:t,invalid:n}=ce(e.allowMail);if(n.length>0)return`\`--allow-mail\` takes email addresses or '*@domain' — not ${n.map(r=>`"${r}"`).join(", ")}.`;if(t.length>0&&e.tunnel!==!0)return"`--allow-mail` only applies to a tunnel — add `--tunnel`."},vr=e=>e.tunnel===!0?{allowMail:ce(e.allowMail).entries}:void 0,Mr=dt(async({argument:e,cwd:t,logger:n,options:r})=>{const o=r.json===!0,a=Et({cwd:t,json:o,lines:r.lines,logger:n,subcommand:e[0]});if(a!==void 0)return a;const d=process.env[ne]==="1",s=d?void 0:Se(),i=o||s!==void 0;i&&ut(),s!==void 0&&r.background!==!0&&n.info(`AI agent detected (${s.name} via ${s.variable}) — starting the dev server in background mode with JSON logs. Set LUNORA_AGENT_MODE=0 to opt out.`);const f=gr(r);if(f!==void 0)return n.error(`dev: ${f}`),{code:$.USAGE};const E=vr(r),m=r.local===!0?!1:Me({configPreference:Ee(t),envValue:process.env.LUNORA_REMOTE,flag:r.remote});if(!d&&(r.background===!0||s!==void 0)){const c=oe(t);return c!==void 0?(j(n,c),{code:0}):(E?.allowMail.length===0&&bt(n),_t({cwd:t,jsonLogs:i,logger:n,options:r,remote:m}))}return ur({apiSpec:xe(r.apiSpec),cwd:t,emitBindings:r.emitBindings,inspectorPort:r.inspectorPort,lazyFunctions:P(r.lazyFunctions),jsonLogs:i,local:r.local,logger:n,port:r.port,remote:m,target:r.target,tunnel:E,workerPort:r.workerPort,...fr(r)})});export{gr as devFlagConflict,Mr as execute,fr as negatableDevFlags,ur as runDevCommand};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.473",
|
|
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",
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"@bomb.sh/tab": "0.0.22",
|
|
59
59
|
"@lunora/advisor": "1.0.0-alpha.284",
|
|
60
60
|
"@lunora/bindings": "1.0.0-alpha.150",
|
|
61
|
-
"@lunora/codegen": "1.0.0-alpha.
|
|
62
|
-
"@lunora/config": "1.0.0-alpha.
|
|
61
|
+
"@lunora/codegen": "1.0.0-alpha.392",
|
|
62
|
+
"@lunora/config": "1.0.0-alpha.449",
|
|
63
63
|
"@lunora/container": "1.0.0-alpha.108",
|
|
64
64
|
"@lunora/d1": "1.0.0-alpha.230",
|
|
65
65
|
"@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
|
|
66
66
|
"@lunora/mcp": "1.0.0-alpha.288",
|
|
67
67
|
"@lunora/runtime": "1.0.0-alpha.272",
|
|
68
|
-
"@lunora/seed": "1.0.0-alpha.
|
|
68
|
+
"@lunora/seed": "1.0.0-alpha.279",
|
|
69
69
|
"@lunora/wire": "1.0.0-alpha.6",
|
|
70
70
|
"@visulima/cerebro": "4.0.1",
|
|
71
71
|
"@visulima/error": "6.1.0",
|