@teispace/next-maker 5.0.2 → 5.0.3

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 Ip}from"commander";var Ae={name:"@teispace/next-maker",version:"5.0.2",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 Qi}from"node:fs/promises";import At from"node:path";import I from"picocolors";var on=/@next-maker:([\w-]+)(?::(start|end))?/,Ks=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,Xs=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(on);if(!i){n.push(s);continue}let[,a,c]=i,l=t.has(a);if(c==="start"){let u=Ys(r,o+1,a);l&&(o=u);continue}if(c==="end")continue;let p=Ks.test(s);if(l){p&&o++;continue}p||n.push(Xs(s))}return n.join(`
4
- `)},Ys=(e,t,r)=>{for(let n=t;n<e.length;n++){let o=e[n].match(on);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:"),sn=(e,t)=>{let r=e.split(`
2
+ import{Command as Fp}from"commander";var Ae={name:"@teispace/next-maker",version:"5.0.3",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
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
6
  `)},We=(e,t)=>{let r=e.split(`
7
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 sn(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 gn,mkdir as ni,mkdtemp as oi,readdir as dn,readFile as Ie,rm as Qt,rmdir as si,stat as ii,writeFile as Ne}from"node:fs/promises";import{tmpdir as ai}from"node:os";import F from"node:path";import{readdir as Qs}from"node:fs/promises";import wt from"node:path";var an=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}$`)},Zs=new Set(["node_modules",".git",".next","coverage","playwright-report","test-results"]),L=async(e,t=Zs)=>{let r=[],n=async o=>{let s;try{s=await Qs(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=an(t);return e.filter(n=>r.test(n))};import{readFile as cn}from"node:fs/promises";import pn from"node:path";var xt="next-maker.json",ye=".next-maker/overlays",ln=1,B=e=>{throw new Error(`Invalid ${xt}: ${e}`)},un=e=>{(typeof e!="object"||e===null)&&B("not an object");let t=e;t.manifestVersion!==ln&&B(`manifestVersion ${String(t.manifestVersion)} is not supported by this CLI (expected ${ln})`),(!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=pn.join(e,xt),r;try{r=await cn(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=un(JSON.parse(r));try{let o=JSON.parse(await cn(pn.join(e,"package.json"),"utf-8"));typeof o.version=="string"&&o.version&&(n.starter={...n.starter,version:o.version})}catch{}return n},mn=(e,t)=>e.some(r=>r===t),bt=(e,t,r)=>t===void 0?!1:e?.type==="multi"&&Array.isArray(t)?t.some(n=>mn(r,n)):mn(r,t),ae=(e,t,r)=>Object.entries(t.when).every(([n,o])=>bt(e.options[n],r[n],o)),ei=e=>e.type==="boolean"?!1:e.type==="multi"?[]:e.default,ti=(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:ti(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=ei(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}`}},ri=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 ri(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??[]))}},ci=new Set([".ts",".tsx",".js",".mjs",".cjs",".css",".json",".yml",".yaml",".md",".sh",".example",".mdx"]),pi=e=>ci.has(F.extname(e))||e.startsWith(".husky/")||e==="Dockerfile",fn=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 ni(F.dirname(i),{recursive:!0}),await gn(F.join(n,s),i,{force:!0})}return o},tr=async(e,t=e)=>{let r;try{r=await dn(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 dn(t)).length===0&&await si(t)},hn=(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&&hn(e,s)}},li=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)hn(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")},mi=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,`
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
10
 
11
- `),"utf-8")},rr=async(e,t,r)=>{let n={removed:[],overlaid:[],anchored:[],unwrapped:[]},o=F.join(e,ye),s=await oi(F.join(ai(),"next-maker-overlays-"));try{await Zt(o)&&await gn(o,s,{recursive:!0});for(let l of r.pmOverlays)n.overlaid.push(...await fn(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 fn(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(!pi(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 li(e,r,t),await mi(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 ii(e),!0}catch{return!1}};import{readFile as ui}from"node:fs/promises";import di from"node:path";var nr=async e=>{let t=di.resolve(process.cwd(),e),r;try{r=await ui(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 yn(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 fi={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=fi[t]??(n=>n);console.log(r(e))}function kt(e){pe(`\u2716 ${e}`,"red")}var b=kt;function wn(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 gi from"ora";function St(e="",t){let r=gi({text:e,...t});return r.start(),r}var hi=e=>e.charAt(0).toUpperCase()+e.slice(1),G=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),$=e=>hi(G(e));import yi from"ora";var h=yi();import{execFile as wi}from"node:child_process";import{cp as xn,mkdir as xi,stat as bi}from"node:fs/promises";import Ze from"node:path";import{promisify as vi}from"node:util";import $i from"degit";var ki=vi(wi),bn="teispace/nextjs-starter",Et="v2.0.0-alpha.1",Pi="NEXT_MAKER_STARTER_PATH",Si=(e=Et)=>e==="main"?bn:`${bn}#${e}`,V=(e={})=>{let t=e.starterPath??process.env[Pi];return t?{kind:"local",location:Ze.resolve(t)}:{kind:"remote",location:Si(e.ref)}},Ei=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 bi(r.location)).isDirectory())throw new Error("not a directory")}catch{throw new Error(`Starter path ${r.location} is not a directory`)}return await Ti(r.location,e),r}return await $i(r.location,{cache:!1,force:!0,verbose:t.verbose??!1}).clone(e),r},Ti=async(e,t)=>{let r=null;try{let{stdout:n}=await ki("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 xn(e,t,{recursive:!0,filter:n=>!Ei.has(Ze.basename(n))});return}for(let n of r){let o=Ze.join(t,n);await xi(Ze.dirname(o),{recursive:!0});try{await xn(Ze.join(e,n),o)}catch{}}};import{existsSync as sr}from"node:fs";import et from"node:fs/promises";import ji from"node:path";var R=async e=>et.readFile(e,"utf-8"),P=async(e,t)=>{await et.mkdir(ji.dirname(e),{recursive:!0}),await et.writeFile(e,t,"utf-8")};var vn=async e=>{sr(e)&&await et.unlink(e)},tt=async e=>{sr(e)&&await et.rm(e,{recursive:!0,force:!0})},$n=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 Ri}from"node:child_process";import{promisify as Ci}from"node:util";var Oi=Ci(Ri),te=(e,t)=>Oi("git",e,t?{cwd:t}:void 0);function Ai(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&&(Ai(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 Ii}from"node:child_process";import{promisify as Ni}from"node:util";var Fi=Ni(Ii),kn=(e,t,r)=>Fi(e,t,{cwd:r,maxBuffer:64*1024*1024}),Mi=e=>{let t=e;return(`${t.stdout??""}
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??""}
12
12
  ${t.stderr??""}`.trim()||(t.message??String(e))).split(`
13
13
  `).filter(Boolean).slice(-12).join(`
