generatesaas 0.10.3 → 0.10.4
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/README.md +1 -1
- package/dist/index.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ generatesaas init
|
|
|
34
34
|
generatesaas init -n my-app --yes
|
|
35
35
|
|
|
36
36
|
# Fully customized
|
|
37
|
-
generatesaas init -n my-app --payment stripe --database neon --deploy
|
|
37
|
+
generatesaas init -n my-app --payment stripe --database neon --deploy vercel --yes
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
**Flags:**
|
package/dist/index.js
CHANGED
|
@@ -470,7 +470,7 @@ import app from "@repo/api";
|
|
|
470
470
|
|
|
471
471
|
export default handle(app);
|
|
472
472
|
`}var Gr={smtp:[{key:"SMTP_HOST",defaultValue:"localhost"},{key:"SMTP_PORT",defaultValue:"1025"}],ses:[{key:"AMAZON_SES_REGION",comment:"# TODO: Configure Amazon SES credentials (e.g. us-east-1)"},{key:"AMAZON_SES_KEY"},{key:"AMAZON_SES_SECRET"}],resend:[{key:"RESEND_API_KEY",comment:"# TODO: Add your Resend API key"}]},Hr={stripe:[{key:"STRIPE_SECRET_KEY",comment:"# TODO: Add your Stripe keys"},{key:"STRIPE_WEBHOOK_SECRET"}],polar:[{key:"POLAR_ACCESS_TOKEN",comment:"# TODO: Add your Polar keys"},{key:"POLAR_WEBHOOK_SECRET"}]};function Ke(e,t){return t?e.map(r=>{let i=t[r.key];return i?{...r,defaultValue:i,comment:void 0}:r}):e}function Be(e,t){for(let r of e)r.comment&&t.push(r.comment),r.defaultValue!==void 0?t.push(`${r.key}=${r.defaultValue}`):t.push(`#${r.key}=`)}function Dt(e){return Array.from(crypto.getRandomValues(new Uint8Array(e))).map(t=>t.toString(16).padStart(2,"0")).join("")}function Yr(e){let t=crypto.randomUUID(),r=Dt(32),i=Dt(32),o=["# API Configuration",`API_URL=${e.architecture==="fullstack"?"http://localhost:3000/api":"http://localhost:3010"}`];o.push("","# Database"),Be(Ke(B[e.databaseProvider].envVars,e.credentials),o),o.push("","# Cache"),Be(Ke(G[e.cacheProvider].envVars,e.credentials),o),o.push("","# Authentication",`BETTER_AUTH_SECRET=${t}`,"","# Job Queue - Inngest","INNGEST_APP_ID=api",`INNGEST_EVENT_KEY=${r}`,`INNGEST_SIGNING_KEY=${i}`,"INNGEST_BASE_URL=http://127.0.0.1:8288"),e.architecture==="separate"&&o.push("","# API Port (standalone backend)","API_PORT=3010");let s=Gr[e.emailProvider];if(s&&(o.push("","# Email"),Be(Ke(s,e.credentials),o)),e.paymentProvider!=="none"){let a=Hr[e.paymentProvider];a&&(o.push("","# Payment"),Be(Ke(a,e.credentials),o))}return o.push(""),o.join(`
|
|
473
|
-
`)}var qr={
|
|
473
|
+
`)}var qr={vercel:"vercel"};function Wr(e){let r=["# API Configuration",`NUXT_PUBLIC_API_URL=${e.architecture==="fullstack"?"http://localhost:3000/api":"http://localhost:3010"}`];if(e.architecture==="fullstack"){let i=qr[e.deploymentTarget];i&&r.push("","# Build",`NITRO_PRESET=${i}`)}return r.push(""),r.join(`
|
|
474
474
|
`)}async function Ot(e){let t=Yr(e),r=Wr(e);if(e.architecture==="fullstack"){let i=r+`
|
|
475
475
|
`+t;await d(`${e.projectDir}/apps/web-nuxt/.env`,i)}else await d(`${e.projectDir}/apps/web-nuxt/.env`,r),await d(`${e.projectDir}/apps/backend/.env`,t)}import{join as Lt,relative as Xr}from"path";import{createHash as Ct}from"crypto";import{readFile as Jr}from"fs/promises";async function Ge(e){let t=await Jr(e);return Ct("sha256").update(t).digest("hex")}function xt(e){return Ct("sha256").update(e).digest("hex")}var Zr=new Set(["data",x]);function Qr(e){let t=e.split("/");for(let r of t)if(et.has(r)||Zr.has(r)||r.startsWith(".env")&&!r.includes("example"))return!0;return!1}async function Nt(e,t){let i=(await ce(e.projectDir,e.projectDir,Qr)).sort(),n=await Promise.all(i.map(async a=>[Xr(e.projectDir,a),await Ge(a)])),o=Object.fromEntries(n),s={version:e.version,initialVersion:e.version,repo:"Duzbee/GenerateSaaS",frontend:e.frontend,aiTools:e.aiTools,deploymentTarget:e.deploymentTarget,databaseProvider:e.databaseProvider,cacheProvider:e.cacheProvider,revenueSharing:e.revenueSharing,...t&&{licenseToken:t.token,licenseKeyHash:t.keyHash,installId:t.installId}};await d(Lt(e.projectDir,W),JSON.stringify(s,null," ")+`
|
|
476
476
|
`),await d(Lt(e.projectDir,ht),JSON.stringify(o,null," ")+`
|
|
@@ -781,7 +781,7 @@ ${n}
|
|
|
781
781
|
`)}import{relative as ln}from"path";async function Ie(e){let r=(await ce(e,e,fe)).sort(),i=await Promise.all(r.map(async n=>[ln(e,n),await Ge(n)]));return Object.fromEntries(i)}import{copyFile as dn,mkdir as mn,rm as un}from"fs/promises";import{dirname as fn,join as Mt,relative as gn}from"path";import{existsSync as yn}from"fs";async function Ft(e,t){let r=Mt(t,Fe);yn(r)&&await un(r,{recursive:!0,force:!0});let i=await ce(e,e,fe);for(let n of i){let o=gn(e,n),s=Mt(r,o);await mn(fn(s),{recursive:!0}),await dn(n,s)}}import{existsSync as hn}from"fs";import{readFile as zt,readdir as vn}from"fs/promises";import{join as M,dirname as Sn,resolve as En,sep as _n}from"path";import{fileURLToPath as An}from"url";var Te={"claude-code":".claude/skills",cursor:".cursor/skills",codex:".agents/skills","gemini-cli":".gemini/skills",windsurf:".windsurf/skills"},In=Object.values(Te),it="generatesaas-update",Kt=Sn(An(import.meta.url));function Tn(){let e=M(Kt,"skill","content");return hn(e)?e:M(Kt,"content")}function ot(e){return!e||e.length===0?In:e.map(t=>Te[t])}async function st(e,t,r,i){let n=ot(i);for(let o of n){let s=M(e,o,it),a=M(s,"scripts"),m=M(s,"references");await ze(a),await ze(m),await d(M(s,"SKILL.md"),t.replaceAll("__SKILL_ROOT__",o)),await d(M(m,".gitkeep"),"");for(let[S,E]of Object.entries(r)){let y=En(a,S);y.startsWith(a+_n)&&await d(y,E)}}}async function Bt(e,t){let r=Tn(),i=await zt(M(r,"SKILL.md"),"utf-8"),n=M(r,"scripts"),o=await vn(n),s={};for(let a of o)a!==".gitkeep"&&(s[a]=await zt(M(n,a),"utf-8"));await st(e,i,s,t)}import{execFile as Pn,execFileSync as wn}from"child_process";import{access as Rn}from"fs/promises";import{join as bn}from"path";import*as F from"@clack/prompts";function We(e){try{let t=process.platform==="win32"?"where":"which";return wn(t,[e],{stdio:"ignore"}),!0}catch{return!1}}function qe(e,t,r,i=3e5){return new Promise((n,o)=>{Pn(e,t,{cwd:r,timeout:i},s=>{s?o(s):n()})})}async function Gt(e){if(!We("pnpm"))return F.log.warn("pnpm not found. Skipping dependency installation."),F.log.info("Install pnpm: https://pnpm.io/installation"),!1;let t=F.spinner();t.start("Installing dependencies (this may take a minute)...");try{return await qe("pnpm",["install"],e),t.stop("Dependencies installed."),!0}catch{return t.stop("Dependency installation failed."),F.log.warn("pnpm install failed. You can run it manually later."),!1}}async function Ht(e){try{return await Rn(bn(e,".git")),F.log.info("Git repository already exists, skipping init."),!0}catch{}if(!We("git"))return F.log.warn("git not found. Skipping repository initialization."),!1;let t=F.spinner();t.start("Initializing git repository...");try{return await qe("git",["init"],e),await qe("git",["add","-A"],e),await qe("git",["commit","-m","Initial commit from GenerateSaaS"],e),t.stop("Git repository initialized."),!0}catch{return t.stop("Git initialization failed."),F.log.warn("You can run git init manually later."),!1}}import*as ge from"@clack/prompts";import N from"picocolors";function Yt(e,t){t.dockerComposeGenerated&&!t.dockerAvailable&&ge.log.warn("Docker not found. Install Docker to run local services: https://docs.docker.com/get-docker/");let r=[];if(r.push(`cd ${e.projectDir}`),t.pnpmInstalled||r.push("pnpm install"),t.dockerComposeGenerated){let o=e.dockerServices.map(s=>me[s].label).join(", ");r.push(`pnpm infra ${N.dim(`# ${o}`)}`)}if(r.push(`pnpm dev ${N.dim("# http://localhost:3000")}`),t.skippedCredentials.length>0&&(r.push(""),r.push(N.dim("Fill in remaining TODO values in .env"))),ge.note(r.join(`
|
|
782
782
|
`),N.yellow("Start Development")),t.dockerComposeGenerated){let o=[];o.push(`App ${N.cyan("http://localhost:3000")}`),e.architecture==="separate"&&o.push(`API ${N.cyan("http://localhost:3010")}`),e.dockerServices.includes("mailpit")&&o.push(`Mailpit ${N.cyan("http://localhost:8025")}`),e.dockerServices.includes("inngest")&&o.push(`Inngest ${N.cyan("http://localhost:8288")}`),ge.note(o.join(`
|
|
783
783
|
`),N.yellow("Dev Tools"))}let i=[],n=kn(e);n.length>0&&i.push(`Set in production: ${N.dim(n.join(", "))}`),i.push("pnpm db:push # Run database migrations"),i.push(Dn(e)),ge.note(i.join(`
|
|
784
|
-
`),N.yellow("Deployment"))}function kn(e){let t=["DATABASE_URL","BETTER_AUTH_SECRET"];return e.cacheProvider==="upstash"?t.push("UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"):t.push("REDIS_URL"),e.paymentProvider==="stripe"?t.push("STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET"):e.paymentProvider==="polar"&&t.push("POLAR_ACCESS_TOKEN","POLAR_WEBHOOK_SECRET"),e.emailProvider==="ses"?t.push("AMAZON_SES_REGION","AMAZON_SES_KEY","AMAZON_SES_SECRET"):e.emailProvider==="resend"?t.push("RESEND_API_KEY"):t.push("SMTP_HOST","SMTP_PORT"),t}function Dn(e){switch(e.deploymentTarget){case"node":return"Deploy with Docker or your preferred Node.js host";case"cloudflare":return
|
|
784
|
+
`),N.yellow("Deployment"))}function kn(e){let t=["DATABASE_URL","BETTER_AUTH_SECRET"];return e.cacheProvider==="upstash"?t.push("UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"):t.push("REDIS_URL"),e.paymentProvider==="stripe"?t.push("STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET"):e.paymentProvider==="polar"&&t.push("POLAR_ACCESS_TOKEN","POLAR_WEBHOOK_SECRET"),e.emailProvider==="ses"?t.push("AMAZON_SES_REGION","AMAZON_SES_KEY","AMAZON_SES_SECRET"):e.emailProvider==="resend"?t.push("RESEND_API_KEY"):t.push("SMTP_HOST","SMTP_PORT"),t}function Dn(e){switch(e.deploymentTarget){case"node":return"Deploy with Docker or your preferred Node.js host";case"cloudflare":return"wrangler deploy # Deploy to Cloudflare Workers";case"vercel":return"vercel deploy # Deploy to Vercel"}}function Wt(e){let t={};if(e.name!==void 0){if(!Ue(e.name))throw new Error(`Invalid project name "${e.name}". Use lowercase letters, numbers, and hyphens only. Must start with a letter.`);t.projectName=e.name}if(e.appName!==void 0){if(!e.appName.trim())throw new Error("App name cannot be empty.");t.appName=e.appName}if(e.location!==void 0?t.projectDir=e.location==="."?process.cwd():e.location:t.projectName!==void 0&&(t.projectDir=`./${t.projectName}`),e.frontend!==void 0&&(t.frontend=e.frontend),e.architecture!==void 0&&(t.architecture=e.architecture),e.payment!==void 0&&(t.paymentProvider=e.payment),e.email!==void 0&&(t.emailProvider=e.email),e.org!==void 0&&(t.multiTenancy=e.org),e.billingScope!==void 0){if(e.org===!1)throw new Error("--billing-scope requires --org to be enabled.");t.billingScope=e.billingScope}if(e.blog!==void 0&&(t.blog=e.blog),e.revenueSharing!==void 0&&(t.revenueSharing=e.revenueSharing),e.docker!==void 0&&(t.dockerServices=qt(e.docker,Le,"docker service")),e.aiTools!==void 0&&(t.aiTools=qt(e.aiTools,Ne,"AI tool")),e.currency!==void 0){if(!ne.includes(e.currency))throw new Error(`Invalid currency "${e.currency}". Valid values: ${ne.join(", ")}`);t.defaultCurrency=e.currency}if(e.deploy!==void 0){if(!ie.includes(e.deploy))throw new Error(`Invalid deployment target "${e.deploy}". Valid values: ${ie.join(", ")}`);t.deploymentTarget=e.deploy}if(e.database!==void 0){if(!oe.includes(e.database))throw new Error(`Invalid database provider "${e.database}". Valid values: ${oe.join(", ")}`);t.databaseProvider=e.database}if(e.cache!==void 0){if(!se.includes(e.cache))throw new Error(`Invalid cache provider "${e.cache}". Valid values: ${se.join(", ")}`);t.cacheProvider=e.cache}return t}var Z={projectName:"my-saas",frontend:"nuxt",architecture:"fullstack",paymentProvider:"stripe",emailProvider:"smtp",multiTenancy:!1,billingScope:"user",blog:!1,revenueSharing:!1,dockerServices:["postgres","redis","inngest"],aiTools:[],defaultCurrency:"USD",deploymentTarget:"node",databaseProvider:"postgres",cacheProvider:"redis"};function Jt(e){let t=e.projectName??Z.projectName,r=e.projectDir??`./${t}`,i=e.appName??je(t),n=e.deploymentTarget??Z.deploymentTarget,o=K[n]?.edgeRuntime??!1,s=e.databaseProvider??(o?"neon":Z.databaseProvider),a=e.cacheProvider??(o?"upstash":Z.cacheProvider),m=e.emailProvider??(o?"resend":Z.emailProvider),S=e.dockerServices??(o?Z.dockerServices.filter(y=>y!=="postgres"&&y!=="redis"):Z.dockerServices),E={...Z,...e,projectName:t,appName:i,projectDir:r,deploymentTarget:n,databaseProvider:s,cacheProvider:a,emailProvider:m,dockerServices:S};for(let y of Ee){if(E.deploymentTarget!==y.target)continue;let h=E.databaseProvider===y.provider?"database":"cache";if(E.databaseProvider===y.provider||E.cacheProvider===y.provider)throw new Error(`Incompatible: --deploy ${y.target} + --${h} ${y.provider}. ${y.reason}`)}return E}function qt(e,t,r){if(e.trim()==="")return[];let i=e.split(",").map(o=>o.trim()).filter(Boolean),n=i.filter(o=>!t.includes(o));if(n.length>0)throw new Error(`Invalid ${r}(s): ${n.join(", ")}. Valid values: ${t.join(", ")}`);return i}import $n from"picocolors";function jn(e){if(e===void 0)return;let t=e.trim().replace(/^v/,"");if(!/^\d+\.\d+\.\d+$/.test(t))throw new Error(`Invalid template version "${e}". Use semver like 1.2.3.`);return t}function Zt(e){e.command("init").description("Scaffold a new GenerateSaaS project").option("-n, --name <name>","project name (lowercase, hyphens, starts with letter)").option("--app-name <name>","display name for the app").option("-l, --location <path>","project directory (default: ./{name})").addOption(new Q("--architecture <type>","fullstack or separate").choices([...Oe])).addOption(new Q("--payment <provider>","payment provider").choices([...Ce])).addOption(new Q("--email <provider>","email provider").choices([...xe])).option("--org","enable multi-tenancy (organizations)").option("--no-org","disable multi-tenancy").addOption(new Q("--billing-scope <scope>","billing scope (requires --org)").choices([...$e])).option("--blog","enable blog").option("--no-blog","disable blog").option("--revenue-sharing","enable revenue sharing").option("--no-revenue-sharing","disable revenue sharing").option("--docker <services>","comma-separated: postgres,redis,inngest,mailpit").option("--ai-tools <tools>","comma-separated: claude-code,cursor,codex,gemini-cli,windsurf").addOption(new Q("--currency <code>","default currency for billing").choices([...ne])).addOption(new Q("--deploy <target>","deployment target").choices([...ie])).addOption(new Q("--database <provider>","database provider").choices([...oe])).addOption(new Q("--cache <provider>","cache provider").choices([...se])).option("--template-version <version>","specific template version to scaffold").option("--api-key <key>","API key (skips interactive prompt)").option("-y, --yes","accept defaults for unspecified options (non-interactive)").action(async t=>{await Un(t)})}async function Un(e){let t=performance.now();mt("0.10.4");let r,i;try{r=Wt(e),i=jn(e.templateVersion)}catch(f){_.cancel(T(f)),process.exit(1)}let n=_.spinner(),o;try{o=await ue({apiKey:e.apiKey,prompt:!e.yes})}catch(f){_.cancel(T(f)),process.exit(1)}let s=L(o),a=async()=>{let f=await V(s),I=f.latest,c=i??I;if(i&&!f.versions.some(p=>p.version===c))throw new Error(`Template version "${i}" is not available.`);return{latestVersion:I,selectedVersion:c}};n.start("Verifying access...");let m,S;try{({latestVersion:m,selectedVersion:S}=await a()),n.stop("Access verified."),Y(o)}catch(f){if(n.stop("Access verification failed."),f instanceof R&&f.status===401){e.yes&&(_.cancel("Invalid API key. Cannot prompt in non-interactive mode."),process.exit(1)),_.log.warning("Invalid API key."),o=await q(),s=L(o),n.start("Verifying access...");try{({latestVersion:m,selectedVersion:S}=await a()),n.stop("Access verified."),Y(o)}catch(I){n.stop("Access verification failed."),_.cancel(I instanceof R&&I.status===401?"Invalid API key.":T(I)),process.exit(1)}}else _.cancel(T(f)),process.exit(1)}_.log.success(`Latest version: ${m}`),S!==m&&_.log.success(`Using template version: ${S}`);let E;n.start("Activating license...");try{let f=crypto.randomUUID();E={token:(await At(s,{frontend:"nuxt",version:S,installId:f})).token,keyHash:xt(o),installId:f},n.stop("License activated.")}catch(f){n.stop("License activation failed."),_.cancel(T(f)),process.exit(1)}let y;e.yes?y=Jt(r):y=await gt(r);let h=Nn(y.projectDir);if(Xt(h)&&On(h).length>0)if(e.yes)_.log.info(`Directory ${h} is not empty. Merging (keeping existing files, overwriting conflicts).`);else{let I=await _.select({message:`Directory ${h} is not empty.`,options:[{value:"merge",label:"Merge",hint:"keep existing files, overwrite conflicts"},{value:"overwrite",label:"Overwrite",hint:"delete everything and start fresh"},{value:"cancel",label:"Cancel"}]});(_.isCancel(I)||I==="cancel")&&(_.cancel("Setup cancelled."),process.exit(0)),I==="overwrite"&&Cn(h,{recursive:!0,force:!0})}let v={...y,projectDir:h,version:S};n.start("Downloading template...");try{await _e(s,S,h);let f=await Ie(h);await d(at(h,Me),JSON.stringify(f,null," ")+`
|
|
785
785
|
`),await Ft(h,h),await yt(h),n.stop("Template downloaded.")}catch(f){n.stop("Download failed."),_.cancel(T(f)),process.exit(1)}let O;n.start("Generating project files...");try{await wt(v),await Ut(v),await Ot(v),O=await bt(v),await Vt(v),await kt(v),await Rt(v),await Pt(v),await jt(v),await Bt(h,v.aiTools),await $t(v),Vn(v),await Nt(v,E),n.stop("Project files generated.")}catch(f){n.stop("Generation failed."),_.cancel(T(f)),process.exit(1)}let de=await Gt(h);await Ht(h);let ee=We("docker"),te=Ze(v).map(f=>f.key).filter(f=>!v.credentials?.[f]);Yt(v,{pnpmInstalled:de,dockerComposeGenerated:O,dockerAvailable:ee,skippedCredentials:te}),ut(),_.log.info($n.dim(`Done in ${((performance.now()-t)/1e3).toFixed(1)}s`))}function Vn(e){let t=[at(e.projectDir,"apps/web-nuxt/wrangler.toml"),at(e.projectDir,"apps/backend/wrangler.toml")];for(let r of t){if(!Xt(r))continue;let i=xn(r,"utf-8");Ln(r,i.replaceAll("your-project",e.projectName))}}import{existsSync as Qt}from"fs";import{readFile as Mn}from"fs/promises";import{join as Pe,resolve as Fn}from"path";import*as w from"@clack/prompts";import ye from"picocolors";function er(e){e.command("update").description("Update AI skill files and stage template updates").option("--cwd <path>","project directory (default: current directory)").action(async t=>{let r=Fn(t.cwd??process.cwd()),i=Pe(r,W),n;try{n=JSON.parse(await Mn(i,"utf-8"))}catch{w.cancel(".generatesaas/manifest.json not found. Run this from a GenerateSaaS project."),process.exit(1)}let o;try{o=await ue()}catch(m){w.cancel(T(m)),process.exit(1)}let s=L(o),a=w.spinner();try{a.start("Verifying access...");let m;try{m=await V(s)}catch(P){if(P instanceof R&&P.status===401)a.stop("Invalid API key."),o=await q(),s=L(o),a.start("Verifying access..."),m=await V(s);else throw P}a.stop("Access verified."),Y(o),a.start("Fetching latest skill files...");let S=await _t(s,m.latest);await st(r,S.skillMd,S.scripts,n.aiTools);let E=ot(n.aiTools);if(a.stop("Skills updated."),w.log.success(`Skill files installed to ${ye.cyan(E.length.toString())} locations.`),n.licenseToken)try{let P=await It(s,{currentToken:n.licenseToken,newVersion:n.version});n.licenseToken=P.token,await d(i,JSON.stringify(n,null," ")+`
|
|
786
786
|
`),w.log.success("License refreshed.")}catch{w.log.warn("License refresh skipped.")}if(n.version===m.latest){w.log.info(`Already on the latest version (${n.version}).`);return}let y=Pe(r,vt);a.start(`Downloading v${m.latest} template...`),await _e(s,m.latest,y),a.stop("Template staged.");let h=await Et(s,m.latest);h&&w.note(h,`Changelog v${m.latest}`);let v=Pe(r,Me),O=Pe(r,Fe),de=!Qt(O),ee=!Qt(v);if(de){if(a.start("Downloading baseline template (one-time migration)..."),await _e(s,n.version,O),ee){let P=await Ie(O);await d(v,JSON.stringify(P,null," ")+`
|
|
787
787
|
`)}a.stop("Baseline template stored.")}else if(ee){a.start("Computing baseline template hashes...");let P=await Ie(O);await d(v,JSON.stringify(P,null," ")+`
|
|
@@ -795,7 +795,7 @@ ${n}
|
|
|
795
795
|
`,` .route("/license", licenseRoutes)
|
|
796
796
|
`]}];function Zn(e){return(e&&e.length>0?e.map(r=>Te[r]):Object.values(Te)).map(r=>pe(r,it))}function pt(e){return Je(e)?(Wn(e,{recursive:!0}),!0):!1}function Qn(e,t){if(!Je(e))return!1;let r=lt(e,"utf-8"),i=r;for(let n of t)i=i.replace(n,"");return i===r?!1:(sr(e,i,"utf-8"),!0)}function ei(e){let t=pe(e,".gitignore");if(!Je(t))return!1;let r=lt(t,"utf-8"),i=r.split(`
|
|
797
797
|
`).filter(n=>!n.includes(".generatesaas")).join(`
|
|
798
|
-
`);return i===r?!1:(sr(t,i,"utf-8"),!0)}function ar(e){e.command("eject").description("Remove all GenerateSaaS ties \u2014 manifest, license, heartbeat, skills").action(async()=>{let t=process.cwd(),r=pe(t,W),i;try{i=JSON.parse(lt(r,"utf-8"))}catch{D.cancel("No GenerateSaaS project found in this directory."),process.exit(1)}let n=await D.text({message:'Type "eject" to confirm (this cannot be undone):',validate:a=>{if(a!=="eject")return'Type "eject" to confirm, or press Ctrl+C to cancel.'}});D.isCancel(n)&&(D.cancel("Eject cancelled."),process.exit(0));let o=[],s=[];for(let a of Zn(i.aiTools))pt(pe(t,a))&&o.push(a);for(let a of Jn)pt(pe(t,a))&&o.push(a);pt(pe(t,x))&&o.push(x+"/");for(let a of Xn){let m=pe(t,a.file);Qn(m,a.removals)?s.push(a.file):Je(m)&&D.log.warn(`Could not auto-modify ${a.file} \u2014 manually remove license/heartbeat references.`)}ei(t)&&s.push(".gitignore");for(let a of o)D.log.info(`Deleted ${a}`);for(let a of s)D.log.info(`Modified ${a}`);D.log.success("Ejected successfully. This project is now fully standalone.")})}var le=new ti().name("generatesaas").description("CLI for scaffolding and managing GenerateSaaS projects").version("0.10.
|
|
798
|
+
`);return i===r?!1:(sr(t,i,"utf-8"),!0)}function ar(e){e.command("eject").description("Remove all GenerateSaaS ties \u2014 manifest, license, heartbeat, skills").action(async()=>{let t=process.cwd(),r=pe(t,W),i;try{i=JSON.parse(lt(r,"utf-8"))}catch{D.cancel("No GenerateSaaS project found in this directory."),process.exit(1)}let n=await D.text({message:'Type "eject" to confirm (this cannot be undone):',validate:a=>{if(a!=="eject")return'Type "eject" to confirm, or press Ctrl+C to cancel.'}});D.isCancel(n)&&(D.cancel("Eject cancelled."),process.exit(0));let o=[],s=[];for(let a of Zn(i.aiTools))pt(pe(t,a))&&o.push(a);for(let a of Jn)pt(pe(t,a))&&o.push(a);pt(pe(t,x))&&o.push(x+"/");for(let a of Xn){let m=pe(t,a.file);Qn(m,a.removals)?s.push(a.file):Je(m)&&D.log.warn(`Could not auto-modify ${a.file} \u2014 manually remove license/heartbeat references.`)}ei(t)&&s.push(".gitignore");for(let a of o)D.log.info(`Deleted ${a}`);for(let a of s)D.log.info(`Modified ${a}`);D.log.success("Ejected successfully. This project is now fully standalone.")})}var le=new ti().name("generatesaas").description("CLI for scaffolding and managing GenerateSaaS projects").version("0.10.4").addHelpText("after",`
|
|
799
799
|
Examples:
|
|
800
800
|
$ generatesaas init Interactive setup
|
|
801
801
|
$ generatesaas init -n my-app -y Quick setup with defaults
|