@arkenv/cli 0.2.11 → 0.3.0

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.
Files changed (2) hide show
  1. package/dist/index.cjs +41 -27
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -110,35 +110,49 @@ ${t?(0,a.styleText)(`cyan`,V):``}
110
110
  outdir: "./dist",
111
111
  ${y.default.green(`plugins: [arkenv]`)}
112
112
  });
113
- `),{success:!0,instructions:a.trim()}}async function It(e,t){let n=t||await J();if(!n)return{status:`not_found`};let i=r.default.basename(n);try{let t=await e.readFile(n);if((0,d.parse)(t)?.compilerOptions?.strict===!0)return{status:`already_strict`,file:i};let r=(0,d.applyEdits)(t,(0,d.modify)(t,[`compilerOptions`,`strict`],!0,{formattingOptions:{insertSpaces:!0,tabSize:2}}));return await e.writeFile(n,r),{status:`updated`,file:i}}catch{return{status:`error`,file:i}}}var Lt=class{constructor(e,t){this.isQuiet=e,this.stdio=t}async exists(e){try{return await n.default.access(e),!0}catch{return!1}}async readFile(e){return n.default.readFile(e,`utf-8`)}async writeFile(e,t){await n.default.writeFile(e,t,`utf-8`)}async mkdir(e,t){await n.default.mkdir(e,{recursive:t})}async execute(e,t=[],n){return new Promise((r,i)=>{let a=(0,l.spawn)(e,t,{cwd:n,stdio:this.isQuiet?`pipe`:this.stdio,shell:!1}),o=``,s=``,c=1e4;this.isQuiet&&(a.stdout?.on(`data`,e=>{o=(o+e.toString()).slice(-c)}),a.stderr?.on(`data`,e=>{s=(s+e.toString()).slice(-c)})),a.on(`close`,(e,t)=>{if(e===0)r();else{let n=e===null?`Command terminated by signal ${t}`:`Command failed with code ${e}`;this.isQuiet&&(o&&(n+=`\n${y.default.dim(`STDOUT:`)}\n${o}`),s&&(n+=`\n${y.default.red(`STDERR:`)}\n${s}`)),i(Error(n))}}),a.on(`error`,i)})}async updateTsConfigToStrict(e){return It(this,e)}async findViteConfig(e){return Ot(e)}async findBunConfig(e){return kt(e)}async findNextjsConfig(e){return At(e)}async findNuxtConfig(e){return Mt(e)}async bootstrapViteConfig(e,t){return Pt(this,e,t)}async bootstrapBunConfig(e,t){return Ft(e,t)}async bootstrapNextjsConfig(e){return jt(this,e)}async bootstrapNuxtConfig(e){return Nt(this,e)}async safeAppend(e,t,n){let{safeAppend:r}=await Promise.resolve().then(()=>p);return r(e,t,n)}};async function Rt(e){let t=e.defaultPath||`./src/env.ts`;if(e.hasEnvSchemaFile){let e=await U({message:y.default.yellow(`An existing ArkEnv configuration was found at ${Y(t)}. Do you want to overwrite it?`),initialValue:!1,active:`Yes (override my configuration)`,inactive:`No (abort)`});return P(e)||!e?null:e}return!0}async function zt(e){let t=e.detectedKeys,n=e.keysSource||`.env.example`;if(t&&t.length>0){let e=t.length,r=e===1,i=await U({message:n===`.env.example`?`Detected ${Y(`.env.example`)} with ${e} ${r?`key`:`keys`}. Use ${r?`it`:`them`} for your schema?`:`Detected ${e} environment variable${r?``:`s`} used in your project. Use ${r?`it`:`them`} for your schema?`,active:`Yes (Recommended)`,initialValue:!0});return P(i)?null:i}return!1}async function Bt(e){if(e.framework===`vite`||e.framework===`bun-fullstack`){let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile)return!0;let n=await U({message:`Establish ${Y(t)} for typesafe environment variables?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No`});return P(n)?null:n}return!0}async function Vt(e){if(!e.installTypeDefinitions||e.framework!==`vite`&&e.framework!==`bun-fullstack`)return`skip`;let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile){let e=await K({message:`Found existing ${Y(t)}. How should we handle ArkEnv types?`,options:[{value:`append`,label:`Append types safely (if needed)`,hint:`Recommended`},{value:`overwrite`,label:`Overwrite entirely`,hint:`Destructive`},{value:`skip`,label:`Skip`}]});return P(e)?null:e}return`overwrite`}async function Ht(e){let t=await K({message:`Select an example:`,options:e.examples.map(e=>({value:e.id,label:e.name,...e.description?{hint:e.description}:{}}))});return P(t)?null:t}async function Ut(e){let t=await K({message:`Select your framework or build tool:`,initialValue:e.framework,options:[{value:`vanilla`,label:`Vanilla${e.framework===`vanilla`?` (Detected)`:``}`,hint:`Node.js, Bun, server-side or runtime-only validation`},{value:`vite`,label:`Vite${e.framework===`vite`?` (Detected)`:``}`,hint:`Client-side and static inlining validation`},{value:`bun-fullstack`,label:`Bun fullstack dev server${e.framework===`bun-fullstack`?` (Detected)`:``}`,hint:`Client-side bundling and Bun.serve integration`},{value:`nextjs`,label:`Next.js${e.framework===`nextjs`?` (Detected)`:``}`,hint:`Next.js App or Pages Router with build and runtime validation`},{value:`nuxt`,label:`Nuxt${e.framework===`nuxt`?` (Detected)`:``}`,hint:`Nuxt with build and runtime validation`}]});return P(t)?null:t}async function Wt(e){let t=await U({message:`Optional: Would you also like to bootstrap a custom Bun.build script for programmatic bundling?`,initialValue:e.initialValue??!1});return P(t)?null:t}async function Gt(){let e=await K({message:`Select your preferred validator library:`,options:[{value:`arktype`,label:`ArkType (Recommended)`,hint:`TypeScript's 1:1 validator, optimized from editor to runtime`},{value:`zod`,label:`Zod`,hint:`TypeScript-first schema validation with static type inference`},{value:`valibot`,label:`Valibot`,hint:`The modular and type safe schema library`}]});return P(e)?null:e}async function Kt(){let e=await K({message:`How would you like to structure your environment variables?`,options:[{value:`simple`,label:`Simple (Recommended)`,hint:`A single env.ts file for the best DX`},{value:`strict`,label:`Strict`,hint:`Separate shared, client, and server files for hard bundle boundaries.`}]});return P(e)?null:e}async function qt(e){let t=await U({message:`Enable automated ${e.framework===`nuxt`?`Nuxt`:`Next.js`} code generation for environment variables?`,initialValue:e.initialValue??!0,active:`Yes (Recommended)`,inactive:`No`});return P(t)?null:t}async function Jt(e){let t=await U({message:`Use default config path (${Y(e.defaultEnvPath||`./src/env.ts`)})?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No, let me customize it`});return P(t)?null:t}async function Yt(e){let t=e.defaultEnvPath||`./src/env.ts`;if(!e.useDefaultPath){let e=await $e({message:`Where should we create the ArkEnv config?`,placeholder:t,initialValue:t,defaultValue:t});if(P(e))return null;let n=typeof e==`string`?e.trim():``;return n===``?t:n}return t}const X={example:Ht,overwriteEnvSchemaFile:Rt,framework:Ut,bunBuild:Wt,layout:Kt,nextjsCodegen:qt,useDefaultPath:Jt,path:Yt,installTypeDefinitions:Bt,envDtsHandling:Vt,validator:Gt,useEnvExample:zt};async function Xt(e,t=!1){return(e?.mode||`existing`)===`new`?Zt(e,t):Qt(e,t)}async function Zt(e,t=!1){let n=e?.examples||[],i=`arkenv-project`;try{let a;if(e?.name){let t=e.name.trim();a=t===`.`||t===`./`||r.default.resolve(process.cwd(),t)===process.cwd()?`.`:t}else if(t)a=i;else{let e=(Z(await $e({message:`Project name:`,placeholder:i,defaultValue:i}))||i).trim();a=e===`.`||e===`./`||r.default.resolve(process.cwd(),e)===process.cwd()?`.`:e}let o=e?.example;!o&&!t?o=Z(await X.example({examples:n})):!o&&t&&(o=`basic`);let s=n.find(e=>e.id===o);if(!s){let e=n.map(e=>e.id).join(`, `);throw Error(`Unknown example ${o}. Available examples: ${e}`)}return{mode:`new`,example:s.id,name:a,path:`./src/env.ts`,validator:`arktype`,framework:s.framework,language:`ts`,installSkill:!1}}catch(e){if(e instanceof en)return null;throw e}}async function Qt(e,n=!1){let r=e?.defaultEnvPath||`./src/env.ts`,i=e?.envKeys||null,a=e?.envKeysSource||`.env.example`;if(n){let n=e?.framework||`vanilla`,a;(n===`nextjs`||n===`nuxt`)&&(a=e?.isStrict?`strict`:(e?.isSimple,`simple`));let o=await $t(e,n,r),s;return(n===`vite`||n===`bun-fullstack`)&&(s=o?`append`:`overwrite`),(0,t.shake)({mode:`existing`,path:r,validator:`arktype`,framework:n,layout:a,bunFeatures:n===`bun-fullstack`?e?.bunFeatures??[`serve`]:void 0,language:`ts`,overwriteEnvSchemaFile:!0,installTypeDefinitions:n===`vite`||n===`bun-fullstack`,installSkill:!1,envDtsHandling:s,envKeys:i??void 0,disableCodegen:e?.disableCodegen??!1,wrapNextjsConfig:n===`nextjs`?!0:void 0})}try{let n=Z(await X.overwriteEnvSchemaFile({hasEnvSchemaFile:e?.hasEnvSchemaFile??!1,defaultPath:r})),o=Z(await X.framework({framework:e?.framework})),s;(o===`nextjs`||o===`nuxt`)&&(s=e?.isStrict?`strict`:e?.isSimple?`simple`:Z(await X.layout()));let c;if(o===`bun-fullstack`){let t=!!e?.bunFeatures?.includes(`build`);c=Z(await X.bunBuild({initialValue:t}))}let l=e?.disableCodegen;o===`nuxt`?l=!0:o===`nextjs`&&l===void 0&&(l=!Z(await X.nextjsCodegen({initialValue:!0,framework:o})));let u;if(o===`nextjs`&&!l){let e=await U({message:`Would you like to wrap your Next.js config with ${Y(`withArkEnv`)}?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No`});if(P(e))throw Ge(`Operation cancelled`),new en;u=e}let d=Z(await X.useDefaultPath({defaultEnvPath:r})),f=Z(await X.path({useDefaultPath:d,defaultEnvPath:r})),p=await $t(e,o,f),m=Z(await X.installTypeDefinitions({framework:o,hasTypeFile:p})),h=Z(await X.envDtsHandling({framework:o,installTypeDefinitions:m,hasTypeFile:p})),g=Z(await X.validator()),_=Z(await X.useEnvExample({detectedKeys:i,keysSource:a}));return(0,t.shake)({mode:`existing`,overwriteEnvSchemaFile:n,framework:o,layout:s,path:f,installTypeDefinitions:m,envDtsHandling:h,validator:g,bunFeatures:o===`bun-fullstack`?c?[`serve`,`build`]:[`serve`]:void 0,language:`ts`,installSkill:!1,envKeys:_?i??void 0:void 0,disableCodegen:l,wrapNextjsConfig:u})}catch(e){if(e instanceof en)return null;throw e}}async function $t(e,t,n){return await e?.hasTypeFileAtPath?.({framework:t,envPath:n})??e?.hasTypeFile??!1}var en=class extends Error{constructor(){super(`Operation cancelled`)}};function Z(e){if(e===null||P(e))throw Ge(`Operation cancelled`),new en;return e}var tn=class{async confirm(e,n=!0,r,i){let a=await U((0,t.shake)({message:e,initialValue:n,active:r,inactive:i}));return P(a)?null:a}async runWizard(e,t=!1){return Xt(e,t)}};const nn={isYes:{long:`--yes`,short:`-y`,kind:`boolean`},isForce:{long:`--force`,short:`-f`,kind:`boolean`},isQuiet:{long:`--quiet`,short:`-q`,kind:`boolean`},isJson:{long:`--json`,short:`-j`,kind:`boolean`},isAgent:{long:`--agent`,short:`-a`,kind:`boolean`},helpRequested:{long:`--help`,short:`-h`,kind:`boolean`},example:{long:`--example`,short:`-e`,kind:`value`},isStrict:{long:`--strict`,short:``,kind:`boolean`},isSimple:{long:`--simple`,short:``,kind:`boolean`},noCodegen:{long:`--no-codegen`,short:`-C`,kind:`boolean`}},rn=new Set(Object.values(nn).flatMap(e=>[e.long,e.short].filter(Boolean))),an=new Set(Object.values(nn).filter(e=>e.kind===`value`).flatMap(e=>[e.long,e.short].filter(Boolean)));var on=class{constructor(e,t={}){let n=e.slice(2),r=[],i=!1;for(let e of n){if(i){r.push(e),i=!1;continue}if(an.has(e)){r.push(e),i=!0;continue}if(/^-[a-zA-Z]{2,}$/.test(e)){let t=e.slice(1).split(``);for(let e of t)r.push(`-${e}`);an.has(`-${t[t.length-1]}`)&&(i=!0)}else r.push(e)}this.args=r,this.command=this.args[0];let a=1,o=[];for(this.validationError=void 0;a<this.args.length;){let e=this.args[a];if(e.startsWith(`-`)){if(!rn.has(e)){this.validationError=`Unknown argument: ${e}`;break}if(an.has(e))if(a+1<this.args.length&&!this.args[a+1].startsWith(`-`))a+=2;else{this.validationError=`Missing value for option: ${e}`;break}else a+=1}else o.push(e),a+=1}this.validationError||(o.length>1?this.validationError=`Unknown argument: ${o[1]}`:this.name=o[0]),this.logger=t.logger||new tt({isQuiet:this.isQuiet,isJson:this.isJson,isYes:this.isYes})}get isAgent(){return this.hasFlag(`isAgent`)}get isYes(){return this.isAgent||this.hasFlag(`isYes`)}get isQuiet(){return this.isAgent||this.hasFlag(`isQuiet`)}get isJson(){return this.isAgent||this.hasFlag(`isJson`)}get isForce(){return this.hasFlag(`isForce`)}get helpRequested(){return this.hasFlag(`helpRequested`)}get example(){let e=nn.example;return this.getFlagValue(e.long,e.short)}get isStrict(){return this.hasFlag(`isStrict`)}get isSimple(){return this.hasFlag(`isSimple`)}get noCodegen(){return this.hasFlag(`noCodegen`)}hasFlag(e){let t=nn[e];return this.args.includes(t.long)||!!t.short&&this.args.includes(t.short)}get initInput(){let e={isYes:this.isYes,isForce:this.isForce,isQuiet:this.isQuiet,isAgent:this.isAgent,isStrict:this.isStrict,isSimple:this.isSimple};return this.example!==void 0&&(e.example=this.example),this.name!==void 0&&(e.name=this.name),this.noCodegen&&(e.noCodegen=!0),e}getFlagValue(e,t){let n=this.args.findIndex(n=>n===e||n===t);if(n!==-1&&this.args[n+1]&&!this.args[n+1].startsWith(`-`))return this.args[n+1]}},sn=`0.2.11`;function cn(e,t=2,n=4){let r=Math.max(...e.map(e=>e.left.length),0),i=` `.repeat(t);return e.map(e=>{let t=` `.repeat(r-e.left.length+n);return`${i}${e.left}${t}${e.right}`})}var ln=class{constructor(e){this.logger=e}async execute(){let e=[{left:`arkenv init [project-name]`,right:`Set up ArkEnv in your project`}],t=[{left:`--yes, -y`,right:`Skip prompts and use defaults (also passed to subprocesses)`},{left:`--force, -f`,right:`Bypass technical requirement checks and dirty git working tree check, then force scaffolding`},{left:`--agent, -a`,right:`Enable non-interactive, machine-readable mode for AI agents. Bypasses all prompts and outputs structured JSON. Macro for --yes --quiet --json`},{left:`--example, -e`,right:`Specify an example name when creating a new project`},{left:`--quiet, -q`,right:`Quiet mode: Suppress output, capture logs on failure`},{left:`--json, -j`,right:`Output structured JSON to stdout`},{left:`--no-codegen, -C`,right:`Disable automatic env.gen.ts code generation for Next.js`},{left:`--help, -h`,right:`Show this help message`}];this.logger.log(`ArkEnv CLI v${sn}`),this.logger.log(`\n${y.default.bold(`Usage:`)}`);for(let t of cn(e))this.logger.log(t);this.logger.log(`\n${y.default.bold(`Options:`)}`);for(let e of cn(t))this.logger.log(e)}};function un(e,t,n,r,i){let{extraImports:a,serverField:o,clientField:s,sharedField:c,defaultServerFields:l,defaultClientFields:u,defaultSharedFields:d}=t,f=i===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`,p=i===`nuxt`?`@arkenv/nuxt`:`@arkenv/nextjs`,m=i===`nuxt`?`Nuxt`:`Next.js`,h=[],g=[],_=[];if(e&&e.length>0)for(let t of e)t.startsWith(f)?g.push(s(t)):t===`NODE_ENV`?_.push(c(t)):h.push(o(t));else h.push(...l),g.push(...u),_.push(...d);let v=[];if(h.length>0&&v.push(`\tserver: {\n${h.join(`
114
- `)}\n\t}`),g.length>0&&v.push(`\tclient: {\n${g.join(`
115
- `)}\n\t}`),_.length>0&&v.push(`\tshared: {\n${_.join(`
116
- `)}\n\t}`),r||i===`nuxt`){let t=[];if(e&&e.length>0)for(let n of e)(n.startsWith(f)||n===`NODE_ENV`)&&t.push(`\t\t${n}: process.env.${n},`);else t.push(`\t\t${f}API_URL: process.env.${f}API_URL,`,` NODE_ENV: process.env.NODE_ENV,`);return i!==`nuxt`&&v.push(`\truntimeEnv: {\n${t.join(`
117
- `)}\n\t}`),`${[`import arkenv from "${p}";`,...a?[a]:[]].join(`
113
+ `),{success:!0,instructions:a.trim()}}async function It(e,t){let n=t||await J();if(!n)return{status:`not_found`};let i=r.default.basename(n);try{let t=await e.readFile(n);if((0,d.parse)(t)?.compilerOptions?.strict===!0)return{status:`already_strict`,file:i};let r=(0,d.applyEdits)(t,(0,d.modify)(t,[`compilerOptions`,`strict`],!0,{formattingOptions:{insertSpaces:!0,tabSize:2}}));return await e.writeFile(n,r),{status:`updated`,file:i}}catch{return{status:`error`,file:i}}}var Lt=class{constructor(e,t){this.isQuiet=e,this.stdio=t}async exists(e){try{return await n.default.access(e),!0}catch{return!1}}async readFile(e){return n.default.readFile(e,`utf-8`)}async writeFile(e,t){await n.default.writeFile(e,t,`utf-8`)}async mkdir(e,t){await n.default.mkdir(e,{recursive:t})}async execute(e,t=[],n){return new Promise((r,i)=>{let a=(0,l.spawn)(e,t,{cwd:n,stdio:this.isQuiet?`pipe`:this.stdio,shell:!1}),o=``,s=``,c=1e4;this.isQuiet&&(a.stdout?.on(`data`,e=>{o=(o+e.toString()).slice(-c)}),a.stderr?.on(`data`,e=>{s=(s+e.toString()).slice(-c)})),a.on(`close`,(e,t)=>{if(e===0)r();else{let n=e===null?`Command terminated by signal ${t}`:`Command failed with code ${e}`;this.isQuiet&&(o&&(n+=`\n${y.default.dim(`STDOUT:`)}\n${o}`),s&&(n+=`\n${y.default.red(`STDERR:`)}\n${s}`)),i(Error(n))}}),a.on(`error`,i)})}async updateTsConfigToStrict(e){return It(this,e)}async findViteConfig(e){return Ot(e)}async findBunConfig(e){return kt(e)}async findNextjsConfig(e){return At(e)}async findNuxtConfig(e){return Mt(e)}async bootstrapViteConfig(e,t){return Pt(this,e,t)}async bootstrapBunConfig(e,t){return Ft(e,t)}async bootstrapNextjsConfig(e){return jt(this,e)}async bootstrapNuxtConfig(e){return Nt(this,e)}async safeAppend(e,t,n){let{safeAppend:r}=await Promise.resolve().then(()=>p);return r(e,t,n)}};async function Rt(e){let t=e.defaultPath||`./src/env.ts`;if(e.hasEnvSchemaFile){let e=await U({message:y.default.yellow(`An existing ArkEnv configuration was found at ${Y(t)}. Do you want to overwrite it?`),initialValue:!1,active:`Yes (override my configuration)`,inactive:`No (abort)`});return P(e)||!e?null:e}return!0}async function zt(e){let t=e.detectedKeys,n=e.keysSource||`.env.example`;if(t&&t.length>0){let e=t.length,r=e===1,i=await U({message:n===`.env.example`?`Detected ${Y(`.env.example`)} with ${e} ${r?`key`:`keys`}. Use ${r?`it`:`them`} for your schema?`:`Detected ${e} environment variable${r?``:`s`} used in your project. Use ${r?`it`:`them`} for your schema?`,active:`Yes (Recommended)`,initialValue:!0});return P(i)?null:i}return!1}async function Bt(e){if(e.framework===`vite`||e.framework===`bun-fullstack`){let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile)return!0;let n=await U({message:`Establish ${Y(t)} for typesafe environment variables?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No`});return P(n)?null:n}return!0}async function Vt(e){if(!e.installTypeDefinitions||e.framework!==`vite`&&e.framework!==`bun-fullstack`)return`skip`;let t=e.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`;if(e.hasTypeFile){let e=await K({message:`Found existing ${Y(t)}. How should we handle ArkEnv types?`,options:[{value:`append`,label:`Append types safely (if needed)`,hint:`Recommended`},{value:`overwrite`,label:`Overwrite entirely`,hint:`Destructive`},{value:`skip`,label:`Skip`}]});return P(e)?null:e}return`overwrite`}async function Ht(e){let t=await K({message:`Select an example:`,options:e.examples.map(e=>({value:e.id,label:e.name,...e.description?{hint:e.description}:{}}))});return P(t)?null:t}async function Ut(e){let t=await K({message:`Select your framework or build tool:`,initialValue:e.framework,options:[{value:`vanilla`,label:`Vanilla${e.framework===`vanilla`?` (Detected)`:``}`,hint:`Node.js, Bun, server-side or runtime-only validation`},{value:`vite`,label:`Vite${e.framework===`vite`?` (Detected)`:``}`,hint:`Client-side and static inlining validation`},{value:`bun-fullstack`,label:`Bun fullstack dev server${e.framework===`bun-fullstack`?` (Detected)`:``}`,hint:`Client-side bundling and Bun.serve integration`},{value:`nextjs`,label:`Next.js${e.framework===`nextjs`?` (Detected)`:``}`,hint:`Next.js App or Pages Router with build and runtime validation`},{value:`nuxt`,label:`Nuxt${e.framework===`nuxt`?` (Detected)`:``}`,hint:`Nuxt with build and runtime validation`}]});return P(t)?null:t}async function Wt(e){let t=await U({message:`Optional: Would you also like to bootstrap a custom Bun.build script for programmatic bundling?`,initialValue:e.initialValue??!1});return P(t)?null:t}async function Gt(){let e=await K({message:`Select your preferred validator library:`,options:[{value:`arktype`,label:`ArkType (Recommended)`,hint:`TypeScript's 1:1 validator, optimized from editor to runtime`},{value:`zod`,label:`Zod`,hint:`TypeScript-first schema validation with static type inference`},{value:`valibot`,label:`Valibot`,hint:`The modular and type safe schema library`}]});return P(e)?null:e}async function Kt(e){let t=await K({message:`How would you like to structure your environment variables?`,options:e?.framework===`nextjs`?[{value:`flat`,label:`Flat (Recommended)`,hint:`A single flat env.ts file for the best DX`},{value:`strict`,label:`Strict`,hint:`Separate shared, client, and server files for hard bundle boundaries.`}]:[{value:`simple`,label:`Simple (Recommended)`,hint:`A single env.ts file for the best DX`},{value:`strict`,label:`Strict`,hint:`Separate shared, client, and server files for hard bundle boundaries.`}]});return P(t)?null:t}async function qt(e){let t=await U({message:`Enable automated ${e.framework===`nuxt`?`Nuxt`:`Next.js`} code generation for environment variables?`,initialValue:e.initialValue??!0,active:`Yes (Recommended)`,inactive:`No`});return P(t)?null:t}async function Jt(e){let t=await U({message:`Use default config path (${Y(e.defaultEnvPath||`./src/env.ts`)})?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No, let me customize it`});return P(t)?null:t}async function Yt(e){let t=e.defaultEnvPath||`./src/env.ts`;if(!e.useDefaultPath){let e=await $e({message:`Where should we create the ArkEnv config?`,placeholder:t,initialValue:t,defaultValue:t});if(P(e))return null;let n=typeof e==`string`?e.trim():``;return n===``?t:n}return t}const X={example:Ht,overwriteEnvSchemaFile:Rt,framework:Ut,bunBuild:Wt,layout:Kt,nextjsCodegen:qt,useDefaultPath:Jt,path:Yt,installTypeDefinitions:Bt,envDtsHandling:Vt,validator:Gt,useEnvExample:zt};async function Xt(e,t=!1){return(e?.mode||`existing`)===`new`?Zt(e,t):Qt(e,t)}async function Zt(e,t=!1){let n=e?.examples||[],i=`arkenv-project`;try{let a;if(e?.name){let t=e.name.trim();a=t===`.`||t===`./`||r.default.resolve(process.cwd(),t)===process.cwd()?`.`:t}else if(t)a=i;else{let e=(Z(await $e({message:`Project name:`,placeholder:i,defaultValue:i}))||i).trim();a=e===`.`||e===`./`||r.default.resolve(process.cwd(),e)===process.cwd()?`.`:e}let o=e?.example;!o&&!t?o=Z(await X.example({examples:n})):!o&&t&&(o=`basic`);let s=n.find(e=>e.id===o);if(!s){let e=n.map(e=>e.id).join(`, `);throw Error(`Unknown example ${o}. Available examples: ${e}`)}return{mode:`new`,example:s.id,name:a,path:`./src/env.ts`,validator:`arktype`,framework:s.framework,language:`ts`,installSkill:!1}}catch(e){if(e instanceof en)return null;throw e}}async function Qt(e,n=!1){let r=e?.defaultEnvPath||`./src/env.ts`,i=e?.envKeys||null,a=e?.envKeysSource||`.env.example`;if(n){let n=e?.framework||`vanilla`,a;(n===`nextjs`||n===`nuxt`)&&(a=e?.isStrict?`strict`:e?.isSimple?`simple`:e?.isFlat||n===`nextjs`?`flat`:`simple`);let o=await $t(e,n,r),s;return(n===`vite`||n===`bun-fullstack`)&&(s=o?`append`:`overwrite`),(0,t.shake)({mode:`existing`,path:r,validator:`arktype`,framework:n,layout:a,bunFeatures:n===`bun-fullstack`?e?.bunFeatures??[`serve`]:void 0,language:`ts`,overwriteEnvSchemaFile:!0,installTypeDefinitions:n===`vite`||n===`bun-fullstack`,installSkill:!1,envDtsHandling:s,envKeys:i??void 0,disableCodegen:e?.disableCodegen??!1,wrapNextjsConfig:n===`nextjs`?!0:void 0})}try{let n=Z(await X.overwriteEnvSchemaFile({hasEnvSchemaFile:e?.hasEnvSchemaFile??!1,defaultPath:r})),o=Z(await X.framework({framework:e?.framework})),s;(o===`nextjs`||o===`nuxt`)&&(s=e?.isStrict?`strict`:e?.isSimple?`simple`:e?.isFlat?`flat`:Z(await X.layout({framework:o})));let c;if(o===`bun-fullstack`){let t=!!e?.bunFeatures?.includes(`build`);c=Z(await X.bunBuild({initialValue:t}))}let l=e?.disableCodegen;o===`nuxt`?l=!0:o===`nextjs`&&l===void 0&&(l=!Z(await X.nextjsCodegen({initialValue:!0,framework:o})));let u;if(o===`nextjs`&&!l){let e=await U({message:`Would you like to wrap your Next.js config with ${Y(`withArkEnv`)}?`,initialValue:!0,active:`Yes (Recommended)`,inactive:`No`});if(P(e))throw Ge(`Operation cancelled`),new en;u=e}let d=Z(await X.useDefaultPath({defaultEnvPath:r})),f=Z(await X.path({useDefaultPath:d,defaultEnvPath:r})),p=await $t(e,o,f),m=Z(await X.installTypeDefinitions({framework:o,hasTypeFile:p})),h=Z(await X.envDtsHandling({framework:o,installTypeDefinitions:m,hasTypeFile:p})),g=Z(await X.validator()),_=Z(await X.useEnvExample({detectedKeys:i,keysSource:a}));return(0,t.shake)({mode:`existing`,overwriteEnvSchemaFile:n,framework:o,layout:s,path:f,installTypeDefinitions:m,envDtsHandling:h,validator:g,bunFeatures:o===`bun-fullstack`?c?[`serve`,`build`]:[`serve`]:void 0,language:`ts`,installSkill:!1,envKeys:_?i??void 0:void 0,disableCodegen:l,wrapNextjsConfig:u})}catch(e){if(e instanceof en)return null;throw e}}async function $t(e,t,n){return await e?.hasTypeFileAtPath?.({framework:t,envPath:n})??e?.hasTypeFile??!1}var en=class extends Error{constructor(){super(`Operation cancelled`)}};function Z(e){if(e===null||P(e))throw Ge(`Operation cancelled`),new en;return e}var tn=class{async confirm(e,n=!0,r,i){let a=await U((0,t.shake)({message:e,initialValue:n,active:r,inactive:i}));return P(a)?null:a}async runWizard(e,t=!1){return Xt(e,t)}};const nn={isYes:{long:`--yes`,short:`-y`,kind:`boolean`},isForce:{long:`--force`,short:`-f`,kind:`boolean`},isQuiet:{long:`--quiet`,short:`-q`,kind:`boolean`},isJson:{long:`--json`,short:`-j`,kind:`boolean`},isAgent:{long:`--agent`,short:`-a`,kind:`boolean`},helpRequested:{long:`--help`,short:`-h`,kind:`boolean`},example:{long:`--example`,short:`-e`,kind:`value`},isStrict:{long:`--strict`,short:``,kind:`boolean`},isSimple:{long:`--simple`,short:``,kind:`boolean`},isFlat:{long:`--flat`,short:``,kind:`boolean`},noCodegen:{long:`--no-codegen`,short:`-C`,kind:`boolean`}},rn=new Set(Object.values(nn).flatMap(e=>[e.long,e.short].filter(Boolean))),an=new Set(Object.values(nn).filter(e=>e.kind===`value`).flatMap(e=>[e.long,e.short].filter(Boolean)));var on=class{constructor(e,t={}){let n=e.slice(2),r=[],i=!1;for(let e of n){if(i){r.push(e),i=!1;continue}if(an.has(e)){r.push(e),i=!0;continue}if(/^-[a-zA-Z]{2,}$/.test(e)){let t=e.slice(1).split(``);for(let e of t)r.push(`-${e}`);an.has(`-${t[t.length-1]}`)&&(i=!0)}else r.push(e)}this.args=r,this.command=this.args[0];let a=1,o=[];for(this.validationError=void 0;a<this.args.length;){let e=this.args[a];if(e.startsWith(`-`)){if(!rn.has(e)){this.validationError=`Unknown argument: ${e}`;break}if(an.has(e))if(a+1<this.args.length&&!this.args[a+1].startsWith(`-`))a+=2;else{this.validationError=`Missing value for option: ${e}`;break}else a+=1}else o.push(e),a+=1}this.validationError||(o.length>1?this.validationError=`Unknown argument: ${o[1]}`:this.name=o[0]),this.logger=t.logger||new tt({isQuiet:this.isQuiet,isJson:this.isJson,isYes:this.isYes})}get isAgent(){return this.hasFlag(`isAgent`)}get isYes(){return this.isAgent||this.hasFlag(`isYes`)}get isQuiet(){return this.isAgent||this.hasFlag(`isQuiet`)}get isJson(){return this.isAgent||this.hasFlag(`isJson`)}get isForce(){return this.hasFlag(`isForce`)}get helpRequested(){return this.hasFlag(`helpRequested`)}get example(){let e=nn.example;return this.getFlagValue(e.long,e.short)}get isStrict(){return this.hasFlag(`isStrict`)}get isSimple(){return this.hasFlag(`isSimple`)}get isFlat(){return this.hasFlag(`isFlat`)}get noCodegen(){return this.hasFlag(`noCodegen`)}hasFlag(e){let t=nn[e];return this.args.includes(t.long)||!!t.short&&this.args.includes(t.short)}get initInput(){let e={isYes:this.isYes,isForce:this.isForce,isQuiet:this.isQuiet,isAgent:this.isAgent,isStrict:this.isStrict,isSimple:this.isSimple,isFlat:this.isFlat};return this.example!==void 0&&(e.example=this.example),this.name!==void 0&&(e.name=this.name),this.noCodegen&&(e.noCodegen=!0),e}getFlagValue(e,t){let n=this.args.findIndex(n=>n===e||n===t);if(n!==-1&&this.args[n+1]&&!this.args[n+1].startsWith(`-`))return this.args[n+1]}},sn=`0.3.0`;function cn(e,t=2,n=4){let r=Math.max(...e.map(e=>e.left.length),0),i=` `.repeat(t);return e.map(e=>{let t=` `.repeat(r-e.left.length+n);return`${i}${e.left}${t}${e.right}`})}var ln=class{constructor(e){this.logger=e}async execute(){let e=[{left:`arkenv init [project-name]`,right:`Set up ArkEnv in your project`}],t=[{left:`--yes, -y`,right:`Skip prompts and use defaults (also passed to subprocesses)`},{left:`--force, -f`,right:`Bypass technical requirement checks and dirty git working tree check, then force scaffolding`},{left:`--agent, -a`,right:`Enable non-interactive, machine-readable mode for AI agents. Bypasses all prompts and outputs structured JSON. Macro for --yes --quiet --json`},{left:`--example, -e`,right:`Specify an example name when creating a new project`},{left:`--quiet, -q`,right:`Quiet mode: Suppress output, capture logs on failure`},{left:`--json, -j`,right:`Output structured JSON to stdout`},{left:`--no-codegen, -C`,right:`Disable automatic env.gen.ts code generation for Next.js`},{left:`--help, -h`,right:`Show this help message`}];this.logger.log(`ArkEnv CLI v${sn}`),this.logger.log(`\n${y.default.bold(`Usage:`)}`);for(let t of cn(e))this.logger.log(t);this.logger.log(`\n${y.default.bold(`Options:`)}`);for(let e of cn(t))this.logger.log(e)}};function un(e,t,n,r,i,a){let{extraImports:o,serverField:s,clientField:c,sharedField:l,defaultServerFields:u,defaultClientFields:d,defaultSharedFields:f}=t,p=i===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`,m=i===`nuxt`?`@arkenv/nuxt`:`@arkenv/nextjs`,h=i===`nuxt`?`Nuxt`:`Next.js`,g=[],_=[],v=[];if(e&&e.length>0)for(let t of e)t.startsWith(p)?_.push(c(t)):t===`NODE_ENV`?v.push(l(t)):g.push(s(t));else g.push(...u),_.push(...d),v.push(...f);if(i===`nextjs`&&a!==`simple`){let t=[...g,..._,...v].map(e=>e.replace(/^\t\t/,` `)),i=[];for(let e of v){let t=e.trim().match(/^([a-zA-Z0-9_]+)\s*:/);if(t){let e=t[1];e!==`NODE_ENV`&&i.push(e)}}let a=[];if(i.length>0&&a.push(`\texposeToClient: [${i.map(e=>`"${e}"`).join(`, `)}]`),r){let t=[];if(e&&e.length>0)for(let n of e)(n.startsWith(p)||n===`NODE_ENV`||i.includes(n))&&t.push(`\t\t${n}: process.env.${n},`);else{t.push(` NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,`,` NODE_ENV: process.env.NODE_ENV,`);for(let e of i)t.push(`\t\t${e}: process.env.${e},`)}a.push(`\truntimeEnv: {\n${t.join(`
114
+ `)}\n\t}`)}let s=a.length>0?`, {\n${a.join(`,
115
+ `)}\n}`:``;return`${[`import arkenv from "${r?`@arkenv/nextjs`:n||`./generated/env.gen`}";`,...o?[o]:[]].join(`
118
116
  `)}
119
117
 
120
118
  /**
121
119
  * Environment variable schema.
122
- * In ${m}, use \`${p}\` to validate variables at build-time and runtime.
120
+ * In ${h}, use the generated \`arkenv\` from \`env.gen.ts\` to validate variables.
123
121
  * Enforces client/server separation and prevents secret leaks.
124
122
  */
125
123
  export const env = arkenv({
126
- ${v.join(`,
124
+ ${t.join(`
125
+ `)}
126
+ }${s});
127
+ `}let y=[];if(g.length>0&&y.push(`\tserver: {\n${g.join(`
128
+ `)}\n\t}`),_.length>0&&y.push(`\tclient: {\n${_.join(`
129
+ `)}\n\t}`),v.length>0&&y.push(`\tshared: {\n${v.join(`
130
+ `)}\n\t}`),r||i===`nuxt`){let t=[];if(e&&e.length>0)for(let n of e)(n.startsWith(p)||n===`NODE_ENV`)&&t.push(`\t\t${n}: process.env.${n},`);else t.push(`\t\t${p}API_URL: process.env.${p}API_URL,`,` NODE_ENV: process.env.NODE_ENV,`);return i!==`nuxt`&&y.push(`\truntimeEnv: {\n${t.join(`
131
+ `)}\n\t}`),`${[`import arkenv from "${m}";`,...o?[o]:[]].join(`
132
+ `)}
133
+
134
+ /**
135
+ * Environment variable schema.
136
+ * In ${h}, use \`${m}\` to validate variables at build-time and runtime.
137
+ * Enforces client/server separation and prevents secret leaks.
138
+ */
139
+ export const env = arkenv({
140
+ ${y.join(`,
127
141
  `)},
128
142
  });
129
- `}return`${[`import arkenv from "${n||`./generated/env.gen`}";`,...a?[a]:[]].join(`
143
+ `}return`${[`import arkenv from "${n||`./generated/env.gen`}";`,...o?[o]:[]].join(`
130
144
  `)}
131
145
 
132
146
  /**
133
147
  * Environment variable schema.
134
- * In ${m}, use the generated \`arkenv\` from \`env.gen.ts\` to validate variables.
148
+ * In ${h}, use the generated \`arkenv\` from \`env.gen.ts\` to validate variables.
135
149
  * Enforces client/server separation and prevents secret leaks.
136
150
  */
137
151
  export const env = arkenv({
138
- ${v.join(`,
152
+ ${y.join(`,
139
153
  `)},
140
154
  });
141
- `}const dn=(e,t,n,r)=>{let a=e?.length?e.map(e=>`\t\t${e}: "string?",`).join(`
155
+ `}const dn=(e,t,n,r,a)=>{let o=e?.length?e.map(e=>`\t\t${e}: "string?",`).join(`
142
156
  `):` NODE_ENV: "'development' | 'production' | 'test' = 'development'",
143
157
  PORT: "number.port = 3000",`;return t===`vite`?i.default`
144
158
  import { type } from "arkenv";
@@ -149,7 +163,7 @@ ${v.join(`,
149
163
  * and provide typesafety for \`import.meta.env\` on the client-side.
150
164
  */
151
165
  export const Env = type({
152
- ${a}
166
+ ${o}
153
167
  });
154
168
  `:t===`bun-fullstack`?i.default`
155
169
  import { type } from "arkenv";
@@ -160,16 +174,16 @@ ${v.join(`,
160
174
  * and provide typesafety for \`process.env\` on the client-side.
161
175
  */
162
176
  export const Env = type({
163
- ${a}
177
+ ${o}
164
178
  });
165
- `:t===`nextjs`||t===`nuxt`?un(e,{serverField:e=>`\t\t${e}: "string?",`,clientField:e=>`\t\t${e}: "string?",`,sharedField:e=>`\t\t${e}: "'development' | 'production' | 'test' = 'development'",`,defaultServerFields:[` DATABASE_URL: "string = 'postgres://localhost:5432/mydb'",`],defaultClientFields:[`\t\t${t===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`}API_URL: "string = 'https://api.example.com'",`],defaultSharedFields:[` NODE_ENV: "'development' | 'production' | 'test' = 'development'",`]},n,r,t):i.default`
179
+ `:t===`nextjs`||t===`nuxt`?un(e,{serverField:e=>`\t\t${e}: "string?",`,clientField:e=>`\t\t${e}: "string?",`,sharedField:e=>`\t\t${e}: "'development' | 'production' | 'test' = 'development'",`,defaultServerFields:[` DATABASE_URL: "string = 'postgres://localhost:5432/mydb'",`],defaultClientFields:[`\t\t${t===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`}API_URL: "string = 'https://api.example.com'",`],defaultSharedFields:[` NODE_ENV: "'development' | 'production' | 'test' = 'development'",`]},n,r,t,a):i.default`
166
180
  import arkenv, { type } from "arkenv";
167
181
 
168
182
  /**
169
183
  * Environment variable schema for server-side or runtime-only validation.
170
184
  */
171
185
  export const Env = type({
172
- ${a}
186
+ ${o}
173
187
  });
174
188
 
175
189
  export const env = arkenv(Env);
@@ -196,7 +210,7 @@ ${a}
196
210
  declare namespace NodeJS {
197
211
  interface ProcessEnv extends ProcessEnvAugmented {}
198
212
  }
199
- `,mn=(e,t,n,r)=>{let a=e?.length?e.map(e=>`\t\t${e}: v.optional(v.string()),`).join(`
213
+ `,mn=(e,t,n,r,a)=>{let o=e?.length?e.map(e=>`\t\t${e}: v.optional(v.string()),`).join(`
200
214
  `):` NODE_ENV: v.optional(v.picklist(["development", "production", "test"]), "development"),
201
215
  PORT: v.optional(v.pipe(v.string(), v.transform(Number), v.number(), v.integer(), v.minValue(1), v.maxValue(65535)), 3000),`;return t===`vite`?i.default`
202
216
  import { type } from "arkenv";
@@ -208,7 +222,7 @@ ${a}
208
222
  * and provide typesafety for \`import.meta.env\` on the client-side.
209
223
  */
210
224
  export const Env = type({
211
- ${a}
225
+ ${o}
212
226
  });
213
227
  `:t===`bun-fullstack`?i.default`
214
228
  import { type } from "arkenv";
@@ -220,9 +234,9 @@ ${a}
220
234
  * and provide typesafety for \`process.env\` on the client-side.
221
235
  */
222
236
  export const Env = type({
223
- ${a}
237
+ ${o}
224
238
  });
225
- `:t===`nextjs`||t===`nuxt`?un(e,{extraImports:`import * as v from "valibot";`,serverField:e=>`\t\t${e}: v.optional(v.string()),`,clientField:e=>`\t\t${e}: v.optional(v.string()),`,sharedField:e=>`\t\t${e}: v.optional(v.picklist(["development", "production", "test"]), "development"),`,defaultServerFields:[` DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), "postgres://localhost:5432/mydb"),`],defaultClientFields:[`\t\t${t===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`}API_URL: v.optional(v.pipe(v.string(), v.url()), "https://api.example.com"),`],defaultSharedFields:[` NODE_ENV: v.optional(v.picklist(["development", "production", "test"]), "development"),`]},n,r,t):i.default`
239
+ `:t===`nextjs`||t===`nuxt`?un(e,{extraImports:`import * as v from "valibot";`,serverField:e=>`\t\t${e}: v.optional(v.string()),`,clientField:e=>`\t\t${e}: v.optional(v.string()),`,sharedField:e=>`\t\t${e}: v.optional(v.picklist(["development", "production", "test"]), "development"),`,defaultServerFields:[` DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), "postgres://localhost:5432/mydb"),`],defaultClientFields:[`\t\t${t===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`}API_URL: v.optional(v.pipe(v.string(), v.url()), "https://api.example.com"),`],defaultSharedFields:[` NODE_ENV: v.optional(v.picklist(["development", "production", "test"]), "development"),`]},n,r,t,a):i.default`
226
240
  import arkenv from "arkenv/standard";
227
241
  import * as v from "valibot";
228
242
 
@@ -230,9 +244,9 @@ ${a}
230
244
  * Environment variable schema for server-side or runtime-only validation.
231
245
  */
232
246
  export const env = arkenv({
233
- ${a}
247
+ ${o}
234
248
  });
235
- `},hn=(e,t,n,r)=>{let a=e?.length?e.map(e=>`\t\t${e}: z.string().optional(),`).join(`
249
+ `},hn=(e,t,n,r,a)=>{let o=e?.length?e.map(e=>`\t\t${e}: z.string().optional(),`).join(`
236
250
  `):` NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
237
251
  PORT: z.coerce.number().int().min(1).max(65535).default(3000),`;return t===`vite`?i.default`
238
252
  import { type } from "arkenv";
@@ -244,7 +258,7 @@ ${a}
244
258
  * and provide typesafety for \`import.meta.env\` on the client-side.
245
259
  */
246
260
  export const Env = type({
247
- ${a}
261
+ ${o}
248
262
  });
249
263
  `:t===`bun-fullstack`?i.default`
250
264
  import { type } from "arkenv";
@@ -256,9 +270,9 @@ ${a}
256
270
  * and provide typesafety for \`process.env\` on the client-side.
257
271
  */
258
272
  export const Env = type({
259
- ${a}
273
+ ${o}
260
274
  });
261
- `:t===`nextjs`||t===`nuxt`?un(e,{extraImports:`import { z } from "zod";`,serverField:e=>`\t\t${e}: z.string().optional(),`,clientField:e=>`\t\t${e}: z.string().optional(),`,sharedField:e=>`\t\t${e}: z.enum(["development", "production", "test"]).default("development"),`,defaultServerFields:[` DATABASE_URL: z.string().url().default("postgres://localhost:5432/mydb"),`],defaultClientFields:[`\t\t${t===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`}API_URL: z.string().url().default("https://api.example.com"),`],defaultSharedFields:[` NODE_ENV: z.enum(["development", "production", "test"]).default("development"),`]},n,r,t):i.default`
275
+ `:t===`nextjs`||t===`nuxt`?un(e,{extraImports:`import { z } from "zod";`,serverField:e=>`\t\t${e}: z.string().optional(),`,clientField:e=>`\t\t${e}: z.string().optional(),`,sharedField:e=>`\t\t${e}: z.enum(["development", "production", "test"]).default("development"),`,defaultServerFields:[` DATABASE_URL: z.string().url().default("postgres://localhost:5432/mydb"),`],defaultClientFields:[`\t\t${t===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`}API_URL: z.string().url().default("https://api.example.com"),`],defaultSharedFields:[` NODE_ENV: z.enum(["development", "production", "test"]).default("development"),`]},n,r,t,a):i.default`
262
276
  import arkenv from "arkenv/standard";
263
277
  import { z } from "zod";
264
278
 
@@ -266,9 +280,9 @@ ${a}
266
280
  * Environment variable schema for server-side or runtime-only validation.
267
281
  */
268
282
  export const env = arkenv({
269
- ${a}
283
+ ${o}
270
284
  });
271
- `};function gn(e,t){let{validator:n,envKeys:r,framework:i,disableCodegen:a}=e;switch(n){case`arktype`:return`${dn(r,i,t,a)}\n`;case`zod`:return`${hn(r,i,t,a)}\n`;case`valibot`:return`${mn(r,i,t,a)}\n`;default:throw Error(`Unsupported validator: ${n}`)}}function Q(e,t=` `){return e.length===0?`{}`:`{\n${t}${e.map(e=>e.trim()).join(`\n${t}`)}\n${t.slice(1)}}`}function _n(e,t){let{validator:n,envKeys:r}=e,i=e.disableCodegen||e.framework===`nuxt`,a=[],o=[],s=[],c=[],l=e.framework===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`,u=e.framework===`nuxt`?`@arkenv/nuxt`:`@arkenv/nextjs`;if(r&&r.length>0)for(let e of r)e.startsWith(l)?(n===`arktype`?o.push(`${e}: "string?",`):n===`zod`?o.push(`${e}: z.string().optional(),`):n===`valibot`&&o.push(`${e}: v.optional(v.string()),`),c.push(`${e}: process.env.${e},`)):e===`NODE_ENV`?(n===`arktype`?s.push(`${e}: "'development' | 'production' | 'test' = 'development'",`):n===`zod`?s.push(`${e}: z.enum(["development", "production", "test"]).default("development"),`):n===`valibot`&&s.push(`${e}: v.optional(v.picklist(["development", "production", "test"]), "development"),`),c.push(`${e}: process.env.${e},`)):e===`PORT`?n===`arktype`?a.push(`PORT: "number.port = 3000",`):n===`zod`?a.push(`PORT: z.coerce.number().int().min(1).max(65535).default(3000),`):n===`valibot`&&a.push(`PORT: v.optional(v.pipe(v.string(), v.transform(Number), v.number(), v.integer(), v.minValue(1), v.maxValue(65535)), 3000),`):n===`arktype`?a.push(`${e}: "string?",`):n===`zod`?a.push(`${e}: z.string().optional(),`):n===`valibot`&&a.push(`${e}: v.optional(v.string()),`);else{let t=e.framework===`nuxt`?`NUXT_PUBLIC_API_URL`:`NEXT_PUBLIC_API_URL`;n===`arktype`?(a.push(`DATABASE_URL: "string = 'postgres://localhost:5432/mydb'",`),o.push(`${t}: "string = 'https://api.example.com'",`),s.push(`NODE_ENV: "'development' | 'production' | 'test' = 'development'",`)):n===`zod`?(a.push(`DATABASE_URL: z.string().url().default("postgres://localhost:5432/mydb"),`),o.push(`${t}: z.string().url().default("https://api.example.com"),`),s.push(`NODE_ENV: z.enum(["development", "production", "test"]).default("development"),`)):n===`valibot`&&(a.push(`DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), "postgres://localhost:5432/mydb"),`),o.push(`${t}: v.optional(v.pipe(v.string(), v.url()), "https://api.example.com"),`),s.push(`NODE_ENV: v.optional(v.picklist(["development", "production", "test"]), "development"),`)),c.push(`${t}: process.env.${t},`,`NODE_ENV: process.env.NODE_ENV,`)}let d=e.framework===`nuxt`?``:`,\n\t\truntimeEnv: {\n\t\t\t${c.map(e=>e.trim()).join(`
285
+ `};function gn(e,t){let{validator:n,envKeys:r,framework:i,disableCodegen:a,layout:o}=e;switch(n){case`arktype`:return`${dn(r,i,t,a,o)}\n`;case`zod`:return`${hn(r,i,t,a,o)}\n`;case`valibot`:return`${mn(r,i,t,a,o)}\n`;default:throw Error(`Unsupported validator: ${n}`)}}function Q(e,t=` `){return e.length===0?`{}`:`{\n${t}${e.map(e=>e.trim()).join(`\n${t}`)}\n${t.slice(1)}}`}function _n(e,t){let{validator:n,envKeys:r}=e,i=e.disableCodegen||e.framework===`nuxt`,a=[],o=[],s=[],c=[],l=e.framework===`nuxt`?`NUXT_PUBLIC_`:`NEXT_PUBLIC_`,u=e.framework===`nuxt`?`@arkenv/nuxt`:`@arkenv/nextjs`;if(r&&r.length>0)for(let e of r)e.startsWith(l)?(n===`arktype`?o.push(`${e}: "string?",`):n===`zod`?o.push(`${e}: z.string().optional(),`):n===`valibot`&&o.push(`${e}: v.optional(v.string()),`),c.push(`${e}: process.env.${e},`)):e===`NODE_ENV`?(n===`arktype`?s.push(`${e}: "'development' | 'production' | 'test' = 'development'",`):n===`zod`?s.push(`${e}: z.enum(["development", "production", "test"]).default("development"),`):n===`valibot`&&s.push(`${e}: v.optional(v.picklist(["development", "production", "test"]), "development"),`),c.push(`${e}: process.env.${e},`)):e===`PORT`?n===`arktype`?a.push(`PORT: "number.port = 3000",`):n===`zod`?a.push(`PORT: z.coerce.number().int().min(1).max(65535).default(3000),`):n===`valibot`&&a.push(`PORT: v.optional(v.pipe(v.string(), v.transform(Number), v.number(), v.integer(), v.minValue(1), v.maxValue(65535)), 3000),`):n===`arktype`?a.push(`${e}: "string?",`):n===`zod`?a.push(`${e}: z.string().optional(),`):n===`valibot`&&a.push(`${e}: v.optional(v.string()),`);else{let t=e.framework===`nuxt`?`NUXT_PUBLIC_API_URL`:`NEXT_PUBLIC_API_URL`;n===`arktype`?(a.push(`DATABASE_URL: "string = 'postgres://localhost:5432/mydb'",`),o.push(`${t}: "string = 'https://api.example.com'",`),s.push(`NODE_ENV: "'development' | 'production' | 'test' = 'development'",`)):n===`zod`?(a.push(`DATABASE_URL: z.string().url().default("postgres://localhost:5432/mydb"),`),o.push(`${t}: z.string().url().default("https://api.example.com"),`),s.push(`NODE_ENV: z.enum(["development", "production", "test"]).default("development"),`)):n===`valibot`&&(a.push(`DATABASE_URL: v.optional(v.pipe(v.string(), v.url()), "postgres://localhost:5432/mydb"),`),o.push(`${t}: v.optional(v.pipe(v.string(), v.url()), "https://api.example.com"),`),s.push(`NODE_ENV: v.optional(v.picklist(["development", "production", "test"]), "development"),`)),c.push(`${t}: process.env.${t},`,`NODE_ENV: process.env.NODE_ENV,`)}let d=e.framework===`nuxt`?``:`,\n\t\truntimeEnv: {\n\t\t\t${c.map(e=>e.trim()).join(`
272
286
  `)}\n\t\t}`,f=``,p=``,m=``;return n===`arktype`?(f=`import { type } from "${u}/shared";
273
287
 
274
288
  /**
@@ -372,4 +386,4 @@ export const env = arkenv(
372
386
 
373
387
  `,o+=`Also, wrap your Next.js config with ${Y(`withArkEnv`)}:\n`,o+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,e.metadata.layout===`strict`?(o+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`,o+=`Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`):(o+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`,o+=`Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`)):r&&(o+=`
374
388
 
375
- `,e.metadata.layout===`strict`?o+=`Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`:o+=`Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`),{message:o,title:`Next steps`}}let r=e.skill?.dlxCommand.join(` `)||`npx`,a=e.skill?.packageName||`yamcodes/arkenv`,o=``,s=1,c=e.metadata.displayPath;if(e.metadata.layout===`strict`){let e=c.lastIndexOf(`.`),t=e===-1?c:c.slice(0,e);c=`${t}/client.ts, ${t}/server.ts, and ${t}/internal/shared.ts`}o+=`${s++}. Check ${Y(c)} and refine your environment schema.\n`;let l=e.metadata.framework===`nextjs`&&!e.metadata.disableCodegen&&!n;return e.metadata.framework===`vite`?o+=`${s++}. Access via ${Y(`import.meta.env.YOUR_VAR`)}\n`:e.metadata.framework===`bun-fullstack`?o+=`${s++}. Access via ${Y(`process.env.YOUR_VAR`)}\n`:e.metadata.framework===`nextjs`?e.metadata.layout===`strict`?(e.metadata.disableCodegen||l&&(o+=`${s++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,o+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,o+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`),o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`):(e.metadata.disableCodegen||l&&(o+=`${s++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,o+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,o+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`),o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`):e.metadata.framework===`nuxt`&&e.metadata.layout===`strict`?o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`:o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`,o+=`${s++}. (Recommended) Install the AI skill: ${Y(`${r} skills add ${a}`)}\n`,o+=` Then run ${Y(`/arkenv`)} inside your AI assistant to finish.`,{message:o,title:`Next steps`}}var Sn=class{constructor(e,t){this.workspace=e,this.reporter=t}async execute(e){let t=this.reporter.spinner();t.start(`Scaffolding ArkEnv configuration...`);try{e.clone&&(t.stop(`Starting new project scaffolding...`),this.reporter.step(`Cloning example ${Y(e.clone.example)}...`),await vn(this.workspace,e.clone),t.start(`Scaffolding complete, finalizing...`));for(let t of e.files){if(t.action===`append`){if(!e.bootstrap||e.bootstrap.framework!==`vite`&&e.bootstrap.framework!==`bun-fullstack`){this.reporter.warn(`Skipping safe-append for ${Y(r.default.basename(t.path))}: unsupported framework.`);continue}await this.workspace.safeAppend(t.path,t.content,e.bootstrap.framework)?this.reporter.info(`Appended ArkEnv types to ${Y(r.default.basename(t.path))}.`):this.reporter.info(`${Y(r.default.basename(t.path))} already contains ArkEnv types.`);continue}if(await this.workspace.mkdir(r.default.dirname(t.path),!0),await this.workspace.writeFile(t.path,t.content),t.label!==`environment schema`&&t.label?.includes(`types`)){let e=t.action===`overwrite`?`Updated`:`Created`;this.reporter.info(`${e} ${Y(r.default.basename(t.path))} for typesafe environment variables.`)}}if(t.stop(`Configuration scaffolded!`),e.install&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing dependencies with ${Y(e.install.packageManager)}...`);let[t,n]=bn(e.install.packageManager,e.install.dependencies);await this.workspace.execute(t,n,e.install.cwd??e.cwd)}let n=!1;if(e.tsConfig){let t=await this.workspace.updateTsConfigToStrict(e.tsConfig.path);t.status===`updated`?(this.reporter.info(`Enforced strict: true in your ${Y(t.file)}`),n=!0):t.status===`error`&&this.reporter.warn(`Could not automatically update ${Y(t.file||`tsconfig.json`)}. Please ensure 'strict: true' is set manually.`)}let i=!1;if(e.bootstrap){if(e.bootstrap.framework===`vite`){let t=await this.workspace.findViteConfig(e.cwd);if(t){this.reporter.step(`Bootstrapping Vite plugin...`);let n=await this.workspace.bootstrapViteConfig(t,e.bootstrap.importPath||`./src/env`);n.success?n.updated&&this.reporter.info(`Updated ${Y(r.default.basename(t))}`):(this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${n.error}`),this.reporter.info(`Please add ${Y(`@arkenv/vite-plugin`)} manually.`))}else this.reporter.info(`No Vite config found — please add ${Y(`@arkenv/vite-plugin`)} to your Vite config manually.`)}else if(e.bootstrap.framework===`bun-fullstack`){let t=await this.workspace.findBunConfig(e.cwd),n=await this.workspace.bootstrapBunConfig(t,e.bootstrap.bunFeatures);n.success&&n.instructions?this.reporter.info(n.instructions):n.success||this.reporter.error(n.error||`Bun bootstrap failed`)}else if(e.bootstrap.framework===`nextjs`){this.reporter.step(`Generating Next.js environment bindings...`);let t=`import('@arkenv/nextjs/config').then(({ runCodegen }) => { const path = require('path'); const schemaPath = path.resolve(process.cwd(), '${e.metadata.displayPath}'); const outputPath = path.join(path.dirname(schemaPath), 'generated', 'env.gen.ts'); runCodegen(schemaPath, outputPath); }).catch(err => { console.error(err); process.exit(1); });`;try{await this.workspace.execute(`node`,[`-e`,t],e.cwd),this.reporter.info(`Generated ${Y(`env.gen.ts`)} for Next.js`)}catch{this.reporter.warn(`Failed to automatically generate ${Y(`env.gen.ts`)}. It will be generated when you start your dev server.`)}if(e.bootstrap.wrapNextjsConfig!==!1){this.reporter.step(`Bootstrapping Next.js config...`);let t=await this.workspace.findNextjsConfig(e.cwd);if(t){let e=await this.workspace.bootstrapNextjsConfig(t);e.success?e.updated?(this.reporter.info(`Updated ${Y(r.default.basename(t))}`),i=!0):(this.reporter.info(`${Y(r.default.basename(t))} already uses withArkEnv`),i=!0):this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${e.error}`)}else this.reporter.info(`No Next.js config found. Please wrap your config with ${Y(`withArkEnv`)} manually.`)}}else if(e.bootstrap.framework===`nuxt`){this.reporter.step(`Bootstrapping Nuxt config...`);let t=await this.workspace.findNuxtConfig(e.cwd);if(t){let e=await this.workspace.bootstrapNuxtConfig(t);e.success?(e.updated?this.reporter.info(`Updated ${Y(r.default.basename(t))}`):this.reporter.info(`${Y(r.default.basename(t))} already registers @arkenv/nuxt/module`),i=!0):this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${e.error}`)}else this.reporter.info(`No Nuxt config found. Please register ${Y(`@arkenv/nuxt/module`)} manually.`)}}let a=!1;if(e.skill&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing ArkEnv agent skill...`);try{let[t,...n]=e.skill.dlxCommand,r=[...n,`skills`,`add`,e.skill.packageName];e.skill.isYes&&r.push(`--yes`),await this.workspace.execute(t,r,e.cwd),a=!0}catch(e){let t=e instanceof Error?e.message:String(e);this.reporter.warn(`Failed to install ArkEnv AI skill: ${t}`)}}let o=xn(e,a,i);if(this.reporter.note(o.message,o.title),e.metadata.layout===`strict`){let t=r.default.resolve(e.cwd,e.metadata.displayPath);if(await this.workspace.exists(t)){let t=e.metadata.displayPath,n=r.default.basename(t,r.default.extname(t));this.reporter.warn(`Found existing single-file schema at ${Y(t)}. You can delete it after updating your imports to point to your new ${Y(`${n}/client`)} and ${Y(`${n}/server`)}.`)}}this.reporter.finish(`${St} ArkEnv scaffolding complete. Happy coding!`,{path:e.metadata.displayPath,framework:e.metadata.framework,validator:e.metadata.validator,packageManager:e.metadata.packageManager,tsConfigUpdated:n,skillInstalled:a})}catch(e){throw t.stop(`Scaffolding failed.`),e}}};function Cn(e){switch(e){case`pnpm`:return[`pnpm`,`dlx`];case`yarn`:return[`yarn`,`dlx`];case`bun`:return[`bunx`];default:return[`npx`]}}function wn(e){let{mode:n,options:i,packageManager:a,tsConfig:o,shouldUpdateTsConfig:s,cwd:c,existingFiles:l}=e,u=i.name&&i.name!==`.`?r.default.basename(i.name):void 0,d={files:[],cwd:c,metadata:(0,t.shake)({displayPath:``,framework:i.framework,validator:i.validator,packageManager:a,importPath:``,mode:n,example:i.example,name:u,layout:i.layout,skillDetected:i.skillDetected,disableCodegen:i.disableCodegen})};if(n===`new`){if(!i.example)throw Error(`New project scaffolding requires an example.`);let t=i.name&&i.name!==`.`?r.default.join(c,i.name):void 0,n=i.name&&i.name!==`.`?r.default.basename(i.name):r.default.basename(c);return d.clone={repository:`https://github.com/yamcodes/arkenv.git`,example:i.example,targetName:n,...t!==void 0&&{targetDir:t}},d.install={packageManager:a,dependencies:[],...t!==void 0&&{cwd:t}},i.installSkill&&(d.skill={dlxCommand:Cn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes}),d.metadata.displayPath=`./src/env.ts`,d.metadata.importPath=`./src/env`,d}let f=r.default.resolve(c,i.path),p=r.default.dirname(f);if((i.framework===`nextjs`||i.framework===`nuxt`)&&i.layout===`strict`){let e=r.default.extname(f),t=f.slice(0,-e.length),n=r.default.join(t,`internal`,`shared${e}`),a=r.default.join(t,`client${e}`),s=r.default.join(t,`server${e}`),u;if((i.framework===`nextjs`||i.framework===`nuxt`)&&!i.disableCodegen&&o?.parsed){let e=o.parsed,n=(e.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=e.path?r.default.dirname(e.path):c,a=r.default.join(t,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let e of n[`@/*`]){let t=e.replace(/^\.\//,``).replace(/\*$/,``);if(t===``||o.startsWith(t)){let e=o;t!==``&&o.startsWith(t)&&(e=o.substring(t.length)),e=e.replace(/^\/+/,``).replace(/\/+$/,``),u=`@/${e}/env.gen`.replace(/\/+/g,`/`);break}}}}let p=_n(i,u),m=l.includes(n),h=l.includes(a),g=l.includes(s);(!m||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:n,content:p.shared,action:m?`overwrite`:`create`,label:`shared environment schema`}),(!h||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:a,content:p.client,action:h?`overwrite`:`create`,label:`client environment schema`}),(!g||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:s,content:p.server,action:g?`overwrite`:`create`,label:`server environment schema`})}else{let e;if((i.framework===`nextjs`||i.framework===`nuxt`)&&!i.disableCodegen&&o?.parsed){let t=o.parsed,n=(t.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=t.path?r.default.dirname(t.path):c,a=r.default.join(p,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let t of n[`@/*`]){let n=t.replace(/^\.\//,``).replace(/\*$/,``);if(n===``||o.startsWith(n)){let t=o;n!==``&&o.startsWith(n)&&(t=o.substring(n.length)),t=t.replace(/^\/+/,``).replace(/\/+$/,``),e=`@/${t}/env.gen`.replace(/\/+/g,`/`);break}}}}let t=gn(i,e),n=l.includes(f);(!n||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:f,content:t,action:n?`overwrite`:`create`,label:`environment schema`})}let m=[`arkenv`,i.validator];if(i.framework===`vite`&&m.push(`@arkenv/vite-plugin`),i.framework===`bun-fullstack`&&i.bunFeatures?.length&&m.push(`@arkenv/bun-plugin`),i.framework===`nextjs`&&m.push(`@arkenv/nextjs`),i.framework===`nuxt`&&m.push(`@arkenv/nuxt`),(i.framework===`vite`||i.framework===`nextjs`||i.framework===`nuxt`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&!m.includes(`arktype`)&&m.push(`arktype`),d.install={packageManager:a,dependencies:m},s&&o.file&&(d.tsConfig={path:r.default.resolve(c,o.file),action:`strict`}),(i.framework===`vite`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&i.installTypeDefinitions!==!1){let e=i.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,t=r.default.join(p,e),n=l.includes(t);if(i.envDtsHandling!==`skip`)if(i.envDtsHandling===`append`||!i.envDtsHandling&&n)d.files.push({path:t,content:f,action:`append`,label:`${i.framework} types`});else{let e=i.framework===`vite`?fn(i.path):pn(i.path);d.files.push({path:t,content:e,action:n?`overwrite`:`create`,label:`${i.framework} types`})}}(i.framework===`vite`||i.framework===`bun-fullstack`||i.framework===`nextjs`&&!i.disableCodegen||i.framework===`nuxt`)&&(d.bootstrap=(0,t.shake)({framework:i.framework,bunFeatures:i.framework===`bun-fullstack`?i.bunFeatures:void 0,wrapNextjsConfig:i.framework===`nextjs`?i.wrapNextjsConfig!==!1:void 0})),i.installSkill&&(d.skill={dlxCommand:Cn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes});let h=r.default.relative(c,f).replace(/\\/g,`/`),g=h.startsWith(`.`)?h:`./${h}`,_=g.replace(/\.(ts|js|tsx|jsx)$/,``);return d.metadata.displayPath=g,d.metadata.importPath=_,d.bootstrap&&(d.bootstrap.importPath=_),d}var Tn=class{async fetchRegistry(){try{let e=await fetch(`https://raw.githubusercontent.com/yamcodes/arkenv/main/examples/registry.json`);if(!e.ok)throw Error(`Failed to fetch registry: ${e.statusText}`);return await e.json()}catch{return{examples:[{id:`basic`,name:`Basic`,description:`A minimal ArkEnv setup in Node.js`,framework:`vanilla`},{id:`with-nextjs`,name:`Next.js`,description:`Minimal Next.js project with ArkType`,framework:`nextjs`},{id:`with-vite-react`,name:`React + Vite`,framework:`vite`},{id:`with-bun`,name:`Bun (Vanilla)`,description:`Minimal Bun project with ArkType`,framework:`vanilla`},{id:`with-bun-react`,name:`React + Bun fullstack dev server`,framework:`bun-fullstack`},{id:`with-zod`,name:`Zod`,description:`ArkEnv with Zod in Node.js`,framework:`vanilla`}]}}}},En=class{constructor(e,t,n,r,i=new Tn){this.logger=e,this.workspace=t,this.prompt=n,this.scanner=r,this.registry=i}async execute(e){let t=await this.collect(e);if(!t)return!1;let n=wn(t),r=new Sn(this.workspace,this.logger);try{await r.execute(n)}catch(e){this.logger.fatal(`Scaffolding failed.`,e)}return!0}async collect(e){this.logger.interactiveStdout(!0);try{let t=e.name;t&&r.default.resolve(process.cwd(),t)===process.cwd()&&(t=`.`);let n={...e,...t!==void 0&&{name:t}},i=t&&t!==`.`?r.default.resolve(process.cwd(),t):process.cwd(),a=await this.workspace.exists(i),o=a?await this.scanner.hasPackageJson(i):!1,s=a?await this.scanner.isEmptyDirectory(i):!0;return n.example===void 0?o?await this.collectExistingProject(n,i):s||n.isForce?await this.collectNewProject(n,s):(this.logger.error(`Directory is not empty and no ${Y(`package.json`)} was found.`),this.logger.info(`To scaffold a new project, run ${Y(`arkenv init`)} in an empty directory or use ${Y(`--force`)} to proceed anyway.`),null):await this.collectNewProject(n,s)}finally{this.logger.interactiveStdout(!1)}}async collectExistingProject(e,n){let{isYes:i,isForce:a,isQuiet:o,isAgent:s}=e,c=await this.scanner.checkRequirements(n),l=c.filter(e=>e.status===`fail`),u=c.filter(e=>e.status===`warn`);for(let e of u)this.logger.warn(`${e.requirement}: ${e.message}`);if(l.length>0)if(a){this.logger.warn(`Technical requirements not met, but continuing due to --force flag.`);for(let e of l)this.logger.warn(`${e.requirement}: ${e.message}`)}else{this.logger.error(`Technical requirements not met:`);for(let e of l)this.logger.error(`- ${e.requirement}: ${e.message}${e.current?` (Current: ${e.current}, Expected: ${e.expected})`:``}`);return this.logger.info(`Use --force to bypass these checks.`),null}let d=await this.scanner.checkGitStatus(n);if(d.status===`dirty`)if(a)this.logger.warn(`Git working tree is not clean, but continuing due to --force flag.`);else return this.logger.error(`Git working tree is not clean. Commit or stash your changes (use 'git stash -u' for untracked files) before running arkenv init.`),this.logger.info(`Use --force to bypass this check.`),null;d.status===`unknown`&&this.logger.warn(`Git working tree status could not be determined. Proceeding with caution.`);let f=!1,p=await this.scanner.checkTsConfig(n);if(p.status===`not_strict`)if(i)f=!0;else{this.logger.warn(`TypeScript strict mode is not enabled in your ${Y(p.file)}.`);let e=await this.prompt.confirm(`ArkEnv requires ${Y(`strict`)} mode in your ${Y(p.file)}. Would you like to enable it now?`,!0,`Yes (Recommended)`);if(e===null)return null;if(!e)return this.logger.cancel(`Operation cancelled.`),null;f=!0}let m=await this.scanner.detectFramework(n,p.parsed),h=m===`bun-fullstack`?await this.scanner.detectBunFeatures(n,p.parsed):void 0,g=await this.scanner.suggestDefaultEnvPath(n,p.parsed),_=r.default.resolve(n,g),v=await this.scanner.getEnvExampleKeys(n,p.parsed,_),y=await(async()=>{if(e.isStrict){let e=r.default.extname(_),t=_.slice(0,-e.length),n=[r.default.join(t,`internal`,`shared${e}`),r.default.join(t,`client${e}`),r.default.join(t,`server${e}`)];if((await Promise.all(n.map(e=>this.workspace.exists(e)))).some(Boolean))return!0}return this.workspace.exists(_)})(),b=async({framework:e,envPath:t})=>{if(e!==`vite`&&e!==`bun-fullstack`)return!1;let i=e===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,a=r.default.resolve(n,t),o=r.default.dirname(a),s=r.default.join(o,i);return this.workspace.exists(s)},x=await b({framework:m,envPath:g}),S=await this.prompt.runWizard((0,t.shake)({mode:`existing`,framework:m,bunFeatures:h,defaultEnvPath:g,tsConfig:p.parsed??null,envKeys:v?.keys,envKeysSource:v?.source,hasTypeFileAtPath:b,hasTypeFile:x,hasEnvSchemaFile:y,isStrict:e.isStrict,isSimple:e.isSimple,disableCodegen:e.noCodegen}),i);if(S===null)return null;let ee=await this.scanner.hasSkill(n);if(ee&&(S.skillDetected=!0,!o&&!s&&this.logger.info(`ArkEnv agent skill detected.`)),ee)S.installSkill=!1;else if(s)S.installSkill=!1;else if(i)S.installSkill=!0;else{let e=await this.prompt.confirm(`Would you like to install the ArkEnv agent skill?`,!0,`Yes (Recommended)`);if(e===null)return null;S.installSkill=e}let C=r.default.resolve(n,S.path);if(S.overwriteEnvSchemaFile===void 0&&(S.layout===`strict`?await(async()=>{let e=r.default.extname(C),t=C.slice(0,-e.length);return(await Promise.all([this.workspace.exists(r.default.join(t,`internal`,`shared${e}`)),this.workspace.exists(r.default.join(t,`client${e}`)),this.workspace.exists(r.default.join(t,`server${e}`))])).some(Boolean)})():await this.workspace.exists(C))){let e=S.layout===`strict`?`Strict layout files (client, server, internal/shared)`:r.default.basename(C),t=await this.prompt.confirm(`${e} already exist. Overwrite?`,!1);if(t===null)return null;if(!t)return this.logger.cancel(`Operation cancelled.`),null;S.overwriteEnvSchemaFile=t}let w=await this.scanner.detectPackageManager(n,p.parsed),T=r.default.extname(C),E=C.slice(0,-T.length),te=S.layout===`strict`?[r.default.join(E,`internal`,`shared${T}`),r.default.join(E,`client${T}`),r.default.join(E,`server${T}`)]:[C],D=[];for(let e of te)await this.workspace.exists(e)&&D.push(e);let O;if(S.framework===`vite`?O=`vite-env.d.ts`:S.framework===`bun-fullstack`&&(O=`bun-env.d.ts`),O){let e=r.default.dirname(C),t=r.default.join(e,O);await this.workspace.exists(t)&&D.push(t)}return(0,t.shake)({mode:`existing`,cwd:n,options:S,detectedFramework:m,detectedBunFeatures:h,packageManager:w,tsConfig:p,shouldUpdateTsConfig:f,existingFiles:D,isYes:i})}async collectNewProject(e,n=!0){let{isYes:r,example:i,name:a,isForce:o}=e,s=await this.registry.fetchRegistry(),c=await this.prompt.runWizard((0,t.shake)({mode:`new`,examples:s.examples,example:i,name:a}),r);if(c===null)return null;if(c.name===`.`&&!n&&!o)return this.logger.error(`Cannot scaffold into ${Y(`.`)} because the current directory is not empty.`),this.logger.info(`Run ${Y(`arkenv init`)} in an empty directory or choose a sub-directory name instead.`),null;let l=this.detectPackageManager();return(0,t.shake)({mode:`new`,cwd:process.cwd(),options:c,detectedFramework:c.framework,packageManager:l,tsConfig:{status:`not_found`},shouldUpdateTsConfig:!1,existingFiles:[],isYes:r})}detectPackageManager(){let e=process.env.npm_config_user_agent||``;return e.includes(`pnpm`)?`pnpm`:e.includes(`yarn`)?`yarn`:e.includes(`bun`)?`bun`:`npm`}};function Dn(e){let t=new on(e),n=t.logger,r=new Lt(t.isQuiet,n.stdio),i=new tn;return{cli:t,logger:n,workspace:r,prompt:i,initUseCase:new En(n,r,i,new xt),helpUseCase:new ln(n)}}let $,On=!1;async function kn(){if(process.env.INIT_CWD)try{process.chdir(process.env.INIT_CWD)}catch{}let{cli:e,logger:n,initUseCase:r,helpUseCase:i}=Dn(process.argv);$=n,An(n),e.validationError&&(n.error(e.validationError),await i.execute(),await n.flush(),process.exit(1)),e.helpRequested&&(await i.execute(),await n.flush(),process.exit(0)),e.command!==`init`&&(e.command?n.error(`Unknown command: ${e.command}`):n.error(`Missing command.`),await i.execute(),await n.flush(),process.exit(1));try{await r.execute((0,t.shake)(e.initInput))||(await n.flush(),process.exit(1))}catch(e){try{n.fatal(`An unexpected error occurred`,e)}catch{}await n.flush(),process.exit(1)}}function An(e){let t=async t=>{On&&process.exit(t),On=!0,setTimeout(()=>{process.exit(t)},2e3).unref(),e.interactiveStdout&&e.interactiveStdout(!1);try{e.cancel(`Operation cancelled.`),await e.flush()}catch(t){e.error&&e.error(`Logger failed during shutdown`,t)}finally{process.exit(t)}};process.on(`SIGINT`,()=>t(130)),process.on(`SIGTERM`,()=>t(143))}kn(),process.on(`unhandledRejection`,async e=>{if($){try{$.fatal(`Unhandled rejection`,e)}catch{}await $.flush()}else console.error(`Unhandled rejection`,e);process.exit(1)}),process.on(`uncaughtException`,async e=>{if($){try{$.fatal(`Uncaught exception`,e)}catch{}await $.flush()}else console.error(`Uncaught exception`,e);process.exit(1)});
389
+ `,e.metadata.layout===`strict`?o+=`Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`:o+=`Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`),{message:o,title:`Next steps`}}let r=e.skill?.dlxCommand.join(` `)||`npx`,a=e.skill?.packageName||`yamcodes/arkenv`,o=``,s=1,c=e.metadata.displayPath;if(e.metadata.layout===`strict`){let e=c.lastIndexOf(`.`),t=e===-1?c:c.slice(0,e);c=`${t}/client.ts, ${t}/server.ts, and ${t}/internal/shared.ts`}o+=`${s++}. Check ${Y(c)} and refine your environment schema.\n`;let l=e.metadata.framework===`nextjs`&&!e.metadata.disableCodegen&&!n;return e.metadata.framework===`vite`?o+=`${s++}. Access via ${Y(`import.meta.env.YOUR_VAR`)}\n`:e.metadata.framework===`bun-fullstack`?o+=`${s++}. Access via ${Y(`process.env.YOUR_VAR`)}\n`:e.metadata.framework===`nextjs`?e.metadata.layout===`strict`?(e.metadata.disableCodegen||l&&(o+=`${s++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,o+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,o+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`),o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`):(e.metadata.disableCodegen||l&&(o+=`${s++}. Wrap your Next.js config with ${Y(`withArkEnv`)} inside ${Y(`next.config.ts`)}:\n`,o+=` ${Y(`import { withArkEnv } from "@arkenv/nextjs/config";`)}\n`,o+=` ${Y(`export default withArkEnv(nextConfig);`)}\n`),o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`):e.metadata.framework===`nuxt`&&e.metadata.layout===`strict`?o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}/client"`)} (client) or ${Y(`import { env } from "${e.metadata.importPath}/server"`)} (server)\n`:o+=`${s++}. Import and use: ${Y(`import { env } from "${e.metadata.importPath}"`)}\n`,o+=`${s++}. (Recommended) Install the AI skill: ${Y(`${r} skills add ${a}`)}\n`,o+=` Then run ${Y(`/arkenv`)} inside your AI assistant to finish.`,{message:o,title:`Next steps`}}var Sn=class{constructor(e,t){this.workspace=e,this.reporter=t}async execute(e){let t=this.reporter.spinner();t.start(`Scaffolding ArkEnv configuration...`);try{e.clone&&(t.stop(`Starting new project scaffolding...`),this.reporter.step(`Cloning example ${Y(e.clone.example)}...`),await vn(this.workspace,e.clone),t.start(`Scaffolding complete, finalizing...`));for(let t of e.files){if(t.action===`append`){if(!e.bootstrap||e.bootstrap.framework!==`vite`&&e.bootstrap.framework!==`bun-fullstack`){this.reporter.warn(`Skipping safe-append for ${Y(r.default.basename(t.path))}: unsupported framework.`);continue}await this.workspace.safeAppend(t.path,t.content,e.bootstrap.framework)?this.reporter.info(`Appended ArkEnv types to ${Y(r.default.basename(t.path))}.`):this.reporter.info(`${Y(r.default.basename(t.path))} already contains ArkEnv types.`);continue}if(await this.workspace.mkdir(r.default.dirname(t.path),!0),await this.workspace.writeFile(t.path,t.content),t.label!==`environment schema`&&t.label?.includes(`types`)){let e=t.action===`overwrite`?`Updated`:`Created`;this.reporter.info(`${e} ${Y(r.default.basename(t.path))} for typesafe environment variables.`)}}if(t.stop(`Configuration scaffolded!`),e.install&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing dependencies with ${Y(e.install.packageManager)}...`);let[t,n]=bn(e.install.packageManager,e.install.dependencies);await this.workspace.execute(t,n,e.install.cwd??e.cwd)}let n=!1;if(e.tsConfig){let t=await this.workspace.updateTsConfigToStrict(e.tsConfig.path);t.status===`updated`?(this.reporter.info(`Enforced strict: true in your ${Y(t.file)}`),n=!0):t.status===`error`&&this.reporter.warn(`Could not automatically update ${Y(t.file||`tsconfig.json`)}. Please ensure 'strict: true' is set manually.`)}let i=!1;if(e.bootstrap){if(e.bootstrap.framework===`vite`){let t=await this.workspace.findViteConfig(e.cwd);if(t){this.reporter.step(`Bootstrapping Vite plugin...`);let n=await this.workspace.bootstrapViteConfig(t,e.bootstrap.importPath||`./src/env`);n.success?n.updated&&this.reporter.info(`Updated ${Y(r.default.basename(t))}`):(this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${n.error}`),this.reporter.info(`Please add ${Y(`@arkenv/vite-plugin`)} manually.`))}else this.reporter.info(`No Vite config found - please add ${Y(`@arkenv/vite-plugin`)} to your Vite config manually.`)}else if(e.bootstrap.framework===`bun-fullstack`){let t=await this.workspace.findBunConfig(e.cwd),n=await this.workspace.bootstrapBunConfig(t,e.bootstrap.bunFeatures);n.success&&n.instructions?this.reporter.info(n.instructions):n.success||this.reporter.error(n.error||`Bun bootstrap failed`)}else if(e.bootstrap.framework===`nextjs`){this.reporter.step(`Generating Next.js environment bindings...`);let t=`import('@arkenv/nextjs/config').then(({ runCodegen }) => { const path = require('path'); const schemaPath = path.resolve(process.cwd(), '${e.metadata.displayPath}'); const outputPath = path.join(path.dirname(schemaPath), 'generated', 'env.gen.ts'); runCodegen(schemaPath, outputPath); }).catch(err => { console.error(err); process.exit(1); });`;try{await this.workspace.execute(`node`,[`-e`,t],e.cwd),this.reporter.info(`Generated ${Y(`env.gen.ts`)} for Next.js`)}catch{this.reporter.warn(`Failed to automatically generate ${Y(`env.gen.ts`)}. It will be generated when you start your dev server.`)}if(e.bootstrap.wrapNextjsConfig!==!1){this.reporter.step(`Bootstrapping Next.js config...`);let t=await this.workspace.findNextjsConfig(e.cwd);if(t){let e=await this.workspace.bootstrapNextjsConfig(t);e.success?e.updated?(this.reporter.info(`Updated ${Y(r.default.basename(t))}`),i=!0):(this.reporter.info(`${Y(r.default.basename(t))} already uses withArkEnv`),i=!0):this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${e.error}`)}else this.reporter.info(`No Next.js config found. Please wrap your config with ${Y(`withArkEnv`)} manually.`)}}else if(e.bootstrap.framework===`nuxt`){this.reporter.step(`Bootstrapping Nuxt config...`);let t=await this.workspace.findNuxtConfig(e.cwd);if(t){let e=await this.workspace.bootstrapNuxtConfig(t);e.success?(e.updated?this.reporter.info(`Updated ${Y(r.default.basename(t))}`):this.reporter.info(`${Y(r.default.basename(t))} already registers @arkenv/nuxt/module`),i=!0):this.reporter.warn(`Could not automatically update ${Y(r.default.basename(t))}: ${e.error}`)}else this.reporter.info(`No Nuxt config found. Please register ${Y(`@arkenv/nuxt/module`)} manually.`)}}let a=!1;if(e.skill&&process.env.SKIP_INSTALL!==`true`){this.reporter.step(`Installing ArkEnv agent skill...`);try{let[t,...n]=e.skill.dlxCommand,r=[...n,`skills`,`add`,e.skill.packageName];e.skill.isYes&&r.push(`--yes`),await this.workspace.execute(t,r,e.cwd),a=!0}catch(e){let t=e instanceof Error?e.message:String(e);this.reporter.warn(`Failed to install ArkEnv AI skill: ${t}`)}}let o=xn(e,a,i);if(this.reporter.note(o.message,o.title),e.metadata.layout===`strict`){let t=r.default.resolve(e.cwd,e.metadata.displayPath);if(await this.workspace.exists(t)){let t=e.metadata.displayPath,n=r.default.basename(t,r.default.extname(t));this.reporter.warn(`Found existing single-file schema at ${Y(t)}. You can delete it after updating your imports to point to your new ${Y(`${n}/client`)} and ${Y(`${n}/server`)}.`)}}this.reporter.finish(`${St} ArkEnv scaffolding complete. Happy coding!`,{path:e.metadata.displayPath,framework:e.metadata.framework,validator:e.metadata.validator,packageManager:e.metadata.packageManager,tsConfigUpdated:n,skillInstalled:a})}catch(e){throw t.stop(`Scaffolding failed.`),e}}};function Cn(e){switch(e){case`pnpm`:return[`pnpm`,`dlx`];case`yarn`:return[`yarn`,`dlx`];case`bun`:return[`bunx`];default:return[`npx`]}}function wn(e){let{mode:n,options:i,packageManager:a,tsConfig:o,shouldUpdateTsConfig:s,cwd:c,existingFiles:l}=e,u=i.name&&i.name!==`.`?r.default.basename(i.name):void 0,d={files:[],cwd:c,metadata:(0,t.shake)({displayPath:``,framework:i.framework,validator:i.validator,packageManager:a,importPath:``,mode:n,example:i.example,name:u,layout:i.layout,skillDetected:i.skillDetected,disableCodegen:i.disableCodegen})};if(n===`new`){if(!i.example)throw Error(`New project scaffolding requires an example.`);let t=i.name&&i.name!==`.`?r.default.join(c,i.name):void 0,n=i.name&&i.name!==`.`?r.default.basename(i.name):r.default.basename(c);return d.clone={repository:`https://github.com/yamcodes/arkenv.git`,example:i.example,targetName:n,...t!==void 0&&{targetDir:t}},d.install={packageManager:a,dependencies:[],...t!==void 0&&{cwd:t}},i.installSkill&&(d.skill={dlxCommand:Cn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes}),d.metadata.displayPath=`./src/env.ts`,d.metadata.importPath=`./src/env`,d}let f=r.default.resolve(c,i.path),p=r.default.dirname(f);if((i.framework===`nextjs`||i.framework===`nuxt`)&&i.layout===`strict`){let e=r.default.extname(f),t=f.slice(0,-e.length),n=r.default.join(t,`internal`,`shared${e}`),a=r.default.join(t,`client${e}`),s=r.default.join(t,`server${e}`),u;if((i.framework===`nextjs`||i.framework===`nuxt`)&&!i.disableCodegen&&o?.parsed){let e=o.parsed,n=(e.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=e.path?r.default.dirname(e.path):c,a=r.default.join(t,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let e of n[`@/*`]){let t=e.replace(/^\.\//,``).replace(/\*$/,``);if(t===``||o.startsWith(t)){let e=o;t!==``&&o.startsWith(t)&&(e=o.substring(t.length)),e=e.replace(/^\/+/,``).replace(/\/+$/,``),u=`@/${e}/env.gen`.replace(/\/+/g,`/`);break}}}}let p=_n(i,u),m=l.includes(n),h=l.includes(a),g=l.includes(s);(!m||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:n,content:p.shared,action:m?`overwrite`:`create`,label:`shared environment schema`}),(!h||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:a,content:p.client,action:h?`overwrite`:`create`,label:`client environment schema`}),(!g||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:s,content:p.server,action:g?`overwrite`:`create`,label:`server environment schema`})}else{let e;if((i.framework===`nextjs`||i.framework===`nuxt`)&&!i.disableCodegen&&o?.parsed){let t=o.parsed,n=(t.compilerOptions||{}).paths||{};if(n[`@/*`]){let i=t.path?r.default.dirname(t.path):c,a=r.default.join(p,`generated`),o=r.default.relative(i,a).replace(/\\/g,`/`);for(let t of n[`@/*`]){let n=t.replace(/^\.\//,``).replace(/\*$/,``);if(n===``||o.startsWith(n)){let t=o;n!==``&&o.startsWith(n)&&(t=o.substring(n.length)),t=t.replace(/^\/+/,``).replace(/\/+$/,``),e=`@/${t}/env.gen`.replace(/\/+/g,`/`);break}}}}let t=gn(i,e),n=l.includes(f);(!n||i.overwriteEnvSchemaFile!==!1)&&d.files.push({path:f,content:t,action:n?`overwrite`:`create`,label:`environment schema`})}let m=[`arkenv`,i.validator];if(i.framework===`vite`&&m.push(`@arkenv/vite-plugin`),i.framework===`bun-fullstack`&&i.bunFeatures?.length&&m.push(`@arkenv/bun-plugin`),i.framework===`nextjs`&&m.push(`@arkenv/nextjs`),i.framework===`nuxt`&&m.push(`@arkenv/nuxt`),(i.framework===`vite`||i.framework===`nextjs`||i.framework===`nuxt`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&!m.includes(`arktype`)&&m.push(`arktype`),d.install={packageManager:a,dependencies:m},s&&o.file&&(d.tsConfig={path:r.default.resolve(c,o.file),action:`strict`}),(i.framework===`vite`||i.framework===`bun-fullstack`&&i.bunFeatures?.length)&&i.installTypeDefinitions!==!1){let e=i.framework===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,t=r.default.join(p,e),n=l.includes(t);if(i.envDtsHandling!==`skip`)if(i.envDtsHandling===`append`||!i.envDtsHandling&&n)d.files.push({path:t,content:f,action:`append`,label:`${i.framework} types`});else{let e=i.framework===`vite`?fn(i.path):pn(i.path);d.files.push({path:t,content:e,action:n?`overwrite`:`create`,label:`${i.framework} types`})}}(i.framework===`vite`||i.framework===`bun-fullstack`||i.framework===`nextjs`&&!i.disableCodegen||i.framework===`nuxt`)&&(d.bootstrap=(0,t.shake)({framework:i.framework,bunFeatures:i.framework===`bun-fullstack`?i.bunFeatures:void 0,wrapNextjsConfig:i.framework===`nextjs`?i.wrapNextjsConfig!==!1:void 0})),i.installSkill&&(d.skill={dlxCommand:Cn(a),packageName:`yamcodes/arkenv`,isYes:e.isYes});let h=r.default.relative(c,f).replace(/\\/g,`/`),g=h.startsWith(`.`)?h:`./${h}`,_=g.replace(/\.(ts|js|tsx|jsx)$/,``);return d.metadata.displayPath=g,d.metadata.importPath=_,d.bootstrap&&(d.bootstrap.importPath=_),d}var Tn=class{async fetchRegistry(){try{let e=await fetch(`https://raw.githubusercontent.com/yamcodes/arkenv/main/examples/registry.json`);if(!e.ok)throw Error(`Failed to fetch registry: ${e.statusText}`);return await e.json()}catch{return{examples:[{id:`basic`,name:`Basic`,description:`A minimal ArkEnv setup in Node.js`,framework:`vanilla`},{id:`with-nextjs`,name:`Next.js`,description:`Minimal Next.js project with ArkType`,framework:`nextjs`},{id:`with-vite-react`,name:`React + Vite`,framework:`vite`},{id:`with-bun`,name:`Bun (Vanilla)`,description:`Minimal Bun project with ArkType`,framework:`vanilla`},{id:`with-bun-react`,name:`React + Bun fullstack dev server`,framework:`bun-fullstack`},{id:`with-zod`,name:`Zod`,description:`ArkEnv with Zod in Node.js`,framework:`vanilla`}]}}}},En=class{constructor(e,t,n,r,i=new Tn){this.logger=e,this.workspace=t,this.prompt=n,this.scanner=r,this.registry=i}async execute(e){let t=await this.collect(e);if(!t)return!1;let n=wn(t),r=new Sn(this.workspace,this.logger);try{await r.execute(n)}catch(e){this.logger.fatal(`Scaffolding failed.`,e)}return!0}async collect(e){this.logger.interactiveStdout(!0);try{let t=e.name;t&&r.default.resolve(process.cwd(),t)===process.cwd()&&(t=`.`);let n={...e,...t!==void 0&&{name:t}},i=t&&t!==`.`?r.default.resolve(process.cwd(),t):process.cwd(),a=await this.workspace.exists(i),o=a?await this.scanner.hasPackageJson(i):!1,s=a?await this.scanner.isEmptyDirectory(i):!0;return n.example===void 0?o?await this.collectExistingProject(n,i):s||n.isForce?await this.collectNewProject(n,s):(this.logger.error(`Directory is not empty and no ${Y(`package.json`)} was found.`),this.logger.info(`To scaffold a new project, run ${Y(`arkenv init`)} in an empty directory or use ${Y(`--force`)} to proceed anyway.`),null):await this.collectNewProject(n,s)}finally{this.logger.interactiveStdout(!1)}}async collectExistingProject(e,n){let{isYes:i,isForce:a,isQuiet:o,isAgent:s}=e,c=await this.scanner.checkRequirements(n),l=c.filter(e=>e.status===`fail`),u=c.filter(e=>e.status===`warn`);for(let e of u)this.logger.warn(`${e.requirement}: ${e.message}`);if(l.length>0)if(a){this.logger.warn(`Technical requirements not met, but continuing due to --force flag.`);for(let e of l)this.logger.warn(`${e.requirement}: ${e.message}`)}else{this.logger.error(`Technical requirements not met:`);for(let e of l)this.logger.error(`- ${e.requirement}: ${e.message}${e.current?` (Current: ${e.current}, Expected: ${e.expected})`:``}`);return this.logger.info(`Use --force to bypass these checks.`),null}let d=await this.scanner.checkGitStatus(n);if(d.status===`dirty`)if(a)this.logger.warn(`Git working tree is not clean, but continuing due to --force flag.`);else return this.logger.error(`Git working tree is not clean. Commit or stash your changes (use 'git stash -u' for untracked files) before running arkenv init.`),this.logger.info(`Use --force to bypass this check.`),null;d.status===`unknown`&&this.logger.warn(`Git working tree status could not be determined. Proceeding with caution.`);let f=!1,p=await this.scanner.checkTsConfig(n);if(p.status===`not_strict`)if(i)f=!0;else{this.logger.warn(`TypeScript strict mode is not enabled in your ${Y(p.file)}.`);let e=await this.prompt.confirm(`ArkEnv requires ${Y(`strict`)} mode in your ${Y(p.file)}. Would you like to enable it now?`,!0,`Yes (Recommended)`);if(e===null)return null;if(!e)return this.logger.cancel(`Operation cancelled.`),null;f=!0}let m=await this.scanner.detectFramework(n,p.parsed);if(e.isSimple&&m===`nextjs`)return this.logger.error(`❌ Error: The --simple layout is deprecated and no longer supported by the CLI. Arkenv now exclusively uses the Flat Layout. Run npx arkenv init without this flag.`),null;let h=m===`bun-fullstack`?await this.scanner.detectBunFeatures(n,p.parsed):void 0,g=await this.scanner.suggestDefaultEnvPath(n,p.parsed),_=r.default.resolve(n,g),v=await this.scanner.getEnvExampleKeys(n,p.parsed,_),y=await(async()=>{if(e.isStrict){let e=r.default.extname(_),t=_.slice(0,-e.length),n=[r.default.join(t,`internal`,`shared${e}`),r.default.join(t,`client${e}`),r.default.join(t,`server${e}`)];if((await Promise.all(n.map(e=>this.workspace.exists(e)))).some(Boolean))return!0}return this.workspace.exists(_)})(),b=async({framework:e,envPath:t})=>{if(e!==`vite`&&e!==`bun-fullstack`)return!1;let i=e===`vite`?`vite-env.d.ts`:`bun-env.d.ts`,a=r.default.resolve(n,t),o=r.default.dirname(a),s=r.default.join(o,i);return this.workspace.exists(s)},x=await b({framework:m,envPath:g}),S=await this.prompt.runWizard((0,t.shake)({mode:`existing`,framework:m,bunFeatures:h,defaultEnvPath:g,tsConfig:p.parsed??null,envKeys:v?.keys,envKeysSource:v?.source,hasTypeFileAtPath:b,hasTypeFile:x,hasEnvSchemaFile:y,isStrict:e.isStrict,isSimple:e.isSimple,isFlat:e.isFlat,disableCodegen:e.noCodegen}),i);if(S===null)return null;let ee=await this.scanner.hasSkill(n);if(ee&&(S.skillDetected=!0,!o&&!s&&this.logger.info(`ArkEnv agent skill detected.`)),ee)S.installSkill=!1;else if(s)S.installSkill=!1;else if(i)S.installSkill=!0;else{let e=await this.prompt.confirm(`Would you like to install the ArkEnv agent skill?`,!0,`Yes (Recommended)`);if(e===null)return null;S.installSkill=e}let C=r.default.resolve(n,S.path);if(S.overwriteEnvSchemaFile===void 0&&(S.layout===`strict`?await(async()=>{let e=r.default.extname(C),t=C.slice(0,-e.length);return(await Promise.all([this.workspace.exists(r.default.join(t,`internal`,`shared${e}`)),this.workspace.exists(r.default.join(t,`client${e}`)),this.workspace.exists(r.default.join(t,`server${e}`))])).some(Boolean)})():await this.workspace.exists(C))){let e=S.layout===`strict`?`Strict layout files (client, server, internal/shared)`:r.default.basename(C),t=await this.prompt.confirm(`${e} already exist. Overwrite?`,!1);if(t===null)return null;if(!t)return this.logger.cancel(`Operation cancelled.`),null;S.overwriteEnvSchemaFile=t}let w=await this.scanner.detectPackageManager(n,p.parsed),T=r.default.extname(C),E=C.slice(0,-T.length),te=S.layout===`strict`?[r.default.join(E,`internal`,`shared${T}`),r.default.join(E,`client${T}`),r.default.join(E,`server${T}`)]:[C],D=[];for(let e of te)await this.workspace.exists(e)&&D.push(e);let O;if(S.framework===`vite`?O=`vite-env.d.ts`:S.framework===`bun-fullstack`&&(O=`bun-env.d.ts`),O){let e=r.default.dirname(C),t=r.default.join(e,O);await this.workspace.exists(t)&&D.push(t)}return(0,t.shake)({mode:`existing`,cwd:n,options:S,detectedFramework:m,detectedBunFeatures:h,packageManager:w,tsConfig:p,shouldUpdateTsConfig:f,existingFiles:D,isYes:i})}async collectNewProject(e,n=!0){let{isYes:r,example:i,name:a,isForce:o}=e,s=await this.registry.fetchRegistry(),c=await this.prompt.runWizard((0,t.shake)({mode:`new`,examples:s.examples,example:i,name:a}),r);if(c===null)return null;if(c.name===`.`&&!n&&!o)return this.logger.error(`Cannot scaffold into ${Y(`.`)} because the current directory is not empty.`),this.logger.info(`Run ${Y(`arkenv init`)} in an empty directory or choose a sub-directory name instead.`),null;let l=this.detectPackageManager();return(0,t.shake)({mode:`new`,cwd:process.cwd(),options:c,detectedFramework:c.framework,packageManager:l,tsConfig:{status:`not_found`},shouldUpdateTsConfig:!1,existingFiles:[],isYes:r})}detectPackageManager(){let e=process.env.npm_config_user_agent||``;return e.includes(`pnpm`)?`pnpm`:e.includes(`yarn`)?`yarn`:e.includes(`bun`)?`bun`:`npm`}};function Dn(e){let t=new on(e),n=t.logger,r=new Lt(t.isQuiet,n.stdio),i=new tn;return{cli:t,logger:n,workspace:r,prompt:i,initUseCase:new En(n,r,i,new xt),helpUseCase:new ln(n)}}let $,On=!1;async function kn(){if(process.env.INIT_CWD)try{process.chdir(process.env.INIT_CWD)}catch{}let{cli:e,logger:n,initUseCase:r,helpUseCase:i}=Dn(process.argv);$=n,An(n),e.validationError&&(n.error(e.validationError),await i.execute(),await n.flush(),process.exit(1)),e.helpRequested&&(await i.execute(),await n.flush(),process.exit(0)),e.command!==`init`&&(e.command?n.error(`Unknown command: ${e.command}`):n.error(`Missing command.`),await i.execute(),await n.flush(),process.exit(1));try{await r.execute((0,t.shake)(e.initInput))||(await n.flush(),process.exit(1))}catch(e){try{n.fatal(`An unexpected error occurred`,e)}catch{}await n.flush(),process.exit(1)}}function An(e){let t=async t=>{On&&process.exit(t),On=!0,setTimeout(()=>{process.exit(t)},2e3).unref(),e.interactiveStdout&&e.interactiveStdout(!1);try{e.cancel(`Operation cancelled.`),await e.flush()}catch(t){e.error&&e.error(`Logger failed during shutdown`,t)}finally{process.exit(t)}};process.on(`SIGINT`,()=>t(130)),process.on(`SIGTERM`,()=>t(143))}kn(),process.on(`unhandledRejection`,async e=>{if($){try{$.fatal(`Unhandled rejection`,e)}catch{}await $.flush()}else console.error(`Unhandled rejection`,e);process.exit(1)}),process.on(`uncaughtException`,async e=>{if($){try{$.fatal(`Uncaught exception`,e)}catch{}await $.flush()}else console.error(`Uncaught exception`,e);process.exit(1)});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arkenv/cli",
3
3
  "type": "module",
4
- "version": "0.2.11",
4
+ "version": "0.3.0",
5
5
  "description": "Interactive CLI for scaffolding ArkEnv projects",
6
6
  "bin": {
7
7
  "arkenv": "./dist/index.cjs"