14
- `)},_i=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 kn(t,_i(t),e)}catch(r){throw new Error(`Failed to install dependencies with ${t}:
15
- ${Mi(r)}`,{cause:r})}},Rt=async(e,t,r)=>{let n=t==="npm"?["run",r]:[r];try{await kn(t,n,e)}catch(o){console.warn(`Warning: Failed to run script '${r}': ${o}`)}};import Di from"enquirer";var{prompt:Pn}=Di,Li=/^[a-z0-9-_]+$/,Ui=/^\d+\.\d+\.\d+$/,Sn=e=>Li.test(e),En=e=>Ui.test(e),rt=e=>{if(!Sn(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(!En(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}},Tn=e=>e.state?.answers??e.enquirer?.answers??{},jn=async e=>{e!==void 0&&rt(e);let t=await Pn([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:r=>Sn(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=>En(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!Tn(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=Tn(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 Pn(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 Gi 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 Bi=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}},Rn=async(e,t)=>{let{remote:r,homepage:n,issues:o}=Bi(t);await $n(Gi.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 Ki}from"node:fs/promises";import de from"node:path";import{cp as Vi,mkdir as Hi,mkdtemp as qi,readFile as be,rm as An,writeFile as Ot}from"node:fs/promises";import{tmpdir as Ji}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 qi(A.join(Ji(),"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:()=>An(o,{recursive:!0,force:!0})}},Cn=(e,t)=>e[t]??{},zi=e=>[...e.off?.anchors??[],...e.on?.anchors??[]],Wi=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},In=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=Cn(r,"off"),o=Cn(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 Wi(e,zi(r))}},Nn=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 In(r,c),f=[];for(let d of[...u.files,...u.overlayFiles])!o&&Nn(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},Fn=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 In(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&&Nn(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},Mn=async(e,t,r,n)=>{for(let i of r.remove)await An(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 Hi(A.dirname(l),{recursive:!0}),await Vi(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=On(s.dependencies),s.devDependencies=On(s.devDependencies),await Ot(o,`${JSON.stringify(s,null,2)}
18
- `,"utf-8"),await ue(e,{...n,answers:r.after})},On=e=>Object.fromEntries(Object.entries(e).sort(([t],[r])=>t.localeCompare(r)));var Xi=(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),_n=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 Ki(n))r.push(de.join(n,o));for(let o of r){if(!w(o))continue;let s=await R(o),i=Xi(s,t);i!==s&&await P(o,i)}},Dn=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)},Yi=(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)}`},Ln=async(e,t,r,n,o)=>{let s=de.join(e,C.README);if(!t.readme){await vn(s);return}let i=Object.entries(n).filter(([l])=>l!=="packageManager").map(([l,p])=>Yi(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
+ `)},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}
19
19
 
20
20
  ${t.description}
21
21
 
@@ -51,9 +51,9 @@ ${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 Rn(e,t),await _n(e,t),await Dn(e,t),await Ln(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"],Zi=e=>{if(e!==void 0){if(!ar.includes(e))throw new Error(`Invalid --package-manager "${e}". Valid: ${ar.join(", ")}.`);return e}},ea=(e,t=[])=>[...t,e],Un=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",ea).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 oa(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)}},ta=e=>Array.isArray(e)?e.length?e.join(", "):"none":String(e),ra=(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))} ${ta(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("")},na=async(e,t)=>{let r=t.config?await nr(t.config):void 0,n=Zi(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 jn(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}},oa=async(e,t)=>{Pt();let r=await na(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(`
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
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(ra(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 Qi(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 Fr from"node:path";import X from"picocolors";import It from"node:path";var Gn=/^[A-Za-z][A-Za-z0-9-]*$/,sa=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;function Bn(e){return sa.test(e)}function M(e,t="name"){let r=e?.trim();if(!r)throw new Error(`A ${t} is required.`);if(!Gn.test(r))throw new Error(`Invalid ${t} "${e}". Use letters, digits, and hyphens only \u2014 no slashes, spaces, "..", or absolute paths.`);if(Bn(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(!Gn.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(Bn(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 ia}from"node:child_process";import{stat as aa}from"node:fs/promises";import cr from"node:path";import{promisify as ca}from"node:util";var pa=ca(ia),la=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".jsonc",".css"]),ma=e=>cr.join(e,"node_modules",".bin","biome"),pr=async(e,t,r=e)=>{let n=ma(r);if(t.length===0||!w(n))return!1;try{await pa(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(la.has(cr.extname(n)))try{(await aa(cr.join(e,n))).mtimeMs>=t-1e3&&r.push(n)}catch{}return r.length&&await pr(e,r),r};import{access as ua}from"node:fs/promises";import da from"node:path";var ke=async(e,t,r)=>{try{return await ua(da.join(e,r,t)),!0}catch{return!1}};import{access as fa,readFile as Hn}from"node:fs/promises";import lr from"node:path";var Le=async e=>{try{return await fa(e),!0}catch{return!1}},Vn=async e=>{try{return JSON.parse(await Hn(e,"utf-8"))}catch{return null}},O=async e=>{let t=await Vn(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 Vn(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 Hn(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 ga,writeFile as ha}from"node:fs/promises";import mr from"node:path";var qn=({pascalName:e,camelName:t})=>`import { z } from 'zod';
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';
57
57
 
58
58
  /**
59
59
  * Wire contracts for the ${t} feature. Types are inferred from the
@@ -78,7 +78,7 @@ export const update${e}InputSchema = create${e}InputSchema.partial().extend({
78
78
  id: z.string(),
79
79
  });
80
80
  export type Update${e}Input = z.infer<typeof update${e}InputSchema>;
81
- `,Jn=({kebabName:e,camelName:t})=>`/**
81
+ `,zn=({kebabName:e,camelName:t})=>`/**
82
82
  * Query keys owned by the feature. Everything under \`${t}Keys.all\` can
83
83
  * be invalidated at once; narrower keys target one resource.
84
84
  */
@@ -87,7 +87,7 @@ export const ${t}Keys = {
87
87
  list: () => [...${t}Keys.all, 'list'] as const,
88
88
  detail: (id: string) => [...${t}Keys.all, 'detail', id] as const,
89
89
  } as const;
90
- `,zn=({pascalName:e,camelName:t})=>`import 'server-only';
90
+ `,Wn=({pascalName:e,camelName:t})=>`import 'server-only';
91
91
 
92
92
  import { AppApis } from '@/lib/config/app-apis';
93
93
  import { serverHttp } from '@/lib/http/server';
@@ -109,7 +109,7 @@ export const list${e}s = async () =>
109
109
 
110
110
  export const get${e} = async (id: string) =>
111
111
  serverHttp.get(AppApis.${t}.detail(id), { schema: ${t}Schema });
112
- `,Wn=({pascalName:e,camelName:t})=>`'use server';
112
+ `,Kn=({pascalName:e,camelName:t})=>`'use server';
113
113
 
114
114
  import { revalidateTag } from 'next/cache';
115
115
 
@@ -158,7 +158,7 @@ export const delete${e} = authActionClient
158
158
  revalidateTag(${t.toUpperCase()}_TAG, 'max');
159
159
  return { deleted: true as const };
160
160
  });
161
- `,Kn=({pascalName:e,camelName:t})=>`import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
161
+ `,Xn=({pascalName:e,camelName:t})=>`import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
162
162
 
163
163
  import { AppApis } from '@/lib/config/app-apis';
164
164
  import { http } from '@/lib/http';
@@ -187,26 +187,26 @@ export const ${t}Query = (id: string) =>
187
187
 
188
188
  export const use${e}List = () => useSuspenseQuery(${t}ListQuery());
189
189
  export const use${e} = (id: string) => useSuspenseQuery(${t}Query(id));
190
- `,Xn=({camelName:e,kebabName:t})=>` ${e}: {
190
+ `,Yn=({camelName:e,kebabName:t})=>` ${e}: {
191
191
  list: '/${t}',
192
192
  detail: (id: string) => \`/${t}/\${id}\`,
193
193
  create: '/${t}',
194
194
  update: (id: string) => \`/${t}/\${id}\`,
195
195
  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 ga(s,{recursive:!0});let i=[["schema.ts",qn(o)],["keys.ts",Jn(o)],["server.ts",zn(o)],["queries.ts",Kn(o)]];return n&&i.push(["actions.ts",Wn(o)]),await Promise.all(i.map(([a,c])=>ha(mr.join(s,a),c))),i.map(([a])=>mr.join("api",a))};import{mkdir as Qn,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
- `)},Yn=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 ya(i,r,s,n,o):await wa(i,t,r,n,o)},ya=async(e,t,r,n,o)=>{let s=Pe.join(t,r,"components");await Qn(s,{recursive:!0}),await dr(Pe.join(s,`${e}.tsx`),ur({componentName:e,isClient:n,hasI18n:o}))},wa=async(e,t,r,n,o)=>{let s=Pe.join(r,"src","components","common",e);await Qn(s,{recursive:!0}),await dr(Pe.join(s,`${e}.tsx`),ur({componentName:e,isClient:n,hasI18n:o})),await dr(Pe.join(s,"index.ts"),Yn({componentName:e}));let i=Pe.join(r,"src","components","common","index.ts");await xa(i,`export { ${e} } from './${e}';
199
- `);let a=Pe.join(r,"src","components","index.ts");await ba(a)},xa=async(e,t)=>{let r="";w(e)&&(r=await R(e)),r.includes(t.trim())||(r+=t,await P(e,r))},ba=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 va,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';
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';
201
201
  `:`export * from './${t}.selectors';
202
202
  export * from './${t}.slice';${r?`
203
203
  export * from './persist';`:""}
204
- `},Zn=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(`
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(`
205
205
  `)}
206
- `},eo=e=>`import 'server-only';
206
+ `},to=e=>`import 'server-only';
207
207
 
208
208
  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 to=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';
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';
210
210
 
211
211
  import type { ${t}State } from '${n}';
212
212
 
@@ -224,12 +224,12 @@ export const ${r}Persistence = definePersistence<${t}State>({
224
224
  // 2: (previous) => ({ ...(previous as ${t}State), newField: 0 }),
225
225
  },
226
226
  });
227
- `};var ro=e=>{let{componentName:t,camelName:r}=e;return`import type { RootState } from '@/store/rootReducer';
227
+ `};var no=e=>{let{componentName:t,camelName:r}=e;return`import type { RootState } from '@/store/rootReducer';
228
228
 
229
229
  export const select${t}State = (state: RootState) => state.${r};
230
230
  export const select${t}Status = (state: RootState) => state.${r}.status;
231
231
  export const select${t}Error = (state: RootState) => state.${r}.error;
232
- `};var no=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
232
+ `};var oo=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
233
233
 
234
234
  import type { ${t}State } from '${n}';
235
235
 
@@ -265,7 +265,7 @@ export interface ${t}State {
265
265
  `:`export interface ${t}Props {
266
266
  // Props for the ${t} component
267
267
  }
268
- `};var oo=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
268
+ `};var so=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
269
269
 
270
270
  import type { ${t}State } from '${n}';
271
271
 
@@ -292,7 +292,7 @@ export const create${t}Slice: StateCreator<any, [], [], ${t}Slice> = (set) => ({
292
292
  ${r}Failed: (error: string) => set({ ${r}: { status: 'error', error } }),
293
293
  ${r}Reset: () => set({ ${r}: initial }),
294
294
  });
295
- `};var it=async e=>{let{name:t,outputPath:r,persist:n,state:o="redux",typesImportPath:s=`./${t}.types`}=e;await va(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`),oo({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`),no({componentName:i,camelName:a,typesImportPath:s})),Se(Ee.join(r,`${t}.selectors.ts`),ro({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"),to({componentName:i,camelName:a,typesImportPath:s})))),await Promise.all(c)};var so=e=>{let{componentName:t,hookName:r,withApi:n,pascalName:o,hasI18n:s}=e,i=s?`import { useTranslations } from 'next-intl';
295
+ `};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';
296
296
 
297
297
  `:"",a=s?` const t = useTranslations('${o}');
298
298
  `:"",c=s?"{t('title')}":t;return n?`'use client';
@@ -300,7 +300,7 @@ export const create${t}Slice: StateCreator<any, [], [], ${t}Slice> = (set) => ({
300
300
  ${i}import { use${o}List } from '../api/queries';
301
301
 
302
302
  /**
303
- * Renders hydrated query data: prefetch \`${$a(o)}ListQuery()\` in the
303
+ * Renders hydrated query data: prefetch \`${Pa(o)}ListQuery()\` in the
304
304
  * page and wrap this component in \`<HydrateQueries>\` for a no-spinner first paint.
305
305
  */
306
306
  export function ${t}() {
@@ -331,7 +331,7 @@ ${a} const state = ${r}();
331
331
  </section>
332
332
  );
333
333
  }
334
- `},$a=e=>e.charAt(0).toLowerCase()+e.slice(1);var io=e=>{let{hookName:t,componentName:r,featureName:n,state:o}=e;return o==="zustand"?`'use client';
334
+ `},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';
335
335
 
336
336
  import { useAppStore } from '@/store/hooks';
337
337
 
@@ -409,7 +409,7 @@ describe('${t}', () => {
409
409
  expect(screen.getByRole('heading')).toBeInTheDocument();
410
410
  });
411
411
  });
412
- `},ao=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`// @vitest-environment jsdom
412
+ `},co=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`// @vitest-environment jsdom
413
413
  import { renderHook } from '@testing-library/react';
414
414
  import { describe, expect, it } from 'vitest';
415
415
 
@@ -434,7 +434,7 @@ describe('${t}', () => {
434
434
  expect(result.current).toBeDefined();
435
435
  });
436
436
  });
437
- `},co=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
437
+ `},po=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
438
438
 
439
439
  import { failed, reset, ${n}, started } from '${r}';
440
440
 
@@ -456,7 +456,7 @@ describe('${n}', () => {
456
456
  expect(${n}.reducer({ status: 'error', error: 'boom' }, reset())).toEqual(initialState);
457
457
  });
458
458
  });
459
- `};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`),so({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"),Zn({featureName:t,componentName:p,hookName:u,pascalName:l,withStore:f,withApi:s}))];s||d.push(Ue(K.join(r,"hooks",`${u}.ts`),f?io({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"),eo({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:`${ka(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`})},ka=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase());import{mkdir as Pa,writeFile as Sa}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 Pa(s,{recursive:!0}),await Sa(xr.join(s,`${o}.ts`),Ft({hookName:o}))};import{mkdir as Ea}from"node:fs/promises";import _t from"node:path";var po=({componentName:e})=>`type Props = {
459
+ `};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 = {
460
460
  children: React.ReactNode;
461
461
  };
