@teispace/next-maker 5.0.5 → 5.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Fp}from"commander";var Ae={name:"@teispace/next-maker",version:"5.0.5",description:"Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",keywords:["nextjs","react","typescript","tailwindcss","starter","template","redux","zustand","tanstack-query","server-actions","cli"],type:"module",homepage:"https://github.com/teispace/npm-packages/tree/main/packages/next-maker#readme",bugs:{url:"https://github.com/teispace/npm-packages/issues"},license:"MIT",author:"Teispace",files:["dist","README.md","LICENSE","CHANGELOG.md"],bin:"dist/index.js",repository:{type:"git",url:"git+https://github.com/teispace/npm-packages.git",directory:"packages/next-maker"},scripts:{build:"tsx build.ts",start:"node dist/index.js",dev:"tsx --watch src/index.ts",test:"vitest run","test:watch":"vitest","test:cov":"vitest run --coverage","type-check":"tsc --noEmit",clean:"rm -rf dist",prepublishOnly:"yarn clean && yarn build",smoke:"tsx scripts/smoke.ts"},dependencies:{commander:"^15.0.0",degit:"^3.8.0",enquirer:"^2.4.1",ora:"^9.4.1",picocolors:"^1.1.1","png-to-ico":"^3.0.2",sharp:"^0.35.3"},devDependencies:{"@types/degit":"^2.8.6","@types/node":"^26.2.0",esbuild:"^0.28.2",tsx:"^4.23.12",typescript:"^6.0.3",vitest:"^4.1.11"},engines:{node:">=24.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};import{copyFile as ea}from"node:fs/promises";import At from"node:path";import I from"picocolors";var sn=/@next-maker:([\w-]+)(?::(start|end))?/,Ys=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,Qs=e=>e.replace(/\s*\{\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*\}\s*$/,"").replace(/\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*$/,"").replace(/\s*\/\/[^\n]*@next-maker:[^\n]*$/,"").replace(/\s*#[^\n]*@next-maker:[^\n]*$/,""),Xt=(e,{off:t})=>{let r=e.split(`
3
- `),n=[];for(let o=0;o<r.length;o++){let s=r[o],i=s.match(sn);if(!i){n.push(s);continue}let[,a,c]=i,l=t.has(a);if(c==="start"){let u=Zs(r,o+1,a);l&&(o=u);continue}if(c==="end")continue;let p=Ys.test(s);if(l){p&&o++;continue}p||n.push(Qs(s))}return n.join(`
4
- `)},Zs=(e,t,r)=>{for(let n=t;n<e.length;n++){let o=e[n].match(sn);if(o&&o[1]===r&&o[2]==="end")return n}throw new Error(`Anchor @next-maker:${r}:start has no matching :end`)},ze=e=>e.includes("@next-maker:"),an=(e,t)=>{let r=e.split(`
5
- `),n=[],o=new RegExp(`^import\\s+${t}\\s+from\\s+['"][^'"]+['"];?\\s*$`),s=/^(import\s+(?:type\s+)?)\{([^}]+)\}(\s+from\s+['"][^'"]+['"];?\s*)$/;for(let i of r){if(o.test(i))continue;let a=i.match(s);if(a){let c=a[2].split(",").map(p=>p.trim()).filter(Boolean),l=c.filter(p=>p.replace(/^type\s+/,"").split(/\s+as\s+/)[0]!==t);if(l.length===0)continue;if(l.length<c.length){n.push(`${a[1]}{ ${l.join(", ")} }${a[3]}`);continue}}n.push(i)}return n.join(`
6
- `)},We=(e,t)=>{let r=e.split(`
7
- `),n=new RegExp(`^([ \\t]*)<${t}\\b`),o=-1,s="";for(let f=0;f<r.length;f++){let d=r[f].match(n);if(d){o=f,s=d[1];break}}if(o===-1)return e;let i=o;for(;i<r.length&&!/>\s*$/.test(r[i]);)i++;if(i>=r.length)throw new Error(`unwrapJsx: opening <${t}> never closes`);if(/\/>\s*$/.test(r[i]))return e;let a=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=new RegExp(`^${a}</${t}>\\s*$`),l=-1;for(let f=i+1;f<r.length;f++)if(c.test(r[f])){l=f;break}if(l===-1)throw new Error(`unwrapJsx: no closing </${t}> at the opening indent`);let p=r.slice(i+1,l).map(f=>f.startsWith(" ")?f.slice(2):f),u=[...r.slice(0,o),...p,...r.slice(l+1)].join(`
8
- `);return an(u,t)},Ke=(e,t)=>{let r=new RegExp(`\\b${t}\\(`,"g"),n=e,o=r.exec(n);for(;o;){let s=o.index,i=0,a=s+o[0].length-1;for(;a<n.length;a++)if(n[a]==="(")i++;else if(n[a]===")"&&(i--,i===0))break;if(i!==0)throw new Error(`unwrapCall: unbalanced parentheses after ${t}(`);let c=n.slice(s+o[0].length,a);n=n.slice(0,s)+c+n.slice(a+1),r.lastIndex=s,o=r.exec(n)}return n};import{cp as hn,mkdir as si,mkdtemp as ii,readdir as fn,readFile as Ie,rm as Qt,rmdir as ai,stat as ci,writeFile as Ne}from"node:fs/promises";import{tmpdir as pi}from"node:os";import F from"node:path";import{readdir as ei}from"node:fs/promises";import wt from"node:path";var cn=e=>{let t="^";for(let r=0;r<e.length;r++){let n=e[r];n==="*"?e[r+1]==="*"?(r++,e[r+1]==="/"?(r++,t+="(?:.*/)?"):t+=".*"):t+="[^/]*":t+=n.replace(/[.+?^${}()|[\]\\]/g,"\\$&")}return new RegExp(`${t}$`)},ti=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results"]),L=async(e,t=ti)=>{let r=[],n=async o=>{let s;try{s=await ei(o,{withFileTypes:!0})}catch{return}for(let i of s)if(i.isDirectory()){if(t.has(i.name))continue;await n(wt.join(o,i.name))}else i.isFile()&&r.push(wt.relative(e,wt.join(o,i.name)).split(wt.sep).join("/"))};return await n(e),r.sort()},ie=(e,t)=>{let r=cn(t);return e.filter(n=>r.test(n))};import{readFile as pn}from"node:fs/promises";import ln from"node:path";var xt="next-maker.json",ye=".next-maker/overlays",mn=1,B=e=>{throw new Error(`Invalid ${xt}: ${e}`)},dn=e=>{(typeof e!="object"||e===null)&&B("not an object");let t=e;t.manifestVersion!==mn&&B(`manifestVersion ${String(t.manifestVersion)} is not supported by this CLI (expected ${mn})`),(!t.starter?.name||!t.starter.version)&&B("starter.name and starter.version are required"),(!t.options||typeof t.options!="object")&&B("options is required"),(!t.features||typeof t.features!="object")&&B("features is required"),(!t.packageManagers||typeof t.packageManagers!="object")&&B("packageManagers is required");let r=t.options,n=t.features;for(let[o,s]of Object.entries(r))["choice","boolean","multi"].includes(s.type)||B(`option ${o} has unknown type ${String(s.type)}`),s.type!=="boolean"&&!Array.isArray(s.values)&&B(`option ${o} needs a values array`),s.default===void 0&&B(`option ${o} needs a default`);for(let[o,s]of Object.entries(n)){(!s.when||typeof s.when!="object")&&B(`feature ${o} needs a when`);for(let i of Object.keys(s.when))r[i]||B(`feature ${o} refers to unknown option ${i}`)}return{...t,always:{remove:t.always?.remove??[]}}},Xe=async e=>{let t=ln.join(e,xt),r;try{r=await pn(t,"utf-8")}catch{throw new Error(`The starter at ${e} has no ${xt}. This CLI needs a starter that ships a composition manifest (nextjs-starter 2.x or later).`)}let n=dn(JSON.parse(r));try{let o=JSON.parse(await pn(ln.join(e,"package.json"),"utf-8"));typeof o.version=="string"&&o.version&&(n.starter={...n.starter,version:o.version})}catch{}return n},un=(e,t)=>e.some(r=>r===t),bt=(e,t,r)=>t===void 0?!1:e?.type==="multi"&&Array.isArray(t)?t.some(n=>un(r,n)):un(r,t),ae=(e,t,r)=>Object.entries(t.when).every(([n,o])=>bt(e.options[n],r[n],o)),ri=e=>e.type==="boolean"?!1:e.type==="multi"?[]:e.default,ni=(e,t,r)=>{if(e.type==="boolean"){if(typeof r=="boolean")return r;if(r==="true")return!0;if(r==="false")return!1;throw new Error(`Option ${t} expects true or false, got ${String(r)}`)}if(e.type==="multi"){let s=(Array.isArray(r)?r:String(r).split(",")).map(i=>String(i).trim()).filter(Boolean);for(let i of s)if(!e.values?.includes(i))throw new Error(`Option ${t} does not accept ${i}; valid: ${e.values?.join(", ")}`);return s}let n=String(r);if(!e.values?.includes(n))throw new Error(`Option ${t} does not accept ${n}; valid: ${e.values?.join(", ")}`);return n},Ye=(e,t={})=>{let r={},n=[],o=Object.keys(t).filter(s=>!e.options[s]);for(let[s,i]of Object.entries(e.options)){let a=t[s];r[s]=a===void 0?i.default:ni(i,s,a)}for(let[s,i]of Object.entries(e.options))if(i.requires)for(let[a,c]of Object.entries(i.requires)){if(bt(e.options[a],r[a],c))continue;let l=ri(i);r[s]!==l&&JSON.stringify(r[s])!==JSON.stringify(l)&&(n.push({option:s,value:l,reason:`${s} requires ${a} to be ${c.map(String).join(" or ")}`}),r[s]=l)}return{answers:r,forced:n,unknown:o}};var ce=(e,t)=>{switch(e){case"npm":return`npm run ${t}`;case"bun":return`bun run ${t}`;case"yarn":return`yarn ${t}`;default:return`pnpm ${t}`}},oi=e=>{switch(e){case"npm":return[[/\bpnpm install --frozen-lockfile\b/g,"npm ci"],[/\bpnpm install\b/g,"npm install"],[/\bpnpm add -D\b/g,"npm install --save-dev"],[/\bpnpm add\b/g,"npm install"],[/\bpnpm dlx\b/g,"npx"],[/\bpnpm exec\b/g,"npx --no --"],[/\bpnpm ([\w:.-]+)/g,"npm run $1"]];case"yarn":return[[/\bpnpm install --frozen-lockfile\b/g,"yarn install --immutable"],[/\bpnpm install\b/g,"yarn install"],[/\bpnpm add -D\b/g,"yarn add -D"],[/\bpnpm add\b/g,"yarn add"],[/\bpnpm dlx\b/g,"yarn dlx"],[/\bpnpm exec\b/g,"yarn"],[/\bpnpm ([\w:.-]+)/g,"yarn $1"]];case"bun":return[[/\bpnpm install --frozen-lockfile\b/g,"bun install --frozen-lockfile"],[/\bpnpm install\b/g,"bun install"],[/\bpnpm add -D\b/g,"bun add -d"],[/\bpnpm add\b/g,"bun add"],[/\bpnpm dlx\b/g,"bunx"],[/\bpnpm exec\b/g,"bunx"],[/\bpnpm ([\w:.-]+)/g,"bun run $1"]];default:return[]}},vt=(e,t)=>{if(t==="pnpm")return e;let r=e;for(let[n,o]of oi(t))r=r.replace(n,o);return r},Yt=e=>e==="package.json"||e.startsWith(".husky/")||e.endsWith(".md")||e===".lintstagedrc.mjs";var we=e=>[...new Set(e)],er=(e,t,r)=>{let n=e.packageManagers[r];if(!n)throw new Error(`This starter does not support ${r}; valid: ${Object.keys(e.packageManagers).join(", ")}`);let o=[],s=[],i=[],a=[],c=[];for(let[p,u]of Object.entries(e.features)){let f=ae(e,u,t);(f?o:s).push(p);let d=f?u.on:u.off;if(!d)continue;i.push(d);let g=Object.keys(u.when);d.overlay&&!a.some(y=>y.name===d.overlay)&&a.push({name:d.overlay,options:g}),d.remove?.length&&c.push({feature:p,options:g,patterns:d.remove})}let l=we([...e.always.remove,...n.remove??[]]);return{answers:t,packageManager:r,pmSpec:n,featuresOn:o,featuresOff:s,pmOverlays:n.overlay?[n.overlay]:[],featureOverlays:a,removePatterns:we([...l,...c.flatMap(p=>p.patterns)]),unconditionalRemovals:l,featureRemovals:c,anchorsOff:new Set(i.flatMap(p=>p.anchors??[])),unwrapJsx:i.flatMap(p=>p.unwrapJsx??[]),unwrapCall:i.flatMap(p=>p.unwrapCall??[]),packages:we(i.flatMap(p=>p.packages??[])),devPackages:we(i.flatMap(p=>p.devPackages??[])),scripts:we(i.flatMap(p=>p.scripts??[])),env:we(i.flatMap(p=>p.env??[])),packageJsonKeys:we(i.flatMap(p=>p.packageJsonKeys??[]))}},li=new Set([".ts",".tsx",".js",".mjs",".cjs",".css",".json",".yml",".yaml",".md",".sh",".example",".mdx"]),mi=e=>li.has(F.extname(e))||e.startsWith(".husky/")||e==="Dockerfile",gn=async(e,t,r)=>{let n=F.join(e,r),o=await L(n,new Set);if(o.length===0)throw new Error(`Overlay "${r}" is missing or empty at ${ye}/${r}`);for(let s of o){let i=F.join(t,s);await si(F.dirname(i),{recursive:!0}),await hn(F.join(n,s),i,{force:!0})}return o},tr=async(e,t=e)=>{let r;try{r=await fn(t,{withFileTypes:!0})}catch{return}for(let n of r)n.isDirectory()&&n.name!=="node_modules"&&n.name!==".git"&&await tr(e,F.join(t,n.name));t!==e&&(await fn(t)).length===0&&await ai(t)},yn=(e,t)=>{let r=t.split("."),n=e;for(let s of r.slice(0,-1)){let i=n?.[s];if(typeof i!="object"||i===null)return;n=i}let o=r[r.length-1];if(n&&o in n&&delete n[o],r.length>1){let s=r.slice(0,-1).join("."),i=r.slice(0,-1).reduce((a,c)=>a?.[c],e);i&&typeof i=="object"&&Object.keys(i).length===0&&yn(e,s)}},ui=async(e,t,r)=>{let n=F.join(e,"package.json"),o=JSON.parse(await Ie(n,"utf-8"));for(let i of t.packages)delete o.dependencies?.[i];for(let i of t.devPackages)delete o.devDependencies?.[i];for(let i of t.scripts)delete o.scripts?.[i];for(let i of t.packageJsonKeys)yn(o,i);let s=r.validateScript;if(s&&o.scripts?.[s.name]){let i=s.steps.filter(a=>o.scripts[a]);o.scripts[s.name]=i.map(a=>ce(t.packageManager,a)).join(" && ")}if(o.scripts)for(let[i,a]of Object.entries(o.scripts))typeof a=="string"&&(o.scripts[i]=vt(a,t.packageManager));if(t.pmSpec.packageManager?o.packageManager=t.pmSpec.packageManager:delete o.packageManager,o.engines){for(let i of Object.keys(r.packageManagers))delete o.engines[i];Object.assign(o.engines,t.pmSpec.engines??{})}await Ne(n,`${JSON.stringify(o,null,2)}
9
- `,"utf-8")},di=async(e,t)=>{let r=F.join(e,".env.example"),n;try{n=await Ie(r,"utf-8")}catch{return}for(let o of t)n=n.replace(new RegExp(`^${o}=.*\\n?`,"gm"),"");await Ne(r,n.replace(/\n{3,}/g,`
10
-
11
- `),"utf-8")},rr=async(e,t,r)=>{let n={removed:[],overlaid:[],anchored:[],unwrapped:[]},o=F.join(e,ye),s=await ii(F.join(pi(),"next-maker-overlays-"));try{await Zt(o)&&await hn(o,s,{recursive:!0});for(let l of r.pmOverlays)n.overlaid.push(...await gn(s,e,l));let a=await L(e),c=new Set(r.removePatterns.flatMap(l=>ie(a,l)));for(let l of c)await Qt(F.join(e,l),{force:!0}),n.removed.push(l);for(let l of r.featureOverlays){let p=await gn(s,e,l.name),u=[...r.unconditionalRemovals,...r.featureRemovals.filter(d=>!d.options.some(g=>l.options.includes(g))).flatMap(d=>d.patterns)],f=new Set(u.flatMap(d=>ie(p,d)));for(let d of f)await Qt(F.join(e,d),{force:!0}),n.removed.push(d);n.overlaid.push(...p.filter(d=>!f.has(d)))}}finally{await Qt(s,{recursive:!0,force:!0})}await tr(e);let i=await L(e);for(let a of i){if(!mi(a))continue;let c=F.join(e,a),l=await Ie(c,"utf-8");ze(l)&&(await Ne(c,Xt(l,{off:r.anchorsOff}),"utf-8"),n.anchored.push(a))}for(let{file:a,tag:c}of r.unwrapJsx){let l=F.join(e,a);if(!await Zt(l))continue;let p=await Ie(l,"utf-8"),u=We(p,c);u!==p&&(await Ne(l,u,"utf-8"),n.unwrapped.push(`${a}:<${c}>`))}for(let{file:a,name:c}of r.unwrapCall){let l=F.join(e,a);if(!await Zt(l))continue;let p=await Ie(l,"utf-8"),u=Ke(p,c);u!==p&&(await Ne(l,u,"utf-8"),n.unwrapped.push(`${a}:${c}()`))}if(await ui(e,r,t),await di(e,r.env),r.packageManager!=="pnpm")for(let a of await L(e)){if(!Yt(a)||a==="package.json")continue;let c=F.join(e,a),l=await Ie(c,"utf-8"),p=vt(l,r.packageManager);p!==l&&await Ne(c,p,"utf-8")}return n},Zt=async e=>{try{return await ci(e),!0}catch{return!1}};import{readFile as fi}from"node:fs/promises";import gi from"node:path";var nr=async e=>{let t=gi.resolve(process.cwd(),e),r;try{r=await fi(t,"utf-8")}catch{throw new Error(`Config file not found: ${t}`)}let n=JSON.parse(r);if(typeof n!="object"||n===null||Array.isArray(n))throw new Error(`Config file ${t} must contain a JSON object`);if(n.options!==void 0&&(typeof n.options!="object"||n.options===null))throw new Error(`Config file ${t}: "options" must be an object`);return n},xe=e=>{let t={};for(let r of e??[]){let n=r.indexOf("=");if(n<=0)throw new Error(`--set expects key=value, got "${r}"`);t[r.slice(0,n).trim()]=r.slice(n+1).trim()}return t};var or={default:{description:"Manifest defaults: Redux, fetch, i18n, dark mode, unit + e2e tests, hooks",answers:{}},minimal:{description:"No state store, no i18n, no dark mode, no tests, no hooks",answers:{state:"none",i18n:!1,darkMode:!1,tests:!1,e2e:!1,hooks:!1,commitizen:!1}},full:{description:"Everything on: WebSocket, both HTTP adapters, Docker, CI, analyzer, OpenAPI, templates",answers:{ws:!0,http:"both",docker:!0,ci:!0,analyzer:!0,openapi:!0,githubTemplates:!0,communityFiles:["CODE_OF_CONDUCT.md","CONTRIBUTING.md","SECURITY.md"]}},zustand:{description:"Defaults with Zustand instead of Redux",answers:{state:"zustand"}},spa:{description:"Client-heavy app: Zustand, Axios, no i18n, Docker and CI on",answers:{state:"zustand",http:"axios",i18n:!1,docker:!0,ci:!0}}},Fe=()=>Object.keys(or),Me=e=>{let t=or[e];if(!t)throw new Error(`Unknown preset "${e}". Valid: ${Fe().join(", ")}.`);return{...t.answers}};var Qe=new Set;function $t(e){return Qe.add(e),()=>Qe.delete(e)}function wn(e){let{logger:t=c=>console.error(c),exitOnCancel:r=process.env.NODE_ENV!=="test"}=e??{},n=!1,o=async()=>{let c=[...Qe];Qe.clear();for(let l of c)try{await l()}catch(p){t(`Cleanup failed: ${p instanceof Error?p.message:String(p)}`)}},s=()=>{if(n){r&&process.exit(130);return}n=!0;let c=Qe.size>0;o().then(()=>{console.log(""),t("Setup cancelled by user"),console.log(""),r&&process.exit(c?130:0)})},i=c=>{if(c!==null&&typeof c=="object"&&"code"in c&&c.code==="ERR_USE_AFTER_CLOSE"){s();return}if(c instanceof Error){t(`Uncaught exception: ${c.message}`);return}t(`Uncaught exception: ${String(c)}`)},a=c=>{if(c instanceof Error){t(`Unhandled promise rejection: ${c.message}`);return}t(`Unhandled promise rejection: ${String(c)}`)};return process.on("SIGINT",s),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",a),()=>{process.off("SIGINT",s),process.off("SIGTERM",s),process.off("uncaughtException",i),process.off("unhandledRejection",a)}}import z from"picocolors";var hi={reset:e=>e,red:z.red,green:z.green,yellow:z.yellow,blue:z.blue,cyan:z.cyan,magenta:z.magenta,white:z.white,gray:z.gray,bright:z.bold,dim:z.dim};function pe(e,t="reset"){let r=hi[t]??(n=>n);console.log(r(e))}function kt(e){pe(`\u2716 ${e}`,"red")}var b=kt;function xn(e){pe(`\u26A0 ${e}`,"yellow")}function m(e){pe(e)}function Pt(){console.log(""),pe("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),pe("\u2551 \u2551","cyan"),pe("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),pe("\u2551 \u2551","cyan"),pe("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}import yi from"ora";function St(e="",t){let r=yi({text:e,...t});return r.start(),r}var wi=e=>e.charAt(0).toUpperCase()+e.slice(1),G=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),$=e=>wi(G(e));import xi from"ora";var h=xi();import{execFile as bi}from"node:child_process";import{cp as bn,mkdir as vi,stat as $i}from"node:fs/promises";import Ze from"node:path";import{promisify as ki}from"node:util";import Pi from"degit";var Si=ki(bi),vn="teispace/nextjs-starter",Et="v2.0.0-alpha.2",Ei="NEXT_MAKER_STARTER_PATH",Ti=(e=Et)=>e==="main"?vn:`${vn}#${e}`,V=(e={})=>{let t=e.starterPath??process.env[Ei];return t?{kind:"local",location:Ze.resolve(t)}:{kind:"remote",location:Ti(e.ref)}},ji=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results",".env"]),Tt=async(e,t={})=>{let r=t.source??V();if(r.kind==="local"){try{if(!(await $i(r.location)).isDirectory())throw new Error("not a directory")}catch{throw new Error(`Starter path ${r.location} is not a directory`)}return await Ri(r.location,e),r}return await Pi(r.location,{cache:!1,force:!0,verbose:t.verbose??!1}).clone(e),r},Ri=async(e,t)=>{let r=null;try{let{stdout:n}=await Si("git",["-C",e,"ls-files","-z","--cached","--others","--exclude-standard"],{maxBuffer:67108864});r=n.split("\0").filter(Boolean)}catch{r=null}if(r===null){await bn(e,t,{recursive:!0,filter:n=>!ji.has(Ze.basename(n))});return}for(let n of r){let o=Ze.join(t,n);await vi(Ze.dirname(o),{recursive:!0});try{await bn(Ze.join(e,n),o)}catch{}}};import{existsSync as sr}from"node:fs";import et from"node:fs/promises";import Ci from"node:path";var R=async e=>et.readFile(e,"utf-8"),P=async(e,t)=>{await et.mkdir(Ci.dirname(e),{recursive:!0}),await et.writeFile(e,t,"utf-8")};var $n=async e=>{sr(e)&&await et.unlink(e)},tt=async e=>{sr(e)&&await et.rm(e,{recursive:!0,force:!0})},kn=async(e,t)=>{let r=await R(e),n=JSON.parse(r),o=t(n);await P(e,JSON.stringify(o,null,2))},w=e=>sr(e);import{execFile as Oi}from"node:child_process";import{promisify as Ai}from"node:util";var Ii=Ai(Oi),te=(e,t)=>Ii("git",e,t?{cwd:t}:void 0);function Ni(e){let t=e.trim();if(!t||t.startsWith("-"))throw new Error(`Invalid git remote "${e}".`);if(!(/^https?:\/\/\S+$/.test(t)||/^git@[\w.-]+:\S+$/.test(t)||/^ssh:\/\/\S+$/.test(t)||/^[\w.-]+\/[\w.-]+$/.test(t)))throw new Error(`Invalid git remote "${e}". Expected an https/ssh URL or "owner/repo".`)}var jt=async(e,t,r)=>{try{if(await te(["init"],e),await te(["add","."],e),await te(["commit","-m","Initial commit from @teispace/next-maker"],e),t&&(Ni(t),await te(["remote","add","origin",t],e),r)){await te(["fetch","origin"],e);let n="main";try{await te(["show-branch","origin/main"],e)}catch{try{await te(["show-branch","origin/master"],e),n="master"}catch{n="main"}}await te(["merge",`origin/${n}`,"--allow-unrelated-histories","-X","ours"],e),await te(["push","origin",`HEAD:${n}`],e)}}catch(n){console.warn("Failed to initialize git repository",n)}};import{execFile as Fi}from"node:child_process";import{promisify as Mi}from"node:util";var _i=Mi(Fi),Pn=(e,t,r)=>_i(e,t,{cwd:r,maxBuffer:64*1024*1024}),Di=e=>{let t=e;return(`${t.stdout??""}
2
+ import{Command as Zp}from"commander";var De={name:"@teispace/next-maker",version:"5.0.7",description:"Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",keywords:["nextjs","react","typescript","tailwindcss","starter","template","redux","zustand","tanstack-query","server-actions","cli"],type:"module",homepage:"https://github.com/teispace/npm-packages/tree/main/packages/next-maker#readme",bugs:{url:"https://github.com/teispace/npm-packages/issues"},license:"MIT",author:"Teispace",files:["dist","README.md","LICENSE","CHANGELOG.md"],bin:"dist/index.js",repository:{type:"git",url:"git+https://github.com/teispace/npm-packages.git",directory:"packages/next-maker"},scripts:{build:"tsx build.ts",start:"node dist/index.js",dev:"tsx --watch src/index.ts",test:"vitest run","test:watch":"vitest","test:cov":"vitest run --coverage","type-check":"tsc --noEmit",clean:"rm -rf dist",prepublishOnly:"yarn clean && yarn build",smoke:"tsx scripts/smoke.ts"},dependencies:{commander:"^15.0.0",degit:"^3.8.0",enquirer:"^2.4.1",ora:"^9.4.1",picocolors:"^1.1.1","png-to-ico":"^3.0.2",sharp:"^0.35.3"},devDependencies:{"@types/degit":"^2.8.6","@types/node":"^26.2.0",esbuild:"^0.28.2",tsx:"^4.23.12",typescript:"^6.0.3",vitest:"^4.1.11"},engines:{node:">=24.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};import{copyFile as ga}from"node:fs/promises";import qe from"node:path";import j from"picocolors";var mn=/@next-maker:([\w-]+)(?::(start|end))?/,ai=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,ci=e=>e.replace(/\s*\{\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*\}\s*$/,"").replace(/\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*$/,"").replace(/\s*\/\/[^\n]*@next-maker:[^\n]*$/,"").replace(/\s*#[^\n]*@next-maker:[^\n]*$/,""),tr=(e,{off:t})=>{let r=e.split(`
3
+ `),n=[];for(let o=0;o<r.length;o++){let s=r[o],i=s.match(mn);if(!i){n.push(s);continue}let[,a,c]=i,m=t.has(a);if(c==="start"){let u=pi(r,o+1,a);m&&(o=u);continue}if(c==="end")continue;let p=ai.test(s);if(m){p&&o++;continue}p||n.push(ci(s))}return n.join(`
4
+ `)},pi=(e,t,r)=>{for(let n=t;n<e.length;n++){let o=e[n].match(mn);if(o&&o[1]===r&&o[2]==="end")return n}throw new Error(`Anchor @next-maker:${r}:start has no matching :end`)},tt=e=>e.includes("@next-maker:"),un=(e,t)=>{let r=e.split(`
5
+ `),n=[],o=new RegExp(`^import\\s+${t}\\s+from\\s+['"][^'"]+['"];?\\s*$`),s=/^(import\s+(?:type\s+)?)\{([^}]+)\}(\s+from\s+['"][^'"]+['"];?\s*)$/;for(let i of r){if(o.test(i))continue;let a=i.match(s);if(a){let c=a[2].split(",").map(p=>p.trim()).filter(Boolean),m=c.filter(p=>p.replace(/^type\s+/,"").split(/\s+as\s+/)[0]!==t);if(m.length===0)continue;if(m.length<c.length){n.push(`${a[1]}{ ${m.join(", ")} }${a[3]}`);continue}}n.push(i)}return n.join(`
6
+ `)},$e=(e,t)=>{let r=e.split(`
7
+ `),n=new RegExp(`^([ \\t]*)<${t}\\b`),o=-1,s="";for(let d=0;d<r.length;d++){let f=r[d].match(n);if(f){o=d,s=f[1];break}}if(o===-1)return e;let i=o;for(;i<r.length&&!/>\s*$/.test(r[i]);)i++;if(i>=r.length)throw new Error(`unwrapJsx: opening <${t}> never closes`);if(/\/>\s*$/.test(r[i]))return e;let a=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=new RegExp(`^${a}</${t}>\\s*$`),m=-1;for(let d=i+1;d<r.length;d++)if(c.test(r[d])){m=d;break}if(m===-1)throw new Error(`unwrapJsx: no closing </${t}> at the opening indent`);let p=r.slice(i+1,m).map(d=>d.startsWith(" ")?d.slice(2):d),u=[...r.slice(0,o),...p,...r.slice(m+1)].join(`
8
+ `);return un(u,t)},Pe=(e,t)=>{let r=new RegExp(`\\b${t}\\(`,"g"),n=e,o=r.exec(n);for(;o;){let s=o.index,i=0,a=s+o[0].length-1;for(;a<n.length;a++)if(n[a]==="(")i++;else if(n[a]===")"&&(i--,i===0))break;if(i!==0)throw new Error(`unwrapCall: unbalanced parentheses after ${t}(`);let c=n.slice(s+o[0].length,a);n=n.slice(0,s)+c+n.slice(a+1),r.lastIndex=s,o=r.exec(n)}return n};import{cp as vn,mkdir as gi,mkdtemp as hi,readdir as xn,readFile as Le,rm as nr,rmdir as yi,stat as wi,writeFile as Ue}from"node:fs/promises";import{tmpdir as xi}from"node:os";import _ from"node:path";import{readdir as li}from"node:fs/promises";import Pt from"node:path";var dn=e=>{let t="^";for(let r=0;r<e.length;r++){let n=e[r];n==="*"?e[r+1]==="*"?(r++,e[r+1]==="/"?(r++,t+="(?:.*/)?"):t+=".*"):t+="[^/]*":t+=n.replace(/[.+?^${}()|[\]\\]/g,"\\$&")}return new RegExp(`${t}$`)},mi=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results"]),I=async(e,t=mi)=>{let r=[],n=async o=>{let s;try{s=await li(o,{withFileTypes:!0})}catch{return}for(let i of s)if(i.isDirectory()){if(t.has(i.name))continue;await n(Pt.join(o,i.name))}else i.isFile()&&r.push(Pt.relative(e,Pt.join(o,i.name)).split(Pt.sep).join("/"))};return await n(e),r.sort()},Y=(e,t)=>{let r=dn(t);return e.filter(n=>r.test(n))};import{readFile as fn}from"node:fs/promises";import gn from"node:path";var St="next-maker.json",ae=".next-maker/overlays",hn=1,W=e=>{throw new Error(`Invalid ${St}: ${e}`)},wn=e=>{(typeof e!="object"||e===null)&&W("not an object");let t=e;t.manifestVersion!==hn&&W(`manifestVersion ${String(t.manifestVersion)} is not supported by this CLI (expected ${hn})`),(!t.starter?.name||!t.starter.version)&&W("starter.name and starter.version are required"),(!t.options||typeof t.options!="object")&&W("options is required"),(!t.features||typeof t.features!="object")&&W("features is required"),(!t.packageManagers||typeof t.packageManagers!="object")&&W("packageManagers is required");let r=t.options,n=t.features;for(let[o,s]of Object.entries(r))["choice","boolean","multi"].includes(s.type)||W(`option ${o} has unknown type ${String(s.type)}`),s.type!=="boolean"&&!Array.isArray(s.values)&&W(`option ${o} needs a values array`),s.default===void 0&&W(`option ${o} needs a default`);for(let[o,s]of Object.entries(n)){(!s.when||typeof s.when!="object")&&W(`feature ${o} needs a when`);for(let i of Object.keys(s.when))r[i]||W(`feature ${o} refers to unknown option ${i}`)}return{...t,always:{remove:t.always?.remove??[]}}},rt=async e=>{let t=gn.join(e,St),r;try{r=await fn(t,"utf-8")}catch{throw new Error(`The starter at ${e} has no ${St}. This CLI needs a starter that ships a composition manifest (nextjs-starter 2.x or later).`)}let n=wn(JSON.parse(r));try{let o=JSON.parse(await fn(gn.join(e,"package.json"),"utf-8"));typeof o.version=="string"&&o.version&&(n.starter={...n.starter,version:o.version})}catch{}return n},yn=(e,t)=>e.some(r=>r===t),Et=(e,t,r)=>t===void 0?!1:e?.type==="multi"&&Array.isArray(t)?t.some(n=>yn(r,n)):yn(r,t),de=(e,t,r)=>Object.entries(t.when).every(([n,o])=>Et(e.options[n],r[n],o)),ui=e=>e.type==="boolean"?!1:e.type==="multi"?[]:e.default,di=(e,t,r)=>{if(e.type==="boolean"){if(typeof r=="boolean")return r;if(r==="true")return!0;if(r==="false")return!1;throw new Error(`Option ${t} expects true or false, got ${String(r)}`)}if(e.type==="multi"){let s=(Array.isArray(r)?r:String(r).split(",")).map(i=>String(i).trim()).filter(Boolean);for(let i of s)if(!e.values?.includes(i))throw new Error(`Option ${t} does not accept ${i}; valid: ${e.values?.join(", ")}`);return s}let n=String(r);if(!e.values?.includes(n))throw new Error(`Option ${t} does not accept ${n}; valid: ${e.values?.join(", ")}`);return n},nt=(e,t={})=>{let r={},n=[],o=Object.keys(t).filter(s=>!e.options[s]);for(let[s,i]of Object.entries(e.options)){let a=t[s];r[s]=a===void 0?i.default:di(i,s,a)}for(let[s,i]of Object.entries(e.options))if(i.requires)for(let[a,c]of Object.entries(i.requires)){if(Et(e.options[a],r[a],c))continue;let m=ui(i);r[s]!==m&&JSON.stringify(r[s])!==JSON.stringify(m)&&(n.push({option:s,value:m,reason:`${s} requires ${a} to be ${c.map(String).join(" or ")}`}),r[s]=m)}return{answers:r,forced:n,unknown:o}};var fe=(e,t)=>{switch(e){case"npm":return`npm run ${t}`;case"bun":return`bun run ${t}`;case"yarn":return`yarn ${t}`;default:return`pnpm ${t}`}},fi=e=>{switch(e){case"npm":return[[/\bpnpm install --frozen-lockfile\b/g,"npm ci"],[/\bpnpm install\b/g,"npm install"],[/\bpnpm add -D\b/g,"npm install --save-dev"],[/\bpnpm add\b/g,"npm install"],[/\bpnpm dlx\b/g,"npx"],[/\bpnpm exec\b/g,"npx --no --"],[/\bpnpm ([\w:.-]+)/g,"npm run $1"]];case"yarn":return[[/\bpnpm install --frozen-lockfile\b/g,"yarn install --immutable"],[/\bpnpm install\b/g,"yarn install"],[/\bpnpm add -D\b/g,"yarn add -D"],[/\bpnpm add\b/g,"yarn add"],[/\bpnpm dlx\b/g,"yarn dlx"],[/\bpnpm exec\b/g,"yarn"],[/\bpnpm ([\w:.-]+)/g,"yarn $1"]];case"bun":return[[/\bpnpm install --frozen-lockfile\b/g,"bun install --frozen-lockfile"],[/\bpnpm install\b/g,"bun install"],[/\bpnpm add -D\b/g,"bun add -d"],[/\bpnpm add\b/g,"bun add"],[/\bpnpm dlx\b/g,"bunx"],[/\bpnpm exec\b/g,"bunx"],[/\bpnpm ([\w:.-]+)/g,"bun run $1"]];default:return[]}},Tt=(e,t)=>{if(t==="pnpm")return e;let r=e;for(let[n,o]of fi(t))r=r.replace(n,o);return r},rr=e=>e==="package.json"||e.startsWith(".husky/")||e.endsWith(".md")||e===".lintstagedrc.mjs";var Se=e=>[...new Set(e)],sr=(e,t,r)=>{let n=e.packageManagers[r];if(!n)throw new Error(`This starter does not support ${r}; valid: ${Object.keys(e.packageManagers).join(", ")}`);let o=[],s=[],i=[],a=[],c=[],m=[],p=[];for(let[d,f]of Object.entries(e.features)){let h=de(e,f,t);(h?o:s).push(d);let y=h?f.on:f.off;if(!y)continue;i.push(y);let x=Object.keys(f.when);y.overlay&&!a.some(b=>b.name===y.overlay)&&a.push({name:y.overlay,options:x}),y.remove?.length&&c.push({feature:d,options:x,patterns:y.remove});for(let b of y.unwrapJsx??[])m.push({...b,options:x});for(let b of y.unwrapCall??[])p.push({...b,options:x})}let u=Se([...e.always.remove,...n.remove??[]]);return{answers:t,packageManager:r,pmSpec:n,featuresOn:o,featuresOff:s,pmOverlays:n.overlay?[n.overlay]:[],featureOverlays:a,removePatterns:Se([...u,...c.flatMap(d=>d.patterns)]),unconditionalRemovals:u,featureRemovals:c,anchorsOff:new Set(i.flatMap(d=>d.anchors??[])),unwrapJsx:m,unwrapCall:p,packages:Se(i.flatMap(d=>d.packages??[])),devPackages:Se(i.flatMap(d=>d.devPackages??[])),scripts:Se(i.flatMap(d=>d.scripts??[])),env:Se(i.flatMap(d=>d.env??[])),packageJsonKeys:Se(i.flatMap(d=>d.packageJsonKeys??[]))}},bi=new Set([".ts",".tsx",".js",".mjs",".cjs",".css",".json",".yml",".yaml",".md",".sh",".example",".mdx"]),vi=e=>bi.has(_.extname(e))||e.startsWith(".husky/")||e==="Dockerfile",bn=async(e,t,r)=>{let n=_.join(e,r),o=await I(n,new Set);if(o.length===0)throw new Error(`Overlay "${r}" is missing or empty at ${ae}/${r}`);for(let s of o){let i=_.join(t,s);await gi(_.dirname(i),{recursive:!0}),await vn(_.join(n,s),i,{force:!0})}return o},ir=async(e,t=e)=>{let r;try{r=await xn(t,{withFileTypes:!0})}catch{return}for(let n of r)n.isDirectory()&&n.name!=="node_modules"&&n.name!==".git"&&await ir(e,_.join(t,n.name));t!==e&&(await xn(t)).length===0&&await yi(t)},kn=(e,t)=>{let r=t.split("."),n=e;for(let s of r.slice(0,-1)){let i=n?.[s];if(typeof i!="object"||i===null)return;n=i}let o=r[r.length-1];if(n&&o in n&&delete n[o],r.length>1){let s=r.slice(0,-1).join("."),i=r.slice(0,-1).reduce((a,c)=>a?.[c],e);i&&typeof i=="object"&&Object.keys(i).length===0&&kn(e,s)}},ki=async(e,t,r)=>{let n=_.join(e,"package.json"),o=JSON.parse(await Le(n,"utf-8"));for(let i of t.packages)delete o.dependencies?.[i];for(let i of t.devPackages)delete o.devDependencies?.[i];for(let i of t.scripts)delete o.scripts?.[i];for(let i of t.packageJsonKeys)kn(o,i);let s=r.validateScript;if(s&&o.scripts?.[s.name]){let i=s.steps.filter(a=>o.scripts[a]);o.scripts[s.name]=i.map(a=>fe(t.packageManager,a)).join(" && ")}if(o.scripts)for(let[i,a]of Object.entries(o.scripts))typeof a=="string"&&(o.scripts[i]=Tt(a,t.packageManager));if(t.pmSpec.packageManager?o.packageManager=t.pmSpec.packageManager:delete o.packageManager,o.engines){for(let i of Object.keys(r.packageManagers))delete o.engines[i];Object.assign(o.engines,t.pmSpec.engines??{})}await Ue(n,`${JSON.stringify(o,null,2)}
9
+ `,"utf-8")},$i=async(e,t)=>{let r=_.join(e,".env.example"),n;try{n=await Le(r,"utf-8")}catch{return}for(let o of t)n=n.replace(new RegExp(`^${o}=.*\\n?`,"gm"),"");await Ue(r,n.replace(/\n{3,}/g,`
10
+
11
+ `),"utf-8")},ar=async(e,t,r)=>{let n={removed:[],overlaid:[],anchored:[],unwrapped:[]},o=_.join(e,ae),s=await hi(_.join(xi(),"next-maker-overlays-"));try{await or(o)&&await vn(o,s,{recursive:!0});for(let m of r.pmOverlays)n.overlaid.push(...await bn(s,e,m));let a=await I(e),c=new Set(r.removePatterns.flatMap(m=>Y(a,m)));for(let m of c)await nr(_.join(e,m),{force:!0}),n.removed.push(m);for(let m of r.featureOverlays){let p=await bn(s,e,m.name),u=[...r.unconditionalRemovals,...r.featureRemovals.filter(f=>!f.options.some(h=>m.options.includes(h))).flatMap(f=>f.patterns)],d=new Set(u.flatMap(f=>Y(p,f)));for(let f of d)await nr(_.join(e,f),{force:!0}),n.removed.push(f);n.overlaid.push(...p.filter(f=>!d.has(f)))}}finally{await nr(s,{recursive:!0,force:!0})}await ir(e);let i=await I(e);for(let a of i){if(!vi(a))continue;let c=_.join(e,a),m=await Le(c,"utf-8");tt(m)&&(await Ue(c,tr(m,{off:r.anchorsOff}),"utf-8"),n.anchored.push(a))}for(let{file:a,tag:c}of r.unwrapJsx){let m=_.join(e,a);if(!await or(m))continue;let p=await Le(m,"utf-8"),u=$e(p,c);u!==p&&(await Ue(m,u,"utf-8"),n.unwrapped.push(`${a}:<${c}>`))}for(let{file:a,name:c}of r.unwrapCall){let m=_.join(e,a);if(!await or(m))continue;let p=await Le(m,"utf-8"),u=Pe(p,c);u!==p&&(await Ue(m,u,"utf-8"),n.unwrapped.push(`${a}:${c}()`))}if(await ki(e,r,t),await $i(e,r.env),r.packageManager!=="pnpm")for(let a of await I(e)){if(!rr(a)||a==="package.json")continue;let c=_.join(e,a),m=await Le(c,"utf-8"),p=Tt(m,r.packageManager);p!==m&&await Ue(c,p,"utf-8")}return n},or=async e=>{try{return await wi(e),!0}catch{return!1}};import{readFile as Pi}from"node:fs/promises";import Si from"node:path";var cr=async e=>{let t=Si.resolve(process.cwd(),e),r;try{r=await Pi(t,"utf-8")}catch{throw new Error(`Config file not found: ${t}`)}let n=JSON.parse(r);if(typeof n!="object"||n===null||Array.isArray(n))throw new Error(`Config file ${t} must contain a JSON object`);if(n.options!==void 0&&(typeof n.options!="object"||n.options===null))throw new Error(`Config file ${t}: "options" must be an object`);return n},Ee=e=>{let t={};for(let r of e??[]){let n=r.indexOf("=");if(n<=0)throw new Error(`--set expects key=value, got "${r}"`);t[r.slice(0,n).trim()]=r.slice(n+1).trim()}return t};var pr={default:{description:"Manifest defaults: Redux, fetch, i18n, dark mode, unit + e2e tests, hooks",answers:{}},minimal:{description:"No state store, no i18n, no dark mode, no tests, no hooks",answers:{state:"none",i18n:!1,darkMode:!1,tests:!1,e2e:!1,hooks:!1,commitizen:!1}},full:{description:"Everything on: WebSocket, both HTTP adapters, Docker, CI, analyzer, OpenAPI, templates",answers:{ws:!0,http:"both",docker:!0,ci:!0,analyzer:!0,openapi:!0,githubTemplates:!0,communityFiles:["CODE_OF_CONDUCT.md","CONTRIBUTING.md","SECURITY.md"]}},zustand:{description:"Defaults with Zustand instead of Redux",answers:{state:"zustand"}},spa:{description:"Client-heavy app: Zustand, Axios, no i18n, Docker and CI on",answers:{state:"zustand",http:"axios",i18n:!1,docker:!0,ci:!0}}},Be=()=>Object.keys(pr),Ge=e=>{let t=pr[e];if(!t)throw new Error(`Unknown preset "${e}". Valid: ${Be().join(", ")}.`);return{...t.answers}};var ot=new Set;function Rt(e){return ot.add(e),()=>ot.delete(e)}function $n(e){let{logger:t=c=>console.error(c),exitOnCancel:r=process.env.NODE_ENV!=="test"}=e??{},n=!1,o=async()=>{let c=[...ot];ot.clear();for(let m of c)try{await m()}catch(p){t(`Cleanup failed: ${p instanceof Error?p.message:String(p)}`)}},s=()=>{if(n){r&&process.exit(130);return}n=!0;let c=ot.size>0;o().then(()=>{console.log(""),t("Setup cancelled by user"),console.log(""),r&&process.exit(c?130:0)})},i=c=>{if(c!==null&&typeof c=="object"&&"code"in c&&c.code==="ERR_USE_AFTER_CLOSE"){s();return}if(c instanceof Error){t(`Uncaught exception: ${c.message}`);return}t(`Uncaught exception: ${String(c)}`)},a=c=>{if(c instanceof Error){t(`Unhandled promise rejection: ${c.message}`);return}t(`Unhandled promise rejection: ${String(c)}`)};return process.on("SIGINT",s),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",a),()=>{process.off("SIGINT",s),process.off("SIGTERM",s),process.off("uncaughtException",i),process.off("unhandledRejection",a)}}import Q from"picocolors";var Ei={reset:e=>e,red:Q.red,green:Q.green,yellow:Q.yellow,blue:Q.blue,cyan:Q.cyan,magenta:Q.magenta,white:Q.white,gray:Q.gray,bright:Q.bold,dim:Q.dim};function ge(e,t="reset"){let r=Ei[t]??(n=>n);console.log(r(e))}function jt(e){ge(`\u2716 ${e}`,"red")}var v=jt;function Pn(e){ge(`\u26A0 ${e}`,"yellow")}function l(e){ge(e)}function Ct(){console.log(""),ge("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),ge("\u2551 \u2551","cyan"),ge("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),ge("\u2551 \u2551","cyan"),ge("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}import Ti from"ora";function Ot(e="",t){let r=Ti({text:e,...t});return r.start(),r}var Ri=e=>e.charAt(0).toUpperCase()+e.slice(1),V=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),$=e=>Ri(V(e));import ji from"ora";var g=ji();import{execFile as Ci}from"node:child_process";import{cp as Sn,mkdir as Oi,stat as Ai}from"node:fs/promises";import st from"node:path";import{promisify as Ii}from"node:util";import Ni from"degit";var Fi=Ii(Ci),En="teispace/nextjs-starter",At="v2.0.0-alpha.3",Mi="NEXT_MAKER_STARTER_PATH",_i=(e=At)=>e==="main"?En:`${En}#${e}`,z=(e={})=>{let t=e.starterPath??process.env[Mi];return t?{kind:"local",location:st.resolve(t)}:{kind:"remote",location:_i(e.ref)}},Di=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results",".env"]),It=async(e,t={})=>{let r=t.source??z();if(r.kind==="local"){try{if(!(await Ai(r.location)).isDirectory())throw new Error("not a directory")}catch{throw new Error(`Starter path ${r.location} is not a directory`)}return await Li(r.location,e),r}return await Ni(r.location,{cache:!1,force:!0,verbose:t.verbose??!1}).clone(e),r},Li=async(e,t)=>{let r=null;try{let{stdout:n}=await Fi("git",["-C",e,"ls-files","-z","--cached","--others","--exclude-standard"],{maxBuffer:67108864});r=n.split("\0").filter(Boolean)}catch{r=null}if(r===null){await Sn(e,t,{recursive:!0,filter:n=>!Di.has(st.basename(n))});return}for(let n of r){let o=st.join(t,n);await Oi(st.dirname(o),{recursive:!0});try{await Sn(st.join(e,n),o)}catch{}}};import{existsSync as lr}from"node:fs";import it from"node:fs/promises";import Ui from"node:path";var O=async e=>it.readFile(e,"utf-8"),R=async(e,t)=>{await it.mkdir(Ui.dirname(e),{recursive:!0}),await it.writeFile(e,t,"utf-8")};var Tn=async e=>{lr(e)&&await it.unlink(e)},at=async e=>{lr(e)&&await it.rm(e,{recursive:!0,force:!0})},Rn=async(e,t)=>{let r=await O(e),n=JSON.parse(r),o=t(n);await R(e,JSON.stringify(o,null,2))},w=e=>lr(e);import{execFile as Bi}from"node:child_process";import{promisify as Gi}from"node:util";var Vi=Gi(Bi),ce=(e,t)=>Vi("git",e,t?{cwd:t}:void 0);function Hi(e){let t=e.trim();if(!t||t.startsWith("-"))throw new Error(`Invalid git remote "${e}".`);if(!(/^https?:\/\/\S+$/.test(t)||/^git@[\w.-]+:\S+$/.test(t)||/^ssh:\/\/\S+$/.test(t)||/^[\w.-]+\/[\w.-]+$/.test(t)))throw new Error(`Invalid git remote "${e}". Expected an https/ssh URL or "owner/repo".`)}var Nt=async(e,t,r)=>{try{if(await ce(["init"],e),await ce(["add","."],e),await ce(["commit","-m","Initial commit from @teispace/next-maker"],e),t&&(Hi(t),await ce(["remote","add","origin",t],e),r)){await ce(["fetch","origin"],e);let n="main";try{await ce(["show-branch","origin/main"],e)}catch{try{await ce(["show-branch","origin/master"],e),n="master"}catch{n="main"}}await ce(["merge",`origin/${n}`,"--allow-unrelated-histories","-X","ours"],e),await ce(["push","origin",`HEAD:${n}`],e)}}catch(n){console.warn("Failed to initialize git repository",n)}};import{execFile as qi}from"node:child_process";import{promisify as Ji}from"node:util";var Wi=Ji(qi),jn=(e,t,r)=>Wi(e,t,{cwd:r,maxBuffer:64*1024*1024}),zi=e=>{let t=e;return(`${t.stdout??""}
12
12
  ${t.stderr??""}`.trim()||(t.message??String(e))).split(`
13
13
  `).filter(Boolean).slice(-12).join(`
14
- `)},Li=e=>{switch(e){case"pnpm":return["install","--no-frozen-lockfile"];case"yarn":return["install","--no-immutable"];default:return["install"]}},le=async(e,t)=>{try{await Pn(t,Li(t),e)}catch(r){throw new Error(`Failed to install dependencies with ${t}:
15
- ${Di(r)}`,{cause:r})}},Rt=async(e,t,r)=>{let n=t==="npm"?["run",r]:[r];try{await Pn(t,n,e)}catch(o){console.warn(`Warning: Failed to run script '${r}': ${o}`)}};import Ui from"enquirer";var{prompt:Sn}=Ui,Gi=/^[a-z0-9-_]+$/,Bi=/^\d+\.\d+\.\d+$/,En=e=>Gi.test(e),Tn=e=>Bi.test(e),rt=e=>{if(!En(e))throw new Error(`Invalid project name "${e}". Use lowercase letters, digits, hyphens, and underscores only \u2014 no slashes, "..", or absolute paths.`)},me=(e,t={})=>{let r=t.projectName??e??"my-app";rt(r);let n=t.version??"0.1.0";if(!Tn(n))throw new Error(`Invalid version "${n}". Expected semver (e.g. 0.1.0).`);return{projectName:r,description:t.description??"A Next.js application",author:t.author??"Teispace",version:n,email:t.email??"support@example.com",gitRemote:t.gitRemote??"",pushToRemote:t.pushToRemote??!1,gitIssues:t.gitIssues??"",gitHomepage:t.gitHomepage??"",readme:t.readme??!0,copyEnv:t.copyEnv??!0}},jn=e=>e.state?.answers??e.enquirer?.answers??{},Rn=async e=>{e!==void 0&&rt(e);let t=await Sn([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:r=>En(r)||"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:r=>Tn(r)||"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com"},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",initial:"",validate:r=>!r||/^(https:\/\/github\.com\/[\w-]+\/[\w.-]+(\.git)?|git@github\.com:[\w-]+\/[\w.-]+\.git)$/.test(r)||"Enter a GitHub URL (https://github.com/user/repo or git@github.com:user/repo.git)."},{type:"confirm",name:"pushToRemote",message:"Push the initial commit to the remote?",initial:!1,skip:function(){return!jn(this).gitRemote}},{type:"confirm",name:"readme",message:"Create a README.md?",initial:!0},{type:"confirm",name:"copyEnv",message:"Copy .env.example to .env?",initial:!0}]);return me(e,{...t,projectName:e??t.projectName})},Ct=async(e,t={})=>{let r=Object.entries(e.options).map(([s,i])=>{let a=t[s]??i.default,c={name:s,message:i.label??s,skip:function(){if(!i.requires)return!1;let p=jn(this);return!Object.entries(i.requires).every(([u,f])=>bt(e.options[u],p[u],f))}};if(i.type==="boolean")return{...c,type:"confirm",initial:!!a};if(i.type==="multi")return{...c,type:"multiselect",choices:(i.values??[]).map(p=>({name:p,value:p})),initial:Array.isArray(a)?a:[]};let l=i.values??[];return{...c,type:"select",choices:l,initial:Math.max(0,l.indexOf(String(a)))}}),n=await Sn(r),o={};for(let[s,i]of Object.entries(e.options)){let a=n[s];a!==void 0&&(o[s]=i.type==="multi"&&!Array.isArray(a)?[]:a)}return o};import Vi from"node:path";var C={NEXT_CONFIG:"next.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",BIOME_CONFIG:"biome.json",VITEST_CONFIG:"vitest.config.ts",TEST_DIR:"test",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",AGENTS_MD:"AGENTS.md",CLAUDE_MD:"CLAUDE.md",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",SEO_FILE:"src/lib/config/seo.ts",SITEMAP_FILE:"src/app/sitemap.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",HTTP_SHARED:"src/lib/utils/http/shared",HTTP_SERVER_FILE:"src/lib/utils/http/server.ts",HTTP_BUNDLE_SENTINEL_DIR:"src/lib/utils/http/__bundle-sentinel__",HTTP_BUNDLE_SENTINEL_FILE:"src/lib/utils/http/__bundle-sentinel__/client-bundle-sentinel.tsx",WS_UTILS:"src/lib/utils/ws",WS_SLICE_FILE:"src/store/slices/ws.slice.ts",WS_SLICE_TEST_FILE:"src/store/slices/ws.slice.test.ts",ROOT_REDUCER:"src/store/rootReducer.ts",TEST_SETUP_FILE:"test/setup.ts",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",AXIOS_CLIENT_FILE:"src/lib/utils/http/axios-client/index.ts",FETCH_CLIENT_FILE:"src/lib/utils/http/fetch-client/index.ts",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",API_URL_FILE:"src/lib/config/api-url.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",LOCALE_LAYOUT:"src/app/[locale]/layout.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md",SCRIPTS_DIR:"scripts",DOCS_DIR:"docs",CLAUDE_DIR:".claude",VSCODE_DIR:".vscode"};var Hi=e=>{let t=e.gitRemote,r=e.gitHomepage,n=e.gitIssues;if(!t)return{remote:"",homepage:"",issues:""};t.startsWith("git@github.com:")&&(t=t.replace("git@github.com:","https://github.com/").replace(/\.git$/,""));let o=t.replace(/\.git$/,"");return r||=`${o}#readme`,n||=`${o}/issues`,t.endsWith(".git")||(t=`${t}.git`),{remote:t,homepage:r,issues:n}},Cn=async(e,t)=>{let{remote:r,homepage:n,issues:o}=Hi(t);await kn(Vi.join(e,C.PACKAGE_JSON),s=>(s.name=t.projectName,s.version=t.version,s.description=t.description,s.author=t.author,delete s.keywords,r?(s.homepage=n,s.bugs={url:o},s.repository={type:"git",url:r}):(delete s.homepage,delete s.bugs,delete s.repository),s))};import{readdir as Yi}from"node:fs/promises";import de from"node:path";import{cp as qi,mkdir as Ji,mkdtemp as zi,readFile as be,rm as In,writeFile as Ot}from"node:fs/promises";import{tmpdir as Wi}from"node:os";import A from"node:path";var _e=".next-maker.json",ue=async(e,t)=>{await Ot(A.join(e,_e),`${JSON.stringify(t,null,2)}
16
- `,"utf-8")},re=async e=>{let t=A.join(e,_e);if(!w(t))throw new Error(`No ${_e} in ${e}. Only projects created with next-maker 5+ can be reconfigured; run \`next-maker init\` for a new project.`);return JSON.parse(await be(t,"utf-8"))},De=async(e,t={})=>{let r=e.starter.source.startsWith("/")&&w(e.starter.source)?e.starter.source:void 0,n=V({starterPath:t.starterPath??r}),o=await zi(A.join(Wi(),"next-maker-starter-"));await Tt(o,{source:n});let s=await Xe(o),i=await L(o);return{dir:o,source:n,manifest:s,files:i,dispose:()=>In(o,{recursive:!0,force:!0})}},On=(e,t)=>e[t]??{},Ki=e=>[...e.off?.anchors??[],...e.on?.anchors??[]],Xi=async(e,t)=>{if(t.length===0)return[];let r=[],n=new RegExp(`@next-maker:(?:${t.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})(?::(start|end))?`);for(let o of e.files){if(o.startsWith(".next-maker/"))continue;let s;try{s=await be(A.join(e.dir,o),"utf-8")}catch{continue}if(!ze(s))continue;let i=s.split(`
17
- `),a=[];for(let c=0;c<i.length;c++){let l=i[c].match(n);if(l)if(l[1]==="start"){let p=c+1;for(;p<i.length&&!/@next-maker:[\w-]+:end/.test(i[p]);)a.push(i[p++]);c=p}else l[1]==="end"||(/^\s*(\{\s*\/\*|\/\*|\/\/|#)/.test(i[c])?i[c+1]!==void 0&&a.push(i[++c]):a.push(i[c].replace(/\s*(\{\s*\/\*|\/\*|\/\/|#).*$/,"")))}a.length&&r.push({file:o,lines:a})}return r},Nn=async(e,t)=>{let r=e.manifest.features[t];if(!r)throw new Error(`Unknown feature "${t}". Valid: ${Object.keys(e.manifest.features).join(", ")}.`);let n=On(r,"off"),o=On(r,"on"),s=new Set(e.manifest.always.remove.flatMap(c=>ie(e.files,c))),i=[...new Set((n.remove??[]).flatMap(c=>ie(e.files,c)))].filter(c=>!s.has(c)).sort(),a=o.overlay?(await L(A.join(e.dir,ye,o.overlay),new Set)).sort():[];return{id:t,feature:r,files:i,overlayFiles:a,packages:n.packages??[],devPackages:n.devPackages??[],scripts:n.scripts??[],env:n.env??[],snippets:await Xi(e,Ki(r))}},Fn=e=>/\.(test|spec)\.tsx?$/.test(e)||e.startsWith("test/")||e.includes("__test-utils__"),ir=async(e,t,r)=>{let n=JSON.parse(await be(A.join(e,"package.json"),"utf-8")),o=t.answers.tests!==!1,s=[],i=Object.values(r.manifest.features).filter(c=>!ae(r.manifest,c,t.answers)).flatMap(c=>c.off?.remove??[]),a=new Set(i.flatMap(c=>ie(r.files,c)));for(let[c,l]of Object.entries(r.manifest.features)){let p=ae(r.manifest,l,t.answers);if(!p){s.push({id:c,on:p,drift:[]});continue}let u=await Nn(r,c),f=[];for(let d of[...u.files,...u.overlayFiles])!o&&Fn(d)||a.has(d)||w(A.join(e,d))||f.push({kind:"missingFile",file:d});for(let d of u.packages)n.dependencies?.[d]||f.push({kind:"missingPackage",name:d,dev:!1});for(let d of u.devPackages)n.devDependencies?.[d]||f.push({kind:"missingPackage",name:d,dev:!0});for(let d of u.scripts)n.scripts?.[d]||f.push({kind:"missingScript",name:d});s.push({id:c,on:p,drift:f})}return s},Mn=async(e,t,r,n)=>{let o=t.answers,s=JSON.parse(await be(A.join(r.dir,"package.json"),"utf-8")),i=[],a=[];for(let[p,u]of Object.entries(r.manifest.features)){let f=ae(r.manifest,u,o),d=ae(r.manifest,u,n);f!==d&&(d?i:a).push(await Nn(r,p))}let c=n.tests!==!1,l={before:o,after:n,turningOn:i,turningOff:a,copy:[],remove:[],addPackages:{},addDevPackages:{},removePackages:[],addScripts:{},removeScripts:[],unwrapJsx:[],unwrapCall:[],manual:[]};for(let p of a){for(let u of[...p.files,...p.overlayFiles])w(A.join(e,u))&&l.remove.push(u);l.removePackages.push(...p.packages,...p.devPackages),l.removeScripts.push(...p.scripts),l.unwrapJsx.push(...p.feature.off?.unwrapJsx??[]),l.unwrapCall.push(...p.feature.off?.unwrapCall??[]),p.snippets.length&&l.manual.push({feature:p.id,direction:"delete",snippets:p.snippets})}for(let p of i){for(let u of[...p.files,...p.overlayFiles])!c&&Fn(u)||(!w(A.join(e,u))||p.overlayFiles.includes(u))&&l.copy.push(u);for(let u of p.packages)l.addPackages[u]=s.dependencies?.[u]??"latest";for(let u of p.devPackages)l.addDevPackages[u]=s.devDependencies?.[u]??"latest";for(let u of p.scripts)s.scripts?.[u]&&(l.addScripts[u]=s.scripts[u]);p.snippets.length&&l.manual.push({feature:p.id,direction:"add",snippets:p.snippets})}return l.copy=[...new Set(l.copy)].sort(),l.remove=[...new Set(l.remove)].sort(),l},_n=async(e,t,r,n)=>{for(let i of r.remove)await In(A.join(e,i),{force:!0});for(let i of r.copy){let a=r.turningOn.find(p=>p.overlayFiles.includes(i)),c=a?.feature.on?.overlay?A.join(t.dir,ye,a.feature.on.overlay,i):A.join(t.dir,i),l=A.join(e,i);await Ji(A.dirname(l),{recursive:!0}),await qi(c,l,{force:!0})}for(let{file:i,tag:a}of r.unwrapJsx){let c=A.join(e,i);if(!w(c))continue;let l=await be(c,"utf-8"),p=We(l,a);p!==l&&await Ot(c,p,"utf-8")}for(let{file:i,name:a}of r.unwrapCall){let c=A.join(e,i);if(!w(c))continue;let l=await be(c,"utf-8"),p=Ke(l,a);p!==l&&await Ot(c,p,"utf-8")}let o=A.join(e,"package.json"),s=JSON.parse(await be(o,"utf-8"));s.dependencies??={},s.devDependencies??={},s.scripts??={};for(let i of r.removePackages)delete s.dependencies[i],delete s.devDependencies[i];for(let i of r.removeScripts)delete s.scripts[i];Object.assign(s.dependencies,r.addPackages),Object.assign(s.devDependencies,r.addDevPackages),Object.assign(s.scripts,r.addScripts),s.dependencies=An(s.dependencies),s.devDependencies=An(s.devDependencies),await Ot(o,`${JSON.stringify(s,null,2)}
18
- `,"utf-8"),await ue(e,{...n,answers:r.after})},An=e=>Object.fromEntries(Object.entries(e).sort(([t],[r])=>t.localeCompare(r)));var Qi=(e,t)=>e.replace(/support@teispace\.com/g,t.email).replace(/Next\.js Starter/g,t.projectName).replace(/\[AUTHOR\]/g,t.author).replace(/\[COMPANY\]/g,t.author).replace(/\[EMAIL\]/g,t.email),Dn=async(e,t)=>{let r=[de.join(e,C.GITHUB_DIR,C.GITHUB_PR_TEMPLATE),de.join(e,C.CODE_OF_CONDUCT),de.join(e,C.CONTRIBUTING),de.join(e,C.SECURITY)],n=de.join(e,C.GITHUB_DIR,C.GITHUB_ISSUE_TEMPLATE);if(w(n))for(let o of await Yi(n))r.push(de.join(n,o));for(let o of r){if(!w(o))continue;let s=await R(o),i=Qi(s,t);i!==s&&await P(o,i)}},Ln=async(e,t)=>{let r=de.join(e,C.ENV_EXAMPLE);if(!w(r))return;let n=await R(r);n=n.replace(/^CONTAINER_NAME=.*$/m,`CONTAINER_NAME=${t.projectName} # -public`),n=n.replace(/^IMAGE_NAME=.*$/m,`IMAGE_NAME=${t.projectName} # -public`),await P(r,n)},Zi=(e,t,r)=>{let n=e.options[t];if(!n)return null;let o=n.label??t;return n.type==="boolean"?r?o:null:Array.isArray(r)?r.length?`${o}: ${r.join(", ")}`:null:r==="none"?null:`${o}: ${String(r)}`},Un=async(e,t,r,n,o)=>{let s=de.join(e,C.README);if(!t.readme){await $n(s);return}let i=Object.entries(n).filter(([l])=>l!=="packageManager").map(([l,p])=>Zi(r,l,p)).filter(l=>l!==null),a=[["dev","development server"],["build","production build"],["start","serve the production build"],["lint:fix","lint, format, and sort imports"],["type-check","route types + tsc"],["check:deprecated","fail on deprecated API usage"],["validate","every gate CI runs"]];n.tests&&a.push(["test","unit and component tests"]),n.e2e&&a.push(["test:e2e","Playwright against a production build"]);let c=`# ${t.projectName}
14
+ `)},Ki=e=>{switch(e){case"pnpm":return["install","--no-frozen-lockfile"];case"yarn":return["install","--no-immutable"];default:return["install"]}},he=async(e,t)=>{try{await jn(t,Ki(t),e)}catch(r){throw new Error(`Failed to install dependencies with ${t}:
15
+ ${zi(r)}`,{cause:r})}},Ft=async(e,t,r)=>{let n=t==="npm"?["run",r]:[r];try{await jn(t,n,e)}catch(o){console.warn(`Warning: Failed to run script '${r}': ${o}`)}};import Xi from"enquirer";var{prompt:Cn}=Xi,Yi=/^[a-z0-9-_]+$/,Qi=/^\d+\.\d+\.\d+$/,On=e=>Yi.test(e),An=e=>Qi.test(e),ct=e=>{if(!On(e))throw new Error(`Invalid project name "${e}". Use lowercase letters, digits, hyphens, and underscores only \u2014 no slashes, "..", or absolute paths.`)},ye=(e,t={})=>{let r=t.projectName??e??"my-app";ct(r);let n=t.version??"0.1.0";if(!An(n))throw new Error(`Invalid version "${n}". Expected semver (e.g. 0.1.0).`);return{projectName:r,description:t.description??"A Next.js application",author:t.author??"Teispace",version:n,email:t.email??"support@example.com",gitRemote:t.gitRemote??"",pushToRemote:t.pushToRemote??!1,gitIssues:t.gitIssues??"",gitHomepage:t.gitHomepage??"",readme:t.readme??!0,copyEnv:t.copyEnv??!0}},In=e=>e.state?.answers??e.enquirer?.answers??{},Nn=async e=>{e!==void 0&&ct(e);let t=await Cn([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:r=>On(r)||"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:r=>An(r)||"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com"},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",initial:"",validate:r=>!r||/^(https:\/\/github\.com\/[\w-]+\/[\w.-]+(\.git)?|git@github\.com:[\w-]+\/[\w.-]+\.git)$/.test(r)||"Enter a GitHub URL (https://github.com/user/repo or git@github.com:user/repo.git)."},{type:"confirm",name:"pushToRemote",message:"Push the initial commit to the remote?",initial:!1,skip:function(){return!In(this).gitRemote}},{type:"confirm",name:"readme",message:"Create a README.md?",initial:!0},{type:"confirm",name:"copyEnv",message:"Copy .env.example to .env?",initial:!0}]);return ye(e,{...t,projectName:e??t.projectName})},Mt=async(e,t={})=>{let r=Object.entries(e.options).map(([s,i])=>{let a=t[s]??i.default,c={name:s,message:i.label??s,skip:function(){if(!i.requires)return!1;let p=In(this);return!Object.entries(i.requires).every(([u,d])=>Et(e.options[u],p[u],d))}};if(i.type==="boolean")return{...c,type:"confirm",initial:!!a};if(i.type==="multi")return{...c,type:"multiselect",choices:(i.values??[]).map(p=>({name:p,value:p})),initial:Array.isArray(a)?a:[]};let m=i.values??[];return{...c,type:"select",choices:m,initial:Math.max(0,m.indexOf(String(a)))}}),n=await Cn(r),o={};for(let[s,i]of Object.entries(e.options)){let a=n[s];a!==void 0&&(o[s]=i.type==="multi"&&!Array.isArray(a)?[]:a)}return o};import Zi from"node:path";var A={NEXT_CONFIG:"next.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",BIOME_CONFIG:"biome.json",VITEST_CONFIG:"vitest.config.ts",TEST_DIR:"test",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",AGENTS_MD:"AGENTS.md",CLAUDE_MD:"CLAUDE.md",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",SEO_FILE:"src/lib/config/seo.ts",SITEMAP_FILE:"src/app/sitemap.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",HTTP_SHARED:"src/lib/utils/http/shared",HTTP_SERVER_FILE:"src/lib/utils/http/server.ts",HTTP_BUNDLE_SENTINEL_DIR:"src/lib/utils/http/__bundle-sentinel__",HTTP_BUNDLE_SENTINEL_FILE:"src/lib/utils/http/__bundle-sentinel__/client-bundle-sentinel.tsx",WS_UTILS:"src/lib/utils/ws",WS_SLICE_FILE:"src/store/slices/ws.slice.ts",WS_SLICE_TEST_FILE:"src/store/slices/ws.slice.test.ts",ROOT_REDUCER:"src/store/rootReducer.ts",TEST_SETUP_FILE:"test/setup.ts",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",AXIOS_CLIENT_FILE:"src/lib/utils/http/axios-client/index.ts",FETCH_CLIENT_FILE:"src/lib/utils/http/fetch-client/index.ts",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",API_URL_FILE:"src/lib/config/api-url.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",LOCALE_LAYOUT:"src/app/[locale]/layout.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md",SCRIPTS_DIR:"scripts",DOCS_DIR:"docs",CLAUDE_DIR:".claude",VSCODE_DIR:".vscode"};var ea=e=>{let t=e.gitRemote,r=e.gitHomepage,n=e.gitIssues;if(!t)return{remote:"",homepage:"",issues:""};t.startsWith("git@github.com:")&&(t=t.replace("git@github.com:","https://github.com/").replace(/\.git$/,""));let o=t.replace(/\.git$/,"");return r||=`${o}#readme`,n||=`${o}/issues`,t.endsWith(".git")||(t=`${t}.git`),{remote:t,homepage:r,issues:n}},Fn=async(e,t)=>{let{remote:r,homepage:n,issues:o}=ea(t);await Rn(Zi.join(e,A.PACKAGE_JSON),s=>(s.name=t.projectName,s.version=t.version,s.description=t.description,s.author=t.author,delete s.keywords,r?(s.homepage=n,s.bugs={url:o},s.repository={type:"git",url:r}):(delete s.homepage,delete s.bugs,delete s.repository),s))};import{readdir as aa}from"node:fs/promises";import xe from"node:path";import{cp as ta,mkdir as ra,mkdtemp as na,readFile as Te,rm as Dn,writeFile as _t}from"node:fs/promises";import{tmpdir as oa}from"node:os";import F from"node:path";var Ve=".next-maker.json",we=async(e,t)=>{await _t(F.join(e,Ve),`${JSON.stringify(t,null,2)}
16
+ `,"utf-8")},pe=async e=>{let t=F.join(e,Ve);if(!w(t))throw new Error(`No ${Ve} in ${e}. Only projects created with next-maker 5+ can be reconfigured; run \`next-maker init\` for a new project.`);return JSON.parse(await Te(t,"utf-8"))},He=async(e,t={})=>{let r=e.starter.source.startsWith("/")&&w(e.starter.source)?e.starter.source:void 0,n=z({starterPath:t.starterPath??r}),o=await na(F.join(oa(),"next-maker-starter-"));await It(o,{source:n});let s=await rt(o),i=await I(o);return{dir:o,source:n,manifest:s,files:i,dispose:()=>Dn(o,{recursive:!0,force:!0})}},Mn=(e,t)=>e[t]??{},sa=e=>[...e.off?.anchors??[],...e.on?.anchors??[]],ia=async(e,t)=>{if(t.length===0)return[];let r=[],n=new RegExp(`@next-maker:(?:${t.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|")})(?::(start|end))?`);for(let o of e.files){if(o.startsWith(".next-maker/"))continue;let s;try{s=await Te(F.join(e.dir,o),"utf-8")}catch{continue}if(!tt(s))continue;let i=s.split(`
17
+ `),a=[];for(let c=0;c<i.length;c++){let m=i[c].match(n);if(m)if(m[1]==="start"){let p=c+1;for(;p<i.length&&!/@next-maker:[\w-]+:end/.test(i[p]);)a.push(i[p++]);c=p}else m[1]==="end"||(/^\s*(\{\s*\/\*|\/\*|\/\/|#)/.test(i[c])?i[c+1]!==void 0&&a.push(i[++c]):a.push(i[c].replace(/\s*(\{\s*\/\*|\/\*|\/\/|#).*$/,"")))}a.length&&r.push({file:o,lines:a})}return r},Ln=async(e,t)=>{let r=e.manifest.features[t];if(!r)throw new Error(`Unknown feature "${t}". Valid: ${Object.keys(e.manifest.features).join(", ")}.`);let n=Mn(r,"off"),o=Mn(r,"on"),s=new Set(e.manifest.always.remove.flatMap(c=>Y(e.files,c))),i=[...new Set((n.remove??[]).flatMap(c=>Y(e.files,c)))].filter(c=>!s.has(c)).sort(),a=o.overlay?(await I(F.join(e.dir,ae,o.overlay),new Set)).sort():[];return{id:t,feature:r,files:i,overlayFiles:a,packages:n.packages??[],devPackages:n.devPackages??[],scripts:n.scripts??[],env:n.env??[],snippets:await ia(e,sa(r))}},Un=e=>/\.(test|spec)\.tsx?$/.test(e)||e.startsWith("test/")||e.includes("__test-utils__"),mr=async(e,t,r)=>{let n=JSON.parse(await Te(F.join(e,"package.json"),"utf-8")),o=t.answers.tests!==!1,s=[],i=Object.values(r.manifest.features).filter(c=>!de(r.manifest,c,t.answers)).flatMap(c=>c.off?.remove??[]),a=new Set(i.flatMap(c=>Y(r.files,c)));for(let[c,m]of Object.entries(r.manifest.features)){let p=de(r.manifest,m,t.answers);if(!p){s.push({id:c,on:p,drift:[]});continue}let u=await Ln(r,c),d=[];for(let f of[...u.files,...u.overlayFiles])!o&&Un(f)||a.has(f)||w(F.join(e,f))||d.push({kind:"missingFile",file:f});for(let f of u.packages)n.dependencies?.[f]||d.push({kind:"missingPackage",name:f,dev:!1});for(let f of u.devPackages)n.devDependencies?.[f]||d.push({kind:"missingPackage",name:f,dev:!0});for(let f of u.scripts)n.scripts?.[f]||d.push({kind:"missingScript",name:f});s.push({id:c,on:p,drift:d})}return s},Bn=async(e,t,r,n)=>{let o=t.answers,s=JSON.parse(await Te(F.join(r.dir,"package.json"),"utf-8")),i=[],a=[];for(let[p,u]of Object.entries(r.manifest.features)){let d=de(r.manifest,u,o),f=de(r.manifest,u,n);d!==f&&(f?i:a).push(await Ln(r,p))}let c=n.tests!==!1,m={before:o,after:n,turningOn:i,turningOff:a,copy:[],remove:[],addPackages:{},addDevPackages:{},removePackages:[],addScripts:{},removeScripts:[],unwrapJsx:[],unwrapCall:[],manual:[]};for(let p of a){for(let u of[...p.files,...p.overlayFiles])w(F.join(e,u))&&m.remove.push(u);m.removePackages.push(...p.packages,...p.devPackages),m.removeScripts.push(...p.scripts),m.unwrapJsx.push(...p.feature.off?.unwrapJsx??[]),m.unwrapCall.push(...p.feature.off?.unwrapCall??[]),p.snippets.length&&m.manual.push({feature:p.id,direction:"delete",snippets:p.snippets})}for(let p of i){for(let u of[...p.files,...p.overlayFiles])!c&&Un(u)||(!w(F.join(e,u))||p.overlayFiles.includes(u))&&m.copy.push(u);for(let u of p.packages)m.addPackages[u]=s.dependencies?.[u]??"latest";for(let u of p.devPackages)m.addDevPackages[u]=s.devDependencies?.[u]??"latest";for(let u of p.scripts)s.scripts?.[u]&&(m.addScripts[u]=s.scripts[u]);p.snippets.length&&m.manual.push({feature:p.id,direction:"add",snippets:p.snippets})}return m.copy=[...new Set(m.copy)].sort(),m.remove=[...new Set(m.remove)].sort(),m},Gn=async(e,t,r,n)=>{for(let i of r.remove)await Dn(F.join(e,i),{force:!0});for(let i of r.copy){let a=r.turningOn.find(p=>p.overlayFiles.includes(i)),c=a?.feature.on?.overlay?F.join(t.dir,ae,a.feature.on.overlay,i):F.join(t.dir,i),m=F.join(e,i);await ra(F.dirname(m),{recursive:!0}),await ta(c,m,{force:!0})}for(let{file:i,tag:a}of r.unwrapJsx){let c=F.join(e,i);if(!w(c))continue;let m=await Te(c,"utf-8"),p=$e(m,a);p!==m&&await _t(c,p,"utf-8")}for(let{file:i,name:a}of r.unwrapCall){let c=F.join(e,i);if(!w(c))continue;let m=await Te(c,"utf-8"),p=Pe(m,a);p!==m&&await _t(c,p,"utf-8")}let o=F.join(e,"package.json"),s=JSON.parse(await Te(o,"utf-8"));s.dependencies??={},s.devDependencies??={},s.scripts??={};for(let i of r.removePackages)delete s.dependencies[i],delete s.devDependencies[i];for(let i of r.removeScripts)delete s.scripts[i];Object.assign(s.dependencies,r.addPackages),Object.assign(s.devDependencies,r.addDevPackages),Object.assign(s.scripts,r.addScripts),s.dependencies=_n(s.dependencies),s.devDependencies=_n(s.devDependencies),await _t(o,`${JSON.stringify(s,null,2)}
18
+ `,"utf-8"),await we(e,{...n,answers:r.after})},_n=e=>Object.fromEntries(Object.entries(e).sort(([t],[r])=>t.localeCompare(r)));var ca=(e,t)=>e.replace(/support@teispace\.com/g,t.email).replace(/Next\.js Starter/g,t.projectName).replace(/\[AUTHOR\]/g,t.author).replace(/\[COMPANY\]/g,t.author).replace(/\[EMAIL\]/g,t.email),Vn=async(e,t)=>{let r=[xe.join(e,A.GITHUB_DIR,A.GITHUB_PR_TEMPLATE),xe.join(e,A.CODE_OF_CONDUCT),xe.join(e,A.CONTRIBUTING),xe.join(e,A.SECURITY)],n=xe.join(e,A.GITHUB_DIR,A.GITHUB_ISSUE_TEMPLATE);if(w(n))for(let o of await aa(n))r.push(xe.join(n,o));for(let o of r){if(!w(o))continue;let s=await O(o),i=ca(s,t);i!==s&&await R(o,i)}},Hn=async(e,t)=>{let r=xe.join(e,A.ENV_EXAMPLE);if(!w(r))return;let n=await O(r);n=n.replace(/^CONTAINER_NAME=.*$/m,`CONTAINER_NAME=${t.projectName} # -public`),n=n.replace(/^IMAGE_NAME=.*$/m,`IMAGE_NAME=${t.projectName} # -public`),await R(r,n)},pa=(e,t,r)=>{let n=e.options[t];if(!n)return null;let o=n.label??t;return n.type==="boolean"?r?o:null:Array.isArray(r)?r.length?`${o}: ${r.join(", ")}`:null:r==="none"?null:`${o}: ${String(r)}`},qn=async(e,t,r,n,o)=>{let s=xe.join(e,A.README);if(!t.readme){await Tn(s);return}let i=Object.entries(n).filter(([m])=>m!=="packageManager").map(([m,p])=>pa(r,m,p)).filter(m=>m!==null),a=[["dev","development server"],["build","production build"],["start","serve the production build"],["lint:fix","lint, format, and sort imports"],["type-check","route types + tsc"],["check:deprecated","fail on deprecated API usage"],["validate","every gate CI runs"]];n.tests&&a.push(["test","unit and component tests"]),n.e2e&&a.push(["test:e2e","Playwright against a production build"]);let c=`# ${t.projectName}
19
19
 
20
20
  ${t.description}
21
21
 
@@ -25,21 +25,21 @@ Generated from [@teispace/nextjs-starter](https://github.com/teispace/nextjs-sta
25
25
 
26
26
  \`\`\`bash
27
27
  ${o} install
28
- ${ce(o,"dev")}
28
+ ${fe(o,"dev")}
29
29
  \`\`\`
30
30
 
31
31
  Open [http://localhost:3000](http://localhost:3000). Copy \`.env.example\` to \`.env\` and set \`NEXT_PUBLIC_API_URL\` to your API origin. Production builds also need \`NEXT_PUBLIC_APP_URL\`, the public URL of this app.
32
32
 
33
33
  ## What is included
34
34
 
35
- ${i.map(l=>`- ${l}`).join(`
35
+ ${i.map(m=>`- ${m}`).join(`
36
36
  `)}
37
37
 
38
38
  ## Scripts
39
39
 
40
40
  | Script | Purpose |
41
41
  | :-- | :-- |
42
- ${a.map(([l,p])=>`| \`${ce(o,l)}\` | ${p} |`).join(`
42
+ ${a.map(([m,p])=>`| \`${fe(o,m)}\` | ${p} |`).join(`
43
43
  `)}
44
44
 
45
45
  ## Guides
@@ -51,9 +51,11 @@ ${a.map(([l,p])=>`| \`${ce(o,l)}\` | ${p} |`).join(`
51
51
  ${n.ws?"- `src/lib/ws/README.md`: the WebSocket client\n":""}${n.i18n?"- `src/i18n/README.md`: internationalization\n":""}- \`docs/ui-libraries.md\`: adding shadcn/ui, Radix, MUI, Mantine, or HeroUI
52
52
 
53
53
  Generators: \`npx @teispace/next-maker feature <name>\`, \`page <name>\`, \`component <name>\`, \`env <NAME>\`${n.i18n?", `locale <code>`":""}.
54
- `;await P(s,c)};var ve=async e=>{await Tt(e.projectPath,{source:e.source});let t=await Xe(e.projectPath);return nt(t,e.supplied,e.packageManager)},nt=(e,t,r)=>{let{answers:n,forced:o,unknown:s}=Ye(e,t),i=n.packageManager??r??"pnpm";return{manifest:e,answers:n,forced:o,unknown:s,packageManager:i,plan:er(e,n,i)}},$e=async(e,t,r,n)=>{let{manifest:o,answers:s,packageManager:i,plan:a}=r,c=await rr(e,o,a);return await Cn(e,t),await Dn(e,t),await Ln(e,t),await Un(e,t,o,s,i),await ue(e,{cli:Ae.version,starter:{name:o.starter.name,version:o.starter.version,source:n.location},packageManager:i,answers:s,identity:{projectName:t.projectName,description:t.description,author:t.author,version:t.version,email:t.email,gitRemote:t.gitRemote,readme:t.readme}}),c};var ar=["pnpm","npm","yarn","bun"],ta=e=>{if(e!==void 0){if(!ar.includes(e))throw new Error(`Invalid --package-manager "${e}". Valid: ${ar.join(", ")}.`);return e}},ra=(e,t=[])=>[...t,e],Gn=e=>{e.command("init").description("Create a new Next.js project from the Teispace starter").argument("[name]","Project name").option("-y, --yes","Skip every prompt and use the starter defaults").option("--preset <name>",`Start from a preset (${Fe().join(", ")})`).option("--config <file>","Read identity and options from a JSON file (non-interactive)").option("--set <key=value>","Override one starter option (repeatable), e.g. --set i18n=false",ra).option("--package-manager <pm>",`Package manager (${ar.join(", ")})`).option("--starter-path <dir>","Compose from a local starter checkout instead of the pinned tag").option("--dry-run","Print the composition plan and create nothing").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").action(async(t,r)=>{try{await ia(t,r)}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},ot=async(e,t,r,n)=>{let o=St(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},na=e=>Array.isArray(e)?e.length?e.join(", "):"none":String(e),oa=(e,t,r)=>{m(I.bold("Options"));for(let[n,o]of Object.entries(t.answers)){let s=e.options[n]?.label??n;m(` ${I.dim(s.padEnd(44))} ${na(o)}`)}for(let n of r)m(I.yellow(` ! ${n.reason}; ${n.option} turned off`));m(""),m(I.bold("Composition")),m(` ${I.green("keep")} ${t.featuresOn.join(", ")||"(none)"}`),m(` ${I.red("drop")} ${t.featuresOff.join(", ")||"(none)"}`),(t.featureOverlays.length||t.pmOverlays.length)&&m(` ${I.cyan("overlay")} ${[...t.pmOverlays,...t.featureOverlays].join(", ")}`),(t.packages.length||t.devPackages.length)&&m(` ${I.red("uninstall")} ${[...t.packages,...t.devPackages].join(", ")}`),m("")},sa=async(e,t)=>{let r=t.config?await nr(t.config):void 0,n=ta(t.packageManager??r?.packageManager),s={...t.preset?Me(t.preset):r?.preset?Me(r.preset):{},...r?.options??{},...xe(t.set)};n&&(s.packageManager=n);let i=!(t.yes||r);return{identity:i?await Rn(e):me(e,{projectName:r?.name,description:r?.description,author:r?.author,version:r?.version,email:r?.email,gitRemote:r?.gitRemote,readme:r?.readme,copyEnv:r?.copyEnv}),packageManager:n??"pnpm",suppliedOptions:s,interactive:i,install:t.install!==!1&&r?.install!==!1,git:t.git!==!1&&r?.git!==!1}},ia=async(e,t)=>{Pt();let r=await sa(e,t),{identity:n}=r,o=At.resolve(process.cwd(),n.projectName);if(w(o))throw new Error(`Directory ${n.projectName} already exists.`);let s={current:null},i=async()=>{w(o)&&(s.current?.stop(),s.current=null,m(I.yellow(`
55
- Cleaning up ${n.projectName}...`)),await tt(o))},a=$t(async()=>{m(I.red(`
56
- Process interrupted.`)),await i()});try{let c=V({starterPath:t.starterPath}),l=await ot(`Fetching starter (${c.location})...`,"Starter fetched.",()=>ve({projectPath:o,source:c,supplied:r.suppliedOptions,packageManager:r.packageManager}),s);if(m(I.dim(` ${l.manifest.starter.name} ${l.manifest.starter.version}`)),m(""),r.interactive){let d={...r.suppliedOptions,...await Ct(l.manifest,l.answers)};t.packageManager&&(d.packageManager=t.packageManager),l=nt(l.manifest,d,r.packageManager),m("")}for(let d of l.unknown)m(I.yellow(` ! unknown option "${d}" ignored`));let{packageManager:p,plan:u,manifest:f}=l;if(oa(f,u,l.forced),t.dryRun){a(),await tt(o),m(I.cyan("Dry run: nothing was created."));return}await ot("Composing project...","Project composed.",()=>$e(o,n,l,c),s),r.install&&(await ot(`Installing dependencies with ${p}...`,"Dependencies installed.",()=>le(o,p),s),await ot("Formatting...","Formatted.",()=>Rt(o,p,"lint:fix"),s)),n.copyEnv&&w(At.join(o,".env.example"))&&await ea(At.join(o,".env.example"),At.join(o,".env")),r.git&&await ot("Initializing git...","Git initialized.",()=>jt(o,n.gitRemote,n.pushToRemote),s),a(),m(""),m(I.green(`\u2728 ${n.projectName} is ready.`)),m(""),m("Next:"),m(I.cyan(` cd ${n.projectName}`)),r.install||m(I.cyan(` ${p} install`)),m(I.cyan(` ${p==="pnpm"||p==="yarn"?`${p} dev`:`${p} run dev`}`)),m("")}catch(c){throw a(),s.current?.fail("Failed to create project."),s.current=null,await i(),c}};import Mr from"node:path";import X from"picocolors";import It from"node:path";var Bn=/^[A-Za-z][A-Za-z0-9-]*$/,aa=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;function Vn(e){return aa.test(e)}function M(e,t="name"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);if(!Bn.test(r))throw new Error(`Invalid ${t} "${e}". Use letters, digits, and hyphens only \u2014 no slashes, spaces, "..", or absolute paths.`);if(Vn(r))throw new Error(`Invalid ${t} "${e}". That is a reserved name on Windows.`);return r}function W(e,t="path"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);let n=r.replace(/^\.\//,"");if(n.startsWith("/")||/^[a-zA-Z]:/.test(n))throw new Error(`Invalid ${t} "${e}". Must be a relative path inside the project (no leading "/" or drive letter).`);for(let o of n.split("/")){if(!Bn.test(o))throw new Error(`Invalid ${t} "${e}". Each segment must be kebab/camel-case (letters, digits, hyphens), separated by "/" \u2014 no "..", dots, or empty segments.`);if(Vn(o))throw new Error(`Invalid ${t} "${e}". Segment "${o}" is reserved on Windows.`)}return n}function ne(e,...t){let r=It.resolve(e),n=It.resolve(r,...t),o=It.relative(r,n);if(o===""||o===".")return n;if(o.startsWith("..")||It.isAbsolute(o))throw new Error(`Refusing to write outside the project directory (resolved path escapes "${r}").`);return n}import{execFile as ca}from"node:child_process";import{stat as pa}from"node:fs/promises";import cr from"node:path";import{promisify as la}from"node:util";var ma=la(ca),ua=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".jsonc",".css"]),da=e=>cr.join(e,"node_modules",".bin","biome"),pr=async(e,t,r=e)=>{let n=da(r);if(t.length===0||!w(n))return!1;try{await ma(n,["check","--write","--no-errors-on-unmatched",...t],{cwd:e,maxBuffer:64*1024*1024})}catch(o){if(o.code==="ENOENT")return!1}return!0},k=async(e,t)=>{let r=[];for(let n of await L(e))if(ua.has(cr.extname(n)))try{(await pa(cr.join(e,n))).mtimeMs>=t-1e3&&r.push(n)}catch{}return r.length&&await pr(e,r),r};import{access as fa}from"node:fs/promises";import ga from"node:path";var ke=async(e,t,r)=>{try{return await fa(ga.join(e,r,t)),!0}catch{return!1}};import{access as ha,readFile as qn}from"node:fs/promises";import lr from"node:path";var Le=async e=>{try{return await ha(e),!0}catch{return!1}},Hn=async e=>{try{return JSON.parse(await qn(e,"utf-8"))}catch{return null}},O=async e=>{let t=await Hn(lr.join(e,"package.json"));if(!t)throw new Error(`Failed to detect project setup: no package.json in ${e}`);let r={...t.dependencies,...t.devDependencies},n=await Hn(lr.join(e,_e)),o=(...y)=>lr.join(e,...y),s=await Le(o("src","store")),i=!!(r["@reduxjs/toolkit"]&&r["react-redux"])&&s,a=!!r.zustand&&s&&!i,c=i?"redux":a?"zustand":"none",l=await Le(o("src","lib","http","core","client.ts")),p=!!r.axios&&await Le(o("src","lib","http","adapters","axios.ts")),u="none";if(l)if(!p)u="fetch";else{let y="";try{y=await qn(o("src","lib","http","client.ts"),"utf-8")}catch{}u=y.includes("axiosAdapter")?"axios":"both"}let f=!!r["next-intl"]&&await Le(o("src","i18n")),d=!!r.vitest||await Le(o("vitest.config.ts")),g=r["socket.io-client"]&&await Le(o("src","lib","ws"))?"present":"none";return{state:c,hasRedux:i,httpClient:u,hasI18n:f,hasTests:d,ws:g,hasQuery:!!r["@tanstack/react-query"],hasActions:!!r["next-safe-action"],record:n??void 0}};import{mkdir as ya,writeFile as wa}from"node:fs/promises";import mr from"node:path";var Jn=({pascalName:e,camelName:t})=>`import { z } from 'zod';
54
+ `;await R(s,c)};var Re=async e=>{await It(e.projectPath,{source:e.source});let t=await rt(e.projectPath);return pt(t,e.supplied,e.packageManager)},pt=(e,t,r)=>{let{answers:n,forced:o,unknown:s}=nt(e,t),i=n.packageManager??r??"pnpm";return{manifest:e,answers:n,forced:o,unknown:s,packageManager:i,plan:sr(e,n,i)}},je=async(e,t,r,n)=>{let{manifest:o,answers:s,packageManager:i,plan:a}=r,c=await ar(e,o,a);return await Fn(e,t),await Vn(e,t),await Hn(e,t),await qn(e,t,o,s,i),await we(e,{cli:De.version,starter:{name:o.starter.name,version:o.starter.version,source:n.location},packageManager:i,answers:s,identity:{projectName:t.projectName,description:t.description,author:t.author,version:t.version,email:t.email,gitRemote:t.gitRemote,readme:t.readme}}),c};import{readFile as Jn,rm as la,writeFile as ma}from"node:fs/promises";import lt from"node:path";var Wn={hooks:!1,commitizen:!1,ci:!1,docker:!1,githubTemplates:!1,communityFiles:[]},ua=["pnpm-workspace.yaml","pnpm-lock.yaml",".npmrc",".nvmrc"],da=e=>{let t=e.split(`
55
+ `),r=t.findIndex(o=>o.trimEnd()==="catalog:");if(r===-1)return{};let n={};for(let o of t.slice(r+1)){if(o.trim()==="")continue;if(!/^\s+\S/.test(o))break;let s=o.match(/^\s+'?([^':]+)'?\s*:\s*'?([^']+?)'?\s*$/);s&&(n[s[1]]=s[2])}return n},zn=async e=>{let t=lt.resolve(e);for(;;){let r=lt.join(t,"pnpm-workspace.yaml");if(w(r))try{return{root:t,catalog:da(await Jn(r,"utf-8"))}}catch{return null}let n=lt.dirname(t);if(n===t)return null;t=n}},fa=(e,t)=>{let r=structuredClone(e),n=0;for(let o of["dependencies","devDependencies"]){let s=r[o];if(s)for(let i of Object.keys(s))t[i]===s[i]&&(s[i]="catalog:",n++)}return{pkg:r,count:n}},Kn=async(e,t)=>{let r=[];for(let a of ua){let c=lt.join(e,a);w(c)&&(await la(c,{force:!0}),r.push(a))}let n=lt.join(e,"package.json"),o=JSON.parse(await Jn(n,"utf-8"));o.packageManager=void 0,o.engines=void 0;let{pkg:s,count:i}=fa(o,t.catalog);return await ma(n,`${JSON.stringify(Object.fromEntries(Object.entries(s).filter(([,a])=>a!==void 0)),null,2)}
56
+ `),{removed:r,catalogued:i}};var ur=["pnpm","npm","yarn","bun"],ha=e=>{if(e!==void 0){if(!ur.includes(e))throw new Error(`Invalid --package-manager "${e}". Valid: ${ur.join(", ")}.`);return e}},ya=(e,t=[])=>[...t,e],Xn=e=>{e.command("init").description("Create a new Next.js project from the Teispace starter").argument("[name]","Project name").option("-y, --yes","Skip every prompt and use the starter defaults").option("--preset <name>",`Start from a preset (${Be().join(", ")})`).option("--config <file>","Read identity and options from a JSON file (non-interactive)").option("--set <key=value>","Override one starter option (repeatable), e.g. --set i18n=false",ya).option("--package-manager <pm>",`Package manager (${ur.join(", ")})`).option("--starter-path <dir>","Compose from a local starter checkout instead of the pinned tag").option("--dry-run","Print the composition plan and create nothing").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").action(async(t,r)=>{try{await va(t,r)}catch(n){v(`${n instanceof Error?n.message:n}`),process.exit(1)}})},mt=async(e,t,r,n)=>{let o=Ot(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},wa=e=>Array.isArray(e)?e.length?e.join(", "):"none":String(e),xa=(e,t,r)=>{l(j.bold("Options"));for(let[n,o]of Object.entries(t.answers)){let s=e.options[n]?.label??n;l(` ${j.dim(s.padEnd(44))} ${wa(o)}`)}for(let n of r)l(j.yellow(` ! ${n.reason}; ${n.option} turned off`));l(""),l(j.bold("Composition")),l(` ${j.green("keep")} ${t.featuresOn.join(", ")||"(none)"}`),l(` ${j.red("drop")} ${t.featuresOff.join(", ")||"(none)"}`),(t.featureOverlays.length||t.pmOverlays.length)&&l(` ${j.cyan("overlay")} ${[...t.pmOverlays,...t.featureOverlays].join(", ")}`),(t.packages.length||t.devPackages.length)&&l(` ${j.red("uninstall")} ${[...t.packages,...t.devPackages].join(", ")}`),l("")},ba=async(e,t)=>{let r=t.config?await cr(t.config):void 0,n=ha(t.packageManager??r?.packageManager),s={...t.preset?Ge(t.preset):r?.preset?Ge(r.preset):{},...r?.options??{},...Ee(t.set)};n&&(s.packageManager=n);let i=!(t.yes||r);return{identity:i?await Nn(e):ye(e,{projectName:r?.name,description:r?.description,author:r?.author,version:r?.version,email:r?.email,gitRemote:r?.gitRemote,readme:r?.readme,copyEnv:r?.copyEnv}),packageManager:n??"pnpm",suppliedOptions:s,interactive:i,install:t.install!==!1&&r?.install!==!1,git:t.git!==!1&&r?.git!==!1}},va=async(e,t)=>{Ct();let r=await ba(e,t),{identity:n}=r,o=qe.resolve(process.cwd(),n.projectName);if(w(o))throw new Error(`Directory ${n.projectName} already exists.`);let s=await zn(qe.dirname(o));s&&(l(j.dim(` pnpm workspace detected at ${qe.relative(process.cwd(),s.root)||"."}`)),l(j.dim(" Hooks, CI, Docker and the lockfile stay at the root.")),l(""),Object.assign(r.suppliedOptions,Wn),r.suppliedOptions.packageManager="pnpm",r.packageManager="pnpm");let i={current:null},a=async()=>{w(o)&&(i.current?.stop(),i.current=null,l(j.yellow(`
57
+ Cleaning up ${n.projectName}...`)),await at(o))},c=Rt(async()=>{l(j.red(`
58
+ Process interrupted.`)),await a()});try{let m=z({starterPath:t.starterPath}),p=await mt(`Fetching starter (${m.location})...`,"Starter fetched.",()=>Re({projectPath:o,source:m,supplied:r.suppliedOptions,packageManager:r.packageManager}),i);if(l(j.dim(` ${p.manifest.starter.name} ${p.manifest.starter.version}`)),l(""),r.interactive){let h={...r.suppliedOptions,...await Mt(p.manifest,p.answers)};t.packageManager&&(h.packageManager=t.packageManager),p=pt(p.manifest,h,r.packageManager),l("")}for(let h of p.unknown)l(j.yellow(` ! unknown option "${h}" ignored`));let{packageManager:u,plan:d,manifest:f}=p;if(xa(f,d,p.forced),t.dryRun){c(),await at(o),l(j.cyan("Dry run: nothing was created."));return}if(await mt("Composing project...","Project composed.",()=>je(o,n,p,m),i),s){let h=await Kn(o,s);h.removed.length&&l(j.dim(` Root-owned files dropped: ${h.removed.join(", ")}`)),h.catalogued&&l(j.dim(` ${h.catalogued} dependency range(s) now read from the root catalog`))}if(r.install){let h=s?s.root:o;await mt(`Installing dependencies with ${u}...`,"Dependencies installed.",()=>he(h,u),i),await mt("Formatting...","Formatted.",()=>Ft(o,u,"lint:fix"),i)}if(n.copyEnv&&w(qe.join(o,".env.example"))&&await ga(qe.join(o,".env.example"),qe.join(o,".env")),r.git&&!s&&await mt("Initializing git...","Git initialized.",()=>Nt(o,n.gitRemote,n.pushToRemote),i),c(),l(""),l(j.green(`\u2728 ${n.projectName} is ready.`)),l(""),l("Next:"),s){l(j.cyan(` pnpm --filter ${n.projectName} dev`)),l("");return}l(j.cyan(` cd ${n.projectName}`)),r.install||l(j.cyan(` ${u} install`)),l(j.cyan(` ${u==="pnpm"||u==="yarn"?`${u} dev`:`${u} run dev`}`)),l("")}catch(m){throw c(),i.current?.fail("Failed to create project."),i.current=null,await a(),m}};import Ur from"node:path";import te from"picocolors";import Dt from"node:path";var Yn=/^[A-Za-z][A-Za-z0-9-]*$/,ka=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;function Qn(e){return ka.test(e)}function D(e,t="name"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);if(!Yn.test(r))throw new Error(`Invalid ${t} "${e}". Use letters, digits, and hyphens only \u2014 no slashes, spaces, "..", or absolute paths.`);if(Qn(r))throw new Error(`Invalid ${t} "${e}". That is a reserved name on Windows.`);return r}function Z(e,t="path"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);let n=r.replace(/^\.\//,"");if(n.startsWith("/")||/^[a-zA-Z]:/.test(n))throw new Error(`Invalid ${t} "${e}". Must be a relative path inside the project (no leading "/" or drive letter).`);for(let o of n.split("/")){if(!Yn.test(o))throw new Error(`Invalid ${t} "${e}". Each segment must be kebab/camel-case (letters, digits, hyphens), separated by "/" \u2014 no "..", dots, or empty segments.`);if(Qn(o))throw new Error(`Invalid ${t} "${e}". Segment "${o}" is reserved on Windows.`)}return n}function le(e,...t){let r=Dt.resolve(e),n=Dt.resolve(r,...t),o=Dt.relative(r,n);if(o===""||o===".")return n;if(o.startsWith("..")||Dt.isAbsolute(o))throw new Error(`Refusing to write outside the project directory (resolved path escapes "${r}").`);return n}import{execFile as $a}from"node:child_process";import{stat as Pa}from"node:fs/promises";import dr from"node:path";import{promisify as Sa}from"node:util";var Ea=Sa($a),Ta=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".jsonc",".css"]),Ra=e=>dr.join(e,"node_modules",".bin","biome"),ut=async(e,t,r=e,n=!1)=>{let o=Ra(r);if(t.length===0||!w(o))return!1;let s=n?["format","--write","--no-errors-on-unmatched",...t]:["check","--write","--no-errors-on-unmatched",...t];try{await Ea(o,s,{cwd:e,maxBuffer:64*1024*1024})}catch(i){if(i.code==="ENOENT")return!1}return!0},E=async(e,t)=>{let r=[];for(let n of await I(e))if(Ta.has(dr.extname(n)))try{(await Pa(dr.join(e,n))).mtimeMs>=t-1e3&&r.push(n)}catch{}return r.length&&await ut(e,r),r};import{access as ja}from"node:fs/promises";import Ca from"node:path";var Ce=async(e,t,r)=>{try{return await ja(Ca.join(e,r,t)),!0}catch{return!1}};import{access as Oa,readFile as eo}from"node:fs/promises";import fr from"node:path";var Je=async e=>{try{return await Oa(e),!0}catch{return!1}},Zn=async e=>{try{return JSON.parse(await eo(e,"utf-8"))}catch{return null}},N=async e=>{let t=await Zn(fr.join(e,"package.json"));if(!t)throw new Error(`Failed to detect project setup: no package.json in ${e}`);let r={...t.dependencies,...t.devDependencies},n=await Zn(fr.join(e,Ve)),o=(...y)=>fr.join(e,...y),s=await Je(o("src","store")),i=!!(r["@reduxjs/toolkit"]&&r["react-redux"])&&s,a=!!r.zustand&&s&&!i,c=i?"redux":a?"zustand":"none",m=await Je(o("src","lib","http","core","client.ts")),p=!!r.axios&&await Je(o("src","lib","http","adapters","axios.ts")),u="none";if(m)if(!p)u="fetch";else{let y="";try{y=await eo(o("src","lib","http","client.ts"),"utf-8")}catch{}u=y.includes("axiosAdapter")?"axios":"both"}let d=!!r["next-intl"]&&await Je(o("src","i18n")),f=!!r.vitest||await Je(o("vitest.config.ts")),h=r["socket.io-client"]&&await Je(o("src","lib","ws"))?"present":"none";return{state:c,hasRedux:i,httpClient:u,hasI18n:d,hasTests:f,ws:h,hasQuery:!!r["@tanstack/react-query"],hasActions:!!r["next-safe-action"],record:n??void 0}};import{mkdir as Aa,writeFile as Ia}from"node:fs/promises";import gr from"node:path";var to=({pascalName:e,camelName:t})=>`import { z } from 'zod';
57
59
 
58
60
  /**
59
61
  * Wire contracts for the ${t} feature. Types are inferred from the
@@ -78,7 +80,7 @@ export const update${e}InputSchema = create${e}InputSchema.partial().extend({
78
80
  id: z.string(),
79
81
  });
80
82
  export type Update${e}Input = z.infer<typeof update${e}InputSchema>;
81
- `,zn=({kebabName:e,camelName:t})=>`/**
83
+ `,ro=({kebabName:e,camelName:t})=>`/**
82
84
  * Query keys owned by the feature. Everything under \`${t}Keys.all\` can
83
85
  * be invalidated at once; narrower keys target one resource.
84
86
  */
@@ -87,7 +89,7 @@ export const ${t}Keys = {
87
89
  list: () => [...${t}Keys.all, 'list'] as const,
88
90
  detail: (id: string) => [...${t}Keys.all, 'detail', id] as const,
89
91
  } as const;
90
- `,Wn=({pascalName:e,camelName:t})=>`import 'server-only';
92
+ `,no=({pascalName:e,camelName:t})=>`import 'server-only';
91
93
 
92
94
  import { AppApis } from '@/lib/config/app-apis';
93
95
  import { serverHttp } from '@/lib/http/server';
@@ -109,7 +111,7 @@ export const list${e}s = async () =>
109
111
 
110
112
  export const get${e} = async (id: string) =>
111
113
  serverHttp.get(AppApis.${t}.detail(id), { schema: ${t}Schema });
112
- `,Kn=({pascalName:e,camelName:t})=>`'use server';
114
+ `,oo=({pascalName:e,camelName:t})=>`'use server';
113
115
 
114
116
  import { revalidateTag } from 'next/cache';
115
117
 
@@ -158,7 +160,7 @@ export const delete${e} = authActionClient
158
160
  revalidateTag(${t.toUpperCase()}_TAG, 'max');
159
161
  return { deleted: true as const };
160
162
  });
161
- `,Xn=({pascalName:e,camelName:t})=>`import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
163
+ `,so=({pascalName:e,camelName:t})=>`import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
162
164
 
163
165
  import { AppApis } from '@/lib/config/app-apis';
164
166
  import { http } from '@/lib/http';
@@ -187,26 +189,26 @@ export const ${t}Query = (id: string) =>
187
189
 
188
190
  export const use${e}List = () => useSuspenseQuery(${t}ListQuery());
189
191
  export const use${e} = (id: string) => useSuspenseQuery(${t}Query(id));
190
- `,Yn=({camelName:e,kebabName:t})=>` ${e}: {
192
+ `,io=({camelName:e,kebabName:t})=>` ${e}: {
191
193
  list: '/${t}',
192
194
  detail: (id: string) => \`/${t}/\${id}\`,
193
195
  create: '/${t}',
194
196
  update: (id: string) => \`/${t}/\${id}\`,
195
197
  delete: (id: string) => \`/${t}/\${id}\`,
196
- },`;var st=async e=>{let{name:t,featurePath:r,withActions:n}=e,o={kebabName:t,camelName:G(t),pascalName:$(t)},s=mr.join(r,"api");await ya(s,{recursive:!0});let i=[["schema.ts",Jn(o)],["keys.ts",zn(o)],["server.ts",Wn(o)],["queries.ts",Xn(o)]];return n&&i.push(["actions.ts",Kn(o)]),await Promise.all(i.map(([a,c])=>wa(mr.join(s,a),c))),i.map(([a])=>mr.join("api",a))};import{mkdir as Zn,writeFile as dr}from"node:fs/promises";import Pe from"node:path";var ur=e=>{let{componentName:t,isClient:r,hasI18n:n}=e,o=e.translationNamespace||t,s=[];return(r||n)&&s.push("'use client';"),n&&s.push("import { useTranslations } from 'next-intl';"),s.push(""),s.push(`export function ${t}() {`),n?(s.push(` const t = useTranslations('${o}');`),s.push(""),s.push(" return ("),s.push(" <div>"),s.push(" <h2>{t('title')}</h2>"),s.push(" </div>"),s.push(" );")):(s.push(" return ("),s.push(" <div>"),s.push(` <h2>${t}</h2>`),s.push(" </div>"),s.push(" );")),s.push("}"),s.push(""),s.join(`
197
- `)},Qn=e=>`export { ${e.componentName} } from './${e.componentName}';
198
- `;var fr=async e=>{let{name:t,projectPath:r,isClient:n,hasI18n:o,featurePath:s}=e,i=$(t);s?await xa(i,r,s,n,o):await ba(i,t,r,n,o)},xa=async(e,t,r,n,o)=>{let s=Pe.join(t,r,"components");await Zn(s,{recursive:!0}),await dr(Pe.join(s,`${e}.tsx`),ur({componentName:e,isClient:n,hasI18n:o}))},ba=async(e,t,r,n,o)=>{let s=Pe.join(r,"src","components","common",e);await Zn(s,{recursive:!0}),await dr(Pe.join(s,`${e}.tsx`),ur({componentName:e,isClient:n,hasI18n:o})),await dr(Pe.join(s,"index.ts"),Qn({componentName:e}));let i=Pe.join(r,"src","components","common","index.ts");await va(i,`export { ${e} } from './${e}';
199
- `);let a=Pe.join(r,"src","components","index.ts");await $a(a)},va=async(e,t)=>{let r="";w(e)&&(r=await R(e)),r.includes(t.trim())||(r+=t,await P(e,r))},$a=async e=>{let t="";w(e)&&(t=await R(e));let r=`export * from './common';
200
- `;t.includes(r.trim())||(t+=r,await P(e,t))};import{mkdir as yr,writeFile as Ue}from"node:fs/promises";import K from"node:path";import{mkdir as ka,writeFile as Se}from"node:fs/promises";import Ee from"node:path";var hr=e=>{let{sliceName:t,withPersist:r,state:n="redux"}=e;return n==="zustand"?`export * from './${t}.store';
198
+ },`;var dt=async e=>{let{name:t,featurePath:r,withActions:n}=e,o={kebabName:t,camelName:V(t),pascalName:$(t)},s=gr.join(r,"api");await Aa(s,{recursive:!0});let i=[["schema.ts",to(o)],["keys.ts",ro(o)],["server.ts",no(o)],["queries.ts",so(o)]];return n&&i.push(["actions.ts",oo(o)]),await Promise.all(i.map(([a,c])=>Ia(gr.join(s,a),c))),i.map(([a])=>gr.join("api",a))};import{mkdir as co,writeFile as yr}from"node:fs/promises";import Oe from"node:path";var hr=e=>{let{componentName:t,isClient:r,hasI18n:n}=e,o=e.translationNamespace||t,s=[];return(r||n)&&s.push("'use client';"),n&&s.push("import { useTranslations } from 'next-intl';"),s.push(""),s.push(`export function ${t}() {`),n?(s.push(` const t = useTranslations('${o}');`),s.push(""),s.push(" return ("),s.push(" <div>"),s.push(" <h2>{t('title')}</h2>"),s.push(" </div>"),s.push(" );")):(s.push(" return ("),s.push(" <div>"),s.push(` <h2>${t}</h2>`),s.push(" </div>"),s.push(" );")),s.push("}"),s.push(""),s.join(`
199
+ `)},ao=e=>`export { ${e.componentName} } from './${e.componentName}';
200
+ `;var wr=async e=>{let{name:t,projectPath:r,isClient:n,hasI18n:o,featurePath:s}=e,i=$(t);s?await Na(i,r,s,n,o):await Fa(i,t,r,n,o)},Na=async(e,t,r,n,o)=>{let s=Oe.join(t,r,"components");await co(s,{recursive:!0}),await yr(Oe.join(s,`${e}.tsx`),hr({componentName:e,isClient:n,hasI18n:o}))},Fa=async(e,t,r,n,o)=>{let s=Oe.join(r,"src","components","common",e);await co(s,{recursive:!0}),await yr(Oe.join(s,`${e}.tsx`),hr({componentName:e,isClient:n,hasI18n:o})),await yr(Oe.join(s,"index.ts"),ao({componentName:e}));let i=Oe.join(r,"src","components","common","index.ts");await Ma(i,`export { ${e} } from './${e}';
201
+ `);let a=Oe.join(r,"src","components","index.ts");await _a(a)},Ma=async(e,t)=>{let r="";w(e)&&(r=await O(e)),r.includes(t.trim())||(r+=t,await R(e,r))},_a=async e=>{let t="";w(e)&&(t=await O(e));let r=`export * from './common';
202
+ `;t.includes(r.trim())||(t+=r,await R(e,t))};import{mkdir as vr,writeFile as We}from"node:fs/promises";import ee from"node:path";import{mkdir as Da,writeFile as Ae}from"node:fs/promises";import Ie from"node:path";var br=e=>{let{sliceName:t,withPersist:r,state:n="redux"}=e;return n==="zustand"?`export * from './${t}.store';
201
203
  `:`export * from './${t}.selectors';
202
204
  export * from './${t}.slice';${r?`
203
205
  export * from './persist';`:""}
204
- `},eo=e=>{let{featureName:t,componentName:r,hookName:n,pascalName:o,withStore:s,withApi:i}=e,a=["/**"," * Client-safe public surface. Server-only pieces live in `./server`."," */"];return i&&(a.push(`export { create${o}, delete${o}, update${o} } from './api/actions';`),a.push(`export { ${gr(t)}Keys } from './api/keys';`),a.push(`export { ${gr(t)}ListQuery, ${gr(t)}Query, use${o}, use${o}List } from './api/queries';`),a.push("export * from './api/schema';")),a.push(`export { ${r} } from './components/${r}';`),i||a.push(`export { ${n} } from './hooks/${n}';`),a.push(`export * from './types/${t}.types';`),s&&a.push("export * from './store';"),`${a.join(`
206
+ `},po=e=>{let{featureName:t,componentName:r,hookName:n,pascalName:o,withStore:s,withApi:i}=e,a=["/**"," * Client-safe public surface. Server-only pieces live in `./server`."," */"];return i&&(a.push(`export { create${o}, delete${o}, update${o} } from './api/actions';`),a.push(`export { ${xr(t)}Keys } from './api/keys';`),a.push(`export { ${xr(t)}ListQuery, ${xr(t)}Query, use${o}, use${o}List } from './api/queries';`),a.push("export * from './api/schema';")),a.push(`export { ${r} } from './components/${r}';`),i||a.push(`export { ${n} } from './hooks/${n}';`),a.push(`export * from './types/${t}.types';`),s&&a.push("export * from './store';"),`${a.join(`
205
207
  `)}
206
- `},to=e=>`import 'server-only';
208
+ `},lo=e=>`import 'server-only';
207
209
 
208
210
  export { get${e.pascalName}, list${e.pascalName}s, ${e.pascalName.toUpperCase()}_TAG } from './api/server';
209
- `,gr=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());var ro=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e,o=`${r.replace(/[A-Z]/g,s=>`_${s}`).toUpperCase()}_PERSIST_VERSION`;return`import { definePersistence } from '@/store/persistence';
211
+ `,xr=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());var mo=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e,o=`${r.replace(/[A-Z]/g,s=>`_${s}`).toUpperCase()}_PERSIST_VERSION`;return`import { definePersistence } from '@/store/persistence';
210
212
 
211
213
  import type { ${t}State } from '${n}';
212
214
 
@@ -224,12 +226,12 @@ export const ${r}Persistence = definePersistence<${t}State>({
224
226
  // 2: (previous) => ({ ...(previous as ${t}State), newField: 0 }),
225
227
  },
226
228
  });
227
- `};var no=e=>{let{componentName:t,camelName:r}=e;return`import type { RootState } from '@/store/rootReducer';
229
+ `};var uo=e=>{let{componentName:t,camelName:r}=e;return`import type { RootState } from '@/store/rootReducer';
228
230
 
229
231
  export const select${t}State = (state: RootState) => state.${r};
230
232
  export const select${t}Status = (state: RootState) => state.${r}.status;
231
233
  export const select${t}Error = (state: RootState) => state.${r}.error;
232
- `};var oo=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
234
+ `};var fo=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
233
235
 
234
236
  import type { ${t}State } from '${n}';
235
237
 
@@ -256,7 +258,7 @@ export const ${r}Slice = createSlice({
256
258
 
257
259
  export const { started, failed, reset } = ${r}Slice.actions;
258
260
  export const ${r}Reducer = ${r}Slice.reducer;
259
- `};var Nt=e=>{let{componentName:t,withStore:r}=e;return r?`export type ${t}Status = 'idle' | 'loading' | 'error';
261
+ `};var Lt=e=>{let{componentName:t,withStore:r}=e;return r?`export type ${t}Status = 'idle' | 'loading' | 'error';
260
262
 
261
263
  export interface ${t}State {
262
264
  status: ${t}Status;
@@ -266,7 +268,7 @@ export interface ${t}State {
266
268
  /** Extra classes for the root element. Add this feature's own props here. */
267
269
  className?: string;
268
270
  }
269
- `};var so=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
271
+ `};var go=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
270
272
 
271
273
  import type { ${t}State } from '${n}';
272
274
 
@@ -293,7 +295,7 @@ export const create${t}Slice: StateCreator<any, [], [], ${t}Slice> = (set) => ({
293
295
  ${r}Failed: (error: string) => set({ ${r}: { status: 'error', error } }),
294
296
  ${r}Reset: () => set({ ${r}: initial }),
295
297
  });
296
- `};var it=async e=>{let{name:t,outputPath:r,persist:n,state:o="redux",typesImportPath:s=`./${t}.types`}=e;await ka(r,{recursive:!0});let i=$(t),a=G(t),c=[];s===`./${t}.types`&&c.push(Se(Ee.join(r,`${t}.types.ts`),Nt({componentName:i,withStore:!0}))),o==="zustand"?c.push(Se(Ee.join(r,`${t}.store.ts`),so({componentName:i,camelName:a,typesImportPath:s})),Se(Ee.join(r,"index.ts"),hr({sliceName:t,withPersist:!1,state:o}))):(c.push(Se(Ee.join(r,`${t}.slice.ts`),oo({componentName:i,camelName:a,typesImportPath:s})),Se(Ee.join(r,`${t}.selectors.ts`),no({componentName:i,camelName:a,sliceName:t})),Se(Ee.join(r,"index.ts"),hr({sliceName:t,withPersist:n,state:o}))),n&&c.push(Se(Ee.join(r,"persist.ts"),ro({componentName:i,camelName:a,typesImportPath:s})))),await Promise.all(c)};var io=e=>{let{componentName:t,hookName:r,withApi:n,pascalName:o,hasI18n:s}=e,i=s?`import { useTranslations } from 'next-intl';
298
+ `};var ft=async e=>{let{name:t,outputPath:r,persist:n,state:o="redux",typesImportPath:s=`./${t}.types`}=e;await Da(r,{recursive:!0});let i=$(t),a=V(t),c=[];s===`./${t}.types`&&c.push(Ae(Ie.join(r,`${t}.types.ts`),Lt({componentName:i,withStore:!0}))),o==="zustand"?c.push(Ae(Ie.join(r,`${t}.store.ts`),go({componentName:i,camelName:a,typesImportPath:s})),Ae(Ie.join(r,"index.ts"),br({sliceName:t,withPersist:!1,state:o}))):(c.push(Ae(Ie.join(r,`${t}.slice.ts`),fo({componentName:i,camelName:a,typesImportPath:s})),Ae(Ie.join(r,`${t}.selectors.ts`),uo({componentName:i,camelName:a,sliceName:t})),Ae(Ie.join(r,"index.ts"),br({sliceName:t,withPersist:n,state:o}))),n&&c.push(Ae(Ie.join(r,"persist.ts"),mo({componentName:i,camelName:a,typesImportPath:s})))),await Promise.all(c)};var ho=e=>{let{componentName:t,hookName:r,withApi:n,pascalName:o,hasI18n:s}=e,i=s?`import { useTranslations } from 'next-intl';
297
299
 
298
300
  `:"",a=s?` const t = useTranslations('${o}');
299
301
  `:"",c=s?"{t('title')}":t;return n?`'use client';
@@ -301,7 +303,7 @@ export const create${t}Slice: StateCreator<any, [], [], ${t}Slice> = (set) => ({
301
303
  ${i}import { use${o}List } from '../api/queries';
302
304
 
303
305
  /**
304
- * Renders hydrated query data: prefetch \`${Pa(o)}ListQuery()\` in the
306
+ * Renders hydrated query data: prefetch \`${La(o)}ListQuery()\` in the
305
307
  * page and wrap this component in \`<HydrateQueries>\` for a no-spinner first paint.
306
308
  */
307
309
  export function ${t}() {
@@ -332,16 +334,16 @@ ${a} const state = ${r}();
332
334
  </section>
333
335
  );
334
336
  }
335
- `},Pa=e=>e.charAt(0).toLowerCase()+e.slice(1);var ao=e=>{let{hookName:t,componentName:r,featureName:n,state:o}=e;return o==="zustand"?`'use client';
337
+ `},La=e=>e.charAt(0).toLowerCase()+e.slice(1);var yo=e=>{let{hookName:t,componentName:r,featureName:n,state:o}=e;return o==="zustand"?`'use client';
336
338
 
337
339
  import { useAppStore } from '@/store/hooks';
338
340
 
339
341
  export const ${t} = () => {
340
- const status = useAppStore((state) => state.${at(n)}.status);
341
- const error = useAppStore((state) => state.${at(n)}.error);
342
- const start = useAppStore((state) => state.${at(n)}Started);
343
- const fail = useAppStore((state) => state.${at(n)}Failed);
344
- const reset = useAppStore((state) => state.${at(n)}Reset);
342
+ const status = useAppStore((state) => state.${gt(n)}.status);
343
+ const error = useAppStore((state) => state.${gt(n)}.error);
344
+ const start = useAppStore((state) => state.${gt(n)}Started);
345
+ const fail = useAppStore((state) => state.${gt(n)}Failed);
346
+ const reset = useAppStore((state) => state.${gt(n)}Reset);
345
347
 
346
348
  return { status, error, start, fail, reset } as const;
347
349
  };
@@ -365,7 +367,7 @@ export const ${t} = () => {
365
367
  reset: () => dispatch(reset()),
366
368
  } as const;
367
369
  };
368
- `},at=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),Ft=e=>{let{hookName:t}=e;return`'use client';
370
+ `},gt=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),Ut=e=>{let{hookName:t}=e;return`'use client';
369
371
 
370
372
  import { useCallback, useState } from 'react';
371
373
 
@@ -383,7 +385,7 @@ export const ${t} = () => {
383
385
 
384
386
  return { busy, run } as const;
385
387
  };
386
- `};var Mt=e=>{let{componentName:t,sourceImportPath:r,testUtilsImportPath:n,hasState:o,hasI18n:s,withQueryData:i}=e,a=[];if(s&&a.push("messages: {}"),o&&a.push("preloadedState: {}"),i)return`import { describe, expect, it } from 'vitest';
388
+ `};var Bt=e=>{let{componentName:t,sourceImportPath:r,testUtilsImportPath:n,hasState:o,hasI18n:s,withQueryData:i}=e,a=[];if(s&&a.push("messages: {}"),o&&a.push("preloadedState: {}"),i)return`import { describe, expect, it } from 'vitest';
387
389
 
388
390
  import { makeTestQueryClient, renderWithProviders, screen } from '${n}';
389
391
  import { ${i.keys} } from '${i.keysImport}';
@@ -410,7 +412,7 @@ describe('${t}', () => {
410
412
  expect(screen.getByRole('heading')).toBeInTheDocument();
411
413
  });
412
414
  });
413
- `},co=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`// @vitest-environment jsdom
415
+ `},wo=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`// @vitest-environment jsdom
414
416
  import { renderHook } from '@testing-library/react';
415
417
  import { describe, expect, it } from 'vitest';
416
418
 
@@ -435,7 +437,7 @@ describe('${t}', () => {
435
437
  expect(result.current).toBeDefined();
436
438
  });
437
439
  });
438
- `},po=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
440
+ `},xo=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
439
441
 
440
442
  import { failed, reset, ${n}, started } from '${r}';
441
443
 
@@ -457,7 +459,7 @@ describe('${n}', () => {
457
459
  expect(${n}.reducer({ status: 'error', error: 'boom' }, reset())).toEqual(initialState);
458
460
  });
459
461
  });
460
- `};var wr=async e=>{let{name:t,outputPath:r,createStore:n,persistStore:o,createApi:s,state:i,hasI18n:a,hasTests:c}=e,l=$(t),p=s?`${l}List`:l,u=`use${l}`,f=n&&i!=="none";await yr(K.join(r,"components"),{recursive:!0}),await yr(K.join(r,"types"),{recursive:!0}),s||await yr(K.join(r,"hooks"),{recursive:!0});let d=[Ue(K.join(r,"components",`${p}.tsx`),io({componentName:p,hookName:u,withApi:s,pascalName:l,hasI18n:a})),Ue(K.join(r,"types",`${t}.types.ts`),Nt({componentName:l,withStore:f})),Ue(K.join(r,"index.ts"),eo({featureName:t,componentName:p,hookName:u,pascalName:l,withStore:f,withApi:s}))];s||d.push(Ue(K.join(r,"hooks",`${u}.ts`),f?ao({hookName:u,componentName:l,featureName:t,state:i==="zustand"?"zustand":"redux"}):Ft({hookName:u}))),s&&(d.push(st({name:t,featurePath:r,withActions:!0})),d.push(Ue(K.join(r,"server.ts"),to({pascalName:l})))),c&&d.push(Ue(K.join(r,"components",`${p}.test.tsx`),Mt({componentName:p,sourceImportPath:`./${p}`,testUtilsImportPath:"../../../../test/test-utils",hasState:i!=="none",hasI18n:a,withQueryData:s?{keysImport:"../api/keys",keys:`${Sa(t)}Keys`,key:"list"}:void 0}))),await Promise.all(d),f&&await it({name:t,outputPath:K.join(r,"store"),persist:o,state:i==="zustand"?"zustand":"redux",typesImportPath:`../types/${t}.types`})},Sa=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());import{mkdir as Ea,writeFile as Ta}from"node:fs/promises";import xr from"node:path";var br=async e=>{let{name:t,projectPath:r,featurePath:n}=e,o=`use${$(t)}`,s=n?xr.join(r,n,"hooks"):xr.join(r,"src","hooks");await Ea(s,{recursive:!0}),await Ta(xr.join(s,`${o}.ts`),Ft({hookName:o}))};import{mkdir as ja}from"node:fs/promises";import _t from"node:path";var lo=({componentName:e})=>`type Props = {
462
+ `};var kr=async e=>{let{name:t,outputPath:r,createStore:n,persistStore:o,createApi:s,state:i,hasI18n:a,hasTests:c}=e,m=$(t),p=s?`${m}List`:m,u=`use${m}`,d=n&&i!=="none";await vr(ee.join(r,"components"),{recursive:!0}),await vr(ee.join(r,"types"),{recursive:!0}),s||await vr(ee.join(r,"hooks"),{recursive:!0});let f=[We(ee.join(r,"components",`${p}.tsx`),ho({componentName:p,hookName:u,withApi:s,pascalName:m,hasI18n:a})),We(ee.join(r,"types",`${t}.types.ts`),Lt({componentName:m,withStore:d})),We(ee.join(r,"index.ts"),po({featureName:t,componentName:p,hookName:u,pascalName:m,withStore:d,withApi:s}))];s||f.push(We(ee.join(r,"hooks",`${u}.ts`),d?yo({hookName:u,componentName:m,featureName:t,state:i==="zustand"?"zustand":"redux"}):Ut({hookName:u}))),s&&(f.push(dt({name:t,featurePath:r,withActions:!0})),f.push(We(ee.join(r,"server.ts"),lo({pascalName:m})))),c&&f.push(We(ee.join(r,"components",`${p}.test.tsx`),Bt({componentName:p,sourceImportPath:`./${p}`,testUtilsImportPath:"../../../../test/test-utils",hasState:i!=="none",hasI18n:a,withQueryData:s?{keysImport:"../api/keys",keys:`${Ua(t)}Keys`,key:"list"}:void 0}))),await Promise.all(f),d&&await ft({name:t,outputPath:ee.join(r,"store"),persist:o,state:i==="zustand"?"zustand":"redux",typesImportPath:`../types/${t}.types`})},Ua=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());import{mkdir as Ba,writeFile as Ga}from"node:fs/promises";import $r from"node:path";var Pr=async e=>{let{name:t,projectPath:r,featurePath:n}=e,o=`use${$(t)}`,s=n?$r.join(r,n,"hooks"):$r.join(r,"src","hooks");await Ba(s,{recursive:!0}),await Ga($r.join(s,`${o}.ts`),Ut({hookName:o}))};import{mkdir as Va}from"node:fs/promises";import Gt from"node:path";var bo=({componentName:e})=>`type Props = {
461
463
  children: React.ReactNode;
462
464
  };
463
465
 
@@ -466,16 +468,16 @@ describe('${n}', () => {
466
468
  export default function ${e}({ children }: Props) {
467
469
  return <>{children}</>;
468
470
  }
469
- `;var Ra=/^[a-z][a-z0-9-]*$/,Ca=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/,Oa=e=>{if(!Ra.test(e))throw new Error(`Invalid layout segment "${e}". Use kebab-case letters, digits, and hyphens. For route groups pass --group instead of wrapping in parens.`)},Aa=e=>{if(!Ca.test(e))throw new Error(`Invalid --at path "${e}". Use kebab-case segments separated by "/", e.g. "dashboard/settings".`)},vr=async e=>{let{segment:t,at:r,projectPath:n,hasI18n:o,withGroup:s}=e;Oa(t),r&&Aa(r);let i=`${$(t)}Layout`,a=s?`(${t})`:t,c=["src","app"];o&&c.push("[locale]"),r&&c.push(...r.split("/")),c.push(a);let l=_t.join(n,...c),p=_t.join(l,"layout.tsx");if(w(p))throw new Error(`Layout already exists at ${_t.relative(n,p)}.`);return await ja(l,{recursive:!0}),await P(p,lo({componentName:i,hasI18n:o})),{layoutFile:p,displayPath:_t.relative(n,p),componentName:i}};import{copyFile as Ia,readFile as Na,writeFile as Fa}from"node:fs/promises";import ct from"node:path";var $r=async e=>{let{code:t,name:r,country:n,flag:o,projectPath:s,copyTranslations:i}=e;await Ma(s,t,i),await _a(s,t),await Da(s,t,r,n,o)},Ma=async(e,t,r)=>{let n=ct.join(e,"src","i18n","translations"),o=ct.join(n,"en.json"),s=ct.join(n,`${t}.json`);if(r)await Ia(o,s);else{let i=await Na(o,"utf-8"),a=JSON.parse(i),c=mo(a);await Fa(s,`${JSON.stringify(c,null,2)}
470
- `)}},mo=e=>{let t={};for(let[r,n]of Object.entries(e))typeof n=="object"&&n!==null?t[r]=mo(n):t[r]="";return t},_a=async(e,t)=>{let r=ct.join(e,"src","types","i18n.ts");if(!w(r))return;let n=await R(r),o=/export const SUPPORTED_LOCALES = \[([^\]]*)\] as const;/,s=n.match(o);if(s){if(s[1].includes(`'${t}'`))return;let c=s[1].split(",").map(l=>l.trim()).filter(Boolean);c.push(`'${t}'`),n=n.replace(o,`export const SUPPORTED_LOCALES = [${c.join(", ")}] as const;`),await P(r,n);return}let i=/export type SupportedLocale = (.*);/,a=n.match(i);a&&!a[1].includes(`'${t}'`)&&(n=n.replace(i,`export type SupportedLocale = ${a[1]} | '${t}';`),await P(r,n))},Da=async(e,t,r,n,o)=>{let s=ct.join(e,"src","lib","config","app-locales.ts");if(!w(s))return;let i=await R(s);if(i.includes(`locale: '${t}'`))return;let a=i.lastIndexOf("];");if(a===-1)return;let c=` {
471
+ `;var Ha=/^[a-z][a-z0-9-]*$/,qa=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/,Ja=e=>{if(!Ha.test(e))throw new Error(`Invalid layout segment "${e}". Use kebab-case letters, digits, and hyphens. For route groups pass --group instead of wrapping in parens.`)},Wa=e=>{if(!qa.test(e))throw new Error(`Invalid --at path "${e}". Use kebab-case segments separated by "/", e.g. "dashboard/settings".`)},Sr=async e=>{let{segment:t,at:r,projectPath:n,hasI18n:o,withGroup:s}=e;Ja(t),r&&Wa(r);let i=`${$(t)}Layout`,a=s?`(${t})`:t,c=["src","app"];o&&c.push("[locale]"),r&&c.push(...r.split("/")),c.push(a);let m=Gt.join(n,...c),p=Gt.join(m,"layout.tsx");if(w(p))throw new Error(`Layout already exists at ${Gt.relative(n,p)}.`);return await Va(m,{recursive:!0}),await R(p,bo({componentName:i,hasI18n:o})),{layoutFile:p,displayPath:Gt.relative(n,p),componentName:i}};import{copyFile as za,readFile as Ka,writeFile as Xa}from"node:fs/promises";import ht from"node:path";var Er=async e=>{let{code:t,name:r,country:n,flag:o,projectPath:s,copyTranslations:i}=e;await Ya(s,t,i),await Qa(s,t),await Za(s,t,r,n,o)},Ya=async(e,t,r)=>{let n=ht.join(e,"src","i18n","translations"),o=ht.join(n,"en.json"),s=ht.join(n,`${t}.json`);if(r)await za(o,s);else{let i=await Ka(o,"utf-8"),a=JSON.parse(i),c=vo(a);await Xa(s,`${JSON.stringify(c,null,2)}
472
+ `)}},vo=e=>{let t={};for(let[r,n]of Object.entries(e))typeof n=="object"&&n!==null?t[r]=vo(n):t[r]="";return t},Qa=async(e,t)=>{let r=ht.join(e,"src","types","i18n.ts");if(!w(r))return;let n=await O(r),o=/export const SUPPORTED_LOCALES = \[([^\]]*)\] as const;/,s=n.match(o);if(s){if(s[1].includes(`'${t}'`))return;let c=s[1].split(",").map(m=>m.trim()).filter(Boolean);c.push(`'${t}'`),n=n.replace(o,`export const SUPPORTED_LOCALES = [${c.join(", ")}] as const;`),await R(r,n);return}let i=/export type SupportedLocale = (.*);/,a=n.match(i);a&&!a[1].includes(`'${t}'`)&&(n=n.replace(i,`export type SupportedLocale = ${a[1]} | '${t}';`),await R(r,n))},Za=async(e,t,r,n,o)=>{let s=ht.join(e,"src","lib","config","app-locales.ts");if(!w(s))return;let i=await O(s);if(i.includes(`locale: '${t}'`))return;let a=i.lastIndexOf("];");if(a===-1)return;let c=` {
471
473
  name: '${r}',
472
474
  locale: '${t}',
473
475
  flag: '${o}',
474
476
  country: '${n}',
475
477
  ogLocale: '${t}_${t.toUpperCase()}',
476
478
  },
477
- `;i=i.slice(0,a)+c+i.slice(a),await P(s,i)};import{mkdir as Ua,writeFile as Pr}from"node:fs/promises";import Dt from"node:path";var La=({routePath:e,hasI18n:t,paramName:r})=>`${t?"/[locale]":""}${e}${r?`/[${r}]`:""}`,kr=e=>e.replace(/[[\]]/g,"").split(/[-_\s]+/).filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(""),uo=(e,t,r)=>`
478
- async function ${e}${kr(t)}({
479
+ `;i=i.slice(0,a)+c+i.slice(a),await R(s,i)};import{mkdir as tc,writeFile as Rr}from"node:fs/promises";import Vt from"node:path";var ec=({routePath:e,hasI18n:t,paramName:r})=>`${t?"/[locale]":""}${e}${r?`/[${r}]`:""}`,Tr=e=>e.replace(/[[\]]/g,"").split(/[-_\s]+/).filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(""),ko=(e,t,r)=>`
480
+ async function ${e}${Tr(t)}({
479
481
  params,
480
482
  }: {
481
483
  params: PageProps<'${r}'>['params'];
@@ -484,7 +486,7 @@ async function ${e}${kr(t)}({
484
486
 
485
487
  return <p className="text-sm">${t}: {${t}}</p>;
486
488
  }
487
- `,fo=e=>{let{componentName:t,routePath:r,hasI18n:n,paramName:o}=e,s=La(e);return n?`import type { Metadata } from 'next';
489
+ `,$o=e=>{let{componentName:t,routePath:r,hasI18n:n,paramName:o}=e,s=ec(e);return n?`import type { Metadata } from 'next';
488
490
  import { getLocale, getTranslations } from 'next-intl/server';${o?`
489
491
  import { Suspense } from 'react';`:""}
490
492
 
@@ -508,12 +510,12 @@ export default async function ${t}Page(${o?`{ params }: PageProps<'${s}'>`:""})
508
510
  <h1 className="font-bold text-2xl">{t('title')}</h1>
509
511
  <p className="text-gray-500 dark:text-gray-400">{t('description')}</p>${o?`
510
512
  <Suspense fallback={<p className="text-sm">\u2026</p>}>
511
- <${t}${kr(o)} params={params} />
513
+ <${t}${Tr(o)} params={params} />
512
514
  </Suspense>`:""}
513
515
  </div>
514
516
  );
515
517
  }
516
- ${o?uo(t,o,s):""}`:`import type { Metadata } from 'next';${o?`
518
+ ${o?ko(t,o,s):""}`:`import type { Metadata } from 'next';${o?`
517
519
  import { Suspense } from 'react';`:""}
518
520
 
519
521
  import { generateSEOMetadata } from '@/lib/config/seo';
@@ -529,19 +531,19 @@ export default function ${t}Page(${o?`{ params }: PageProps<'${s}'>`:""}) {
529
531
  <div className="flex flex-col gap-2 p-6">
530
532
  <h1 className="font-bold text-2xl">${t}</h1>${o?`
531
533
  <Suspense fallback={<p className="text-sm">\u2026</p>}>
532
- <${t}${kr(o)} params={params} />
534
+ <${t}${Tr(o)} params={params} />
533
535
  </Suspense>`:""}
534
536
  </div>
535
537
  );
536
538
  }
537
- ${o?uo(t,o,s):""}`},go=e=>`export default function ${e.componentName}Loading() {
539
+ ${o?ko(t,o,s):""}`},Po=e=>`export default function ${e.componentName}Loading() {
538
540
  return (
539
541
  <div className="flex h-full items-center justify-center p-6">
540
542
  <p className="text-gray-500 text-sm dark:text-gray-400">Loading\u2026</p>
541
543
  </div>
542
544
  );
543
545
  }
544
- `,ho=e=>`'use client';
546
+ `,So=e=>`'use client';
545
547
 
546
548
  import { useEffect } from 'react';
547
549
 
@@ -571,7 +573,7 @@ export default function ${e.componentName}Error({
571
573
  </div>
572
574
  );
573
575
  }
574
- `;var Sr=async e=>{let{name:t,projectPath:r,hasI18n:n,group:o,dynamic:s,withLoading:i=!1,withError:a=!1}=e,c=$(t),l=`/${t}`,p=[r,"src","app"];n&&p.push("[locale]"),o&&p.push(`(${o})`),p.push(t),s&&p.push(`[${s}]`);let u=Dt.join(...p);return await Ua(u,{recursive:!0}),await Pr(Dt.join(u,"page.tsx"),fo({componentName:c,routePath:l,hasI18n:n,paramName:s})),i&&await Pr(Dt.join(u,"loading.tsx"),go({componentName:c})),a&&await Pr(Dt.join(u,"error.tsx"),ho({componentName:c})),{pageDir:u,routePath:s?`${l}/[${s}]`:l}};import{mkdir as Ga}from"node:fs/promises";import Er from"node:path";var yo=(e,t)=>e.endsWith(t)?e:`${e}${t}`,wo=({baseName:e})=>{let t=yo(e,"Provider"),r=t.replace(/Provider$/,""),n=`${r}ContextValue`,o=`${r}Context`,s=`use${r}`;return`'use client';
576
+ `;var jr=async e=>{let{name:t,projectPath:r,hasI18n:n,group:o,dynamic:s,withLoading:i=!1,withError:a=!1}=e,c=$(t),m=`/${t}`,p=[r,"src","app"];n&&p.push("[locale]"),o&&p.push(`(${o})`),p.push(t),s&&p.push(`[${s}]`);let u=Vt.join(...p);return await tc(u,{recursive:!0}),await Rr(Vt.join(u,"page.tsx"),$o({componentName:c,routePath:m,hasI18n:n,paramName:s})),i&&await Rr(Vt.join(u,"loading.tsx"),Po({componentName:c})),a&&await Rr(Vt.join(u,"error.tsx"),So({componentName:c})),{pageDir:u,routePath:s?`${m}/[${s}]`:m}};import{mkdir as rc}from"node:fs/promises";import Cr from"node:path";var Eo=(e,t)=>e.endsWith(t)?e:`${e}${t}`,To=({baseName:e})=>{let t=Eo(e,"Provider"),r=t.replace(/Provider$/,""),n=`${r}ContextValue`,o=`${r}Context`,s=`use${r}`;return`'use client';
575
577
  import { createContext, useContext, useMemo } from 'react';
576
578
 
577
579
  type ${n} = {
@@ -593,139 +595,139 @@ export const ${t} = ({ children }: { children: React.ReactNode }) => {
593
595
  const value = useMemo<${n}>(() => ({ ready: true }), []);
594
596
  return <${o}.Provider value={value}>{children}</${o}.Provider>;
595
597
  };
596
- `},xo=e=>yo(e,"Provider");var Ba=/^[A-Za-z][A-Za-z0-9-]*$/,Va=e=>e.includes("-")?$(e):e.charAt(0).toUpperCase()+e.slice(1),Tr=async e=>{let{name:t,projectPath:r}=e;if(!Ba.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=Va(t).replace(/Provider$/,""),o=xo(n),s=o,i=Er.join(r,C.PROVIDERS),a=Er.join(i,`${s}.tsx`);if(w(a))throw new Error(`Provider already exists at ${Er.relative(r,a)}.`);return await Ga(i,{recursive:!0}),await P(a,wo({baseName:n})),{componentName:o,fileBaseName:s,providerFile:a}};import pt from"node:path";var oe=async e=>{let{projectPath:t,sourceFile:r,kind:n,symbolName:o}=e,s=pt.dirname(r),i=pt.basename(r).replace(/\.(tsx?|jsx?)$/i,""),a=n==="component"?".tsx":".ts",c=pt.join(s,`${i}.test${a}`),l=`./${i}`,p=Ha(s,pt.join(t,"test","test-utils")),u;return n==="component"?u=Mt({componentName:o,sourceImportPath:l,testUtilsImportPath:p,hasState:!!e.hasState,hasI18n:!!e.hasI18n}):n==="hook"?u=co({hookName:o,sourceImportPath:l,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?p:void 0}):u=po({camelName:o,sourceImportPath:l}),await P(c,u),c},Ha=(e,t)=>{let r=pt.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import{readFile as qa,writeFile as Ja}from"node:fs/promises";import za from"node:path";var Ge=(e,t)=>{let r=/import\s+.*\s+from\s+['"].*['"];?\n/g,n=e.match(r);if(n&&n.length>0){let o=n[n.length-1],s=e.lastIndexOf(o);return e.slice(0,s+o.length)+t+`
598
+ `},Ro=e=>Eo(e,"Provider");var nc=/^[A-Za-z][A-Za-z0-9-]*$/,oc=e=>e.includes("-")?$(e):e.charAt(0).toUpperCase()+e.slice(1),Or=async e=>{let{name:t,projectPath:r}=e;if(!nc.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=oc(t).replace(/Provider$/,""),o=Ro(n),s=o,i=Cr.join(r,A.PROVIDERS),a=Cr.join(i,`${s}.tsx`);if(w(a))throw new Error(`Provider already exists at ${Cr.relative(r,a)}.`);return await rc(i,{recursive:!0}),await R(a,To({baseName:n})),{componentName:o,fileBaseName:s,providerFile:a}};import yt from"node:path";var me=async e=>{let{projectPath:t,sourceFile:r,kind:n,symbolName:o}=e,s=yt.dirname(r),i=yt.basename(r).replace(/\.(tsx?|jsx?)$/i,""),a=n==="component"?".tsx":".ts",c=yt.join(s,`${i}.test${a}`),m=`./${i}`,p=sc(s,yt.join(t,"test","test-utils")),u;return n==="component"?u=Bt({componentName:o,sourceImportPath:m,testUtilsImportPath:p,hasState:!!e.hasState,hasI18n:!!e.hasI18n}):n==="hook"?u=wo({hookName:o,sourceImportPath:m,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?p:void 0}):u=xo({camelName:o,sourceImportPath:m}),await R(c,u),c},sc=(e,t)=>{let r=yt.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import{readFile as ic,writeFile as ac}from"node:fs/promises";import cc from"node:path";var ze=(e,t)=>{let r=/import\s+.*\s+from\s+['"].*['"];?\n/g,n=e.match(r);if(n&&n.length>0){let o=n[n.length-1],s=e.lastIndexOf(o);return e.slice(0,s+o.length)+t+`
597
599
  `+e.slice(s+o.length)}return`${t}
598
- ${e}`},jr=(e,t)=>{let r=/combineSlices\(([\s\S]*?)\)/,n=e.match(r);if(!n)throw new Error("Could not find combineSlices in rootReducer.ts");let o=n[1].split(",").map(c=>c.trim()).filter(Boolean);if(o.includes(t))return e;let s=o.indexOf("persistSlice");s===-1?o.push(t):o.splice(s,0,t);let i=`combineSlices(${o.join(", ")})`,a=`combineSlices(
600
+ ${e}`},Ar=(e,t)=>{let r=/combineSlices\(([\s\S]*?)\)/,n=e.match(r);if(!n)throw new Error("Could not find combineSlices in rootReducer.ts");let o=n[1].split(",").map(c=>c.trim()).filter(Boolean);if(o.includes(t))return e;let s=o.indexOf("persistSlice");s===-1?o.push(t):o.splice(s,0,t);let i=`combineSlices(${o.join(", ")})`,a=`combineSlices(
599
601
  ${o.join(`,
600
602
  `)},
601
- )`;return e.replace(r,i.length<=100?i:a)},Rr=(e,t)=>{let r=/entries:\s*\[([\s\S]*?)\]/,n=e.match(r);if(!n)throw new Error("Could not find `entries: [...]` in src/store/index.ts");let o=n[1].split(",").map(s=>s.trim()).filter(Boolean);return o.includes(t)?e:(o.push(t),e.replace(r,`entries: [${o.join(", ")}]`))},Cr=(e,t)=>{let r=e.lastIndexOf("} as const;");if(r===-1)throw new Error("Could not find closing brace of AppApis object");let n=e.substring(0,r),o=e.substring(r);return`${n.trimEnd()}
603
+ )`;return e.replace(r,i.length<=100?i:a)},Ir=(e,t)=>{let r=/entries:\s*\[([\s\S]*?)\]/,n=e.match(r);if(!n)throw new Error("Could not find `entries: [...]` in src/store/index.ts");let o=n[1].split(",").map(s=>s.trim()).filter(Boolean);return o.includes(t)?e:(o.push(t),e.replace(r,`entries: [${o.join(", ")}]`))},Nr=(e,t)=>{let r=e.lastIndexOf("} as const;");if(r===-1)throw new Error("Could not find closing brace of AppApis object");let n=e.substring(0,r),o=e.substring(r);return`${n.trimEnd()}
602
604
  ${t}
603
- ${o}`};var lt=async e=>{let{serviceName:t,projectPath:r}=e,n=G(t),o=za.join(r,"src","lib","config","app-apis.ts");try{let s=await qa(o,"utf-8");if(s.includes(`${n}:`))return;if(!s.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");s=Cr(s,Yn({kebabName:t,camelName:n,pascalName:$(t)})),await Ja(o,s)}catch(s){throw new Error(`Failed to register API endpoints: ${s}`,{cause:s})}};import{readFile as Wa,writeFile as Ka}from"node:fs/promises";import Xa from"node:path";var Or=async(e,t,r)=>{let n=Xa.join(e,"src","lib","config","app-paths.ts");if(!w(n))return;let o=await Wa(n,"utf-8"),s=G(t);if(o.includes(`${s}:`))return;let i=o.lastIndexOf("} as const;");if(i===-1)return;let a=` ${s}: '${r}',
604
- `;o=o.slice(0,i)+a+o.slice(i),await Ka(n,o)};import Ar from"node:path";var Ya=/^[A-Z][A-Z0-9_]*$/,$o=e=>{if(!Ya.test(e))throw new Error(`Invalid env var name "${e}". Use UPPER_SNAKE_CASE (e.g. SENTRY_DSN, NEXT_PUBLIC_API_URL).`)},se=(e,t)=>t?e.startsWith("NEXT_PUBLIC_")?e:`NEXT_PUBLIC_${e}`:e,Ir=e=>e.public?"client":"server",Qa=e=>{if(e.default===void 0)return"";switch(e.type){case"number":return`.default(${Number(e.default)})`;case"boolean":return`.default(${e.default==="true"})`;default:return`.default('${e.default.replace(/'/g,"\\'")}')`}},Za=e=>{switch(e.type){case"url":return"e.url()";case"number":return"e.number()";case"boolean":return"e.boolean()";case"enum":{let t=e.enumValues??[];if(t.length===0)throw new Error(`Enum env var "${e.name}" requires --enum values.`);return`e.enum([${t.map(n=>`'${n.replace(/'/g,"\\'")}'`).join(", ")}])`}default:return"e.string()"}},ko=e=>{let t=se(e.name,e.public),r=Za(e),n=e.default!==void 0,o=!e.required&&!n;if(n&&(r+=Qa(e)),o&&(r+=".optional()"),e.description){let s=e.description.replace(/'/g,"\\'");r+=`
605
- .describe('${s}')`}return` ${t}: ${r},`},Po=e=>{let t=se(e.name,e.public);return` ${t}: process.env.${t},`},ec=e=>new RegExp(`(${e}:\\s*\\{)([\\s\\S]*?)(\\n\\s*\\})`),bo=/(runtimeEnv:\s*\{)([\s\S]*?)(\n\s*\})/,vo=(e,t,r,n)=>{let o=t.replace(/\s+$/,""),s=o.length===0||/,\s*$/.test(o)?o:`${o},`;return`${e}${s}
605
+ ${o}`};var wt=async e=>{let{serviceName:t,projectPath:r}=e,n=V(t),o=cc.join(r,"src","lib","config","app-apis.ts");try{let s=await ic(o,"utf-8");if(s.includes(`${n}:`))return;if(!s.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");s=Nr(s,io({kebabName:t,camelName:n,pascalName:$(t)})),await ac(o,s)}catch(s){throw new Error(`Failed to register API endpoints: ${s}`,{cause:s})}};import{readFile as pc,writeFile as lc}from"node:fs/promises";import mc from"node:path";var Fr=async(e,t,r)=>{let n=mc.join(e,"src","lib","config","app-paths.ts");if(!w(n))return;let o=await pc(n,"utf-8"),s=V(t);if(o.includes(`${s}:`))return;let i=o.lastIndexOf("} as const;");if(i===-1)return;let a=` ${s}: '${r}',
606
+ `;o=o.slice(0,i)+a+o.slice(i),await lc(n,o)};import Mr from"node:path";var uc=/^[A-Z][A-Z0-9_]*$/,Oo=e=>{if(!uc.test(e))throw new Error(`Invalid env var name "${e}". Use UPPER_SNAKE_CASE (e.g. SENTRY_DSN, NEXT_PUBLIC_API_URL).`)},ue=(e,t)=>t?e.startsWith("NEXT_PUBLIC_")?e:`NEXT_PUBLIC_${e}`:e,_r=e=>e.public?"client":"server",dc=e=>{if(e.default===void 0)return"";switch(e.type){case"number":return`.default(${Number(e.default)})`;case"boolean":return`.default(${e.default==="true"})`;default:return`.default('${e.default.replace(/'/g,"\\'")}')`}},fc=e=>{switch(e.type){case"url":return"e.url()";case"number":return"e.number()";case"boolean":return"e.boolean()";case"enum":{let t=e.enumValues??[];if(t.length===0)throw new Error(`Enum env var "${e.name}" requires --enum values.`);return`e.enum([${t.map(n=>`'${n.replace(/'/g,"\\'")}'`).join(", ")}])`}default:return"e.string()"}},Ao=e=>{let t=ue(e.name,e.public),r=fc(e),n=e.default!==void 0,o=!e.required&&!n;if(n&&(r+=dc(e)),o&&(r+=".optional()"),e.description){let s=e.description.replace(/'/g,"\\'");r+=`
607
+ .describe('${s}')`}return` ${t}: ${r},`},Io=e=>{let t=ue(e.name,e.public);return` ${t}: process.env.${t},`},gc=e=>new RegExp(`(${e}:\\s*\\{)([\\s\\S]*?)(\\n\\s*\\})`),jo=/(runtimeEnv:\s*\{)([\s\S]*?)(\n\s*\})/,Co=(e,t,r,n)=>{let o=t.replace(/\s+$/,""),s=o.length===0||/,\s*$/.test(o)?o:`${o},`;return`${e}${s}
606
608
  ${n}
607
- ${r.replace(/^\n/,"")}`},So=(e,t)=>{let r=se(t.name,t.public),n=Ir(t);if(new RegExp(`\\b${r}\\s*:`).test(e))return e;if(!/defineEnv\(\{/.test(e))throw new Error("Could not locate `defineEnv({ \u2026 })` in src/lib/env/index.ts. Is this a @teispace/env project?");let s=ec(n),i=e.match(s);if(!i)throw new Error(`Could not locate the \`${n}: { \u2026 }\` group in src/lib/env/index.ts.`);let[,a,c,l]=i,p=ko(t),u=e.replace(s,vo(a,c,l,p)),f=u.match(bo);if(!f)throw new Error("Could not locate the `runtimeEnv: { \u2026 }` map in src/lib/env/index.ts.");let[,d,g,y]=f;return u=u.replace(bo,vo(d,g,y,Po(t))),u},tc="# -public",rc=e=>{let t=se(e.name,e.public),r=e.default??"",n=e.public?` ${tc}`:"";return`${t}=${r}${n}`},Eo=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
609
+ ${r.replace(/^\n/,"")}`},No=(e,t)=>{let r=ue(t.name,t.public),n=_r(t);if(new RegExp(`\\b${r}\\s*:`).test(e))return e;if(!/defineEnv\(\{/.test(e))throw new Error("Could not locate `defineEnv({ \u2026 })` in src/lib/env/index.ts. Is this a @teispace/env project?");let s=gc(n),i=e.match(s);if(!i)throw new Error(`Could not locate the \`${n}: { \u2026 }\` group in src/lib/env/index.ts.`);let[,a,c,m]=i,p=Ao(t),u=e.replace(s,Co(a,c,m,p)),d=u.match(jo);if(!d)throw new Error("Could not locate the `runtimeEnv: { \u2026 }` map in src/lib/env/index.ts.");let[,f,h,y]=d;return u=u.replace(jo,Co(f,h,y,Io(t))),u},hc="# -public",yc=e=>{let t=ue(e.name,e.public),r=e.default??"",n=e.public?` ${hc}`:"";return`${t}=${r}${n}`},Fo=(e,t)=>{let r=ue(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
608
610
  `)?"":`
609
611
  `,s=e===""?"":`
610
612
  `,i=t.description?`# ${t.description}
611
- `:"";return`${e}${o}${s}${i}${rc(t)}
612
- `},To=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
613
+ `:"";return`${e}${o}${s}${i}${yc(t)}
614
+ `},Mo=(e,t)=>{let r=ue(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
613
615
  `)?"":`
614
616
  `,s=t.default??"";return`${e}${o}${r}=${s}
615
- `},Nr=async(e,t)=>{$o(t.name);let r=Ar.join(e,"src/lib/env/index.ts");if(!w(r))throw new Error("src/lib/env/index.ts not found \u2014 run `next-maker init` first.");let n=await R(r),o=So(n,t),s=o!==n;s&&await P(r,o);let i=Ar.join(e,C.ENV_EXAMPLE),a=!1;if(w(i)){let p=await R(i),u=Eo(p,t);a=u!==p,a&&await P(i,u)}let c=Ar.join(e,".env"),l=!1;if(w(c)){let p=await R(c),u=To(p,t);l=u!==p,l&&await P(c,u)}return{schemaUpdated:s,envExampleUpdated:a,envUpdated:l,group:Ir(t)}};import Lt from"node:path";var nc=e=>new RegExp(`<\\s*${e}\\b`),jo=(e,t)=>{if(nc(t).test(e))return e;let r=/^(?<indent>[ \t]*)\{children\}\s*$/m,n=e.match(r);if(!n||n.index===void 0)throw new Error("Could not locate `{children}` line in RootProvider \u2014 expected a line containing only `{children}`.");let o=n.groups?.indent??"",s=`${o} `,i=`${o}<${t}>
617
+ `},Dr=async(e,t)=>{Oo(t.name);let r=Mr.join(e,"src/lib/env/index.ts");if(!w(r))throw new Error("src/lib/env/index.ts not found \u2014 run `next-maker init` first.");let n=await O(r),o=No(n,t),s=o!==n;s&&await R(r,o);let i=Mr.join(e,A.ENV_EXAMPLE),a=!1;if(w(i)){let p=await O(i),u=Fo(p,t);a=u!==p,a&&await R(i,u)}let c=Mr.join(e,".env"),m=!1;if(w(c)){let p=await O(c),u=Mo(p,t);m=u!==p,m&&await R(c,u)}return{schemaUpdated:s,envExampleUpdated:a,envUpdated:m,group:_r(t)}};import Ht from"node:path";var wc=e=>new RegExp(`<\\s*${e}\\b`),_o=(e,t)=>{if(wc(t).test(e))return e;let r=/^(?<indent>[ \t]*)\{children\}\s*$/m,n=e.match(r);if(!n||n.index===void 0)throw new Error("Could not locate `{children}` line in RootProvider \u2014 expected a line containing only `{children}`.");let o=n.groups?.indent??"",s=`${o} `,i=`${o}<${t}>
616
618
  ${s}{children}
617
- ${o}</${t}>`;return e.replace(r,i)},Ro=(e,t)=>{let r=`export * from './${t}';`;if(e.includes(r))return e;let n=e.split(`
619
+ ${o}</${t}>`;return e.replace(r,i)},Do=(e,t)=>{let r=`export * from './${t}';`;if(e.includes(r))return e;let n=e.split(`
618
620
  `),o=[],s=[];for(let u of n)/^export \* from '\.\/.*';\s*$/.test(u)?o.push(u):s.push(u);let i=[...o,r].sort(),a=n.findIndex(u=>/^export \* from '\.\//.test(u));if(a===-1)return`${r}
619
- ${e.replace(/^\n+/,"")}`;let c=n.slice(0,a),l=n.findIndex((u,f)=>f>a&&!/^export \* from '\.\//.test(u)),p=l===-1?[]:n.slice(l);return[...c,...i,...p].join(`
620
- `)},oc=C.PROVIDERS,sc=C.ROOT_PROVIDER,ic=C.PROVIDERS_INDEX,Co=async(e,t={fileExists:w,readFile:R})=>{let r=Lt.join(e,sc);if(t.fileExists(r))return r;let n=Lt.join(e,oc);if(!t.fileExists(n))return null;let{readdir:o}=await import("node:fs/promises"),i=(await o(n).catch(()=>[])).filter(c=>c.endsWith(".tsx")),a=null;for(let c of i){let l=Lt.join(n,c),p=await t.readFile(l);if(!/\{children\}/.test(p))continue;let f=((p.split("{children}")[0]??"").match(/<[A-Z][A-Za-z0-9_]*\b/g)??[]).length;(!a||f>a.depth)&&(a={file:l,depth:f})}return a?.file??null},Fr=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await Co(t);if(o){let a=await R(o),c=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(c=Ge(c,`import { ${r} } from './${n}';`)),c=jo(c,r),c!==a&&await P(o,c)}let s=Lt.join(t,ic),i=null;if(w(s)){let a=await R(s),c=Ro(a,n);c!==a&&await P(s,c),i=s}return{rootProviderFile:o,barrelFile:i}};import{readFile as Oo,writeFile as Ao}from"node:fs/promises";import Io from"node:path";var mt=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,s=Io.join(t,"src","store","rootReducer.ts"),i=Io.join(t,"src","store","index.ts"),a=G(r),c=o.replace(/^src\//,"@/");try{let l=await Oo(s,"utf-8");if(l=Ge(l,`import { ${a}Slice } from '${c}';`),l=jr(l,`${a}Slice`),await Ao(s,l),n&&w(i)){let p=await Oo(i,"utf-8");p=Ge(p,`import { ${a}Persistence } from '${c}';`),p=Rr(p,`${a}Persistence`),await Ao(i,p)}}catch(l){throw new Error(`Failed to register slice '${r}': ${l}`,{cause:l})}};import{readFile as ac,writeFile as cc}from"node:fs/promises";import pc from"node:path";var Te=async(e,t)=>{let r=pc.join(e,"src","i18n","translations","en.json");if(!w(r))return;let n=await ac(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await cc(r,`${JSON.stringify(o,null,2)}
621
- `))};import lc from"enquirer";var{prompt:mc}=lc,No=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await mc(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Fo=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--no-client","Keep the component a Server Component").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(X.cyan(`
621
+ ${e.replace(/^\n+/,"")}`;let c=n.slice(0,a),m=n.findIndex((u,d)=>d>a&&!/^export \* from '\.\//.test(u)),p=m===-1?[]:n.slice(m);return[...c,...i,...p].join(`
622
+ `)},xc=A.PROVIDERS,bc=A.ROOT_PROVIDER,vc=A.PROVIDERS_INDEX,Lo=async(e,t={fileExists:w,readFile:O})=>{let r=Ht.join(e,bc);if(t.fileExists(r))return r;let n=Ht.join(e,xc);if(!t.fileExists(n))return null;let{readdir:o}=await import("node:fs/promises"),i=(await o(n).catch(()=>[])).filter(c=>c.endsWith(".tsx")),a=null;for(let c of i){let m=Ht.join(n,c),p=await t.readFile(m);if(!/\{children\}/.test(p))continue;let d=((p.split("{children}")[0]??"").match(/<[A-Z][A-Za-z0-9_]*\b/g)??[]).length;(!a||d>a.depth)&&(a={file:m,depth:d})}return a?.file??null},Lr=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await Lo(t);if(o){let a=await O(o),c=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(c=ze(c,`import { ${r} } from './${n}';`)),c=_o(c,r),c!==a&&await R(o,c)}let s=Ht.join(t,vc),i=null;if(w(s)){let a=await O(s),c=Do(a,n);c!==a&&await R(s,c),i=s}return{rootProviderFile:o,barrelFile:i}};import{readFile as Uo,writeFile as Bo}from"node:fs/promises";import Go from"node:path";var xt=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,s=Go.join(t,"src","store","rootReducer.ts"),i=Go.join(t,"src","store","index.ts"),a=V(r),c=o.replace(/^src\//,"@/");try{let m=await Uo(s,"utf-8");if(m=ze(m,`import { ${a}Slice } from '${c}';`),m=Ar(m,`${a}Slice`),await Bo(s,m),n&&w(i)){let p=await Uo(i,"utf-8");p=ze(p,`import { ${a}Persistence } from '${c}';`),p=Ir(p,`${a}Persistence`),await Bo(i,p)}}catch(m){throw new Error(`Failed to register slice '${r}': ${m}`,{cause:m})}};import{readFile as kc,writeFile as $c}from"node:fs/promises";import Pc from"node:path";var Ne=async(e,t)=>{let r=Pc.join(e,"src","i18n","translations","en.json");if(!w(r))return;let n=await kc(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await $c(r,`${JSON.stringify(o,null,2)}
623
+ `))};import Sc from"enquirer";var{prompt:Ec}=Sc,Vo=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await Ec(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Ho=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--no-client","Keep the component a Server Component").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(te.cyan(`
622
624
  \u{1F9E9} Component Generator
623
- `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=await No(t,{client:r.client});M(i.componentName,"component name"),r.feature&&W(r.feature,"feature path");let a=$(i.componentName),c=i.isClient,l=r.i18n??!1,p=uc(r,s.hasTests);h.start("Generating component..."),await fr({name:i.componentName,projectPath:n,isClient:c||l,hasI18n:l,featurePath:r.feature}),h.succeed("Component generated"),l&&await Te(n,a);let u=null;if(p){let d=r.feature?Mr.join(n,r.feature,"components",`${a}.tsx`):Mr.join(n,"src/components/common",a,`${a}.tsx`);h.start("Generating test..."),u=await oe({projectPath:n,sourceFile:d,kind:"component",symbolName:a,hasState:s.state!=="none",hasI18n:s.hasI18n}),h.succeed("Test generated")}let f=r.feature?`${r.feature}/components/${a}.tsx`:`src/components/common/${a}/${a}.tsx`;await k(n,o),m(X.green(`
625
+ `)),g.start("Detecting project setup...");let s=await N(n);g.succeed("Project setup detected");let i=await Vo(t,{client:r.client});D(i.componentName,"component name"),r.feature&&Z(r.feature,"feature path");let a=$(i.componentName),c=i.isClient,m=r.i18n??!1,p=Tc(r,s.hasTests);g.start("Generating component..."),await wr({name:i.componentName,projectPath:n,isClient:c||m,hasI18n:m,featurePath:r.feature}),g.succeed("Component generated"),m&&await Ne(n,a);let u=null;if(p){let f=r.feature?Ur.join(n,r.feature,"components",`${a}.tsx`):Ur.join(n,"src/components/common",a,`${a}.tsx`);g.start("Generating test..."),u=await me({projectPath:n,sourceFile:f,kind:"component",symbolName:a,hasState:s.state!=="none",hasI18n:s.hasI18n}),g.succeed("Test generated")}let d=r.feature?`${r.feature}/components/${a}.tsx`:`src/components/common/${a}/${a}.tsx`;await E(n,o),l(te.green(`
624
626
  \u2728 Component '${a}' created successfully!
625
- `)),m(X.dim(` \u{1F4C4} ${f}`)),r.feature||(m(X.dim(` \u{1F4C4} src/components/common/${a}/index.ts`)),m(X.dim(" \u{1F4DD} Updated src/components/common/index.ts")),m(X.dim(" \u{1F4DD} Updated src/components/index.ts"))),u&&m(X.dim(` \u{1F9EA} ${Mr.relative(n,u)}`)),m(""),m(X.cyan("Usage:")),r.feature?m(X.dim(` import { ${a} } from '${r.feature.replace(/^src\//,"@/")}/components/${a}';`)):m(X.dim(` import { ${a} } from '@/components';`)),m("")}catch(n){h.fail("Component generation failed"),b(`${n}`),process.exit(1)}})},uc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import{spawnSync as dc}from"node:child_process";import _ from"picocolors";var fc=e=>{switch(e.kind){case"missingFile":return`missing file: ${e.file}`;case"missingPackage":return`missing ${e.dev?"devDependency":"dependency"}: ${e.name}`;case"missingScript":return`missing script: ${e.name}`}},Mo=e=>{e.command("doctor").description("Diagnose drift between the project and the starter features it was generated with").option("--fix","Restore missing files, packages, and scripts from the starter").option("--compile","Run the project type-check as part of the diagnosis").option("--json","Print machine-readable JSON").option("--starter-path <dir>","Compare against a local starter checkout").action(async t=>{let r=process.cwd(),n;try{let o=await re(r),s=await De(o,{starterPath:t.starterPath});n=s.dispose;let i=await ir(r,o,s),a=0;if(t.fix&&i.some(p=>p.drift.length)){let p=await Mn(r,{...o,answers:{}},s,o.answers),u=new Set(i.flatMap(g=>g.drift.filter(y=>y.kind==="missingFile").map(y=>y.file)));p.copy=p.copy.filter(g=>u.has(g)),p.remove=[],p.unwrapJsx=[],p.unwrapCall=[],p.removePackages=[],p.removeScripts=[],p.manual=[];let f=new Set(i.flatMap(g=>g.drift.filter(y=>y.kind==="missingPackage").map(y=>y.name)));for(let g of Object.keys(p.addPackages))f.has(g)||delete p.addPackages[g];for(let g of Object.keys(p.addDevPackages))f.has(g)||delete p.addDevPackages[g];let d=new Set(i.flatMap(g=>g.drift.filter(y=>y.kind==="missingScript").map(y=>y.name)));for(let g of Object.keys(p.addScripts))d.has(g)||delete p.addScripts[g];await _n(r,s,p,o),a=p.copy.length+Object.keys(p.addPackages).length+Object.keys(p.addDevPackages).length+Object.keys(p.addScripts).length,i=await ir(r,o,s)}let c;if(t.compile){let[p,...u]=ce(o.packageManager,"type-check").split(" "),f=dc(p,u,{cwd:r,encoding:"utf-8"});c={ok:f.status===0,output:`${f.stdout}${f.stderr}`.trim()}}let l=i.filter(p=>p.on&&p.drift.length);t.json&&(m(JSON.stringify({starter:o.starter,results:i,fixed:a,compile:c},null,2)),process.exit(l.length||c?.ok===!1?1:0)),m(_.cyan(`
627
+ `)),l(te.dim(` \u{1F4C4} ${d}`)),r.feature||(l(te.dim(` \u{1F4C4} src/components/common/${a}/index.ts`)),l(te.dim(" \u{1F4DD} Updated src/components/common/index.ts")),l(te.dim(" \u{1F4DD} Updated src/components/index.ts"))),u&&l(te.dim(` \u{1F9EA} ${Ur.relative(n,u)}`)),l(""),l(te.cyan("Usage:")),r.feature?l(te.dim(` import { ${a} } from '${r.feature.replace(/^src\//,"@/")}/components/${a}';`)):l(te.dim(` import { ${a} } from '@/components';`)),l("")}catch(n){g.fail("Component generation failed"),v(`${n}`),process.exit(1)}})},Tc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import{spawnSync as Rc}from"node:child_process";import L from"picocolors";var jc=e=>{switch(e.kind){case"missingFile":return`missing file: ${e.file}`;case"missingPackage":return`missing ${e.dev?"devDependency":"dependency"}: ${e.name}`;case"missingScript":return`missing script: ${e.name}`}},qo=e=>{e.command("doctor").description("Diagnose drift between the project and the starter features it was generated with").option("--fix","Restore missing files, packages, and scripts from the starter").option("--compile","Run the project type-check as part of the diagnosis").option("--json","Print machine-readable JSON").option("--starter-path <dir>","Compare against a local starter checkout").action(async t=>{let r=process.cwd(),n;try{let o=await pe(r),s=await He(o,{starterPath:t.starterPath});n=s.dispose;let i=await mr(r,o,s),a=0;if(t.fix&&i.some(p=>p.drift.length)){let p=await Bn(r,{...o,answers:{}},s,o.answers),u=new Set(i.flatMap(h=>h.drift.filter(y=>y.kind==="missingFile").map(y=>y.file)));p.copy=p.copy.filter(h=>u.has(h)),p.remove=[],p.unwrapJsx=[],p.unwrapCall=[],p.removePackages=[],p.removeScripts=[],p.manual=[];let d=new Set(i.flatMap(h=>h.drift.filter(y=>y.kind==="missingPackage").map(y=>y.name)));for(let h of Object.keys(p.addPackages))d.has(h)||delete p.addPackages[h];for(let h of Object.keys(p.addDevPackages))d.has(h)||delete p.addDevPackages[h];let f=new Set(i.flatMap(h=>h.drift.filter(y=>y.kind==="missingScript").map(y=>y.name)));for(let h of Object.keys(p.addScripts))f.has(h)||delete p.addScripts[h];await Gn(r,s,p,o),a=p.copy.length+Object.keys(p.addPackages).length+Object.keys(p.addDevPackages).length+Object.keys(p.addScripts).length,i=await mr(r,o,s)}let c;if(t.compile){let[p,...u]=fe(o.packageManager,"type-check").split(" "),d=Rc(p,u,{cwd:r,encoding:"utf-8"});c={ok:d.status===0,output:`${d.stdout}${d.stderr}`.trim()}}let m=i.filter(p=>p.on&&p.drift.length);t.json&&(l(JSON.stringify({starter:o.starter,results:i,fixed:a,compile:c},null,2)),process.exit(m.length||c?.ok===!1?1:0)),l(L.cyan(`
626
628
  \u{1FA7A} Project Doctor
627
- `)),m(_.dim(` ${o.starter.name} ${o.starter.version} \xB7 ${s.source.location}
628
- `));for(let p of i){if(!p.on){m(` ${_.dim("\u2014")} ${_.dim(p.id)} ${_.dim("(off)")}`);continue}if(p.drift.length===0){m(` ${_.green("\u2713")} ${p.id}`);continue}m(` ${_.yellow("!")} ${_.bold(p.id)} ${_.dim(`(${p.drift.length} issue${p.drift.length===1?"":"s"})`)}`);for(let u of p.drift)m(` ${_.yellow("\u2022")} ${fc(u)}`)}a&&m(_.green(`
629
- restored ${a} item(s) from the starter`)),c&&(m(""),m(c.ok?_.green(" \u2713 type-check passed"):_.red(" \u2717 type-check failed")),c.ok||m(_.dim(c.output.split(`
629
+ `)),l(L.dim(` ${o.starter.name} ${o.starter.version} \xB7 ${s.source.location}
630
+ `));for(let p of i){if(!p.on){l(` ${L.dim("\u2014")} ${L.dim(p.id)} ${L.dim("(off)")}`);continue}if(p.drift.length===0){l(` ${L.green("\u2713")} ${p.id}`);continue}l(` ${L.yellow("!")} ${L.bold(p.id)} ${L.dim(`(${p.drift.length} issue${p.drift.length===1?"":"s"})`)}`);for(let u of p.drift)l(` ${L.yellow("\u2022")} ${jc(u)}`)}a&&l(L.green(`
631
+ restored ${a} item(s) from the starter`)),c&&(l(""),l(c.ok?L.green(" \u2713 type-check passed"):L.red(" \u2717 type-check failed")),c.ok||l(L.dim(c.output.split(`
630
632
  `).slice(-30).join(`
631
- `)))),m(""),l.length===0&&c?.ok!==!1&&(m(_.green(`\u2713 No drift detected.
632
- `)),process.exit(0)),l.length&&!t.fix&&m(_.dim(`Run with --fix to restore missing pieces from the starter.
633
- `)),process.exit(1)}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{await n?.()}})};import Be from"picocolors";var _o=new Set(["string","url","number","boolean","enum"]),gc=e=>{let t=(e??"string").toLowerCase();if(!_o.has(t))throw new Error(`Invalid --type "${e}". Valid: ${Array.from(_o).join(", ")}.`);return t},hc=e=>{if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean);return t.length===0?void 0:t},Do=e=>{e.command("env <NAME>").description("Declare a new environment variable across src/lib/env/index.ts, .env.example, and .env").option("--type <type>","Coercer type (string|url|number|boolean|enum)","string").option("--required","Make the variable required (no .optional() / .default())").option("--default <value>","Set a default value (mutually exclusive with --required)").option("--public","Mark as public: place in the client group, auto-prefix NEXT_PUBLIC_, tag .env.example").option("--describe <text>","Description (rendered as .describe() and .env.example comment)").option("--enum <list>",'Comma-separated values when --type=enum (e.g. "dev,prod")').action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();if(m(Be.cyan(`
633
+ `)))),l(""),m.length===0&&c?.ok!==!1&&(l(L.green(`\u2713 No drift detected.
634
+ `)),process.exit(0)),m.length&&!t.fix&&l(L.dim(`Run with --fix to restore missing pieces from the starter.
635
+ `)),process.exit(1)}catch(o){v(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{await n?.()}})};import Ke from"picocolors";var Jo=new Set(["string","url","number","boolean","enum"]),Cc=e=>{let t=(e??"string").toLowerCase();if(!Jo.has(t))throw new Error(`Invalid --type "${e}". Valid: ${Array.from(Jo).join(", ")}.`);return t},Oc=e=>{if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean);return t.length===0?void 0:t},Wo=e=>{e.command("env <NAME>").description("Declare a new environment variable across src/lib/env/index.ts, .env.example, and .env").option("--type <type>","Coercer type (string|url|number|boolean|enum)","string").option("--required","Make the variable required (no .optional() / .default())").option("--default <value>","Set a default value (mutually exclusive with --required)").option("--public","Mark as public: place in the client group, auto-prefix NEXT_PUBLIC_, tag .env.example").option("--describe <text>","Description (rendered as .describe() and .env.example comment)").option("--enum <list>",'Comma-separated values when --type=enum (e.g. "dev,prod")').action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();if(l(Ke.cyan(`
634
636
  \u{1F510} Env Var Generator
635
- `)),r.required&&r.default!==void 0)throw new Error("--required and --default are mutually exclusive.");let s=gc(r.type),i=hc(r.enum);if(s==="enum"&&(!i||i.length===0))throw new Error("--type=enum requires at least one value via --enum a,b,c.");let a={name:t,type:s,required:!!r.required,default:r.default,description:r.describe,enumValues:i,public:!!r.public};h.start("Updating src/lib/env/index.ts, .env.example, and .env...");let c=await Nr(n,a);h.succeed("Env var written");let l=se(a.name,a.public);await k(n,o),m(Be.green(`
636
- \u2728 ${l} declared in the ${c.group} group.
637
- `)),m(Be.dim("Touched:")),m(Be.dim(` ${c.schemaUpdated?"\u270F\uFE0F ":"\u23ED "} src/lib/env/index.ts`)),m(Be.dim(` ${c.envExampleUpdated?"\u270F\uFE0F ":"\u23ED "} .env.example`)),m(Be.dim(` ${c.envUpdated?"\u270F\uFE0F ":"\u23ED "} .env`)),m("")}catch(n){h.fail("Env var declaration failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Bt from"node:path";import Re from"picocolors";import yc from"enquirer";var{prompt:wc}=yc,Lo=async(e={})=>e.source?{source:e.source}:{source:(await wc({type:"input",name:"source",message:"Path to source image (PNG/JPG/JPEG/SVG/WebP/AVIF):",validate:r=>r?!0:"Source path is required"})).source};import{access as xc,readFile as bc,stat as vc}from"node:fs/promises";import je from"node:path";var Uo=async e=>{try{return await xc(e),!0}catch{return!1}},$c=async e=>{try{return(await vc(e)).isDirectory()}catch{return!1}},Ut=async e=>{let t=[je.join(e,"src","app"),je.join(e,"app")];for(let r of t)if(await $c(r))return r;return null},kc=["next-pwa","@ducanh2912/next-pwa","@serwist/next","serwist"],_r=async e=>{let t={isPwa:!1},r=[je.join(e,"public","manifest.json"),je.join(e,"public","manifest.webmanifest"),je.join(e,"public","site.webmanifest")];for(let o of r)if(await Uo(o)){t.publicManifestPath=o,t.isPwa=!0;break}let n=await Ut(e);if(n)for(let o of["ts","tsx","js"]){let s=je.join(n,`manifest.${o}`);if(await Uo(s)){t.appManifestPath=s,t.isPwa=!0;break}}try{let o=JSON.parse(await bc(je.join(e,"package.json"),"utf-8")),s={...o.dependencies,...o.devDependencies};for(let i of kc)if(s[i]){t.framework=i,t.isPwa=!0;break}}catch{}return t};import{mkdir as jc,readFile as Xo,stat as Rc,writeFile as Cc}from"node:fs/promises";import Y from"node:path";import Oc from"sharp";import Sc from"png-to-ico";import ut from"sharp";var Go=e=>e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),Dr=(e,t,r)=>{switch(e){case"square":return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" fill="white"/></svg>`;case"circle":{let n=t/2;return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><circle cx="${n}" cy="${n}" r="${n}" fill="white"/></svg>`}case"rounded":{let n=Math.round(t*r/100);return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" rx="${n}" ry="${n}" fill="white"/></svg>`}case"squircle":return Pc(t)}},Pc=e=>{let t=e,r=t*.225,n=[`M 0 ${r}`,`C 0 0 0 0 ${r} 0`,`L ${t-r} 0`,`C ${t} 0 ${t} 0 ${t} ${r}`,`L ${t} ${t-r}`,`C ${t} ${t} ${t} ${t} ${t-r} ${t}`,`L ${r} ${t}`,`C 0 ${t} 0 ${t} 0 ${t-r}`,"Z"].join(" ");return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><path d="${Go(n)}" fill="white"/></svg>`},Bo=(e,t)=>`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}"><rect width="${e}" height="${e}" fill="${Go(t)}"/></svg>`;var Ve=async e=>{let{size:t,paddingPercent:r,bg:n,fit:o,shape:s,radiusPercent:i,quality:a,forceSquare:c,sourceBuffer:l}=e,p=Math.max(1,Math.round(t*(1-r*2/100))),u=o==="cover"?"cover":"contain",f=await ut(l,{density:384}).resize(p,p,{fit:u,background:{r:0,g:0,b:0,alpha:0}}).png().toBuffer(),d=Math.round((t-p)/2),g=n==="transparent"?{r:0,g:0,b:0,alpha:0}:await Lr(n),y=await ut({create:{width:t,height:t,channels:4,background:g}}).composite([{input:f,left:d,top:d}]).png().toBuffer();if(!c&&(s!=="square"||o==="clip")){let x=s==="square"?"rounded":s,T=Buffer.from(Dr(x,t,i));y=await ut(y).composite([{input:T,blend:"dest-in"}]).png({compressionLevel:Vo(a)}).toBuffer()}else y=await ut(y).png({compressionLevel:Vo(a)}).toBuffer();return y},Lr=async e=>{let t=await ut(Buffer.from(Bo(1,e))).raw().toBuffer({resolveWithObject:!0}),[r,n,o,s=255]=t.data;return{r,g:n,b:o,alpha:s/255}},Vo=e=>{let t=Math.round((100-e)/100*9);return Math.max(0,Math.min(9,t))},Ho=async e=>{if(e.length===0)throw new Error("No frames provided to encodeIco");return Sc(e)};import{readFile as Ec,writeFile as Qf}from"node:fs/promises";var qo=e=>e.map(({src:t,size:r})=>({src:t,sizes:`${r}x${r}`,type:"image/png",purpose:"any maskable"})),Jo=async(e,t)=>{let r=await Ec(e,"utf-8"),n=JSON.parse(r),o=Array.isArray(n.icons)?n.icons:[],s=new Map;for(let i of[...o,...t])i&&typeof i.src=="string"&&s.set(i.src,i);return n.icons=[...s.values()],`${JSON.stringify(n,null,2)}
638
- `};var zo=e=>`icons: [
637
+ `)),r.required&&r.default!==void 0)throw new Error("--required and --default are mutually exclusive.");let s=Cc(r.type),i=Oc(r.enum);if(s==="enum"&&(!i||i.length===0))throw new Error("--type=enum requires at least one value via --enum a,b,c.");let a={name:t,type:s,required:!!r.required,default:r.default,description:r.describe,enumValues:i,public:!!r.public};g.start("Updating src/lib/env/index.ts, .env.example, and .env...");let c=await Dr(n,a);g.succeed("Env var written");let m=ue(a.name,a.public);await E(n,o),l(Ke.green(`
638
+ \u2728 ${m} declared in the ${c.group} group.
639
+ `)),l(Ke.dim("Touched:")),l(Ke.dim(` ${c.schemaUpdated?"\u270F\uFE0F ":"\u23ED "} src/lib/env/index.ts`)),l(Ke.dim(` ${c.envExampleUpdated?"\u270F\uFE0F ":"\u23ED "} .env.example`)),l(Ke.dim(` ${c.envUpdated?"\u270F\uFE0F ":"\u23ED "} .env`)),l("")}catch(n){g.fail("Env var declaration failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Wt from"node:path";import Me from"picocolors";import Ac from"enquirer";var{prompt:Ic}=Ac,zo=async(e={})=>e.source?{source:e.source}:{source:(await Ic({type:"input",name:"source",message:"Path to source image (PNG/JPG/JPEG/SVG/WebP/AVIF):",validate:r=>r?!0:"Source path is required"})).source};import{access as Nc,readFile as Fc,stat as Mc}from"node:fs/promises";import Fe from"node:path";var Ko=async e=>{try{return await Nc(e),!0}catch{return!1}},_c=async e=>{try{return(await Mc(e)).isDirectory()}catch{return!1}},qt=async e=>{let t=[Fe.join(e,"src","app"),Fe.join(e,"app")];for(let r of t)if(await _c(r))return r;return null},Dc=["next-pwa","@ducanh2912/next-pwa","@serwist/next","serwist"],Br=async e=>{let t={isPwa:!1},r=[Fe.join(e,"public","manifest.json"),Fe.join(e,"public","manifest.webmanifest"),Fe.join(e,"public","site.webmanifest")];for(let o of r)if(await Ko(o)){t.publicManifestPath=o,t.isPwa=!0;break}let n=await qt(e);if(n)for(let o of["ts","tsx","js"]){let s=Fe.join(n,`manifest.${o}`);if(await Ko(s)){t.appManifestPath=s,t.isPwa=!0;break}}try{let o=JSON.parse(await Fc(Fe.join(e,"package.json"),"utf-8")),s={...o.dependencies,...o.devDependencies};for(let i of Dc)if(s[i]){t.framework=i,t.isPwa=!0;break}}catch{}return t};import{mkdir as Vc,readFile as ss,stat as Hc,writeFile as qc}from"node:fs/promises";import re from"node:path";import Jc from"sharp";import Uc from"png-to-ico";import bt from"sharp";var Xo=e=>e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),Gr=(e,t,r)=>{switch(e){case"square":return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" fill="white"/></svg>`;case"circle":{let n=t/2;return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><circle cx="${n}" cy="${n}" r="${n}" fill="white"/></svg>`}case"rounded":{let n=Math.round(t*r/100);return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" rx="${n}" ry="${n}" fill="white"/></svg>`}case"squircle":return Lc(t)}},Lc=e=>{let t=e,r=t*.225,n=[`M 0 ${r}`,`C 0 0 0 0 ${r} 0`,`L ${t-r} 0`,`C ${t} 0 ${t} 0 ${t} ${r}`,`L ${t} ${t-r}`,`C ${t} ${t} ${t} ${t} ${t-r} ${t}`,`L ${r} ${t}`,`C 0 ${t} 0 ${t} 0 ${t-r}`,"Z"].join(" ");return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><path d="${Xo(n)}" fill="white"/></svg>`},Yo=(e,t)=>`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}"><rect width="${e}" height="${e}" fill="${Xo(t)}"/></svg>`;var Xe=async e=>{let{size:t,paddingPercent:r,bg:n,fit:o,shape:s,radiusPercent:i,quality:a,forceSquare:c,sourceBuffer:m}=e,p=Math.max(1,Math.round(t*(1-r*2/100))),u=o==="cover"?"cover":"contain",d=await bt(m,{density:384}).resize(p,p,{fit:u,background:{r:0,g:0,b:0,alpha:0}}).png().toBuffer(),f=Math.round((t-p)/2),h=n==="transparent"?{r:0,g:0,b:0,alpha:0}:await Vr(n),y=await bt({create:{width:t,height:t,channels:4,background:h}}).composite([{input:d,left:f,top:f}]).png().toBuffer();if(!c&&(s!=="square"||o==="clip")){let b=s==="square"?"rounded":s,P=Buffer.from(Gr(b,t,i));y=await bt(y).composite([{input:P,blend:"dest-in"}]).png({compressionLevel:Qo(a)}).toBuffer()}else y=await bt(y).png({compressionLevel:Qo(a)}).toBuffer();return y},Vr=async e=>{let t=await bt(Buffer.from(Yo(1,e))).raw().toBuffer({resolveWithObject:!0}),[r,n,o,s=255]=t.data;return{r,g:n,b:o,alpha:s/255}},Qo=e=>{let t=Math.round((100-e)/100*9);return Math.max(0,Math.min(9,t))},Zo=async e=>{if(e.length===0)throw new Error("No frames provided to encodeIco");return Uc(e)};import{readFile as Bc,writeFile as vg}from"node:fs/promises";var es=e=>e.map(({src:t,size:r})=>({src:t,sizes:`${r}x${r}`,type:"image/png",purpose:"any maskable"})),ts=async(e,t)=>{let r=await Bc(e,"utf-8"),n=JSON.parse(r),o=Array.isArray(n.icons)?n.icons:[],s=new Map;for(let i of[...o,...t])i&&typeof i.src=="string"&&s.set(i.src,i);return n.icons=[...s.values()],`${JSON.stringify(n,null,2)}
640
+ `};var rs=e=>`icons: [
639
641
  ${e.map(r=>` { src: '${r.src}', sizes: '${r.sizes}', type: '${r.type}'${r.purpose?`, purpose: '${r.purpose}'`:""} }`).join(`,
640
642
  `)},
641
- ],`,Wo=(e,t,r)=>`${JSON.stringify({name:e,short_name:e,start_url:"/",display:"standalone",background_color:"#ffffff",theme_color:t,icons:r},null,2)}
642
- `;import{stat as Tc}from"node:fs/promises";import Ur from"node:path";var Ko=[".png",".jpg",".jpeg",".webp",".svg",".avif"],Gt=async e=>{if(!e)throw new Error("Source image path is required (use --path).");let t=Ur.isAbsolute(e)?e:Ur.resolve(process.cwd(),e),r;try{r=await Tc(t)}catch{throw new Error(`Source image not found: ${t}`)}if(!r.isFile())throw new Error(`Source is not a file: ${t}`);let n=Ur.extname(t).toLowerCase();if(!Ko.includes(n))throw new Error(`Unsupported source format '${n}'. Use one of: ${Ko.join(", ")}`);return{absolutePath:t,ext:n,bytes:r.size,isVector:n===".svg"}};var Gr=(e,t)=>{if(!e)return t;let r=e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0&&n<=1024);if(r.length===0)throw new Error(`Invalid --sizes value: '${e}'. Provide comma-separated positive integers.`);return r};var Ac=async e=>{try{return await Rc(e),!0}catch{return!1}},Ic=async(e,t,r)=>{let n=[];for(let o of e){if(await Ac(o.outPath)&&!t&&!o.alwaysWrite){n.push({path:o.outPath,bytes:o.bytes.length,skipped:!0});continue}r||(await jc(Y.dirname(o.outPath),{recursive:!0}),await Cc(o.outPath,o.bytes)),n.push({path:o.outPath,bytes:o.bytes.length})}return n},Br=async(e,t)=>{let r=await Gt(t.source),n=await Xo(r.absolutePath),o=t.ogSource?await Xo((await Gt(t.ogSource)).absolutePath):n,s=[],i=[];for(let p of t.icoSizes)i.push(await Ve({sourceBuffer:n,size:p,shape:"square",radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality,forceSquare:!0}));let a=await Ho(i);if(s.push({outPath:Y.join(t.outDir,"favicon.ico"),bytes:a}),t.emitIcon){let p=await Ve({sourceBuffer:n,size:512,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:Y.join(t.outDir,"icon.png"),bytes:p})}if(t.emitApple){let p=t.bg==="transparent"?"#ffffff":t.bg,u=await Ve({sourceBuffer:n,size:180,shape:t.shape,radiusPercent:t.radius,bg:p,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:Y.join(t.outDir,"apple-icon.png"),bytes:u})}if(t.emitOg){let p=await Yo(o,t,!1);s.push({outPath:Y.join(t.outDir,"opengraph-image.png"),bytes:p})}if(t.emitTwitter){let p=await Yo(o,t,!0);s.push({outPath:Y.join(t.outDir,"twitter-image.png"),bytes:p})}let c;if(t.pwa||t.pwaInit){let p=await _r(e);if(t.pwa&&!p.isPwa)throw new Error("No PWA setup detected. Use --pwa-init to bootstrap a manifest, or set up next-pwa/serwist first.");let u=Y.join(e,"public"),f=[192,512],d=[];for(let y of f){let E=await Ve({sourceBuffer:n,size:y,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality}),x=`icon-${y}.png`;s.push({outPath:Y.join(u,x),bytes:E}),d.push({src:`/${x}`,size:y})}let g=qo(d);if(p.publicManifestPath){let y=await Jo(p.publicManifestPath,g);s.push({outPath:p.publicManifestPath,bytes:Buffer.from(y,"utf-8"),alwaysWrite:!0})}else if(p.appManifestPath)c=zo(g);else if(t.pwaInit){let y=Y.join(u,"manifest.webmanifest"),E=Wo(Y.basename(e)||"App","#000000",g);s.push({outPath:y,bytes:Buffer.from(E,"utf-8")})}}return{outputs:await Ic(s,t.force,t.dryRun),pwaSnippet:c}},Yo=async(e,t,r)=>{let o=r?600:630,s=Math.round(Math.min(1200,o)*(1-t.padding*2/100)),i=await Ve({sourceBuffer:e,size:s,shape:t.shape,radiusPercent:t.radius,bg:"transparent",paddingPercent:0,fit:t.fit,quality:t.quality}),a=t.bg==="transparent"?"#ffffff":t.bg,c=await Lr(a),l=Math.round((1200-s)/2),p=Math.round((o-s)/2);return Oc({create:{width:1200,height:o,channels:4,background:c}}).composite([{input:i,left:l,top:p}]).png().toBuffer()};var Qo=new Set(["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]);var Nc=["square","rounded","circle","squircle"],Fc=["contain","cover","clip"],Zo=(e,t,r,n)=>{if(!e)return r;if(!t.includes(e))throw new Error(`Invalid value for --${n}: '${e}'. Allowed: ${t.join(", ")}`);return e},Vr=(e,t,r,n,o)=>{if(e===void 0)return t;let s=Number(e);if(!Number.isFinite(s)||s<n||s>o)throw new Error(`Invalid value for --${r}: '${e}'. Must be a number between ${n}\u2013${o}.`);return s},ts=e=>{e.command("favicon").description("Generate favicon.ico (and optionally icons, OG image, PWA manifest icons)").option("--path <file>","Path to source image (PNG, JPG, JPEG, WebP, SVG, AVIF)").option("--out <dir>","Output dir (default: src/app or app)").option("--force","Overwrite existing files without prompt",!1).option("--dry-run","Show what would be written without writing",!1).option("--icon","Also emit icon.png (512\xD7512)",!1).option("--apple","Also emit apple-icon.png (180\xD7180)",!1).option("--og","Also emit opengraph-image.png (1200\xD7630)",!1).option("--og-source <file>","Use a separate image for the OG/Twitter card").option("--twitter","Also emit twitter-image.png (1200\xD7600)",!1).option("--all","Shorthand for --icon --apple --og",!1).option("--pwa","Detect PWA setup and emit manifest icons (192/512); errors if not detected",!1).option("--pwa-init","Bootstrap public/manifest.webmanifest with icons",!1).option("--shape <shape>","square | rounded | circle | squircle","square").option("--radius <percent>","Corner radius % when shape=rounded (0-50)","20").option("--bg <color>",'Background color (hex, css name, or "transparent")',"transparent").option("--padding <percent>","Padding around source content (0-30)","0").option("--fit <fit>","How source fits target: contain | cover | clip","contain").option("--sizes <list>","Comma-separated ICO sizes (default: 16,32,48)").option("--quality <n>","PNG compression 1-100 (higher = smaller file; PNG is lossless, default: 90)","90").action(async t=>{try{let r=process.cwd();m(Re.cyan(`
643
+ ],`,ns=(e,t,r)=>`${JSON.stringify({name:e,short_name:e,start_url:"/",display:"standalone",background_color:"#ffffff",theme_color:t,icons:r},null,2)}
644
+ `;import{stat as Gc}from"node:fs/promises";import Hr from"node:path";var os=[".png",".jpg",".jpeg",".webp",".svg",".avif"],Jt=async e=>{if(!e)throw new Error("Source image path is required (use --path).");let t=Hr.isAbsolute(e)?e:Hr.resolve(process.cwd(),e),r;try{r=await Gc(t)}catch{throw new Error(`Source image not found: ${t}`)}if(!r.isFile())throw new Error(`Source is not a file: ${t}`);let n=Hr.extname(t).toLowerCase();if(!os.includes(n))throw new Error(`Unsupported source format '${n}'. Use one of: ${os.join(", ")}`);return{absolutePath:t,ext:n,bytes:r.size,isVector:n===".svg"}};var qr=(e,t)=>{if(!e)return t;let r=e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0&&n<=1024);if(r.length===0)throw new Error(`Invalid --sizes value: '${e}'. Provide comma-separated positive integers.`);return r};var Wc=async e=>{try{return await Hc(e),!0}catch{return!1}},zc=async(e,t,r)=>{let n=[];for(let o of e){if(await Wc(o.outPath)&&!t&&!o.alwaysWrite){n.push({path:o.outPath,bytes:o.bytes.length,skipped:!0});continue}r||(await Vc(re.dirname(o.outPath),{recursive:!0}),await qc(o.outPath,o.bytes)),n.push({path:o.outPath,bytes:o.bytes.length})}return n},Jr=async(e,t)=>{let r=await Jt(t.source),n=await ss(r.absolutePath),o=t.ogSource?await ss((await Jt(t.ogSource)).absolutePath):n,s=[],i=[];for(let p of t.icoSizes)i.push(await Xe({sourceBuffer:n,size:p,shape:"square",radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality,forceSquare:!0}));let a=await Zo(i);if(s.push({outPath:re.join(t.outDir,"favicon.ico"),bytes:a}),t.emitIcon){let p=await Xe({sourceBuffer:n,size:512,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:re.join(t.outDir,"icon.png"),bytes:p})}if(t.emitApple){let p=t.bg==="transparent"?"#ffffff":t.bg,u=await Xe({sourceBuffer:n,size:180,shape:t.shape,radiusPercent:t.radius,bg:p,paddingPercent:t.padding,fit:t.fit,quality:t.quality});s.push({outPath:re.join(t.outDir,"apple-icon.png"),bytes:u})}if(t.emitOg){let p=await is(o,t,!1);s.push({outPath:re.join(t.outDir,"opengraph-image.png"),bytes:p})}if(t.emitTwitter){let p=await is(o,t,!0);s.push({outPath:re.join(t.outDir,"twitter-image.png"),bytes:p})}let c;if(t.pwa||t.pwaInit){let p=await Br(e);if(t.pwa&&!p.isPwa)throw new Error("No PWA setup detected. Use --pwa-init to bootstrap a manifest, or set up next-pwa/serwist first.");let u=re.join(e,"public"),d=[192,512],f=[];for(let y of d){let x=await Xe({sourceBuffer:n,size:y,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality}),b=`icon-${y}.png`;s.push({outPath:re.join(u,b),bytes:x}),f.push({src:`/${b}`,size:y})}let h=es(f);if(p.publicManifestPath){let y=await ts(p.publicManifestPath,h);s.push({outPath:p.publicManifestPath,bytes:Buffer.from(y,"utf-8"),alwaysWrite:!0})}else if(p.appManifestPath)c=rs(h);else if(t.pwaInit){let y=re.join(u,"manifest.webmanifest"),x=ns(re.basename(e)||"App","#000000",h);s.push({outPath:y,bytes:Buffer.from(x,"utf-8")})}}return{outputs:await zc(s,t.force,t.dryRun),pwaSnippet:c}},is=async(e,t,r)=>{let o=r?600:630,s=Math.round(Math.min(1200,o)*(1-t.padding*2/100)),i=await Xe({sourceBuffer:e,size:s,shape:t.shape,radiusPercent:t.radius,bg:"transparent",paddingPercent:0,fit:t.fit,quality:t.quality}),a=t.bg==="transparent"?"#ffffff":t.bg,c=await Vr(a),m=Math.round((1200-s)/2),p=Math.round((o-s)/2);return Jc({create:{width:1200,height:o,channels:4,background:c}}).composite([{input:i,left:m,top:p}]).png().toBuffer()};var as=new Set(["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]);var Kc=["square","rounded","circle","squircle"],Xc=["contain","cover","clip"],cs=(e,t,r,n)=>{if(!e)return r;if(!t.includes(e))throw new Error(`Invalid value for --${n}: '${e}'. Allowed: ${t.join(", ")}`);return e},Wr=(e,t,r,n,o)=>{if(e===void 0)return t;let s=Number(e);if(!Number.isFinite(s)||s<n||s>o)throw new Error(`Invalid value for --${r}: '${e}'. Must be a number between ${n}\u2013${o}.`);return s},ls=e=>{e.command("favicon").description("Generate favicon.ico (and optionally icons, OG image, PWA manifest icons)").option("--path <file>","Path to source image (PNG, JPG, JPEG, WebP, SVG, AVIF)").option("--out <dir>","Output dir (default: src/app or app)").option("--force","Overwrite existing files without prompt",!1).option("--dry-run","Show what would be written without writing",!1).option("--icon","Also emit icon.png (512\xD7512)",!1).option("--apple","Also emit apple-icon.png (180\xD7180)",!1).option("--og","Also emit opengraph-image.png (1200\xD7630)",!1).option("--og-source <file>","Use a separate image for the OG/Twitter card").option("--twitter","Also emit twitter-image.png (1200\xD7600)",!1).option("--all","Shorthand for --icon --apple --og",!1).option("--pwa","Detect PWA setup and emit manifest icons (192/512); errors if not detected",!1).option("--pwa-init","Bootstrap public/manifest.webmanifest with icons",!1).option("--shape <shape>","square | rounded | circle | squircle","square").option("--radius <percent>","Corner radius % when shape=rounded (0-50)","20").option("--bg <color>",'Background color (hex, css name, or "transparent")',"transparent").option("--padding <percent>","Padding around source content (0-30)","0").option("--fit <fit>","How source fits target: contain | cover | clip","contain").option("--sizes <list>","Comma-separated ICO sizes (default: 16,32,48)").option("--quality <n>","PNG compression 1-100 (higher = smaller file; PNG is lossless, default: 90)","90").action(async t=>{try{let r=process.cwd();l(Me.cyan(`
643
645
  \u{1F3A8} Favicon Generator
644
- `));let n=await Lo({source:t.path}),o=await Mc(r,t.out),s=Zo(t.shape,Nc,"square","shape"),i=Zo(t.fit,Fc,"contain","fit"),a=Vr(t.radius,20,"radius",0,50),c=Vr(t.padding,0,"padding",0,30),l=Vr(t.quality,90,"quality",1,100),p=Gr(t.sizes,[16,32,48]),u=t.bg??"transparent";Lc(u);let f=t.all===!0,d={source:n.source,outDir:o,force:!!t.force,dryRun:!!t.dryRun,emitIcon:!!t.icon||f,emitApple:!!t.apple||f,emitOg:!!t.og||f,emitTwitter:!!t.twitter,ogSource:t.ogSource,pwa:!!t.pwa,pwaInit:!!t.pwaInit,shape:s,radius:a,bg:u,padding:c,fit:i,icoSizes:p,quality:l};h.start("Generating favicon assets...");let g=await Br(r,d);h.succeed(d.dryRun?"Favicon plan ready":"Favicon assets generated"),m("");for(let y of g.outputs){let E=Bt.relative(r,y.path);y.skipped?m(Re.yellow(` \u21B7 skipped ${E} (exists; use --force to overwrite)`)):d.dryRun?m(Re.dim(` \u{1F4C4} would write ${E} (${es(y.bytes)})`)):m(Re.green(` \u2713 ${E} `)+Re.dim(`(${es(y.bytes)})`))}g.pwaSnippet&&(m(""),m(Re.cyan("Add this to your typed manifest (src/app/manifest.ts):")),m(Re.dim(g.pwaSnippet))),m("")}catch(r){h.fail("Favicon generation failed");let n=r instanceof Error?r.message:String(r);b(n),process.exit(1)}})},Mc=async(e,t)=>{if(t)return Bt.isAbsolute(t)?t:Bt.resolve(e,t);let r=await Ut(e);return r||(xn("Could not detect app/ or src/app/ \u2014 falling back to src/app"),Bt.join(e,"src","app"))},_c=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Dc=/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/]+\)$/i,Lc=e=>{if(e!=="transparent"&&!_c.test(e)&&!Dc.test(e)&&!Qo.has(e.toLowerCase()))throw new Error(`Invalid value for --bg: '${e}'. Use 'transparent', a hex code (e.g. #0f172a), a CSS color name, or rgb()/rgba()/hsl()/hsla().`)},es=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`;import Hr from"node:path";import D from"picocolors";import Uc from"enquirer";var{prompt:Gc}=Uc,rs=async(e,t,r={})=>{let n=[];e||n.push({type:"input",name:"featureName",message:"Feature name (kebab-case):",initial:"my-feature",validate:s=>/^[a-z][a-z0-9-]*$/.test(s)||"Use lowercase letters, digits, and hyphens only."}),r.api===void 0&&n.push({type:"confirm",name:"createApi",message:"Generate the api/ layer (schema, DAL, Server Actions, queries)?",initial:!0}),t!=="none"&&r.store===void 0&&(n.push({type:"confirm",name:"createStore",message:`Generate a ${t==="zustand"?"Zustand":"Redux"} slice for client-only state?`,initial:!1}),t==="redux"&&r.persist===void 0&&n.push({type:"confirm",name:"persistStore",message:"Persist the slice across reloads?",initial:!1,skip(){return!this.state.answers.createStore}}));let o=n.length>0?await Gc(n):{};return{featureName:e??o.featureName,createApi:r.api??o.createApi??!0,createStore:t!=="none"&&(r.store??o.createStore??!1),persistStore:t==="redux"&&(r.persist??o.persistStore??!1)}};var os=e=>{e.command("feature [name]").description("Generate a feature module (api/, components/, store/, index.ts, server.ts)").option("--api","Generate the api/ layer: schema, DAL, Server Actions, queries").option("--no-api","Skip the api/ layer").option("--store","Generate a client-state slice (Redux or Zustand, whichever the project uses)").option("--no-store","Skip the slice").option("--persist","Persist the Redux slice across reloads").option("--no-persist","Do not persist the slice").option("--path <path>","Base directory (default: src/features)").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(D.cyan(`
646
+ `));let n=await zo({source:t.path}),o=await Yc(r,t.out),s=cs(t.shape,Kc,"square","shape"),i=cs(t.fit,Xc,"contain","fit"),a=Wr(t.radius,20,"radius",0,50),c=Wr(t.padding,0,"padding",0,30),m=Wr(t.quality,90,"quality",1,100),p=qr(t.sizes,[16,32,48]),u=t.bg??"transparent";ep(u);let d=t.all===!0,f={source:n.source,outDir:o,force:!!t.force,dryRun:!!t.dryRun,emitIcon:!!t.icon||d,emitApple:!!t.apple||d,emitOg:!!t.og||d,emitTwitter:!!t.twitter,ogSource:t.ogSource,pwa:!!t.pwa,pwaInit:!!t.pwaInit,shape:s,radius:a,bg:u,padding:c,fit:i,icoSizes:p,quality:m};g.start("Generating favicon assets...");let h=await Jr(r,f);g.succeed(f.dryRun?"Favicon plan ready":"Favicon assets generated"),l("");for(let y of h.outputs){let x=Wt.relative(r,y.path);y.skipped?l(Me.yellow(` \u21B7 skipped ${x} (exists; use --force to overwrite)`)):f.dryRun?l(Me.dim(` \u{1F4C4} would write ${x} (${ps(y.bytes)})`)):l(Me.green(` \u2713 ${x} `)+Me.dim(`(${ps(y.bytes)})`))}h.pwaSnippet&&(l(""),l(Me.cyan("Add this to your typed manifest (src/app/manifest.ts):")),l(Me.dim(h.pwaSnippet))),l("")}catch(r){g.fail("Favicon generation failed");let n=r instanceof Error?r.message:String(r);v(n),process.exit(1)}})},Yc=async(e,t)=>{if(t)return Wt.isAbsolute(t)?t:Wt.resolve(e,t);let r=await qt(e);return r||(Pn("Could not detect app/ or src/app/ \u2014 falling back to src/app"),Wt.join(e,"src","app"))},Qc=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Zc=/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/]+\)$/i,ep=e=>{if(e!=="transparent"&&!Qc.test(e)&&!Zc.test(e)&&!as.has(e.toLowerCase()))throw new Error(`Invalid value for --bg: '${e}'. Use 'transparent', a hex code (e.g. #0f172a), a CSS color name, or rgb()/rgba()/hsl()/hsla().`)},ps=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`;import zr from"node:path";import U from"picocolors";import tp from"enquirer";var{prompt:rp}=tp,ms=async(e,t,r={})=>{let n=[];e||n.push({type:"input",name:"featureName",message:"Feature name (kebab-case):",initial:"my-feature",validate:s=>/^[a-z][a-z0-9-]*$/.test(s)||"Use lowercase letters, digits, and hyphens only."}),r.api===void 0&&n.push({type:"confirm",name:"createApi",message:"Generate the api/ layer (schema, DAL, Server Actions, queries)?",initial:!0}),t!=="none"&&r.store===void 0&&(n.push({type:"confirm",name:"createStore",message:`Generate a ${t==="zustand"?"Zustand":"Redux"} slice for client-only state?`,initial:!1}),t==="redux"&&r.persist===void 0&&n.push({type:"confirm",name:"persistStore",message:"Persist the slice across reloads?",initial:!1,skip(){return!this.state.answers.createStore}}));let o=n.length>0?await rp(n):{};return{featureName:e??o.featureName,createApi:r.api??o.createApi??!0,createStore:t!=="none"&&(r.store??o.createStore??!1),persistStore:t==="redux"&&(r.persist??o.persistStore??!1)}};var ds=e=>{e.command("feature [name]").description("Generate a feature module (api/, components/, store/, index.ts, server.ts)").option("--api","Generate the api/ layer: schema, DAL, Server Actions, queries").option("--no-api","Skip the api/ layer").option("--store","Generate a client-state slice (Redux or Zustand, whichever the project uses)").option("--no-store","Skip the slice").option("--persist","Persist the Redux slice across reloads").option("--no-persist","Do not persist the slice").option("--path <path>","Base directory (default: src/features)").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(U.cyan(`
645
647
  \u{1F3AF} Feature Generator
646
- `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),m(D.dim(` state: ${s.state} i18n: ${s.hasI18n?"\u2713":"\u2717"} tests: ${s.hasTests?"\u2713":"\u2717"}
647
- `));let i=await rs(t,s.state,{api:r.api,store:r.store,persist:r.persist});M(i.featureName,"feature name"),r.path&&W(r.path,"path");let a=r.path||Hr.join("src","features"),c=ne(n,a,i.featureName);await ke(n,i.featureName,a)&&(b(`Feature '${i.featureName}' already exists at ${a}.`),process.exit(1)),h.start("Generating feature files..."),await wr({name:i.featureName,outputPath:c,createStore:i.createStore,persistStore:i.persistStore,createApi:i.createApi,state:s.state,hasI18n:s.hasI18n,hasTests:s.hasTests}),h.succeed("Feature files generated"),s.hasI18n&&await Te(n,$(i.featureName)),i.createApi&&(h.start("Registering API endpoints..."),await lt({serviceName:i.featureName,projectPath:n}),h.succeed("API endpoints registered")),i.createStore&&s.state==="redux"&&(h.start("Registering slice in the store..."),await mt({projectPath:n,name:i.featureName,persist:i.persistStore,importPath:Hr.join(a,i.featureName,"store")}),h.succeed("Slice registered")),await k(n,o),Bc(i,a,s.state)}catch(n){h.fail("Feature generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},Bc=(e,t,r)=>{let n=Hr.join(t,e.featureName);m(D.green(`
648
+ `)),g.start("Detecting project setup...");let s=await N(n);g.succeed("Project setup detected"),l(U.dim(` state: ${s.state} i18n: ${s.hasI18n?"\u2713":"\u2717"} tests: ${s.hasTests?"\u2713":"\u2717"}
649
+ `));let i=await ms(t,s.state,{api:r.api,store:r.store,persist:r.persist});D(i.featureName,"feature name"),r.path&&Z(r.path,"path");let a=r.path||zr.join("src","features"),c=le(n,a,i.featureName);await Ce(n,i.featureName,a)&&(v(`Feature '${i.featureName}' already exists at ${a}.`),process.exit(1)),g.start("Generating feature files..."),await kr({name:i.featureName,outputPath:c,createStore:i.createStore,persistStore:i.persistStore,createApi:i.createApi,state:s.state,hasI18n:s.hasI18n,hasTests:s.hasTests}),g.succeed("Feature files generated"),s.hasI18n&&await Ne(n,$(i.featureName)),i.createApi&&(g.start("Registering API endpoints..."),await wt({serviceName:i.featureName,projectPath:n}),g.succeed("API endpoints registered")),i.createStore&&s.state==="redux"&&(g.start("Registering slice in the store..."),await xt({projectPath:n,name:i.featureName,persist:i.persistStore,importPath:zr.join(a,i.featureName,"store")}),g.succeed("Slice registered")),await E(n,o),np(i,a,s.state)}catch(n){g.fail("Feature generation failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})},np=(e,t,r)=>{let n=zr.join(t,e.featureName);l(U.green(`
648
650
  \u2728 Feature '${e.featureName}' created.
649
- `)),m(D.dim(` ${n}/`)),e.createApi&&m(D.dim(" api/ schema, keys, server (DAL), actions, queries")),m(D.dim(" components/")),e.createApi||m(D.dim(" hooks/")),e.createStore&&m(D.dim(" store/")),m(D.dim(" types/")),m(D.dim(" index.ts client-safe barrel")),e.createApi&&m(D.dim(" server.ts server-only barrel")),m(""),m(D.cyan("Next:")),e.createApi&&(m(D.dim(` 1. Adjust the contracts in ${n}/api/schema.ts and the paths in src/lib/config/app-apis.ts`)),m(D.dim(` 2. Read in a Server Component: import { list${ns(e.featureName)}s } from '@/features/${e.featureName}/server'`)),m(D.dim(` 3. Prefetch + hydrate for the client list: prefetchQuery(${Vc(e.featureName)}ListQuery())`))),e.createStore&&r==="zustand"&&m(D.yellow(` ! Compose create${ns(e.featureName)}Slice into AppState in src/store/index.ts`)),m("")},Vc=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),ns=$;import qr from"node:path";import He from"picocolors";import Hc from"enquirer";var{prompt:qc}=Hc,ss=async e=>e?{hookName:e}:await qc({type:"input",name:"hookName",message:'Hook name (kebab-case, without "use" prefix):',validate:r=>r?/^[a-z][a-z0-9-]*$/.test(r)?!0:"Use lowercase letters, numbers, and hyphens only":"Hook name is required"});var is=e=>{e.command("hook [name]").description("Generate a custom React hook").option("--client","Add 'use client' directive (default: true)",!0).option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(He.cyan(`
651
+ `)),l(U.dim(` ${n}/`)),e.createApi&&l(U.dim(" api/ schema, keys, server (DAL), actions, queries")),l(U.dim(" components/")),e.createApi||l(U.dim(" hooks/")),e.createStore&&l(U.dim(" store/")),l(U.dim(" types/")),l(U.dim(" index.ts client-safe barrel")),e.createApi&&l(U.dim(" server.ts server-only barrel")),l(""),l(U.cyan("Next:")),e.createApi&&(l(U.dim(` 1. Adjust the contracts in ${n}/api/schema.ts and the paths in src/lib/config/app-apis.ts`)),l(U.dim(` 2. Read in a Server Component: import { list${us(e.featureName)}s } from '@/features/${e.featureName}/server'`)),l(U.dim(` 3. Prefetch + hydrate for the client list: prefetchQuery(${op(e.featureName)}ListQuery())`))),e.createStore&&r==="zustand"&&l(U.yellow(` ! Compose create${us(e.featureName)}Slice into AppState in src/store/index.ts`)),l("")},op=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),us=$;import Kr from"node:path";import Ye from"picocolors";import sp from"enquirer";var{prompt:ip}=sp,fs=async e=>e?{hookName:e}:await ip({type:"input",name:"hookName",message:'Hook name (kebab-case, without "use" prefix):',validate:r=>r?/^[a-z][a-z0-9-]*$/.test(r)?!0:"Use lowercase letters, numbers, and hyphens only":"Hook name is required"});var gs=e=>{e.command("hook [name]").description("Generate a custom React hook").option("--client","Add 'use client' directive (default: true)",!0).option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(Ye.cyan(`
650
652
  \u{1FA9D} Hook Generator
651
- `));let s=await O(n),i=await ss(t);M(i.hookName,"hook name"),r.feature&&W(r.feature,"feature path");let c=`use${$(i.hookName)}`,l=Jc(r,s.hasTests);h.start("Generating hook..."),await br({name:i.hookName,projectPath:n,isClient:r.client??!0,featurePath:r.feature}),h.succeed("Hook generated");let p=r.feature?qr.join(n,r.feature,"hooks",`${c}.ts`):qr.join(n,"src/hooks",`${c}.ts`),u=null;l&&(h.start("Generating test..."),u=await oe({projectPath:n,sourceFile:p,kind:"hook",symbolName:c,hookUsesStore:s.state!=="none"&&!!r.feature}),h.succeed("Test generated"));let f=r.feature?`${r.feature}/hooks/${c}.ts`:`src/hooks/${c}.ts`;await k(n,o),m(He.green(`
653
+ `));let s=await N(n),i=await fs(t);D(i.hookName,"hook name"),r.feature&&Z(r.feature,"feature path");let c=`use${$(i.hookName)}`,m=ap(r,s.hasTests);g.start("Generating hook..."),await Pr({name:i.hookName,projectPath:n,isClient:r.client??!0,featurePath:r.feature}),g.succeed("Hook generated");let p=r.feature?Kr.join(n,r.feature,"hooks",`${c}.ts`):Kr.join(n,"src/hooks",`${c}.ts`),u=null;m&&(g.start("Generating test..."),u=await me({projectPath:n,sourceFile:p,kind:"hook",symbolName:c,hookUsesStore:s.state!=="none"&&!!r.feature}),g.succeed("Test generated"));let d=r.feature?`${r.feature}/hooks/${c}.ts`:`src/hooks/${c}.ts`;await E(n,o),l(Ye.green(`
652
654
  \u2728 Hook '${c}' created successfully!
653
- `)),m(He.dim(` \u{1F4C4} ${f}`)),u&&m(He.dim(` \u{1F9EA} ${qr.relative(n,u)}`)),m(""),m(He.cyan("Usage:"));let d=r.feature?`${r.feature.replace(/^src\//,"@/")}/hooks/${c}`:`@/hooks/${c}`;m(He.dim(` import { ${c} } from '${d}';`)),m("")}catch(n){h.fail("Hook generation failed"),b(`${n}`),process.exit(1)}})},Jc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import Vt from"picocolors";var as=e=>{e.command("layout <segment>").description("Generate a nested layout.tsx (locale-aware when i18n is detected)").option("--group","Treat the segment as a route group (wraps it in parens)").option("--at <path>","Place the layout under this nested path (kebab-case, slash-separated)").option("--no-locale","Skip the locale wrapper even if i18n is detected").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(Vt.cyan(`
655
+ `)),l(Ye.dim(` \u{1F4C4} ${d}`)),u&&l(Ye.dim(` \u{1F9EA} ${Kr.relative(n,u)}`)),l(""),l(Ye.cyan("Usage:"));let f=r.feature?`${r.feature.replace(/^src\//,"@/")}/hooks/${c}`:`@/hooks/${c}`;l(Ye.dim(` import { ${c} } from '${f}';`)),l("")}catch(n){g.fail("Hook generation failed"),v(`${n}`),process.exit(1)}})},ap=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import zt from"picocolors";var hs=e=>{e.command("layout <segment>").description("Generate a nested layout.tsx (locale-aware when i18n is detected)").option("--group","Treat the segment as a route group (wraps it in parens)").option("--at <path>","Place the layout under this nested path (kebab-case, slash-separated)").option("--no-locale","Skip the locale wrapper even if i18n is detected").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(zt.cyan(`
654
656
  \u{1F4D0} Layout Generator
655
- `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=s.hasI18n&&r.locale!==!1;m(Vt.dim(` i18n: ${i?"\u2713":"\u2717"}
656
- `)),h.start("Generating layout...");let a=await vr({segment:t,at:r.at,projectPath:n,hasI18n:i,withGroup:!!r.group});h.succeed("Layout generated"),await k(n,o),m(Vt.green(`
657
+ `)),g.start("Detecting project setup...");let s=await N(n);g.succeed("Project setup detected");let i=s.hasI18n&&r.locale!==!1;l(zt.dim(` i18n: ${i?"\u2713":"\u2717"}
658
+ `)),g.start("Generating layout...");let a=await Sr({segment:t,at:r.at,projectPath:n,hasI18n:i,withGroup:!!r.group});g.succeed("Layout generated"),await E(n,o),l(zt.green(`
657
659
  \u2728 ${a.componentName} created!
658
- `)),m(Vt.dim(` \u{1F4C4} ${a.displayPath}`)),m("")}catch(n){h.fail("Layout generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Q from"picocolors";import zc from"enquirer";var{prompt:Wc}=zc,cs=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),t.name||r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"}),t.country||r.push({type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"}),t.flag||r.push({type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=r.length>0?await Wc(r):{};return{code:e??n.code,name:t.name??n.name,country:t.country??n.country,flag:t.flag??n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var ps=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").option("--no-copy-translations","Start the new locale with empty values").option("--name <name>","Language name, e.g. Spanish").option("--country <country>","Country, e.g. Spain").option("--flag <emoji>","Flag emoji, e.g. \u{1F1EA}\u{1F1F8}").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(Q.cyan(`
660
+ `)),l(zt.dim(` \u{1F4C4} ${a.displayPath}`)),l("")}catch(n){g.fail("Layout generation failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import ne from"picocolors";import cp from"enquirer";var{prompt:pp}=cp,ys=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),t.name||r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"}),t.country||r.push({type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"}),t.flag||r.push({type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=r.length>0?await pp(r):{};return{code:e??n.code,name:t.name??n.name,country:t.country??n.country,flag:t.flag??n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var ws=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").option("--no-copy-translations","Start the new locale with empty values").option("--name <name>","Language name, e.g. Spanish").option("--country <country>","Country, e.g. Spain").option("--flag <emoji>","Flag emoji, e.g. \u{1F1EA}\u{1F1F8}").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(ne.cyan(`
659
661
  \u{1F30D} Locale Generator
660
- `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),s.hasI18n||(h.fail("i18n is not set up in this project"),b("Please set up internationalization first"),m(Q.dim(`
662
+ `)),g.start("Detecting project setup...");let s=await N(n);g.succeed("Project setup detected"),s.hasI18n||(g.fail("i18n is not set up in this project"),v("Please set up internationalization first"),l(ne.dim(`
661
663
  Run: npx @teispace/next-maker setup --i18n
662
- `)),process.exit(1));let i=await cs(t,{copyTranslations:r.copyTranslations,name:r.name,country:r.country,flag:r.flag});M(i.code,"locale code");let a=ne(n,"src","i18n","translations",`${i.code}.json`);w(a)&&(b(`Locale '${i.code}' already exists!`),process.exit(1)),h.start("Adding locale..."),await $r({...i,projectPath:n}),h.succeed("Locale added"),await k(n,o),m(Q.green(`
664
+ `)),process.exit(1));let i=await ys(t,{copyTranslations:r.copyTranslations,name:r.name,country:r.country,flag:r.flag});D(i.code,"locale code");let a=le(n,"src","i18n","translations",`${i.code}.json`);w(a)&&(v(`Locale '${i.code}' already exists!`),process.exit(1)),g.start("Adding locale..."),await Er({...i,projectPath:n}),g.succeed("Locale added"),await E(n,o),l(ne.green(`
663
665
  \u2728 Locale '${i.code}' (${i.name}) added successfully!
664
- `)),m(Q.dim("Updated files:")),m(Q.dim(` \u{1F4C4} src/i18n/translations/${i.code}.json`)),m(Q.dim(" \u{1F4DD} src/types/i18n.ts (SupportedLocale type)")),m(Q.dim(" \u{1F4DD} src/lib/config/app-locales.ts")),m(""),m(Q.cyan("Next steps:")),m(Q.dim(` 1. Translate: src/i18n/translations/${i.code}.json`)),m(Q.dim(` 2. Visit: http://localhost:3000/${i.code}`)),m("")}catch(n){h.fail("Locale generation failed"),b(`${n}`),process.exit(1)}})};import Kc from"node:path";import dt from"picocolors";var ls=e=>{e.command("options").description("List the starter's options and this project's current values").option("--starter-path <dir>","Read the manifest from a local starter checkout").action(async t=>{let r;try{let n=process.cwd(),o=w(Kc.join(n,".next-maker.json")),s=o?await re(n):{cli:"",starter:{name:"",version:"",source:""},packageManager:"pnpm",answers:{}},i=await De(s,{starterPath:t.starterPath});r=i.dispose,m(dt.cyan(`
666
+ `)),l(ne.dim("Updated files:")),l(ne.dim(` \u{1F4C4} src/i18n/translations/${i.code}.json`)),l(ne.dim(" \u{1F4DD} src/types/i18n.ts (SupportedLocale type)")),l(ne.dim(" \u{1F4DD} src/lib/config/app-locales.ts")),l(""),l(ne.cyan("Next steps:")),l(ne.dim(` 1. Translate: src/i18n/translations/${i.code}.json`)),l(ne.dim(` 2. Visit: http://localhost:3000/${i.code}`)),l("")}catch(n){g.fail("Locale generation failed"),v(`${n}`),process.exit(1)}})};import lp from"node:path";import vt from"picocolors";var xs=e=>{e.command("options").description("List the starter's options and this project's current values").option("--starter-path <dir>","Read the manifest from a local starter checkout").action(async t=>{let r;try{let n=process.cwd(),o=w(lp.join(n,".next-maker.json")),s=o?await pe(n):{cli:"",starter:{name:"",version:"",source:""},packageManager:"pnpm",answers:{}},i=await He(s,{starterPath:t.starterPath});r=i.dispose,l(vt.cyan(`
665
667
  ${i.manifest.starter.name} ${i.manifest.starter.version}
666
- `));for(let[a,c]of Object.entries(i.manifest.options)){let l=o?s.answers[a]:c.default,p=c.type==="boolean"?"true | false":(c.values??[]).join(" | ");m(` ${dt.bold(a.padEnd(18))} ${String(Array.isArray(l)?l.join(",")||"none":l).padEnd(10)} ${dt.dim(p)}`),c.label&&m(` ${"".padEnd(18)} ${dt.dim(c.label)}`)}m(""),m(dt.dim(o?"Change with: next-maker setup --set <option>=<value>":"Use with: next-maker init --set <option>=<value>")),m("")}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}finally{await r?.()}})};import Jr from"node:path";import H from"picocolors";import Xc from"enquirer";var{prompt:Yc}=Xc,ms=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"pageName",message:"Page name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Page name is required"}),t.loading===void 0&&r.push({type:"confirm",name:"withLoading",message:"Generate loading.tsx?",initial:!0}),t.error===void 0&&r.push({type:"confirm",name:"withError",message:"Generate error.tsx?",initial:!0});let n=r.length>0?await Yc(r):{};return{pageName:e??n.pageName,withLoading:t.loading??n.withLoading??!0,withError:t.error??n.withError??!0}};var us=e=>{e.command("page [name]").description("Generate a new page/route").option("--dynamic <param>","Create dynamic route with parameter (e.g., id)").option("--group <name>","Route group to place the page in, e.g. app or marketing").option("--loading","Generate loading.tsx").option("--no-loading","Skip loading.tsx").option("--error","Generate error.tsx").option("--no-error","Skip error.tsx").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(H.cyan(`
668
+ `));for(let[a,c]of Object.entries(i.manifest.options)){let m=o?s.answers[a]:c.default,p=c.type==="boolean"?"true | false":(c.values??[]).join(" | ");l(` ${vt.bold(a.padEnd(18))} ${String(Array.isArray(m)?m.join(",")||"none":m).padEnd(10)} ${vt.dim(p)}`),c.label&&l(` ${"".padEnd(18)} ${vt.dim(c.label)}`)}l(""),l(vt.dim(o?"Change with: next-maker setup --set <option>=<value>":"Use with: next-maker init --set <option>=<value>")),l("")}catch(n){v(`${n instanceof Error?n.message:n}`),process.exit(1)}finally{await r?.()}})};import Xr from"node:path";import K from"picocolors";import mp from"enquirer";var{prompt:up}=mp,bs=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"pageName",message:"Page name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Page name is required"}),t.loading===void 0&&r.push({type:"confirm",name:"withLoading",message:"Generate loading.tsx?",initial:!0}),t.error===void 0&&r.push({type:"confirm",name:"withError",message:"Generate error.tsx?",initial:!0});let n=r.length>0?await up(r):{};return{pageName:e??n.pageName,withLoading:t.loading??n.withLoading??!0,withError:t.error??n.withError??!0}};var vs=e=>{e.command("page [name]").description("Generate a new page/route").option("--dynamic <param>","Create dynamic route with parameter (e.g., id)").option("--group <name>","Route group to place the page in, e.g. app or marketing").option("--loading","Generate loading.tsx").option("--no-loading","Skip loading.tsx").option("--error","Generate error.tsx").option("--no-error","Skip error.tsx").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(K.cyan(`
667
669
  \u{1F4C4} Page Generator
668
- `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),m(H.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
669
- `));let i=await ms(t,{loading:r.loading,error:r.error}),a=i.pageName;M(a,"page name"),r.dynamic&&M(r.dynamic,"dynamic param"),r.group&&M(r.group,"route group");let c=$(a),l=Jr.join(s.hasI18n?"src/app/[locale]":"src/app",r.group?`(${r.group})`:"");await ke(n,a,l)&&(b(`Page '${a}' already exists at ${l}/${a}!`),process.exit(1)),h.start("Generating page files..."),await Sr({name:a,projectPath:n,hasI18n:s.hasI18n,group:r.group,dynamic:r.dynamic,withLoading:r.loading??i.withLoading,withError:r.error??i.withError}),h.succeed("Page files generated"),h.start("Registering route...");let u=r.dynamic?`/${a}/[${r.dynamic}]`:`/${a}`;await Or(n,a,u),h.succeed("Route registered"),s.hasI18n&&(h.start("Adding translation namespace..."),await Te(n,c),h.succeed("Translation namespace added"));let f=r.dynamic?Jr.join(l,a,`[${r.dynamic}]`):Jr.join(l,a);await k(n,o),m(H.green(`
670
+ `)),g.start("Detecting project setup...");let s=await N(n);g.succeed("Project setup detected"),l(K.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
671
+ `));let i=await bs(t,{loading:r.loading,error:r.error}),a=i.pageName;D(a,"page name"),r.dynamic&&D(r.dynamic,"dynamic param"),r.group&&D(r.group,"route group");let c=$(a),m=Xr.join(s.hasI18n?"src/app/[locale]":"src/app",r.group?`(${r.group})`:"");await Ce(n,a,m)&&(v(`Page '${a}' already exists at ${m}/${a}!`),process.exit(1)),g.start("Generating page files..."),await jr({name:a,projectPath:n,hasI18n:s.hasI18n,group:r.group,dynamic:r.dynamic,withLoading:r.loading??i.withLoading,withError:r.error??i.withError}),g.succeed("Page files generated"),g.start("Registering route...");let u=r.dynamic?`/${a}/[${r.dynamic}]`:`/${a}`;await Fr(n,a,u),g.succeed("Route registered"),s.hasI18n&&(g.start("Adding translation namespace..."),await Ne(n,c),g.succeed("Translation namespace added"));let d=r.dynamic?Xr.join(m,a,`[${r.dynamic}]`):Xr.join(m,a);await E(n,o),l(K.green(`
670
672
  \u2728 Page '${a}' created successfully!
671
- `)),m(H.dim("Generated files:")),m(H.dim(` \u{1F4C2} ${f}/`)),m(H.dim(" \u251C\u2500\u2500 page.tsx")),(r.loading??i.withLoading)&&m(H.dim(" \u251C\u2500\u2500 loading.tsx")),(r.error??i.withError)&&m(H.dim(" \u2514\u2500\u2500 error.tsx")),m(""),s.hasI18n&&(m(H.cyan("Next steps:")),m(H.dim(` 1. Add translations in: src/i18n/translations/en.json \u2192 "${c}"`)),m(H.dim(` 2. Visit: http://localhost:3000/${a}`)),m(""))}catch(n){h.fail("Page generation failed"),b(`${n}`),process.exit(1)}})};import zr from"node:path";import fe from"picocolors";var ds=e=>{e.command("provider <name>").description("Generate a context provider in src/providers/ and wire it into RootProvider").action(async t=>{try{let r=process.cwd(),n=Date.now();m(fe.cyan(`
673
+ `)),l(K.dim("Generated files:")),l(K.dim(` \u{1F4C2} ${d}/`)),l(K.dim(" \u251C\u2500\u2500 page.tsx")),(r.loading??i.withLoading)&&l(K.dim(" \u251C\u2500\u2500 loading.tsx")),(r.error??i.withError)&&l(K.dim(" \u2514\u2500\u2500 error.tsx")),l(""),s.hasI18n&&(l(K.cyan("Next steps:")),l(K.dim(` 1. Add translations in: src/i18n/translations/en.json \u2192 "${c}"`)),l(K.dim(` 2. Visit: http://localhost:3000/${a}`)),l(""))}catch(n){g.fail("Page generation failed"),v(`${n}`),process.exit(1)}})};import Yr from"node:path";import be from"picocolors";var ks=e=>{e.command("provider <name>").description("Generate a context provider in src/providers/ and wire it into RootProvider").action(async t=>{try{let r=process.cwd(),n=Date.now();l(be.cyan(`
672
674
  \u{1F50C} Provider Generator
673
- `)),h.start("Generating provider...");let{componentName:o,fileBaseName:s,providerFile:i}=await Tr({name:t,projectPath:r});h.succeed("Provider generated"),h.start("Registering provider in RootProvider and barrel...");let{rootProviderFile:a,barrelFile:c}=await Fr({projectPath:r,componentName:o,fileBaseName:s});h.succeed("Provider registered"),await k(r,n),m(fe.green(`
675
+ `)),g.start("Generating provider...");let{componentName:o,fileBaseName:s,providerFile:i}=await Or({name:t,projectPath:r});g.succeed("Provider generated"),g.start("Registering provider in RootProvider and barrel...");let{rootProviderFile:a,barrelFile:c}=await Lr({projectPath:r,componentName:o,fileBaseName:s});g.succeed("Provider registered"),await E(r,n),l(be.green(`
674
676
  \u2728 ${o} created!
675
- `)),m(fe.dim("Generated files:")),m(fe.dim(` \u{1F4C4} ${zr.relative(r,i)}`)),a?m(fe.dim(` \u270F\uFE0F ${zr.relative(r,a)} \u2014 wrapped {children}`)):(m(fe.yellow(`
676
- \u26A0\uFE0F Could not locate a RootProvider file. Wire the new provider manually:`)),m(fe.dim(` <${o}>{children}</${o}>`))),c&&m(fe.dim(` \u270F\uFE0F ${zr.relative(r,c)} \u2014 added re-export`)),m("")}catch(r){h.fail("Provider generation failed"),b(`${r instanceof Error?r.message:r}`),process.exit(1)}})};import Qc from"picocolors";var fs=e=>{e.command("remove <feature>").alias("uninstall").description("Turn a boolean starter feature off (shorthand for `setup --set <feature>=false`)").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").action(async(t,r)=>{try{let n=["setup","--set",`${t}=false`];r.yes&&n.push("--yes"),r.dryRun&&n.push("--dry-run"),r.install===!1&&n.push("--no-install"),await e.parseAsync([process.argv[0],process.argv[1],...n])}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}}).addHelpText("after",`
677
- ${Qc.dim("Example: next-maker remove ws")}
678
- `)};import Wr from"node:path";import Kr from"picocolors";var gs=e=>{e.command("api [name]").alias("service").description("Generate api/{schema,keys,server,queries,actions}.ts for a resource inside a feature").option("--feature <path>","Feature directory (default: src/features/<name>)").option("--no-actions","Skip actions.ts (read-only resource)").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();if(m(Kr.cyan(`
677
+ `)),l(be.dim("Generated files:")),l(be.dim(` \u{1F4C4} ${Yr.relative(r,i)}`)),a?l(be.dim(` \u270F\uFE0F ${Yr.relative(r,a)} \u2014 wrapped {children}`)):(l(be.yellow(`
678
+ \u26A0\uFE0F Could not locate a RootProvider file. Wire the new provider manually:`)),l(be.dim(` <${o}>{children}</${o}>`))),c&&l(be.dim(` \u270F\uFE0F ${Yr.relative(r,c)} \u2014 added re-export`)),l("")}catch(r){g.fail("Provider generation failed"),v(`${r instanceof Error?r.message:r}`),process.exit(1)}})};import dp from"picocolors";var $s=e=>{e.command("remove <feature>").alias("uninstall").description("Turn a boolean starter feature off (shorthand for `setup --set <feature>=false`)").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").action(async(t,r)=>{try{let n=["setup","--set",`${t}=false`];r.yes&&n.push("--yes"),r.dryRun&&n.push("--dry-run"),r.install===!1&&n.push("--no-install"),await e.parseAsync([process.argv[0],process.argv[1],...n])}catch(n){v(`${n instanceof Error?n.message:n}`),process.exit(1)}}).addHelpText("after",`
679
+ ${dp.dim("Example: next-maker remove ws")}
680
+ `)};import Qr from"node:path";import Zr from"picocolors";var Ps=e=>{e.command("api [name]").alias("service").description("Generate api/{schema,keys,server,queries,actions}.ts for a resource inside a feature").option("--feature <path>","Feature directory (default: src/features/<name>)").option("--no-actions","Skip actions.ts (read-only resource)").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();if(l(Zr.cyan(`
679
681
  \u{1F50C} API Layer Generator
680
- `)),!t)throw new Error("Pass the resource name, e.g. `next-maker api invoice`.");M(t,"resource name"),r.feature&&W(r.feature,"feature path");let s=await O(n);if(!s.hasQuery||!s.hasActions)throw new Error("This generator needs @tanstack/react-query and next-safe-action (starter 2.x).");let i=r.feature?ne(n,r.feature):ne(n,"src","features",t);if(w(Wr.join(i,"api","schema.ts")))throw new Error(`${Wr.relative(n,i)}/api already exists.`);h.start("Generating api/ files...");let a=await st({name:t,featurePath:i,withActions:r.actions!==!1});h.succeed("api/ generated"),h.start("Registering API endpoints..."),await lt({serviceName:t,projectPath:n}),h.succeed("Endpoints registered in src/lib/config/app-apis.ts"),await k(n,o),m(Kr.green(`
681
- \u2728 ${Wr.relative(n,i)}/api ready.
682
- `));for(let c of a)m(Kr.dim(` ${c}`));m("")}catch(n){h.fail("API generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import bp from"enquirer";import q from"picocolors";import{execFile as ip}from"node:child_process";import{cp as ry,mkdir as $s,readFile as ap,rm as ks,stat as ny,writeFile as qt}from"node:fs/promises";import ee from"node:path";import{promisify as cp}from"node:util";var Xr=(e,t)=>{let r=e.length,n=t.length;if((r+1)*(n+1)>4e6)return null;let o=n+1,s=new Int32Array((r+1)*o);for(let u=r-1;u>=0;u--)for(let f=n-1;f>=0;f--)s[u*o+f]=e[u]===t[f]?s[(u+1)*o+f+1]+1:Math.max(s[(u+1)*o+f],s[u*o+f+1]);let i=[],a=null,c=0,l=0,p=()=>(a||(a={start:c,end:c,insert:[]},i.push(a)),a);for(;c<r||l<n;){let u=c*o+l;c<r&&l<n&&e[c]===t[l]&&s[u]===s[u+o+1]+1?(a=null,c++,l++):l<n&&(c>=r||s[u+1]>=s[u+o])?(p().insert.push(t[l]),l++):p().end=++c}return i},Z=e=>e.start===e.end,Zc=(e,t)=>Z(e)&&Z(t)?!1:Z(e)?t.start<e.start&&e.start<t.end:Z(t)?e.start<t.start&&t.start<e.end:Math.max(e.start,t.start)<Math.min(e.end,t.end),ep=(e,t)=>e.start===t.start&&e.end===t.end&&e.insert.length===t.insert.length&&e.insert.every((r,n)=>r===t.insert[n]),hs=(e,t,r)=>{let n=t.start,o=t.insert;for(;n<r.end&&o.length>0&&o[0]===e[n];)o=[...o.slice(1),o[0]],n++;if(n===r.end)return{start:n,end:n,insert:o};for(n=t.start,o=t.insert;n>r.start&&o.length>0&&o[o.length-1]===e[n-1];)o=[o[o.length-1],...o.slice(0,-1)],n--;return n===r.start?{start:n,end:n,insert:o}:null},Yr=(e,t)=>e.map(r=>({start:r.start+t,end:r.end+t,insert:r.insert})),ys=(e,t,r,n)=>{let o=[],s=0,i=0,a=0,c=p=>{for(let u=s;u<p.start;u++)o.push(e[u]);o.push(...p.insert),s=Math.max(s,p.end)},l=(p,u)=>{if(!n)return!1;let f=Math.min(p.start,u.start),d=Math.max(p.end,u.end),g=i,y=a,E=!0;for(;E;){for(E=!1;g+1<t.length&&t[g+1].start<d;)g++,d=Math.max(d,t[g].end),E=!0;for(;y+1<r.length&&r[y+1].start<d;)y++,d=Math.max(d,r[y].end),E=!0}let x=n(e.slice(f,d),Yr(t.slice(i,g+1),-f),Yr(r.slice(a,y+1),-f));return x?(c({start:f,end:d,insert:x}),i=g+1,a=y+1,!0):!1};for(;i<t.length||a<r.length;){let p=t[i],u=r[a];if(p&&u){if(ep(p,u)){c(p),i++,a++;continue}if(Zc(p,u)){let d=Z(p)&&!Z(u)?hs(e,p,u):Z(u)&&!Z(p)?hs(e,u,p):null;if(d&&Z(p))p=d;else if(d)u=d;else{if(l(p,u))continue;return null}}p.start<u.start||p.start===u.start&&Z(p)?(c(p),i++):(c(u),a++)}else p?(c(p),i++):u&&(c(u),a++)}for(let p=s;p<e.length;p++)o.push(e[p]);return o},tp=(e,t,r,n)=>{let o=Xr(e,t),s=Xr(e,r);return o&&s?ys(e,o,s,n):null},rp=/\s+|[\p{L}\p{N}_$]+\s*|[^\s\p{L}\p{N}_$]\s*/gu,ws=e=>e.match(rp)??[],np=e=>e.flatMap(t=>ws(`${t}
683
- `)),ft=e=>{if(e==="")return[];let t=e.split(`
684
- `);return t[t.length-1]===""&&t.pop(),t},Ht=e=>e.length?`${e.join(`
682
+ `)),!t)throw new Error("Pass the resource name, e.g. `next-maker api invoice`.");D(t,"resource name"),r.feature&&Z(r.feature,"feature path");let s=await N(n);if(!s.hasQuery||!s.hasActions)throw new Error("This generator needs @tanstack/react-query and next-safe-action (starter 2.x).");let i=r.feature?le(n,r.feature):le(n,"src","features",t);if(w(Qr.join(i,"api","schema.ts")))throw new Error(`${Qr.relative(n,i)}/api already exists.`);g.start("Generating api/ files...");let a=await dt({name:t,featurePath:i,withActions:r.actions!==!1});g.succeed("api/ generated"),g.start("Registering API endpoints..."),await wt({serviceName:t,projectPath:n}),g.succeed("Endpoints registered in src/lib/config/app-apis.ts"),await E(n,o),l(Zr.green(`
683
+ \u2728 ${Qr.relative(n,i)}/api ready.
684
+ `));for(let c of a)l(Zr.dim(` ${c}`));l("")}catch(n){g.fail("API generation failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import{readFile as Ms,writeFile as Fp}from"node:fs/promises";import cn from"node:path";import Mp from"enquirer";import G from"picocolors";import{execFile as vp}from"node:child_process";import{cp as Sy,mkdir as Os,readFile as kp,rm as on,stat as Ey,writeFile as Xt}from"node:fs/promises";import se from"node:path";import{promisify as $p}from"node:util";var en=(e,t)=>{let r=e.length,n=t.length;if((r+1)*(n+1)>4e6)return null;let o=n+1,s=new Int32Array((r+1)*o);for(let u=r-1;u>=0;u--)for(let d=n-1;d>=0;d--)s[u*o+d]=e[u]===t[d]?s[(u+1)*o+d+1]+1:Math.max(s[(u+1)*o+d],s[u*o+d+1]);let i=[],a=null,c=0,m=0,p=()=>(a||(a={start:c,end:c,insert:[]},i.push(a)),a);for(;c<r||m<n;){let u=c*o+m;c<r&&m<n&&e[c]===t[m]&&s[u]===s[u+o+1]+1?(a=null,c++,m++):m<n&&(c>=r||s[u+1]>=s[u+o])?(p().insert.push(t[m]),m++):p().end=++c}return i},oe=e=>e.start===e.end,fp=(e,t)=>oe(e)&&oe(t)?!1:oe(e)?t.start<e.start&&e.start<t.end:oe(t)?e.start<t.start&&t.start<e.end:Math.max(e.start,t.start)<Math.min(e.end,t.end),gp=(e,t)=>e.start===t.start&&e.end===t.end&&e.insert.length===t.insert.length&&e.insert.every((r,n)=>r===t.insert[n]),Ss=(e,t,r)=>{let n=t.start,o=t.insert;for(;n<r.end&&o.length>0&&o[0]===e[n];)o=[...o.slice(1),o[0]],n++;if(n===r.end)return{start:n,end:n,insert:o};for(n=t.start,o=t.insert;n>r.start&&o.length>0&&o[o.length-1]===e[n-1];)o=[o[o.length-1],...o.slice(0,-1)],n--;return n===r.start?{start:n,end:n,insert:o}:null},tn=(e,t)=>e.map(r=>({start:r.start+t,end:r.end+t,insert:r.insert})),Es=(e,t,r,n)=>{let o=[],s=0,i=0,a=0,c=p=>{for(let u=s;u<p.start;u++)o.push(e[u]);o.push(...p.insert),s=Math.max(s,p.end)},m=(p,u)=>{if(!n)return!1;let d=Math.min(p.start,u.start),f=Math.max(p.end,u.end),h=i,y=a,x=!0;for(;x;){for(x=!1;h+1<t.length&&t[h+1].start<f;)h++,f=Math.max(f,t[h].end),x=!0;for(;y+1<r.length&&r[y+1].start<f;)y++,f=Math.max(f,r[y].end),x=!0}let b=n(e.slice(d,f),tn(t.slice(i,h+1),-d),tn(r.slice(a,y+1),-d));return b?(c({start:d,end:f,insert:b}),i=h+1,a=y+1,!0):!1};for(;i<t.length||a<r.length;){let p=t[i],u=r[a];if(p&&u){if(gp(p,u)){c(p),i++,a++;continue}if(fp(p,u)){let f=oe(p)&&!oe(u)?Ss(e,p,u):oe(u)&&!oe(p)?Ss(e,u,p):null;if(f&&oe(p))p=f;else if(f)u=f;else{if(m(p,u))continue;return null}}p.start<u.start||p.start===u.start&&oe(p)?(c(p),i++):(c(u),a++)}else p?(c(p),i++):u&&(c(u),a++)}for(let p=s;p<e.length;p++)o.push(e[p]);return o},hp=(e,t,r,n)=>{let o=en(e,t),s=en(e,r);return o&&s?Es(e,o,s,n):null},yp=/\s+|[\p{L}\p{N}_$]+\s*|[^\s\p{L}\p{N}_$]\s*/gu,Ts=e=>e.match(yp)??[],wp=e=>e.flatMap(t=>Ts(`${t}
685
+ `)),kt=e=>{if(e==="")return[];let t=e.split(`
686
+ `);return t[t.length-1]===""&&t.pop(),t},Kt=e=>e.length?`${e.join(`
685
687
  `)}
686
- `:"",op=(e,t,r)=>{let n=[],o=[];for(let l of e)o.push(n.length),n.push(...ws(`${l}
687
- `));o.push(n.length);let s=l=>{let p=[];for(let u of l){let f=o[u.start],d=Xr(n.slice(f,o[u.end]),np(u.insert));if(!d)return null;p.push(...Yr(d,f))}return p},i=s(t),a=s(r);if(!i||!a)return null;let c=ys(n,i,a);return c?ft(c.join("")):null},sp=(e,t,r)=>{let n=tp(ft(t),ft(e),ft(r),op);return n?Ht(n):null},xs=(e,t)=>{let r=e.split(`
688
+ `:"",xp=(e,t,r)=>{let n=[],o=[];for(let m of e)o.push(n.length),n.push(...Ts(`${m}
689
+ `));o.push(n.length);let s=m=>{let p=[];for(let u of m){let d=o[u.start],f=en(n.slice(d,o[u.end]),wp(u.insert));if(!f)return null;p.push(...tn(f,d))}return p},i=s(t),a=s(r);if(!i||!a)return null;let c=Es(n,i,a);return c?kt(c.join("")):null},bp=(e,t,r)=>{let n=hp(kt(t),kt(e),kt(r),xp);return n?Kt(n):null},Rs=(e,t)=>{let r=e.split(`
688
690
  `),n=e.endsWith(`
689
- `);n&&r.pop();let o=[],s=0,i=0;for(;i<r.length;){let a=r[i];if(!a.startsWith("<<<<<<< ")){o.push(a),i++;continue}let c=[],l=[],p=[],u=c;i++;let f=!1;for(;i<r.length;){let g=r[i++];if(u===c&&g.startsWith("||||||| "))u=l;else if((u===c||u===l)&&g==="=======")u=p;else if(u===p&&g.startsWith(">>>>>>> ")){f=!0;break}else u.push(g)}if(!f)throw new Error("Malformed conflict block in merge output.");let d=sp(Ht(c),Ht(l),Ht(p));if(d!==null){o.push(...ft(d));continue}s++,o.push(`<<<<<<< ${t.ours}`,...c,"=======",...p,`>>>>>>> ${t.theirs}`)}return{content:o.join(`
691
+ `);n&&r.pop();let o=[],s=0,i=0;for(;i<r.length;){let a=r[i];if(!a.startsWith("<<<<<<< ")){o.push(a),i++;continue}let c=[],m=[],p=[],u=c;i++;let d=!1;for(;i<r.length;){let h=r[i++];if(u===c&&h.startsWith("||||||| "))u=m;else if((u===c||u===m)&&h==="=======")u=p;else if(u===p&&h.startsWith(">>>>>>> ")){d=!0;break}else u.push(h)}if(!d)throw new Error("Malformed conflict block in merge output.");let f=bp(Kt(c),Kt(m),Kt(p));if(f!==null){o.push(...kt(f));continue}s++,o.push(`<<<<<<< ${t.ours}`,...c,"=======",...p,`>>>>>>> ${t.theirs}`)}return{content:o.join(`
690
692
  `)+(n?`
691
- `:""),conflicts:s}};var pp=cp(ip),lp=new Set(["pnpm-lock.yaml","package-lock.json","yarn.lock","bun.lock","bun.lockb",".next-maker.json","next-env.d.ts","tsconfig.tsbuildinfo"]),mp=e=>{let t=e.split("/").pop()??e;return t===".env.example"?!1:lp.has(e)||t.startsWith(".env")||e.endsWith(".log")},up=new Set([".png",".jpg",".jpeg",".gif",".webp",".avif",".ico",".woff",".woff2",".ttf",".otf",".pdf",".zip",".gz"]),Qr=(e,t)=>up.has(ee.extname(e))||t.subarray(0,8e3).includes(0),Zr=async e=>{try{return await ap(e)}catch{return null}},gt=async(e,t,r)=>{r||(await $s(ee.dirname(e),{recursive:!0}),await qt(e,t))},bs=async(e,t,r,n={ours:"project",base:"starter (previous)",theirs:"starter (new)"})=>{let o=ee.join(process.env.TMPDIR??"/tmp",`next-maker-merge-${process.pid}-${Math.random().toString(36).slice(2)}`);await $s(o,{recursive:!0});try{await qt(ee.join(o,"ours"),e),await qt(ee.join(o,"base"),t),await qt(ee.join(o,"theirs"),r);try{let{stdout:s}=await pp("git",["merge-file","-p","--diff3","-L",n.ours,"-L",n.base,"-L",n.theirs,"ours","base","theirs"],{cwd:o,maxBuffer:67108864});return{content:s,conflicts:0}}catch(s){let i=s;if(typeof i.code=="number"&&i.code>0&&i.code<128&&typeof i.stdout=="string")return xs(i.stdout,n);throw i.code==="ENOENT"?new Error("git is required for merges but was not found on PATH."):s}}finally{await ks(o,{recursive:!0,force:!0})}},vs=["scripts","dependencies","devDependencies","peerDependencies","optionalDependencies","engines"],dp=(e,t,r)=>{let n=structuredClone(e),o=[],s=(a,c)=>JSON.stringify(a)===JSON.stringify(c),i=(a,c,l,p,u,f)=>{let d=l[u],g=p[u],y=c[u];if(!s(d,g)){if(s(y,d)||s(y,g)){g===void 0?delete a[u]:a[u]=g;return}o.push(f)}};for(let a of vs){let c=t[a]??{},l=r[a]??{},p=e[a]??{};n[a]||(n[a]={});let u=n[a];for(let f of new Set([...Object.keys(c),...Object.keys(l)]))i(u,p,c,l,f,`${a}.${f}`);Object.keys(u).length===0&&!(a in r)?delete n[a]:a!=="scripts"&&a!=="engines"&&(n[a]=Object.fromEntries(Object.entries(u).sort(([f],[d])=>f.localeCompare(d))))}for(let a of new Set([...Object.keys(t),...Object.keys(r)]))vs.includes(a)||i(n,e,t,r,a,a);return{result:n,conflicts:o}},qe=async({base:e,theirs:t,ours:r},n={})=>{let o=n.dryRun??!1,s=n.skip??mp,[i,a,c]=await Promise.all([L(e),L(t),L(r)]),l=new Set(c),p=new Set(i),u=new Set(a),f={entries:[],conflicts:[]},d=(g,y,E)=>{f.entries.push({file:g,outcome:y,note:E}),y==="conflict"&&f.conflicts.push(g)};for(let g of[...new Set([...i,...a])].sort()){if(s(g))continue;let y=p.has(g),E=u.has(g),x=l.has(g),[T,j,U]=await Promise.all([y?Zr(ee.join(e,g)):null,E?Zr(ee.join(t,g)):null,x?Zr(ee.join(r,g)):null]),Oe=ee.join(r,g);if(E&&!y){if(!x)await gt(Oe,j,o),d(g,"added");else if(U.equals(j))d(g,"unchanged");else if(Qr(g,j))d(g,"kept","starter added a binary the project also has");else{let ht=await bs(U.toString("utf8"),"",j.toString("utf8"));await gt(Oe,ht.content,o),d(g,ht.conflicts?"conflict":"merged")}continue}if(y&&!E){if(!x)continue;U.equals(T)?(o||await ks(Oe,{force:!0}),d(g,"deleted")):d(g,"kept","starter removed it, but the project changed it");continue}if(!x){d(g,"kept","deleted in the project");continue}if(T.equals(j)||U.equals(j)){d(g,"unchanged");continue}if(U.equals(T)){await gt(Oe,j,o),d(g,"updated");continue}if(Qr(g,U)||Qr(g,j)){d(g,"kept","binary changed on both sides");continue}if(g==="package.json"){let{result:ht,conflicts:yt}=dp(JSON.parse(U.toString("utf8")),JSON.parse(T.toString("utf8")),JSON.parse(j.toString("utf8")));await gt(Oe,`${JSON.stringify(ht,null,2)}
692
- `,o),d(g,yt.length?"conflict":"merged",yt.length?`project kept: ${yt.join(", ")}`:void 0),yt.length&&f.conflicts.pop();continue}let on=await bs(U.toString("utf8"),T.toString("utf8"),j.toString("utf8"));await gt(Oe,on.content,o),d(g,on.conflicts?"conflict":"merged")}return f};import{mkdtemp as fp,readFile as gp,rm as Ps}from"node:fs/promises";import{tmpdir as hp}from"node:os";import ge from"node:path";var Jt=async(e,t)=>{if(t.identity)return me(t.identity.projectName,{...t.identity,copyEnv:!1});let r=JSON.parse(await gp(ge.join(e,"package.json"),"utf-8"));return me(ge.basename(e),{projectName:r.name??ge.basename(e),description:r.description,author:typeof r.author=="string"?r.author:void 0,version:r.version,readme:w(ge.join(e,"README.md")),copyEnv:!1})},Ss=e=>{let t=e.starter.source;if(t.startsWith("/")||t.startsWith(".")){if(!w(t))throw new Error(`The starter this project was generated from is a local path that no longer exists (${t}). Pass --from <ref|dir>.`);return{kind:"local",location:ge.resolve(t)}}return{kind:"remote",location:t}},en=e=>e.startsWith("/")||e.startsWith(".")||w(e)?{kind:"local",location:ge.resolve(e)}:V({ref:e.includes("#")?e.split("#")[1]:e,starterPath:void 0}),Je=async(e,t,r,n,o)=>{let s=await fp(ge.join(hp(),"next-maker-ref-")),i=ge.join(s,r.projectName);try{let a=await ve({projectPath:i,source:e,supplied:t,packageManager:n});return await $e(i,r,a,e),o&&await pr(i,["."],o),{dir:i,scaffold:a,dispose:()=>Ps(s,{recursive:!0,force:!0})}}catch(a){throw await Ps(s,{recursive:!0,force:!0}),a}};import yp from"enquirer";import S from"picocolors";var{prompt:wp}=yp,xp={added:S.green("+"),updated:S.cyan("\u2191"),merged:S.cyan("\u21C4"),deleted:S.red("-"),conflict:S.red("\u2717"),kept:S.yellow("\xB7"),skipped:S.dim("\xB7")},tn=e=>{let t=e.entries.filter(n=>n.outcome!=="unchanged");if(t.length===0){m(S.dim(" no file changes"));return}for(let n of t)m(` ${xp[n.outcome]??" "} ${n.outcome.padEnd(8)} ${n.file}${n.note?S.dim(` (${n.note})`):""}`);let r={};for(let n of t)r[n.outcome]=(r[n.outcome]??0)+1;if(m(""),m(S.dim(` ${Object.entries(r).map(([n,o])=>`${o} ${n}`).join(", ")}`)),t.some(n=>n.file.endsWith(".env.example")&&n.outcome!=="kept")&&(m(""),m(S.yellow(" .env.example changed; check your own .env for new or renamed variables."))),e.conflicts.length){m(""),m(S.red(` ${e.conflicts.length} file(s) need attention; look for <<<<<<< markers:`));for(let n of e.conflicts)m(S.red(` ${n}`))}},Es=e=>{e.command("upgrade").description(`Merge starter changes into this project (default target: ${Et})`).option("--to <ref|dir>","Starter tag or local checkout to upgrade to").option("--from <ref|dir>","Starter the project was generated from (default: recorded at init)").option("--starter-path <dir>","Alias for --to with a local checkout").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Report what would change without writing").option("--no-install","Skip dependency installation afterwards").action(async t=>{let r=process.cwd(),n=[];try{let o=await re(r),s=await Jt(r,o),i=t.from?en(t.from):Ss(o),a=t.to?en(t.to):V({starterPath:t.starterPath,ref:Et});if(i.location===a.location){m(S.dim(`Already on ${a.location}; nothing to upgrade.`));return}m(S.cyan(`
693
+ `:""),conflicts:s}};var Pp=$p(vp),Sp=new Set(["pnpm-lock.yaml","package-lock.json","yarn.lock","bun.lock","bun.lockb",".next-maker.json","next-env.d.ts","tsconfig.tsbuildinfo"]),Ep=e=>{let t=e.split("/").pop()??e;return t===".env.example"?!1:Sp.has(e)||t.startsWith(".env")||e.endsWith(".log")},Tp=new Set([".png",".jpg",".jpeg",".gif",".webp",".avif",".ico",".woff",".woff2",".ttf",".otf",".pdf",".zip",".gz"]),rn=(e,t)=>Tp.has(se.extname(e))||t.subarray(0,8e3).includes(0),nn=async e=>{try{return await kp(e)}catch{return null}},Qe=async(e,t,r)=>{r||(await Os(se.dirname(e),{recursive:!0}),await Xt(e,t))},js=async(e,t,r,n={ours:"project",base:"starter (previous)",theirs:"starter (new)"})=>{let o=se.join(process.env.TMPDIR??"/tmp",`next-maker-merge-${process.pid}-${Math.random().toString(36).slice(2)}`);await Os(o,{recursive:!0});try{await Xt(se.join(o,"ours"),e),await Xt(se.join(o,"base"),t),await Xt(se.join(o,"theirs"),r);try{let{stdout:s}=await Pp("git",["merge-file","-p","--diff3","-L",n.ours,"-L",n.base,"-L",n.theirs,"ours","base","theirs"],{cwd:o,maxBuffer:67108864});return{content:s,conflicts:0}}catch(s){let i=s;if(typeof i.code=="number"&&i.code>0&&i.code<128&&typeof i.stdout=="string")return Rs(i.stdout,n);throw i.code==="ENOENT"?new Error("git is required for merges but was not found on PATH."):s}}finally{await on(o,{recursive:!0,force:!0})}},Cs=["scripts","dependencies","devDependencies","peerDependencies","optionalDependencies","engines"],Rp=(e,t,r)=>{let n=structuredClone(e),o=[],s=(a,c)=>JSON.stringify(a)===JSON.stringify(c),i=(a,c,m,p,u,d)=>{let f=m[u],h=p[u],y=c[u];if(!s(f,h)){if(s(y,f)||s(y,h)){h===void 0?delete a[u]:a[u]=h;return}o.push(d)}};for(let a of Cs){let c=t[a]??{},m=r[a]??{},p=e[a]??{};n[a]||(n[a]={});let u=n[a];for(let d of new Set([...Object.keys(c),...Object.keys(m)]))i(u,p,c,m,d,`${a}.${d}`);Object.keys(u).length===0&&!(a in r)?delete n[a]:a!=="scripts"&&a!=="engines"&&(n[a]=Object.fromEntries(Object.entries(u).sort(([d],[f])=>d.localeCompare(f))))}for(let a of new Set([...Object.keys(t),...Object.keys(r)]))Cs.includes(a)||i(n,e,t,r,a,a);return{result:n,conflicts:o}},Ze=async({base:e,theirs:t,ours:r},n={})=>{let o=n.dryRun??!1,s=n.skip??Ep,[i,a,c]=await Promise.all([I(e),I(t),I(r)]),m=new Set(c),p=new Set(i),u=new Set(a),d={entries:[],conflicts:[]},f=(x,b,P)=>{d.entries.push({file:x,outcome:b,note:P}),b==="conflict"&&d.conflicts.push(x)},h=n.variant??(()=>!1),y=new Set([...i,...a,...c.filter(h)]);for(let x of[...y].sort()){if(s(x))continue;let b=p.has(x),P=u.has(x),C=m.has(x),[H,B,q]=await Promise.all([b?nn(se.join(e,x)):null,P?nn(se.join(t,x)):null,C?nn(se.join(r,x)):null]),J=se.join(r,x);if(h(x)){if(P){let ie=C&&q.equals(B);ie||await Qe(J,B,o),f(x,ie?"unchanged":C?"replaced":"added")}else C&&(o||await on(J,{force:!0}),f(x,"deleted","belonged to the variant you switched away from"));continue}if(P&&!b){if(!C)await Qe(J,B,o),f(x,"added");else if(q.equals(B))f(x,"unchanged");else if(rn(x,B))f(x,"kept","starter added a binary the project also has");else{let ie=await js(q.toString("utf8"),"",B.toString("utf8"));await Qe(J,ie.content,o),f(x,ie.conflicts?"conflict":"merged")}continue}if(b&&!P){if(!C)continue;q.equals(H)?(o||await on(J,{force:!0}),f(x,"deleted")):f(x,"kept","starter removed it, but the project changed it");continue}if(!C){f(x,"kept","deleted in the project");continue}if(H.equals(B)||q.equals(B)){f(x,"unchanged");continue}if(q.equals(H)){await Qe(J,B,o),f(x,"updated");continue}if(rn(x,q)||rn(x,B)){f(x,"kept","binary changed on both sides");continue}if(x==="package.json"){let{result:ie,conflicts:$t}=Rp(JSON.parse(q.toString("utf8")),JSON.parse(H.toString("utf8")),JSON.parse(B.toString("utf8")));await Qe(J,`${JSON.stringify(ie,null,2)}
694
+ `,o),f(x,$t.length?"conflict":"merged",$t.length?`project kept: ${$t.join(", ")}`:void 0),$t.length&&d.conflicts.pop();continue}let S=await js(q.toString("utf8"),H.toString("utf8"),B.toString("utf8"));await Qe(J,S.content,o),f(x,S.conflicts?"conflict":"merged")}return d};import{mkdtemp as jp,readFile as Cp,rm as As}from"node:fs/promises";import{tmpdir as Op}from"node:os";import ve from"node:path";var Yt=async(e,t)=>{if(t.identity)return ye(t.identity.projectName,{...t.identity,copyEnv:!1});let r=JSON.parse(await Cp(ve.join(e,"package.json"),"utf-8"));return ye(ve.basename(e),{projectName:r.name??ve.basename(e),description:r.description,author:typeof r.author=="string"?r.author:void 0,version:r.version,readme:w(ve.join(e,"README.md")),copyEnv:!1})},Is=e=>{let t=e.starter.source;if(t.startsWith("/")||t.startsWith(".")){if(!w(t))throw new Error(`The starter this project was generated from is a local path that no longer exists (${t}). Pass --from <ref|dir>.`);return{kind:"local",location:ve.resolve(t)}}return{kind:"remote",location:t}},sn=e=>e.startsWith("/")||e.startsWith(".")||w(e)?{kind:"local",location:ve.resolve(e)}:z({ref:e.includes("#")?e.split("#")[1]:e,starterPath:void 0}),et=async(e,t,r,n,o)=>{let s=await jp(ve.join(Op(),"next-maker-ref-")),i=ve.join(s,r.projectName);try{let a=await Re({projectPath:i,source:e,supplied:t,packageManager:n});return await je(i,r,a,e),o&&await ut(i,["."],o),{dir:i,scaffold:a,dispose:()=>As(s,{recursive:!0,force:!0})}}catch(a){throw await As(s,{recursive:!0,force:!0}),a}};import Ap from"enquirer";import T from"picocolors";var{prompt:Ip}=Ap,Np={added:T.green("+"),updated:T.cyan("\u2191"),merged:T.cyan("\u21C4"),deleted:T.red("-"),conflict:T.red("\u2717"),replaced:T.cyan("\u21C9"),kept:T.yellow("\xB7"),skipped:T.dim("\xB7")},an=e=>{let t=e.entries.filter(n=>n.outcome!=="unchanged");if(t.length===0){l(T.dim(" no file changes"));return}for(let n of t)l(` ${Np[n.outcome]??" "} ${n.outcome.padEnd(8)} ${n.file}${n.note?T.dim(` (${n.note})`):""}`);let r={};for(let n of t)r[n.outcome]=(r[n.outcome]??0)+1;if(l(""),l(T.dim(` ${Object.entries(r).map(([n,o])=>`${o} ${n}`).join(", ")}`)),t.some(n=>n.file.endsWith(".env.example")&&n.outcome!=="kept")&&(l(""),l(T.yellow(" .env.example changed; check your own .env for new or renamed variables."))),e.conflicts.length){l(""),l(T.red(` ${e.conflicts.length} file(s) need attention; look for <<<<<<< markers:`));for(let n of e.conflicts)l(T.red(` ${n}`))}},Ns=e=>{e.command("upgrade").description(`Merge starter changes into this project (default target: ${At})`).option("--to <ref|dir>","Starter tag or local checkout to upgrade to").option("--from <ref|dir>","Starter the project was generated from (default: recorded at init)").option("--starter-path <dir>","Alias for --to with a local checkout").option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Report what would change without writing").option("--no-install","Skip dependency installation afterwards").action(async t=>{let r=process.cwd(),n=[];try{let o=await pe(r),s=await Yt(r,o),i=t.from?sn(t.from):Is(o),a=t.to?sn(t.to):z({starterPath:t.starterPath,ref:At});if(i.location===a.location){l(T.dim(`Already on ${a.location}; nothing to upgrade.`));return}l(T.cyan(`
693
695
  \u2B06 Upgrade
694
- `)),m(` ${S.dim("from")} ${i.location}`),m(` ${S.dim("to ")} ${a.location}
695
- `);let c=await Je(i,o.answers,s,o.packageManager,r);n.push(c.dispose);let l=await Je(a,o.answers,s,o.packageManager,r);n.push(l.dispose);for(let d of l.scaffold.forced)m(S.yellow(` ! ${d.reason}; ${d.option} turned off`));for(let d of l.scaffold.unknown)m(S.yellow(` ! option "${d}" no longer exists in the new starter`));let p=await qe({base:c.dir,theirs:l.dir,ours:r},{dryRun:!0});if(tn(p),t.dryRun){m(S.dim(`
696
+ `)),l(` ${T.dim("from")} ${i.location}`),l(` ${T.dim("to ")} ${a.location}
697
+ `);let c=await et(i,o.answers,s,o.packageManager,r);n.push(c.dispose);let m=await et(a,o.answers,s,o.packageManager,r);n.push(m.dispose);for(let f of m.scaffold.forced)l(T.yellow(` ! ${f.reason}; ${f.option} turned off`));for(let f of m.scaffold.unknown)l(T.yellow(` ! option "${f}" no longer exists in the new starter`));let p=await Ze({base:c.dir,theirs:m.dir,ours:r},{dryRun:!0});if(an(p),t.dryRun){l(T.dim(`
696
698
  Dry run: nothing was written.
697
- `));return}if(!t.yes){let{confirm:d}=await wp({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!d){m(S.yellow(`Aborted.
698
- `));return}}let u=Date.now(),f=await qe({base:c.dir,theirs:l.dir,ours:r});await k(r,u),await ue(r,{...o,cli:Ae.version,starter:{...l.scaffold.manifest.starter,source:a.location},answers:l.scaffold.answers,identity:o.identity??{projectName:s.projectName,description:s.description,author:s.author,version:s.version,email:s.email,gitRemote:s.gitRemote,readme:s.readme}}),t.install!==!1&&(m(S.dim(`
699
- Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(S.green(`
700
- \u2713 Upgraded to ${l.scaffold.manifest.starter.version}.`)),f.conflicts.length?m(S.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")):m(S.dim(" Run `next-maker doctor --compile` to confirm.")),m("")}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};var{prompt:vp}=bp,$p=(e,t=[])=>[...t,e],Ts=e=>{e.command("setup").description("Turn starter features on or off in an existing project (e.g. --set ws=true)").option("--set <key=value>","Option to change (repeatable), e.g. --set i18n=false --set state=zustand",$p).option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").option("--starter-path <dir>","Use a local starter checkout").action(async t=>{let r=process.cwd(),n=[];try{let o=await re(r),s=xe(t.set);if(Object.keys(s).length===0)throw new Error("Nothing to change. Pass at least one --set key=value (run `next-maker options` to list them).");let i=await De(o,{starterPath:t.starterPath});n.push(i.dispose);let{answers:a,forced:c,unknown:l}=Ye(i.manifest,{...o.answers,...s});for(let x of l)m(q.yellow(` ! unknown option "${x}" ignored`));for(let x of c)m(q.yellow(` ! ${x.reason}; ${x.option} turned off`));let p=Object.keys(a).filter(x=>JSON.stringify(a[x])!==JSON.stringify(o.answers[x]));if(m(q.cyan(`
699
+ `));return}if(!t.yes){let{confirm:f}=await Ip({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!f){l(T.yellow(`Aborted.
700
+ `));return}}let u=Date.now(),d=await Ze({base:c.dir,theirs:m.dir,ours:r});await E(r,u),await we(r,{...o,cli:De.version,starter:{...m.scaffold.manifest.starter,source:a.location},answers:m.scaffold.answers,identity:o.identity??{projectName:s.projectName,description:s.description,author:s.author,version:s.version,email:s.email,gitRemote:s.gitRemote,readme:s.readme}}),t.install!==!1&&(l(T.dim(`
701
+ Installing with ${o.packageManager}...`)),await he(r,o.packageManager)),l(T.green(`
702
+ \u2713 Upgraded to ${m.scaffold.manifest.starter.version}.`)),d.conflicts.length?l(T.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")):l(T.dim(" Run `next-maker doctor --compile` to confirm.")),l("")}catch(o){v(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};var{prompt:_p}=Mp,Dp=(e,t=[])=>[...t,e],Fs=async(e,t,r)=>{let n=i=>i.some(a=>r.has(a)),o=[],s=[...t.unwrapJsx.filter(i=>n(i.options)).map(i=>[i.file,a=>$e(a,i.tag)]),...t.unwrapCall.filter(i=>n(i.options)).map(i=>[i.file,a=>Pe(a,i.name)])];for(let[i,a]of s){let c=cn.join(e,i),m;try{m=await Ms(c,"utf-8")}catch{continue}let p=a(m);p!==m&&(await Fp(c,p),o.includes(i)||o.push(i))}return o},Lp=async(e,t,r,n)=>{let o=a=>a.some(c=>n.has(c)),s=new Set;for(let{plan:a}of r)for(let c of a.featureOverlays)if(o(c.options))for(let m of await I(cn.join(e,ae,c.name),new Set))s.add(m);let i=r.flatMap(({plan:a})=>a.featureRemovals.filter(c=>o(c.options)).flatMap(c=>c.patterns));if(i.length){let a=await I(t);for(let c of i)for(let m of Y(a,c))s.add(m)}return s},Up=async(e,t)=>{let r=[...t.packages,...t.devPackages];if(r.length===0)return[];let n=(await I(e)).filter(s=>/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(s)),o=[];for(let s of n){let i;try{i=await Ms(cn.join(e,s),"utf-8")}catch{continue}let a=r.filter(c=>new RegExp(`from ['"]${c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(/[^'"]*)?['"]`).test(i));a.length&&o.push({file:s,packages:a})}return o},_s=e=>{e.command("setup").description("Turn starter features on or off in an existing project (e.g. --set ws=true)").option("--set <key=value>","Option to change (repeatable), e.g. --set i18n=false --set state=zustand",Dp).option("-y, --yes","Skip the confirmation prompt").option("--dry-run","Print the plan without writing").option("--no-install","Skip dependency installation after the change").option("--starter-path <dir>","Use a local starter checkout").action(async t=>{let r=process.cwd(),n=[];try{let o=await pe(r),s=Ee(t.set);if(Object.keys(s).length===0)throw new Error("Nothing to change. Pass at least one --set key=value (run `next-maker options` to list them).");let i=await He(o,{starterPath:t.starterPath});n.push(i.dispose);let{answers:a,forced:c,unknown:m}=nt(i.manifest,{...o.answers,...s});for(let S of m)l(G.yellow(` ! unknown option "${S}" ignored`));for(let S of c)l(G.yellow(` ! ${S.reason}; ${S.option} turned off`));let p=Object.keys(a).filter(S=>JSON.stringify(a[S])!==JSON.stringify(o.answers[S]));if(l(G.cyan(`
701
703
  \u{1F527} Setup
702
- `)),p.length===0){m(q.dim(`No option changes; the project already has these values.
703
- `));return}for(let x of p)m(` ${q.dim(x.padEnd(18))} ${String(o.answers[x])} ${q.dim("\u2192")} ${String(a[x])}`);m("");let u=await Jt(r,o),f=await Je(i.source,o.answers,u,o.packageManager,r);n.push(f.dispose);let d=await Je(i.source,a,u,o.packageManager,r);n.push(d.dispose);let g=await qe({base:f.dir,theirs:d.dir,ours:r},{dryRun:!0});if(tn(g),t.dryRun){m(q.dim(`
704
+ `)),p.length===0){l(G.dim(`No option changes; the project already has these values.
705
+ `));return}for(let S of p)l(` ${G.dim(S.padEnd(18))} ${String(o.answers[S])} ${G.dim("\u2192")} ${String(a[S])}`);l("");let u=await Yt(r,o),d=await et(i.source,o.answers,u,o.packageManager,r);n.push(d.dispose);let f=await et(i.source,a,u,o.packageManager,r);n.push(f.dispose);let h=new Set(p),y=await Lp(i.dir,r,[d.scaffold,f.scaffold],h),x={variant:S=>y.has(S)},b=await Fs(r,f.scaffold.plan,h),P=await Fs(d.dir,f.scaffold.plan,h);P.length&&await ut(d.dir,P,r,!0);for(let S of b)l(G.dim(` unwrapped in place: ${S}`));let C=await Ze({base:d.dir,theirs:f.dir,ours:r},{...x,dryRun:!0});if(an(C),t.dryRun){l(G.dim(`
704
706
  Dry run: nothing was written.
705
- `));return}if(!t.yes){let{confirm:x}=await vp({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!x){m(q.yellow(`Aborted.
706
- `));return}}let y=Date.now(),E=await qe({base:f.dir,theirs:d.dir,ours:r});await k(r,y),await ue(r,{...o,answers:a}),t.install!==!1&&(m(q.dim(`
707
- Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(q.green(`
708
- \u2713 Applied.`)),E.conflicts.length&&m(q.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")),m("")}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};import rn from"node:path";import zt from"picocolors";import kp from"enquirer";var{prompt:Pp}=kp,js=async(e,t)=>{let r=[];e||r.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:o=>/^[a-z0-9-]+$/.test(o)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),t===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let n=r.length>0?await Pp(r):{};return{sliceName:e||n.sliceName,persistSlice:t===void 0?n.persistSlice||!1:t}};var Rs=e=>{e.command("slice [name]").description("Generate a store slice (Redux or Zustand, whichever the project uses)").option("--path <path>","Directory for the slice (default: src/store/slices/<name>)").option("--persist","Persist the slice across reloads (Redux)").option("--no-persist","Do not persist the slice").option("--test","Also generate a sibling test file (Redux)").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(zt.cyan(`
707
+ `));return}if(!t.yes){let{confirm:S}=await _p({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!S){l(G.yellow(`Aborted.
708
+ `));return}}let H=Date.now(),B=await Ze({base:d.dir,theirs:f.dir,ours:r},x);await E(r,H),await we(r,{...o,answers:a}),t.install!==!1&&(l(G.dim(`
709
+ Installing with ${o.packageManager}...`)),await he(r,o.packageManager));let q=B.entries.filter(S=>S.outcome==="replaced"||S.outcome==="deleted"&&S.note).length;q>0&&(l(""),l(G.dim(` ${q} file(s) came from the variant you switched; run \`next-maker doctor --compile\` to catch code of your own that no longer builds.`)));let J=await Up(r,f.scaffold.plan);if(J.length){l(""),l(G.yellow(" Still importing packages this change removed; port them by hand:"));for(let{file:S,packages:ie}of J)l(G.yellow(` ${S} \u2014 ${ie.join(", ")}`))}l(G.green(`
710
+ \u2713 Applied.`)),B.conflicts.length&&l(G.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")),l("")}catch(o){v(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{for(let o of n)await o()}})};import pn from"node:path";import Qt from"picocolors";import Bp from"enquirer";var{prompt:Gp}=Bp,Ds=async(e,t)=>{let r=[];e||r.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:o=>/^[a-z0-9-]+$/.test(o)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),t===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let n=r.length>0?await Gp(r):{};return{sliceName:e||n.sliceName,persistSlice:t===void 0?n.persistSlice||!1:t}};var Ls=e=>{e.command("slice [name]").description("Generate a store slice (Redux or Zustand, whichever the project uses)").option("--path <path>","Directory for the slice (default: src/store/slices/<name>)").option("--persist","Persist the slice across reloads (Redux)").option("--no-persist","Do not persist the slice").option("--test","Also generate a sibling test file (Redux)").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();l(Qt.cyan(`
709
711
  \u{1F527} Slice Generator
710
- `)),h.start("Detecting project setup...");let s=await O(n);if(h.succeed("Project setup detected"),s.state==="none")throw new Error("This project has no client store. Re-run init with a state store, or add one with `next-maker setup --set state=redux`.");m(zt.dim(` state: ${s.state}
711
- `));let i=await js(t,s.state==="zustand"?!1:r.persist);M(i.sliceName,"slice name"),r.path&&W(r.path,"path");let a=r.path??rn.join("src","store","slices"),c=ne(n,a,i.sliceName);if(await ke(n,i.sliceName,a))throw new Error(`Slice '${i.sliceName}' already exists at ${a}.`);h.start("Generating slice files..."),await it({name:i.sliceName,outputPath:c,persist:i.persistSlice,state:s.state}),h.succeed("Slice files generated"),s.state==="redux"&&(h.start("Registering slice in the store..."),await mt({projectPath:n,name:i.sliceName,persist:i.persistSlice,importPath:rn.join(a,i.sliceName)}),h.succeed("Slice registered"),(r.test??s.hasTests)&&(h.start("Generating test..."),await oe({projectPath:n,sourceFile:rn.join(c,`${i.sliceName}.slice.ts`),kind:"slice",symbolName:i.sliceName.replace(/-([a-z])/g,(l,p)=>p.toUpperCase())}),h.succeed("Test generated"))),await k(n,o),m(zt.green(`
712
+ `)),g.start("Detecting project setup...");let s=await N(n);if(g.succeed("Project setup detected"),s.state==="none")throw new Error("This project has no client store. Re-run init with a state store, or add one with `next-maker setup --set state=redux`.");l(Qt.dim(` state: ${s.state}
713
+ `));let i=await Ds(t,s.state==="zustand"?!1:r.persist);D(i.sliceName,"slice name"),r.path&&Z(r.path,"path");let a=r.path??pn.join("src","store","slices"),c=le(n,a,i.sliceName);if(await Ce(n,i.sliceName,a))throw new Error(`Slice '${i.sliceName}' already exists at ${a}.`);g.start("Generating slice files..."),await ft({name:i.sliceName,outputPath:c,persist:i.persistSlice,state:s.state}),g.succeed("Slice files generated"),s.state==="redux"&&(g.start("Registering slice in the store..."),await xt({projectPath:n,name:i.sliceName,persist:i.persistSlice,importPath:pn.join(a,i.sliceName)}),g.succeed("Slice registered"),(r.test??s.hasTests)&&(g.start("Generating test..."),await me({projectPath:n,sourceFile:pn.join(c,`${i.sliceName}.slice.ts`),kind:"slice",symbolName:i.sliceName.replace(/-([a-z])/g,(m,p)=>p.toUpperCase())}),g.succeed("Test generated"))),await E(n,o),l(Qt.green(`
712
714
  \u2728 Slice '${i.sliceName}' created in ${a}/${i.sliceName}/.
713
- `)),s.state==="zustand"&&(m(zt.yellow(` ! Compose create${$(i.sliceName)}Slice into AppState in src/store/index.ts`)),m(""))}catch(n){h.fail("Slice generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import J from"node:path";import nn from"picocolors";var Cs=e=>{e.command("test <file>").description(`Generate a sibling test file for an existing component, hook, or slice.
714
- Infers the kind from filename/content; pass --kind to override.`).option("--kind <kind>","Override inferred kind: component | hook | slice").option("--force","Overwrite an existing test file").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now(),s=J.isAbsolute(t)?t:J.join(n,t);m(nn.cyan(`
715
+ `)),s.state==="zustand"&&(l(Qt.yellow(` ! Compose create${$(i.sliceName)}Slice into AppState in src/store/index.ts`)),l(""))}catch(n){g.fail("Slice generation failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import X from"node:path";import ln from"picocolors";var Us=e=>{e.command("test <file>").description(`Generate a sibling test file for an existing component, hook, or slice.
716
+ Infers the kind from filename/content; pass --kind to override.`).option("--kind <kind>","Override inferred kind: component | hook | slice").option("--force","Overwrite an existing test file").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now(),s=X.isAbsolute(t)?t:X.join(n,t);l(ln.cyan(`
715
717
  \u{1F9EA} Test Generator
716
- `)),w(s)||(b(`Source file not found: ${t}`),process.exit(1));let i=await O(n);i.hasTests||(b("Testing is not installed in this project. Run `next-maker setup --tests` first."),process.exit(1));let a=await R(s),c=Sp(r.kind)??Ep(s,a);c||(b(`Could not infer test kind for ${J.basename(s)}. Pass --kind component|hook|slice.`),process.exit(1));let l=Tp(s,c),p=jp(s,c);w(p)&&!r.force&&(b(`Test file already exists: ${J.relative(n,p)}. Use --force to overwrite.`),process.exit(1)),h.start(`Generating ${c} test...`);let u=await oe({projectPath:n,sourceFile:s,kind:c,symbolName:l,hasState:i.state!=="none",hasI18n:i.hasI18n,hookUsesStore:c==="hook"&&i.state!=="none"&&a.includes("useAppSelector")});h.succeed("Test generated"),await k(n,o),m(nn.green(`
717
- \u2728 Test '${J.basename(u)}' created.
718
- `)),m(nn.dim(` \u{1F9EA} ${J.relative(n,u)}`)),m("")}catch(n){h.fail("Test generation failed"),b(`${n}`),process.exit(1)}})},Sp=e=>{if(!e)return null;if(e==="component"||e==="hook"||e==="slice")return e;throw new Error(`Invalid --kind: ${e}. Use component | hook | slice.`)},Ep=(e,t)=>{let r=J.basename(e);return/\.slice\.ts$/.test(r)?"slice":/^use[A-Z]/.test(r.replace(/\.tsx?$/,""))?"hook":r.endsWith(".tsx")?"component":/createSlice\s*\(/.test(t)?"slice":/^export\s+(const|function)\s+use[A-Z]/m.test(t)?"hook":null},Tp=(e,t)=>{let r=J.basename(e).replace(/\.(tsx?|jsx?)$/i,"");return t==="slice"?G(r.replace(/\.slice$/,"")):t==="hook"?/^use[A-Z]/.test(r)?r:`use${$(r.replace(/^use-?/,""))}`:$(r)},jp=(e,t)=>{let r=J.dirname(e),n=J.basename(e).replace(/\.(tsx?|jsx?)$/i,""),o=t==="component"?".tsx":".ts";return J.join(r,`${n}.test${o}`)};import{chmod as Rp,cp as Cp,mkdir as Wt,readFile as Kt,rm as Op,writeFile as N}from"node:fs/promises";import v from"node:path";import he from"picocolors";var Os=e=>{let t={"@biomejs/biome":e.biomeVersion,turbo:e.turboVersion};e.hooks&&(e.huskyVersion&&(t.husky=e.huskyVersion),e.lintStagedVersion&&(t["lint-staged"]=e.lintStagedVersion),e.commitlintCliVersion&&(t["@commitlint/cli"]=e.commitlintCliVersion),e.commitlintConfigVersion&&(t["@commitlint/config-conventional"]=e.commitlintConfigVersion));let r={name:e.name,version:"0.1.0",description:e.description,author:e.author,private:!0,type:"module",packageManager:e.packageManagerPin,engines:{node:e.nodeEngine,pnpm:">=11.0.0"},scripts:{dev:"turbo run dev",build:"turbo run build",start:"turbo run start",lint:"turbo run lint","lint:fix":"biome check --write . && turbo run lint:fix","ci:check":"biome ci . && turbo run ci:check","type-check":"turbo run type-check","check:deprecated":"turbo run check:deprecated",test:"turbo run test","test:e2e":"turbo run test:e2e",validate:"pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test && pnpm build",...e.hooks?{prepare:"husky","lint-staged":"lint-staged"}:{}},devDependencies:Object.fromEntries(Object.entries(t).sort())};return`${JSON.stringify(r,null,2)}
719
- `},As=e=>`packages:
718
+ `)),w(s)||(v(`Source file not found: ${t}`),process.exit(1));let i=await N(n);i.hasTests||(v("Testing is not installed in this project. Run `next-maker setup --tests` first."),process.exit(1));let a=await O(s),c=Vp(r.kind)??Hp(s,a);c||(v(`Could not infer test kind for ${X.basename(s)}. Pass --kind component|hook|slice.`),process.exit(1));let m=qp(s,c),p=Jp(s,c);w(p)&&!r.force&&(v(`Test file already exists: ${X.relative(n,p)}. Use --force to overwrite.`),process.exit(1)),g.start(`Generating ${c} test...`);let u=await me({projectPath:n,sourceFile:s,kind:c,symbolName:m,hasState:i.state!=="none",hasI18n:i.hasI18n,hookUsesStore:c==="hook"&&i.state!=="none"&&a.includes("useAppSelector")});g.succeed("Test generated"),await E(n,o),l(ln.green(`
719
+ \u2728 Test '${X.basename(u)}' created.
720
+ `)),l(ln.dim(` \u{1F9EA} ${X.relative(n,u)}`)),l("")}catch(n){g.fail("Test generation failed"),v(`${n}`),process.exit(1)}})},Vp=e=>{if(!e)return null;if(e==="component"||e==="hook"||e==="slice")return e;throw new Error(`Invalid --kind: ${e}. Use component | hook | slice.`)},Hp=(e,t)=>{let r=X.basename(e);return/\.slice\.ts$/.test(r)?"slice":/^use[A-Z]/.test(r.replace(/\.tsx?$/,""))?"hook":r.endsWith(".tsx")?"component":/createSlice\s*\(/.test(t)?"slice":/^export\s+(const|function)\s+use[A-Z]/m.test(t)?"hook":null},qp=(e,t)=>{let r=X.basename(e).replace(/\.(tsx?|jsx?)$/i,"");return t==="slice"?V(r.replace(/\.slice$/,"")):t==="hook"?/^use[A-Z]/.test(r)?r:`use${$(r.replace(/^use-?/,""))}`:$(r)},Jp=(e,t)=>{let r=X.dirname(e),n=X.basename(e).replace(/\.(tsx?|jsx?)$/i,""),o=t==="component"?".tsx":".ts";return X.join(r,`${n}.test${o}`)};import{chmod as Wp,cp as zp,mkdir as Zt,readFile as er,rm as Kp,writeFile as M}from"node:fs/promises";import k from"node:path";import ke from"picocolors";var Bs=e=>{let t={"@biomejs/biome":e.biomeVersion,turbo:e.turboVersion};e.hooks&&(e.huskyVersion&&(t.husky=e.huskyVersion),e.lintStagedVersion&&(t["lint-staged"]=e.lintStagedVersion),e.commitlintCliVersion&&(t["@commitlint/cli"]=e.commitlintCliVersion),e.commitlintConfigVersion&&(t["@commitlint/config-conventional"]=e.commitlintConfigVersion));let r={name:e.name,version:"0.1.0",description:e.description,author:e.author,private:!0,type:"module",packageManager:e.packageManagerPin,engines:{node:e.nodeEngine,pnpm:">=11.0.0"},scripts:{dev:"turbo run dev",build:"turbo run build",start:"turbo run start",lint:"turbo run lint","lint:fix":"biome check --write . && turbo run lint:fix","ci:check":"biome ci . && turbo run ci:check","type-check":"turbo run type-check","check:deprecated":"turbo run check:deprecated",test:"turbo run test","test:e2e":"turbo run test:e2e",validate:"pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test && pnpm build",...e.hooks?{prepare:"husky","lint-staged":"lint-staged"}:{}},devDependencies:Object.fromEntries(Object.entries(t).sort())};return`${JSON.stringify(r,null,2)}
721
+ `},Gs=e=>`packages:
720
722
  - 'apps/*'
721
723
  - 'packages/*'
722
724
 
723
725
  ${e.split(`
724
726
  `).filter(r=>!r.startsWith("packages:")&&!r.startsWith("# Single-package")&&!r.startsWith("# Monorepo mode")).join(`
725
727
  `).trim()}
726
- `,Is=()=>`${JSON.stringify({$schema:"https://turborepo.com/schema.json",ui:"tui",globalEnv:["NODE_ENV","CI"],globalPassThroughEnv:["NEXT_PUBLIC_*","API_INTERNAL_URL","CSP_MODE","BUILD_STANDALONE","DEFAULT_TIMEZONE","DEFAULT_LOCALE","NEXT_TELEMETRY_DISABLED"],tasks:{build:{dependsOn:["^build"],inputs:["$TURBO_DEFAULT$",".env.production",".env"],outputs:[".next/**","!.next/cache/**"]},dev:{cache:!1,persistent:!0},start:{cache:!1,persistent:!0,dependsOn:["build"]},lint:{},"lint:fix":{cache:!1},"ci:check":{},"type-check":{dependsOn:["^build"]},"check:deprecated":{dependsOn:["^build"]},test:{dependsOn:["^build"],outputs:["coverage/**"]},"test:e2e":{dependsOn:["build"],cache:!1}}},null,2)}
727
- `,Ns=e=>`${JSON.stringify({$schema:`https://biomejs.dev/schemas/${e.replace(/^[\^~]/,"")}/schema.json`,vcs:{enabled:!0,clientKind:"git",useIgnoreFile:!0},files:{includes:["*.json","*.mjs","*.ts",".github/**","!apps","!packages"]},formatter:{enabled:!0,indentStyle:"space",indentWidth:2,lineWidth:100,lineEnding:"lf"},javascript:{formatter:{quoteStyle:"single",semicolons:"always",trailingCommas:"all"}},json:{formatter:{trailingCommas:"none"}},linter:{enabled:!0,rules:{preset:"recommended"}}},null,2)}
728
- `,Fs=()=>`# dependencies
728
+ `,Vs=()=>`${JSON.stringify({$schema:"https://turborepo.com/schema.json",ui:"tui",globalEnv:["NODE_ENV","CI"],globalPassThroughEnv:["NEXT_PUBLIC_*","API_INTERNAL_URL","CSP_MODE","BUILD_STANDALONE","DEFAULT_TIMEZONE","DEFAULT_LOCALE","NEXT_TELEMETRY_DISABLED"],tasks:{build:{dependsOn:["^build"],inputs:["$TURBO_DEFAULT$",".env.production",".env"],outputs:[".next/**","!.next/cache/**"]},dev:{cache:!1,persistent:!0},start:{cache:!1,persistent:!0,dependsOn:["build"]},lint:{},"lint:fix":{cache:!1},"ci:check":{},"type-check":{dependsOn:["^build"]},"check:deprecated":{dependsOn:["^build"]},test:{dependsOn:["^build"],outputs:["coverage/**"]},"test:e2e":{dependsOn:["build"],cache:!1}}},null,2)}
729
+ `,Hs=e=>`${JSON.stringify({$schema:`https://biomejs.dev/schemas/${e.replace(/^[\^~]/,"")}/schema.json`,vcs:{enabled:!0,clientKind:"git",useIgnoreFile:!0},files:{includes:["*.json","*.mjs","*.ts",".github/**","!apps","!packages"]},formatter:{enabled:!0,indentStyle:"space",indentWidth:2,lineWidth:100,lineEnding:"lf"},javascript:{formatter:{quoteStyle:"single",semicolons:"always",trailingCommas:"all"}},json:{formatter:{trailingCommas:"none"}},linter:{enabled:!0,rules:{preset:"recommended"}}},null,2)}
730
+ `,qs=()=>`# dependencies
729
731
  node_modules
730
732
  .pnpm-store
731
733
 
@@ -751,7 +753,7 @@ next-env.d.ts
751
753
  *.pem
752
754
  npm-debug.log*
753
755
  .pnpm-debug.log*
754
- `,Ms=(e,t)=>`# ${e.name}
756
+ `,Js=(e,t)=>`# ${e.name}
755
757
 
756
758
  ${e.description}
757
759
 
@@ -799,10 +801,13 @@ Give the package a \`build\` script (or point \`exports\` at TypeScript sources
799
801
  ## Adding an app
800
802
 
801
803
  \`\`\`bash
802
- cd apps && npx @teispace/next-maker init <name> --yes --set hooks=false --set commitizen=false --set ci=false --set docker=false --no-git
804
+ cd apps && npx @teispace/next-maker init <name> --yes
803
805
  \`\`\`
804
806
 
805
- Git hooks, CI, and Docker live at the workspace root; apps keep their own tests, lint, and type-check.
807
+ \`init\` sees the workspace above it and shapes the app to match its siblings:
808
+ git hooks, CI, Docker and the lockfile stay at the root, dependency ranges
809
+ come from the root catalog, and the install runs from the root. Apps keep
810
+ their own tests, lint, and type-check.
806
811
 
807
812
  ## Docker
808
813
 
@@ -820,7 +825,7 @@ Ranges shared by every app live in the \`catalog:\` section of \`pnpm-workspace.
820
825
  ## Maintenance
821
826
 
822
827
  \`cd apps/<app> && npx @teispace/next-maker doctor --compile\` checks an app against the starter; \`setup --set <option>=<value>\` changes its features.
823
- `,_s=()=>`name: CI
828
+ `,Ws=()=>`name: CI
824
829
 
825
830
  on:
826
831
  push:
@@ -862,12 +867,12 @@ jobs:
862
867
  - run: pnpm check:deprecated
863
868
  - run: pnpm test
864
869
  - run: pnpm build
865
- `,Ds=()=>`const config = {
870
+ `,zs=()=>`const config = {
866
871
  '*': ['biome check --write --no-errors-on-unmatched --files-ignore-unknown=true'],
867
872
  };
868
873
 
869
874
  export default config;
870
- `,Ls=()=>`const config = {
875
+ `,Ks=()=>`const config = {
871
876
  extends: ['@commitlint/config-conventional'],
872
877
  rules: {
873
878
  'header-max-length': [2, 'always', 150],
@@ -876,13 +881,13 @@ export default config;
876
881
  };
877
882
 
878
883
  export default config;
879
- `,Us=()=>({"pre-commit":`#!/usr/bin/env sh
884
+ `,Xs=()=>({"pre-commit":`#!/usr/bin/env sh
880
885
  pnpm lint-staged
881
886
  `,"commit-msg":`#!/usr/bin/env sh
882
887
  pnpm exec commitlint --edit "$1"
883
888
  `,"pre-push":`#!/usr/bin/env sh
884
889
  pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test
885
- `}),Gs=(e,t="24")=>`# syntax=docker.io/docker/dockerfile:1
890
+ `}),Ys=(e,t="24")=>`# syntax=docker.io/docker/dockerfile:1
886
891
  # Build from the workspace root:
887
892
  # docker build -f apps/${e}/Dockerfile -t ${e} .
888
893
 
@@ -935,7 +940,7 @@ EXPOSE 3000
935
940
  HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \\
936
941
  CMD wget -qO- http://127.0.0.1:3000/robots.txt >/dev/null || exit 1
937
942
  CMD ["node", "apps/${e}/server.js"]
938
- `,Bs=e=>`services:
943
+ `,Qs=e=>`services:
939
944
  ${e.map((r,n)=>` ${r}:
940
945
  build:
941
946
  context: .
@@ -952,7 +957,7 @@ ${e.map((r,n)=>` ${r}:
952
957
  API_INTERNAL_URL: \${API_INTERNAL_URL}`).join(`
953
958
 
954
959
  `)}
955
- `,Vs=()=>`node_modules
960
+ `,Zs=()=>`node_modules
956
961
  **/node_modules
957
962
  .git
958
963
  .turbo
@@ -962,12 +967,12 @@ ${e.map((r,n)=>` ${r}:
962
967
  **/test-results
963
968
  **/.env
964
969
  **/.env.*
965
- `,Hs=e=>{if(e.length===0)return{};let t=o=>({...o.dependencies??{},...o.devDependencies??{}}),r=t(e[0]),n={};for(let[o,s]of Object.entries(r))e.every(i=>t(i)[o]===s)&&(n[o]=s);return Object.fromEntries(Object.entries(n).sort(([o],[s])=>o.localeCompare(s)))},qs=(e,t)=>{let r=structuredClone(e);for(let n of["dependencies","devDependencies"]){let o=r[n];if(o)for(let s of Object.keys(o))t[s]===o[s]&&(o[s]="catalog:")}return r},Js=e=>Object.keys(e).length?`
970
+ `,ei=e=>{if(e.length===0)return{};let t=o=>({...o.dependencies??{},...o.devDependencies??{}}),r=t(e[0]),n={};for(let[o,s]of Object.entries(r))e.every(i=>t(i)[o]===s)&&(n[o]=s);return Object.fromEntries(Object.entries(n).sort(([o],[s])=>o.localeCompare(s)))},ti=(e,t)=>{let r=structuredClone(e);for(let n of["dependencies","devDependencies"]){let o=r[n];if(o)for(let s of Object.keys(o))t[s]===o[s]&&(o[s]="catalog:")}return r},ri=e=>Object.keys(e).length?`
966
971
  catalog:
967
972
  ${Object.entries(e).map(([t,r])=>` '${t}': '${r}'`).join(`
968
973
  `)}
969
- `:"";var Ap=(e,t=[])=>[...t,e],zs={hooks:!1,commitizen:!1,ci:!1,docker:!1,githubTemplates:!1,communityFiles:[]},Ws=e=>{e.command("workspace <name>").alias("monorepo").description("Create a pnpm + Turborepo workspace with one starter app per --apps entry").option("--apps <names>","Comma-separated app names","web,admin").option("-y, --yes","Skip prompts and use the starter defaults for every app").option("--preset <name>",`Preset for the apps (${Fe().join(", ")})`).option("--set <key=value>","Starter option applied to every app (repeatable)",Ap).option("--starter-path <dir>","Compose from a local starter checkout").option("--docker","Per-app Dockerfiles (turbo prune) and a root docker-compose.yml").option("--no-catalog","Keep dependency ranges in each app instead of the pnpm catalog").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").option("--no-ci","Skip the root GitHub Actions workflow").option("--no-hooks","Skip root git hooks (Husky, lint-staged, commitlint)").action(async(t,r)=>{try{await Np(t,r)}catch(n){b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},Ce=async(e,t,r,n)=>{let o=St(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},Ip=e=>{let t=e.split(",").map(r=>r.trim()).filter(Boolean);if(t.length===0)throw new Error("Pass at least one app name with --apps.");for(let r of t)rt(r);if(new Set(t).size!==t.length)throw new Error("App names must be unique.");return t},Np=async(e,t)=>{Pt(),rt(e);let r=Ip(t.apps??"web,admin"),n=v.resolve(process.cwd(),e);if(w(n))throw new Error(`Directory ${e} already exists.`);let o={...t.preset?Me(t.preset):{},...xe(t.set)};for(let[c,l]of Object.entries(zs))o[c]!==void 0&&JSON.stringify(o[c])!==JSON.stringify(l)&&m(he.yellow(` ! ${c} is managed at the workspace root; ignoring --set ${c}`)),o[c]=l;o.packageManager="pnpm";let s={current:null},i=async()=>{w(n)&&(s.current?.stop(),s.current=null,m(he.yellow(`
970
- Cleaning up ${e}...`)),await tt(n))},a=$t(async()=>{m(he.red(`
971
- Process interrupted.`)),await i()});try{await Wt(v.join(n,"apps"),{recursive:!0}),await Wt(v.join(n,"packages"),{recursive:!0});let c=V({starterPath:t.starterPath}),l=v.join(n,"apps",r[0]),p=await Ce(`Fetching starter (${c.location})...`,"Starter fetched.",()=>ve({projectPath:l,source:c,supplied:o,packageManager:"pnpm"}),s);if(!t.yes){let x=await Ct(p.manifest,p.answers);p=nt(p.manifest,{...x,...zs,packageManager:"pnpm"},"pnpm"),m("")}for(let x of p.forced)m(he.yellow(` ! ${x.reason}; ${x.option} turned off`));let u=JSON.parse(await Kt(v.join(l,"package.json"),"utf-8")),f=await Kt(v.join(l,"pnpm-workspace.yaml"),"utf-8"),d={};for(let x of[".nvmrc",".npmrc",".editorconfig"])w(v.join(l,x))&&(d[x]=await Kt(v.join(l,x),"utf-8"));let g=x=>me(x,{projectName:x,description:`${x} app of ${e}`,readme:!0,copyEnv:!0});await Ce(`Composing apps/${r[0]}...`,`apps/${r[0]} composed.`,()=>$e(l,g(r[0]),p,c),s);for(let x of r.slice(1)){let T=v.join(n,"apps",x);await Ce(`Composing apps/${x}...`,`apps/${x} composed.`,async()=>{let j=await ve({projectPath:T,source:c,supplied:p.answers,packageManager:"pnpm"});await $e(T,g(x),j,c)},s)}let y=[];for(let x of r){let T=v.join(n,"apps",x);for(let U of["pnpm-workspace.yaml","pnpm-lock.yaml",".npmrc",".nvmrc"])await Op(v.join(T,U),{force:!0});let j=JSON.parse(await Kt(v.join(T,"package.json"),"utf-8"));delete j.packageManager,delete j.engines,y.push(j)}let E=t.catalog===!1?{}:Hs(y);for(let[x,T]of r.entries()){let j=qs(y[x],E);await N(v.join(n,"apps",T,"package.json"),`${JSON.stringify(j,null,2)}
972
- `),t.docker&&await N(v.join(n,"apps",T,"Dockerfile"),Gs(T))}await Ce("Writing workspace root...","Workspace root written.",async()=>{let x={name:e,description:`${e} workspace`,author:u.author??"",apps:r,packageManager:"pnpm",packageManagerPin:u.packageManager??"pnpm@11.25.0",nodeEngine:u.engines?.node??">=24.0.0",turboVersion:"^2.10.0",biomeVersion:u.devDependencies?.["@biomejs/biome"]??"^2.5.0",hooks:t.hooks!==!1,huskyVersion:u.devDependencies?.husky,lintStagedVersion:u.devDependencies?.["lint-staged"],commitlintCliVersion:u.devDependencies?.["@commitlint/cli"],commitlintConfigVersion:u.devDependencies?.["@commitlint/config-conventional"]};await N(v.join(n,"package.json"),Os(x)),await N(v.join(n,"pnpm-workspace.yaml"),As(f)+Js(E)),await N(v.join(n,"turbo.json"),Is()),await N(v.join(n,"biome.json"),Ns(x.biomeVersion)),await N(v.join(n,".gitignore"),Fs()),await N(v.join(n,"README.md"),Ms(x,p.manifest.starter.version)),await N(v.join(n,"packages",".gitkeep"),"");for(let[T,j]of Object.entries(d))await N(v.join(n,T),j);if(t.docker&&(await N(v.join(n,"docker-compose.yml"),Bs(r)),await N(v.join(n,".dockerignore"),Vs())),t.ci!==!1&&(await Wt(v.join(n,".github","workflows"),{recursive:!0}),await N(v.join(n,".github","workflows","ci.yml"),_s())),t.hooks!==!1){await N(v.join(n,".lintstagedrc.mjs"),Ds()),await N(v.join(n,"commitlint.config.mjs"),Ls()),await Wt(v.join(n,".husky"),{recursive:!0});for(let[T,j]of Object.entries(Us())){let U=v.join(n,".husky",T);await N(U,j),await Rp(U,493)}}await N(v.join(n,".next-maker.json"),`${JSON.stringify({workspace:!0,apps:r,starter:p.manifest.starter,answers:p.answers,docker:!!t.docker,catalog:t.catalog!==!1},null,2)}
973
- `)},s),t.install!==!1&&(await Ce("Installing dependencies with pnpm...","Dependencies installed.",()=>le(n,"pnpm"),s),await Ce("Formatting...","Formatted.",()=>Rt(n,"pnpm","lint:fix"),s));for(let x of r){let T=v.join(n,"apps",x,".env.example");w(T)&&await Cp(T,v.join(n,"apps",x,".env"))}t.git!==!1&&await Ce("Initializing git...","Git initialized.",()=>jt(n),s),a(),m(""),m(he.green(`\u2728 Workspace ${e} is ready with ${r.map(x=>`apps/${x}`).join(", ")}.`)),m(""),m("Next:"),m(he.cyan(` cd ${e}`)),t.install===!1&&m(he.cyan(" pnpm install")),m(he.cyan(` pnpm --filter ${r[0]} dev`)),m("")}catch(c){throw a(),s.current?.fail("Failed to create workspace."),s.current=null,await i(),c}};var Ks=e=>{Gn(e),Ws(e),Ts(e),ls(e),Es(e),os(e),Rs(e),gs(e),us(e),as(e),Fo(e),ps(e),is(e),ds(e),Do(e),ts(e),Mo(e),fs(e),Cs(e)};var Mp=process.emitWarning;process.emitWarning=function(e,t,r,n){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return Mp.apply(process,arguments)};async function _p(){wn({logger:t=>kt(t)});let e=new Fp;e.name("next-maker").description("Teispace Next.js Project Generator").version(Ae.version),Ks(e),e.parse()}_p().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);kt(`Unexpected error: ${t}`)});
974
+ `:"";var Xp=(e,t=[])=>[...t,e],ni={hooks:!1,commitizen:!1,ci:!1,docker:!1,githubTemplates:!1,communityFiles:[]},oi=e=>{e.command("workspace <name>").alias("monorepo").description("Create a pnpm + Turborepo workspace with one starter app per --apps entry").option("--apps <names>","Comma-separated app names","web,admin").option("-y, --yes","Skip prompts and use the starter defaults for every app").option("--preset <name>",`Preset for the apps (${Be().join(", ")})`).option("--set <key=value>","Starter option applied to every app (repeatable)",Xp).option("--starter-path <dir>","Compose from a local starter checkout").option("--docker","Per-app Dockerfiles (turbo prune) and a root docker-compose.yml").option("--no-catalog","Keep dependency ranges in each app instead of the pnpm catalog").option("--no-install","Skip dependency installation").option("--no-git","Skip git init").option("--no-ci","Skip the root GitHub Actions workflow").option("--no-hooks","Skip root git hooks (Husky, lint-staged, commitlint)").action(async(t,r)=>{try{await Qp(t,r)}catch(n){v(`${n instanceof Error?n.message:n}`),process.exit(1)}})},_e=async(e,t,r,n)=>{let o=Ot(e);n.current=o;try{let s=await r();return o.succeed(t),s}finally{n.current===o&&(n.current=null)}},Yp=e=>{let t=e.split(",").map(r=>r.trim()).filter(Boolean);if(t.length===0)throw new Error("Pass at least one app name with --apps.");for(let r of t)ct(r);if(new Set(t).size!==t.length)throw new Error("App names must be unique.");return t},Qp=async(e,t)=>{Ct(),ct(e);let r=Yp(t.apps??"web,admin"),n=k.resolve(process.cwd(),e);if(w(n))throw new Error(`Directory ${e} already exists.`);let o={...t.preset?Ge(t.preset):{},...Ee(t.set)};for(let[c,m]of Object.entries(ni))o[c]!==void 0&&JSON.stringify(o[c])!==JSON.stringify(m)&&l(ke.yellow(` ! ${c} is managed at the workspace root; ignoring --set ${c}`)),o[c]=m;o.packageManager="pnpm";let s={current:null},i=async()=>{w(n)&&(s.current?.stop(),s.current=null,l(ke.yellow(`
975
+ Cleaning up ${e}...`)),await at(n))},a=Rt(async()=>{l(ke.red(`
976
+ Process interrupted.`)),await i()});try{await Zt(k.join(n,"apps"),{recursive:!0}),await Zt(k.join(n,"packages"),{recursive:!0});let c=z({starterPath:t.starterPath}),m=k.join(n,"apps",r[0]),p=await _e(`Fetching starter (${c.location})...`,"Starter fetched.",()=>Re({projectPath:m,source:c,supplied:o,packageManager:"pnpm"}),s);if(!t.yes){let b=await Mt(p.manifest,p.answers);p=pt(p.manifest,{...b,...ni,packageManager:"pnpm"},"pnpm"),l("")}for(let b of p.forced)l(ke.yellow(` ! ${b.reason}; ${b.option} turned off`));let u=JSON.parse(await er(k.join(m,"package.json"),"utf-8")),d=await er(k.join(m,"pnpm-workspace.yaml"),"utf-8"),f={};for(let b of[".nvmrc",".npmrc",".editorconfig"])w(k.join(m,b))&&(f[b]=await er(k.join(m,b),"utf-8"));let h=b=>ye(b,{projectName:b,description:`${b} app of ${e}`,readme:!0,copyEnv:!0});await _e(`Composing apps/${r[0]}...`,`apps/${r[0]} composed.`,()=>je(m,h(r[0]),p,c),s);for(let b of r.slice(1)){let P=k.join(n,"apps",b);await _e(`Composing apps/${b}...`,`apps/${b} composed.`,async()=>{let C=await Re({projectPath:P,source:c,supplied:p.answers,packageManager:"pnpm"});await je(P,h(b),C,c)},s)}let y=[];for(let b of r){let P=k.join(n,"apps",b);for(let H of["pnpm-workspace.yaml","pnpm-lock.yaml",".npmrc",".nvmrc"])await Kp(k.join(P,H),{force:!0});let C=JSON.parse(await er(k.join(P,"package.json"),"utf-8"));delete C.packageManager,delete C.engines,y.push(C)}let x=t.catalog===!1?{}:ei(y);for(let[b,P]of r.entries()){let C=ti(y[b],x);await M(k.join(n,"apps",P,"package.json"),`${JSON.stringify(C,null,2)}
977
+ `),t.docker&&await M(k.join(n,"apps",P,"Dockerfile"),Ys(P))}await _e("Writing workspace root...","Workspace root written.",async()=>{let b={name:e,description:`${e} workspace`,author:u.author??"",apps:r,packageManager:"pnpm",packageManagerPin:u.packageManager??"pnpm@11.25.0",nodeEngine:u.engines?.node??">=24.0.0",turboVersion:"^2.10.0",biomeVersion:u.devDependencies?.["@biomejs/biome"]??"^2.5.0",hooks:t.hooks!==!1,huskyVersion:u.devDependencies?.husky,lintStagedVersion:u.devDependencies?.["lint-staged"],commitlintCliVersion:u.devDependencies?.["@commitlint/cli"],commitlintConfigVersion:u.devDependencies?.["@commitlint/config-conventional"]};await M(k.join(n,"package.json"),Bs(b)),await M(k.join(n,"pnpm-workspace.yaml"),Gs(d)+ri(x)),await M(k.join(n,"turbo.json"),Vs()),await M(k.join(n,"biome.json"),Hs(b.biomeVersion)),await M(k.join(n,".gitignore"),qs()),await M(k.join(n,"README.md"),Js(b,p.manifest.starter.version)),await M(k.join(n,"packages",".gitkeep"),"");for(let[P,C]of Object.entries(f))await M(k.join(n,P),C);if(t.docker&&(await M(k.join(n,"docker-compose.yml"),Qs(r)),await M(k.join(n,".dockerignore"),Zs())),t.ci!==!1&&(await Zt(k.join(n,".github","workflows"),{recursive:!0}),await M(k.join(n,".github","workflows","ci.yml"),Ws())),t.hooks!==!1){await M(k.join(n,".lintstagedrc.mjs"),zs()),await M(k.join(n,"commitlint.config.mjs"),Ks()),await Zt(k.join(n,".husky"),{recursive:!0});for(let[P,C]of Object.entries(Xs())){let H=k.join(n,".husky",P);await M(H,C),await Wp(H,493)}}await M(k.join(n,".next-maker.json"),`${JSON.stringify({workspace:!0,apps:r,starter:p.manifest.starter,answers:p.answers,docker:!!t.docker,catalog:t.catalog!==!1},null,2)}
978
+ `)},s),t.install!==!1&&(await _e("Installing dependencies with pnpm...","Dependencies installed.",()=>he(n,"pnpm"),s),await _e("Formatting...","Formatted.",()=>Ft(n,"pnpm","lint:fix"),s));for(let b of r){let P=k.join(n,"apps",b,".env.example");w(P)&&await zp(P,k.join(n,"apps",b,".env"))}t.git!==!1&&await _e("Initializing git...","Git initialized.",()=>Nt(n),s),a(),l(""),l(ke.green(`\u2728 Workspace ${e} is ready with ${r.map(b=>`apps/${b}`).join(", ")}.`)),l(""),l("Next:"),l(ke.cyan(` cd ${e}`)),t.install===!1&&l(ke.cyan(" pnpm install")),l(ke.cyan(` pnpm --filter ${r[0]} dev`)),l("")}catch(c){throw a(),s.current?.fail("Failed to create workspace."),s.current=null,await i(),c}};var si=e=>{Xn(e),oi(e),_s(e),xs(e),Ns(e),ds(e),Ls(e),Ps(e),vs(e),hs(e),Ho(e),ws(e),gs(e),ks(e),Wo(e),ls(e),qo(e),$s(e),Us(e)};var el=process.emitWarning;process.emitWarning=function(e,t,r,n){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return el.apply(process,arguments)};async function tl(){$n({logger:t=>jt(t)});let e=new Zp;e.name("next-maker").description("Teispace Next.js Project Generator").version(De.version),si(e),e.parse()}tl().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);jt(`Unexpected error: ${t}`)});