462
462
 
@@ -465,16 +465,27 @@ describe('${n}', () => {
465
465
  export default function ${e}({ children }: Props) {
466
466
  return <>{children}</>;
467
467
  }
468
- `;var Ta=/^[a-z][a-z0-9-]*$/,ja=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/,Ra=e=>{if(!Ta.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.`)},Ca=e=>{if(!ja.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;Ra(t),r&&Ca(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 Ea(l,{recursive:!0}),await P(p,po({componentName:i,hasI18n:o})),{layoutFile:p,displayPath:_t.relative(n,p),componentName:i}};import{copyFile as Oa,readFile as Aa,writeFile as Ia}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 Na(s,t,i),await Fa(s,t),await Ma(s,t,r,n,o)},Na=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 Oa(o,s);else{let i=await Aa(o,"utf-8"),a=JSON.parse(i),c=lo(a);await Ia(s,`${JSON.stringify(c,null,2)}
469
- `)}},lo=e=>{let t={};for(let[r,n]of Object.entries(e))typeof n=="object"&&n!==null?t[r]=lo(n):t[r]="";return t},Fa=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))},Ma=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=` {
468
+ `;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)}
469
+ `)}},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=` {
470
470
  name: '${r}',
471
471
  locale: '${t}',
472
472
  flag: '${o}',
473
473
  country: '${n}',
474
474
  ogLocale: '${t}_${t.toUpperCase()}',
475
475
  },
476
- `;i=i.slice(0,a)+c+i.slice(a),await P(s,i)};import{mkdir as Da,writeFile as kr}from"node:fs/promises";import Dt from"node:path";var _a=({routePath:e,hasI18n:t,paramName:r})=>`${t?"/[locale]":""}${e}${r?`/[${r}]`:""}`,mo=e=>{let{componentName:t,routePath:r,hasI18n:n,paramName:o}=e,s=_a(e);return n?`import type { Metadata } from 'next';
477
- import { getLocale, getTranslations } from 'next-intl/server';
476
+ `;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)=>`
477
+ async function ${e}${kr(t)}({
478
+ params,
479
+ }: {
480
+ params: PageProps<'${r}'>['params'];
481
+ }) {
482
+ const { ${t} } = await params;
483
+
484
+ return <p className="text-sm">${t}: {${t}}</p>;
485
+ }
486
+ `,fo=e=>{let{componentName:t,routePath:r,hasI18n:n,paramName:o}=e,s=La(e);return n?`import type { Metadata } from 'next';
487
+ import { getLocale, getTranslations } from 'next-intl/server';${o?`
488
+ import { Suspense } from 'react';`:""}
478
489
 
479
490
  import { generateSEOMetadata } from '@/lib/config/seo';
480
491
 
@@ -490,17 +501,19 @@ export async function generateMetadata(): Promise<Metadata> {
490
501
 
491
502
  export default async function ${t}Page(${o?`{ params }: PageProps<'${s}'>`:""}) {
492
503
  const t = await getTranslations('${t}');
493
- ${o?` const { ${o} } = await params;
494
- `:""}
504
+
495
505
  return (
496
506
  <div className="flex flex-col gap-2 p-6">
497
507
  <h1 className="font-bold text-2xl">{t('title')}</h1>
498
508
  <p className="text-gray-500 dark:text-gray-400">{t('description')}</p>${o?`
499
- <p className="text-sm">${o}: {${o}}</p>`:""}
509
+ <Suspense fallback={<p className="text-sm">\u2026</p>}>
510
+ <${t}${kr(o)} params={params} />
511
+ </Suspense>`:""}
500
512
  </div>
501
513
  );
502
514
  }
503
- `:`import type { Metadata } from 'next';
515
+ ${o?uo(t,o,s):""}`:`import type { Metadata } from 'next';${o?`
516
+ import { Suspense } from 'react';`:""}
504
517
 
505
518
  import { generateSEOMetadata } from '@/lib/config/seo';
506
519
 
@@ -510,24 +523,24 @@ export const metadata: Metadata = generateSEOMetadata({
510
523
  path: '${r}',
511
524
  });
512
525
 
513
- export default ${o?"async ":""}function ${t}Page(${o?`{ params }: PageProps<'${s}'>`:""}) {
514
- ${o?` const { ${o} } = await params;
515
-
516
- `:""} return (
526
+ export default function ${t}Page(${o?`{ params }: PageProps<'${s}'>`:""}) {
527
+ return (
517
528
  <div className="flex flex-col gap-2 p-6">
518
529
  <h1 className="font-bold text-2xl">${t}</h1>${o?`
519
- <p className="text-sm">${o}: {${o}}</p>`:""}
530
+ <Suspense fallback={<p className="text-sm">\u2026</p>}>
531
+ <${t}${kr(o)} params={params} />
532
+ </Suspense>`:""}
520
533
  </div>
521
534
  );
522
535
  }
523
- `},uo=e=>`export default function ${e.componentName}Loading() {
536
+ ${o?uo(t,o,s):""}`},go=e=>`export default function ${e.componentName}Loading() {
524
537
  return (
525
538
  <div className="flex h-full items-center justify-center p-6">
526
539
  <p className="text-gray-500 text-sm dark:text-gray-400">Loading\u2026</p>
527
540
  </div>
528
541
  );
529
542
  }
530
- `,fo=e=>`'use client';
543
+ `,ho=e=>`'use client';
531
544
 
532
545
  import { useEffect } from 'react';
533
546
 
@@ -557,7 +570,7 @@ export default function ${e.componentName}Error({
557
570
  </div>
558
571
  );
559
572
  }
560
- `;var Pr=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 Da(u,{recursive:!0}),await kr(Dt.join(u,"page.tsx"),mo({componentName:c,routePath:l,hasI18n:n,paramName:s})),i&&await kr(Dt.join(u,"loading.tsx"),uo({componentName:c})),a&&await kr(Dt.join(u,"error.tsx"),fo({componentName:c})),{pageDir:u,routePath:s?`${l}/[${s}]`:l}};import{mkdir as La}from"node:fs/promises";import Sr from"node:path";var go=(e,t)=>e.endsWith(t)?e:`${e}${t}`,ho=({baseName:e})=>{let t=go(e,"Provider"),r=t.replace(/Provider$/,""),n=`${r}ContextValue`,o=`${r}Context`,s=`use${r}`;return`'use client';
573
+ `;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';
561
574
  import { createContext, useContext, useMemo } from 'react';
562
575
 
563
576
  type ${n} = {
@@ -578,139 +591,139 @@ export const ${t} = ({ children }: { children: React.ReactNode }) => {
578
591
  const value = useMemo<${n}>(() => ({}), []);
579
592
  return <${o}.Provider value={value}>{children}</${o}.Provider>;
580
593
  };
581
- `},yo=e=>go(e,"Provider");var Ua=/^[A-Za-z][A-Za-z0-9-]*$/,Ga=e=>e.includes("-")?$(e):e.charAt(0).toUpperCase()+e.slice(1),Er=async e=>{let{name:t,projectPath:r}=e;if(!Ua.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=Ga(t).replace(/Provider$/,""),o=yo(n),s=o,i=Sr.join(r,C.PROVIDERS),a=Sr.join(i,`${s}.tsx`);if(w(a))throw new Error(`Provider already exists at ${Sr.relative(r,a)}.`);return await La(i,{recursive:!0}),await P(a,ho({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=Ba(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=ao({hookName:o,sourceImportPath:l,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?p:void 0}):u=co({camelName:o,sourceImportPath:l}),await P(c,u),c},Ba=(e,t)=>{let r=pt.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import{readFile as Va,writeFile as Ha}from"node:fs/promises";import qa 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+`
594
+ `},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+`
582
595
  `+e.slice(s+o.length)}return`${t}
583
- ${e}`},Tr=(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(
596
+ ${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(
584
597
  ${o.join(`,
585
598
  `)},
586
- )`;return e.replace(r,i.length<=100?i:a)},jr=(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(", ")}]`))},Rr=(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()}
599
+ )`;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()}
587
600
  ${t}
588
- ${o}`};var lt=async e=>{let{serviceName:t,projectPath:r}=e,n=G(t),o=qa.join(r,"src","lib","config","app-apis.ts");try{let s=await Va(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=Rr(s,Xn({kebabName:t,camelName:n,pascalName:$(t)})),await Ha(o,s)}catch(s){throw new Error(`Failed to register API endpoints: ${s}`,{cause:s})}};import{readFile as Ja,writeFile as za}from"node:fs/promises";import Wa from"node:path";var Cr=async(e,t,r)=>{let n=Wa.join(e,"src","lib","config","app-paths.ts");if(!w(n))return;let o=await Ja(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}',
589
- `;o=o.slice(0,i)+a+o.slice(i),await za(n,o)};import Or from"node:path";var Ka=/^[A-Z][A-Z0-9_]*$/,bo=e=>{if(!Ka.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,Ar=e=>e.public?"client":"server",Xa=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,"\\'")}')`}},Ya=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()"}},vo=e=>{let t=se(e.name,e.public),r=Ya(e),n=e.default!==void 0,o=!e.required&&!n;if(n&&(r+=Xa(e)),o&&(r+=".optional()"),e.description){let s=e.description.replace(/'/g,"\\'");r+=`
590
- .describe('${s}')`}return` ${t}: ${r},`},$o=e=>{let t=se(e.name,e.public);return` ${t}: process.env.${t},`},Qa=e=>new RegExp(`(${e}:\\s*\\{)([\\s\\S]*?)(\\n\\s*\\})`),wo=/(runtimeEnv:\s*\{)([\s\S]*?)(\n\s*\})/,xo=(e,t,r,n)=>{let o=t.replace(/\s+$/,""),s=o.length===0||/,\s*$/.test(o)?o:`${o},`;return`${e}${s}
601
+ ${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}',
602
+ `;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+=`
603
+ .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}
591
604
  ${n}
592
- ${r.replace(/^\n/,"")}`},ko=(e,t)=>{let r=se(t.name,t.public),n=Ar(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=Qa(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=vo(t),u=e.replace(s,xo(a,c,l,p)),f=u.match(wo);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(wo,xo(d,g,y,$o(t))),u},Za="# -public",ec=e=>{let t=se(e.name,e.public),r=e.default??"",n=e.public?` ${Za}`:"";return`${t}=${r}${n}`},Po=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
605
+ ${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(`
593
606
  `)?"":`
594
607
  `,s=e===""?"":`
595
608
  `,i=t.description?`# ${t.description}
596
- `:"";return`${e}${o}${s}${i}${ec(t)}
597
- `},So=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
609
+ `:"";return`${e}${o}${s}${i}${rc(t)}
610
+ `},To=(e,t)=>{let r=se(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
598
611
  `)?"":`
599
612
  `,s=t.default??"";return`${e}${o}${r}=${s}
600
- `},Ir=async(e,t)=>{bo(t.name);let r=Or.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=ko(n,t),s=o!==n;s&&await P(r,o);let i=Or.join(e,C.ENV_EXAMPLE),a=!1;if(w(i)){let p=await R(i),u=Po(p,t);a=u!==p,a&&await P(i,u)}let c=Or.join(e,".env"),l=!1;if(w(c)){let p=await R(c),u=So(p,t);l=u!==p,l&&await P(c,u)}return{schemaUpdated:s,envExampleUpdated:a,envUpdated:l,group:Ar(t)}};import Lt from"node:path";var tc=e=>new RegExp(`<\\s*${e}\\b`),Eo=(e,t)=>{if(tc(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}>
613
+ `},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}>
601
614
  ${s}{children}
602
- ${o}</${t}>`;return e.replace(r,i)},To=(e,t)=>{let r=`export * from './${t}';`;if(e.includes(r))return e;let n=e.split(`
615
+ ${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(`
603
616
  `),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}
604
617
  ${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(`
605
- `)},rc=C.PROVIDERS,nc=C.ROOT_PROVIDER,oc=C.PROVIDERS_INDEX,jo=async(e,t={fileExists:w,readFile:R})=>{let r=Lt.join(e,nc);if(t.fileExists(r))return r;let n=Lt.join(e,rc);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},Nr=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await jo(t);if(o){let a=await R(o),c=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(c=Ge(c,`import { ${r} } from './${n}';`)),c=Eo(c,r),c!==a&&await P(o,c)}let s=Lt.join(t,oc),i=null;if(w(s)){let a=await R(s),c=To(a,n);c!==a&&await P(s,c),i=s}return{rootProviderFile:o,barrelFile:i}};import{readFile as Ro,writeFile as Co}from"node:fs/promises";import Oo from"node:path";var mt=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,s=Oo.join(t,"src","store","rootReducer.ts"),i=Oo.join(t,"src","store","index.ts"),a=G(r),c=o.replace(/^src\//,"@/");try{let l=await Ro(s,"utf-8");if(l=Ge(l,`import { ${a}Slice } from '${c}';`),l=Tr(l,`${a}Slice`),await Co(s,l),n&&w(i)){let p=await Ro(i,"utf-8");p=Ge(p,`import { ${a}Persistence } from '${c}';`),p=jr(p,`${a}Persistence`),await Co(i,p)}}catch(l){throw new Error(`Failed to register slice '${r}': ${l}`,{cause:l})}};import{readFile as sc,writeFile as ic}from"node:fs/promises";import ac from"node:path";var Te=async(e,t)=>{let r=ac.join(e,"src","i18n","translations","en.json");if(!w(r))return;let n=await sc(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await ic(r,`${JSON.stringify(o,null,2)}
606
- `))};import cc from"enquirer";var{prompt:pc}=cc,Ao=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 pc(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Io=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").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(`
618
+ `)},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)}
619
+ `))};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("--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(`
607
620
  \u{1F9E9} Component Generator
608
- `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=await Ao(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=lc(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?Fr.join(n,r.feature,"components",`${a}.tsx`):Fr.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(`
621
+ `)),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(`
609
622
  \u2728 Component '${a}' created successfully!
610
- `)),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} ${Fr.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)}})},lc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import{spawnSync as mc}from"node:child_process";import _ from"picocolors";var uc=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}`}},No=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 Fn(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 Mn(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=mc(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(`
623
+ `)),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(`
611
624
  \u{1FA7A} Project Doctor
612
625
  `)),m(_.dim(` ${o.starter.name} ${o.starter.version} \xB7 ${s.source.location}
613
- `));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")} ${uc(u)}`)}a&&m(_.green(`
626
+ `));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(`
614
627
  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(`
615
628
  `).slice(-30).join(`
616
629
  `)))),m(""),l.length===0&&c?.ok!==!1&&(m(_.green(`\u2713 No drift detected.
617
630
  `)),process.exit(0)),l.length&&!t.fix&&m(_.dim(`Run with --fix to restore missing pieces from the starter.
618
- `)),process.exit(1)}catch(o){b(`${o instanceof Error?o.message:o}`),process.exit(1)}finally{await n?.()}})};import Be from"picocolors";var Fo=new Set(["string","url","number","boolean","enum"]),dc=e=>{let t=(e??"string").toLowerCase();if(!Fo.has(t))throw new Error(`Invalid --type "${e}". Valid: ${Array.from(Fo).join(", ")}.`);return t},fc=e=>{if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean);return t.length===0?void 0:t},Mo=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(`
631
+ `)),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(`
619
632
  \u{1F510} Env Var Generator
620
- `)),r.required&&r.default!==void 0)throw new Error("--required and --default are mutually exclusive.");let s=dc(r.type),i=fc(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 Ir(n,a);h.succeed("Env var written");let l=se(a.name,a.public);await k(n,o),m(Be.green(`
633
+ `)),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(`
621
634
  \u2728 ${l} declared in the ${c.group} group.
622
- `)),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 gc from"enquirer";var{prompt:hc}=gc,_o=async(e={})=>e.source?{source:e.source}:{source:(await hc({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 yc,readFile as wc,stat as xc}from"node:fs/promises";import je from"node:path";var Do=async e=>{try{return await yc(e),!0}catch{return!1}},bc=async e=>{try{return(await xc(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 bc(r))return r;return null},vc=["next-pwa","@ducanh2912/next-pwa","@serwist/next","serwist"],Mr=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 Do(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 Do(s)){t.appManifestPath=s,t.isPwa=!0;break}}try{let o=JSON.parse(await wc(je.join(e,"package.json"),"utf-8")),s={...o.dependencies,...o.devDependencies};for(let i of vc)if(s[i]){t.framework=i,t.isPwa=!0;break}}catch{}return t};import{mkdir as Ec,readFile as Wo,stat as Tc,writeFile as jc}from"node:fs/promises";import Y from"node:path";import Rc from"sharp";import kc from"png-to-ico";import ut from"sharp";var Lo=e=>e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),_r=(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 $c(t)}},$c=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="${Lo(n)}" fill="white"/></svg>`},Uo=(e,t)=>`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}"><rect width="${e}" height="${e}" fill="${Lo(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 Dr(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,E=Buffer.from(_r(x,t,i));y=await ut(y).composite([{input:E,blend:"dest-in"}]).png({compressionLevel:Go(a)}).toBuffer()}else y=await ut(y).png({compressionLevel:Go(a)}).toBuffer();return y},Dr=async e=>{let t=await ut(Buffer.from(Uo(1,e))).raw().toBuffer({resolveWithObject:!0}),[r,n,o,s=255]=t.data;return{r,g:n,b:o,alpha:s/255}},Go=e=>{let t=Math.round((100-e)/100*9);return Math.max(0,Math.min(9,t))},Bo=async e=>{if(e.length===0)throw new Error("No frames provided to encodeIco");return kc(e)};import{readFile as Pc,writeFile as Xf}from"node:fs/promises";var Vo=e=>e.map(({src:t,size:r})=>({src:t,sizes:`${r}x${r}`,type:"image/png",purpose:"any maskable"})),Ho=async(e,t)=>{let r=await Pc(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)}
623
- `};var qo=e=>`icons: [
635
+ `)),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)}
636
+ `};var zo=e=>`icons: [
624
637
  ${e.map(r=>` { src: '${r.src}', sizes: '${r.sizes}', type: '${r.type}'${r.purpose?`, purpose: '${r.purpose}'`:""} }`).join(`,
625
638
  `)},
626
- ],`,Jo=(e,t,r)=>`${JSON.stringify({name:e,short_name:e,start_url:"/",display:"standalone",background_color:"#ffffff",theme_color:t,icons:r},null,2)}
627
- `;import{stat as Sc}from"node:fs/promises";import Lr from"node:path";var zo=[".png",".jpg",".jpeg",".webp",".svg",".avif"],Gt=async e=>{if(!e)throw new Error("Source image path is required (use --path).");let t=Lr.isAbsolute(e)?e:Lr.resolve(process.cwd(),e),r;try{r=await Sc(t)}catch{throw new Error(`Source image not found: ${t}`)}if(!r.isFile())throw new Error(`Source is not a file: ${t}`);let n=Lr.extname(t).toLowerCase();if(!zo.includes(n))throw new Error(`Unsupported source format '${n}'. Use one of: ${zo.join(", ")}`);return{absolutePath:t,ext:n,bytes:r.size,isVector:n===".svg"}};var Ur=(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 Cc=async e=>{try{return await Tc(e),!0}catch{return!1}},Oc=async(e,t,r)=>{let n=[];for(let o of e){if(await Cc(o.outPath)&&!t&&!o.alwaysWrite){n.push({path:o.outPath,bytes:o.bytes.length,skipped:!0});continue}r||(await Ec(Y.dirname(o.outPath),{recursive:!0}),await jc(o.outPath,o.bytes)),n.push({path:o.outPath,bytes:o.bytes.length})}return n},Gr=async(e,t)=>{let r=await Gt(t.source),n=await Wo(r.absolutePath),o=t.ogSource?await Wo((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 Bo(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 Ko(o,t,!1);s.push({outPath:Y.join(t.outDir,"opengraph-image.png"),bytes:p})}if(t.emitTwitter){let p=await Ko(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 Mr(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 S=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:S}),d.push({src:`/${x}`,size:y})}let g=Vo(d);if(p.publicManifestPath){let y=await Ho(p.publicManifestPath,g);s.push({outPath:p.publicManifestPath,bytes:Buffer.from(y,"utf-8"),alwaysWrite:!0})}else if(p.appManifestPath)c=qo(g);else if(t.pwaInit){let y=Y.join(u,"manifest.webmanifest"),S=Jo(Y.basename(e)||"App","#000000",g);s.push({outPath:y,bytes:Buffer.from(S,"utf-8")})}}return{outputs:await Oc(s,t.force,t.dryRun),pwaSnippet:c}},Ko=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 Dr(a),l=Math.round((1200-s)/2),p=Math.round((o-s)/2);return Rc({create:{width:1200,height:o,channels:4,background:c}}).composite([{input:i,left:l,top:p}]).png().toBuffer()};var Xo=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 Ac=["square","rounded","circle","squircle"],Ic=["contain","cover","clip"],Yo=(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},Br=(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},Zo=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(`
639
+ ],`,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)}
640
+ `;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(`
628
641
  \u{1F3A8} Favicon Generator
629
- `));let n=await _o({source:t.path}),o=await Nc(r,t.out),s=Yo(t.shape,Ac,"square","shape"),i=Yo(t.fit,Ic,"contain","fit"),a=Br(t.radius,20,"radius",0,50),c=Br(t.padding,0,"padding",0,30),l=Br(t.quality,90,"quality",1,100),p=Ur(t.sizes,[16,32,48]),u=t.bg??"transparent";_c(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 Gr(r,d);h.succeed(d.dryRun?"Favicon plan ready":"Favicon assets generated"),m("");for(let y of g.outputs){let S=Bt.relative(r,y.path);y.skipped?m(Re.yellow(` \u21B7 skipped ${S} (exists; use --force to overwrite)`)):d.dryRun?m(Re.dim(` \u{1F4C4} would write ${S} (${Qo(y.bytes)})`)):m(Re.green(` \u2713 ${S} `)+Re.dim(`(${Qo(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)}})},Nc=async(e,t)=>{if(t)return Bt.isAbsolute(t)?t:Bt.resolve(e,t);let r=await Ut(e);return r||(wn("Could not detect app/ or src/app/ \u2014 falling back to src/app"),Bt.join(e,"src","app"))},Fc=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Mc=/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/]+\)$/i,_c=e=>{if(e!=="transparent"&&!Fc.test(e)&&!Mc.test(e)&&!Xo.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().`)},Qo=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`;import Vr from"node:path";import D from"picocolors";import Dc from"enquirer";var{prompt:Lc}=Dc,es=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 Lc(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 rs=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(`
642
+ `));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(`
630
643
  \u{1F3AF} Feature Generator
631
644
  `)),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"}
632
- `));let i=await es(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||Vr.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:Vr.join(a,i.featureName,"store")}),h.succeed("Slice registered")),await k(n,o),Uc(i,a,s.state)}catch(n){h.fail("Feature generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})},Uc=(e,t,r)=>{let n=Vr.join(t,e.featureName);m(D.green(`
645
+ `));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(`
633
646
  \u2728 Feature '${e.featureName}' created.
634
- `)),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${ts(e.featureName)}s } from '@/features/${e.featureName}/server'`)),m(D.dim(` 3. Prefetch + hydrate for the client list: prefetchQuery(${Gc(e.featureName)}ListQuery())`))),e.createStore&&r==="zustand"&&m(D.yellow(` ! Compose create${ts(e.featureName)}Slice into AppState in src/store/index.ts`)),m("")},Gc=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),ts=$;import Hr from"node:path";import He from"picocolors";import Bc from"enquirer";var{prompt:Vc}=Bc,ns=async e=>e?{hookName:e}:await Vc({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 os=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(`
647
+ `)),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(`
635
648
  \u{1FA9D} Hook Generator
636
- `));let s=await O(n),i=await ns(t);M(i.hookName,"hook name"),r.feature&&W(r.feature,"feature path");let c=`use${$(i.hookName)}`,l=Hc(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?Hr.join(n,r.feature,"hooks",`${c}.ts`):Hr.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(`
649
+ `));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(`
637
650
  \u2728 Hook '${c}' created successfully!
638
- `)),m(He.dim(` \u{1F4C4} ${f}`)),u&&m(He.dim(` \u{1F9EA} ${Hr.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)}})},Hc=(e,t)=>e.test===!1?!1:e.test===!0?!0:t;import Vt from"picocolors";var ss=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(`
651
+ `)),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(`
639
652
  \u{1F4D0} Layout Generator
640
653
  `)),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"}
641
654
  `)),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(`
642
655
  \u2728 ${a.componentName} created!
643
- `)),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 qc from"enquirer";var{prompt:Jc}=qc,is=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 Jc(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 as=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of 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(`
656
+ `)),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("--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(`
644
657
  \u{1F30D} Locale Generator
645
658
  `)),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(`
646
659
  Run: npx @teispace/next-maker setup --i18n
647
- `)),process.exit(1));let i=await is(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(`
660
+ `)),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(`
648
661
  \u2728 Locale '${i.code}' (${i.name}) added successfully!
649
- `)),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 zc from"node:path";import dt from"picocolors";var cs=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(zc.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(`
662
+ `)),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(`
650
663
  ${i.manifest.starter.name} ${i.manifest.starter.version}
651
- `));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 qr from"node:path";import H from"picocolors";import Wc from"enquirer";var{prompt:Kc}=Wc,ps=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 Kc(r):{};return{pageName:e??n.pageName,withLoading:t.loading??n.withLoading??!0,withError:t.error??n.withError??!0}};var ls=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(`
664
+ `));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(`
652
665
  \u{1F4C4} Page Generator
653
666
  `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),m(H.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
654
- `));let i=await ps(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=qr.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 Pr({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 Cr(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?qr.join(l,a,`[${r.dynamic}]`):qr.join(l,a);await k(n,o),m(H.green(`
667
+ `));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(`
655
668
  \u2728 Page '${a}' created successfully!
656
- `)),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 Jr from"node:path";import fe from"picocolors";var ms=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(`
669
+ `)),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(`
657
670
  \u{1F50C} Provider Generator
658
- `)),h.start("Generating provider...");let{componentName:o,fileBaseName:s,providerFile:i}=await Er({name:t,projectPath:r});h.succeed("Provider generated"),h.start("Registering provider in RootProvider and barrel...");let{rootProviderFile:a,barrelFile:c}=await Nr({projectPath:r,componentName:o,fileBaseName:s});h.succeed("Provider registered"),await k(r,n),m(fe.green(`
671
+ `)),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(`
659
672
  \u2728 ${o} created!
660
- `)),m(fe.dim("Generated files:")),m(fe.dim(` \u{1F4C4} ${Jr.relative(r,i)}`)),a?m(fe.dim(` \u270F\uFE0F ${Jr.relative(r,a)} \u2014 wrapped {children}`)):(m(fe.yellow(`
661
- \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 ${Jr.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 Xc from"picocolors";var us=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",`
662
- ${Xc.dim("Example: next-maker remove ws")}
663
- `)};import zr from"node:path";import Wr from"picocolors";var ds=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(Wr.cyan(`
673
+ `)),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(`
674
+ \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",`
675
+ ${Qc.dim("Example: next-maker remove ws")}
676
+ `)};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(`
664
677
  \u{1F50C} API Layer Generator
665
- `)),!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(zr.join(i,"api","schema.ts")))throw new Error(`${zr.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(Wr.green(`
666
- \u2728 ${zr.relative(n,i)}/api ready.
667
- `));for(let c of a)m(Wr.dim(` ${c}`));m("")}catch(n){h.fail("API generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import wp from"enquirer";import q from"picocolors";import{execFile as op}from"node:child_process";import{cp as ey,mkdir as bs,readFile as sp,rm as vs,stat as ty,writeFile as qt}from"node:fs/promises";import ee from"node:path";import{promisify as ip}from"node:util";var Kr=(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,Yc=(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),Qc=(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]),fs=(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},Xr=(e,t)=>e.map(r=>({start:r.start+t,end:r.end+t,insert:r.insert})),gs=(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,S=!0;for(;S;){for(S=!1;g+1<t.length&&t[g+1].start<d;)g++,d=Math.max(d,t[g].end),S=!0;for(;y+1<r.length&&r[y+1].start<d;)y++,d=Math.max(d,r[y].end),S=!0}let x=n(e.slice(f,d),Xr(t.slice(i,g+1),-f),Xr(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(Qc(p,u)){c(p),i++,a++;continue}if(Yc(p,u)){let d=Z(p)&&!Z(u)?fs(e,p,u):Z(u)&&!Z(p)?fs(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},Zc=(e,t,r,n)=>{let o=Kr(e,t),s=Kr(e,r);return o&&s?gs(e,o,s,n):null},ep=/\s+|[\p{L}\p{N}_$]+\s*|[^\s\p{L}\p{N}_$]\s*/gu,hs=e=>e.match(ep)??[],tp=e=>e.flatMap(t=>hs(`${t}
678
+ `)),!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(`
679
+ \u2728 ${Wr.relative(n,i)}/api ready.
680
+ `));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}
668
681
  `)),ft=e=>{if(e==="")return[];let t=e.split(`
669
682
  `);return t[t.length-1]===""&&t.pop(),t},Ht=e=>e.length?`${e.join(`
670
683
  `)}
671
- `:"",rp=(e,t,r)=>{let n=[],o=[];for(let l of e)o.push(n.length),n.push(...hs(`${l}
672
- `));o.push(n.length);let s=l=>{let p=[];for(let u of l){let f=o[u.start],d=Kr(n.slice(f,o[u.end]),tp(u.insert));if(!d)return null;p.push(...Xr(d,f))}return p},i=s(t),a=s(r);if(!i||!a)return null;let c=gs(n,i,a);return c?ft(c.join("")):null},np=(e,t,r)=>{let n=Zc(ft(t),ft(e),ft(r),rp);return n?Ht(n):null},ys=(e,t)=>{let r=e.split(`
684
+ `:"",op=(e,t,r)=>{let n=[],o=[];for(let l of e)o.push(n.length),n.push(...ws(`${l}
685
+ `));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(`
673
686
  `),n=e.endsWith(`
674
- `);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=np(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(`
687
+ `);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(`
675
688
  `)+(n?`
676
- `:""),conflicts:s}};var ap=ip(op),cp=new Set(["pnpm-lock.yaml","package-lock.json","yarn.lock","bun.lock","bun.lockb",".env",".next-maker.json","next-env.d.ts","tsconfig.tsbuildinfo"]),pp=e=>cp.has(e)||e.startsWith(".env.")||e.endsWith(".log"),lp=new Set([".png",".jpg",".jpeg",".gif",".webp",".avif",".ico",".woff",".woff2",".ttf",".otf",".pdf",".zip",".gz"]),Yr=(e,t)=>lp.has(ee.extname(e))||t.subarray(0,8e3).includes(0),Qr=async e=>{try{return await sp(e)}catch{return null}},gt=async(e,t,r)=>{r||(await bs(ee.dirname(e),{recursive:!0}),await qt(e,t))},ws=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 bs(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 ap("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 ys(i.stdout,n);throw i.code==="ENOENT"?new Error("git is required for merges but was not found on PATH."):s}}finally{await vs(o,{recursive:!0,force:!0})}},xs=["scripts","dependencies","devDependencies","peerDependencies","optionalDependencies","engines"],mp=(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 xs){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)]))xs.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??pp,[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,S)=>{f.entries.push({file:g,outcome:y,note:S}),y==="conflict"&&f.conflicts.push(g)};for(let g of[...new Set([...i,...a])].sort()){if(s(g))continue;let y=p.has(g),S=u.has(g),x=l.has(g),[E,j,U]=await Promise.all([y?Qr(ee.join(e,g)):null,S?Qr(ee.join(t,g)):null,x?Qr(ee.join(r,g)):null]),Oe=ee.join(r,g);if(S&&!y){if(!x)await gt(Oe,j,o),d(g,"added");else if(U.equals(j))d(g,"unchanged");else if(Yr(g,j))d(g,"kept","starter added a binary the project also has");else{let ht=await ws(U.toString("utf8"),"",j.toString("utf8"));await gt(Oe,ht.content,o),d(g,ht.conflicts?"conflict":"merged")}continue}if(y&&!S){if(!x)continue;U.equals(E)?(o||await vs(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(E.equals(j)||U.equals(j)){d(g,"unchanged");continue}if(U.equals(E)){await gt(Oe,j,o),d(g,"updated");continue}if(Yr(g,U)||Yr(g,j)){d(g,"kept","binary changed on both sides");continue}if(g==="package.json"){let{result:ht,conflicts:yt}=mp(JSON.parse(U.toString("utf8")),JSON.parse(E.toString("utf8")),JSON.parse(j.toString("utf8")));await gt(Oe,`${JSON.stringify(ht,null,2)}
677
- `,o),d(g,yt.length?"conflict":"merged",yt.length?`project kept: ${yt.join(", ")}`:void 0),yt.length&&f.conflicts.pop();continue}let nn=await ws(U.toString("utf8"),E.toString("utf8"),j.toString("utf8"));await gt(Oe,nn.content,o),d(g,nn.conflicts?"conflict":"merged")}return f};import{mkdtemp as up,readFile as dp,rm as $s}from"node:fs/promises";import{tmpdir as fp}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 dp(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})},ks=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}},Zr=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 up(ge.join(fp(),"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:()=>$s(s,{recursive:!0,force:!0})}}catch(a){throw await $s(s,{recursive:!0,force:!0}),a}};import gp from"enquirer";import T from"picocolors";var{prompt:hp}=gp,yp={added:T.green("+"),updated:T.cyan("\u2191"),merged:T.cyan("\u21C4"),deleted:T.red("-"),conflict:T.red("\u2717"),kept:T.yellow("\xB7"),skipped:T.dim("\xB7")},en=e=>{let t=e.entries.filter(n=>n.outcome!=="unchanged");if(t.length===0){m(T.dim(" no file changes"));return}for(let n of t)m(` ${yp[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(m(""),m(T.dim(` ${Object.entries(r).map(([n,o])=>`${o} ${n}`).join(", ")}`)),e.conflicts.length){m(""),m(T.red(` ${e.conflicts.length} file(s) need attention; look for <<<<<<< markers:`));for(let n of e.conflicts)m(T.red(` ${n}`))}},Ps=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?Zr(t.from):ks(o),a=t.to?Zr(t.to):V({starterPath:t.starterPath,ref:Et});if(i.location===a.location){m(T.dim(`Already on ${a.location}; nothing to upgrade.`));return}m(T.cyan(`
689
+ `:""),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)}
690
+ `,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(`
678
691
  \u2B06 Upgrade
679
- `)),m(` ${T.dim("from")} ${i.location}`),m(` ${T.dim("to ")} ${a.location}
680
- `);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(T.yellow(` ! ${d.reason}; ${d.option} turned off`));for(let d of l.scaffold.unknown)m(T.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(en(p),t.dryRun){m(T.dim(`
692
+ `)),m(` ${S.dim("from")} ${i.location}`),m(` ${S.dim("to ")} ${a.location}
693
+ `);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(`
681
694
  Dry run: nothing was written.
682
- `));return}if(!t.yes){let{confirm:d}=await hp({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!d){m(T.yellow(`Aborted.
683
- `));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(T.dim(`
684
- Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(T.green(`
685
- \u2713 Upgraded to ${l.scaffold.manifest.starter.version}.`)),f.conflicts.length?m(T.yellow(" Resolve the conflicts above, then run `next-maker doctor --compile`.")):m(T.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:xp}=wp,bp=(e,t=[])=>[...t,e],Ss=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",bp).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(`
695
+ `));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.
696
+ `));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(`
697
+ Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(S.green(`
698
+ \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(`
686
699
  \u{1F527} Setup
687
700
  `)),p.length===0){m(q.dim(`No option changes; the project already has these values.
688
- `));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(en(g),t.dryRun){m(q.dim(`
701
+ `));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(`
689
702
  Dry run: nothing was written.
690
- `));return}if(!t.yes){let{confirm:x}=await xp({type:"confirm",name:"confirm",message:"Apply these changes?",initial:!1});if(!x){m(q.yellow(`Aborted.
691
- `));return}}let y=Date.now(),S=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(`
703
+ `));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.
704
+ `));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(`
692
705
  Installing with ${o.packageManager}...`)),await le(r,o.packageManager)),m(q.green(`
693
- \u2713 Applied.`)),S.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 tn from"node:path";import zt from"picocolors";import vp from"enquirer";var{prompt:$p}=vp,Es=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 $p(r):{};return{sliceName:e||n.sliceName,persistSlice:t===void 0?n.persistSlice||!1:t}};var Ts=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(`
706
+ \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(`
694
707
  \u{1F527} Slice Generator
695
708
  `)),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}
696
- `));let i=await Es(t,s.state==="zustand"?!1:r.persist);M(i.sliceName,"slice name"),r.path&&W(r.path,"path");let a=r.path??tn.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:tn.join(a,i.sliceName)}),h.succeed("Slice registered"),(r.test??s.hasTests)&&(h.start("Generating test..."),await oe({projectPath:n,sourceFile:tn.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(`
709
+ `));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(`
697
710
  \u2728 Slice '${i.sliceName}' created in ${a}/${i.sliceName}/.
698
- `)),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 rn from"picocolors";var js=e=>{e.command("test <file>").description(`Generate a sibling test file for an existing component, hook, or slice.
699
- 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(rn.cyan(`
711
+ `)),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.
712
+ 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(`
700
713
  \u{1F9EA} Test Generator
701
- `)),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=kp(r.kind)??Pp(s,a);c||(b(`Could not infer test kind for ${J.basename(s)}. Pass --kind component|hook|slice.`),process.exit(1));let l=Sp(s,c),p=Ep(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(rn.green(`
714
+ `)),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(`
702
715
  \u2728 Test '${J.basename(u)}' created.
703
- `)),m(rn.dim(` \u{1F9EA} ${J.relative(n,u)}`)),m("")}catch(n){h.fail("Test generation failed"),b(`${n}`),process.exit(1)}})},kp=e=>{if(!e)return null;if(e==="component"||e==="hook"||e==="slice")return e;throw new Error(`Invalid --kind: ${e}. Use component | hook | slice.`)},Pp=(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},Sp=(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)},Ep=(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 Tp,cp as jp,mkdir as Wt,readFile as Kt,rm as Rp,writeFile as N}from"node:fs/promises";import v from"node:path";import he from"picocolors";var Rs=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)}
704
- `},Cs=e=>`packages:
716
+ `)),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)}
717
+ `},As=e=>`packages:
705
718
  - 'apps/*'
706
719
  - 'packages/*'
707
720
 
708
721
  ${e.split(`
709
722
  `).filter(r=>!r.startsWith("packages:")&&!r.startsWith("# Single-package")&&!r.startsWith("# Monorepo mode")).join(`
710
723
  `).trim()}
711
- `,Os=()=>`${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)}
712
- `,As=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)}
713
- `,Is=()=>`# dependencies
724
+ `,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)}
725
+ `,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)}
726
+ `,Fs=()=>`# dependencies
714
727
  node_modules
715
728
  .pnpm-store
716
729
 
@@ -736,7 +749,7 @@ next-env.d.ts
736
749
  *.pem
737
750
  npm-debug.log*
738
751
  .pnpm-debug.log*
739
- `,Ns=(e,t)=>`# ${e.name}
752
+ `,Ms=(e,t)=>`# ${e.name}
740
753
 
741
754
  ${e.description}
742
755
 
@@ -805,7 +818,7 @@ Ranges shared by every app live in the \`catalog:\` section of \`pnpm-workspace.
805
818
  ## Maintenance
806
819
 
807
820
  \`cd apps/<app> && npx @teispace/next-maker doctor --compile\` checks an app against the starter; \`setup --set <option>=<value>\` changes its features.
808
- `,Fs=()=>`name: CI
821
+ `,_s=()=>`name: CI
809
822
 
810
823
  on:
811
824
  push:
@@ -847,12 +860,12 @@ jobs:
847
860
  - run: pnpm check:deprecated
848
861
  - run: pnpm test
849
862
  - run: pnpm build
850
- `,Ms=()=>`const config = {
863
+ `,Ds=()=>`const config = {
851
864
  '*': ['biome check --write --no-errors-on-unmatched --files-ignore-unknown=true'],
852
865
  };
853
866
 
854
867
  export default config;
855
- `,_s=()=>`const config = {
868
+ `,Ls=()=>`const config = {
856
869
  extends: ['@commitlint/config-conventional'],
857
870
  rules: {
858
871
  'header-max-length': [2, 'always', 150],
@@ -861,13 +874,13 @@ export default config;
861
874
  };
862
875
 
863
876
  export default config;
864
- `,Ds=()=>({"pre-commit":`#!/usr/bin/env sh
877
+ `,Us=()=>({"pre-commit":`#!/usr/bin/env sh
865
878
  pnpm lint-staged
866
879
  `,"commit-msg":`#!/usr/bin/env sh
867
880
  pnpm exec commitlint --edit "$1"
868
881
  `,"pre-push":`#!/usr/bin/env sh
869
882
  pnpm ci:check && pnpm type-check && pnpm check:deprecated && pnpm test
870
- `}),Ls=(e,t="24")=>`# syntax=docker.io/docker/dockerfile:1
883
+ `}),Gs=(e,t="24")=>`# syntax=docker.io/docker/dockerfile:1
871
884
  # Build from the workspace root:
872
885
  # docker build -f apps/${e}/Dockerfile -t ${e} .
873
886
 
@@ -920,7 +933,7 @@ EXPOSE 3000
920
933
  HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \\
921
934
  CMD wget -qO- http://127.0.0.1:3000/robots.txt >/dev/null || exit 1
922
935
  CMD ["node", "apps/${e}/server.js"]
923
- `,Us=e=>`services:
936
+ `,Bs=e=>`services:
924
937
  ${e.map((r,n)=>` ${r}:
925
938
  build:
926
939
  context: .
@@ -937,7 +950,7 @@ ${e.map((r,n)=>` ${r}:
937
950
  API_INTERNAL_URL: \${API_INTERNAL_URL}`).join(`
938
951
 
939
952
  `)}
940
- `,Gs=()=>`node_modules
953
+ `,Vs=()=>`node_modules
941
954
  **/node_modules
942
955
  .git
943
956
  .turbo
@@ -947,12 +960,12 @@ ${e.map((r,n)=>` ${r}:
947
960
  **/test-results
948
961
  **/.env
949
962
  **/.env.*
950
- `,Bs=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)))},Vs=(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},Hs=e=>Object.keys(e).length?`
963
+ `,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?`
951
964
  catalog:
952
965
  ${Object.entries(e).map(([t,r])=>` '${t}': '${r}'`).join(`
953
966
  `)}
954
- `:"";var Cp=(e,t=[])=>[...t,e],qs={hooks:!1,commitizen:!1,ci:!1,docker:!1,githubTemplates:!1,communityFiles:[]},Js=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)",Cp).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 Ap(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)}},Op=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},Ap=async(e,t)=>{Pt(),rt(e);let r=Op(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(qs))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(`
967
+ `:"";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(`
955
968
  Cleaning up ${e}...`)),await tt(n))},a=$t(async()=>{m(he.red(`
956
- 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,...qs,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 E=v.join(n,"apps",x);await Ce(`Composing apps/${x}...`,`apps/${x} composed.`,async()=>{let j=await ve({projectPath:E,source:c,supplied:p.answers,packageManager:"pnpm"});await $e(E,g(x),j,c)},s)}let y=[];for(let x of r){let E=v.join(n,"apps",x);for(let U of["pnpm-workspace.yaml","pnpm-lock.yaml",".npmrc",".nvmrc"])await Rp(v.join(E,U),{force:!0});let j=JSON.parse(await Kt(v.join(E,"package.json"),"utf-8"));delete j.packageManager,delete j.engines,y.push(j)}let S=t.catalog===!1?{}:Bs(y);for(let[x,E]of r.entries()){let j=Vs(y[x],S);await N(v.join(n,"apps",E,"package.json"),`${JSON.stringify(j,null,2)}
957
- `),t.docker&&await N(v.join(n,"apps",E,"Dockerfile"),Ls(E))}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"),Rs(x)),await N(v.join(n,"pnpm-workspace.yaml"),Cs(f)+Hs(S)),await N(v.join(n,"turbo.json"),Os()),await N(v.join(n,"biome.json"),As(x.biomeVersion)),await N(v.join(n,".gitignore"),Is()),await N(v.join(n,"README.md"),Ns(x,p.manifest.starter.version)),await N(v.join(n,"packages",".gitkeep"),"");for(let[E,j]of Object.entries(d))await N(v.join(n,E),j);if(t.docker&&(await N(v.join(n,"docker-compose.yml"),Us(r)),await N(v.join(n,".dockerignore"),Gs())),t.ci!==!1&&(await Wt(v.join(n,".github","workflows"),{recursive:!0}),await N(v.join(n,".github","workflows","ci.yml"),Fs())),t.hooks!==!1){await N(v.join(n,".lintstagedrc.mjs"),Ms()),await N(v.join(n,"commitlint.config.mjs"),_s()),await Wt(v.join(n,".husky"),{recursive:!0});for(let[E,j]of Object.entries(Ds())){let U=v.join(n,".husky",E);await N(U,j),await Tp(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)}
958
- `)},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 E=v.join(n,"apps",x,".env.example");w(E)&&await jp(E,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 zs=e=>{Un(e),Js(e),Ss(e),cs(e),Ps(e),rs(e),Ts(e),ds(e),ls(e),ss(e),Io(e),as(e),os(e),ms(e),Mo(e),Zo(e),No(e),us(e),js(e)};var Np=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 Np.apply(process,arguments)};async function Fp(){yn({logger:t=>kt(t)});let e=new Ip;e.name("next-maker").description("Teispace Next.js Project Generator").version(Ae.version),zs(e),e.parse()}Fp().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);kt(`Unexpected error: ${t}`)});
969
+ 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)}
970
+ `),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)}
971
+ `)},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}`)});