create-sailor 1.10.0 → 1.10.1

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,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import{execSync as gp}from"child_process";import os from"fs";import*as rs from"@clack/prompts";import L from"picocolors";import{Command as ps}from"commander";import Fn from"fs";import Jt from"path";import{fileURLToPath as as}from"url";function cs(){try{let t=Jt.dirname(as(import.meta.url));for(let n=0;n<4;n++){let o=Jt.join(t,"package.json");if(Fn.existsSync(o)){let r=Fn.readFileSync(o,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Jt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var z=cs();var ls="create-sailor";function jn(){let e=new ps;return e.name(ls).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(z,"-v, --version").helpOption(!1).argument("[name]","project name or path (default: my-app; use . for current directory)",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | supabase | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--access-gate <mode>","none | invite (default: none)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: false \u2014 @nebutra/audit is WIP)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e}import Vn from"picocolors";var Qt=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require",comment:"Supabase session pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres?sslmode=require",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY",placeholder:""},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_PUBLISHABLE_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<branch-id>:<password>@<host>.horizon.psdb.cloud:6432/postgres?sslmode=require",comment:"PlanetScale Postgres pooled/PgBouncer URL \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<branch-id>:<password>@<host>.horizon.psdb.cloud:5432/postgres?sslmode=require",comment:"PlanetScale Postgres direct URL \u2014 Prisma migrations"}],docs:"https://planetscale.com/docs/postgres",description:"Managed Postgres with branching; compatible with Sailor migrations.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function mt(e){return Qt.find(t=>t.id===e)}function Bn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}var Re=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Zt(e){let t=e==="supabase"?"supabase-storage":e;return Re.some(n=>n.id===t)?t:void 0}function $n(e){let t=Zt(e);return t?Re.find(n=>n.id===t):void 0}var Ap=Re.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Yn(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function en(e){switch(e){case"postgres":case"postgresql":return"postgresql";case"mysql":return"mysql";case"sqlite":return"sqlite";case"none":return"none";default:return"postgresql"}}function tn(e,t,n){let o=e?.trim().toLowerCase()??Bn(t),r=mt(o);if(!r){let i=Qt.map(a=>a.id).join(", ");throw new Error(`Unknown --db-host="${o}". Valid: ${i}`)}let s=n;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function nn(e){return e==="drizzle"?"drizzle":"prisma"}function gt(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function ft(e){if(!e)return"stripe";let t=e.toLowerCase();return t==="lemon"||t==="lemonsqueezy"?"lemon":t==="wechat"?"wechat":t==="alipay"?"alipay":t==="none"?"none":"stripe"}function on(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="supabase"||t==="supabase-auth"?"supabase":t==="none"?"none":"clerk"}var ds=new Set(["gateway","direct","custom","none"]);function rn(e){if(!e)return!1;let t=e.trim().toLowerCase();return ds.has(t)}function sn(e){if(!e)return["openai"];if(rn(e))return[];let t=e.split(",").map(n=>n.trim().toLowerCase());return t.includes("none")?[]:t}function qn(e,t){let n=e??t;return Zt(n)??n}var Kn={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function an(e,t){if(!e)return"fumadocs";let n=e.toLowerCase();if(n==="fumadocs"||n==="none")return n;if(n in Kn){let o=Kn[n];return t?process.stdout.write(JSON.stringify({event:"notice",kind:"docs-fallback",requested:n,effective:"fumadocs"})+`
3
- `):process.stdout.write(Vn.yellow(`\u26A0 ${o} support is coming in v1.2. Falling back to fumadocs.
4
- `)+Vn.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
5
- `)),"fumadocs"}return"fumadocs"}function yt(e){switch(e){case"vercel":return"vercel";case"railway":return"railway";case"cloudflare":return"cloudflare";case"selfhost":return"selfhost";case"none":return"none";default:return"vercel"}}function cn(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Gn(e){return{...e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"},queue:"none",search:"none",cache:e==="global"?"upstash-redis":e==="cn"?"redis":"upstash-redis",notifications:"none",webhooks:"none",cms:"none",featureFlags:"none",captcha:"none",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk",accessGate:"none"}}function pn(e){return e==="cn"?"wechat":"stripe"}import*as q from"@clack/prompts";import Ts from"picocolors";var ln=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensenova.cn/docs",baseURL:"https://token.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],kp=ln.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var us=["openai","anthropic","google"],ms=["openai"];function dn(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let n=t.length>0?t:[...us];return{mode:"gateway",providerIds:n,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:n,runtimeGovernance:!0}}}case"direct":{let n=t.length>0?t:[...ms];return{mode:"direct",providerIds:n,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:n,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}var Ze=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],gs=new Set(Ze.map(e=>e.id));function Hn(e){return Ze.find(t=>t.id===e)}function Wn(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let n=[],o=new Set;for(let r of t)gs.has(r)&&!o.has(r)&&(n.push(r),o.add(r));return n}import te from"fs";import T from"path";import{fileURLToPath as bs}from"url";var Xn=["web","landing","auth","admin","design-docs","sailor-docs","router","forge","typelens","gateway","python-ai"],fs={web:"frontend",landing:"frontend",auth:"frontend",admin:"frontend","design-docs":"frontend","sailor-docs":"frontend",router:"frontend",forge:"frontend",typelens:"frontend",gateway:"edgeGateway","python-ai":"originBackend"},ys={frontend:"vercel",edgeGateway:"cloudflare-workers",originBackend:"ecs-docker"};function Ss(e){return Xn.includes(e)}function hs(e){if(!Ss(e))throw new Error(`Unknown deploy service '${e}'. Deploy targets apply only to apps/backends, not packages.`)}function Es(e){return hs(e),fs[e]}function vs(e){let t=Es(e);return ys[t]}function zn(){return Object.fromEntries(Xn.map(e=>[e,vs(e)]))}var _s=bs(import.meta.url),Jn=T.dirname(_s),ws="cloudflare-pages",Ps="standalone",As="railway";function un(e,t,n,o){return{...e,web:t,landing:t,auth:t,admin:t,"design-docs":t,"sailor-docs":t,router:t,forge:t,typelens:t,gateway:n,"python-ai":o}}function Cs(){let e=[T.join(Jn,"..","templates","deploy"),T.join(Jn,"..","..","templates","deploy")];for(let t of e)if(te.existsSync(t))return t;return e[0]}function Ct(e){let t=zn();switch(e){case"cloudflare":return un(t,ws,"cloudflare-workers","ecs-docker");case"selfhost":return un(t,Ps,"ecs-docker","ecs-docker");case"railway":return un(t,As,"railway","railway");case"none":case"vercel":return t}}function Is(e){return`DEPLOY_TARGET_${e.toUpperCase().replace(/-/g,"_")}`}async function Qn(e,t){let n=T.join(e,"backends","gateway");te.existsSync(n)&&await te.promises.copyFile(T.join(t,"wrangler.gateway.toml"),T.join(n,"wrangler.toml"))}async function Zn(e,t){let n=T.join(e,".env.example"),o;try{o=await te.promises.readFile(n,"utf8")}catch(i){if(i.code==="ENOENT")return;throw i}if(o.includes("# Deployment Targets"))return;let s=["","# Deployment Targets",...Object.entries(t).map(([i,a])=>`${Is(i)}="${a}"`)].join(`
6
- `);await te.promises.appendFile(n,`${s}
7
- `)}async function eo(e,t){if(t==="none")return;let n=Cs();t==="vercel"?(await te.promises.copyFile(T.join(n,"vercel.json"),T.join(e,"vercel.json")),await Qn(e,n)):t==="railway"?await te.promises.copyFile(T.join(n,"railway.toml"),T.join(e,"railway.toml")):t==="cloudflare"?(await te.promises.copyFile(T.join(n,"wrangler.toml"),T.join(e,"wrangler.toml")),await Qn(e,n)):t==="selfhost"&&(await te.promises.copyFile(T.join(n,"docker-compose.yml"),T.join(e,"docker-compose.yml")),await te.promises.copyFile(T.join(n,"Dockerfile.web"),T.join(e,"Dockerfile.web")))}var xs={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation","vercel-flags":"foundation",growthbook:"foundation",configcat:"foundation",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip",invite:"foundation"};function Rs(e){return e?xs[e]??"stable":"stable"}function et(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function Te(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 core contracts work, but production use still requires provider credentials, adapter wiring, or a verified integration contract.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function It(e){let t=[];for(let{flag:n,provider:o}of e){if(!o||o==="none")continue;let r=Rs(o);r!=="stable"&&t.push({flag:n,provider:o,status:r})}return t}function _e(e,t){if(e===void 0)return t;let n=String(e).trim().toLowerCase();return n==="true"||n==="1"||n==="yes"||n==="on"?!0:n==="false"||n==="0"||n==="no"||n==="off"?!1:t}function to(e,t){let n=t==="cn";return{cronJobs:_e(e.cronJobs,!0),auditLog:_e(e.auditLog,!1),apiKeys:_e(e.apiKeys,!0),webhooks:_e(e.webhooks,!0),commandPalette:_e(e.commandPalette,!0),cookieConsent:_e(e.cookieConsent,!0),legalPages:_e(e.legalPages,!0),chinaCompliance:_e(e.chinaCompliance,n)}}async function ks(e,t,n,o){let r={};return t||(r.region=()=>q.select({message:"Target region?",options:[{value:"global",label:"Global",hint:"Stripe \xB7 Resend \xB7 R2 defaults"},{value:"cn",label:"China",hint:"WeChat Pay \xB7 Aliyun DM/OSS defaults"},{value:"hybrid",label:"Hybrid",hint:"global + CN dual track"}],initialValue:"global"})),n||(r.auth=()=>q.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"supabase",label:"Supabase Auth",hint:"managed auth with Supabase storage/realtime ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),o||(r.aiMode=()=>q.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),r.aiProviders=({results:s})=>{if(s.aiMode!=="direct")return Promise.resolve([]);let i=ln.map(a=>({value:a.id,label:`[${a.category}] ${a.name}`}));return q.multiselect({message:"Select direct AI provider adapters (expert path)",options:i,initialValues:["openai"],required:!1})},r.customAiName=({results:s})=>s.aiMode==="custom"?q.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),r.customAiBaseUrl=({results:s})=>s.aiMode==="custom"?q.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:i=>{if(!i?.length)return"Base URL is required."}}):Promise.resolve(void 0),r.customAiApiKeyEnv=({results:s})=>s.aiMode==="custom"?q.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)),Object.keys(r).length===0?{}:await q.group(r,{onCancel:()=>{process.stdout.write(Ts.red(`\u2718 Cancelled
8
- `)),process.exit(130)}})}async function no(e,t){let n=!!e.region,o=!!e.auth,r=!!e.payment,s=!!e.ai,i=!!e.email,a=!!e.storage,c=!!e.monitoring,p=!!e.analytics,d=!!e.sms,u=e.i18n!==void 0,h=!!e.yes||!process.stdin.isTTY,g,E,S,m,_,H,M,he=Wn(e.socialLogin),le,ee,V,K,C,W,de;if(h){g=cn(e.region),E=nn(e.orm);{let Y=en(e.db),At=tn(e.dbHost,g,Y);S=At.engine,m=At.hostId}let X=r?e.payment:pn(g);_=gt(X),H=ft(X),M=on(e.auth);let Qe="gateway";if(s){let Y=e.ai?.trim().toLowerCase()??"";rn(Y)?Qe=Y:Qe="direct"}let ut=dn({mode:Qe,providerIds:s?sn(e.ai):void 0});le=ut.mode,ee=ut.routing,V=ut.providerIds,C=yt(e.deploy),W=an(e.docs,t),de=u?!!e.i18n:!0}else{let X=await ks(e,n,o,s);g=cn(n?e.region:X.region),E=nn(e.orm);{let At=en(e.db),Mn=tn(e.dbHost,g,At);S=Mn.engine,m=Mn.hostId}let Qe=r?e.payment:pn(g);_=gt(Qe),H=ft(Qe),M=on(o?e.auth:X.auth);let ut=X.aiMode==="custom"?{name:X.customAiName??"custom",baseURL:X.customAiBaseUrl??"",apiKeyEnvName:X.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,Y=dn({mode:s?e.ai?.trim().toLowerCase()==="none"?"none":"direct":X.aiMode??"gateway",providerIds:s?sn(e.ai):X.aiProviders,customEndpoint:ut});le=Y.mode,ee=Y.routing,V=Y.providerIds,Y.customEndpoint&&(K={name:Y.customEndpoint.name,baseURL:Y.customEndpoint.baseURL,apiKeyEnvName:Y.customEndpoint.apiKeyEnvName}),C=yt(e.deploy),W=an(e.docs,t),de=u?!!e.i18n:!0}let w=Gn(g),Ee=i?e.email:w.email,ze=qn(a?e.storage:void 0,w.storage),Je=c?e.monitoring:w.monitoring,ve=p?e.analytics:w.analytics,v=d?e.sms:w.sms,R=e.queue??w.queue,P=e.search??w.search,I=e.cache??w.cache,Gt=e.notifications??w.notifications,Ht=e.webhooks??w.webhooks,kn=e.cms??w.cms,Wt=e.featureFlags??w.featureFlags,Xt=e.captcha??w.captcha,Nn=e.mcp??w.mcp,On=e.metering??w.metering,Ln=e.billingMode??w.billingMode,Un=e.idp??w.idp,zt=e.accessGate==="invite"?"invite":w.accessGate,Dn=Ct(C),be=to({cronJobs:e.cronJobs,auditLog:e.auditLog,apiKeys:e.apiKeys,commandPalette:e.commandPalette,cookieConsent:e.cookieConsent,legalPages:e.legalPages,chinaCompliance:e.chinaCompliance},g),ss=It([{flag:"queue",provider:R},{flag:"search",provider:P},{flag:"notifications",provider:Gt},{flag:"webhooks",provider:Ht},{flag:"feature-flags",provider:Wt},{flag:"captcha",provider:Xt},{flag:"access-gate",provider:zt}]),is={region:g,orm:E,database:S,databaseHost:m,payment:_,aiMode:le,aiRouting:ee,aiProviders:V,customAiEndpoint:K,deployTarget:C,deployTargets:Dn,docs:W,i18n:de,email:Ee,storage:ze,monitoring:Je,analytics:ve,sms:v,queue:R,search:P,cache:I,notifications:Gt,webhooks:Ht,cms:kn,featureFlags:Wt,captcha:Xt,mcp:Nn,metering:On,billingMode:Ln,idp:Un,accessGate:zt,cronJobs:be.cronJobs,auditLog:be.auditLog,apiKeys:be.apiKeys,commandPalette:be.commandPalette,cookieConsent:be.cookieConsent,legalPages:be.legalPages,chinaCompliance:be.chinaCompliance};return{region:g,orm:E,database:S,databaseHost:m,payment:_,paymentChoice:H,auth:M,socialLoginIds:he,aiMode:le,aiRouting:ee,aiProviders:V,customAiEndpoint:K,deployTarget:C,deployTargets:Dn,docs:W,i18n:de,email:Ee,storage:ze,monitoring:Je,analytics:ve,sms:v,queue:R,search:P,cache:I,notifications:Gt,webhooks:Ht,cms:kn,featureFlags:Wt,captcha:Xt,mcp:Nn,metering:On,billingMode:Ln,idp:Un,accessGate:zt,waveToggles:be,previewSelections:ss,config:is}}import{execFileSync as Kt}from"child_process";import Yt from"fs";import Xe from"path";import We from"picocolors";import zc from"update-notifier";import tt from"picocolors";function Ns(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function oo(e){let t=Ns(),n=t?"\u2693":"-",o=t?"\u25B8":"->",r=e.packageManager??"pnpm",s=e.hasDatabase!==!1,i=e.targetDir==="."||e.targetDir==="./"||e.targetDir===".\\",a=i?".":e.targetDir.endsWith("/")?e.targetDir:`${e.targetDir}/`,c=t?tt.bold(`${n} Done in ${e.elapsedSec}s \xB7 ${a}`):`${n} Done in ${e.elapsedSec}s \xB7 ${a}`,p=h=>t?tt.dim(h):h,d=h=>t?tt.bold(h):h,u=["",` ${c}`,"",` ${d("Next:")}`];i||u.push(` ${o} cd ${e.targetDir}`),e.skippedInstall&&u.push(` ${o} ${r} install`),u.push(` ${o} fill .env.local ${p("\u2192 provider keys from .env.example")}`),s&&u.push(` ${o} ${r} infra:up ${p("\u2192 local Postgres (optional)")}`,` ${o} ${r} db:migrate ${p("\u2192 apply Prisma schema")}`),u.push(` ${o} ${r} dev ${p("\u2192 http://localhost:3000")}`,"",` ${p("More:")} ${p("nebutra doctor")} ${p("\xB7")} ${p("docs.nebutra.com")}`);let A=e.previewSelections??[];if(A.length>0){let h=t?tt.bold(tt.yellow("\u26A0 Preview / foundation providers:")):"!! Preview / foundation providers:";u.push("",` ${h}`);for(let g of A){let E=et(g.status),S=` ${o} ${g.flag}=${g.provider} ${E}`;u.push(t?tt.yellow(S):S)}u.push(` ${p(Te("foundation"))}`)}u.push(""),process.stdout.write(u.join(`
2
+ import{execSync as Rp}from"child_process";import us from"fs";import Dn from"path";import*as ms from"@clack/prompts";import x from"picocolors";import{Command as hs}from"commander";import Yn from"fs";import Zt from"path";import{fileURLToPath as ys}from"url";function Ss(){try{let t=Zt.dirname(ys(import.meta.url));for(let n=0;n<4;n++){let o=Zt.join(t,"package.json");if(Yn.existsSync(o)){let r=Yn.readFileSync(o,"utf-8"),s=JSON.parse(r);if(s.name==="create-sailor"&&typeof s.version=="string")return s.version}t=Zt.dirname(t)}return"0.0.0-dev"}catch{return"0.0.0-dev"}}var Q=Ss();var Es="create-sailor";function Gn(){let e=new hs;return e.name(Es).description("Nebutra-Sailor \u2014 AI-Native SaaS template").version(Q,"-v, --version").helpOption(!1).argument("[name]","project name or path (default: my-app; use . for current directory)",void 0).option("-p, --pm <id>","npm | pnpm | yarn | bun").option("--region <id>","global | cn | hybrid").option("--orm <id>","prisma (default, primary) | drizzle (dual-ORM: adds db-drizzle alongside Prisma \u2014 Postgres only)").option("--db <id>","postgres | mysql | sqlite | none \u2014 engine (Prisma provider)").option("--db-host <id>","local | supabase | neon | vercel-postgres | planetscale | railway | aliyun-rds | tencent-cdb | none \u2014 managed-provider (region default: supabase global, local cn)").option("--auth <id>","clerk | betterauth | nextauth | supabase | none").option("--social-login <ids>","CN social login providers \u2014 wechat | qq | dingtalk | workweixin | feishu | weibo (comma-separated)").option("--payment <id>","stripe | lemon | wechat | alipay | none").option("--ai <mode-or-ids>","topology shorthand (gateway | direct | custom | none) OR comma-separated provider ids (e.g. openai,anthropic)").option("--deploy <target>","vercel | railway | cloudflare | selfhost").option("--docs <id>","fumadocs | mintlify | docusaurus | nextra | vitepress | none").option("--email <id>","resend | postmark | ses | aliyun-dm | tencent-ses | netease | none").option("--storage <id>","r2 | s3 | supabase-storage | aliyun-oss | tencent-cos | qiniu | none").option("--monitoring <id>","sentry | datadog | aliyun-arms | tingyun | none").option("--analytics <id>","posthog | plausible | umami | baidu | sensors | none").option("--sms <id>","twilio | aliyun-sms | tencent-sms | yunpian | none").option("--queue <id>","qstash | bullmq | sqs | none").option("--search <id>","meilisearch | typesense | algolia | pgvector | none").option("--cache <id>","upstash-redis | vercel-kv | redis | dragonfly | none").option("--notifications <id>","novu | knock | custom | none").option("--webhooks <id>","svix | custom | none").option("--cms <id>","sanity | contentful | strapi | none").option("--feature-flags <id>","vercel-flags | growthbook | configcat | none").option("--captcha <id>","turnstile | hcaptcha | aliyun-slide | none").option("--mcp <mode>","on | off (default: on)").option("--metering <mode>","auto | on | off (default: auto \u2014 auto-on when payment is set)").option("--billing-mode <mode>","usage | seat | credits (default: usage)").option("--idp <id>","clerk | oauth-server (default: clerk)").option("--access-gate <mode>","none | invite (default: none)").option("--cron-jobs <bool>","true | false \u2014 scaffold scheduled cron handlers (default: true)").option("--audit-log <bool>","true | false \u2014 enable /settings/audit-log + arch test (default: false \u2014 @nebutra/audit is WIP)").option("--api-keys <bool>","true | false \u2014 enable /settings/api-keys page (default: true)").option("--command-palette <bool>","true | false \u2014 enable \u2318K command palette (default: true)").option("--cookie-consent <bool>","true | false \u2014 enable GDPR/CCPA cookie banner (default: true)").option("--legal-pages <bool>","true | false \u2014 enable dynamic /legal/[slug] route (default: true)").option("--china-compliance <bool>","true | false \u2014 enable @nebutra/china-compliance + ICP footer (default: true when --region=cn, otherwise false)").option("--i18n","enable i18n").option("--no-i18n","disable i18n").option("--with-workflows","scaffold workflows/ (inngest + n8n + pusher stubs)").option("--with-python-backend","scaffold backends/python/ (FastAPI stub \u2014 only when TS-by-Default ADR exception applies)").option("--no-install","skip package install").option("--no-git","skip git init").option("-y, --yes","accept all defaults (non-interactive)").option("--dry-run","preview actions without writing files").option("--json","machine-readable output").option("--no-color","disable color output").option("-h, --help","show help"),e}import Wn from"picocolors";var en=[{id:"local",name:"Local / Self-hosted Docker",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres:postgres@localhost:5432/$PROJECT",comment:"Local Postgres via docker-compose (pnpm infra:up)"}],docs:"https://www.postgresql.org/docs/",description:"Docker on localhost. You operate it.",tier:"self-hosted"},{id:"supabase",name:"Supabase",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require",comment:"Supabase session pooler \u2014 use for runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres?sslmode=require",comment:"Supabase direct \u2014 use for Prisma migrations"},{name:"NEXT_PUBLIC_SUPABASE_URL",placeholder:"https://<project>.supabase.co"},{name:"NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY",placeholder:""},{name:"NEXT_PUBLIC_SUPABASE_ANON_KEY",placeholder:""},{name:"SUPABASE_PUBLISHABLE_KEY",placeholder:""},{name:"SUPABASE_SERVICE_ROLE_KEY",placeholder:""}],docs:"https://supabase.com/docs",description:"Managed Postgres + auth/storage/realtime/edge-functions.",tier:"managed"},{id:"neon",name:"Neon",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>-pooler.<region>.neon.tech/<db>?sslmode=require",comment:"Neon pooled \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://<user>:<pwd>@ep-<branch>.<region>.neon.tech/<db>?sslmode=require",comment:"Neon direct (no -pooler) \u2014 migrations"}],docs:"https://neon.tech/docs",description:"Serverless Postgres with branching and scale-to-zero.",tier:"managed"},{id:"vercel-postgres",name:"Vercel Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"$POSTGRES_PRISMA_URL",comment:"Vercel Marketplace injects POSTGRES_PRISMA_URL automatically"},{name:"DIRECT_URL",placeholder:"$POSTGRES_URL_NON_POOLING",comment:"Vercel Marketplace injects POSTGRES_URL_NON_POOLING automatically"}],docs:"https://vercel.com/docs/storage/vercel-postgres",description:"Neon-backed, auto-provisioned via Vercel Marketplace.",tier:"managed"},{id:"planetscale",name:"PlanetScale Postgres",region:"global",supportedEngines:["postgresql"],forcedEngine:"postgresql",keepDirectUrl:!0,envVars:[{name:"DATABASE_URL",placeholder:"postgresql://postgres.<branch-id>:<password>@<host>.horizon.psdb.cloud:6432/postgres?sslmode=require",comment:"PlanetScale Postgres pooled/PgBouncer URL \u2014 runtime queries"},{name:"DIRECT_URL",placeholder:"postgresql://postgres.<branch-id>:<password>@<host>.horizon.psdb.cloud:5432/postgres?sslmode=require",comment:"PlanetScale Postgres direct URL \u2014 Prisma migrations"}],docs:"https://planetscale.com/docs/postgres",description:"Managed Postgres with branching; compatible with Sailor migrations.",tier:"managed"},{id:"railway",name:"Railway",region:"global",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"$DATABASE_URL",comment:"Railway service env var; injected when you link a Postgres service"}],docs:"https://docs.railway.app/databases/postgresql",description:"Generalist managed infra; standard TCP Postgres/MySQL.",tier:"managed"},{id:"aliyun-rds",name:"Aliyun RDS",region:"cn",supportedEngines:["postgresql","mysql"],envVars:[{name:"DATABASE_URL",placeholder:"postgresql://<user>:<pwd>@<rds-instance>.rds.aliyuncs.com:5432/<db>",comment:"Aliyun RDS Postgres \u2014 internal VPC endpoint recommended"}],docs:"https://www.alibabacloud.com/help/en/rds",description:"Aliyun RDS \u2014 China compliance + intranet routing.",tier:"managed"},{id:"tencent-cdb",name:"Tencent CloudDB (CDB)",region:"cn",supportedEngines:["mysql","postgresql"],envVars:[{name:"DATABASE_URL",placeholder:"mysql://<user>:<pwd>@<cdb-instance>.tencentcdb.com:3306/<db>",comment:"Tencent CloudDB \u2014 VPC endpoint recommended"}],docs:"https://intl.cloud.tencent.com/document/product/236",description:"Tencent CloudDB \u2014 China compliance.",tier:"managed"},{id:"none",name:"None",region:"both",supportedEngines:["postgresql","mysql","sqlite"],envVars:[],docs:"",description:"Skip database scaffolding.",tier:"self-hosted"}];function ft(e){return en.find(t=>t.id===e)}function qn(e){return e==="cn"||e==="hybrid"?"local":"supabase"}var ke=[{id:"r2",name:"Cloudflare R2",region:"global",envVars:["R2_ACCOUNT_ID","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY","R2_BUCKET"],docs:"https://developers.cloudflare.com/r2/api/s3/api/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"s3",name:"AWS S3",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_S3_REGION","S3_BUCKET"],docs:"https://docs.aws.amazon.com/s3/",pkg:"@aws-sdk/client-s3",pkgVersion:"^3.658.0"},{id:"supabase-storage",name:"Supabase Storage",region:"global",envVars:["SUPABASE_URL","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_BUCKET"],docs:"https://supabase.com/docs/guides/storage",pkg:"@supabase/supabase-js",pkgVersion:"^2.45.4"},{id:"aliyun-oss",name:"\u963F\u91CC\u4E91 OSS",region:"cn",envVars:["ALIYUN_OSS_ACCESS_KEY","ALIYUN_OSS_ACCESS_SECRET","ALIYUN_OSS_REGION","ALIYUN_OSS_BUCKET"],docs:"https://help.aliyun.com/product/31815.html",pkg:"ali-oss",pkgVersion:"^6.21.0"},{id:"tencent-cos",name:"\u817E\u8BAF\u4E91 COS",region:"cn",envVars:["TENCENT_COS_SECRET_ID","TENCENT_COS_SECRET_KEY","TENCENT_COS_BUCKET","TENCENT_COS_REGION"],docs:"https://cloud.tencent.com/document/product/436",pkg:"cos-nodejs-sdk-v5",pkgVersion:"^2.13.7"},{id:"qiniu",name:"\u4E03\u725B\u4E91 Kodo",region:"cn",envVars:["QINIU_ACCESS_KEY","QINIU_SECRET_KEY","QINIU_BUCKET","QINIU_DOMAIN"],docs:"https://developer.qiniu.com/kodo",pkg:"qiniu",pkgVersion:"^7.14.0"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function tn(e){let t=e==="supabase"?"supabase-storage":e;return ke.some(n=>n.id===t)?t:void 0}function Hn(e){let t=tn(e);return t?ke.find(n=>n.id===t):void 0}var $p=ke.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function zn(){let e=process.env.npm_config_user_agent??"";return e.startsWith("pnpm")?"pnpm":e.startsWith("yarn")?"yarn":e.startsWith("bun")?"bun":"npm"}function nn(e){switch(e){case"postgres":case"postgresql":return"postgresql";case"mysql":return"mysql";case"sqlite":return"sqlite";case"none":return"none";default:return"postgresql"}}function on(e,t,n){let o=e?.trim().toLowerCase()??qn(t),r=ft(o);if(!r){let i=en.map(a=>a.id).join(", ");throw new Error(`Unknown --db-host="${o}". Valid: ${i}`)}let s=n;return r.forcedEngine&&s!=="none"&&s!==r.forcedEngine&&(s=r.forcedEngine),{hostId:r.id,engine:s}}function rn(e){return e==="drizzle"?"drizzle":"prisma"}function yt(e){return e==="lemon"||e==="lemonsqueezy"?"lemon":e==="wechat"?"wechat":e==="alipay"?"alipay":e==="none"?"none":"stripe"}function St(e){if(!e)return"stripe";let t=e.toLowerCase();return t==="lemon"||t==="lemonsqueezy"?"lemon":t==="wechat"?"wechat":t==="alipay"?"alipay":t==="none"?"none":"stripe"}function sn(e){if(!e)return"clerk";let t=e.toLowerCase();return t==="betterauth"||t==="better-auth"?"betterauth":t==="nextauth"||t==="next-auth"||t==="authjs"||t==="auth.js"?"nextauth":t==="supabase"||t==="supabase-auth"?"supabase":t==="none"?"none":"clerk"}var vs=new Set(["gateway","direct","custom","none"]);function an(e){if(!e)return!1;let t=e.trim().toLowerCase();return vs.has(t)}function cn(e){if(!e)return["openai"];if(an(e))return[];let t=e.split(",").map(n=>n.trim().toLowerCase());return t.includes("none")?[]:t}function Jn(e,t){let n=e??t;return tn(n)??n}var Xn={mintlify:"Mintlify",docusaurus:"Docusaurus",nextra:"Nextra",vitepress:"VitePress"};function pn(e,t){if(!e)return"fumadocs";let n=e.toLowerCase();if(n==="fumadocs"||n==="none")return n;if(n in Xn){let o=Xn[n];return t?process.stdout.write(JSON.stringify({event:"notice",kind:"docs-fallback",requested:n,effective:"fumadocs"})+`
3
+ `):process.stdout.write(Wn.yellow(`\u26A0 ${o} support is coming in v1.2. Falling back to fumadocs.
4
+ `)+Wn.dim(` Track progress: https://github.com/Nebutra/Nebutra-Sailor/issues
5
+ `)),"fumadocs"}return"fumadocs"}function ht(e){switch(e){case"vercel":return"vercel";case"railway":return"railway";case"cloudflare":return"cloudflare";case"selfhost":return"selfhost";case"none":return"none";default:return"vercel"}}function ln(e){if(!e)return"global";let t=e.toLowerCase();return t==="cn"?"cn":t==="hybrid"?"hybrid":"global"}function Qn(e){return{...e==="cn"?{email:"aliyun-dm",storage:"aliyun-oss",monitoring:"sentry",analytics:"baidu",sms:"aliyun-sms"}:e==="hybrid"?{email:"resend",storage:"aliyun-oss",monitoring:"sentry",analytics:"posthog",sms:"aliyun-sms"}:{email:"resend",storage:"r2",monitoring:"sentry",analytics:"posthog",sms:"twilio"},queue:"none",search:"none",cache:e==="global"?"upstash-redis":e==="cn"?"redis":"upstash-redis",notifications:"none",webhooks:"none",cms:"none",featureFlags:"none",captcha:"none",mcp:"on",metering:"auto",billingMode:"usage",idp:"clerk",accessGate:"none"}}function dn(e){return e==="cn"?"wechat":"stripe"}import*as W from"@clack/prompts";import js from"picocolors";var un=[{id:"anthropic",name:"Anthropic",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.anthropic.com",envVarPrefix:"ANTHROPIC",requiredEnvVars:["ANTHROPIC_API_KEY"]},{id:"openai",name:"OpenAI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.openai.com/docs",envVarPrefix:"OPENAI",requiredEnvVars:["OPENAI_API_KEY"]},{id:"deepseek",name:"DeepSeek",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.deepseek.com/api-docs",envVarPrefix:"DEEPSEEK",requiredEnvVars:["DEEPSEEK_API_KEY"]},{id:"xai",name:"xAI (Grok)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://docs.x.ai/api",envVarPrefix:"XAI",requiredEnvVars:["XAI_API_KEY"]},{id:"moonshot",name:"Moonshot (Kimi)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"opencode",docs:"https://platform.moonshot.cn/docs",envVarPrefix:"MOONSHOT",requiredEnvVars:["MOONSHOT_API_KEY","MOONSHOT_BASE_URL"]},{id:"google",name:"Google Gemini",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://ai.google.dev/gemini-api/docs",envVarPrefix:"GOOGLE_GENERATIVE_AI",requiredEnvVars:["GOOGLE_GENERATIVE_AI_API_KEY"]},{id:"mistral",name:"Mistral AI",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.mistral.ai",envVarPrefix:"MISTRAL",requiredEnvVars:["MISTRAL_API_KEY"]},{id:"cohere",name:"Cohere",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"ai-sdk",docs:"https://docs.cohere.com",envVarPrefix:"COHERE",requiredEnvVars:["COHERE_API_KEY"]},{id:"perplexity",name:"Perplexity",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.perplexity.ai",baseURL:"https://api.perplexity.ai",envVarPrefix:"PERPLEXITY",requiredEnvVars:["PERPLEXITY_API_KEY"]},{id:"ai21",name:"AI21 Labs",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://docs.ai21.com",baseURL:"https://api.ai21.com/studio/v1",envVarPrefix:"AI21",requiredEnvVars:["AI21_API_KEY"]},{id:"upstage",name:"Upstage (Solar)",category:"\u76F4\u63A5\u5B9E\u9A8C\u5BA4",status:"cn-compatible",docs:"https://developers.upstage.ai/docs",baseURL:"https://api.upstage.ai/v1/solar",envVarPrefix:"UPSTAGE",requiredEnvVars:["UPSTAGE_API_KEY"]},{id:"siliconflow",name:"\u7845\u57FA\u6D41\u52A8 SiliconFlow",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://docs.siliconflow.cn",baseURL:"https://api.siliconflow.cn/v1",envVarPrefix:"SILICONFLOW",requiredEnvVars:["SILICONFLOW_API_KEY"]},{id:"volcengine-ark",name:"\u706B\u5C71\u5F15\u64CE ARK (\u8C46\u5305)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://www.volcengine.com/docs/82379",baseURL:"https://ark.cn-beijing.volces.com/api/v3",envVarPrefix:"ARK",requiredEnvVars:["ARK_API_KEY"]},{id:"bailian",name:"\u767E\u70BC Bailian (\u901A\u4E49)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://help.aliyun.com/zh/model-studio",baseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",envVarPrefix:"DASHSCOPE",requiredEnvVars:["DASHSCOPE_API_KEY"]},{id:"zhipu",name:"\u667A\u8C31 AI Zhipu",category:"\u56FD\u5185\u5E73\u53F0",status:"ai-sdk",docs:"https://docs.bigmodel.cn",baseURL:"https://open.bigmodel.cn/api/paas/v4",envVarPrefix:"ZHIPU",requiredEnvVars:["ZHIPU_API_KEY"]},{id:"baichuan",name:"\u767E\u5DDD\u667A\u80FD Baichuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.baichuan-ai.com/docs",baseURL:"https://api.baichuan-ai.com/v1",envVarPrefix:"BAICHUAN",requiredEnvVars:["BAICHUAN_API_KEY"]},{id:"minimax",name:"MiniMax (ABAB)",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.minimaxi.com/document/guides",baseURL:"https://api.minimax.chat/v1",envVarPrefix:"MINIMAX",requiredEnvVars:["MINIMAX_API_KEY","MINIMAX_GROUP_ID"]},{id:"stepfun",name:"\u9636\u8DC3\u661F\u8FB0 StepFun",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.stepfun.com/docs",baseURL:"https://api.stepfun.com/v1",envVarPrefix:"STEPFUN",requiredEnvVars:["STEPFUN_API_KEY"]},{id:"sensetime",name:"\u5546\u6C64 SenseNova",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.sensenova.cn/docs",baseURL:"https://token.sensenova.cn/v1",envVarPrefix:"SENSENOVA",requiredEnvVars:["SENSENOVA_API_KEY"]},{id:"tencent",name:"\u817E\u8BAF\u6DF7\u5143 Hunyuan",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://cloud.tencent.com/document/product/1729",baseURL:"https://api.hunyuan.cloud.tencent.com/v1",envVarPrefix:"HUNYUAN",requiredEnvVars:["HUNYUAN_API_KEY"]},{id:"lingyi",name:"\u96F6\u4E00\u4E07\u7269 Yi",category:"\u56FD\u5185\u5E73\u53F0",status:"cn-compatible",docs:"https://platform.lingyiwanwu.com/docs",baseURL:"https://api.lingyiwanwu.com/v1",envVarPrefix:"YI",requiredEnvVars:["YI_API_KEY"]},{id:"openrouter",name:"OpenRouter",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://openrouter.ai/docs",envVarPrefix:"OPENROUTER",requiredEnvVars:["OPENROUTER_API_KEY"]},{id:"vercel-gateway",name:"Vercel AI Gateway",category:"\u7EDF\u4E00\u7F51\u5173",status:"opencode",docs:"https://vercel.com/docs/ai-gateway",envVarPrefix:"AI_GATEWAY",requiredEnvVars:["AI_GATEWAY_API_KEY"]},{id:"litellm",name:"LiteLLM Proxy",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://docs.litellm.ai",baseURL:"http://localhost:4000/v1",envVarPrefix:"LITELLM",requiredEnvVars:["LITELLM_API_KEY"]},{id:"portkey",name:"Portkey",category:"\u7EDF\u4E00\u7F51\u5173",status:"cn-compatible",docs:"https://portkey.ai/docs",baseURL:"https://api.portkey.ai/v1",envVarPrefix:"PORTKEY",requiredEnvVars:["PORTKEY_API_KEY"]},{id:"aws-bedrock",name:"AWS Bedrock",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://aws.amazon.com/bedrock/",envVarPrefix:"AWS_BEDROCK",requiredEnvVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"]},{id:"azure-openai",name:"Azure OpenAI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/",envVarPrefix:"AZURE_OPENAI",requiredEnvVars:["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"]},{id:"gcp-vertex",name:"GCP Vertex AI",category:"\u4E91\u5E73\u53F0",status:"ai-sdk",docs:"https://cloud.google.com/vertex-ai",envVarPrefix:"GOOGLE_VERTEX",requiredEnvVars:["GOOGLE_APPLICATION_CREDENTIALS"]},{id:"groq",name:"Groq",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://console.groq.com/docs",envVarPrefix:"GROQ",requiredEnvVars:["GROQ_API_KEY"]},{id:"fireworks",name:"Fireworks AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.fireworks.ai",envVarPrefix:"FIREWORKS",requiredEnvVars:["FIREWORKS_API_KEY"]},{id:"together",name:"Together AI",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://docs.together.ai",envVarPrefix:"TOGETHER",requiredEnvVars:["TOGETHER_API_KEY"]},{id:"huggingface",name:"Hugging Face",category:"\u63A8\u7406\u52A0\u901F",status:"opencode",docs:"https://huggingface.co/docs/inference-providers",envVarPrefix:"HF",requiredEnvVars:["HF_API_KEY"]},{id:"replicate",name:"Replicate",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://replicate.com/docs",envVarPrefix:"REPLICATE",requiredEnvVars:["REPLICATE_API_TOKEN"]},{id:"lepton",name:"Lepton AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://www.lepton.ai/docs",baseURL:"https://api.lepton.ai/v1",envVarPrefix:"LEPTON",requiredEnvVars:["LEPTON_API_KEY"]},{id:"anyscale",name:"Anyscale Endpoints",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://docs.endpoints.anyscale.com/",baseURL:"https://api.endpoints.anyscale.com/v1",envVarPrefix:"ANYSCALE",requiredEnvVars:["ANYSCALE_API_KEY"]},{id:"octoai",name:"OctoAI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://octoai.cloud/docs",baseURL:"https://text.octoai.run/v1",envVarPrefix:"OCTOAI",requiredEnvVars:["OCTOAI_TOKEN"]},{id:"deepinfra",name:"DeepInfra",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://deepinfra.com/docs",baseURL:"https://api.deepinfra.com/v1/openai",envVarPrefix:"DEEPINFRA",requiredEnvVars:["DEEPINFRA_API_KEY"]},{id:"novita",name:"Novita AI",category:"\u63A8\u7406\u52A0\u901F",status:"cn-compatible",docs:"https://novita.ai/docs",baseURL:"https://api.novita.ai/v3/openai",envVarPrefix:"NOVITA",requiredEnvVars:["NOVITA_API_KEY"]},{id:"black-forest-labs",name:"Black Forest Labs (FLUX)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://docs.bfl.ml",envVarPrefix:"BFL",requiredEnvVars:["BFL_API_KEY"]},{id:"elevenlabs",name:"ElevenLabs (TTS)",category:"\u591A\u6A21\u6001",status:"ai-sdk",docs:"https://elevenlabs.io/docs",envVarPrefix:"ELEVENLABS",requiredEnvVars:["ELEVENLABS_API_KEY"]},{id:"runway",name:"Runway (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://runwayml.com",envVarPrefix:"RUNWAY",requiredEnvVars:["RUNWAY_API_KEY"]},{id:"luma",name:"Luma (Video)",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://lumalabs.ai",envVarPrefix:"LUMA",requiredEnvVars:["LUMA_API_KEY"]},{id:"midjourney",name:"Midjourney",category:"\u591A\u6A21\u6001",status:"pending",docs:"https://docs.midjourney.com",envVarPrefix:"MIDJOURNEY",requiredEnvVars:[]},{id:"ollama",name:"Ollama (\u672C\u5730)",category:"\u672C\u5730\u90E8\u7F72",status:"opencode",docs:"https://github.com/ollama/ollama",baseURL:"http://localhost:11434/v1",envVarPrefix:"OLLAMA",requiredEnvVars:["OLLAMA_BASE_URL"]},{id:"lmstudio",name:"LM Studio",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://lmstudio.ai/docs",baseURL:"http://localhost:1234/v1",envVarPrefix:"LMSTUDIO",requiredEnvVars:[]},{id:"vllm",name:"vLLM",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://docs.vllm.ai",baseURL:"http://localhost:8000/v1",envVarPrefix:"VLLM",requiredEnvVars:[]},{id:"tgi",name:"HF TGI",category:"\u672C\u5730\u90E8\u7F72",status:"cn-compatible",docs:"https://huggingface.co/docs/text-generation-inference",baseURL:"http://localhost:8080/v1",envVarPrefix:"TGI",requiredEnvVars:[]}],Hp=un.reduce((e,t)=>(e[t.category]||(e[t.category]=[]),e[t.category].push(t),e),{});var bs=["openai","anthropic","google"],_s=["openai"];function mn(e){let t=e.providerIds??[];switch(e.mode){case"gateway":{let n=t.length>0?t:[...bs];return{mode:"gateway",providerIds:n,customEndpoint:e.customEndpoint,routing:{profile:"multi-provider-gateway",providerSeed:n,runtimeGovernance:!0}}}case"direct":{let n=t.length>0?t:[..._s];return{mode:"direct",providerIds:n,customEndpoint:e.customEndpoint,routing:{profile:"direct-adapters",providerSeed:n,runtimeGovernance:!1}}}case"custom":return{mode:"custom",providerIds:t,customEndpoint:e.customEndpoint,routing:{profile:"openai-compatible",providerSeed:t,runtimeGovernance:!0}};case"none":return{mode:"none",providerIds:[],routing:{profile:"disabled",providerSeed:[],runtimeGovernance:!1}}}}var et=[{id:"wechat",name:"\u5FAE\u4FE1\u5F00\u653E\u5E73\u53F0",region:"cn",envVars:["WECHAT_APP_ID","WECHAT_APP_SECRET"],docs:"https://open.weixin.qq.com/cgi-bin/showdocument",callbackUrl:"/api/auth/callback/wechat",tokenEndpoint:"https://api.weixin.qq.com/sns/oauth2/access_token"},{id:"qq",name:"QQ \u767B\u5F55",region:"cn",envVars:["QQ_APP_ID","QQ_APP_KEY"],docs:"https://wiki.connect.qq.com",callbackUrl:"/api/auth/callback/qq",tokenEndpoint:"https://graph.qq.com/oauth2.0/token"},{id:"dingtalk",name:"\u9489\u9489",region:"cn",envVars:["DINGTALK_APP_ID","DINGTALK_APP_SECRET"],docs:"https://open.dingtalk.com/document/",callbackUrl:"/api/auth/callback/dingtalk",tokenEndpoint:"https://api.dingtalk.com/v1.0/oauth2/userAccessToken"},{id:"workweixin",name:"\u4F01\u4E1A\u5FAE\u4FE1",region:"cn",envVars:["WORKWEIXIN_CORP_ID","WORKWEIXIN_AGENT_ID","WORKWEIXIN_SECRET"],docs:"https://developer.work.weixin.qq.com",callbackUrl:"/api/auth/callback/workweixin",tokenEndpoint:"https://qyapi.weixin.qq.com/cgi-bin/gettoken"},{id:"feishu",name:"\u98DE\u4E66 / Lark",region:"cn",envVars:["FEISHU_APP_ID","FEISHU_APP_SECRET"],docs:"https://open.feishu.cn/document/",callbackUrl:"/api/auth/callback/feishu",tokenEndpoint:"https://open.feishu.cn/open-apis/authen/v1/access_token"},{id:"weibo",name:"\u5FAE\u535A",region:"cn",envVars:["WEIBO_APP_KEY","WEIBO_APP_SECRET"],docs:"https://open.weibo.com/wiki/",callbackUrl:"/api/auth/callback/weibo",tokenEndpoint:"https://api.weibo.com/oauth2/access_token"}],ws=new Set(et.map(e=>e.id));function Zn(e){return et.find(t=>t.id===e)}function eo(e){if(!e)return[];let t=e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(t.includes("none"))return[];let n=[],o=new Set;for(let r of t)ws.has(r)&&!o.has(r)&&(n.push(r),o.add(r));return n}import re from"fs";import k from"path";import{fileURLToPath as Rs}from"url";var to=["web","landing","auth","admin","design-docs","sailor-docs","router","forge","typelens","gateway","python-ai"],Ps={web:"frontend",landing:"frontend",auth:"frontend",admin:"frontend","design-docs":"frontend","sailor-docs":"frontend",router:"frontend",forge:"frontend",typelens:"frontend",gateway:"edgeGateway","python-ai":"originBackend"},As={frontend:"vercel",edgeGateway:"cloudflare-workers",originBackend:"ecs-docker"};function Cs(e){return to.includes(e)}function Is(e){if(!Cs(e))throw new Error(`Unknown deploy service '${e}'. Deploy targets apply only to apps/backends, not packages.`)}function Ts(e){return Is(e),Ps[e]}function xs(e){let t=Ts(e);return As[t]}function no(){return Object.fromEntries(to.map(e=>[e,xs(e)]))}var ks=Rs(import.meta.url),oo=k.dirname(ks),Ns="cloudflare-pages",Os="standalone",Ls="railway";function gn(e,t,n,o){return{...e,web:t,landing:t,auth:t,admin:t,"design-docs":t,"sailor-docs":t,router:t,forge:t,typelens:t,gateway:n,"python-ai":o}}function Us(){let e=[k.join(oo,"..","templates","deploy"),k.join(oo,"..","..","templates","deploy")];for(let t of e)if(re.existsSync(t))return t;return e[0]}function xt(e){let t=no();switch(e){case"cloudflare":return gn(t,Ns,"cloudflare-workers","ecs-docker");case"selfhost":return gn(t,Os,"ecs-docker","ecs-docker");case"railway":return gn(t,Ls,"railway","railway");case"none":case"vercel":return t}}function Ds(e){return`DEPLOY_TARGET_${e.toUpperCase().replace(/-/g,"_")}`}async function ro(e,t){let n=k.join(e,"backends","gateway");re.existsSync(n)&&await re.promises.copyFile(k.join(t,"wrangler.gateway.toml"),k.join(n,"wrangler.toml"))}async function so(e,t){let n=k.join(e,".env.example"),o;try{o=await re.promises.readFile(n,"utf8")}catch(i){if(i.code==="ENOENT")return;throw i}if(o.includes("# Deployment Targets"))return;let s=["","# Deployment Targets",...Object.entries(t).map(([i,a])=>`${Ds(i)}="${a}"`)].join(`
6
+ `);await re.promises.appendFile(n,`${s}
7
+ `)}async function io(e,t){if(t==="none")return;let n=Us();t==="vercel"?(await re.promises.copyFile(k.join(n,"vercel.json"),k.join(e,"vercel.json")),await ro(e,n)):t==="railway"?await re.promises.copyFile(k.join(n,"railway.toml"),k.join(e,"railway.toml")):t==="cloudflare"?(await re.promises.copyFile(k.join(n,"wrangler.toml"),k.join(e,"wrangler.toml")),await ro(e,n)):t==="selfhost"&&(await re.promises.copyFile(k.join(n,"docker-compose.yml"),k.join(e,"docker-compose.yml")),await re.promises.copyFile(k.join(n,"Dockerfile.web"),k.join(e,"Dockerfile.web")))}var Ms={qstash:"foundation",bullmq:"foundation",upstash:"foundation",sqs:"foundation",meilisearch:"foundation",typesense:"foundation",algolia:"foundation",pgvector:"foundation","vercel-flags":"foundation",growthbook:"foundation",configcat:"foundation",turnstile:"wip",hcaptcha:"wip","aliyun-slide":"wip",invite:"foundation"};function Fs(e){return e?Ms[e]??"stable":"stable"}function tt(e){switch(e){case"stable":return"";case"foundation":return"[Foundation]";case"wip":return"[WIP]";case"deprecated":return"[Deprecated]"}}function Ne(e){switch(e){case"stable":return"Production-ready.";case"foundation":return"Foundation status \u2014 core contracts work, but production use still requires provider credentials, adapter wiring, or a verified integration contract.";case"wip":return"WIP \u2014 actively being built, should not be used in production.";case"deprecated":return"Deprecated \u2014 scheduled for removal, do not use."}}function Rt(e){let t=[];for(let{flag:n,provider:o}of e){if(!o||o==="none")continue;let r=Fs(o);r!=="stable"&&t.push({flag:n,provider:o,status:r})}return t}function Pe(e,t){if(e===void 0)return t;let n=String(e).trim().toLowerCase();return n==="true"||n==="1"||n==="yes"||n==="on"?!0:n==="false"||n==="0"||n==="no"||n==="off"?!1:t}function ao(e,t){let n=t==="cn";return{cronJobs:Pe(e.cronJobs,!0),auditLog:Pe(e.auditLog,!1),apiKeys:Pe(e.apiKeys,!0),webhooks:Pe(e.webhooks,!0),commandPalette:Pe(e.commandPalette,!0),cookieConsent:Pe(e.cookieConsent,!0),legalPages:Pe(e.legalPages,!0),chinaCompliance:Pe(e.chinaCompliance,n)}}async function Bs(e,t,n,o){let r={};return t||(r.region=()=>W.select({message:"Target region?",options:[{value:"global",label:"Global",hint:"Stripe \xB7 Resend \xB7 R2 defaults"},{value:"cn",label:"China",hint:"WeChat Pay \xB7 Aliyun DM/OSS defaults"},{value:"hybrid",label:"Hybrid",hint:"global + CN dual track"}],initialValue:"global"})),n||(r.auth=()=>W.select({message:"Auth provider?",options:[{value:"clerk",label:"Clerk",hint:"managed, fastest setup"},{value:"betterauth",label:"Better Auth",hint:"self-hosted, modern (2FA / passkeys / RBAC)"},{value:"nextauth",label:"NextAuth (Auth.js v5)",hint:"self-hosted, mature, large ecosystem"},{value:"supabase",label:"Supabase Auth",hint:"managed auth with Supabase storage/realtime ecosystem"},{value:"none",label:"None"}],initialValue:"clerk"})),o||(r.aiMode=()=>W.select({message:"AI topology?",options:[{value:"gateway",label:"Multi-provider AI Gateway / router",hint:"recommended"},{value:"direct",label:"Direct SDK/provider adapters"},{value:"custom",label:"OpenAI-compatible endpoint"},{value:"none",label:"Skip AI"}],initialValue:"gateway"}),r.aiProviders=({results:s})=>{if(s.aiMode!=="direct")return Promise.resolve([]);let i=un.map(a=>({value:a.id,label:`[${a.category}] ${a.name}`}));return W.multiselect({message:"Select direct AI provider adapters (expert path)",options:i,initialValues:["openai"],required:!1})},r.customAiName=({results:s})=>s.aiMode==="custom"?W.text({message:"Custom endpoint name (e.g. proxy, local):",defaultValue:"custom",placeholder:"custom"}):Promise.resolve(void 0),r.customAiBaseUrl=({results:s})=>s.aiMode==="custom"?W.text({message:"Custom endpoint base URL (e.g. https://api.proxy.com/v1):",validate:i=>{if(!i?.length)return"Base URL is required."}}):Promise.resolve(void 0),r.customAiApiKeyEnv=({results:s})=>s.aiMode==="custom"?W.text({message:"Environment variable name for the API Key:",defaultValue:"CUSTOM_AI_API_KEY",placeholder:"CUSTOM_AI_API_KEY"}):Promise.resolve(void 0)),Object.keys(r).length===0?{}:await W.group(r,{onCancel:()=>{process.stdout.write(js.red(`\u2718 Cancelled
8
+ `)),process.exit(130)}})}async function co(e,t){let n=!!e.region,o=!!e.auth,r=!!e.payment,s=!!e.ai,i=!!e.email,a=!!e.storage,c=!!e.monitoring,p=!!e.analytics,m=!!e.sms,d=e.i18n!==void 0,g=!!e.yes||!process.stdin.isTTY,h,P,E,l,y,U,R,ve=eo(e.socialLogin),ue,oe,G,q,I,z,V;if(g){h=ln(e.region),P=rn(e.orm);{let H=nn(e.db),Tt=on(e.dbHost,h,H);E=Tt.engine,l=Tt.hostId}let J=r?e.payment:dn(h);y=yt(J),U=St(J),R=sn(e.auth);let Ze="gateway";if(s){let H=e.ai?.trim().toLowerCase()??"";an(H)?Ze=H:Ze="direct"}let gt=mn({mode:Ze,providerIds:s?cn(e.ai):void 0});ue=gt.mode,oe=gt.routing,G=gt.providerIds,I=ht(e.deploy),z=pn(e.docs,t),V=d?!!e.i18n:!0}else{let J=await Bs(e,n,o,s);h=ln(n?e.region:J.region),P=rn(e.orm);{let Tt=nn(e.db),Kn=on(e.dbHost,h,Tt);E=Kn.engine,l=Kn.hostId}let Ze=r?e.payment:dn(h);y=yt(Ze),U=St(Ze),R=sn(o?e.auth:J.auth);let gt=J.aiMode==="custom"?{name:J.customAiName??"custom",baseURL:J.customAiBaseUrl??"",apiKeyEnvName:J.customAiApiKeyEnv??"CUSTOM_AI_API_KEY"}:void 0,H=mn({mode:s?e.ai?.trim().toLowerCase()==="none"?"none":"direct":J.aiMode??"gateway",providerIds:s?cn(e.ai):J.aiProviders,customEndpoint:gt});ue=H.mode,oe=H.routing,G=H.providerIds,H.customEndpoint&&(q={name:H.customEndpoint.name,baseURL:H.customEndpoint.baseURL,apiKeyEnvName:H.customEndpoint.apiKeyEnvName}),I=ht(e.deploy),z=pn(e.docs,t),V=d?!!e.i18n:!0}let A=Qn(h),Re=i?e.email:A.email,be=Jn(a?e.storage:void 0,A.storage),Je=c?e.monitoring:A.monitoring,Qe=p?e.analytics:A.analytics,_e=m?e.sms:A.sms,b=e.queue??A.queue,D=e.search??A.search,_=e.cache??A.cache,me=e.notifications??A.notifications,Xt=e.webhooks??A.webhooks,Mn=e.cms??A.cms,zt=e.featureFlags??A.featureFlags,Jt=e.captcha??A.captcha,Fn=e.mcp??A.mcp,jn=e.metering??A.metering,Bn=e.billingMode??A.billingMode,$n=e.idp??A.idp,Qt=e.accessGate==="invite"?"invite":A.accessGate,Vn=xt(I),we=ao({cronJobs:e.cronJobs,auditLog:e.auditLog,apiKeys:e.apiKeys,commandPalette:e.commandPalette,cookieConsent:e.cookieConsent,legalPages:e.legalPages,chinaCompliance:e.chinaCompliance},h),gs=Rt([{flag:"queue",provider:b},{flag:"search",provider:D},{flag:"notifications",provider:me},{flag:"webhooks",provider:Xt},{flag:"feature-flags",provider:zt},{flag:"captcha",provider:Jt},{flag:"access-gate",provider:Qt}]),fs={region:h,orm:P,database:E,databaseHost:l,payment:y,aiMode:ue,aiRouting:oe,aiProviders:G,customAiEndpoint:q,deployTarget:I,deployTargets:Vn,docs:z,i18n:V,email:Re,storage:be,monitoring:Je,analytics:Qe,sms:_e,queue:b,search:D,cache:_,notifications:me,webhooks:Xt,cms:Mn,featureFlags:zt,captcha:Jt,mcp:Fn,metering:jn,billingMode:Bn,idp:$n,accessGate:Qt,cronJobs:we.cronJobs,auditLog:we.auditLog,apiKeys:we.apiKeys,commandPalette:we.commandPalette,cookieConsent:we.cookieConsent,legalPages:we.legalPages,chinaCompliance:we.chinaCompliance};return{region:h,orm:P,database:E,databaseHost:l,payment:y,paymentChoice:U,auth:R,socialLoginIds:ve,aiMode:ue,aiRouting:oe,aiProviders:G,customAiEndpoint:q,deployTarget:I,deployTargets:Vn,docs:z,i18n:V,email:Re,storage:be,monitoring:Je,analytics:Qe,sms:_e,queue:b,search:D,cache:_,notifications:me,webhooks:Xt,cms:Mn,featureFlags:zt,captcha:Jt,mcp:Fn,metering:jn,billingMode:Bn,idp:$n,accessGate:Qt,waveToggles:we,previewSelections:gs,config:fs}}import{execFileSync as qt}from"child_process";import Ht from"fs";import ze from"path";import F from"picocolors";import pp from"update-notifier";import nt from"picocolors";function $s(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function po(e){let t=$s(),n=t?"\u2693":"-",o=t?"\u25B8":"->",r=e.packageManager??"pnpm",s=e.hasDatabase!==!1,i=e.targetDir==="."||e.targetDir==="./"||e.targetDir===".\\",a=i?".":e.targetDir.endsWith("/")?e.targetDir:`${e.targetDir}/`,c=t?nt.bold(`${n} Done in ${e.elapsedSec}s \xB7 ${a}`):`${n} Done in ${e.elapsedSec}s \xB7 ${a}`,p=g=>t?nt.dim(g):g,m=g=>t?nt.bold(g):g,d=["",` ${c}`,"",` ${m("Next:")}`];i||d.push(` ${o} cd ${e.targetDir}`),e.skippedInstall&&d.push(` ${o} ${r} install`),d.push(` ${o} fill .env.local ${p("\u2192 provider keys from .env.example")}`),s&&d.push(` ${o} ${r} infra:up ${p("\u2192 local Postgres (optional)")}`,` ${o} ${r} db:migrate ${p("\u2192 apply Prisma schema")}`),d.push(` ${o} ${r} dev ${p("\u2192 http://localhost:3000")}`,"",` ${p("More:")} ${p("nebutra doctor")} ${p("\xB7")} ${p("docs.nebutra.com")}`);let v=e.previewSelections??[];if(v.length>0){let g=t?nt.bold(nt.yellow("\u26A0 Preview / foundation providers:")):"!! Preview / foundation providers:";d.push("",` ${g}`);for(let h of v){let P=tt(h.status),E=` ${o} ${h.flag}=${h.provider} ${P}`;d.push(t?nt.yellow(E):E)}d.push(` ${p(Ne("foundation"))}`)}d.push(""),process.stdout.write(d.join(`
9
9
  `)+`
10
- `)}import nt from"fs";import B from"path";var ro=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","POSTHOG_HOST","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],nl=ro.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function so(e){return ro.find(t=>t.id===e)}function Os(e){nt.mkdirSync(e,{recursive:!0})}function ne(e,t){Os(B.dirname(e)),nt.writeFileSync(e,t)}function ke(e,t){let n=B.join(e,".env.example");nt.existsSync(n)?nt.appendFileSync(n,`
11
- `+t):nt.writeFileSync(n,t)}function Ls(e){let t=`"use client";
10
+ `)}import ot from"fs";import K from"path";var lo=[{id:"posthog",name:"PostHog",region:"both",envVars:["POSTHOG_KEY","POSTHOG_HOST","NEXT_PUBLIC_POSTHOG_KEY","NEXT_PUBLIC_POSTHOG_HOST"],docs:"https://posthog.com/docs",pkgs:["posthog-js","posthog-node"],providerFile:"apps/web/src/lib/analytics/posthog.client.ts"},{id:"plausible",name:"Plausible",region:"global",envVars:["NEXT_PUBLIC_PLAUSIBLE_DOMAIN","NEXT_PUBLIC_PLAUSIBLE_SRC"],docs:"https://plausible.io/docs",providerFile:"apps/web/src/components/analytics/PlausibleScript.tsx"},{id:"umami",name:"Umami",region:"both",envVars:["NEXT_PUBLIC_UMAMI_WEBSITE_ID","NEXT_PUBLIC_UMAMI_SRC"],docs:"https://umami.is/docs",providerFile:"apps/web/src/components/analytics/UmamiScript.tsx"},{id:"mixpanel",name:"Mixpanel",region:"global",envVars:["MIXPANEL_TOKEN","NEXT_PUBLIC_MIXPANEL_TOKEN"],docs:"https://docs.mixpanel.com",pkgs:["mixpanel-browser","mixpanel"],providerFile:"apps/web/src/lib/analytics/mixpanel.client.ts"},{id:"baidu",name:"\u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji",region:"cn",envVars:["NEXT_PUBLIC_BAIDU_STATS_ID"],docs:"https://tongji.baidu.com",providerFile:"apps/web/src/components/analytics/BaiduStatsScript.tsx"},{id:"sensors",name:"\u795E\u7B56 Sensors Analytics",region:"cn",envVars:["NEXT_PUBLIC_SENSORS_SERVER_URL","NEXT_PUBLIC_SENSORS_APP_JS_URL"],docs:"https://manual.sensorsdata.cn",pkgs:["sa-sdk-javascript"],providerFile:"apps/web/src/lib/analytics/sensors.client.ts"},{id:"growingio",name:"GrowingIO",region:"cn",envVars:["NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID"],docs:"https://growingio.com/docs",providerFile:"apps/web/src/components/analytics/GrowingIoScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],hl=lo.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function uo(e){return lo.find(t=>t.id===e)}function Vs(e){ot.mkdirSync(e,{recursive:!0})}function se(e,t){Vs(K.dirname(e)),ot.writeFileSync(e,t)}function Oe(e,t){let n=K.join(e,".env.example");ot.existsSync(n)?ot.appendFileSync(n,`
11
+ `+t):ot.writeFileSync(n,t)}function Ks(e){let t=`"use client";
12
12
  /**
13
13
  * PostHog browser SDK \u2014 lazy-initialized on first access.
14
14
  */
@@ -91,12 +91,12 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
91
91
 
92
92
  return <>{children}</>;
93
93
  }
94
- `;ne(B.join(e,"src","lib","analytics","posthog.client.ts"),t),ne(B.join(e,"src","lib","analytics","posthog.server.ts"),n),ne(B.join(e,"src","components","analytics","AnalyticsProvider.tsx"),o)}function Us(){return`# PostHog \u2014 product analytics
94
+ `;se(K.join(e,"src","lib","analytics","posthog.client.ts"),t),se(K.join(e,"src","lib","analytics","posthog.server.ts"),n),se(K.join(e,"src","components","analytics","AnalyticsProvider.tsx"),o)}function Ys(){return`# PostHog \u2014 product analytics
95
95
  POSTHOG_KEY=
96
96
  POSTHOG_HOST=https://us.i.posthog.com
97
97
  NEXT_PUBLIC_POSTHOG_KEY=
98
98
  NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
99
- `}function Ds(e){ne(B.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
99
+ `}function Gs(e){se(K.join(e,"src","components","analytics","PlausibleScript.tsx"),`"use client";
100
100
  /**
101
101
  * Plausible script tag \u2014 lightweight, privacy-friendly analytics.
102
102
  */
@@ -116,10 +116,10 @@ export function PlausibleScript() {
116
116
  />
117
117
  );
118
118
  }
119
- `)}function Ms(){return`# Plausible \u2014 privacy-friendly analytics
119
+ `)}function qs(){return`# Plausible \u2014 privacy-friendly analytics
120
120
  NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
121
121
  NEXT_PUBLIC_PLAUSIBLE_SRC=https://plausible.io/js/script.js
122
- `}function Fs(e){ne(B.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
122
+ `}function Hs(e){se(K.join(e,"src","components","analytics","UmamiScript.tsx"),`"use client";
123
123
  /**
124
124
  * Umami analytics \u2014 self-hosted OR umami.is cloud.
125
125
  */
@@ -139,10 +139,10 @@ export function UmamiScript() {
139
139
  />
140
140
  );
141
141
  }
142
- `)}function js(){return`# Umami \u2014 self-hostable analytics
142
+ `)}function Ws(){return`# Umami \u2014 self-hostable analytics
143
143
  NEXT_PUBLIC_UMAMI_WEBSITE_ID=
144
144
  NEXT_PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
145
- `}function Bs(e){let t=`"use client";
145
+ `}function Xs(e){let t=`"use client";
146
146
  import mixpanel from "mixpanel-browser";
147
147
 
148
148
  let initialized = false;
@@ -181,10 +181,10 @@ export function trackServer(
181
181
  if (!c) return;
182
182
  c.track(event, { distinct_id: distinctId, ...properties });
183
183
  }
184
- `;ne(B.join(e,"src","lib","analytics","mixpanel.client.ts"),t),ne(B.join(e,"src","lib","analytics","mixpanel.server.ts"),n)}function $s(){return`# Mixpanel \u2014 product analytics
184
+ `;se(K.join(e,"src","lib","analytics","mixpanel.client.ts"),t),se(K.join(e,"src","lib","analytics","mixpanel.server.ts"),n)}function zs(){return`# Mixpanel \u2014 product analytics
185
185
  MIXPANEL_TOKEN=
186
186
  NEXT_PUBLIC_MIXPANEL_TOKEN=
187
- `}function Vs(e){ne(B.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
187
+ `}function Js(e){se(K.join(e,"src","components","analytics","BaiduStatsScript.tsx"),`"use client";
188
188
  /**
189
189
  * \u767E\u5EA6\u7EDF\u8BA1 Baidu Tongji \u2014 hm.js \u57CB\u70B9\u811A\u672C.
190
190
  */
@@ -210,9 +210,9 @@ var _hmt = _hmt || [];
210
210
  />
211
211
  );
212
212
  }
213
- `)}function Ks(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
213
+ `)}function Qs(){return`# \u767E\u5EA6\u7EDF\u8BA1 \u2014 \u4E2D\u56FD\u533A\u7F51\u7AD9\u5206\u6790
214
214
  NEXT_PUBLIC_BAIDU_STATS_ID=
215
- `}function Ys(e){ne(B.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
215
+ `}function Zs(e){se(K.join(e,"src","lib","analytics","sensors.client.ts"),`"use client";
216
216
  /**
217
217
  * \u795E\u7B56\u5206\u6790 (Sensors Analytics) \u2014 sa-sdk-javascript \u5C01\u88C5.
218
218
  */
@@ -240,10 +240,10 @@ export function initSensors(): void {
240
240
  }
241
241
 
242
242
  export { sensors };
243
- `)}function qs(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
243
+ `)}function ei(){return`# \u795E\u7B56\u5206\u6790 Sensors Analytics
244
244
  NEXT_PUBLIC_SENSORS_SERVER_URL=
245
245
  NEXT_PUBLIC_SENSORS_APP_JS_URL=
246
- `}function Gs(e){ne(B.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
246
+ `}function ti(e){se(K.join(e,"src","components","analytics","GrowingIoScript.tsx"),`"use client";
247
247
  /**
248
248
  * GrowingIO CDP \u2014 inline snippet installer.
249
249
  */
@@ -268,21 +268,21 @@ gdp("send");
268
268
  />
269
269
  );
270
270
  }
271
- `)}function Hs(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
271
+ `)}function ni(){return`# GrowingIO \u2014 \u5168\u57CB\u70B9 CDP (\u4E2D\u56FD\u533A)
272
272
  NEXT_PUBLIC_GROWINGIO_ACCOUNT_ID=
273
- `}async function io(e,t,n="global"){let o=so(t);if(!o||o.id==="none")return;let r=B.join(e,"apps","web");if(!nt.existsSync(r))return;let s=o.id;try{switch(s){case"posthog":Ls(r),ke(e,Us());return;case"plausible":Ds(r),ke(e,Ms());return;case"umami":Fs(r),ke(e,js());return;case"mixpanel":Bs(r),ke(e,$s());return;case"baidu":Vs(r),ke(e,Ks());return;case"sensors":Ys(r),ke(e,qs());return;case"growingio":Gs(r),ke(e,Hs());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Ws={name:"Nebutra",nameCn:"\u4E91\u6BD3\u667A\u80FD",nameFull:"\u65E0\u9521\u4E91\u6BD3\u667A\u80FD\u79D1\u6280\u6709\u9650\u516C\u53F8",nameFullEn:"Wuxi Nebutra Intelligence Technology Co., Ltd.",tagline:"Ship AI products, not boilerplate.",taglineCn:"AI\u539F\u751F\xB7\u5FEB\u901F\u51FA\u6D77\xB7\u5373\u523B\u4EA4\u4ED8",description:"Production-ready Next.js monorepo template for AI SaaS products. Auth, billing, multi-tenancy, AI services, design system, and enterprise infrastructure \u2014 pre-configured.",descriptionCn:"\u9762\u5411AI\u521B\u4E1A\u8005\u7684\u4E00\u4F53\u5316SaaS\u57FA\u7840\u8BBE\u65BD\u6A21\u677F\uFF0C\u8986\u76D6\u8BA4\u8BC1\u3001\u8BA1\u8D39\u3001\u591A\u79DF\u6237\u3001AI\u670D\u52A1\u4E0E\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u5F00\u7BB1\u5373\u4EA7\u54C1",story:{concept:"Logo\u4EE5\u9996\u5B57\u6BCDN\u7684\u57FA\u7840\u9020\u578B\u6982\u5FF5\u4E3A\u4E3B\u8981\u8BBE\u8BA1\u6846\u67B6\uFF0C\u901A\u8FC7\u51E0\u4F55\u6B63\u8D1F\u7A7A\u95F4\u6784\u5EFA\u9690\u5F62'N'\uFF0C\u5F62\u6210\u8FD1\u4F3C\u516D\u8FB9\u5F62\u7684\u7A33\u5B9A\u7ED3\u6784",colorMeaning:"\u84DD\u7EFF\u6E10\u53D8\u4F53\u73B0\u672A\u6765\u611F\u4E0E\u79D1\u6280\u950B\u8292\uFF0C'\u4E91'\u4EE3\u8868\u4E91\u7AEF\u5E73\u53F0\uFF0C'\u6BD3'\u5BD3\u610F\u5B55\u80B2\u4E0E\u8F6C\u5316",values:["AI Native","Ship Fast","Open by Default","Global-Ready","Enterprise-Grade"],missionStatement:"Help AI founders and SaaS teams go from idea to production 10x faster by providing the infrastructure layer they shouldn't have to build."},domains:{landing:"nebutra.com",app:"app.nebutra.com",api:"api.nebutra.com",auth:"auth.nebutra.com",sso:"sso.nebutra.com",docs:"docs.nebutra.com",studio:"studio.nebutra.com",cdn:"cdn.nebutra.com",router:"router.nebutra.com",forge:"forge.nebutra.com",design:"design.nebutra.com",status:"status.nebutra.com",open:"open.nebutra.com",admin:"admin.nebutra.com",analytics:"analytics.nebutra.com",pebble:"pebble.nebutra.com",carina:"carina.nebutra.com",kuanlan:"kuanlan.nebutra.com",origin:"origin.nebutra.com"},social:{twitter:"https://twitter.com/nebutra",github:"https://github.com/nebutra",discord:"https://discord.gg/nebutra",linkedin:"https://linkedin.com/company/nebutra"}};function ao(e){let t=Ws.domains[e];if(!t?.trim())throw new Error(`brand.domains.${String(e)} is empty \u2014 run brand:apply`);return`https://${t.replace(/^https?:\/\//,"").replace(/\/+$/,"")}`}var Xs=ao("analytics");function zs(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function co(e,t={}){zs(t)||(async()=>{try{let n=await import("@nebutra/analytics");if(typeof n.createProductAnalyticsClient!="function")return;let o=n.createProductAnalyticsClient({posthog:{apiKey:process.env.POSTHOG_KEY??process.env.NEXT_PUBLIC_POSTHOG_KEY??process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.POSTHOG_HOST??process.env.NEXT_PUBLIC_POSTHOG_HOST??process.env.NEBUTRA_POSTHOG_HOST??Xs},onError:()=>{}});if(typeof o?.track!="function")return;let r=o.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import G from"fs";import k from"path";function $(e){G.existsSync(e)&&G.rmSync(e,{recursive:!0,force:!0})}function xt(e,t){let n=k.join(e,".env.example");G.existsSync(n)?G.appendFileSync(n,`
274
- `+t):G.writeFileSync(n,t)}function Rt(e,t){if(!G.existsSync(e))return;let n=G.readFileSync(e,"utf8"),o=n.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);o!==n&&G.writeFileSync(e,o)}function Js(e,t){let n=k.join(e,"README.md");if(!G.existsSync(n)){G.writeFileSync(n,t);return}G.appendFileSync(n,`
275
- `+t)}async function po(e,t){let n=k.join(e,"packages","iam","auth");if(!G.existsSync(n))return;if(t==="none"){$(n),Js(e,`
273
+ `}async function mo(e,t,n="global"){let o=uo(t);if(!o||o.id==="none")return;let r=K.join(e,"apps","web");if(!ot.existsSync(r))return;let s=o.id;try{switch(s){case"posthog":Ks(r),Oe(e,Ys());return;case"plausible":Gs(r),Oe(e,qs());return;case"umami":Hs(r),Oe(e,Ws());return;case"mixpanel":Xs(r),Oe(e,zs());return;case"baidu":Js(r),Oe(e,Qs());return;case"sensors":Zs(r),Oe(e,ei());return;case"growingio":ti(r),Oe(e,ni());return;default:return}}catch(i){throw console.error(`Failed to apply analytics selection "${t}":`,i),new Error(`Analytics scaffold for "${t}" failed \u2014 see stderr for details.`)}}var oi={name:"Nebutra",nameCn:"\u4E91\u6BD3\u667A\u80FD",nameFull:"\u65E0\u9521\u4E91\u6BD3\u667A\u80FD\u79D1\u6280\u6709\u9650\u516C\u53F8",nameFullEn:"Wuxi Nebutra Intelligence Technology Co., Ltd.",tagline:"Ship AI products, not boilerplate.",taglineCn:"AI\u539F\u751F\xB7\u5FEB\u901F\u51FA\u6D77\xB7\u5373\u523B\u4EA4\u4ED8",description:"Production-ready Next.js monorepo template for AI SaaS products. Auth, billing, multi-tenancy, AI services, design system, and enterprise infrastructure \u2014 pre-configured.",descriptionCn:"\u9762\u5411AI\u521B\u4E1A\u8005\u7684\u4E00\u4F53\u5316SaaS\u57FA\u7840\u8BBE\u65BD\u6A21\u677F\uFF0C\u8986\u76D6\u8BA4\u8BC1\u3001\u8BA1\u8D39\u3001\u591A\u79DF\u6237\u3001AI\u670D\u52A1\u4E0E\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u5F00\u7BB1\u5373\u4EA7\u54C1",story:{concept:"Logo\u4EE5\u9996\u5B57\u6BCDN\u7684\u57FA\u7840\u9020\u578B\u6982\u5FF5\u4E3A\u4E3B\u8981\u8BBE\u8BA1\u6846\u67B6\uFF0C\u901A\u8FC7\u51E0\u4F55\u6B63\u8D1F\u7A7A\u95F4\u6784\u5EFA\u9690\u5F62'N'\uFF0C\u5F62\u6210\u8FD1\u4F3C\u516D\u8FB9\u5F62\u7684\u7A33\u5B9A\u7ED3\u6784",colorMeaning:"\u84DD\u7EFF\u6E10\u53D8\u4F53\u73B0\u672A\u6765\u611F\u4E0E\u79D1\u6280\u950B\u8292\uFF0C'\u4E91'\u4EE3\u8868\u4E91\u7AEF\u5E73\u53F0\uFF0C'\u6BD3'\u5BD3\u610F\u5B55\u80B2\u4E0E\u8F6C\u5316",values:["AI Native","Ship Fast","Open by Default","Global-Ready","Enterprise-Grade"],missionStatement:"Help AI founders and SaaS teams go from idea to production 10x faster by providing the infrastructure layer they shouldn't have to build."},domains:{landing:"nebutra.com",app:"app.nebutra.com",api:"api.nebutra.com",auth:"auth.nebutra.com",sso:"sso.nebutra.com",docs:"docs.nebutra.com",studio:"studio.nebutra.com",cdn:"cdn.nebutra.com",router:"router.nebutra.com",forge:"forge.nebutra.com",design:"design.nebutra.com",status:"status.nebutra.com",open:"open.nebutra.com",admin:"admin.nebutra.com",analytics:"analytics.nebutra.com",pebble:"pebble.nebutra.com",carina:"carina.nebutra.com",kuanlan:"kuanlan.nebutra.com",origin:"origin.nebutra.com"},social:{twitter:"https://twitter.com/nebutra",github:"https://github.com/nebutra",discord:"https://discord.gg/nebutra",linkedin:"https://linkedin.com/company/nebutra"}};function go(e){let t=oi.domains[e];if(!t?.trim())throw new Error(`brand.domains.${String(e)} is empty \u2014 run brand:apply`);return`https://${t.replace(/^https?:\/\//,"").replace(/\/+$/,"")}`}var ri=go("analytics");function si(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function fo(e,t={}){si(t)||(async()=>{try{let n=await import("@nebutra/analytics");if(typeof n.createProductAnalyticsClient!="function")return;let o=n.createProductAnalyticsClient({posthog:{apiKey:process.env.POSTHOG_KEY??process.env.NEXT_PUBLIC_POSTHOG_KEY??process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.POSTHOG_HOST??process.env.NEXT_PUBLIC_POSTHOG_HOST??process.env.NEBUTRA_POSTHOG_HOST??ri},onError:()=>{}});if(typeof o?.track!="function")return;let r=o.track("scaffold.completed",e);r&&typeof r.then=="function"&&await r.catch(()=>{})}catch{}})()}import X from"fs";import N from"path";function Y(e){X.existsSync(e)&&X.rmSync(e,{recursive:!0,force:!0})}function kt(e,t){let n=N.join(e,".env.example");X.existsSync(n)?X.appendFileSync(n,`
274
+ `+t):X.writeFileSync(n,t)}function Nt(e,t){if(!X.existsSync(e))return;let n=X.readFileSync(e,"utf8"),o=n.replace(/export type AuthProviderId\s*=\s*(?:"[^"]+"\s*\|\s*)+"[^"]+";/,`export type AuthProviderId = "${t}";`);o!==n&&X.writeFileSync(e,o)}function ii(e,t){let n=N.join(e,"README.md");if(!X.existsSync(n)){X.writeFileSync(n,t);return}X.appendFileSync(n,`
275
+ `+t)}async function yo(e,t){let n=N.join(e,"packages","iam","auth");if(!X.existsSync(n))return;if(t==="none"){Y(n),ii(e,`
276
276
  ## Auth
277
277
 
278
278
  Auth was skipped at scaffold time (\`--auth=none\`). Add your preferred auth provider manually (e.g. Clerk, Better Auth, NextAuth, Supabase).
279
- `);return}let o=k.join(n,"src","providers"),r=k.join(n,"src","types.ts");if(t==="clerk"){$(k.join(o,"better-auth.ts")),$(k.join(o,"nextauth.ts")),$(k.join(o,"supabase.ts")),Rt(r,"clerk"),xt(e,`# Clerk auth
279
+ `);return}let o=N.join(n,"src","providers"),r=N.join(n,"src","types.ts");if(t==="clerk"){Y(N.join(o,"better-auth.ts")),Y(N.join(o,"nextauth.ts")),Y(N.join(o,"supabase.ts")),Nt(r,"clerk"),kt(e,`# Clerk auth
280
280
  CLERK_PUBLISHABLE_KEY=
281
281
  CLERK_SECRET_KEY=
282
- `);return}if(t==="betterauth"){$(k.join(o,"clerk.ts")),$(k.join(o,"nextauth.ts")),$(k.join(o,"supabase.ts")),Rt(r,"better-auth"),xt(e,`# Better Auth
282
+ `);return}if(t==="betterauth"){Y(N.join(o,"clerk.ts")),Y(N.join(o,"nextauth.ts")),Y(N.join(o,"supabase.ts")),Nt(r,"better-auth"),kt(e,`# Better Auth
283
283
  BETTER_AUTH_SECRET=
284
284
  BETTER_AUTH_URL=http://localhost:3000
285
- `);return}if(t==="nextauth"){$(k.join(o,"clerk.ts")),$(k.join(o,"better-auth.ts")),$(k.join(o,"supabase.ts")),Rt(r,"nextauth"),xt(e,`# NextAuth (Auth.js v5)
285
+ `);return}if(t==="nextauth"){Y(N.join(o,"clerk.ts")),Y(N.join(o,"better-auth.ts")),Y(N.join(o,"supabase.ts")),Nt(r,"nextauth"),kt(e,`# NextAuth (Auth.js v5)
286
286
  AUTH_SECRET=
287
287
  NEXTAUTH_URL=http://localhost:3000
288
288
  # OAuth (optional \u2014 leave blank to disable that provider)
@@ -290,7 +290,7 @@ GOOGLE_CLIENT_ID=
290
290
  GOOGLE_CLIENT_SECRET=
291
291
  GITHUB_CLIENT_ID=
292
292
  GITHUB_CLIENT_SECRET=
293
- `);return}if(t==="supabase"){$(k.join(o,"clerk.ts")),$(k.join(o,"better-auth.ts")),$(k.join(o,"nextauth.ts")),Rt(r,"supabase"),xt(e,`# Supabase Auth
293
+ `);return}if(t==="supabase"){Y(N.join(o,"clerk.ts")),Y(N.join(o,"better-auth.ts")),Y(N.join(o,"nextauth.ts")),Nt(r,"supabase"),kt(e,`# Supabase Auth
294
294
  NEXT_PUBLIC_SUPABASE_URL=
295
295
  NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
296
296
  NEXT_PUBLIC_SUPABASE_ANON_KEY=
@@ -298,7 +298,7 @@ SUPABASE_URL=
298
298
  SUPABASE_PUBLISHABLE_KEY=
299
299
  SUPABASE_ANON_KEY=
300
300
  SUPABASE_SERVICE_ROLE_KEY=
301
- `);return}}import Oe from"fs";import Ne from"path";function Qs(e,t){let n=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
301
+ `);return}}import Ue from"fs";import Le from"path";function ai(e,t){let n=`// apps/web/src/app/api/auth/callback/${e.id}/route.ts
302
302
  // Generated by create-sailor \u2014 OAuth callback for ${e.name}
303
303
  // Primary auth provider: ${t}
304
304
  // Docs: ${e.docs}`,o={wechat:` const tokenRes = await fetch(
@@ -423,7 +423,7 @@ ${o[e.id]}
423
423
  void state;
424
424
  return NextResponse.redirect(new URL("/dashboard", req.url));
425
425
  }
426
- `}function Zs(e){return`"use client";
426
+ `}function ci(e){return`"use client";
427
427
 
428
428
  /**
429
429
  * SocialLoginButtons \u2014 generated by create-sailor.
@@ -466,23 +466,23 @@ export function SocialLoginButtons() {
466
466
  </div>
467
467
  );
468
468
  }
469
- `}function lo(e){Oe.mkdirSync(e,{recursive:!0})}function ei(e,t){let n=Ne.join(e,".env.example");Oe.existsSync(n)?Oe.appendFileSync(n,`
470
- `+t):Oe.writeFileSync(n,t)}function ti(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,n=e.envVars.map(o=>`${o}=`).join(`
469
+ `}function So(e){Ue.mkdirSync(e,{recursive:!0})}function pi(e,t){let n=Le.join(e,".env.example");Ue.existsSync(n)?Ue.appendFileSync(n,`
470
+ `+t):Ue.writeFileSync(n,t)}function li(e){let t=`# ${e.name} (${e.id}) \u2014 ${e.docs}`,n=e.envVars.map(o=>`${o}=`).join(`
471
471
  `);return`${t}
472
472
  ${n}
473
- `}async function uo(e,t,n){if(!t||t.length===0)return;let o=Ne.join(e,"apps","web");if(!Oe.existsSync(o))return;let r=new Set,s=[];for(let p of t){if(r.has(p))continue;r.add(p);let d=Hn(p);d&&s.push(d)}if(s.length===0)return;for(let p of s)ei(e,ti(p));let i=Ne.join(o,"src","app","api","auth","callback");for(let p of s){let d=Ne.join(i,p.id);lo(d);let u=Ne.join(d,"route.ts");Oe.writeFileSync(u,Qs(p,n))}let a=Ne.join(o,"src","components","auth");lo(a);let c=Ne.join(a,"SocialLoginButtons.tsx");Oe.writeFileSync(c,Zs(s))}import ot from"fs";import go from"path";var Tt=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function mo(e){return Tt.find(t=>t.id===e)}var hl=Tt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import oe from"fs";import kt from"path";function re(e,t){let n=kt.join(e,".env.example");if(!oe.existsSync(n)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(oe.readFileSync(n,"utf-8").includes(r))return;let a=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(c=>`${c}=""`),""].filter(c=>c!==null).join(`
474
- `);oe.appendFileSync(n,a)}function se(e,t,n){let o=kt.join(e,".env.example");if(!oe.existsSync(o))return;let r=oe.readFileSync(o,"utf-8"),s=`${t}="${n}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){oe.writeFileSync(o,r.replace(i,s));return}let a=r.endsWith(`
473
+ `}async function ho(e,t,n){if(!t||t.length===0)return;let o=Le.join(e,"apps","web");if(!Ue.existsSync(o))return;let r=new Set,s=[];for(let p of t){if(r.has(p))continue;r.add(p);let m=Zn(p);m&&s.push(m)}if(s.length===0)return;for(let p of s)pi(e,li(p));let i=Le.join(o,"src","app","api","auth","callback");for(let p of s){let m=Le.join(i,p.id);So(m);let d=Le.join(m,"route.ts");Ue.writeFileSync(d,ai(p,n))}let a=Le.join(o,"src","components","auth");So(a);let c=Le.join(a,"SocialLoginButtons.tsx");Ue.writeFileSync(c,ci(s))}import rt from"fs";import vo from"path";var Ot=[{id:"upstash-redis",name:"Upstash Redis",region:"both",envVars:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],docs:"https://upstash.com/docs/redis",description:"Serverless Redis"},{id:"vercel-kv",name:"Vercel KV",region:"global",envVars:["KV_URL","KV_REST_API_URL","KV_REST_API_TOKEN","KV_REST_API_READ_ONLY_TOKEN"],docs:"https://vercel.com/docs/storage/vercel-kv",description:"Vercel native KV"},{id:"redis",name:"Redis (self-hosted)",region:"both",envVars:["REDIS_URL"],docs:"https://redis.io/docs/",description:"Self-hosted Redis"},{id:"dragonfly",name:"Dragonfly",region:"global",envVars:["DRAGONFLY_URL"],docs:"https://www.dragonflydb.io/docs",description:"Drop-in Redis replacement, faster"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip cache package"}];function Eo(e){return Ot.find(t=>t.id===e)}var Ll=Ot.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});import ie from"fs";import Lt from"path";function ae(e,t){let n=Lt.join(e,".env.example");if(!ie.existsSync(n)||t.envVars.length===0)return;let r=`# ${t.category??t.name}: ${t.name}`;if(ie.readFileSync(n,"utf-8").includes(r))return;let a=["","# =============================================",r,t.docs?`# Docs: ${t.docs}`:null,"# =============================================",...t.envVars.map(c=>`${c}=""`),""].filter(c=>c!==null).join(`
474
+ `);ie.appendFileSync(n,a)}function ce(e,t,n){let o=Lt.join(e,".env.example");if(!ie.existsSync(o))return;let r=ie.readFileSync(o,"utf-8"),s=`${t}="${n}"`,i=new RegExp(`^${t}=.*$`,"m");if(i.test(r)){ie.writeFileSync(o,r.replace(i,s));return}let a=r.endsWith(`
475
475
  `)?"":`
476
- `;oe.appendFileSync(o,`${a}${s}
477
- `)}var ni=["design","iam","commerce","integrations","platform","ops","ai"];function Le(e,t){for(let o of ni){let r=kt.join(e,"packages",o,t);if(oe.existsSync(r))return r}let n=kt.join(e,"packages",t);return oe.existsSync(n)?n:null}function J(e,t){let n=Le(e,t);n&&oe.rmSync(n,{recursive:!0,force:!0})}function fo(e){return ot.existsSync(e)?ot.readFileSync(e,"utf-8"):null}function oi(e,t){let n=go.join(e,".env.example"),o=fo(n);if(o===null)return;let r=`# Cache: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
478
- `);ot.appendFileSync(n,s)}function ri(e,t,n){let o=go.join(e,".env.example"),r=fo(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ot.writeFileSync(o,r.replace(s,`${t}="${n}"`)):ot.appendFileSync(o,`${t}="${n}"
479
- `)}async function yo(e,t,n){let o=Le(e,"cache");if(t==="none"){o&&ot.rmSync(o,{recursive:!0,force:!0});return}let r=mo(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Tt.map(s=>s.id).join(", ")}`);o&&(oi(e,r),ri(e,"CACHE_PROVIDER",t))}var Nt=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function So(e){return Nt.find(t=>t.id===e)}var xl=Nt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function ho(e,t,n="global"){let o=So(t);if(!o)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${Nt.map(r=>r.id).join(", ")}`);if(o.id==="none"){J(e,"captcha");return}o.envVars.length>0&&re(e,{category:"Captcha",name:o.name,envVars:o.envVars,docs:o.docs}),se(e,"CAPTCHA_PROVIDER",o.id)}import Lt from"fs";import si from"path";var Ot=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Eo(e){return Ot.find(t=>t.id===e)}var Ol=Ot.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function vo(e,t,n="global"){let o=Eo(t);if(!o)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Ot.map(s=>s.id).join(", ")}`);let r=si.join(e,"apps","studio");if(o.id==="none"){J(e,"sanity"),Lt.existsSync(r)&&Lt.rmSync(r,{recursive:!0,force:!0});return}o.id!=="sanity"&&(J(e,"sanity"),Lt.existsSync(r)&&Lt.rmSync(r,{recursive:!0,force:!0})),o.envVars.length>0&&re(e,{category:"CMS",name:o.name,envVars:o.envVars,docs:o.docs}),se(e,"CMS_PROVIDER",o.id)}import U from"fs";import N from"path";var ii=N.join("apps","web"),mn=N.join("src","components","compliance"),St=N.join("src","app","[locale]");function ie(e){return N.join(e,ii)}function ai(e){U.mkdirSync(e,{recursive:!0})}function Q(e,t){ai(N.dirname(e)),U.writeFileSync(e,t,"utf8")}function gn(e,t){let n=N.join(e,".env.example");if(U.existsSync(n)){if(U.readFileSync(n,"utf8").includes(t.split(`
480
- `)[0]??""))return;U.appendFileSync(n,`
476
+ `;ie.appendFileSync(o,`${a}${s}
477
+ `)}var di=["design","iam","commerce","integrations","platform","ops","ai"];function De(e,t){for(let o of di){let r=Lt.join(e,"packages",o,t);if(ie.existsSync(r))return r}let n=Lt.join(e,"packages",t);return ie.existsSync(n)?n:null}function Z(e,t){let n=De(e,t);n&&ie.rmSync(n,{recursive:!0,force:!0})}function bo(e){return rt.existsSync(e)?rt.readFileSync(e,"utf-8"):null}function ui(e,t){let n=vo.join(e,".env.example"),o=bo(n);if(o===null)return;let r=`# Cache: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
478
+ `);rt.appendFileSync(n,s)}function mi(e,t,n){let o=vo.join(e,".env.example"),r=bo(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?rt.writeFileSync(o,r.replace(s,`${t}="${n}"`)):rt.appendFileSync(o,`${t}="${n}"
479
+ `)}async function _o(e,t,n){let o=De(e,"cache");if(t==="none"){o&&rt.rmSync(o,{recursive:!0,force:!0});return}let r=Eo(t);if(!r)throw new Error(`Unknown cache provider "${t}". Valid ids: ${Ot.map(s=>s.id).join(", ")}`);o&&(ui(e,r),mi(e,"CACHE_PROVIDER",t))}var Ut=[{id:"turnstile",name:"Cloudflare Turnstile",region:"global",envVars:["NEXT_PUBLIC_TURNSTILE_SITE_KEY","TURNSTILE_SECRET_KEY"],docs:"https://developers.cloudflare.com/turnstile/",description:"Free, privacy-focused captcha alternative"},{id:"hcaptcha",name:"hCaptcha",region:"global",envVars:["NEXT_PUBLIC_HCAPTCHA_SITE_KEY","HCAPTCHA_SECRET_KEY"],docs:"https://docs.hcaptcha.com/",description:"Privacy-respecting captcha"},{id:"aliyun-slide",name:"\u963F\u91CC\u4E91\u9A8C\u8BC1\u7801 2.0",region:"cn",envVars:["ALIYUN_CAPTCHA_ACCESS_KEY_ID","ALIYUN_CAPTCHA_ACCESS_KEY_SECRET","ALIYUN_CAPTCHA_APP_KEY","NEXT_PUBLIC_ALIYUN_CAPTCHA_APP_KEY"],docs:"https://help.aliyun.com/product/28308.html",description:"\u963F\u91CC\u4E91\u667A\u80FD\u9A8C\u8BC1 (\u6ED1\u5757/\u65E0\u75D5)"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function wo(e){return Ut.find(t=>t.id===e)}var Yl=Ut.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Po(e,t,n="global"){let o=wo(t);if(!o)throw new Error(`Unknown captcha provider "${t}". Valid ids: ${Ut.map(r=>r.id).join(", ")}`);if(o.id==="none"){Z(e,"captcha");return}o.envVars.length>0&&ae(e,{category:"Captcha",name:o.name,envVars:o.envVars,docs:o.docs}),ce(e,"CAPTCHA_PROVIDER",o.id)}import Mt from"fs";import gi from"path";var Dt=[{id:"sanity",name:"Sanity",region:"global",envVars:["SANITY_PROJECT_ID","SANITY_DATASET","SANITY_API_TOKEN","SANITY_API_VERSION"],docs:"https://www.sanity.io/docs",description:"Structured content platform with Studio"},{id:"contentful",name:"Contentful",region:"global",envVars:["CONTENTFUL_SPACE_ID","CONTENTFUL_ACCESS_TOKEN","CONTENTFUL_PREVIEW_ACCESS_TOKEN"],docs:"https://www.contentful.com/developers/docs/",description:"Headless CMS"},{id:"strapi",name:"Strapi",region:"both",envVars:["STRAPI_URL","STRAPI_API_TOKEN"],docs:"https://docs.strapi.io",description:"Open-source self-hosted CMS"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Ao(e){return Dt.find(t=>t.id===e)}var Xl=Dt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Co(e,t,n="global"){let o=Ao(t);if(!o)throw new Error(`Unknown CMS provider "${t}". Valid ids: ${Dt.map(s=>s.id).join(", ")}`);let r=gi.join(e,"apps","studio");if(o.id==="none"){Z(e,"sanity"),Mt.existsSync(r)&&Mt.rmSync(r,{recursive:!0,force:!0});return}o.id!=="sanity"&&(Z(e,"sanity"),Mt.existsSync(r)&&Mt.rmSync(r,{recursive:!0,force:!0})),o.envVars.length>0&&ae(e,{category:"CMS",name:o.name,envVars:o.envVars,docs:o.docs}),ce(e,"CMS_PROVIDER",o.id)}import M from"fs";import O from"path";var fi=O.join("apps","web"),fn=O.join("src","components","compliance"),Et=O.join("src","app","[locale]");function pe(e){return O.join(e,fi)}function yi(e){M.mkdirSync(e,{recursive:!0})}function ee(e,t){yi(O.dirname(e)),M.writeFileSync(e,t,"utf8")}function yn(e,t){let n=O.join(e,".env.example");if(M.existsSync(n)){if(M.readFileSync(n,"utf8").includes(t.split(`
480
+ `)[0]??""))return;M.appendFileSync(n,`
481
481
  `+t+`
482
- `)}else U.writeFileSync(n,t+`
483
- `)}var ht=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
482
+ `)}else M.writeFileSync(n,t+`
483
+ `)}var vt=`> **TEMPLATE \u2014 NOT LEGAL ADVICE.** This document is a boilerplate scaffold only.
484
484
  > Consult a qualified lawyer in every jurisdiction you operate in before publishing.
485
- > \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,ci=`import Link from "next/link";
485
+ > \u672C\u6587\u6863\u4E3A\u6A21\u677F\u811A\u624B\u67B6\uFF0C\u4E0D\u6784\u6210\u6CD5\u5F8B\u610F\u89C1\u3002\u53D1\u5E03\u524D\u8BF7\u54A8\u8BE2\u76F8\u5173\u53F8\u6CD5\u8F96\u533A\u7684\u5408\u683C\u5F8B\u5E08\u3002`,Si=`import Link from "next/link";
486
486
  import { IcpFooter } from "@/components/compliance/IcpFooter";
487
487
  import { PublicSecurityFooter } from "@/components/compliance/PublicSecurityFooter";
488
488
 
@@ -533,7 +533,7 @@ export function Footer({ region = "global" }: FooterProps) {
533
533
  </footer>
534
534
  );
535
535
  }
536
- `,pi=`export function IcpFooter() {
536
+ `,hi=`export function IcpFooter() {
537
537
  const icp = process.env.NEXT_PUBLIC_ICP_BEIAN;
538
538
  if (!icp) return null;
539
539
  return (
@@ -547,7 +547,7 @@ export function Footer({ region = "global" }: FooterProps) {
547
547
  </a>
548
548
  );
549
549
  }
550
- `,li=`export function PublicSecurityFooter() {
550
+ `,Ei=`export function PublicSecurityFooter() {
551
551
  const psb = process.env.NEXT_PUBLIC_PSB_BEIAN;
552
552
  const psbCode = process.env.NEXT_PUBLIC_PSB_CODE;
553
553
  if (!psb) return null;
@@ -564,7 +564,7 @@ export function Footer({ region = "global" }: FooterProps) {
564
564
  </a>
565
565
  );
566
566
  }
567
- `,di=`"use client";
567
+ `,vi=`"use client";
568
568
 
569
569
  import { useEffect, useState } from "react";
570
570
 
@@ -718,7 +718,7 @@ export function CookieBanner() {
718
718
  </div>
719
719
  );
720
720
  }
721
- `,ui=`interface AigcDisclaimerProps {
721
+ `,bi=`interface AigcDisclaimerProps {
722
722
  className?: string;
723
723
  }
724
724
 
@@ -738,13 +738,13 @@ export function AigcDisclaimer({ className }: AigcDisclaimerProps) {
738
738
  </div>
739
739
  );
740
740
  }
741
- `,mi=`---
741
+ `,_i=`---
742
742
  title: Privacy Policy / \u9690\u79C1\u653F\u7B56
743
743
  description: How {{COMPANY_NAME}} collects, uses, shares, and protects personal information.
744
744
  lastUpdated: 2026-01-01
745
745
  ---
746
746
 
747
- ${ht}
747
+ ${vt}
748
748
 
749
749
  # Privacy Policy / \u9690\u79C1\u653F\u7B56
750
750
 
@@ -883,13 +883,13 @@ or in-app notification before the change takes effect.
883
883
  **Data Controller / \u6570\u636E\u63A7\u5236\u8005:** {{COMPANY_NAME}}
884
884
  **Address / \u5730\u5740:** {{COMPANY_ADDRESS}}
885
885
  **Email / \u90AE\u7BB1:** {{COMPANY_CONTACT_EMAIL}}
886
- `,gi=`---
886
+ `,wi=`---
887
887
  title: Terms of Service / \u670D\u52A1\u6761\u6B3E
888
888
  description: Terms governing your use of {{COMPANY_NAME}}.
889
889
  lastUpdated: 2026-01-01
890
890
  ---
891
891
 
892
- ${ht}
892
+ ${vt}
893
893
 
894
894
  # Terms of Service / \u670D\u52A1\u6761\u6B3E
895
895
 
@@ -1002,13 +1002,13 @@ conflict-of-laws principles. Disputes shall be resolved in the competent courts
1002
1002
  ## 11. Contact / \u8054\u7CFB\u65B9\u5F0F
1003
1003
 
1004
1004
  {{COMPANY_NAME}} \xB7 {{COMPANY_ADDRESS}} \xB7 {{COMPANY_CONTACT_EMAIL}}
1005
- `,fi=`---
1005
+ `,Pi=`---
1006
1006
  title: AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1007
1007
  description: Disclosure required by \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300B
1008
1008
  lastUpdated: 2026-01-01
1009
1009
  ---
1010
1010
 
1011
- ${ht}
1011
+ ${vt}
1012
1012
 
1013
1013
  # AIGC Disclosure / \u751F\u6210\u5F0F AI \u670D\u52A1\u8BF4\u660E
1014
1014
 
@@ -1084,13 +1084,13 @@ human professional.
1084
1084
 
1085
1085
  AI \u8F93\u51FA\u53EF\u80FD\u4E0D\u51C6\u786E\u3001\u5B58\u5728\u504F\u89C1\u6216\u8FC7\u65F6\u3002**\u8BF7\u52FF**\u5728\u672A\u7ECF\u5408\u683C\u4E13\u4E1A\u4EBA\u58EB\u72EC\u7ACB\u6838\u5B9E\u7684\u60C5\u51B5\u4E0B\uFF0C\u5C06 AI \u8F93\u51FA
1086
1086
  \u7528\u4E8E\u533B\u7597\u3001\u6CD5\u5F8B\u3001\u91D1\u878D\u6216\u5B89\u5168\u6538\u5173\u7684\u51B3\u7B56\u3002
1087
- `,yi=`---
1087
+ `,Ai=`---
1088
1088
  title: Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1089
1089
  description: Notice of cross-border transfer of personal information, per PIPL.
1090
1090
  lastUpdated: 2026-01-01
1091
1091
  ---
1092
1092
 
1093
- ${ht}
1093
+ ${vt}
1094
1094
 
1095
1095
  # Cross-Border Data Notice / \u6570\u636E\u51FA\u5883\u544A\u77E5
1096
1096
 
@@ -1149,13 +1149,13 @@ Refusal may limit your ability to use features that rely on overseas services.
1149
1149
  - \u4F20\u8F93\u4E2D\u52A0\u5BC6 (TLS 1.2+) \u53CA\u9759\u6001\u52A0\u5BC6 (AES-256)\u3002
1150
1150
  - \u5408\u540C\u6761\u6B3E\u8981\u6C42\u5883\u5916\u63A5\u6536\u65B9\u63D0\u4F9B\u7B49\u540C\u4E8E PIPL \u7684\u4FDD\u62A4\u3002
1151
1151
  - \u8BBF\u95EE\u63A7\u5236\u3001\u5BA1\u8BA1\u65E5\u5FD7\u548C\u8FDD\u89C4\u901A\u77E5\u7A0B\u5E8F\u3002
1152
- `,Si=`---
1152
+ `,Ci=`---
1153
1153
  title: Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1154
1154
  description: Itemized list of personal information collected, per PIPL Article 17.
1155
1155
  lastUpdated: 2026-01-01
1156
1156
  ---
1157
1157
 
1158
- ${ht}
1158
+ ${vt}
1159
1159
 
1160
1160
  # Personal Information Collection List / \u4E2A\u4EBA\u4FE1\u606F\u6536\u96C6\u6E05\u5355
1161
1161
 
@@ -1191,26 +1191,26 @@ To exercise your rights (access, rectify, delete, export, withdraw consent), con
1191
1191
  **{{COMPANY_CONTACT_EMAIL}}**.
1192
1192
 
1193
1193
  \u5982\u9700\u884C\u4F7F\u60A8\u7684\u6743\u5229\uFF08\u8BBF\u95EE\u3001\u66F4\u6B63\u3001\u5220\u9664\u3001\u5BFC\u51FA\u3001\u64A4\u56DE\u540C\u610F\uFF09\uFF0C\u8BF7\u8054\u7CFB **{{COMPANY_CONTACT_EMAIL}}**\u3002
1194
- `;async function hi(e,t){let n=ie(e);if(!U.existsSync(n))return;let o=N.join(n,"src","components","compliance","Footer.tsx");Q(o,ci);let r=N.join(n,"src","components","compliance","README.md");Q(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
1195
- `))}async function Ei(e,t){let n=ie(e);if(!U.existsSync(n))return;let o=N.join(n,"src","components","compliance","CookieBanner.tsx");Q(o,di)}async function vi(e,t){let n=ie(e);if(!U.existsSync(n))return;let o=N.join(n,St,"privacy","page.mdx");Q(o,mi)}async function bi(e,t){let n=ie(e);if(!U.existsSync(n))return;let o=N.join(n,St,"terms","page.mdx");Q(o,gi)}async function _i(e){let t=ie(e);if(!U.existsSync(t))return;let n=N.join(t,mn,"IcpFooter.tsx");Q(n,pi),gn(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
1196
- `))}async function wi(e){let t=ie(e);if(!U.existsSync(t))return;let n=N.join(t,mn,"PublicSecurityFooter.tsx");Q(n,li),gn(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
1197
- `))}async function Pi(e){let t=ie(e);if(!U.existsSync(t))return;let n=N.join(t,mn,"AigcDisclaimer.tsx");Q(n,ui),gn(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
1198
- `))}async function Ai(e){let t=ie(e);if(!U.existsSync(t))return;let n=N.join(t,St,"aigc-disclosure","page.mdx");Q(n,fi)}async function Ci(e){let t=ie(e);if(!U.existsSync(t))return;let n=N.join(t,St,"cross-border-data","page.mdx");Q(n,yi)}async function Ii(e){let t=ie(e);if(!U.existsSync(t))return;let n=N.join(t,St,"pii-collection","page.mdx");Q(n,Si)}async function bo(e,t){try{await hi(e,t),await Ei(e,t),await vi(e,t),await bi(e,t),(t==="cn"||t==="hybrid")&&(await _i(e),await wi(e),await Pi(e),await Ai(e),await Ci(e),await Ii(e))}catch(n){throw console.error("applyComplianceTemplates failed:",n),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import xi from"fs";import Ri from"path";async function _o(e,t){let n=Ri.join(e,"nebutra.config.json");xi.writeFileSync(n,JSON.stringify(t,null,2)+`
1199
- `)}import x from"fs";import Ue from"path";function Ti(e){x.existsSync(e)&&x.rmSync(e,{recursive:!0,force:!0})}function wo(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function ki(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Po(e){let t=e.replace(/^\s*extensions\s*=\s*\[[^\]]*\]\s*\n/gm,"");return t=t.replace(/previewFeatures\s*=\s*\[\s*"postgresqlExtensions"\s*\]\s*\n/g,""),t}function Ni(e,t){let n=Ue.join(e,".env.example");x.existsSync(n)?x.appendFileSync(n,`
1200
- `+t):x.writeFileSync(n,t)}async function Ao(e,t,n){let o=Ue.join(e,"packages","platform","db");if(t==="none"){Ti(o);return}let r=Ue.join(o,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${n}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${n}`:s="file:./dev.db",Ni(e,`# Database (${t})
1194
+ `;async function Ii(e,t){let n=pe(e);if(!M.existsSync(n))return;let o=O.join(n,"src","components","compliance","Footer.tsx");ee(o,Si);let r=O.join(n,"src","components","compliance","README.md");ee(r,["# Compliance Components","",`Auto-generated by \`create-sailor\` for region: \`${t}\`.`,"","## Mounting the Footer","","```tsx",'import { Footer } from "@/components/compliance/Footer";','import { CookieBanner } from "@/components/compliance/CookieBanner";',"","export default function RootLayout({ children }) {"," return ("," <html>"," <body>"," {children}",` <Footer region="${t}" />`," <CookieBanner />"," </body>"," </html>"," );","}","```","","## Placeholders","","Policy MDX files contain `{{COMPANY_NAME}}`, `{{COMPANY_ADDRESS}}`,","`{{COMPANY_CONTACT_EMAIL}}`, `{{GOVERNING_JURISDICTION}}`, and","`{{AIGC_ALGORITHM_FILING_NUMBER}}`. These are filled by the `brand-apply` step.",""].join(`
1195
+ `))}async function Ti(e,t){let n=pe(e);if(!M.existsSync(n))return;let o=O.join(n,"src","components","compliance","CookieBanner.tsx");ee(o,vi)}async function xi(e,t){let n=pe(e);if(!M.existsSync(n))return;let o=O.join(n,Et,"privacy","page.mdx");ee(o,_i)}async function Ri(e,t){let n=pe(e);if(!M.existsSync(n))return;let o=O.join(n,Et,"terms","page.mdx");ee(o,wi)}async function ki(e){let t=pe(e);if(!M.existsSync(t))return;let n=O.join(t,fn,"IcpFooter.tsx");ee(n,hi),yn(e,["# Chinese ICP filing (\u5DE5\u4FE1\u90E8 ICP \u5907\u6848) \u2014 required to legally host a","# public-facing site from mainland China. Apply at https://beian.miit.gov.cn/",'NEXT_PUBLIC_ICP_BEIAN="" # \u5982 \u82CFICP\u59072024XXXXXX\u53F7'].join(`
1196
+ `))}async function Ni(e){let t=pe(e);if(!M.existsSync(t))return;let n=O.join(t,fn,"PublicSecurityFooter.tsx");ee(n,Ei),yn(e,["# Chinese Public Security Bureau filing (\u516C\u5B89\u8054\u7F51\u5907\u6848)","# Required in addition to ICP. Apply at http://www.beian.gov.cn/",'NEXT_PUBLIC_PSB_BEIAN="" # \u5982 \u82CF\u516C\u7F51\u5B89\u5907 32011402XXXXXX\u53F7','NEXT_PUBLIC_PSB_CODE="" # 14-digit record code'].join(`
1197
+ `))}async function Oi(e){let t=pe(e);if(!M.existsSync(t))return;let n=O.join(t,fn,"AigcDisclaimer.tsx");ee(n,bi),yn(e,["# Generative AI algorithm filing (\u7B97\u6CD5\u5907\u6848\u53F7) \u2014 required by","# \u7F51\u4FE1\u529E\u300A\u751F\u6210\u5F0F\u4EBA\u5DE5\u667A\u80FD\u670D\u52A1\u7BA1\u7406\u6682\u884C\u529E\u6CD5\u300Bfor services offered in China.",'NEXT_PUBLIC_AIGC_FILING_NUMBER="" # e.g. \u7F51\u4FE1\u7B97\u5907XXXXXXXX\u53F7'].join(`
1198
+ `))}async function Li(e){let t=pe(e);if(!M.existsSync(t))return;let n=O.join(t,Et,"aigc-disclosure","page.mdx");ee(n,Pi)}async function Ui(e){let t=pe(e);if(!M.existsSync(t))return;let n=O.join(t,Et,"cross-border-data","page.mdx");ee(n,Ai)}async function Di(e){let t=pe(e);if(!M.existsSync(t))return;let n=O.join(t,Et,"pii-collection","page.mdx");ee(n,Ci)}async function Io(e,t){try{await Ii(e,t),await Ti(e,t),await xi(e,t),await Ri(e,t),(t==="cn"||t==="hybrid")&&(await ki(e),await Ni(e),await Oi(e),await Li(e),await Ui(e),await Di(e))}catch(n){throw console.error("applyComplianceTemplates failed:",n),new Error(`Failed to apply compliance templates for region "${t}". Check that ${e} is writable.`)}}import Mi from"fs";import Fi from"path";async function To(e,t){let n=Fi.join(e,"nebutra.config.json");Mi.writeFileSync(n,JSON.stringify(t,null,2)+`
1199
+ `)}import T from"fs";import Me from"path";function ji(e){T.existsSync(e)&&T.rmSync(e,{recursive:!0,force:!0})}function xo(e,t){return e.replace(/provider\s*=\s*"postgresql"/,`provider = "${t}"`)}function Bi(e){return e.replace(/^\s*directUrl\s*=\s*env\([^)]*\)\s*\n/gm,"")}function Ro(e){let t=e.replace(/^\s*extensions\s*=\s*\[[^\]]*\]\s*\n/gm,"");return t=t.replace(/previewFeatures\s*=\s*\[\s*"postgresqlExtensions"\s*\]\s*\n/g,""),t}function $i(e,t){let n=Me.join(e,".env.example");T.existsSync(n)?T.appendFileSync(n,`
1200
+ `+t):T.writeFileSync(n,t)}async function ko(e,t,n){let o=Me.join(e,"packages","platform","db");if(t==="none"){ji(o);return}let r=Me.join(o,"prisma","schema.prisma"),s;if(t==="postgresql"?s=`postgresql://postgres:postgres@localhost:5432/${n}`:t==="mysql"?s=`mysql://root:root@localhost:3306/${n}`:s="file:./dev.db",$i(e,`# Database (${t})
1201
1201
  DATABASE_URL="${s}"
1202
- `),!x.existsSync(r))return;let i=x.readFileSync(r,"utf8"),a=i;t==="mysql"?(a=wo(a,"mysql"),a=Po(a)):t==="sqlite"&&(a=wo(a,"sqlite"),a=ki(a),a=Po(a)),a!==i&&x.writeFileSync(r,a)}function Oi(e){let t=Ue.join(e,".env.example");return x.existsSync(t)?x.readFileSync(t,"utf8"):""}function Li(e,t,n,o){let r=Ue.join(e,".env.example"),s=Oi(e),i=o?`# ${o}
1202
+ `),!T.existsSync(r))return;let i=T.readFileSync(r,"utf8"),a=i;t==="mysql"?(a=xo(a,"mysql"),a=Ro(a)):t==="sqlite"&&(a=xo(a,"sqlite"),a=Bi(a),a=Ro(a)),a!==i&&T.writeFileSync(r,a)}function Vi(e){let t=Me.join(e,".env.example");return T.existsSync(t)?T.readFileSync(t,"utf8"):""}function Ki(e,t,n,o){let r=Me.join(e,".env.example"),s=Vi(e),i=o?`# ${o}
1203
1203
  ${t}="${n}"
1204
1204
  `:`${t}="${n}"
1205
- `,a=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(a.test(s)){x.writeFileSync(r,s.replace(a,`${t}="${n}"`));return}s?x.appendFileSync(r,`
1206
- ${i}`):x.writeFileSync(r,i)}function Ui(e,t){let n=Ue.join(e,"packages","platform","db","prisma","schema.prisma");if(!x.existsSync(n))return;let o=x.readFileSync(n,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!o.match(r))return;let i=t.filter(p=>!o.includes(p.trim()));if(i.length===0)return;let a=i.map(p=>` ${p}`).join(`
1205
+ `,a=new RegExp(`^\\s*${t}\\s*=.*$`,"m");if(a.test(s)){T.writeFileSync(r,s.replace(a,`${t}="${n}"`));return}s?T.appendFileSync(r,`
1206
+ ${i}`):T.writeFileSync(r,i)}function Yi(e,t){let n=Me.join(e,"packages","platform","db","prisma","schema.prisma");if(!T.existsSync(n))return;let o=T.readFileSync(n,"utf8"),r=/(datasource\s+db\s*\{[^}]*?)(\n})/;if(!o.match(r))return;let i=t.filter(p=>!o.includes(p.trim()));if(i.length===0)return;let a=i.map(p=>` ${p}`).join(`
1207
1207
  `),c=o.replace(r,`$1
1208
- ${a}$2`);x.writeFileSync(n,c)}function Di(e){let t=Ue.join(e,"packages","platform","db","prisma","schema.prisma");if(!x.existsSync(t))return;let n=x.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(n))return;let o=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;o.test(n)&&x.writeFileSync(t,n.replace(o,`$1 directUrl = env("DIRECT_URL")
1209
- `))}async function Co(e,t,n){if(!(t.id==="none"||t.id==="local")){for(let o of t.envVars){let r=o.placeholder.replace(/\$PROJECT/g,n);Li(e,o.name,r,o.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Ui(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Di(e)}}import we from"fs";import De from"path";import{fileURLToPath as Mi}from"url";var Fi=Mi(import.meta.url),Io=De.dirname(Fi),ji=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,xo=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function Bi(e){let t=[De.join(Io,"..","templates","docs",e),De.join(Io,"..","..","templates","docs",e)];for(let n of t)if(we.existsSync(n))return n;return t[0]}async function Ro(e,t){if(t.framework==="none")return;if(!xo.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${xo.join(", ")}, none.`);let n=Bi(t.framework),o=De.join(e,"apps","docs");if(!we.existsSync(n))throw new Error(`Docs template not found: ${n}`);To(n,o),ko(o,{"{PRODUCT_NAME}":t.projectName})}function To(e,t){we.mkdirSync(t,{recursive:!0});for(let n of we.readdirSync(e,{withFileTypes:!0})){let o=De.join(e,n.name),r=De.join(t,n.name);n.isDirectory()?To(o,r):we.copyFileSync(o,r)}}function ko(e,t){for(let n of we.readdirSync(e,{withFileTypes:!0})){let o=De.join(e,n.name);if(n.isDirectory())ko(o,t);else if(ji.test(n.name)){let r=we.readFileSync(o,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);we.writeFileSync(o,r)}}}import Fe from"fs";import Me from"path";var rt=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function No(e){return rt.find(t=>t.id===e)}var ed=rt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var je="@nebutra/email";function fn(e,t){Fe.mkdirSync(Me.dirname(e),{recursive:!0}),Fe.writeFileSync(e,t)}function $i(e,t){let n=Me.join(e,".env.example");Fe.existsSync(n)?Fe.appendFileSync(n,`
1210
- `+t):Fe.writeFileSync(n,t)}function Vi(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
1208
+ ${a}$2`);T.writeFileSync(n,c)}function Gi(e){let t=Me.join(e,"packages","platform","db","prisma","schema.prisma");if(!T.existsSync(t))return;let n=T.readFileSync(t,"utf8");if(/directUrl\s*=\s*env\(/.test(n))return;let o=/(datasource\s+db\s*\{[\s\S]*?url\s*=\s*env\(\s*"DATABASE_URL"\s*\)[^\n]*\n)/;o.test(n)&&T.writeFileSync(t,n.replace(o,`$1 directUrl = env("DIRECT_URL")
1209
+ `))}async function No(e,t,n){if(!(t.id==="none"||t.id==="local")){for(let o of t.envVars){let r=o.placeholder.replace(/\$PROJECT/g,n);Ki(e,o.name,r,o.comment)}t.prismaDatasourceExtras&&t.prismaDatasourceExtras.length>0&&Yi(e,t.prismaDatasourceExtras),t.keepDirectUrl&&Gi(e)}}import Ae from"fs";import Fe from"path";import{fileURLToPath as qi}from"url";var Hi=qi(import.meta.url),Oo=Fe.dirname(Hi),Wi=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|vue)$/,Lo=["fumadocs","nextra","mintlify","docusaurus","vitepress"];function Xi(e){let t=[Fe.join(Oo,"..","templates","docs",e),Fe.join(Oo,"..","..","templates","docs",e)];for(let n of t)if(Ae.existsSync(n))return n;return t[0]}async function Uo(e,t){if(t.framework==="none")return;if(!Lo.includes(t.framework))throw new Error(`Unsupported docs framework: "${t.framework}". Supported: ${Lo.join(", ")}, none.`);let n=Xi(t.framework),o=Fe.join(e,"apps","docs");if(!Ae.existsSync(n))throw new Error(`Docs template not found: ${n}`);Do(n,o),Mo(o,{"{PRODUCT_NAME}":t.projectName})}function Do(e,t){Ae.mkdirSync(t,{recursive:!0});for(let n of Ae.readdirSync(e,{withFileTypes:!0})){let o=Fe.join(e,n.name),r=Fe.join(t,n.name);n.isDirectory()?Do(o,r):Ae.copyFileSync(o,r)}}function Mo(e,t){for(let n of Ae.readdirSync(e,{withFileTypes:!0})){let o=Fe.join(e,n.name);if(n.isDirectory())Mo(o,t);else if(Wi.test(n.name)){let r=Ae.readFileSync(o,"utf-8");for(let[s,i]of Object.entries(t))r=r.split(s).join(i);Ae.writeFileSync(o,r)}}}import Be from"fs";import je from"path";var st=[{id:"resend",name:"Resend",region:"global",envVars:["RESEND_API_KEY","RESEND_FROM"],docs:"https://resend.com/docs",pkg:"resend",pkgVersion:"^4.0.1"},{id:"postmark",name:"Postmark",region:"global",envVars:["POSTMARK_API_KEY","POSTMARK_FROM"],docs:"https://postmarkapp.com/developer",pkg:"postmark",pkgVersion:"^4.0.5"},{id:"ses",name:"AWS SES",region:"global",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SES_REGION","SES_FROM"],docs:"https://docs.aws.amazon.com/ses",pkg:"@aws-sdk/client-sesv2",pkgVersion:"^3.658.0"},{id:"aliyun-dm",name:"\u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001",region:"cn",envVars:["ALIYUN_DM_ACCESS_KEY","ALIYUN_DM_ACCESS_SECRET","ALIYUN_DM_ACCOUNT_NAME","ALIYUN_DM_FROM_ALIAS"],docs:"https://help.aliyun.com/product/29412.html",pkg:"@alicloud/dm20151123",pkgVersion:"^3.0.0"},{id:"tencent-ses",name:"\u817E\u8BAF\u4E91 SES",region:"cn",envVars:["TENCENT_SECRET_ID","TENCENT_SECRET_KEY","TENCENT_SES_FROM_EMAIL"],docs:"https://cloud.tencent.com/document/product/1288",pkg:"tencentcloud-sdk-nodejs-ses",pkgVersion:"^4.0.900"},{id:"netease",name:"\u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1",region:"cn",envVars:["NETEASE_USER","NETEASE_PASS","NETEASE_FROM"],docs:"https://qiye.163.com/help",pkg:"nodemailer",pkgVersion:"^6.9.15"},{id:"none",name:"None",region:"global",envVars:[],docs:""}];function Fo(e){return st.find(t=>t.id===e)}var yd=st.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});var $e="@nebutra/email";function Sn(e,t){Be.mkdirSync(je.dirname(e),{recursive:!0}),Be.writeFileSync(e,t)}function zi(e,t){let n=je.join(e,".env.example");Be.existsSync(n)?Be.appendFileSync(n,`
1210
+ `+t):Be.writeFileSync(n,t)}function Ji(e){if(e.envVars.length===0)return"";let t=`# Email provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
1211
1211
  `);return`${t}
1212
1212
  ${n}
1213
- `}var Ki=`/**
1213
+ `}var Qi=`/**
1214
1214
  * Public inputs accepted by the \`sendEmail\` wrapper.
1215
1215
  * Keep the surface minimal \u2014 individual providers may accept more, but
1216
1216
  * consumers should code against this shape for portability.
@@ -1230,8 +1230,8 @@ export interface SendEmailResult {
1230
1230
  /** Raw provider response \u2014 useful for debugging, not a stable contract. */
1231
1231
  raw?: unknown;
1232
1232
  }
1233
- `;function Yi(){return`/**
1234
- * @${je.slice(1)} \u2014 Resend transactional email wrapper.
1233
+ `;function Zi(){return`/**
1234
+ * @${$e.slice(1)} \u2014 Resend transactional email wrapper.
1235
1235
  *
1236
1236
  * Docs: https://resend.com/docs
1237
1237
  */
@@ -1269,8 +1269,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1269
1269
  }
1270
1270
 
1271
1271
  export type { SendEmailInput, SendEmailResult } from "./types";
1272
- `}function qi(){return`/**
1273
- * @${je.slice(1)} \u2014 Postmark transactional email wrapper.
1272
+ `}function ea(){return`/**
1273
+ * @${$e.slice(1)} \u2014 Postmark transactional email wrapper.
1274
1274
  *
1275
1275
  * Docs: https://postmarkapp.com/developer
1276
1276
  */
@@ -1307,8 +1307,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1307
1307
  }
1308
1308
 
1309
1309
  export type { SendEmailInput, SendEmailResult } from "./types";
1310
- `}function Gi(){return`/**
1311
- * @${je.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1310
+ `}function ta(){return`/**
1311
+ * @${$e.slice(1)} \u2014 AWS SES v2 transactional email wrapper.
1312
1312
  *
1313
1313
  * Docs: https://docs.aws.amazon.com/ses
1314
1314
  */
@@ -1363,8 +1363,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1363
1363
  }
1364
1364
 
1365
1365
  export type { SendEmailInput, SendEmailResult } from "./types";
1366
- `}function Hi(){return`/**
1367
- * @${je.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1366
+ `}function na(){return`/**
1367
+ * @${$e.slice(1)} \u2014 \u963F\u91CC\u4E91\u90AE\u4EF6\u63A8\u9001 (Aliyun DirectMail) wrapper.
1368
1368
  *
1369
1369
  * Docs: https://help.aliyun.com/product/29412.html
1370
1370
  */
@@ -1413,8 +1413,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1413
1413
  }
1414
1414
 
1415
1415
  export type { SendEmailInput, SendEmailResult } from "./types";
1416
- `}function Wi(){return`/**
1417
- * @${je.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1416
+ `}function oa(){return`/**
1417
+ * @${$e.slice(1)} \u2014 \u817E\u8BAF\u4E91 SES wrapper.
1418
1418
  *
1419
1419
  * Docs: https://cloud.tencent.com/document/product/1288
1420
1420
  */
@@ -1461,8 +1461,8 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1461
1461
  }
1462
1462
 
1463
1463
  export type { SendEmailInput, SendEmailResult } from "./types";
1464
- `}function Xi(){return`/**
1465
- * @${je.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1464
+ `}function ra(){return`/**
1465
+ * @${$e.slice(1)} \u2014 \u7F51\u6613\u4F01\u4E1A\u90AE\u7BB1 via SMTP (nodemailer).
1466
1466
  *
1467
1467
  * Docs: https://qiye.163.com/help
1468
1468
  */
@@ -1499,32 +1499,44 @@ export async function sendEmail(input: SendEmailInput): Promise<SendEmailResult>
1499
1499
  }
1500
1500
 
1501
1501
  export type { SendEmailInput, SendEmailResult } from "./types";
1502
- `}function zi(e){switch(e){case"resend":return Yi();case"postmark":return qi();case"ses":return Gi();case"aliyun-dm":return Hi();case"tencent-ses":return Wi();case"netease":return Xi();case"none":return`export {};
1503
- `}}function Ji(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let n={name:je,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
1504
- `}async function Oo(e,t,n){if(t==="none")return;let o=No(t);if(!o)throw new Error(`Unknown email provider "${t}". Valid ids: ${rt.map(i=>i.id).join(", ")}`);let r=Me.join(e,"packages","email"),s=Me.join(r,"src");Fe.existsSync(s)&&Fe.rmSync(s,{recursive:!0,force:!0}),fn(Me.join(r,"package.json"),Ji(o)),fn(Me.join(s,"types.ts"),Ki),fn(Me.join(s,"index.ts"),zi(o.id)),$i(e,Vi(o))}import ue from"fs";import Lo from"path";function Qi(e,t){return new RegExp(`^\\s*${t}\\s*=`,"m").test(e)}function Uo(e){return e.endsWith(`
1502
+ `}function sa(e){switch(e){case"resend":return Zi();case"postmark":return ea();case"ses":return ta();case"aliyun-dm":return na();case"tencent-ses":return oa();case"netease":return ra();case"none":return`export {};
1503
+ `}}function ia(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),e.id==="aliyun-dm"&&(t["@alicloud/openapi-client"]="^0.4.12");let n={name:$e,version:"0.1.0",private:!0,description:`Transactional email via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
1504
+ `}async function jo(e,t,n){if(t==="none")return;let o=Fo(t);if(!o)throw new Error(`Unknown email provider "${t}". Valid ids: ${st.map(i=>i.id).join(", ")}`);let r=je.join(e,"packages","email"),s=je.join(r,"src");Be.existsSync(s)&&Be.rmSync(s,{recursive:!0,force:!0}),Sn(je.join(r,"package.json"),ia(o)),Sn(je.join(s,"types.ts"),Qi),Sn(je.join(s,"index.ts"),sa(o.id)),zi(e,Ji(o))}import ge from"fs";import Bo from"path";function aa(e,t){return new RegExp(`^\\s*${t}\\s*=`,"m").test(e)}function $o(e){return e.endsWith(`
1505
1505
  `)?e:`${e}
1506
- `}async function Do(e,t){let n=Lo.join(e,".env"),o=Lo.join(e,".env.local"),r=ue.existsSync(n)?ue.readFileSync(n,"utf8"):"",s=ue.existsSync(o)?ue.readFileSync(o,"utf8"):"",i=`${r}
1507
- ${s}`,a=[{name:"DATABASE_URL",value:String(t.databaseUrl)},{name:"NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY",value:String(t.clerkPublishable)},{name:"CLERK_SECRET_KEY",value:String(t.clerkSecret)},{name:"NEXT_PUBLIC_SITE_URL",value:"http://localhost:3000"}].filter(p=>!Qi(i,p.name)).map(p=>`${p.name}="${p.value}"`);if(a.length===0)return;let c=`# Automatically injected by create-sailor
1506
+ `}async function Vo(e,t){let n=Bo.join(e,".env"),o=Bo.join(e,".env.local"),r=ge.existsSync(n)?ge.readFileSync(n,"utf8"):"",s=ge.existsSync(o)?ge.readFileSync(o,"utf8"):"",i=`${r}
1507
+ ${s}`,a=[{name:"DATABASE_URL",value:String(t.databaseUrl)},{name:"NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY",value:String(t.clerkPublishable)},{name:"CLERK_SECRET_KEY",value:String(t.clerkSecret)},{name:"NEXT_PUBLIC_SITE_URL",value:"http://localhost:3000"}].filter(p=>!aa(i,p.name)).map(p=>`${p.name}="${p.value}"`);if(a.length===0)return;let c=`# Automatically injected by create-sailor
1508
1508
  ${a.join(`
1509
1509
  `)}
1510
- `;try{let p=ue.readFileSync(o,"utf8"),d=Uo(p);ue.writeFileSync(o,`${d}
1511
- ${c}`)}catch{try{ue.writeFileSync(o,c,{flag:"wx"})}catch{let p=ue.readFileSync(o,"utf8");ue.writeFileSync(o,`${Uo(p)}
1512
- ${c}`)}}}import Fo from"crypto";import Et from"fs";import Mo from"path";function Be(e){return Fo.randomBytes(e).toString("base64").replace(/=+$/,"")}function Zi(e){return Fo.randomBytes(e).toString("hex")}function ea(){return{AUTH_SECRET:Be(32),NEXTAUTH_SECRET:Be(32),BETTER_AUTH_SECRET:Be(32),JWT_SECRET:Be(32),WEBHOOK_SECRET:Zi(16),ENCRYPTION_KEY:Be(32),API_SECRET_KEY:Be(32),SESSION_SECRET:Be(32)}}function ta(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function na(e,t,n){let o=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=ta(n);return e.replace(o,`${t}="${r}"`)}async function jo(e){let t=Mo.join(e,".env.example"),n=Mo.join(e,".env.local");if(!Et.existsSync(t))return null;try{let o=Et.readFileSync(t,"utf8"),r=ea(),i=Et.existsSync(n)?Et.readFileSync(n,"utf8"):o;for(let a of Object.keys(r))i=na(i,a,r[a]);return Et.writeFileSync(n,i),r}catch(o){let r=o instanceof Error?o.message:String(o);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var Ut=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function Bo(e){return Ut.find(t=>t.id===e)}var md=Ut.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function $o(e,t,n="global"){let o=Bo(t);if(!o)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${Ut.map(r=>r.id).join(", ")}`);if(o.id==="none"){J(e,"feature-flags");return}o.envVars.length>0&&re(e,{category:"Feature Flags",name:o.name,envVars:o.envVars,docs:o.docs}),se(e,"FEATURE_FLAGS_PROVIDER",o.id)}import{execFileSync as qo}from"child_process";import O from"fs";import oa from"os";import ae from"path";import ra from"ignore";var sa={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"}};function ia(){let e=process.env.SAILOR_TEMPLATE_LOCAL_DIR;if(!(!e||e.trim().length===0))return ae.resolve(e.trim())}var aa=new Set(["node_modules",".git","dist",".next",".turbo"]);function ca(e,t){if(!O.statSync(e).isDirectory())throw new Error(`SAILOR_TEMPLATE_LOCAL_DIR is not a directory: ${e}`);O.cpSync(e,t,{recursive:!0,dereference:!0,filter:o=>{let r=ae.basename(o);return!aa.has(r)}})}function pa(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function la(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function Go(e){return/^[0-9a-f]{7,40}$/i.test(e)}function da(e,t){let n=`https://github.com/${e}.git`,o=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of o)try{let s=qo("git",["ls-remote",n,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(Go(i))return i}catch{}return null}async function ua(e,t){if(Go(t))return t;let n=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"}});if(!n.ok){let r=da(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${n.status})`)}let o=await n.json();if(typeof o.sha!="string"||o.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return o.sha}function Ho(e,t,n){let o=O.readdirSync(t,{withFileTypes:!0});for(let r of o){if(r.name==="node_modules"||r.name===".git")continue;let s=ae.join(t,r.name),i=ae.relative(e,s).split(ae.sep).join("/");r.isDirectory()?(n.push(i+"/"),Ho(e,s,n)):n.push(i)}}function Vo(e){let t=ae.join(e,".templateignore");if(!O.existsSync(t))return;let n=O.readFileSync(t,"utf8"),o=ra().add(n),r=[];Ho(e,e,r);let s=r.map(c=>c.endsWith("/")?c.slice(0,-1):c),i=new Set(o.filter(s)),a=s.filter(c=>!i.has(c)).sort((c,p)=>p.split("/").length-c.split("/").length);for(let c of a){let p=ae.join(e,c);try{O.existsSync(p)&&O.rmSync(p,{recursive:!0,force:!0})}catch{}}try{O.existsSync(t)&&O.rmSync(t,{force:!0})}catch{}}async function Ko(e,t){let n=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"}});if(!n.ok)throw new Error(`Failed to download archive (${n.status})`);let o=Buffer.from(await n.arrayBuffer());if(o.byteLength<1024)throw new Error(`Downloaded archive is unexpectedly small (${o.byteLength} bytes)`);O.writeFileSync(t,o);let r=O.statSync(t);if(r.size!==o.byteLength)throw new Error(`Archive write verification failed (${r.size} != ${o.byteLength})`);return r.size}function Yo(e,t){qo("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:"ignore"})}function yn(e){try{let t=O.readdirSync(e);for(let n of t)O.rmSync(ae.join(e,n),{recursive:!0,force:!0})}catch{}}async function ma(e,t){let n=O.mkdtempSync(ae.join(oa.tmpdir(),"create-sailor-")),o=ae.join(n,"template.tar.gz");try{let r=await ua(e.repo,e.ref);await Ko(la(e.repo,r),o),Yo(o,t)}catch(r){if(!e.allowMutableFallback)throw r;yn(t),await Ko(pa(e.repo,e.ref),o),Yo(o,t)}finally{O.rmSync(n,{recursive:!0,force:!0})}}async function Wo(e){O.mkdirSync(e,{recursive:!0});let t=ia();if(t){if(!O.existsSync(t))throw new Error(`SAILOR_TEMPLATE_LOCAL_DIR does not exist: ${t}`);yn(e),ca(t,e);try{Vo(e)}catch(s){throw new Error(`Local template copied, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}return}let o=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],r;for(let s of o){let i=sa[s];try{if(await ma(i,e),i.applyIgnore)try{Vo(e)}catch(a){throw new Error(`Template cloned, but .templateignore processing failed: ${a instanceof Error?a.message:String(a)}`)}return}catch(a){r=a instanceof Error?a:new Error(String(a)),yn(e)}}throw new Error(`Failed to download the template from any source. Last error: ${r?.message??"unknown"}
1513
-
1514
- Ensure you have internet access and 'tar' installed.
1515
- You can override the source with SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF env vars.`)}import Dt from"fs";import Sn from"path";var ga="node scripts/governance/lint-no-raw-inputs.mjs",fa="node scripts/governance/lint-repository-seam.mjs",ya="node scripts/governance/lint-brand-literals.mjs",Sa="node scripts/governance/lint-microcopy.mjs",ha=/\bnode\s+scripts\/(governance\/)?lint-[\w-]+\.mjs/g,Ea=/\bnode\s+scripts\/lint-[\w-]+\.mjs/,va={scanRoots:["apps"],primitivesImport:"@nebutra/ui/primitives",whitelist:["/storybook/src/stories/","/design-docs/src/components/previews/","/sailor-docs/src/components/previews/","\\.test\\.tsx?$","/__tests__/"]},ba={coreDomains:["^packages/.*/(billing|license|metering|auth|audit|permissions|identity|tenant)/","^backends/gateway/src/routes/(billing|ai|admin|legal|integrations|webhooks)/","^apps/web/src/app/api/"],seamPaths:["^packages/platform/repositories/","^packages/platform/db/"],dbAccessors:["getTenantDb","getSystemDb"],allowlist:["apps/web/src/app/api/invitations/[invitationId]/accept/route.ts","apps/web/src/app/api/onboarding/invite-members/route.ts","apps/web/src/app/api/startup-os/projects/[projectId]/runs/[runId]/execute/route.ts","apps/web/src/app/api/cofounder/room/[profileId]/form-team/route.ts","apps/web/src/app/api/provider-keys/route.ts","backends/gateway/src/routes/admin/index.ts","backends/gateway/src/routes/ai/api-keys.ts","backends/gateway/src/routes/ai/usage.ts","backends/gateway/src/routes/billing/index.ts","backends/gateway/src/routes/integrations/index.ts","backends/gateway/src/routes/legal/consent.ts","backends/gateway/src/routes/webhooks/clerk.ts","backends/gateway/src/routes/webhooks/stripe.ts","packages/commerce/license/src/issue-license.ts","packages/commerce/license/src/validate-license.ts","packages/commerce/billing/src/credits/service.ts","packages/commerce/billing/src/usage/ledger.ts","packages/iam/audit/src/index.ts","packages/iam/auth/src/plugins/passkey-plugin.ts"]},_a={scanRoots:["apps/web/src"],excludePaths:["/api/","\\.test\\.tsx?$","/__tests__/","/storybook/src/stories/","/design-docs/","/sailor-docs/"],bannedPatterns:[],allowlist:[]},Xo={governedPaths:["apps","packages/commerce","packages/integrations/email"],allowExpressions:["Nebutra","\u4E91\u6BD3\u667A\u80FD","\u4E91\u6BD3","^https?://([a-z0-9-]+\\.)?nebutra\\.com(?:/|$)","^https?://([a-z0-9-]+\\.)?nebutra\\.ai(?:/|$)","#0033FE","#0BF1C3"],knownExemptPatterns:["\\.stories\\.tsx?$","/__tests__/","\\.test\\.tsx?$","/previews/","^packages/design/brand/","^packages/design/tokens/","^packages/design/design-tokens/"],allowlist:[]},wa=["apps/design-docs/mdx-components.tsx","apps/design-docs/next.config.ts","apps/design-docs/src/__registry__/index.tsx","apps/design-docs/src/app/[lang]/docs/[[...slug]]/page.tsx","apps/design-docs/src/app/[lang]/docs/layout.tsx","apps/design-docs/src/app/[lang]/layout.tsx","apps/design-docs/src/app/[lang]/registry/[name]/page.tsx","apps/design-docs/src/app/[lang]/registry/page.tsx","apps/design-docs/src/app/og/docs/[...slug]/route.tsx","apps/design-docs/src/components/brand-overview-visuals.tsx","apps/design-docs/src/components/color-usage.tsx","apps/design-docs/src/components/component-preview.tsx","apps/design-docs/src/components/gradient-demos.tsx","apps/design-docs/src/components/introduction-hero.tsx","apps/design-docs/src/components/motion-demos.tsx","apps/design-docs/src/components/pattern-demos.tsx","apps/design-docs/src/components/registry/registry-card.tsx","apps/design-docs/src/lib/github.ts","apps/design-docs/src/lib/registry-strings.ts","apps/design-docs/src/lib/registry.ts","apps/idp/src/app/layout.tsx","apps/idp/src/app/oauth/authorize/page.tsx","apps/idp/src/app/page.tsx","apps/idp/src/lib/oidc.ts","apps/landing/src/app/[lang]/layout.tsx","apps/landing/src/app/api/blog/comments/route.ts","apps/landing/src/app/api/blog/reactions/route.ts","apps/landing/src/app/api/og/route.ts","apps/landing/src/app/apple-icon.tsx","apps/landing/src/components/auth/google-one-tap.tsx","apps/landing/src/components/cookie-consent-banner.tsx","apps/landing/src/components/marketing/ProductHuntSection.tsx","apps/landing/src/components/marketing/TestimonialsSection.tsx","apps/landing/src/i18n/request.ts","apps/landing/src/lib/analytics/emit.ts","apps/landing/src/lib/blog-fallback.ts","apps/landing/src/lib/constants/playbook-data.ts","apps/landing/src/lib/constants/resources-data.ts","apps/landing/src/lib/constants/solutions-data.ts","apps/landing/src/lib/docs-links.ts","apps/landing/src/lib/env.ts","apps/landing/src/lib/landing-content.ts","apps/landing/src/lib/seo/metadata.ts","apps/landing/src/lib/seo/site-routes.ts","apps/landing/src/lib/status-checks.ts","apps/landing/src/proxy.ts","apps/mail-preview/scripts/export.ts","apps/mail-preview/scripts/render-react-templates.ts","apps/mail-preview/src/app/api/send-test/route.ts","apps/mail-preview/src/app/layout.tsx","apps/mail-preview/src/lib/fixtures.ts","apps/web/next.config.ts","apps/web/src/app/(app)/checkout-return/page.tsx","apps/web/src/app/(app)/choose-plan/page.tsx","apps/web/src/app/(app)/settings/api-keys/page.tsx","apps/web/src/app/(app)/settings/notifications/page.tsx","apps/web/src/app/(app)/settings/provider-keys/page.tsx","apps/web/src/app/(auth)/desktop-auth/complete/page.tsx","apps/web/src/app/(public)/page.tsx","apps/web/src/app/[locale]/welcome/page.tsx","apps/web/src/app/api/account/email-change/route.ts","apps/web/src/app/api/admin/access-invites/route.ts","apps/web/src/app/api/blog/comments/route.ts","apps/web/src/app/api/blog/reactions/route.ts","apps/web/src/app/api/me/public/route.ts","apps/web/src/app/api/organizations/[orgId]/members/route.ts","apps/web/src/app/global-error.tsx","apps/web/src/components/ErrorBoundary.tsx","apps/web/src/components/api-keys/create-api-key-dialog.tsx","apps/web/src/components/appearance/store.ts","apps/web/src/components/auth/auth-banner.tsx","apps/web/src/components/auth/desktop-auth-complete-handoff.tsx","apps/web/src/components/auth/sign-up-form.tsx","apps/web/src/components/billing/billing-self-service.tsx","apps/web/src/components/navigation/public-page-chrome.tsx","apps/web/src/components/notifications/inbox-bell.tsx","apps/web/src/components/notifications/notification-inbox-preview.tsx","apps/web/src/components/notifications/notification-preference-matrix.tsx","apps/web/src/components/notifications/notification-runtime-banner.tsx","apps/web/src/components/settings/security/security-capabilities.ts","apps/web/src/components/settings/security/security-settings-client.tsx","apps/web/src/components/theme-playground/design-md-import.tsx","apps/web/src/components/theme-playground/theme-playground-workbench.tsx","apps/web/src/components/theme-playground/theme-token-data.ts","apps/web/src/lib/api.ts","apps/web/src/lib/api/client.ts","apps/web/src/lib/env.ts","apps/web/src/lib/integrations/catalog.tsx","apps/web/src/lib/permissions.ts","apps/web/src/lib/public-url-defaults.ts","apps/web/src/lib/session-hint.ts","apps/web/src/lib/startup-os/company-context/generate.ts","apps/web/src/lib/startup-os/company-context/projection.ts","apps/web/src/lib/startup-os/conversation.ts","apps/web/src/lib/startup-os/execution.ts","apps/web/src/lib/startup-os/files.ts","apps/web/src/proxy.ts","packages/commerce/billing/src/index.ts","packages/commerce/contracts/src/identity.ts","packages/commerce/legal/src/components/CookieBanner.tsx","packages/commerce/legal/src/documents/config.ts","packages/commerce/legal/src/index.ts","packages/commerce/marketing/src/components/ProductHuntBadge.tsx","packages/commerce/marketing/src/config/index.ts","packages/commerce/marketing/src/index.ts","packages/integrations/email/src/index.ts","packages/integrations/email/src/templates/_layout.ts","packages/integrations/email/src/templates/invitation.tsx"];function Pa(e,t){let n=(e??"").replace(ha,"").split("&&").map(r=>r.trim()).filter(Boolean).join(" && ");return[n.length>0?n:"biome check .",...t].join(" && ")}function Aa(e){let t=new RegExp(Xo.allowExpressions.join("|"));return wa.filter(n=>{try{return t.test(Dt.readFileSync(Sn.join(e,n),"utf8"))}catch{return!1}})}async function zo(e,t){let n=t.database!=="none",o=[ga];n&&o.push(fa),o.push(ya),o.push(Sa);let r={...Xo,allowlist:Aa(e)},s={rawInputs:va,brandLiterals:r,microcopyRules:_a};n&&(s.repositorySeam=ba);let i=Sn.join(e,"governance.config.json");Dt.writeFileSync(i,JSON.stringify(s,null,2)+`
1516
- `);let a=Sn.join(e,"package.json"),c;try{c=Dt.readFileSync(a,"utf8")}catch(p){if(p.code!=="ENOENT")throw p}if(c!==void 0){let p=JSON.parse(c);p.scripts=p.scripts??{};for(let[d,u]of Object.entries(p.scripts))d!=="lint"&&typeof u=="string"&&Ea.test(u)&&delete p.scripts[d];p.scripts.lint=Pa(p.scripts.lint,o),Dt.writeFileSync(a,JSON.stringify(p,null,2)+`
1517
- `)}return{lints:o,configWritten:!0}}import Z from"fs";import ce from"path";import{fileURLToPath as Ca}from"url";var Ia=Ca(import.meta.url),Jo=ce.dirname(Ia),Qo="scaffold-meta.json",Zo=".nebutra";function xa(e){if(e)return e;let t=[ce.join(Jo,"..","templates"),ce.join(Jo,"..","..","templates")];for(let n of t)if(Z.existsSync(n))return n;return t[0]}function er(e,t){let n=[],o=xa(t.templatesRoot),r=ce.join(e,"LICENSE");if(Z.existsSync(r)){let p=Z.readFileSync(r,"utf-8").slice(0,256);(/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(p)||/Functional Source License/i.test(p))&&(Z.renameSync(r,ce.join(e,"LICENSE-UPSTREAM-REFERENCE.md")),n.push("LICENSE-UPSTREAM-REFERENCE.md (preserved upstream licence)"))}let s=ce.join(o,"LICENSE-SCAFFOLD.md");if(!Z.existsSync(s))throw new Error(`LICENSE-SCAFFOLD.md template missing at ${s}; cannot emit license.`);Z.copyFileSync(s,ce.join(e,"LICENSE")),n.push("LICENSE");let i={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:new Date().toISOString(),projectName:t.projectName,purpose:"Records which `create-sailor` version produced this project, for support triage. Provenance only: the MIT licence in LICENSE applies unconditionally and does not depend on this file. Deleting it costs you nothing.",license:{tier:"mit-scaffold",file:"LICENSE"}},a=ce.join(e,Zo);Z.mkdirSync(a,{recursive:!0}),Z.writeFileSync(ce.join(a,Qo),`${JSON.stringify(i,null,2)}
1518
- `),n.push(`${Zo}/${Qo}`);let c=ce.join(e,"README.md");if(Z.existsSync(c)){let p=Z.readFileSync(c,"utf-8");p.includes("Scaffolded by `create-sailor`")||(Z.writeFileSync(c,`> **License notice:** Scaffolded by \`create-sailor\`. The Nebutra-Sailor
1510
+ `;try{let p=ge.readFileSync(o,"utf8"),m=$o(p);ge.writeFileSync(o,`${m}
1511
+ ${c}`)}catch{try{ge.writeFileSync(o,c,{flag:"wx"})}catch{let p=ge.readFileSync(o,"utf8");ge.writeFileSync(o,`${$o(p)}
1512
+ ${c}`)}}}import Yo from"crypto";import bt from"fs";import Ko from"path";function Ve(e){return Yo.randomBytes(e).toString("base64").replace(/=+$/,"")}function ca(e){return Yo.randomBytes(e).toString("hex")}function pa(){return{AUTH_SECRET:Ve(32),NEXTAUTH_SECRET:Ve(32),BETTER_AUTH_SECRET:Ve(32),JWT_SECRET:Ve(32),WEBHOOK_SECRET:ca(16),ENCRYPTION_KEY:Ve(32),API_SECRET_KEY:Ve(32),SESSION_SECRET:Ve(32)}}function la(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function da(e,t,n){let o=new RegExp(`^(?!#)\\s*${t}=.*$`,"gm"),r=la(n);return e.replace(o,`${t}="${r}"`)}async function Go(e){let t=Ko.join(e,".env.example"),n=Ko.join(e,".env.local");if(!bt.existsSync(t))return null;try{let o=bt.readFileSync(t,"utf8"),r=pa(),i=bt.existsSync(n)?bt.readFileSync(n,"utf8"):o;for(let a of Object.keys(r))i=da(i,a,r[a]);return bt.writeFileSync(n,i),r}catch(o){let r=o instanceof Error?o.message:String(o);throw console.error(`[create-sailor] Failed to generate env secrets: ${r}`),new Error(`Unable to write .env.local: ${r}`)}}var Ft=[{id:"vercel-flags",name:"Vercel Flags SDK",region:"global",envVars:["FLAGS_SECRET"],docs:"https://vercel.com/docs/workflow-collaboration/feature-flags",description:"Native Vercel feature flags"},{id:"growthbook",name:"GrowthBook",region:"both",envVars:["GROWTHBOOK_API_HOST","GROWTHBOOK_CLIENT_KEY","GROWTHBOOK_DECRYPTION_KEY"],docs:"https://docs.growthbook.io",description:"Open-source A/B testing + flags"},{id:"configcat",name:"ConfigCat",region:"global",envVars:["CONFIGCAT_SDK_KEY"],docs:"https://configcat.com/docs/",description:"Feature flag & config management"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function qo(e){return Ft.find(t=>t.id===e)}var xd=Ft.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Ho(e,t,n="global"){let o=qo(t);if(!o)throw new Error(`Unknown feature-flags provider "${t}". Valid ids: ${Ft.map(r=>r.id).join(", ")}`);if(o.id==="none"){Z(e,"feature-flags");return}o.envVars.length>0&&ae(e,{category:"Feature Flags",name:o.name,envVars:o.envVars,docs:o.docs}),ce(e,"FEATURE_FLAGS_PROVIDER",o.id)}import{execFileSync as bn}from"child_process";import{once as ua}from"events";import C from"fs";import ma from"os";import te from"path";import ga from"ignore";var fa={mirror:{repo:process.env.SAILOR_TEMPLATE_REPO||"Nebutra/Sailor-Template",ref:process.env.SAILOR_TEMPLATE_REF||"main",applyIgnore:!1,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"},main:{repo:"Nebutra/Nebutra-Sailor",ref:"main",applyIgnore:!0,allowMutableFallback:process.env.SAILOR_TEMPLATE_ALLOW_MUTABLE_FALLBACK==="1"}},Wo=3e4,Xo=3;function hn(e){return`${e.repo}@${e.ref}`}function ya(){let e=process.env.SAILOR_TEMPLATE_LOCAL_DIR;if(!(!e||e.trim().length===0))return te.resolve(e.trim())}var Sa=new Set(["node_modules",".git","dist",".next",".turbo"]);function ha(e,t){if(!C.statSync(e).isDirectory())throw new Error(`SAILOR_TEMPLATE_LOCAL_DIR is not a directory: ${e}`);C.cpSync(e,t,{recursive:!0,dereference:!0,filter:o=>{let r=te.basename(o);return!Sa.has(r)}})}function Ea(e,t){return`https://github.com/${e}/archive/refs/heads/${t}.tar.gz`}function va(e,t){return`https://github.com/${e}/archive/${t}.tar.gz`}function er(e){return/^[0-9a-f]{7,40}$/i.test(e)}function zo(e,t){let n=`https://github.com/${e}.git`,o=[`refs/heads/${t}`,`refs/tags/${t}`];for(let r of o)try{let s=bn("git",["ls-remote",n,r],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();if(!s)continue;let[i]=s.split(/\s+/);if(er(i))return i}catch{}return null}async function ba(e,t){if(er(t))return t;let n;try{n=await fetch(`https://api.github.com/repos/${e}/commits/${encodeURIComponent(t)}`,{headers:{Accept:"application/vnd.github+json","User-Agent":"create-sailor"},signal:AbortSignal.timeout(2e4)})}catch(r){let s=zo(e,t);if(s)return s;throw new Error(`Cannot reach api.github.com to resolve ${e}@${t} (${En(r)})`)}if(!n.ok){let r=zo(e,t);if(r)return r;throw new Error(`Failed to resolve ${e}@${t} (GitHub API ${n.status})`)}let o=await n.json();if(typeof o.sha!="string"||o.sha.length===0)throw new Error(`GitHub API did not return a commit SHA for ${e}@${t}`);return o.sha}function tr(e,t,n){let o=C.readdirSync(t,{withFileTypes:!0});for(let r of o){if(r.name==="node_modules"||r.name===".git")continue;let s=te.join(t,r.name),i=te.relative(e,s).split(te.sep).join("/");r.isDirectory()?(n.push(i+"/"),tr(e,s,n)):n.push(i)}}function nr(e){let t=te.join(e,".templateignore");if(!C.existsSync(t))return;let n=C.readFileSync(t,"utf8"),o=ga().add(n),r=[];tr(e,e,r);let s=r.map(c=>c.endsWith("/")?c.slice(0,-1):c),i=new Set(o.filter(s)),a=s.filter(c=>!i.has(c)).sort((c,p)=>p.split("/").length-c.split("/").length);for(let c of a){let p=te.join(e,c);try{C.existsSync(p)&&C.rmSync(p,{recursive:!0,force:!0})}catch{}}try{C.existsSync(t)&&C.rmSync(t,{force:!0})}catch{}}function En(e){if(!(e instanceof Error))return String(e);let t=e.cause,n=t&&typeof t=="object"&&"code"in t?String(t.code):void 0,o=t instanceof Error?t.message:void 0;switch(n){case"ENOTFOUND":case"EAI_AGAIN":return"DNS lookup failed \u2014 check your connection or proxy";case"ECONNREFUSED":return"connection refused \u2014 a proxy or firewall may be blocking github.com";case"ECONNRESET":return"connection reset by peer mid-transfer";case"ETIMEDOUT":case"UND_ERR_CONNECT_TIMEOUT":return"connection timed out";case"UND_ERR_HEADERS_TIMEOUT":case"UND_ERR_BODY_TIMEOUT":return"the server stopped sending data mid-transfer";case"CERT_HAS_EXPIRED":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"SELF_SIGNED_CERT_IN_CHAIN":return"TLS certificate rejected \u2014 a corporate proxy may be intercepting HTTPS";default:break}return e.name==="TimeoutError"?"request timed out":e.name==="AbortError"?e.message||"transfer aborted":o?`${e.message}: ${o}`:e.message}function _a(e){return e===408||e===425||e===429||e>=500}async function wa(e,t,n){let o=new AbortController,r,s=()=>{r&&clearTimeout(r),r=setTimeout(()=>{o.abort(new Error(`no data received for ${Math.round(Wo/1e3)}s \u2014 transfer stalled`))},Wo)};s();try{let i=await fetch(e,{headers:{Accept:"application/octet-stream","User-Agent":"create-sailor"},signal:o.signal,redirect:"follow"});if(!i.ok){let g=new Error(`Failed to download archive (HTTP ${i.status} ${i.statusText})`);throw g.retryable=_a(i.status),g}if(!i.body)throw new Error("Download response had no body");let a=i.headers.get("content-length"),c=a&&/^\d+$/.test(a)?Number(a):void 0,p=C.createWriteStream(t),m=i.body.getReader(),d=0;try{for(;;){let{done:g,value:h}=await m.read();if(g)break;s(),d+=h.byteLength,p.write(h)||await ua(p,"drain"),n?.(d,c)}await new Promise((g,h)=>{p.end(P=>P?h(P):g())})}catch(g){throw p.destroy(),await m.cancel().catch(()=>{}),g}if(d<1024)throw new Error(`Downloaded archive is unexpectedly small (${d} bytes)`);if(c!==void 0&&d!==c){let g=new Error(`Download truncated \u2014 got ${it(d)} of ${it(c)}`);throw g.retryable=!0,g}let v=C.statSync(t);if(v.size!==d)throw new Error(`Archive write verification failed (${v.size} != ${d})`);return{bytes:d}}finally{r&&clearTimeout(r)}}async function Jo(e,t,n,o){let r;for(let s=1;s<=Xo;s++)try{return o?.({phase:"download",source:n,attempt:s,receivedBytes:0}),await wa(e,t,(i,a)=>{o?.({phase:"download",source:n,attempt:s,receivedBytes:i,totalBytes:a})})}catch(i){r=i instanceof Error?i:new Error(String(i));try{C.rmSync(t,{force:!0})}catch{}if(!(r.retryable??!0)||s===Xo)break;o?.({phase:"retry",source:n,attempt:s+1,reason:En(r)}),await new Promise(c=>setTimeout(c,s*1500))}throw new Error(En(r??new Error("unknown download failure")))}function Pa(e,t){try{bn("tar",["-xzf",e,"-C",t,"--strip-components=1"],{stdio:["ignore","ignore","pipe"]})}catch(n){let o=n.stderr?.toString().trim();throw new Error(`Failed to extract the template archive${o?`: ${o.split(`
1513
+ `)[0]}`:""}`)}}function Aa(){try{bn("tar",["--version"],{stdio:"ignore"})}catch{throw new Error("`tar` was not found on PATH. Install it (macOS/Linux ship it; on Windows use Git Bash or WSL) and retry.")}}function Qo(e){let t=0,n=o=>{for(let r of C.readdirSync(o,{withFileTypes:!0})){let s=te.join(o,r.name);if(r.isDirectory())n(s);else if(r.isFile())try{t+=C.statSync(s).size}catch{}}};try{n(e)}catch{}return t}function it(e){if(e<1024)return`${e} B`;let t=e/1e6;return t<1?`${Math.round(e/1024)} KB`:t<1e3?`${t.toFixed(1)} MB`:`${(t/1e3).toFixed(2)} GB`}function Zo(e,t){let n=new Set(vn(t));return C.cpSync(e,t,{recursive:!0,force:!0}),vn(t).filter(o=>!n.has(o))}function vn(e){try{return C.readdirSync(e)}catch{return[]}}async function Ca(e,t,n,o){let r=hn(e);o?.({phase:"resolve",source:r});try{let s=await ba(e.repo,e.ref);await Jo(va(e.repo,s),n,r,o)}catch(s){if(!e.allowMutableFallback)throw s;await Jo(Ea(e.repo,e.ref),n,r,o)}if(o?.({phase:"extract",source:r}),Pa(n,t),e.applyIgnore){o?.({phase:"strip",source:r});try{nr(t)}catch(s){throw new Error(`Template downloaded, but .templateignore processing failed: ${s instanceof Error?s.message:String(s)}`)}}if(vn(t).length===0)throw new Error("The extracted template was empty")}async function or(e,t={}){let{onProgress:n}=t;Aa(),C.mkdirSync(e,{recursive:!0});let o=C.mkdtempSync(te.join(ma.tmpdir(),"create-sailor-")),r=te.join(o,"template.tar.gz"),s=te.join(o,"tree"),i=()=>{C.rmSync(s,{recursive:!0,force:!0}),C.mkdirSync(s,{recursive:!0})};try{let a=ya();if(a){if(!C.existsSync(a))throw new Error(`SAILOR_TEMPLATE_LOCAL_DIR does not exist: ${a}`);let d=`local:${a}`;n?.({phase:"extract",source:d}),i(),ha(a,s),n?.({phase:"strip",source:d});try{nr(s)}catch(g){throw new Error(`Local template copied, but .templateignore processing failed: ${g instanceof Error?g.message:String(g)}`)}n?.({phase:"install",source:d});let v=Qo(s);return{source:d,bytes:v,createdEntries:Zo(s,e)}}let p=process.env.SAILOR_TEMPLATE_SOURCE==="main"?["main"]:["mirror","main"],m=[];for(let d of p){let v=fa[d];try{i(),await Ca(v,s,r,n);let g=hn(v);n?.({phase:"install",source:g});let h=Qo(s);return{source:g,bytes:h,createdEntries:Zo(s,e)}}catch(g){m.push(` ${hn(v)} \u2014 ${g instanceof Error?g.message:String(g)}`)}}throw new Error(`Could not download the Sailor template.
1514
+
1515
+ Tried:
1516
+ ${m.join(`
1517
+ `)}
1518
+
1519
+ The template is a large archive, so an unstable or filtered connection is the
1520
+ usual cause. Things that help, in order:
1521
+ 1. Retry \u2014 transient resets are common on big transfers.
1522
+ 2. Scaffold from a local checkout (no download at all):
1523
+ git clone --depth 1 https://github.com/Nebutra/Sailor-Template.git
1524
+ SAILOR_TEMPLATE_LOCAL_DIR=./Sailor-Template npx create-sailor@latest
1525
+ 3. Pin a different source: SAILOR_TEMPLATE_REPO / SAILOR_TEMPLATE_REF.
1526
+
1527
+ Nothing was written to your project directory.`)}finally{C.rmSync(o,{recursive:!0,force:!0})}}import jt from"fs";import _n from"path";var Ia="node scripts/governance/lint-no-raw-inputs.mjs",Ta="node scripts/governance/lint-repository-seam.mjs",xa="node scripts/governance/lint-brand-literals.mjs",Ra="node scripts/governance/lint-microcopy.mjs",ka=/\bnode\s+scripts\/(governance\/)?lint-[\w-]+\.mjs/g,Na=/\bnode\s+scripts\/lint-[\w-]+\.mjs/,Oa={scanRoots:["apps"],primitivesImport:"@nebutra/ui/primitives",whitelist:["/storybook/src/stories/","/design-docs/src/components/previews/","/sailor-docs/src/components/previews/","\\.test\\.tsx?$","/__tests__/"]},La={coreDomains:["^packages/.*/(billing|license|metering|auth|audit|permissions|identity|tenant)/","^backends/gateway/src/routes/(billing|ai|admin|legal|integrations|webhooks)/","^apps/web/src/app/api/"],seamPaths:["^packages/platform/repositories/","^packages/platform/db/"],dbAccessors:["getTenantDb","getSystemDb"],allowlist:["apps/web/src/app/api/invitations/[invitationId]/accept/route.ts","apps/web/src/app/api/onboarding/invite-members/route.ts","apps/web/src/app/api/startup-os/projects/[projectId]/runs/[runId]/execute/route.ts","apps/web/src/app/api/cofounder/room/[profileId]/form-team/route.ts","apps/web/src/app/api/provider-keys/route.ts","backends/gateway/src/routes/admin/index.ts","backends/gateway/src/routes/ai/api-keys.ts","backends/gateway/src/routes/ai/usage.ts","backends/gateway/src/routes/billing/index.ts","backends/gateway/src/routes/integrations/index.ts","backends/gateway/src/routes/legal/consent.ts","backends/gateway/src/routes/webhooks/clerk.ts","backends/gateway/src/routes/webhooks/stripe.ts","packages/commerce/license/src/issue-license.ts","packages/commerce/license/src/validate-license.ts","packages/commerce/billing/src/credits/service.ts","packages/commerce/billing/src/usage/ledger.ts","packages/iam/audit/src/index.ts","packages/iam/auth/src/plugins/passkey-plugin.ts"]},Ua={scanRoots:["apps/web/src"],excludePaths:["/api/","\\.test\\.tsx?$","/__tests__/","/storybook/src/stories/","/design-docs/","/sailor-docs/"],bannedPatterns:[],allowlist:[]},rr={governedPaths:["apps","packages/commerce","packages/integrations/email"],allowExpressions:["Nebutra","\u4E91\u6BD3\u667A\u80FD","\u4E91\u6BD3","^https?://([a-z0-9-]+\\.)?nebutra\\.com(?:/|$)","^https?://([a-z0-9-]+\\.)?nebutra\\.ai(?:/|$)","#0033FE","#0BF1C3"],knownExemptPatterns:["\\.stories\\.tsx?$","/__tests__/","\\.test\\.tsx?$","/previews/","^packages/design/brand/","^packages/design/tokens/","^packages/design/design-tokens/"],allowlist:[]},Da=["apps/design-docs/mdx-components.tsx","apps/design-docs/next.config.ts","apps/design-docs/src/__registry__/index.tsx","apps/design-docs/src/app/[lang]/docs/[[...slug]]/page.tsx","apps/design-docs/src/app/[lang]/docs/layout.tsx","apps/design-docs/src/app/[lang]/layout.tsx","apps/design-docs/src/app/[lang]/registry/[name]/page.tsx","apps/design-docs/src/app/[lang]/registry/page.tsx","apps/design-docs/src/app/og/docs/[...slug]/route.tsx","apps/design-docs/src/components/brand-overview-visuals.tsx","apps/design-docs/src/components/color-usage.tsx","apps/design-docs/src/components/component-preview.tsx","apps/design-docs/src/components/gradient-demos.tsx","apps/design-docs/src/components/introduction-hero.tsx","apps/design-docs/src/components/motion-demos.tsx","apps/design-docs/src/components/pattern-demos.tsx","apps/design-docs/src/components/registry/registry-card.tsx","apps/design-docs/src/lib/github.ts","apps/design-docs/src/lib/registry-strings.ts","apps/design-docs/src/lib/registry.ts","apps/idp/src/app/layout.tsx","apps/idp/src/app/oauth/authorize/page.tsx","apps/idp/src/app/page.tsx","apps/idp/src/lib/oidc.ts","apps/landing/src/app/[lang]/layout.tsx","apps/landing/src/app/api/blog/comments/route.ts","apps/landing/src/app/api/blog/reactions/route.ts","apps/landing/src/app/api/og/route.ts","apps/landing/src/app/apple-icon.tsx","apps/landing/src/components/auth/google-one-tap.tsx","apps/landing/src/components/cookie-consent-banner.tsx","apps/landing/src/components/marketing/ProductHuntSection.tsx","apps/landing/src/components/marketing/TestimonialsSection.tsx","apps/landing/src/i18n/request.ts","apps/landing/src/lib/analytics/emit.ts","apps/landing/src/lib/blog-fallback.ts","apps/landing/src/lib/constants/playbook-data.ts","apps/landing/src/lib/constants/resources-data.ts","apps/landing/src/lib/constants/solutions-data.ts","apps/landing/src/lib/docs-links.ts","apps/landing/src/lib/env.ts","apps/landing/src/lib/landing-content.ts","apps/landing/src/lib/seo/metadata.ts","apps/landing/src/lib/seo/site-routes.ts","apps/landing/src/lib/status-checks.ts","apps/landing/src/proxy.ts","apps/mail-preview/scripts/export.ts","apps/mail-preview/scripts/render-react-templates.ts","apps/mail-preview/src/app/api/send-test/route.ts","apps/mail-preview/src/app/layout.tsx","apps/mail-preview/src/lib/fixtures.ts","apps/web/next.config.ts","apps/web/src/app/(app)/checkout-return/page.tsx","apps/web/src/app/(app)/choose-plan/page.tsx","apps/web/src/app/(app)/settings/api-keys/page.tsx","apps/web/src/app/(app)/settings/notifications/page.tsx","apps/web/src/app/(app)/settings/provider-keys/page.tsx","apps/web/src/app/(auth)/desktop-auth/complete/page.tsx","apps/web/src/app/(public)/page.tsx","apps/web/src/app/[locale]/welcome/page.tsx","apps/web/src/app/api/account/email-change/route.ts","apps/web/src/app/api/admin/access-invites/route.ts","apps/web/src/app/api/blog/comments/route.ts","apps/web/src/app/api/blog/reactions/route.ts","apps/web/src/app/api/me/public/route.ts","apps/web/src/app/api/organizations/[orgId]/members/route.ts","apps/web/src/app/global-error.tsx","apps/web/src/components/ErrorBoundary.tsx","apps/web/src/components/api-keys/create-api-key-dialog.tsx","apps/web/src/components/appearance/store.ts","apps/web/src/components/auth/auth-banner.tsx","apps/web/src/components/auth/desktop-auth-complete-handoff.tsx","apps/web/src/components/auth/sign-up-form.tsx","apps/web/src/components/billing/billing-self-service.tsx","apps/web/src/components/navigation/public-page-chrome.tsx","apps/web/src/components/notifications/inbox-bell.tsx","apps/web/src/components/notifications/notification-inbox-preview.tsx","apps/web/src/components/notifications/notification-preference-matrix.tsx","apps/web/src/components/notifications/notification-runtime-banner.tsx","apps/web/src/components/settings/security/security-capabilities.ts","apps/web/src/components/settings/security/security-settings-client.tsx","apps/web/src/components/theme-playground/design-md-import.tsx","apps/web/src/components/theme-playground/theme-playground-workbench.tsx","apps/web/src/components/theme-playground/theme-token-data.ts","apps/web/src/lib/api.ts","apps/web/src/lib/api/client.ts","apps/web/src/lib/env.ts","apps/web/src/lib/integrations/catalog.tsx","apps/web/src/lib/permissions.ts","apps/web/src/lib/public-url-defaults.ts","apps/web/src/lib/session-hint.ts","apps/web/src/lib/startup-os/company-context/generate.ts","apps/web/src/lib/startup-os/company-context/projection.ts","apps/web/src/lib/startup-os/conversation.ts","apps/web/src/lib/startup-os/execution.ts","apps/web/src/lib/startup-os/files.ts","apps/web/src/proxy.ts","packages/commerce/billing/src/index.ts","packages/commerce/contracts/src/identity.ts","packages/commerce/legal/src/components/CookieBanner.tsx","packages/commerce/legal/src/documents/config.ts","packages/commerce/legal/src/index.ts","packages/commerce/marketing/src/components/ProductHuntBadge.tsx","packages/commerce/marketing/src/config/index.ts","packages/commerce/marketing/src/index.ts","packages/integrations/email/src/index.ts","packages/integrations/email/src/templates/_layout.ts","packages/integrations/email/src/templates/invitation.tsx"];function Ma(e,t){let n=(e??"").replace(ka,"").split("&&").map(r=>r.trim()).filter(Boolean).join(" && ");return[n.length>0?n:"biome check .",...t].join(" && ")}function Fa(e){let t=new RegExp(rr.allowExpressions.join("|"));return Da.filter(n=>{try{return t.test(jt.readFileSync(_n.join(e,n),"utf8"))}catch{return!1}})}async function sr(e,t){let n=t.database!=="none",o=[Ia];n&&o.push(Ta),o.push(xa),o.push(Ra);let r={...rr,allowlist:Fa(e)},s={rawInputs:Oa,brandLiterals:r,microcopyRules:Ua};n&&(s.repositorySeam=La);let i=_n.join(e,"governance.config.json");jt.writeFileSync(i,JSON.stringify(s,null,2)+`
1528
+ `);let a=_n.join(e,"package.json"),c;try{c=jt.readFileSync(a,"utf8")}catch(p){if(p.code!=="ENOENT")throw p}if(c!==void 0){let p=JSON.parse(c);p.scripts=p.scripts??{};for(let[m,d]of Object.entries(p.scripts))m!=="lint"&&typeof d=="string"&&Na.test(d)&&delete p.scripts[m];p.scripts.lint=Ma(p.scripts.lint,o),jt.writeFileSync(a,JSON.stringify(p,null,2)+`
1529
+ `)}return{lints:o,configWritten:!0}}import ne from"fs";import le from"path";import{fileURLToPath as ja}from"url";var Ba=ja(import.meta.url),ir=le.dirname(Ba),ar="scaffold-meta.json",cr=".nebutra";function $a(e){if(e)return e;let t=[le.join(ir,"..","templates"),le.join(ir,"..","..","templates")];for(let n of t)if(ne.existsSync(n))return n;return t[0]}function pr(e,t){let n=[],o=$a(t.templatesRoot),r=le.join(e,"LICENSE");if(ne.existsSync(r)){let p=ne.readFileSync(r,"utf-8").slice(0,256);(/GNU AFFERO GENERAL PUBLIC LICENSE/i.test(p)||/Functional Source License/i.test(p))&&(ne.renameSync(r,le.join(e,"LICENSE-UPSTREAM-REFERENCE.md")),n.push("LICENSE-UPSTREAM-REFERENCE.md (preserved upstream licence)"))}let s=le.join(o,"LICENSE-SCAFFOLD.md");if(!ne.existsSync(s))throw new Error(`LICENSE-SCAFFOLD.md template missing at ${s}; cannot emit license.`);ne.copyFileSync(s,le.join(e,"LICENSE")),n.push("LICENSE");let i={schemaVersion:1,cliVersion:t.cliVersion,scaffoldedAt:new Date().toISOString(),projectName:t.projectName,purpose:"Records which `create-sailor` version produced this project, for support triage. Provenance only: the MIT licence in LICENSE applies unconditionally and does not depend on this file. Deleting it costs you nothing.",license:{tier:"mit-scaffold",file:"LICENSE"}},a=le.join(e,cr);ne.mkdirSync(a,{recursive:!0}),ne.writeFileSync(le.join(a,ar),`${JSON.stringify(i,null,2)}
1530
+ `),n.push(`${cr}/${ar}`);let c=le.join(e,"README.md");if(ne.existsSync(c)){let p=ne.readFileSync(c,"utf-8");p.includes("Scaffolded by `create-sailor`")||(ne.writeFileSync(c,`> **License notice:** Scaffolded by \`create-sailor\`. The Nebutra-Sailor
1519
1531
  > code in this project is [MIT licensed](./LICENSE) \u2014 commercial use, closed
1520
1532
  > source, no fee, no attribution required. The upstream monorepo is
1521
1533
  > FSL-1.1-ALv2 \u2014 see \`LICENSE-UPSTREAM-REFERENCE.md\`.
1522
1534
 
1523
- `+p),n.push("README.md (prepended license notice)"))}return{wrote:n}}import $e from"fs";import hn from"path";async function tr(e,t){let n=hn.join(e,"packages","mcp");if(t==="off"){$e.existsSync(n)&&$e.rmSync(n,{recursive:!0,force:!0});let r=hn.join(e,"packages","cli","src","commands","mcp-server.ts");$e.existsSync(r)&&$e.rmSync(r,{force:!0});return}let o=hn.join(e,".env.example");if($e.existsSync(o)){let r=$e.readFileSync(o,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1524
- `);$e.appendFileSync(o,i)}}}import vt from"fs";import nr from"path";async function or(e,t,n){let o=nr.join(e,"packages","metering"),r;if(t==="auto"?r=n!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){vt.existsSync(o)&&vt.rmSync(o,{recursive:!0,force:!0});return}let s=nr.join(e,".env.example");if(!vt.existsSync(s))return;let i=vt.readFileSync(s,"utf-8"),a="# Metering (usage-based billing)";if(!i.includes(a)){let c=["","# =============================================",a,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1525
- `);vt.appendFileSync(s,c)}}import me from"fs";import F from"path";var rr=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Md=rr.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function sr(e){return rr.find(t=>t.id===e)}var En={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function Ra(e){me.mkdirSync(e,{recursive:!0})}function vn(e,t){let n=F.join(e,"package.json");if(!me.existsSync(n))return;let o;try{o=JSON.parse(me.readFileSync(n,"utf-8"))}catch(a){console.error(`Failed to parse ${n}:`,a);return}let s={...o.dependencies??{}};for(let[a,c]of Object.entries(t))s[a]||(s[a]=c);let i={...o,dependencies:s};me.writeFileSync(n,JSON.stringify(i,null,2)+`
1526
- `)}function pe(e,t){Ra(F.dirname(e)),me.writeFileSync(e,t)}function bt(e,t){let n=F.join(e,".env.example");me.existsSync(n)?me.appendFileSync(n,`
1527
- `+t):me.writeFileSync(n,t)}function Ta(e){let t=`import * as Sentry from "@sentry/nextjs";
1535
+ `+p),n.push("README.md (prepended license notice)"))}return{wrote:n}}import Ke from"fs";import wn from"path";async function lr(e,t){let n=wn.join(e,"packages","mcp");if(t==="off"){Ke.existsSync(n)&&Ke.rmSync(n,{recursive:!0,force:!0});let r=wn.join(e,"packages","cli","src","commands","mcp-server.ts");Ke.existsSync(r)&&Ke.rmSync(r,{force:!0});return}let o=wn.join(e,".env.example");if(Ke.existsSync(o)){let r=Ke.readFileSync(o,"utf-8"),s="# MCP Server (Agent-friendly API)";if(!r.includes(s)){let i=["","# =============================================",s,"# Docs: https://modelcontextprotocol.io","# =============================================","# MCP server exposes your SaaS capabilities to AI agents via MCP protocol.","# Run: pnpm mcp-server (starts stdio server)","# No config required for stdio transport. HTTP transport needs:",'MCP_HTTP_PORT="3100"','MCP_API_KEY=""',""].join(`
1536
+ `);Ke.appendFileSync(o,i)}}}import _t from"fs";import dr from"path";async function ur(e,t,n){let o=dr.join(e,"packages","metering"),r;if(t==="auto"?r=n!=="none"?"on":"off":t==="on"||t==="off"?r=t:r="off",r==="off"){_t.existsSync(o)&&_t.rmSync(o,{recursive:!0,force:!0});return}let s=dr.join(e,".env.example");if(!_t.existsSync(s))return;let i=_t.readFileSync(s,"utf-8"),a="# Metering (usage-based billing)";if(!i.includes(a)){let c=["","# =============================================",a,"# Docs: see packages/commerce/metering/README.md","# =============================================","# ClickHouse-based metering pipeline for consumption billing.",'CLICKHOUSE_URL=""','CLICKHOUSE_USER="default"','CLICKHOUSE_PASSWORD=""','CLICKHOUSE_DATABASE="metering"',""].join(`
1537
+ `);_t.appendFileSync(s,c)}}import fe from"fs";import j from"path";var mr=[{id:"sentry",name:"Sentry",region:"both",envVars:["SENTRY_DSN","NEXT_PUBLIC_SENTRY_DSN"],docs:"https://docs.sentry.io",pkg:"@sentry/nextjs",instrumentationFile:"apps/web/instrumentation.ts"},{id:"datadog",name:"Datadog",region:"global",envVars:["DD_API_KEY","DD_APP_KEY","DD_SITE"],docs:"https://docs.datadoghq.com",pkg:"dd-trace",instrumentationFile:"apps/web/instrumentation.ts"},{id:"bugsnag",name:"Bugsnag",region:"global",envVars:["BUGSNAG_API_KEY","NEXT_PUBLIC_BUGSNAG_API_KEY"],docs:"https://docs.bugsnag.com",pkg:"@bugsnag/js",instrumentationFile:"apps/web/src/lib/monitoring/bugsnag.ts"},{id:"aliyun-arms",name:"\u963F\u91CC\u4E91 ARMS",region:"cn",envVars:["ALIYUN_ARMS_LICENSE_KEY","ALIYUN_ARMS_APP_NAME","NEXT_PUBLIC_ARMS_PID"],docs:"https://help.aliyun.com/product/34364.html",instrumentationFile:"apps/web/src/components/monitoring/ArmsScript.tsx"},{id:"tingyun",name:"\u542C\u4E91 TingYun",region:"cn",envVars:["TINGYUN_LICENSE_KEY","NEXT_PUBLIC_TINGYUN_APP_KEY"],docs:"https://www.tingyun.com/docs",instrumentationFile:"apps/web/src/components/monitoring/TingYunScript.tsx"},{id:"none",name:"None",region:"both",envVars:[],docs:""}],eu=mr.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function gr(e){return mr.find(t=>t.id===e)}var Pn={sentry:{"@sentry/nextjs":"^8.45.0"},datadog:{"dd-trace":"^5.32.0","@datadog/browser-rum":"^5.30.0"},bugsnag:{"@bugsnag/js":"^8.2.0","@bugsnag/plugin-react":"^8.2.0"}};function Va(e){fe.mkdirSync(e,{recursive:!0})}function An(e,t){let n=j.join(e,"package.json");if(!fe.existsSync(n))return;let o;try{o=JSON.parse(fe.readFileSync(n,"utf-8"))}catch(a){console.error(`Failed to parse ${n}:`,a);return}let s={...o.dependencies??{}};for(let[a,c]of Object.entries(t))s[a]||(s[a]=c);let i={...o,dependencies:s};fe.writeFileSync(n,JSON.stringify(i,null,2)+`
1538
+ `)}function de(e,t){Va(j.dirname(e)),fe.writeFileSync(e,t)}function wt(e,t){let n=j.join(e,".env.example");fe.existsSync(n)?fe.appendFileSync(n,`
1539
+ `+t):fe.writeFileSync(n,t)}function Ka(e){let t=`import * as Sentry from "@sentry/nextjs";
1528
1540
 
1529
1541
  Sentry.init({
1530
1542
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
@@ -1567,14 +1579,14 @@ export async function register() {
1567
1579
  }
1568
1580
 
1569
1581
  export { captureRequestError as onRequestError } from "@sentry/nextjs";
1570
- `;pe(F.join(e,"sentry.client.config.ts"),t),pe(F.join(e,"sentry.server.config.ts"),n),pe(F.join(e,"sentry.edge.config.ts"),o),pe(F.join(e,"instrumentation.ts"),r)}function ka(){return`# Sentry \u2014 error tracking + performance monitoring
1582
+ `;de(j.join(e,"sentry.client.config.ts"),t),de(j.join(e,"sentry.server.config.ts"),n),de(j.join(e,"sentry.edge.config.ts"),o),de(j.join(e,"instrumentation.ts"),r)}function Ya(){return`# Sentry \u2014 error tracking + performance monitoring
1571
1583
  # Get your DSN from https://sentry.io/settings/projects/<project>/keys/
1572
1584
  SENTRY_DSN=
1573
1585
  NEXT_PUBLIC_SENTRY_DSN=
1574
1586
  SENTRY_ORG=
1575
1587
  SENTRY_PROJECT=
1576
1588
  SENTRY_AUTH_TOKEN=
1577
- `}function Na(e){let t=`/**
1589
+ `}function Ga(e){let t=`/**
1578
1590
  * Next.js instrumentation hook \u2014 wires Datadog APM (dd-trace) into Node runtime.
1579
1591
  * Edge runtime is not supported by dd-trace; only nodejs is initialized.
1580
1592
  */
@@ -1622,7 +1634,7 @@ export function initDatadogRum(): void {
1622
1634
  });
1623
1635
  initialized = true;
1624
1636
  }
1625
- `;pe(F.join(e,"instrumentation.ts"),t),pe(F.join(e,"src","lib","monitoring","datadog-rum.ts"),n)}function Oa(){return`# Datadog \u2014 APM + RUM
1637
+ `;de(j.join(e,"instrumentation.ts"),t),de(j.join(e,"src","lib","monitoring","datadog-rum.ts"),n)}function qa(){return`# Datadog \u2014 APM + RUM
1626
1638
  # Server APM (dd-trace)
1627
1639
  DD_API_KEY=
1628
1640
  DD_APP_KEY=
@@ -1637,7 +1649,7 @@ NEXT_PUBLIC_DD_SITE=datadoghq.com
1637
1649
  NEXT_PUBLIC_DD_SERVICE=sailor-web
1638
1650
  NEXT_PUBLIC_DD_ENV=production
1639
1651
  NEXT_PUBLIC_DD_VERSION=
1640
- `}function La(e){let t=`/**
1652
+ `}function Ha(e){let t=`/**
1641
1653
  * Bugsnag server-side initialization.
1642
1654
  * Import this once at the top of your server entrypoint or a shared init module.
1643
1655
  */
@@ -1686,11 +1698,11 @@ export function getBugsnagErrorBoundary() {
1686
1698
  errorBoundary = plugin.createErrorBoundary(React) as typeof errorBoundary;
1687
1699
  return errorBoundary;
1688
1700
  }
1689
- `;pe(F.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),pe(F.join(e,"src","lib","monitoring","bugsnag.client.tsx"),n)}function Ua(){return`# Bugsnag \u2014 error tracking
1701
+ `;de(j.join(e,"src","lib","monitoring","bugsnag.server.ts"),t),de(j.join(e,"src","lib","monitoring","bugsnag.client.tsx"),n)}function Wa(){return`# Bugsnag \u2014 error tracking
1690
1702
  BUGSNAG_API_KEY=
1691
1703
  NEXT_PUBLIC_BUGSNAG_API_KEY=
1692
1704
  APP_VERSION=
1693
- `}function Da(e){pe(F.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1705
+ `}function Xa(e){de(j.join(e,"src","components","monitoring","ArmsScript.tsx"),`"use client";
1694
1706
  /**
1695
1707
  * \u963F\u91CC\u4E91 ARMS (Application Real-time Monitoring Service) browser agent.
1696
1708
  * Injects the official JS agent via next/script.
@@ -1711,11 +1723,11 @@ export function ArmsScript() {
1711
1723
  />
1712
1724
  );
1713
1725
  }
1714
- `)}function Ma(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1726
+ `)}function za(){return`# \u963F\u91CC\u4E91 ARMS \u2014 APM (\u4E2D\u56FD\u533A)
1715
1727
  ALIYUN_ARMS_LICENSE_KEY=
1716
1728
  ALIYUN_ARMS_APP_NAME=
1717
1729
  NEXT_PUBLIC_ARMS_PID=
1718
- `}function Fa(e){pe(F.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1730
+ `}function Ja(e){de(j.join(e,"src","components","monitoring","TingYunScript.tsx"),`"use client";
1719
1731
  /**
1720
1732
  * \u542C\u4E91 Browser Agent (\u524D\u7AEF\u6027\u80FD\u76D1\u63A7).
1721
1733
  * Docs: https://www.tingyun.com/docs
@@ -1733,12 +1745,12 @@ export function TingYunScript() {
1733
1745
  />
1734
1746
  );
1735
1747
  }
1736
- `)}function ja(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1748
+ `)}function Qa(){return`# \u542C\u4E91 TingYun \u2014 APM (\u4E2D\u56FD\u533A)
1737
1749
  TINGYUN_LICENSE_KEY=
1738
1750
  NEXT_PUBLIC_TINGYUN_APP_KEY=
1739
- `}async function ir(e,t,n="global"){let o=sr(t);if(!o||o.id==="none")return;let r=F.join(e,"apps","web");if(!me.existsSync(r))return;let s=o.id;try{switch(s){case"sentry":Ta(r),vn(r,En.sentry),bt(e,ka());return;case"datadog":Na(r),vn(r,En.datadog),bt(e,Oa());return;case"bugsnag":La(r),vn(r,En.bugsnag),bt(e,Ua());return;case"aliyun-arms":Da(r),bt(e,Ma());return;case"tingyun":Fa(r),bt(e,ja());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Mt=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function ar(e){return Mt.find(t=>t.id===e)}var Kd=Mt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function cr(e,t,n="global"){let o=ar(t);if(!o)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Mt.map(r=>r.id).join(", ")}`);if(o.id==="none"){J(e,"notifications");return}o.envVars.length>0&&re(e,{category:"Notifications",name:o.name,envVars:o.envVars,docs:o.docs}),se(e,"NOTIFICATIONS_PROVIDER",o.id)}import bn from"fs";import Ba from"path";async function pr(e,t){let n=Ba.join(e,"package.json");if(bn.existsSync(n)){let o=bn.readFileSync(n,"utf8"),r=JSON.parse(o);r.name=t,r.version="0.1.0",bn.writeFileSync(n,JSON.stringify(r,null,2)+`
1740
- `)}}import Ft from"fs";import st from"path";import{fileURLToPath as $a}from"url";var Va=$a(import.meta.url),lr=st.dirname(Va);function Ka(){let e=[st.join(lr,"..","templates","orm","drizzle"),st.join(lr,"..","..","templates","orm","drizzle")];for(let t of e)if(Ft.existsSync(t))return t;return null}function dr(e,t){Ft.mkdirSync(t,{recursive:!0});for(let n of Ft.readdirSync(e,{withFileTypes:!0})){let o=st.join(e,n.name),r=st.join(t,n.name);n.isDirectory()?dr(o,r):Ft.copyFileSync(o,r)}}async function ur(e,t,n){if(t!=="drizzle")return{applied:!1};if(n!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${n} keeps Prisma as sole ORM`};let o=Ka();if(!o)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=st.join(e,"packages","platform","db-drizzle");return dr(o,r),{applied:!0}}import ge from"fs";import _t from"path";var Ya=["stripe","lemonsqueezy","chinapay","polar"];function mr(e){ge.existsSync(e)&&ge.rmSync(e,{recursive:!0,force:!0})}function qa(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function Ga(e,t){let n=_t.join(e,".env.example");ge.existsSync(n)?ge.appendFileSync(n,`
1741
- `+t):ge.writeFileSync(n,t)}function Ha(e){switch(e){case"stripe":return`# Stripe
1751
+ `}async function fr(e,t,n="global"){let o=gr(t);if(!o||o.id==="none")return;let r=j.join(e,"apps","web");if(!fe.existsSync(r))return;let s=o.id;try{switch(s){case"sentry":Ka(r),An(r,Pn.sentry),wt(e,Ya());return;case"datadog":Ga(r),An(r,Pn.datadog),wt(e,qa());return;case"bugsnag":Ha(r),An(r,Pn.bugsnag),wt(e,Wa());return;case"aliyun-arms":Xa(r),wt(e,za());return;case"tingyun":Ja(r),wt(e,Qa());return;default:return}}catch(i){throw console.error(`Failed to apply monitoring selection "${t}":`,i),new Error(`Monitoring scaffold for "${t}" failed \u2014 see stderr for details.`)}}var Bt=[{id:"novu",name:"Novu",region:"both",envVars:["NOVU_API_KEY","NOVU_APPLICATION_IDENTIFIER"],docs:"https://docs.novu.co",description:"Multi-channel notification infrastructure"},{id:"knock",name:"Knock",region:"global",envVars:["KNOCK_API_KEY","KNOCK_SIGNING_KEY","KNOCK_PUBLIC_API_KEY"],docs:"https://docs.knock.app",description:"Product notifications platform"},{id:"custom",name:"Custom (direct dispatchers)",region:"both",envVars:[],docs:"",description:"Use email + sms + push directly"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function yr(e){return Bt.find(t=>t.id===e)}var iu=Bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Sr(e,t,n="global"){let o=yr(t);if(!o)throw new Error(`Unknown notifications provider "${t}". Valid ids: ${Bt.map(r=>r.id).join(", ")}`);if(o.id==="none"){Z(e,"notifications");return}o.envVars.length>0&&ae(e,{category:"Notifications",name:o.name,envVars:o.envVars,docs:o.docs}),ce(e,"NOTIFICATIONS_PROVIDER",o.id)}import Cn from"fs";import Za from"path";async function hr(e,t){let n=Za.join(e,"package.json");if(Cn.existsSync(n)){let o=Cn.readFileSync(n,"utf8"),r=JSON.parse(o);r.name=t,r.version="0.1.0",Cn.writeFileSync(n,JSON.stringify(r,null,2)+`
1752
+ `)}}import $t from"fs";import at from"path";import{fileURLToPath as ec}from"url";var tc=ec(import.meta.url),Er=at.dirname(tc);function nc(){let e=[at.join(Er,"..","templates","orm","drizzle"),at.join(Er,"..","..","templates","orm","drizzle")];for(let t of e)if($t.existsSync(t))return t;return null}function vr(e,t){$t.mkdirSync(t,{recursive:!0});for(let n of $t.readdirSync(e,{withFileTypes:!0})){let o=at.join(e,n.name),r=at.join(t,n.name);n.isDirectory()?vr(o,r):$t.copyFileSync(o,r)}}async function br(e,t,n){if(t!=="drizzle")return{applied:!1};if(n!=="postgresql")return{applied:!1,reason:`Drizzle template currently targets Postgres only; --db=${n} keeps Prisma as sole ORM`};let o=nc();if(!o)return{applied:!1,reason:"Drizzle template directory not found in package \u2014 bundling error"};let r=at.join(e,"packages","platform","db-drizzle");return vr(o,r),{applied:!0}}import ye from"fs";import Pt from"path";var oc=["stripe","lemonsqueezy","chinapay","polar"];function _r(e){ye.existsSync(e)&&ye.rmSync(e,{recursive:!0,force:!0})}function rc(e){switch(e){case"stripe":return["stripe"];case"lemon":return["lemonsqueezy"];case"wechat":case"alipay":return["chinapay"]}}function sc(e,t){let n=Pt.join(e,".env.example");ye.existsSync(n)?ye.appendFileSync(n,`
1753
+ `+t):ye.writeFileSync(n,t)}function ic(e){switch(e){case"stripe":return`# Stripe
1742
1754
  STRIPE_SECRET_KEY=
1743
1755
  STRIPE_WEBHOOK_SECRET=
1744
1756
  `;case"lemon":return`# Lemon Squeezy
@@ -1753,14 +1765,14 @@ CHINAPAY_WECHAT_ENABLED=true
1753
1765
  CHINAPAY_APP_ID=
1754
1766
  CHINAPAY_APP_SECRET=
1755
1767
  CHINAPAY_ALIPAY_ENABLED=true
1756
- `}}async function gr(e,t){let n=_t.join(e,"packages","commerce","billing");if(!ge.existsSync(n))return;if(t==="none"){mr(n);return}let o=_t.join(n,"src"),r=new Set(qa(t));for(let i of Ya)r.has(i)||mr(_t.join(o,i));let s=_t.join(o,"checkout","types.ts");if(ge.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",a=ge.readFileSync(s,"utf8"),c=a.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);c!==a&&ge.writeFileSync(s,c)}Ga(e,Ha(t))}import Pe from"fs";import it from"path";var Sr=new Set(["siliconflow","volcengine-ark","bailian","moonshot","sensetime"]),_n=/@sailor:([^\s*]+)/;function Wa(e,t){let{providerIds:n,customEndpoint:o}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:n.includes(r)}}if(e==="cn-compatible"){let r=n.some(s=>Sr.has(s));return{marker:e,keep:r||!!o}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:n.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!o}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function fr(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function yr(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function hr(e,t){let n=e.split(`
1757
- `),o=[],r=e.includes("#"),s=0;for(;s<n.length;){let i=n[s],a=i.match(_n);if(!a){o.push(i),s++;continue}let{marker:c,keep:p}=Wa(a[1],t);if(c==="registry-entries"){o.push(r?yr(i):fr(i)),s++;continue}if(p){let d=r?yr(i):fr(i);d.trim().length>0&&o.push(d);let u=s+1;for(;u<n.length&&n[u].trim()!==""&&!_n.test(n[u]);)o.push(n[u]),u++;u<n.length&&n[u].trim()===""&&(o.push(n[u]),u++),s=u}else{let d=s+1;for(;d<n.length&&n[d].trim()!==""&&!_n.test(n[d]);)d++;d<n.length&&n[d].trim()===""&&d++,s=d}}return Xa(o.join(`
1758
- `),t)}function Xa(e,t){let{providerIds:n,customEndpoint:o}=t,r=new Set;for(let p of n)["openai","anthropic","google","mistral","xai"].includes(p)&&r.add(p),r.add(p.replace(/-/g,"_")),r.add(p);o&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let c=i[1].split(`
1759
- `).filter(p=>{let d=p.trim();if(d===""||d.startsWith("//"))return!0;let u=d.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return u?r.has(u[1]):!0}).join(`
1760
- `);return e.replace(s,`createProviderRegistry({${c}})`)}function za(e,t){let n=it.join(t,"registry.ts.template"),o=Pe.readFileSync(n,"utf-8");return hr(o,e)}function Ja(e,t){let n=it.join(t,".env.example.template"),o=Pe.readFileSync(n,"utf-8");return hr(o,e)}async function Er(e,t,n){let o=za(t,n),r=Ja(t,n),s=it.join(e,"packages/ai/agents/src");await Pe.promises.mkdir(s,{recursive:!0}),await Pe.promises.writeFile(it.join(s,"registry.ts"),o),await Pe.promises.appendFile(it.join(e,".env.example"),`
1761
- `+r);let i={ai:"latest"},{providerIds:a,customEndpoint:c}=t;(a.includes("openai")||c||a.some(d=>Sr.has(d)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),a.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),a.includes("google")&&(i["@ai-sdk/google"]="latest"),a.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),a.includes("xai")&&(i["@ai-sdk/openai"]="latest");let p=it.join(e,"package.json");if(Pe.existsSync(p)){let d=JSON.parse(await Pe.promises.readFile(p,"utf-8"));d.dependencies||(d.dependencies={});for(let[u,A]of Object.entries(i))d.dependencies[u]=A;await Pe.promises.writeFile(p,JSON.stringify(d,null,2)+`
1762
- `)}}import y from"fs";import f from"path";function vr(e,t){if(!y.existsSync(e))return;let n=y.readdirSync(e);for(let o of n){let r=f.join(e,o);y.statSync(r).isDirectory()?vr(r,t):t(r)}}async function br(e,t){let n=f.join(e,"package.json");if(!y.existsSync(n))return;let o=JSON.parse(y.readFileSync(n,"utf8"));if(t.orm!=="prisma"){let r=f.join(e,"packages","db");if(y.existsSync(r)){let s=f.join(r,"prisma");y.existsSync(s)&&y.rmSync(s,{recursive:!0,force:!0});let i=f.join(r,"package.json");if(y.existsSync(i)){let c=JSON.parse(y.readFileSync(i,"utf8"));c.dependencies&&delete c.dependencies["@prisma/client"],c.devDependencies&&delete c.devDependencies.prisma,y.writeFileSync(i,JSON.stringify(c,null,2)+`
1763
- `)}let a=f.join(r,"src","index.ts");y.existsSync(a)&&y.writeFileSync(a,`
1768
+ `}}async function wr(e,t){let n=Pt.join(e,"packages","commerce","billing");if(!ye.existsSync(n))return;if(t==="none"){_r(n);return}let o=Pt.join(n,"src"),r=new Set(rc(t));for(let i of oc)r.has(i)||_r(Pt.join(o,i));let s=Pt.join(o,"checkout","types.ts");if(ye.existsSync(s)){let i=t==="stripe"?"stripe":t==="lemon"?"lemonsqueezy":"chinapay",a=ye.readFileSync(s,"utf8"),c=a.replace(/export type CheckoutProviderType\s*=\s*[^;]+;/,`export type CheckoutProviderType = "${i}";`);c!==a&&ye.writeFileSync(s,c)}sc(e,ic(t))}import Ce from"fs";import ct from"path";var Cr=new Set(["siliconflow","volcengine-ark","bailian","moonshot","sensetime"]),In=/@sailor:([^\s*]+)/;function ac(e,t){let{providerIds:n,customEndpoint:o}=t;if(e.startsWith("provider:")){let r=e.slice(9);return{marker:e,keep:n.includes(r)}}if(e==="cn-compatible"){let r=n.some(s=>Cr.has(s));return{marker:e,keep:r||!!o}}if(e.startsWith("cn-instance:")){let r=e.slice(12);return{marker:e,keep:n.includes(r)}}return e==="custom-endpoint"?{marker:e,keep:!!o}:e==="registry-entries"?{marker:e,keep:!0}:{marker:e,keep:!0}}function Pr(e){return e.replace(/\s*\/\/\s*@sailor:[^\n]*$/,"")}function Ar(e){return e.replace(/\s*#\s*@sailor:[^\n]*$/,"")}function Ir(e,t){let n=e.split(`
1769
+ `),o=[],r=e.includes("#"),s=0;for(;s<n.length;){let i=n[s],a=i.match(In);if(!a){o.push(i),s++;continue}let{marker:c,keep:p}=ac(a[1],t);if(c==="registry-entries"){o.push(r?Ar(i):Pr(i)),s++;continue}if(p){let m=r?Ar(i):Pr(i);m.trim().length>0&&o.push(m);let d=s+1;for(;d<n.length&&n[d].trim()!==""&&!In.test(n[d]);)o.push(n[d]),d++;d<n.length&&n[d].trim()===""&&(o.push(n[d]),d++),s=d}else{let m=s+1;for(;m<n.length&&n[m].trim()!==""&&!In.test(n[m]);)m++;m<n.length&&n[m].trim()===""&&m++,s=m}}return cc(o.join(`
1770
+ `),t)}function cc(e,t){let{providerIds:n,customEndpoint:o}=t,r=new Set;for(let p of n)["openai","anthropic","google","mistral","xai"].includes(p)&&r.add(p),r.add(p.replace(/-/g,"_")),r.add(p);o&&r.add("custom");let s=/createProviderRegistry\(\{([\s\S]*?)\}\)/,i=e.match(s);if(!i)return e;let c=i[1].split(`
1771
+ `).filter(p=>{let m=p.trim();if(m===""||m.startsWith("//"))return!0;let d=m.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*,?$/);return d?r.has(d[1]):!0}).join(`
1772
+ `);return e.replace(s,`createProviderRegistry({${c}})`)}function pc(e,t){let n=ct.join(t,"registry.ts.template"),o=Ce.readFileSync(n,"utf-8");return Ir(o,e)}function lc(e,t){let n=ct.join(t,".env.example.template"),o=Ce.readFileSync(n,"utf-8");return Ir(o,e)}async function Tr(e,t,n){let o=pc(t,n),r=lc(t,n),s=ct.join(e,"packages/ai/agents/src");await Ce.promises.mkdir(s,{recursive:!0}),await Ce.promises.writeFile(ct.join(s,"registry.ts"),o),await Ce.promises.appendFile(ct.join(e,".env.example"),`
1773
+ `+r);let i={ai:"latest"},{providerIds:a,customEndpoint:c}=t;(a.includes("openai")||c||a.some(m=>Cr.has(m)))&&(i["@ai-sdk/openai"]="latest",i["@ai-sdk/openai-compatible"]="latest"),a.includes("anthropic")&&(i["@ai-sdk/anthropic"]="latest"),a.includes("google")&&(i["@ai-sdk/google"]="latest"),a.includes("mistral")&&(i["@ai-sdk/mistral"]="latest"),a.includes("xai")&&(i["@ai-sdk/openai"]="latest");let p=ct.join(e,"package.json");if(Ce.existsSync(p)){let m=JSON.parse(await Ce.promises.readFile(p,"utf-8"));m.dependencies||(m.dependencies={});for(let[d,v]of Object.entries(i))m.dependencies[d]=v;await Ce.promises.writeFile(p,JSON.stringify(m,null,2)+`
1774
+ `)}}import S from"fs";import f from"path";function xr(e,t){if(!S.existsSync(e))return;let n=S.readdirSync(e);for(let o of n){let r=f.join(e,o);S.statSync(r).isDirectory()?xr(r,t):t(r)}}async function Rr(e,t){let n=f.join(e,"package.json");if(!S.existsSync(n))return;let o=JSON.parse(S.readFileSync(n,"utf8"));if(t.orm!=="prisma"){let r=f.join(e,"packages","db");if(S.existsSync(r)){let s=f.join(r,"prisma");S.existsSync(s)&&S.rmSync(s,{recursive:!0,force:!0});let i=f.join(r,"package.json");if(S.existsSync(i)){let c=JSON.parse(S.readFileSync(i,"utf8"));c.dependencies&&delete c.dependencies["@prisma/client"],c.devDependencies&&delete c.devDependencies.prisma,S.writeFileSync(i,JSON.stringify(c,null,2)+`
1775
+ `)}let a=f.join(r,"src","index.ts");S.existsSync(a)&&S.writeFileSync(a,`
1764
1776
  export const prisma = {} as any;
1765
1777
  export const db = {} as any;
1766
1778
  export type PrismaClient = any;
@@ -1806,7 +1818,7 @@ export type UsageAggregate = any;
1806
1818
  export type UsageLedgerEntry = any;
1807
1819
  export type UsageType = any;
1808
1820
  export type UsageLedgerSource = any;
1809
- `)}o.scripts?.postinstall&&(o.scripts.postinstall=o.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=f.join(e,"apps");if(y.existsSync(r)){let s=y.readdirSync(r);for(let i of s){let a=f.join(r,i);if(!y.statSync(a).isDirectory())continue;let c=f.join(a,"src","app");if(!y.existsSync(c))continue;["[lang]","[locale]"].forEach(S=>{let m=f.join(c,S);if(y.existsSync(m)){let _=y.readdirSync(m);for(let H of _)y.renameSync(f.join(m,H),f.join(c,H));y.rmdirSync(m)}}),["src/middleware.ts","middleware.ts"].forEach(S=>{let m=f.join(a,S);y.existsSync(m)&&y.rmSync(m)});let p=f.join(a,"src","lib");y.existsSync(p)||y.mkdirSync(p,{recursive:!0});let d=f.join(p,"mock-i18n.ts");y.writeFileSync(d,`
1821
+ `)}o.scripts?.postinstall&&(o.scripts.postinstall=o.scripts.postinstall.replace(/prisma generate/g,'echo "ORM Disabled"'))}if(!t.i18n){let r=f.join(e,"apps");if(S.existsSync(r)){let s=S.readdirSync(r);for(let i of s){let a=f.join(r,i);if(!S.statSync(a).isDirectory())continue;let c=f.join(a,"src","app");if(!S.existsSync(c))continue;["[lang]","[locale]"].forEach(E=>{let l=f.join(c,E);if(S.existsSync(l)){let y=S.readdirSync(l);for(let U of y)S.renameSync(f.join(l,U),f.join(c,U));S.rmdirSync(l)}}),["src/middleware.ts","middleware.ts"].forEach(E=>{let l=f.join(a,E);S.existsSync(l)&&S.rmSync(l)});let p=f.join(a,"src","lib");S.existsSync(p)||S.mkdirSync(p,{recursive:!0});let m=f.join(p,"mock-i18n.ts");S.writeFileSync(m,`
1810
1822
  import React from 'react';
1811
1823
  export function useTranslations(namespace?: string): any { return (key: string) => key; }
1812
1824
  export function useLocale() { return 'en'; }
@@ -1824,7 +1836,7 @@ export const useRouter = () => ({ push: (...args: any[]) => {}, replace: (...arg
1824
1836
  export default function createMiddleware(...args: any[]) { return (req: any) => req; }
1825
1837
  export function createNavigation(...args: any[]) { return { Link, redirect, usePathname, useRouter, getPathname: () => '/' }; }
1826
1838
  export function defineRouting<T>(config: T): T { return config; }
1827
- `);let A=f.join(p,"mock-i18n.d.ts");y.writeFileSync(A,`declare module '@/lib/mock-i18n' {
1839
+ `);let v=f.join(p,"mock-i18n.d.ts");S.writeFileSync(v,`declare module '@/lib/mock-i18n' {
1828
1840
  export function useTranslations(namespace?: string): any;
1829
1841
  export function useLocale(): string;
1830
1842
  export const NextIntlClientProvider: React.FC<any>;
@@ -1842,19 +1854,19 @@ export function defineRouting<T>(config: T): T { return config; }
1842
1854
  export function createNavigation(...args: any[]): any;
1843
1855
  export function defineRouting<T>(config: T): T;
1844
1856
  }
1845
- `),y.writeFileSync(f.join(p,"mock-i18n-index.ts"),`
1857
+ `),S.writeFileSync(f.join(p,"mock-i18n-index.ts"),`
1846
1858
  export * from './mock-i18n';
1847
1859
  export { default } from './mock-i18n';
1848
- `);let h=f.join(a,"tsconfig.json");if(y.existsSync(h))try{let S=y.readFileSync(h,"utf8");if(S.includes('"paths": {')){let m=S.replace(/"paths":\s*\{/,`"paths": {
1860
+ `);let g=f.join(a,"tsconfig.json");if(S.existsSync(g))try{let E=S.readFileSync(g,"utf8");if(E.includes('"paths": {')){let l=E.replace(/"paths":\s*\{/,`"paths": {
1849
1861
  "next-intl": ["./src/lib/mock-i18n"],
1850
- "next-intl/*": ["./src/lib/mock-i18n"],`);y.writeFileSync(h,m)}}catch{}let g=f.join(a,"src");y.existsSync(g)&&vr(g,S=>{if(!S.endsWith(".ts")&&!S.endsWith(".tsx"))return;let m=y.readFileSync(S,"utf8"),_=!1;S.endsWith("src/app/layout.tsx")&&m.includes("../providers")&&(m=m.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),_=!0),m=m.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),m=m.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),m.match(/locale\s*:\s*any/)&&(m=m.replace(/locale\s*:\s*any/g,"locale: string"),_=!0),m.match(/lang\s*:\s*any/)&&(m=m.replace(/lang\s*:\s*any/g,"lang: string"),_=!0),m.match(/requestLocale\s*:\s*any/)&&(m=m.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),_=!0),m.match(/\(locale\s*=\s*(.*)\)/)&&(m=m.replace(/\(locale\s*=\s*(.*)\)/g,"() "),_=!0),m.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(m=m.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),_=!0),(S.endsWith("src/app/layout.tsx")||S.endsWith("src/app/sitemap.ts")||S.endsWith("src/app/robots.ts")||S.endsWith("src/components/ui/locale-switcher.tsx")||S.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(m=m.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),m=m.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),m=m.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),m=m.replace(/\(l\)\s*=>/g,"(l: any) =>"),_=!0),S.endsWith("src/i18n/request.ts")&&(m=m.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),_=!0),(m.match(/locale\s*:/)||m.match(/lang\s*:/))&&(_=!0),_&&y.writeFileSync(S,m)});let E=f.join(a,"package.json");if(y.existsSync(E)){let S=JSON.parse(y.readFileSync(E,"utf8"));S.dependencies&&delete S.dependencies["next-intl"],y.writeFileSync(E,JSON.stringify(S,null,2)+`
1851
- `)}}}}y.writeFileSync(n,JSON.stringify(o,null,2)+`
1852
- `)}function b(e){try{y.rmSync(e,{recursive:!0,force:!0})}catch{}}function Qa(e,t){if(!y.existsSync(e))return;let n;try{n=JSON.parse(y.readFileSync(e,"utf8"))}catch{return}let o=!1;if(n.dependencies&&t in n.dependencies){let{[t]:r,...s}=n.dependencies;n={...n,dependencies:s},o=!0}if(n.devDependencies&&t in n.devDependencies){let{[t]:r,...s}=n.devDependencies;n={...n,devDependencies:s},o=!0}o&&y.writeFileSync(e,JSON.stringify(n,null,2)+`
1853
- `)}function _r(e,t){t.cronJobs||(b(f.join(e,"apps/web/src/app/api/cron")),b(f.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(b(f.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),b(f.join(e,"apps/web/src/app/api/audit-logs")),b(f.join(e,"apps/web/src/components/audit"))),t.apiKeys||(b(f.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),b(f.join(e,"apps/web/src/app/api/api-keys")),b(f.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(b(f.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),b(f.join(e,"apps/web/src/app/api/webhooks")),b(f.join(e,"apps/web/src/components/webhooks")),b(f.join(e,"packages/integrations/webhooks"))),t.commandPalette||(b(f.join(e,"apps/web/src/components/command-palette")),b(f.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(b(f.join(e,"apps/landing/src/components/cookie-consent-banner.tsx")),b(f.join(e,"apps/landing/src/components/__tests__/cookie-consent-banner.test.tsx")),b(f.join(e,"apps/landing/src/lib/cookie-consent.ts")),b(f.join(e,"apps/landing/src/lib/__tests__/cookie-consent.test.ts")),b(f.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(b(f.join(e,"apps/landing/src/app/[lang]/(legal)/legal")),b(f.join(e,"apps/landing/src/lib/legal-documents.ts")),b(f.join(e,"apps/landing/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(b(f.join(e,"packages/ops/china-compliance")),b(f.join(e,"apps/landing/src/components/icp-footer.tsx")),b(f.join(e,"apps/landing/src/components/__tests__/icp-footer.test.tsx")),b(f.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),b(f.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),Qa(f.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import at from"fs";import wr from"path";var Pr=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function Za(e){let t=Pr.exec(e);if(!t)return null;let[,n,o]=t,r=o.split("|").map(s=>s.trim()).filter(Boolean);return{flag:n,values:r}}function ec(e){return e.replace(Pr,"").replace(/^\n/,"")}function wn(e,t){let n={kept:[],removed:[],skipped:[]};if(!at.existsSync(e))return n;let o=at.readdirSync(e,{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,s)=>r.name.localeCompare(s.name));for(let r of o){let s=wr.join(e,r.name),i=wr.join(s,"migration.sql");if(!at.existsSync(i)){n.skipped.push(r.name);continue}let a=at.readFileSync(i,"utf8"),c=Za(a);if(!c){n.skipped.push(r.name);continue}let p=t[c.flag];if(p!==void 0&&c.values.includes(p)){at.writeFileSync(i,ec(a)),n.kept.push(r.name);continue}at.rmSync(s,{recursive:!0,force:!0}),n.removed.push(r.name)}return n}import{getSchema as tc,printSchema as nc}from"@mrleebo/prisma-ast";var oc=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function rc(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function sc(e){let t=oc.exec(e.trim());if(!t)return null;let[,n,o]=t,r=o.split("|").map(s=>s.trim()).filter(s=>s.length>0);return{flag:n,values:r}}function ic(e,t){for(let n=t-1;n>=0;n--){let o=e[n];if(o.type==="comment"){let r=sc(o.text);if(r)return{annIndex:n,parsed:r};continue}break}return null}function ac(e){return e.type==="model"||e.type==="enum"}function Pn(e,t){let n=tc(e),o=new Set;for(let a=0;a<n.list.length;a++){let c=n.list[a];if(!ac(c))continue;let p=ic(n.list,a);if(!p)continue;let d=t[p.parsed.flag];if(d!==void 0&&p.parsed.values.includes(d))o.add(p.annIndex);else{o.add(a);for(let h=a-1;h>=0;h--){let g=n.list[h];if(rc(g)){o.add(h);continue}break}let A=n.list[a+1];A&&A.type==="break"&&o.add(a+1)}}let r=n.list.filter((a,c)=>!o.has(c)),s=[];for(let a of r){let c=s[s.length-1];a.type==="break"&&c&&c.type==="break"||s.push(a)}return nc({type:"schema",list:s})}import ct from"fs";import Cr from"path";var jt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function Ar(e){return jt.find(t=>t.id===e)}var fu=jt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Ir(e){return ct.existsSync(e)?ct.readFileSync(e,"utf-8"):null}function cc(e,t){let n=Cr.join(e,".env.example"),o=Ir(n);if(o===null)return;let r=`# Queue: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1854
- `);ct.appendFileSync(n,s)}function pc(e,t,n){let o=Cr.join(e,".env.example"),r=Ir(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?ct.writeFileSync(o,r.replace(s,`${t}="${n}"`)):ct.appendFileSync(o,`${t}="${n}"
1855
- `)}async function xr(e,t,n){let o=Le(e,"queue");if(t==="none"){o&&ct.rmSync(o,{recursive:!0,force:!0});return}let r=Ar(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${jt.map(s=>s.id).join(", ")}`);o&&(cc(e,r),pc(e,"QUEUE_PROVIDER",t))}import fe from"fs";import Ae from"path";import{fileURLToPath as lc}from"url";var dc=lc(import.meta.url),Rr=Ae.dirname(dc),uc=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,mc=["backends/gateway","infra","e2e","tests"];function gc(){let e=[Ae.join(Rr,"..","templates"),Ae.join(Rr,"..","..","templates")];for(let t of e)if(fe.existsSync(t))return t;return e[0]}async function Tr(e,t){let n=gc(),o=[],r=[],s=[...mc,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let a=Ae.join(n,i);if(!fe.existsSync(a)){r.push(i);continue}let c=Ae.join(e,i);kr(a,c),Nr(c,{"{PRODUCT_NAME}":t.projectName}),o.push(i)}return{applied:o,skipped:r}}function kr(e,t){fe.mkdirSync(t,{recursive:!0});for(let n of fe.readdirSync(e,{withFileTypes:!0})){let o=Ae.join(e,n.name),r=Ae.join(t,n.name);n.isDirectory()?kr(o,r):fe.existsSync(r)||fe.copyFileSync(o,r)}}function Nr(e,t){for(let n of fe.readdirSync(e,{withFileTypes:!0})){let o=Ae.join(e,n.name);if(n.isDirectory()){Nr(o,t);continue}if(!uc.test(n.name))continue;let r=fe.readFileSync(o,"utf-8"),s=!1;for(let[i,a]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(a),s=!0);s&&fe.writeFileSync(o,r)}}import pt from"fs";import Lr from"path";var Bt=[{id:"meilisearch",name:"Meilisearch",region:"both",envVars:["MEILISEARCH_HOST","MEILISEARCH_MASTER_KEY"],docs:"https://docs.meilisearch.com",description:"Self-hostable search"},{id:"typesense",name:"Typesense",region:"both",envVars:["TYPESENSE_HOST","TYPESENSE_PORT","TYPESENSE_PROTOCOL","TYPESENSE_API_KEY"],docs:"https://typesense.org/docs",description:"Open-source search"},{id:"algolia",name:"Algolia",region:"global",envVars:["ALGOLIA_APP_ID","ALGOLIA_ADMIN_API_KEY","ALGOLIA_SEARCH_API_KEY"],docs:"https://www.algolia.com/doc/",description:"Managed search as a service"},{id:"pgvector",name:"pgvector (Postgres)",region:"both",envVars:["DATABASE_URL"],docs:"https://github.com/pgvector/pgvector",description:"Postgres vector + full-text"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip search package"}];function Or(e){return Bt.find(t=>t.id===e)}var Cu=Bt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Ur(e){return pt.existsSync(e)?pt.readFileSync(e,"utf-8"):null}function fc(e,t){let n=Lr.join(e,".env.example"),o=Ur(n);if(o===null)return;let r=`# Search: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1856
- `);pt.appendFileSync(n,s)}function yc(e,t,n){let o=Lr.join(e,".env.example"),r=Ur(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?pt.writeFileSync(o,r.replace(s,`${t}="${n}"`)):pt.appendFileSync(o,`${t}="${n}"
1857
- `)}async function Dr(e,t,n){let o=Le(e,"search");if(t==="none"){o&&pt.rmSync(o,{recursive:!0,force:!0});return}let r=Or(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Bt.map(s=>s.id).join(", ")}`);o&&(fc(e,r),yc(e,"SEARCH_PROVIDER",t))}import Ce from"fs";import Ve from"path";function Sc(e){let t=[Ve.join(e,"packages","db"),Ve.join(e,"apps","web")];for(let n of t){let o=Ve.join(n,"prisma","schema.prisma");if(Ce.existsSync(o))return{packageDir:n,seedPath:Ve.join(n,"prisma","seed.ts"),packageJsonPath:Ve.join(n,"package.json")}}return null}function hc(e){try{let t=Ce.readFileSync(e,"utf8"),n=new Set,o=/^\s*model\s+(\w+)\s*\{/gm,r=o.exec(t);for(;r;)n.add(r[1]),r=o.exec(t);return n}catch{return new Set}}function Ec(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1862
+ "next-intl/*": ["./src/lib/mock-i18n"],`);S.writeFileSync(g,l)}}catch{}let h=f.join(a,"src");S.existsSync(h)&&xr(h,E=>{if(!E.endsWith(".ts")&&!E.endsWith(".tsx"))return;let l=S.readFileSync(E,"utf8"),y=!1;E.endsWith("src/app/layout.tsx")&&l.includes("../providers")&&(l=l.replace(/from\s+['"]\.\.\/providers['"]/g,"from './providers'"),y=!0),l=l.replace(/params:\s*Promise<\{[^}]*(lang|locale)[^}]*\}>/g,"params: any"),l=l.replace(/\(\{\s*params\s*\}\s*:\s*\{\s*params:\s*any\s*\}\)/g,"({ params }: any)"),l.match(/locale\s*:\s*any/)&&(l=l.replace(/locale\s*:\s*any/g,"locale: string"),y=!0),l.match(/lang\s*:\s*any/)&&(l=l.replace(/lang\s*:\s*any/g,"lang: string"),y=!0),l.match(/requestLocale\s*:\s*any/)&&(l=l.replace(/requestLocale\s*:\s*any/g,"requestLocale: string"),y=!0),l.match(/\(locale\s*=\s*(.*)\)/)&&(l=l.replace(/\(locale\s*=\s*(.*)\)/g,"() "),y=!0),l.match(/export\s+default\s+async\s+function\s+LangLayout/)&&(l=l.replace(/export\s+default\s+async\s+function\s+LangLayout\s*\(\s*\{\s*children\s*,\s*params\s*\}\s*:\s*LangLayoutProps\s*\)/g,"export default async function LangLayout({ children }: { children: React.ReactNode })"),y=!0),(E.endsWith("src/app/layout.tsx")||E.endsWith("src/app/sitemap.ts")||E.endsWith("src/app/robots.ts")||E.endsWith("src/components/ui/locale-switcher.tsx")||E.endsWith("src/app/(marketing)/blog/[slug]/page.tsx"))&&(l=l.replace(/const\s+\{\s*lang\s*\}\s*=\s*(await\s+)?params;?/g,'const lang = "en";'),l=l.replace(/const\s+\{\s*locale\s*\}\s*=\s*(await\s+)?params;?/g,'const locale = "en";'),l=l.replace(/const\s+locale\s*=\s*lang\s+as\s+Locale;?/g,'const locale = "en";'),l=l.replace(/\(l\)\s*=>/g,"(l: any) =>"),y=!0),E.endsWith("src/i18n/request.ts")&&(l=l.replace(/async\s*\(\{\s*requestLocale\s*\}\)/g,"async ({ requestLocale }: any)"),y=!0),(l.match(/locale\s*:/)||l.match(/lang\s*:/))&&(y=!0),y&&S.writeFileSync(E,l)});let P=f.join(a,"package.json");if(S.existsSync(P)){let E=JSON.parse(S.readFileSync(P,"utf8"));E.dependencies&&delete E.dependencies["next-intl"],S.writeFileSync(P,JSON.stringify(E,null,2)+`
1863
+ `)}}}}S.writeFileSync(n,JSON.stringify(o,null,2)+`
1864
+ `)}function w(e){try{S.rmSync(e,{recursive:!0,force:!0})}catch{}}function dc(e,t){if(!S.existsSync(e))return;let n;try{n=JSON.parse(S.readFileSync(e,"utf8"))}catch{return}let o=!1;if(n.dependencies&&t in n.dependencies){let{[t]:r,...s}=n.dependencies;n={...n,dependencies:s},o=!0}if(n.devDependencies&&t in n.devDependencies){let{[t]:r,...s}=n.devDependencies;n={...n,devDependencies:s},o=!0}o&&S.writeFileSync(e,JSON.stringify(n,null,2)+`
1865
+ `)}function kr(e,t){t.cronJobs||(w(f.join(e,"apps/web/src/app/api/cron")),w(f.join(e,"packages/integrations/queue/src/scheduled"))),t.auditLog||(w(f.join(e,"apps/web/src/app/[locale]/(app)/settings/audit-log")),w(f.join(e,"apps/web/src/app/api/audit-logs")),w(f.join(e,"apps/web/src/components/audit"))),t.apiKeys||(w(f.join(e,"apps/web/src/app/[locale]/(app)/settings/api-keys")),w(f.join(e,"apps/web/src/app/api/api-keys")),w(f.join(e,"apps/web/src/components/api-keys"))),t.webhooks||(w(f.join(e,"apps/web/src/app/[locale]/(app)/settings/webhooks")),w(f.join(e,"apps/web/src/app/api/webhooks")),w(f.join(e,"apps/web/src/components/webhooks")),w(f.join(e,"packages/integrations/webhooks"))),t.commandPalette||(w(f.join(e,"apps/web/src/components/command-palette")),w(f.join(e,"apps/web/src/app/[locale]/providers/command-palette-mount.tsx"))),t.cookieConsent||(w(f.join(e,"apps/landing/src/components/cookie-consent-banner.tsx")),w(f.join(e,"apps/landing/src/components/__tests__/cookie-consent-banner.test.tsx")),w(f.join(e,"apps/landing/src/lib/cookie-consent.ts")),w(f.join(e,"apps/landing/src/lib/__tests__/cookie-consent.test.ts")),w(f.join(e,"apps/web/src/app/api/cookie-consent"))),t.legalPages||(w(f.join(e,"apps/landing/src/app/[lang]/(legal)/legal")),w(f.join(e,"apps/landing/src/lib/legal-documents.ts")),w(f.join(e,"apps/landing/src/lib/__tests__/legal-documents.test.ts"))),t.chinaCompliance||(w(f.join(e,"packages/ops/china-compliance")),w(f.join(e,"apps/landing/src/components/icp-footer.tsx")),w(f.join(e,"apps/landing/src/components/__tests__/icp-footer.test.tsx")),w(f.join(e,"apps/web/src/components/auth/wechat-login-button.tsx")),w(f.join(e,"apps/web/src/components/auth/__tests__/wechat-login-button.test.tsx")),dc(f.join(e,"apps/web/package.json"),"@nebutra/china-compliance"))}import pt from"fs";import Nr from"path";var Or=/^--\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/m;function uc(e){let t=Or.exec(e);if(!t)return null;let[,n,o]=t,r=o.split("|").map(s=>s.trim()).filter(Boolean);return{flag:n,values:r}}function mc(e){return e.replace(Or,"").replace(/^\n/,"")}function Tn(e,t){let n={kept:[],removed:[],skipped:[]};if(!pt.existsSync(e))return n;let o=pt.readdirSync(e,{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,s)=>r.name.localeCompare(s.name));for(let r of o){let s=Nr.join(e,r.name),i=Nr.join(s,"migration.sql");if(!pt.existsSync(i)){n.skipped.push(r.name);continue}let a=pt.readFileSync(i,"utf8"),c=uc(a);if(!c){n.skipped.push(r.name);continue}let p=t[c.flag];if(p!==void 0&&c.values.includes(p)){pt.writeFileSync(i,mc(a)),n.kept.push(r.name);continue}pt.rmSync(s,{recursive:!0,force:!0}),n.removed.push(r.name)}return n}import{getSchema as gc,printSchema as fc}from"@mrleebo/prisma-ast";var yc=/^\/\/\/\s*@conditional\(([A-Za-z][A-Za-z0-9_-]*)=([^)]+)\)\s*$/;function Sc(e){return e.type==="comment"&&e.text.trim().startsWith("//")}function hc(e){let t=yc.exec(e.trim());if(!t)return null;let[,n,o]=t,r=o.split("|").map(s=>s.trim()).filter(s=>s.length>0);return{flag:n,values:r}}function Ec(e,t){for(let n=t-1;n>=0;n--){let o=e[n];if(o.type==="comment"){let r=hc(o.text);if(r)return{annIndex:n,parsed:r};continue}break}return null}function vc(e){return e.type==="model"||e.type==="enum"}function xn(e,t){let n=gc(e),o=new Set;for(let a=0;a<n.list.length;a++){let c=n.list[a];if(!vc(c))continue;let p=Ec(n.list,a);if(!p)continue;let m=t[p.parsed.flag];if(m!==void 0&&p.parsed.values.includes(m))o.add(p.annIndex);else{o.add(a);for(let g=a-1;g>=0;g--){let h=n.list[g];if(Sc(h)){o.add(g);continue}break}let v=n.list[a+1];v&&v.type==="break"&&o.add(a+1)}}let r=n.list.filter((a,c)=>!o.has(c)),s=[];for(let a of r){let c=s[s.length-1];a.type==="break"&&c&&c.type==="break"||s.push(a)}return fc({type:"schema",list:s})}import lt from"fs";import Ur from"path";var Vt=[{id:"qstash",name:"Upstash QStash",region:"both",envVars:["QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY"],docs:"https://upstash.com/docs/qstash",description:"Serverless HTTP-based queue"},{id:"bullmq",name:"BullMQ",region:"both",envVars:["REDIS_URL"],docs:"https://docs.bullmq.io",description:"Redis-backed job queue"},{id:"sqs",name:"AWS SQS",region:"global",envVars:["AWS_SQS_QUEUE_URL","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],docs:"https://docs.aws.amazon.com/AWSSimpleQueueService/",description:"AWS managed queue"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip queue package"}];function Lr(e){return Vt.find(t=>t.id===e)}var Nu=Vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Dr(e){return lt.existsSync(e)?lt.readFileSync(e,"utf-8"):null}function bc(e,t){let n=Ur.join(e,".env.example"),o=Dr(n);if(o===null)return;let r=`# Queue: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1866
+ `);lt.appendFileSync(n,s)}function _c(e,t,n){let o=Ur.join(e,".env.example"),r=Dr(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?lt.writeFileSync(o,r.replace(s,`${t}="${n}"`)):lt.appendFileSync(o,`${t}="${n}"
1867
+ `)}async function Mr(e,t,n){let o=De(e,"queue");if(t==="none"){o&&lt.rmSync(o,{recursive:!0,force:!0});return}let r=Lr(t);if(!r)throw new Error(`Unknown queue provider "${t}". Valid ids: ${Vt.map(s=>s.id).join(", ")}`);o&&(bc(e,r),_c(e,"QUEUE_PROVIDER",t))}import Se from"fs";import Ie from"path";import{fileURLToPath as wc}from"url";var Pc=wc(import.meta.url),Fr=Ie.dirname(Pc),Ac=/\.(md|mdx|json|ts|tsx|js|mjs|cjs|yaml|yml|css|html|toml|py)$/,Cc=["backends/gateway","infra","e2e","tests"];function Ic(){let e=[Ie.join(Fr,"..","templates"),Ie.join(Fr,"..","..","templates")];for(let t of e)if(Se.existsSync(t))return t;return e[0]}async function jr(e,t){let n=Ic(),o=[],r=[],s=[...Cc,...t.withWorkflows?["workflows"]:[],...t.withPythonBackend?["backends/python"]:[]];for(let i of s){let a=Ie.join(n,i);if(!Se.existsSync(a)){r.push(i);continue}let c=Ie.join(e,i);Br(a,c),$r(c,{"{PRODUCT_NAME}":t.projectName}),o.push(i)}return{applied:o,skipped:r}}function Br(e,t){Se.mkdirSync(t,{recursive:!0});for(let n of Se.readdirSync(e,{withFileTypes:!0})){let o=Ie.join(e,n.name),r=Ie.join(t,n.name);n.isDirectory()?Br(o,r):Se.existsSync(r)||Se.copyFileSync(o,r)}}function $r(e,t){for(let n of Se.readdirSync(e,{withFileTypes:!0})){let o=Ie.join(e,n.name);if(n.isDirectory()){$r(o,t);continue}if(!Ac.test(n.name))continue;let r=Se.readFileSync(o,"utf-8"),s=!1;for(let[i,a]of Object.entries(t))r.includes(i)&&(r=r.split(i).join(a),s=!0);s&&Se.writeFileSync(o,r)}}import dt from"fs";import Kr from"path";var Kt=[{id:"meilisearch",name:"Meilisearch",region:"both",envVars:["MEILISEARCH_HOST","MEILISEARCH_MASTER_KEY"],docs:"https://docs.meilisearch.com",description:"Self-hostable search"},{id:"typesense",name:"Typesense",region:"both",envVars:["TYPESENSE_HOST","TYPESENSE_PORT","TYPESENSE_PROTOCOL","TYPESENSE_API_KEY"],docs:"https://typesense.org/docs",description:"Open-source search"},{id:"algolia",name:"Algolia",region:"global",envVars:["ALGOLIA_APP_ID","ALGOLIA_ADMIN_API_KEY","ALGOLIA_SEARCH_API_KEY"],docs:"https://www.algolia.com/doc/",description:"Managed search as a service"},{id:"pgvector",name:"pgvector (Postgres)",region:"both",envVars:["DATABASE_URL"],docs:"https://github.com/pgvector/pgvector",description:"Postgres vector + full-text"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:"Skip search package"}];function Vr(e){return Kt.find(t=>t.id===e)}var Ku=Kt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Yr(e){return dt.existsSync(e)?dt.readFileSync(e,"utf-8"):null}function Tc(e,t){let n=Kr.join(e,".env.example"),o=Yr(n);if(o===null)return;let r=`# Search: ${t.name}`;if(o.includes(r))return;let s=["","# =============================================",r,`# Docs: ${t.docs}`,"# =============================================",...t.envVars.map(i=>`${i}=""`),""].join(`
1868
+ `);dt.appendFileSync(n,s)}function xc(e,t,n){let o=Kr.join(e,".env.example"),r=Yr(o);if(r===null)return;let s=new RegExp(`^${t}=.*$`,"m");s.test(r)?dt.writeFileSync(o,r.replace(s,`${t}="${n}"`)):dt.appendFileSync(o,`${t}="${n}"
1869
+ `)}async function Gr(e,t,n){let o=De(e,"search");if(t==="none"){o&&dt.rmSync(o,{recursive:!0,force:!0});return}let r=Vr(t);if(!r)throw new Error(`Unknown search provider "${t}". Valid ids: ${Kt.map(s=>s.id).join(", ")}`);o&&(Tc(e,r),xc(e,"SEARCH_PROVIDER",t))}import Te from"fs";import Ye from"path";function Rc(e){let t=[Ye.join(e,"packages","db"),Ye.join(e,"apps","web")];for(let n of t){let o=Ye.join(n,"prisma","schema.prisma");if(Te.existsSync(o))return{packageDir:n,seedPath:Ye.join(n,"prisma","seed.ts"),packageJsonPath:Ye.join(n,"package.json")}}return null}function kc(e){try{let t=Te.readFileSync(e,"utf8"),n=new Set,o=/^\s*model\s+(\w+)\s*\{/gm,r=o.exec(t);for(;r;)n.add(r[1]),r=o.exec(t);return n}catch{return new Set}}function Nc(e,t){return!t||e==="none"?` // Skipping admin user \u2014 auth=${JSON.stringify(e)} (or no User model).`:e==="clerk"?` try {
1858
1870
  const admin = await prisma.user.create({
1859
1871
  data: {
1860
1872
  clerkId: "user_mock_admin",
@@ -1885,7 +1897,7 @@ export { default } from './mock-i18n';
1885
1897
  console.log("\\u2713 Created admin user:", admin.email);
1886
1898
  } catch (err) {
1887
1899
  console.warn("\\u26A0 Admin user creation skipped:", (err as Error).message);
1888
- }`}function vc(e,t){let n=t.has("Tenant"),o=t.has("User"),r=t.has("Project"),s=Ec(e,o),i=n?` let tenants: Array<{ id: string; name: string }> = [];
1900
+ }`}function Oc(e,t){let n=t.has("Tenant"),o=t.has("User"),r=t.has("Project"),s=Nc(e,o),i=n?` let tenants: Array<{ id: string; name: string }> = [];
1889
1901
  try {
1890
1902
  tenants = await Promise.all([
1891
1903
  prisma.tenant.create({
@@ -1954,12 +1966,12 @@ main()
1954
1966
  .finally(async () => {
1955
1967
  await prisma.$disconnect();
1956
1968
  });
1957
- `}function bc(e){if(Ce.existsSync(e))try{let t=Ce.readFileSync(e,"utf8"),n=JSON.parse(t),o=n.scripts??{},r=!1;o["db:seed"]||(o["db:seed"]="prisma db seed",r=!0);let s=n.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let i={...n,scripts:o,prisma:s};Ce.writeFileSync(e,JSON.stringify(i,null,2)+`
1958
- `)}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${n}`)}}async function Mr(e,t){let n=Sc(e);if(n)try{let o=Ve.join(n.packageDir,"prisma","schema.prisma"),r=hc(o),s=vc(t,r),i=Ve.dirname(n.seedPath);Ce.existsSync(i)||Ce.mkdirSync(i,{recursive:!0}),Ce.writeFileSync(n.seedPath,s),bc(n.packageJsonPath)}catch(o){let r=o instanceof Error?o.message:String(o);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import Ie from"fs";import Ke from"path";var $t=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Du=$t.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Fr(e){return $t.find(t=>t.id===e)}var _c="@nebutra/sms",wc={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function An(e,t){Ie.mkdirSync(Ke.dirname(e),{recursive:!0}),Ie.writeFileSync(e,t)}function Pc(e,t){let n=Ke.join(e,".env.example");Ie.existsSync(n)?Ie.appendFileSync(n,`
1959
- `+t):Ie.writeFileSync(n,t)}function Ac(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
1969
+ `}function Lc(e){if(Te.existsSync(e))try{let t=Te.readFileSync(e,"utf8"),n=JSON.parse(t),o=n.scripts??{},r=!1;o["db:seed"]||(o["db:seed"]="prisma db seed",r=!0);let s=n.prisma??{};if(s.seed||(s.seed="tsx prisma/seed.ts",r=!0),!r)return;let i={...n,scripts:o,prisma:s};Te.writeFileSync(e,JSON.stringify(i,null,2)+`
1970
+ `)}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`[create-sailor] Failed to patch seed scripts in ${e}: ${n}`)}}async function qr(e,t){let n=Rc(e);if(n)try{let o=Ye.join(n.packageDir,"prisma","schema.prisma"),r=kc(o),s=Oc(t,r),i=Ye.dirname(n.seedPath);Te.existsSync(i)||Te.mkdirSync(i,{recursive:!0}),Te.writeFileSync(n.seedPath,s),Lc(n.packageJsonPath)}catch(o){let r=o instanceof Error?o.message:String(o);throw console.error(`[create-sailor] Failed to generate seed data: ${r}`),new Error(`Unable to write prisma/seed.ts: ${r}`)}}import xe from"fs";import Ge from"path";var Yt=[{id:"twilio",name:"Twilio",region:"global",envVars:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_FROM_NUMBER"],docs:"https://www.twilio.com/docs/sms",pkgs:["twilio"]},{id:"messagebird",name:"MessageBird (Bird)",region:"global",envVars:["MESSAGEBIRD_ACCESS_KEY","MESSAGEBIRD_ORIGINATOR"],docs:"https://developers.messagebird.com/api/sms-messaging/",pkgs:["messagebird"]},{id:"plivo",name:"Plivo",region:"global",envVars:["PLIVO_AUTH_ID","PLIVO_AUTH_TOKEN","PLIVO_FROM_NUMBER"],docs:"https://www.plivo.com/docs/sms/",pkgs:["plivo"]},{id:"aliyun-sms",name:"\u963F\u91CC\u4E91\u77ED\u4FE1 Aliyun SMS",region:"cn",envVars:["ALIYUN_SMS_ACCESS_KEY","ALIYUN_SMS_ACCESS_SECRET","ALIYUN_SMS_SIGN_NAME","ALIYUN_SMS_TEMPLATE_CODE","ALIYUN_SMS_ENDPOINT"],docs:"https://help.aliyun.com/product/44282.html",pkgs:["@alicloud/dysmsapi20170525","@alicloud/openapi-client"]},{id:"tencent-sms",name:"\u817E\u8BAF\u4E91\u77ED\u4FE1 Tencent SMS",region:"cn",envVars:["TENCENT_SMS_SECRET_ID","TENCENT_SMS_SECRET_KEY","TENCENT_SMS_SDK_APP_ID","TENCENT_SMS_SIGN_NAME","TENCENT_SMS_TEMPLATE_ID","TENCENT_SMS_REGION"],docs:"https://cloud.tencent.com/document/product/382",pkgs:["tencentcloud-sdk-nodejs-sms"]},{id:"yunpian",name:"\u4E91\u7247 Yunpian",region:"cn",envVars:["YUNPIAN_API_KEY","YUNPIAN_SIGN"],docs:"https://www.yunpian.com/official/document/sms/zh_CN/introduction_product_intro",pkgs:["yunpian-nodejs-sdk"]},{id:"none",name:"None",region:"both",envVars:[],docs:""}],Zu=Yt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});function Hr(e){return Yt.find(t=>t.id===e)}var Uc="@nebutra/sms",Dc={twilio:"^5.3.6",messagebird:"^4.0.1",plivo:"^4.73.0","@alicloud/dysmsapi20170525":"^2.0.24","@alicloud/openapi-client":"^0.4.12","tencentcloud-sdk-nodejs-sms":"^4.0.970","yunpian-nodejs-sdk":"^0.0.2"};function Rn(e,t){xe.mkdirSync(Ge.dirname(e),{recursive:!0}),xe.writeFileSync(e,t)}function Mc(e,t){let n=Ge.join(e,".env.example");xe.existsSync(n)?xe.appendFileSync(n,`
1971
+ `+t):xe.writeFileSync(n,t)}function Fc(e){if(e.envVars.length===0)return"";let t=`# SMS provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
1960
1972
  `);return`${t}
1961
1973
  ${n}
1962
- `}var Cc=`/**
1974
+ `}var jc=`/**
1963
1975
  * Inputs for the \`sendSms\` wrapper. Keep this surface portable across
1964
1976
  * providers \u2014 provider-specific options belong in the wrapper itself.
1965
1977
  */
@@ -1979,7 +1991,7 @@ export interface SendSmsResult {
1979
1991
  provider: string;
1980
1992
  raw?: unknown;
1981
1993
  }
1982
- `;function Ic(){return`import twilio from "twilio";
1994
+ `;function Bc(){return`import twilio from "twilio";
1983
1995
  import type { SendSmsInput, SendSmsResult } from "./types";
1984
1996
 
1985
1997
  let client: ReturnType<typeof twilio> | null = null;
@@ -2014,7 +2026,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2014
2026
  }
2015
2027
 
2016
2028
  export type { SendSmsInput, SendSmsResult } from "./types";
2017
- `}function xc(){return`import messagebird from "messagebird";
2029
+ `}function $c(){return`import messagebird from "messagebird";
2018
2030
  import type { SendSmsInput, SendSmsResult } from "./types";
2019
2031
 
2020
2032
  let client: ReturnType<typeof messagebird> | null = null;
@@ -2052,7 +2064,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2052
2064
  }
2053
2065
 
2054
2066
  export type { SendSmsInput, SendSmsResult } from "./types";
2055
- `}function Rc(){return`import plivo from "plivo";
2067
+ `}function Vc(){return`import plivo from "plivo";
2056
2068
  import type { SendSmsInput, SendSmsResult } from "./types";
2057
2069
 
2058
2070
  let client: InstanceType<typeof plivo.Client> | null = null;
@@ -2091,7 +2103,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2091
2103
  }
2092
2104
 
2093
2105
  export type { SendSmsInput, SendSmsResult } from "./types";
2094
- `}function Tc(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2106
+ `}function Kc(){return`import Dysmsapi, { SendSmsRequest } from "@alicloud/dysmsapi20170525";
2095
2107
  import * as $OpenApi from "@alicloud/openapi-client";
2096
2108
  import type { SendSmsInput, SendSmsResult } from "./types";
2097
2109
 
@@ -2140,7 +2152,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2140
2152
  }
2141
2153
 
2142
2154
  export type { SendSmsInput, SendSmsResult } from "./types";
2143
- `}function kc(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2155
+ `}function Yc(){return`import * as tencentcloud from "tencentcloud-sdk-nodejs-sms";
2144
2156
  import type { SendSmsInput, SendSmsResult } from "./types";
2145
2157
 
2146
2158
  const SmsClient = tencentcloud.sms.v20210111.Client;
@@ -2205,7 +2217,7 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2205
2217
  }
2206
2218
 
2207
2219
  export type { SendSmsInput, SendSmsResult } from "./types";
2208
- `}function Nc(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2220
+ `}function Gc(){return`// @ts-expect-error \u2014 yunpian-nodejs-sdk ships no type declarations
2209
2221
  import Yunpian from "yunpian-nodejs-sdk";
2210
2222
  import type { SendSmsInput, SendSmsResult } from "./types";
2211
2223
 
@@ -2257,13 +2269,13 @@ export async function sendSms(input: SendSmsInput): Promise<SendSmsResult> {
2257
2269
  }
2258
2270
 
2259
2271
  export type { SendSmsInput, SendSmsResult } from "./types";
2260
- `}function Oc(e){switch(e){case"twilio":return Ic();case"messagebird":return xc();case"plivo":return Rc();case"aliyun-sms":return Tc();case"tencent-sms":return kc();case"yunpian":return Nc();case"none":return`export {};
2261
- `}}function Lc(e){let t={};for(let o of e.pkgs??[]){let r=wc[o];r&&(t[o]=r)}let n={name:_c,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2262
- `}async function jr(e,t,n="global"){if(t==="none")return;let o=Fr(t);if(!o)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${$t.map(i=>i.id).join(", ")}`);let r=Ke.join(e,"packages","sms");if(!Ie.existsSync(r))return;let s=Ke.join(r,"src");Ie.existsSync(s)&&Ie.rmSync(s,{recursive:!0,force:!0});try{An(Ke.join(r,"package.json"),Lc(o)),An(Ke.join(s,"types.ts"),Cc),An(Ke.join(s,"index.ts"),Oc(o.id)),Pc(e,Ac(o))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import qe from"fs";import Ye from"path";var Ge="@nebutra/storage";function Cn(e,t){qe.mkdirSync(Ye.dirname(e),{recursive:!0}),qe.writeFileSync(e,t)}function Uc(e,t){let n=Ye.join(e,".env.example");qe.existsSync(n)?qe.appendFileSync(n,`
2263
- `+t):qe.writeFileSync(n,t)}function Dc(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
2272
+ `}function qc(e){switch(e){case"twilio":return Bc();case"messagebird":return $c();case"plivo":return Vc();case"aliyun-sms":return Kc();case"tencent-sms":return Yc();case"yunpian":return Gc();case"none":return`export {};
2273
+ `}}function Hc(e){let t={};for(let o of e.pkgs??[]){let r=Dc[o];r&&(t[o]=r)}let n={name:Uc,version:"0.1.0",private:!0,description:`Transactional SMS via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2274
+ `}async function Wr(e,t,n="global"){if(t==="none")return;let o=Hr(t);if(!o)throw new Error(`Unknown SMS provider "${t}". Valid ids: ${Yt.map(i=>i.id).join(", ")}`);let r=Ge.join(e,"packages","sms");if(!xe.existsSync(r))return;let s=Ge.join(r,"src");xe.existsSync(s)&&xe.rmSync(s,{recursive:!0,force:!0});try{Rn(Ge.join(r,"package.json"),Hc(o)),Rn(Ge.join(s,"types.ts"),jc),Rn(Ge.join(s,"index.ts"),qc(o.id)),Mc(e,Fc(o))}catch(i){throw console.error(`Failed to apply SMS selection "${t}":`,i),new Error(`SMS scaffold for "${t}" failed \u2014 see stderr for details.`)}}import He from"fs";import qe from"path";var We="@nebutra/storage";function kn(e,t){He.mkdirSync(qe.dirname(e),{recursive:!0}),He.writeFileSync(e,t)}function Wc(e,t){let n=qe.join(e,".env.example");He.existsSync(n)?He.appendFileSync(n,`
2275
+ `+t):He.writeFileSync(n,t)}function Xc(e){if(e.envVars.length===0)return"";let t=`# Storage provider: ${e.name}`,n=e.envVars.map(o=>`${o}=`).join(`
2264
2276
  `);return`${t}
2265
2277
  ${n}
2266
- `}var Mc=`/**
2278
+ `}var zc=`/**
2267
2279
  * Inputs for the \`uploadFile\` wrapper. Keep this surface portable across
2268
2280
  * providers \u2014 provider-specific options belong in the wrapper itself.
2269
2281
  */
@@ -2289,8 +2301,8 @@ export interface SignedUrlOptions {
2289
2301
  operation?: "get" | "put";
2290
2302
  contentType?: string;
2291
2303
  }
2292
- `;function Fc(){return`/**
2293
- * @${Ge.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2304
+ `;function Jc(){return`/**
2305
+ * @${We.slice(1)} \u2014 Cloudflare R2 via the S3-compatible API.
2294
2306
  *
2295
2307
  * Docs: https://developers.cloudflare.com/r2/api/s3/api/
2296
2308
  */
@@ -2353,8 +2365,8 @@ export async function getSignedUrl(
2353
2365
  }
2354
2366
 
2355
2367
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2356
- `}function jc(){return`/**
2357
- * @${Ge.slice(1)} \u2014 AWS S3 wrapper.
2368
+ `}function Qc(){return`/**
2369
+ * @${We.slice(1)} \u2014 AWS S3 wrapper.
2358
2370
  *
2359
2371
  * Docs: https://docs.aws.amazon.com/s3/
2360
2372
  */
@@ -2418,8 +2430,8 @@ export async function getSignedUrl(
2418
2430
  }
2419
2431
 
2420
2432
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2421
- `}function Bc(){return`/**
2422
- * @${Ge.slice(1)} \u2014 Supabase Storage wrapper.
2433
+ `}function Zc(){return`/**
2434
+ * @${We.slice(1)} \u2014 Supabase Storage wrapper.
2423
2435
  *
2424
2436
  * Docs: https://supabase.com/docs/guides/storage
2425
2437
  */
@@ -2481,8 +2493,8 @@ export async function getSignedUrl(
2481
2493
  }
2482
2494
 
2483
2495
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2484
- `}function $c(){return`/**
2485
- * @${Ge.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2496
+ `}function ep(){return`/**
2497
+ * @${We.slice(1)} \u2014 \u963F\u91CC\u4E91 OSS wrapper via ali-oss.
2486
2498
  *
2487
2499
  * Docs: https://help.aliyun.com/product/31815.html
2488
2500
  */
@@ -2528,8 +2540,8 @@ export async function getSignedUrl(
2528
2540
  }
2529
2541
 
2530
2542
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2531
- `}function Vc(){return`/**
2532
- * @${Ge.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2543
+ `}function tp(){return`/**
2544
+ * @${We.slice(1)} \u2014 \u817E\u8BAF\u4E91 COS wrapper via cos-nodejs-sdk-v5.
2533
2545
  *
2534
2546
  * Docs: https://cloud.tencent.com/document/product/436
2535
2547
  */
@@ -2583,8 +2595,8 @@ export async function getSignedUrl(
2583
2595
  }
2584
2596
 
2585
2597
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2586
- `}function Kc(){return`/**
2587
- * @${Ge.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2598
+ `}function np(){return`/**
2599
+ * @${We.slice(1)} \u2014 \u4E03\u725B\u4E91 Kodo wrapper.
2588
2600
  *
2589
2601
  * Docs: https://developer.qiniu.com/kodo
2590
2602
  */
@@ -2651,9 +2663,9 @@ export async function getSignedUrl(
2651
2663
  }
2652
2664
 
2653
2665
  export type { UploadFileInput, UploadFileResult, SignedUrlOptions } from "./types";
2654
- `}function Yc(e){switch(e){case"r2":return Fc();case"s3":return jc();case"supabase-storage":return Bc();case"aliyun-oss":return $c();case"tencent-cos":return Vc();case"qiniu":return Kc();case"none":return`export {};
2655
- `}}function qc(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let n={name:Ge,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2656
- `}async function Br(e,t,n){if(t==="none")return;let o=$n(t);if(!o)throw new Error(`Unknown storage provider "${t}". Valid ids: ${Re.map(i=>i.id).join(", ")}`);let r=Ye.join(e,"packages","storage"),s=Ye.join(r,"src");qe.existsSync(s)&&qe.rmSync(s,{recursive:!0,force:!0}),Cn(Ye.join(r,"package.json"),qc(o)),Cn(Ye.join(s,"types.ts"),Mc),Cn(Ye.join(s,"index.ts"),Yc(o.id)),Uc(e,Dc(o))}var Vt=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function $r(e){return Vt.find(t=>t.id===e)}var Gu=Vt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Vr(e,t,n="global"){let o=$r(t);if(!o)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Vt.map(r=>r.id).join(", ")}`);if(o.id==="none"){J(e,"webhooks");return}o.envVars.length>0&&re(e,{category:"Webhooks",name:o.name,envVars:o.envVars,docs:o.docs}),se(e,"WEBHOOKS_PROVIDER",o.id)}import He from"fs";import wt from"path";function Gc(e){return`import Link from "next/link";
2666
+ `}function op(e){switch(e){case"r2":return Jc();case"s3":return Qc();case"supabase-storage":return Zc();case"aliyun-oss":return ep();case"tencent-cos":return tp();case"qiniu":return np();case"none":return`export {};
2667
+ `}}function rp(e){let t={};e.pkg&&e.pkgVersion&&(t[e.pkg]=e.pkgVersion),(e.id==="r2"||e.id==="s3")&&(t["@aws-sdk/s3-request-presigner"]="^3.658.0");let n={name:We,version:"0.1.0",private:!0,description:`Object storage via ${e.name}`,type:"module",main:"./dist/index.js",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},scripts:{build:"tsup",typecheck:"tsc --noEmit",clean:"rm -rf dist .turbo"},dependencies:t,devDependencies:{tsup:"^8.5.0",typescript:"catalog:"}};return JSON.stringify(n,null,2)+`
2668
+ `}async function Xr(e,t,n){if(t==="none")return;let o=Hn(t);if(!o)throw new Error(`Unknown storage provider "${t}". Valid ids: ${ke.map(i=>i.id).join(", ")}`);let r=qe.join(e,"packages","storage"),s=qe.join(r,"src");He.existsSync(s)&&He.rmSync(s,{recursive:!0,force:!0}),kn(qe.join(r,"package.json"),rp(o)),kn(qe.join(s,"types.ts"),zc),kn(qe.join(s,"index.ts"),op(o.id)),Wc(e,Xc(o))}var Gt=[{id:"svix",name:"Svix",region:"global",envVars:["SVIX_API_TOKEN"],docs:"https://docs.svix.com",description:"Managed webhooks platform"},{id:"custom",name:"Custom (self-hosted)",region:"both",envVars:["WEBHOOK_SIGNING_SECRET"],docs:"",description:"Custom implementation with built-in package"},{id:"none",name:"None",region:"both",envVars:[],docs:"",description:""}];function zr(e){return Gt.find(t=>t.id===e)}var pm=Gt.reduce((e,t)=>(e[t.region]||(e[t.region]=[]),e[t.region].push(t),e),{});async function Jr(e,t,n="global"){let o=zr(t);if(!o)throw new Error(`Unknown webhooks provider "${t}". Valid ids: ${Gt.map(r=>r.id).join(", ")}`);if(o.id==="none"){Z(e,"webhooks");return}o.envVars.length>0&&ae(e,{category:"Webhooks",name:o.name,envVars:o.envVars,docs:o.docs}),ce(e,"WEBHOOKS_PROVIDER",o.id)}import Xe from"fs";import At from"path";function sp(e){return`import Link from "next/link";
2657
2669
 
2658
2670
  export default function WelcomePage() {
2659
2671
  const projectName = ${JSON.stringify(e)};
@@ -2762,21 +2774,21 @@ function Step({
2762
2774
  </li>
2763
2775
  );
2764
2776
  }
2765
- `}function Hc(e={}){return`
2777
+ `}function ip(e={}){return`
2766
2778
  ## What you can do next
2767
2779
 
2768
2780
  ${[e.apiKeys===!1?"- Manage API keys at `/settings/api-keys` (disabled \u2014 re-enable with `--api-keys=true`)":"- Manage API keys at `/settings/api-keys`",e.auditLog===!1?"- View audit log at `/settings/audit-log` (disabled \u2014 re-enable with `--audit-log=true`)":"- View audit log at `/settings/audit-log`","- Configure webhooks at `/settings/webhooks`",e.commandPalette===!1?"- Press \u2318K to open the command palette (disabled \u2014 re-enable with `--command-palette=true`)":"- Press \u2318K to open the command palette","- Edit notification preferences at `/settings/notifications`","- Export your data at `/settings/account/export`","- For China deployments, see `packages/ops/china-compliance/README.md`"].join(`
2769
2781
  `)}
2770
- `}function Wc(e=[]){return e.length===0?"":`
2782
+ `}function ap(e=[]){return e.length===0?"":`
2771
2783
  ## Production readiness holds
2772
2784
 
2773
2785
  Do not enable these in production until provider credentials, adapter wiring, and the integration contract are verified:
2774
2786
 
2775
- ${e.map(n=>{let o=et(n.status);return`- ${n.flag}=${n.provider} ${o} \u2014 ${Te(n.status)}`}).join(`
2787
+ ${e.map(n=>{let o=tt(n.status);return`- ${n.flag}=${n.provider} ${o} \u2014 ${Ne(n.status)}`}).join(`
2776
2788
  `)}
2777
2789
 
2778
2790
  Review the package readiness matrix before handoff: [docs/package-status.md](docs/package-status.md)
2779
- `}function Xc(e,t,n=[],o={}){return`# Next steps \u2014 ${e}
2791
+ `}function cp(e,t,n=[],o={}){return`# Next steps \u2014 ${e}
2780
2792
 
2781
2793
  Region: ${t}
2782
2794
 
@@ -2802,28 +2814,31 @@ Your AI-native SaaS scaffold is ready. Complete these four steps to go from temp
2802
2814
  \`\`\`
2803
2815
 
2804
2816
  After setup, delete the welcome route at \`apps/web/src/app/[locale]/welcome/\`.
2805
- ${Hc(o)}${Wc(n)}
2817
+ ${ip(o)}${ap(n)}
2806
2818
 
2807
2819
  ## Resources
2808
2820
 
2809
2821
  - [Documentation](/docs)
2810
2822
  - [GitHub](https://github.com/nebutra/nebutra-sailor)
2811
2823
  - [Licensing](https://nebutra.com/licensing)
2812
- `}async function Kr(e,t){let{projectName:n,region:o,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=wt.join(e,".sailor");He.existsSync(i)||He.mkdirSync(i,{recursive:!0}),He.writeFileSync(wt.join(i,"next-steps.md"),Xc(n,o,r,s))}catch(i){let a=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${a}`)}try{let i=wt.join(e,"apps","web");if(!He.existsSync(i))return;let a=wt.join(i,"src","app","[locale]","welcome");He.existsSync(a)||He.mkdirSync(a,{recursive:!0}),He.writeFileSync(wt.join(a,"page.tsx"),Gc(n))}catch(i){let a=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${a}`)}}function l(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2813
- `)}function Yr(e){return e!==null&&typeof e=="object"&&"code"in e&&e.code==="ENOENT"}function Jc(e,t){for(let n of t)if(e)l(!0,{event:"warn",step:n.flag,provider:n.provider,packageStatus:n.status,message:Te(n.status)});else{let o=et(n.status);process.stdout.write(We.yellow(`\u26A0 ${n.flag}=${n.provider} ${o} \u2014 ${Te(n.status)}
2814
- `))}}function Qc(e,t,n){let o=Xe.join(t,"packages/platform/db/prisma/schema.prisma"),r;try{r=Yt.readFileSync(o,"utf8")}catch(s){if(Yr(s)){l(e,{event:"step",step:"schema-prune",status:"skip"});return}let i=s instanceof Error?s.message:String(s);l(e,{event:"step",step:"schema-prune",status:"error",error:i});return}l(e,{event:"step",step:"schema-prune",status:"start"});try{let s=Pn(r,n);Yt.writeFileSync(o,s),wn(Xe.join(Xe.dirname(o),"migrations"),n),l(e,{event:"step",step:"schema-prune",status:"ok"})}catch(s){let i=s instanceof Error?s.message:String(s);l(e,{event:"step",step:"schema-prune",status:"error",error:i})}}async function qr(e){let{resolvedTarget:t,projectName:n,resolvedPm:o,opts:r,useJson:s,resolved:i,startedAt:a}=e,{region:c,orm:p,database:d,databaseHost:u,payment:A,paymentChoice:h,auth:g,socialLoginIds:E,aiProviders:S,deployTarget:m,docs:_,metering:H,billingMode:M,idp:he,accessGate:le,mcp:ee,waveToggles:V,previewSelections:K,config:C}=i,W={auth:g,payment:h,"billing-mode":M,idp:he,template:"saas","access-gate":le};l(s,{event:"step",step:"clone",status:"start"}),await Wo(t),l(s,{event:"step",step:"clone",status:"ok"}),l(s,{event:"step",step:"package",status:"start"}),await pr(t,n),l(s,{event:"step",step:"package",status:"ok"}),l(s,{event:"step",step:"config",status:"start"}),await _o(t,C),l(s,{event:"step",step:"config",status:"ok"}),l(s,{event:"step",step:"governance-lints",status:"start"});let de=await zo(t,C);l(s,{event:"step",step:"governance-lints",status:"ok",lints:de.lints}),l(s,{event:"step",step:"prune",status:"start"}),await br(t,C),l(s,{event:"step",step:"prune",status:"ok"});{let v=Xe.join(t,"packages/platform/db/prisma/schema.prisma"),R;try{R=Yt.readFileSync(v,"utf-8")}catch(P){if(Yr(P))l(s,{event:"step",step:"schema-prune",status:"skip"});else{let I=P instanceof Error?P.message:String(P);l(s,{event:"step",step:"schema-prune",status:"error",error:I})}}if(R!==void 0){l(s,{event:"step",step:"schema-prune",status:"start"});try{let P=Pn(R,W);Yt.writeFileSync(v,P),wn(Xe.join(Xe.dirname(v),"migrations"),W),l(s,{event:"step",step:"schema-prune",status:"ok"})}catch(P){let I=P instanceof Error?P.message:String(P);l(s,{event:"step",step:"schema-prune",status:"error",error:I})}}}if(l(s,{event:"step",step:"auth",choice:g,status:"start"}),await po(t,g),l(s,{event:"step",step:"auth",choice:g,status:"ok"}),E.length>0?(l(s,{event:"step",step:"social-login",providers:E,status:"start"}),await uo(t,E,g),l(s,{event:"step",step:"social-login",providers:E,status:"ok"})):l(s,{event:"step",step:"social-login",status:"skip"}),l(s,{event:"step",step:"db",choice:d,status:"start"}),await Ao(t,d,n),d!=="none"){let v=mt(u);v&&(await Co(t,v,n),l(s,{event:"step",step:"db-host",choice:u,status:"ok"}))}if(l(s,{event:"step",step:"db",choice:d,status:"ok"}),p==="drizzle"){l(s,{event:"step",step:"orm",choice:"drizzle",status:"start"});let v=await ur(t,"drizzle",d);l(s,{event:"step",step:"orm",choice:"drizzle",status:v.applied?"ok":"skip",...v.reason?{reason:v.reason}:{}})}if(l(s,{event:"step",step:"payment",choice:h,status:"start"}),await gr(t,h),l(s,{event:"step",step:"payment",choice:h,status:"ok"}),await Oo(t,i.email,c),s&&l(!0,{event:"step",step:"email",choice:i.email,status:"ok"}),await Br(t,i.storage,c),s&&l(!0,{event:"step",step:"storage",choice:i.storage,status:"ok"}),await ir(t,i.monitoring,c),s&&l(!0,{event:"step",step:"monitoring",choice:i.monitoring,status:"ok"}),await io(t,i.analytics,c),s&&l(!0,{event:"step",step:"analytics",choice:i.analytics,status:"ok"}),await jr(t,i.sms,c),s&&l(!0,{event:"step",step:"sms",choice:i.sms,status:"ok"}),await xr(t,i.queue,c),s&&l(!0,{event:"step",step:"queue",choice:i.queue,status:"ok"}),await Dr(t,i.search,c),s&&l(!0,{event:"step",step:"search",choice:i.search,status:"ok"}),await yo(t,i.cache,c),s&&l(!0,{event:"step",step:"cache",choice:i.cache,status:"ok"}),await cr(t,i.notifications,c),s&&l(!0,{event:"step",step:"notifications",choice:i.notifications,status:"ok"}),await Vr(t,i.webhooks,c),s&&l(!0,{event:"step",step:"webhooks",choice:i.webhooks,status:"ok"}),await vo(t,i.cms,c),s&&l(!0,{event:"step",step:"cms",choice:i.cms,status:"ok"}),await $o(t,i.featureFlags,c),s&&l(!0,{event:"step",step:"feature-flags",choice:i.featureFlags,status:"ok"}),await ho(t,i.captcha,c),s&&l(!0,{event:"step",step:"captcha",choice:i.captcha,status:"ok"}),await tr(t,ee),s&&l(!0,{event:"step",step:"mcp",mode:ee,status:"ok"}),await or(t,H,A),s&&l(!0,{event:"step",step:"metering",mode:H,status:"ok"}),l(s,{event:"step",step:"prune-wave-features",status:"start"}),_r(t,V),l(s,{event:"step",step:"prune-wave-features",status:"ok",toggles:V}),C.orm==="prisma"&&C.database!=="none"?Qc(s,t,W):l(s,{event:"step",step:"schema-prune",status:"skip"}),l(s,{event:"step",step:"billing-mode",choice:M,status:"ok"}),l(s,{event:"step",step:"idp",choice:he,status:"ok"}),await bo(t,c),s&&l(!0,{event:"step",step:"compliance",region:c,status:"ok"}),await jo(t),await Mr(t,g),await Kr(t,{projectName:n,region:c,previewSelections:K,waveFeatures:V}),C.aiMode!=="none"){l(s,{event:"step",step:"ai-providers",status:"start"});let v={providerIds:C.aiProviders,customEndpoint:C.customAiEndpoint},R=Xe.join(t,"packages/ai/ai-providers/templates");await Er(t,v,R),l(s,{event:"step",step:"ai-providers",status:"ok"})}else l(s,{event:"step",step:"ai-providers",status:"skip"});l(s,{event:"step",step:"docs",status:"start"}),_!=="none"?(await Ro(t,{framework:_,projectName:n}),l(s,{event:"step",step:"docs",framework:"fumadocs",requested:_,status:"ok"})):l(s,{event:"step",step:"docs",status:"skip"}),l(s,{event:"step",step:"deploy-target",status:"start"}),m!=="none"&&await eo(t,m),await Zn(t,C.deployTargets),l(s,{event:"step",step:"deploy-target",status:"ok",targets:C.deployTargets});let w={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""};l(s,{event:"step",step:"env",status:"start"}),await Do(t,w),l(s,{event:"step",step:"env",status:"ok"}),l(s,{event:"step",step:"scaffold-extras",status:"start"});let Ee=await Tr(t,{projectName:n,withWorkflows:!!r.withWorkflows,withPythonBackend:!!r.withPythonBackend});l(s,{event:"step",step:"scaffold-extras",status:"ok",applied:Ee.applied,skipped:Ee.skipped}),l(s,{event:"step",step:"license",status:"start"});try{let v=er(t,{projectName:n,cliVersion:z});l(s,{event:"step",step:"license",status:"ok",tier:"mit-scaffold",wrote:v.wrote}),s||process.stdout.write(We.dim(` License: MIT \u2014 commercial use, closed source, no fee, no attribution.
2824
+ `}async function Qr(e,t){let{projectName:n,region:o,previewSelections:r=[],waveFeatures:s={}}=t;try{let i=At.join(e,".sailor");Xe.existsSync(i)||Xe.mkdirSync(i,{recursive:!0}),Xe.writeFileSync(At.join(i,"next-steps.md"),cp(n,o,r,s))}catch(i){let a=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write .sailor/next-steps.md: ${a}`)}try{let i=At.join(e,"apps","web");if(!Xe.existsSync(i))return;let a=At.join(i,"src","app","[locale]","welcome");Xe.existsSync(a)||Xe.mkdirSync(a,{recursive:!0}),Xe.writeFileSync(At.join(a,"page.tsx"),sp(n))}catch(i){let a=i instanceof Error?i.message:String(i);console.warn(`[create-sailor] Failed to write welcome page: ${a}`)}}function u(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2825
+ `)}function Zr(e){return e!==null&&typeof e=="object"&&"code"in e&&e.code==="ENOENT"}function lp(e,t){for(let n of t)if(e)u(!0,{event:"warn",step:n.flag,provider:n.provider,packageStatus:n.status,message:Ne(n.status)});else{let o=tt(n.status);process.stdout.write(F.yellow(`\u26A0 ${n.flag}=${n.provider} ${o} \u2014 ${Ne(n.status)}
2826
+ `))}}function dp(e,t,n){let o=ze.join(t,"packages/platform/db/prisma/schema.prisma"),r;try{r=Ht.readFileSync(o,"utf8")}catch(s){if(Zr(s)){u(e,{event:"step",step:"schema-prune",status:"skip"});return}let i=s instanceof Error?s.message:String(s);u(e,{event:"step",step:"schema-prune",status:"error",error:i});return}u(e,{event:"step",step:"schema-prune",status:"start"});try{let s=xn(r,n);Ht.writeFileSync(o,s),Tn(ze.join(ze.dirname(o),"migrations"),n),u(e,{event:"step",step:"schema-prune",status:"ok"})}catch(s){let i=s instanceof Error?s.message:String(s);u(e,{event:"step",step:"schema-prune",status:"error",error:i})}}function up(e){let t=0,n=process.stdout.isTTY===!0,o=r=>{if(!n){process.stdout.write(` ${r}
2827
+ `);return}process.stdout.write(`\r\x1B[2K ${r}`)};return r=>{if(e){u(!0,{event:"step",step:"clone",status:"start",phase:r.phase,source:r.source,receivedBytes:r.receivedBytes,totalBytes:r.totalBytes,attempt:r.attempt});return}switch(r.phase){case"resolve":o(F.dim(`Resolving ${r.source}\u2026`));break;case"download":{let s=Date.now();if(r.receivedBytes&&s-t<120)return;t=s;let i=it(r.receivedBytes??0),a=r.totalBytes?` / ${it(r.totalBytes)}`:"",c=r.totalBytes&&r.receivedBytes?` (${Math.floor(r.receivedBytes/r.totalBytes*100)}%)`:"";o(F.dim(`Downloading template ${i}${a}${c}`));break}case"retry":n&&process.stdout.write("\r\x1B[2K"),process.stdout.write(F.yellow(` \u26A0 ${r.reason} \u2014 retrying (attempt ${r.attempt}/3)
2828
+ `));break;case"extract":o(F.dim("Extracting template\u2026"));break;case"strip":o(F.dim("Stripping template-only files\u2026"));break;case"install":o(F.dim("Writing project files\u2026"));break}}}async function es(e){let{resolvedTarget:t,projectName:n,resolvedPm:o,opts:r,useJson:s,resolved:i,startedAt:a}=e,{region:c,orm:p,database:m,databaseHost:d,payment:v,paymentChoice:g,auth:h,socialLoginIds:P,aiProviders:E,deployTarget:l,docs:y,metering:U,billingMode:R,idp:ve,accessGate:ue,mcp:oe,waveToggles:G,previewSelections:q,config:I}=i,z={auth:h,payment:g,"billing-mode":R,idp:ve,template:"saas","access-gate":ue};u(s,{event:"step",step:"clone",status:"start"});let V=await or(t,{onProgress:up(s)});e.reportCreatedEntries?.(V.createdEntries),s?u(!0,{event:"step",step:"clone",status:"ok",source:V.source,bytes:V.bytes}):(process.stdout.isTTY===!0&&process.stdout.write("\r\x1B[2K"),process.stdout.write(F.green(" \u2713 Template ready")+F.dim(` (${it(V.bytes)} from ${V.source})
2829
+ `))),u(s,{event:"step",step:"package",status:"start"}),await hr(t,n),u(s,{event:"step",step:"package",status:"ok"}),u(s,{event:"step",step:"config",status:"start"}),await To(t,I),u(s,{event:"step",step:"config",status:"ok"}),u(s,{event:"step",step:"governance-lints",status:"start"});let A=await sr(t,I);u(s,{event:"step",step:"governance-lints",status:"ok",lints:A.lints}),u(s,{event:"step",step:"prune",status:"start"}),await Rr(t,I),u(s,{event:"step",step:"prune",status:"ok"});{let b=ze.join(t,"packages/platform/db/prisma/schema.prisma"),D;try{D=Ht.readFileSync(b,"utf-8")}catch(_){if(Zr(_))u(s,{event:"step",step:"schema-prune",status:"skip"});else{let me=_ instanceof Error?_.message:String(_);u(s,{event:"step",step:"schema-prune",status:"error",error:me})}}if(D!==void 0){u(s,{event:"step",step:"schema-prune",status:"start"});try{let _=xn(D,z);Ht.writeFileSync(b,_),Tn(ze.join(ze.dirname(b),"migrations"),z),u(s,{event:"step",step:"schema-prune",status:"ok"})}catch(_){let me=_ instanceof Error?_.message:String(_);u(s,{event:"step",step:"schema-prune",status:"error",error:me})}}}if(u(s,{event:"step",step:"auth",choice:h,status:"start"}),await yo(t,h),u(s,{event:"step",step:"auth",choice:h,status:"ok"}),P.length>0?(u(s,{event:"step",step:"social-login",providers:P,status:"start"}),await ho(t,P,h),u(s,{event:"step",step:"social-login",providers:P,status:"ok"})):u(s,{event:"step",step:"social-login",status:"skip"}),u(s,{event:"step",step:"db",choice:m,status:"start"}),await ko(t,m,n),m!=="none"){let b=ft(d);b&&(await No(t,b,n),u(s,{event:"step",step:"db-host",choice:d,status:"ok"}))}if(u(s,{event:"step",step:"db",choice:m,status:"ok"}),p==="drizzle"){u(s,{event:"step",step:"orm",choice:"drizzle",status:"start"});let b=await br(t,"drizzle",m);u(s,{event:"step",step:"orm",choice:"drizzle",status:b.applied?"ok":"skip",...b.reason?{reason:b.reason}:{}})}if(u(s,{event:"step",step:"payment",choice:g,status:"start"}),await wr(t,g),u(s,{event:"step",step:"payment",choice:g,status:"ok"}),await jo(t,i.email,c),s&&u(!0,{event:"step",step:"email",choice:i.email,status:"ok"}),await Xr(t,i.storage,c),s&&u(!0,{event:"step",step:"storage",choice:i.storage,status:"ok"}),await fr(t,i.monitoring,c),s&&u(!0,{event:"step",step:"monitoring",choice:i.monitoring,status:"ok"}),await mo(t,i.analytics,c),s&&u(!0,{event:"step",step:"analytics",choice:i.analytics,status:"ok"}),await Wr(t,i.sms,c),s&&u(!0,{event:"step",step:"sms",choice:i.sms,status:"ok"}),await Mr(t,i.queue,c),s&&u(!0,{event:"step",step:"queue",choice:i.queue,status:"ok"}),await Gr(t,i.search,c),s&&u(!0,{event:"step",step:"search",choice:i.search,status:"ok"}),await _o(t,i.cache,c),s&&u(!0,{event:"step",step:"cache",choice:i.cache,status:"ok"}),await Sr(t,i.notifications,c),s&&u(!0,{event:"step",step:"notifications",choice:i.notifications,status:"ok"}),await Jr(t,i.webhooks,c),s&&u(!0,{event:"step",step:"webhooks",choice:i.webhooks,status:"ok"}),await Co(t,i.cms,c),s&&u(!0,{event:"step",step:"cms",choice:i.cms,status:"ok"}),await Ho(t,i.featureFlags,c),s&&u(!0,{event:"step",step:"feature-flags",choice:i.featureFlags,status:"ok"}),await Po(t,i.captcha,c),s&&u(!0,{event:"step",step:"captcha",choice:i.captcha,status:"ok"}),await lr(t,oe),s&&u(!0,{event:"step",step:"mcp",mode:oe,status:"ok"}),await ur(t,U,v),s&&u(!0,{event:"step",step:"metering",mode:U,status:"ok"}),u(s,{event:"step",step:"prune-wave-features",status:"start"}),kr(t,G),u(s,{event:"step",step:"prune-wave-features",status:"ok",toggles:G}),I.orm==="prisma"&&I.database!=="none"?dp(s,t,z):u(s,{event:"step",step:"schema-prune",status:"skip"}),u(s,{event:"step",step:"billing-mode",choice:R,status:"ok"}),u(s,{event:"step",step:"idp",choice:ve,status:"ok"}),await Io(t,c),s&&u(!0,{event:"step",step:"compliance",region:c,status:"ok"}),await Go(t),await qr(t,h),await Qr(t,{projectName:n,region:c,previewSelections:q,waveFeatures:G}),I.aiMode!=="none"){u(s,{event:"step",step:"ai-providers",status:"start"});let b={providerIds:I.aiProviders,customEndpoint:I.customAiEndpoint},D=ze.join(t,"packages/ai/ai-providers/templates");await Tr(t,b,D),u(s,{event:"step",step:"ai-providers",status:"ok"})}else u(s,{event:"step",step:"ai-providers",status:"skip"});u(s,{event:"step",step:"docs",status:"start"}),y!=="none"?(await Uo(t,{framework:y,projectName:n}),u(s,{event:"step",step:"docs",framework:"fumadocs",requested:y,status:"ok"})):u(s,{event:"step",step:"docs",status:"skip"}),u(s,{event:"step",step:"deploy-target",status:"start"}),l!=="none"&&await io(t,l),await so(t,I.deployTargets),u(s,{event:"step",step:"deploy-target",status:"ok",targets:I.deployTargets});let Re={databaseUrl:"postgresql://postgres:postgres@localhost:5432/nebutra",clerkPublishable:"",clerkSecret:""};u(s,{event:"step",step:"env",status:"start"}),await Vo(t,Re),u(s,{event:"step",step:"env",status:"ok"}),u(s,{event:"step",step:"scaffold-extras",status:"start"});let be=await jr(t,{projectName:n,withWorkflows:!!r.withWorkflows,withPythonBackend:!!r.withPythonBackend});u(s,{event:"step",step:"scaffold-extras",status:"ok",applied:be.applied,skipped:be.skipped}),u(s,{event:"step",step:"license",status:"start"});try{let b=pr(t,{projectName:n,cliVersion:Q});u(s,{event:"step",step:"license",status:"ok",tier:"mit-scaffold",wrote:b.wrote}),s||process.stdout.write(F.dim(` License: MIT \u2014 commercial use, closed source, no fee, no attribution.
2815
2830
  Upstream terms preserved as LICENSE-UPSTREAM-REFERENCE.md.
2816
- `))}catch(v){l(s,{event:"step",step:"license",status:"warn",message:v instanceof Error?v.message:String(v)})}if(r.install!==!1){let v=o==="bun"?"bun":o,R=["install"];s?l(!0,{event:"step",step:"install",pm:o,status:"start"}):process.stdout.write(We.dim(` Installing dependencies with ${o}\u2026
2817
- `));try{Kt(v,R,{cwd:t,stdio:s?"ignore":"inherit"}),l(s,{event:"step",step:"install",status:"ok"}),s||process.stdout.write(We.green(` \u2713 Dependencies installed (${o})
2818
- `))}catch(P){let I=P instanceof Error?P.message:String(P);s?l(!0,{event:"step",step:"install",status:"error",error:I}):process.stdout.write(We.yellow(`
2831
+ `))}catch(b){u(s,{event:"step",step:"license",status:"warn",message:b instanceof Error?b.message:String(b)})}if(r.install!==!1){let b=o==="bun"?"bun":o,D=["install"];s?u(!0,{event:"step",step:"install",pm:o,status:"start"}):process.stdout.write(F.dim(` Installing dependencies with ${o}\u2026
2832
+ `));try{qt(b,D,{cwd:t,stdio:s?"ignore":"inherit"}),u(s,{event:"step",step:"install",status:"ok"}),s||process.stdout.write(F.green(` \u2713 Dependencies installed (${o})
2833
+ `))}catch(_){let me=_ instanceof Error?_.message:String(_);s?u(!0,{event:"step",step:"install",status:"error",error:me}):process.stdout.write(F.yellow(`
2819
2834
  \u26A0 Install failed \u2014 the project files are ready, but deps are incomplete.
2820
- Fix: ${We.cyan(`cd ${t} && ${o} install`)}
2835
+ Fix: ${F.cyan(`cd ${t} && ${o} install`)}
2821
2836
 
2822
- `))}}else l(s,{event:"step",step:"install",status:"skip"});if(r.git!==!1){s&&l(!0,{event:"step",step:"git-init",status:"start"});try{Kt("git",["init","-q"],{cwd:t,stdio:"ignore"}),Kt("git",["add","-A"],{cwd:t,stdio:"ignore"}),Kt("git",["-c","user.email=you@example.com","-c","user.name=You","commit","-q","-m","chore: initial scaffold from create-sailor"],{cwd:t,stdio:"ignore"}),l(s,{event:"step",step:"git-init",status:"ok"})}catch(v){let R=v instanceof Error?v.message:String(v);s?l(!0,{event:"step",step:"git-init",status:"error",error:R}):process.stdout.write(We.yellow(` \u26A0 git init skipped \u2014 not fatal.
2823
- `))}}else l(s,{event:"step",step:"git-init",status:"skip"});let ve=Math.max(1,Math.round((Date.now()-a)/1e3));co({template_version:z,package_manager:o,region:c,auth:g,payment:h,ai_providers:S,deploy_target:m,duration_ms:Date.now()-a}),K.length>0&&Jc(s,K),s?l(!0,{event:"done",status:"ok",elapsedSec:ve,targetDir:t,previewSelections:K,waveFeatures:V}):oo({elapsedSec:ve,targetDir:t,packageManager:o,skippedInstall:r.install===!1,hasDatabase:d!=="none",previewSelections:K});try{zc({pkg:{name:"create-sailor",version:z},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}}import Zc from"cfonts";import ep from"picocolors";function Gr(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${z}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
2824
- `));return}Zc.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(ep.dim(` AI-Native SaaS Template \xB7 v${z} \xB7 nebutra.com
2837
+ `))}}else u(s,{event:"step",step:"install",status:"skip"});if(r.git!==!1){s&&u(!0,{event:"step",step:"git-init",status:"start"});try{qt("git",["init","-q"],{cwd:t,stdio:"ignore"}),qt("git",["add","-A"],{cwd:t,stdio:"ignore"}),qt("git",["-c","user.email=you@example.com","-c","user.name=You","commit","-q","-m","chore: initial scaffold from create-sailor"],{cwd:t,stdio:"ignore"}),u(s,{event:"step",step:"git-init",status:"ok"})}catch(b){let D=b instanceof Error?b.message:String(b);s?u(!0,{event:"step",step:"git-init",status:"error",error:D}):process.stdout.write(F.yellow(` \u26A0 git init skipped \u2014 not fatal.
2838
+ `))}}else u(s,{event:"step",step:"git-init",status:"skip"});let _e=Math.max(1,Math.round((Date.now()-a)/1e3));fo({template_version:Q,package_manager:o,region:c,auth:h,payment:g,ai_providers:E,deploy_target:l,duration_ms:Date.now()-a}),q.length>0&&lp(s,q),s?u(!0,{event:"done",status:"ok",elapsedSec:_e,targetDir:t,previewSelections:q,waveFeatures:G}):po({elapsedSec:_e,targetDir:t,packageManager:o,skippedInstall:r.install===!1,hasDatabase:m!=="none",previewSelections:q});try{pp({pkg:{name:"create-sailor",version:Q},updateCheckInterval:1e3*60*60*24}).notify({defer:!1,isGlobal:!0})}catch{}}import mp from"cfonts";import gp from"picocolors";function ts(){if(process.env.NO_COLOR||!process.stdout.isTTY){process.stdout.write([`Sailor v${Q}`,"AI-Native SaaS Unicorn Template","by Nebutra \xB7 https://nebutra.com","",""].join(`
2839
+ `));return}mp.say("Sailor",{font:"block",align:"left",colors:["#0033FE","#0BF1C3"],gradient:["#0033FE","#0BF1C3"],transitionGradient:!0,space:!1}),process.stdout.write(gp.dim(` AI-Native SaaS Template \xB7 v${Q} \xB7 nebutra.com
2825
2840
 
2826
- `))}var tp=`Usage: create-sailor [name] [options]
2841
+ `))}var fp=`Usage: create-sailor [name] [options]
2827
2842
 
2828
2843
  Arguments:
2829
2844
  name project name or path (default: my-app; use . for cwd)
@@ -2903,39 +2918,43 @@ Examples:
2903
2918
  $ npx create-sailor@latest my-app --region=cn --auth=clerk
2904
2919
  $ npx create-sailor@latest my-app --region=hybrid --ai=openai,deepseek
2905
2920
  $ npx create-sailor@latest my-app --dry-run --region=cn
2906
- `;function Hr(){process.stdout.write(tp)}import qt from"picocolors";function Wr(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function np(e){let t=Wr()?"\u25B8":"->",n=`[${e.index}/${e.total}]`,o=e.label.padEnd(18," ");return Wr()?`${qt.dim(n)} ${qt.bold(o)} ${qt.dim(t)} ${qt.cyan(e.value)}`:`${n} ${o} ${t} ${e.value}`}function Xr(e){process.stdout.write(np(e)+`
2907
- `)}import{existsSync as op,mkdirSync as rp,writeFileSync as sp}from"fs";import{homedir as zr,platform as ip}from"os";import{join as Pt}from"path";import In from"picocolors";function ap(){if(ip()==="win32"){let t=process.env.LOCALAPPDATA||Pt(zr(),"AppData","Local");return Pt(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Pt(e,"nebutra"):Pt(zr(),".config","nebutra")}function cp(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function Jr(e,t){try{rp(e,{recursive:!0}),sp(t,"")}catch{}}function Qr(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=ap(),t=Pt(e,"first-run-acked");try{if(op(t))return}catch{return}if(cp()){Jr(e,t);return}let o=[`${In.cyan("\u2139")} Nebutra collects anonymous usage analytics to improve the scaffolder.`,` Opt out at any time: ${In.dim("export NEBUTRA_TELEMETRY=0")}`,` Privacy policy: ${In.dim("https://nebutra.com/legal/cli-analytics")}`,""];try{process.stderr.write(o.join(`
2908
- `))}catch{}Jr(e,t)}import dt from"fs";import ye from"path";import*as D from"@clack/prompts";var Se="my-app",pp=new Set([".DS_Store",".Spotlight-V100",".Trashes","Thumbs.db","desktop.ini"]),Zr=new Set(["package.json","node_modules","pnpm-workspace.yaml","pnpm-lock.yaml","yarn.lock","package-lock.json","bun.lockb","turbo.json"]);function Tn(e){let t=e.trim();return t==="."||t==="./"||t===".\\"}function xn(e){if(!dt.existsSync(e))return!0;let t;try{t=dt.readdirSync(e)}catch{return!1}return t.every(n=>pp.has(n)||n===".git")}function Rn(e){if(!dt.existsSync(e))return!1;let t;try{t=dt.readdirSync(e)}catch{return!0}return t.some(n=>Zr.has(n))}function lp(e=process.cwd()){return xn(e)&&!Rn(e)}function es(e){let t=e.trim();if(!t)return"Please enter a project name.";if(t.length>128)return"Name is too long (max 128 characters).";if(!Tn(t)&&!(/[\\/]/.test(t)||ye.isAbsolute(t))&&!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(t))return"Use letters, numbers, dots, underscores, or hyphens (start with a letter or number)."}function lt(e,t=process.cwd()){let n=e.trim()||Se;if(Tn(n)){let a=ye.resolve(t);return{targetDir:".",projectName:ye.basename(a)||Se,absoluteDir:a}}if(ye.isAbsolute(n)||n.startsWith("./")||n.startsWith(".\\")||n.startsWith("../")||n.startsWith("..\\")||n.includes("/")||n.includes("\\")){let a=ye.resolve(t,n);return{targetDir:n,projectName:ye.basename(a)||Se,absoluteDir:a}}let r=es(n);if(r)throw new Error(r);let s=`./${n}`,i=ye.resolve(t,n);return{targetDir:s,projectName:n,absoluteDir:i}}async function ts(e={}){let t=e.cwd??process.cwd(),n=e.onCancel??(()=>{process.stdout.write(`Cancelled
2909
- `),process.exit(130)}),o=lp(t),r=ye.basename(t)||t,s=await D.select({message:"Create the project\u2026",options:[{value:"new",label:"In a new folder",hint:o?void 0:"recommended from home or a parent directory"},{value:"current",label:"In the current directory",hint:o?`${r} looks empty \u2014 good to go`:t}],initialValue:o?"current":"new"});if(D.isCancel(s)&&n(),s==="current"){if(Rn(t)){let c=dt.readdirSync(t).filter(p=>Zr.has(p)).slice(0,4).join(", ");D.log.error(`Current directory already looks like a project (${c}). Choose a new folder, or pass a different path: create-sailor my-app`),n()}if(!xn(t)){let c=await D.confirm({message:"Current directory is not empty. Scaffold files will be mixed in \u2014 continue?",initialValue:!1});(D.isCancel(c)||!c)&&n()}return lt(".",t)}let i=await D.text({message:"What should we call your project?",placeholder:Se,defaultValue:Se,validate:c=>{let p=(c??"").trim()||Se;if(Tn(p)||/[\\/]/.test(p)||ye.isAbsolute(p))try{lt(p,t);return}catch(d){return d instanceof Error?d.message:"Invalid path."}return es(p)}});D.isCancel(i)&&n();let a=lt(String(i).trim()||Se,t);if(dt.existsSync(a.absoluteDir)&&!xn(a.absoluteDir)){Rn(a.absoluteDir)&&(D.log.error(`Folder "${a.projectName}" already exists and looks like a project. Pick another name.`),n());let c=await D.confirm({message:`Folder "${a.projectName}" is not empty. Continue?`,initialValue:!1});(D.isCancel(c)||!c)&&n()}return a}import*as j from"@clack/prompts";function dp(e){return{...e.config,region:e.region,orm:e.orm,database:e.database,databaseHost:e.databaseHost,payment:e.payment,aiMode:e.aiMode,aiRouting:e.aiRouting,aiProviders:e.aiProviders,customAiEndpoint:e.customAiEndpoint,deployTarget:e.deployTarget,deployTargets:e.deployTargets,docs:e.docs,i18n:e.i18n,email:e.email,storage:e.storage,monitoring:e.monitoring,analytics:e.analytics,sms:e.sms,queue:e.queue,search:e.search,cache:e.cache,notifications:e.notifications,webhooks:e.webhooks,cms:e.cms,featureFlags:e.featureFlags,captcha:e.captcha,mcp:e.mcp,metering:e.metering,billingMode:e.billingMode,idp:e.idp,accessGate:e.accessGate}}function up(e){e.previewSelections=It([{flag:"queue",provider:e.queue},{flag:"search",provider:e.search},{flag:"notifications",provider:e.notifications},{flag:"webhooks",provider:e.webhooks},{flag:"feature-flags",provider:e.featureFlags},{flag:"captcha",provider:e.captcha},{flag:"access-gate",provider:e.accessGate}]),e.config=dp(e)}async function mp(e,t){let n=await j.select({message:"Payment provider",options:[{value:"stripe",label:"Stripe",hint:"global default"},{value:"lemon",label:"Lemon Squeezy"},{value:"wechat",label:"WeChat Pay",hint:"CN"},{value:"alipay",label:"Alipay",hint:"CN"},{value:"none",label:"None"}],initialValue:e.paymentChoice});j.isCancel(n)&&t();let o=String(n);e.payment=gt(o),e.paymentChoice=ft(o);let r=await j.select({message:"Email provider",options:rt.map(a=>({value:a.id,label:a.name,hint:a.region==="cn"?"CN":a.id==="none"?void 0:"global"})),initialValue:e.email});j.isCancel(r)&&t(),e.email=String(r);let s=await j.select({message:"Object storage",options:Re.map(a=>({value:a.id,label:a.name,hint:a.region==="cn"?"CN":a.id==="none"?void 0:"global"})),initialValue:e.storage});j.isCancel(s)&&t(),e.storage=String(s);let i=await j.select({message:"Deploy target",options:[{value:"vercel",label:"Vercel",hint:"recommended for Next.js"},{value:"railway",label:"Railway"},{value:"cloudflare",label:"Cloudflare"},{value:"selfhost",label:"Self-host / Docker"}],initialValue:e.deployTarget});j.isCancel(i)&&t(),e.deployTarget=yt(String(i)),e.deployTargets=Ct(e.deployTarget),up(e)}async function ns(e,t){let n={...e,config:{...e.config},aiProviders:[...e.aiProviders],socialLoginIds:[...e.socialLoginIds],previewSelections:[...e.previewSelections],deployTargets:{...e.deployTargets},waveToggles:{...e.waveToggles}},o=await j.select({message:"Create project with these settings?",options:[{value:"proceed",label:"Yes, create project",hint:"use region defaults above"},{value:"customize",label:"Customize key providers",hint:"payment \xB7 email \xB7 storage \xB7 deploy"},{value:"cancel",label:"Cancel"}],initialValue:"proceed"});return(j.isCancel(o)||o==="cancel")&&t(),o==="customize"&&(await mp(n,t),j.log.success("Defaults updated \u2014 scaffolding with your choices.")),n}function xe(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2910
- `)}function fp(e,t,n,o,r){let{region:s,orm:i,database:a,paymentChoice:c,docs:p,socialLoginIds:d,aiMode:u,aiProviders:A,customAiEndpoint:h,deployTarget:g,metering:E,payment:S,billingMode:m,idp:_,mcp:H,waveToggles:M,previewSelections:he}=t,{email:le,storage:ee,monitoring:V,analytics:K,sms:C,queue:W,search:de,cache:w,notifications:Ee,webhooks:ze,cms:Je,featureFlags:ve,captcha:v}=t,R=A.length,P=[`clone template \u2192 ${n}`,"write nebutra.config.json",`governance-lints \u2192 write governance.config.json + wire pnpm lint (no-raw-inputs${a!=="none"?" + repository-seam":""})`,`prune template (orm=${i}, i18n=${t.i18n})`,`region \u2192 ${s}`,`auth \u2192 ${t.auth==="none"?"skip (remove packages/auth)":`configure ${t.auth}`}`,...d.length>0?[`social-login \u2192 generate ${d.length} callback route${d.length===1?"":"s"} + SocialLoginButtons.tsx (${d.join(", ")})`]:[],`db \u2192 ${a==="none"?"skip (remove packages/db)":`configure Prisma for ${a}`}`,...a!=="none"?[`db-host \u2192 configure ${t.databaseHost}`]:[],`payment \u2192 ${c==="none"?"skip (remove packages/billing)":`configure ${c}`}`,...p!=="none"?[`docs \u2192 scaffold apps/docs (${p==="fumadocs"?"fumadocs":`${p} \u2192 fumadocs fallback`})`]:[],...R>0||h?[`ai-providers \u2192 generate ${u} registry seed + env (${R}${h?" + custom":""} provider${R===1&&!h?"":"s"})`]:[],...le!=="none"?[`email \u2192 configure ${le}`]:[],...ee!=="none"?[`storage \u2192 configure ${ee}`]:[],...V!=="none"?[`monitoring \u2192 configure ${V}`]:[],...K!=="none"?[`analytics \u2192 configure ${K}`]:[],...C!=="none"?[`sms \u2192 configure ${C}`]:[],...W!=="none"?[`queue \u2192 configure ${W}`]:[],...de!=="none"?[`search \u2192 configure ${de}`]:[],...w!=="none"?[`cache \u2192 configure ${w}`]:[],...Ee!=="none"?[`notifications \u2192 configure ${Ee}`]:[],...ze!=="none"?[`webhooks \u2192 configure ${ze}`]:[],...Je!=="none"?[`cms \u2192 configure ${Je}`]:[],...ve!=="none"?[`feature-flags \u2192 configure ${ve}`]:[],...v!=="none"?[`captcha \u2192 configure ${v}`]:[],`mcp \u2192 ${H==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${E==="off"?"disabled":E==="auto"?S!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...m!=="usage"?[`billing-mode \u2192 ${m}`]:[],..._!=="clerk"?[`idp \u2192 ${_}`]:[],`cron-jobs \u2192 ${M.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${M.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${M.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${M.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${M.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${M.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${M.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${s} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...g!=="none"?[`deploy \u2192 inject ${g} config`]:[],"inject .env.local",r.install===!1?"skip install":`run ${o} install`,r.git===!1?"skip git init":"run git init"];if(e){for(let I of P)xe(!0,{event:"plan",action:I});for(let I of he)xe(!0,{event:"warn",step:I.flag,provider:I.provider,packageStatus:I.status});xe(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2911
- `+L.bold(`Dry run \u2014 planned actions:
2912
- `));for(let I of P)process.stdout.write(` \u2022 ${I}
2913
- `);if(he.length>0){process.stdout.write(`
2914
- `+L.bold(L.yellow(`Preview-status providers selected:
2915
- `)));for(let I of he)process.stdout.write(L.yellow(`\u26A0 ${I.flag}=${I.provider}
2916
- `))}process.stdout.write(L.dim(`
2921
+ `;function ns(){process.stdout.write(fp)}import Wt from"picocolors";function os(){return!process.env.NO_COLOR&&!!process.stdout.isTTY}function yp(e){let t=os()?"\u25B8":"->",n=`[${e.index}/${e.total}]`,o=e.label.padEnd(18," ");return os()?`${Wt.dim(n)} ${Wt.bold(o)} ${Wt.dim(t)} ${Wt.cyan(e.value)}`:`${n} ${o} ${t} ${e.value}`}function rs(e){process.stdout.write(yp(e)+`
2922
+ `)}import{existsSync as Sp,mkdirSync as hp,writeFileSync as Ep}from"fs";import{homedir as ss,platform as vp}from"os";import{join as Ct}from"path";import Nn from"picocolors";function bp(){if(vp()==="win32"){let t=process.env.LOCALAPPDATA||Ct(ss(),"AppData","Local");return Ct(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Ct(e,"nebutra"):Ct(ss(),".config","nebutra")}function _p(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function is(e,t){try{hp(e,{recursive:!0}),Ep(t,"")}catch{}}function as(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=bp(),t=Ct(e,"first-run-acked");try{if(Sp(t))return}catch{return}if(_p()){is(e,t);return}let o=[`${Nn.cyan("\u2139")} Nebutra collects anonymous usage analytics to improve the scaffolder.`,` Opt out at any time: ${Nn.dim("export NEBUTRA_TELEMETRY=0")}`,` Privacy policy: ${Nn.dim("https://nebutra.com/legal/cli-analytics")}`,""];try{process.stderr.write(o.join(`
2923
+ `))}catch{}is(e,t)}import mt from"fs";import wp from"os";import B from"path";import*as L from"@clack/prompts";var he="my-app",Pp=new Set([".DS_Store",".Spotlight-V100",".Trashes","Thumbs.db","desktop.ini"]),cs=new Set(["package.json","node_modules","pnpm-workspace.yaml","pnpm-lock.yaml","yarn.lock","package-lock.json","bun.lockb","turbo.json"]);function Ap(){let e=wp.homedir(),t=new Map,n=(o,r)=>{o&&t.set(B.resolve(o),r)};n(e,"your home directory"),n(B.parse(e||"/").root,"the filesystem root");for(let o of["Desktop","Documents","Downloads","Library","Movies","Music","Pictures","Public"])e&&n(B.join(e,o),`your ${o} folder`);return n(process.env.XDG_CONFIG_HOME,"your config directory"),e&&n(B.join(e,".config"),"your config directory"),t}function It(e){let t=B.resolve(e);return Ap().get(t)}function Un(e){let t=e.trim();return t==="."||t==="./"||t===".\\"}function On(e){if(!mt.existsSync(e))return!0;let t;try{t=mt.readdirSync(e)}catch{return!1}return t.every(n=>Pp.has(n)||n===".git")}function Ln(e){if(!mt.existsSync(e))return!1;let t;try{t=mt.readdirSync(e)}catch{return!0}return t.some(n=>cs.has(n))}function Cp(e=process.cwd()){return On(e)&&!Ln(e)}function ps(e){let t=e.trim();if(!t)return"Please enter a project name.";if(t.length>128)return"Name is too long (max 128 characters).";if(!Un(t)&&!(/[\\/]/.test(t)||B.isAbsolute(t))&&!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(t))return"Use letters, numbers, dots, underscores, or hyphens (start with a letter or number)."}function ut(e,t=process.cwd()){let n=e.trim()||he;if(Un(n)){let a=B.resolve(t);return{targetDir:".",projectName:B.basename(a)||he,absoluteDir:a}}if(B.isAbsolute(n)||n.startsWith("./")||n.startsWith(".\\")||n.startsWith("../")||n.startsWith("..\\")||n.includes("/")||n.includes("\\")){let a=B.resolve(t,n);return{targetDir:n,projectName:B.basename(a)||he,absoluteDir:a}}let r=ps(n);if(r)throw new Error(r);let s=`./${n}`,i=B.resolve(t,n);return{targetDir:s,projectName:n,absoluteDir:i}}async function ls(e={}){let t=e.cwd??process.cwd(),n=e.onCancel??(()=>{process.stdout.write(`Cancelled
2924
+ `),process.exit(130)}),o=Cp(t),r=B.basename(t)||t,s=It(t),i=s?"new":await L.select({message:"Create the project\u2026",options:[{value:"new",label:"In a new folder",hint:o?void 0:"recommended from home or a parent directory"},{value:"current",label:"In the current directory",hint:o?`${r} looks empty \u2014 good to go`:t}],initialValue:o?"current":"new"});if(s&&L.log.info(`You're in ${s} \u2014 Sailor will create a subfolder here instead.`),L.isCancel(i)&&n(),i==="current"){let p=It(t);if(p&&(L.log.error(`Refusing to scaffold directly into ${p} (${t}). Run create-sailor from an empty folder, or pass a name: create-sailor my-app`),n()),Ln(t)){let m=mt.readdirSync(t).filter(d=>cs.has(d)).slice(0,4).join(", ");L.log.error(`Current directory already looks like a project (${m}). Choose a new folder, or pass a different path: create-sailor my-app`),n()}if(!On(t)){let m=await L.confirm({message:"Current directory is not empty. Scaffold files will be mixed in \u2014 continue?",initialValue:!1});(L.isCancel(m)||!m)&&n()}return ut(".",t)}let a=await L.text({message:"What should we call your project?",placeholder:he,defaultValue:he,validate:p=>{let m=(p??"").trim()||he;if(Un(m)||/[\\/]/.test(m)||B.isAbsolute(m))try{let d=ut(m,t),v=It(d.absoluteDir);return v?`That path is ${v} \u2014 choose a subfolder.`:void 0}catch(d){return d instanceof Error?d.message:"Invalid path."}return ps(m)}});L.isCancel(a)&&n();let c=ut(String(a).trim()||he,t);if(mt.existsSync(c.absoluteDir)&&!On(c.absoluteDir)){Ln(c.absoluteDir)&&(L.log.error(`Folder "${c.projectName}" already exists and looks like a project. Pick another name.`),n());let p=await L.confirm({message:`Folder "${c.projectName}" is not empty. Continue?`,initialValue:!1});(L.isCancel(p)||!p)&&n()}return c}import*as $ from"@clack/prompts";function Ip(e){return{...e.config,region:e.region,orm:e.orm,database:e.database,databaseHost:e.databaseHost,payment:e.payment,aiMode:e.aiMode,aiRouting:e.aiRouting,aiProviders:e.aiProviders,customAiEndpoint:e.customAiEndpoint,deployTarget:e.deployTarget,deployTargets:e.deployTargets,docs:e.docs,i18n:e.i18n,email:e.email,storage:e.storage,monitoring:e.monitoring,analytics:e.analytics,sms:e.sms,queue:e.queue,search:e.search,cache:e.cache,notifications:e.notifications,webhooks:e.webhooks,cms:e.cms,featureFlags:e.featureFlags,captcha:e.captcha,mcp:e.mcp,metering:e.metering,billingMode:e.billingMode,idp:e.idp,accessGate:e.accessGate}}function Tp(e){e.previewSelections=Rt([{flag:"queue",provider:e.queue},{flag:"search",provider:e.search},{flag:"notifications",provider:e.notifications},{flag:"webhooks",provider:e.webhooks},{flag:"feature-flags",provider:e.featureFlags},{flag:"captcha",provider:e.captcha},{flag:"access-gate",provider:e.accessGate}]),e.config=Ip(e)}async function xp(e,t){let n=await $.select({message:"Payment provider",options:[{value:"stripe",label:"Stripe",hint:"global default"},{value:"lemon",label:"Lemon Squeezy"},{value:"wechat",label:"WeChat Pay",hint:"CN"},{value:"alipay",label:"Alipay",hint:"CN"},{value:"none",label:"None"}],initialValue:e.paymentChoice});$.isCancel(n)&&t();let o=String(n);e.payment=yt(o),e.paymentChoice=St(o);let r=await $.select({message:"Email provider",options:st.map(a=>({value:a.id,label:a.name,hint:a.region==="cn"?"CN":a.id==="none"?void 0:"global"})),initialValue:e.email});$.isCancel(r)&&t(),e.email=String(r);let s=await $.select({message:"Object storage",options:ke.map(a=>({value:a.id,label:a.name,hint:a.region==="cn"?"CN":a.id==="none"?void 0:"global"})),initialValue:e.storage});$.isCancel(s)&&t(),e.storage=String(s);let i=await $.select({message:"Deploy target",options:[{value:"vercel",label:"Vercel",hint:"recommended for Next.js"},{value:"railway",label:"Railway"},{value:"cloudflare",label:"Cloudflare"},{value:"selfhost",label:"Self-host / Docker"}],initialValue:e.deployTarget});$.isCancel(i)&&t(),e.deployTarget=ht(String(i)),e.deployTargets=xt(e.deployTarget),Tp(e)}async function ds(e,t){let n={...e,config:{...e.config},aiProviders:[...e.aiProviders],socialLoginIds:[...e.socialLoginIds],previewSelections:[...e.previewSelections],deployTargets:{...e.deployTargets},waveToggles:{...e.waveToggles}},o=await $.select({message:"Create project with these settings?",options:[{value:"proceed",label:"Yes, create project",hint:"use region defaults above"},{value:"customize",label:"Customize key providers",hint:"payment \xB7 email \xB7 storage \xB7 deploy"},{value:"cancel",label:"Cancel"}],initialValue:"proceed"});return($.isCancel(o)||o==="cancel")&&t(),o==="customize"&&(await xp(n,t),$.log.success("Defaults updated \u2014 scaffolding with your choices.")),n}function Ee(e,t){e&&process.stdout.write(JSON.stringify(t)+`
2925
+ `)}function kp(e,t,n,o,r){let{region:s,orm:i,database:a,paymentChoice:c,docs:p,socialLoginIds:m,aiMode:d,aiProviders:v,customAiEndpoint:g,deployTarget:h,metering:P,payment:E,billingMode:l,idp:y,mcp:U,waveToggles:R,previewSelections:ve}=t,{email:ue,storage:oe,monitoring:G,analytics:q,sms:I,queue:z,search:V,cache:A,notifications:Re,webhooks:be,cms:Je,featureFlags:Qe,captcha:_e}=t,b=v.length,D=[`clone template \u2192 ${n}`,"write nebutra.config.json",`governance-lints \u2192 write governance.config.json + wire pnpm lint (no-raw-inputs${a!=="none"?" + repository-seam":""})`,`prune template (orm=${i}, i18n=${t.i18n})`,`region \u2192 ${s}`,`auth \u2192 ${t.auth==="none"?"skip (remove packages/auth)":`configure ${t.auth}`}`,...m.length>0?[`social-login \u2192 generate ${m.length} callback route${m.length===1?"":"s"} + SocialLoginButtons.tsx (${m.join(", ")})`]:[],`db \u2192 ${a==="none"?"skip (remove packages/db)":`configure Prisma for ${a}`}`,...a!=="none"?[`db-host \u2192 configure ${t.databaseHost}`]:[],`payment \u2192 ${c==="none"?"skip (remove packages/billing)":`configure ${c}`}`,...p!=="none"?[`docs \u2192 scaffold apps/docs (${p==="fumadocs"?"fumadocs":`${p} \u2192 fumadocs fallback`})`]:[],...b>0||g?[`ai-providers \u2192 generate ${d} registry seed + env (${b}${g?" + custom":""} provider${b===1&&!g?"":"s"})`]:[],...ue!=="none"?[`email \u2192 configure ${ue}`]:[],...oe!=="none"?[`storage \u2192 configure ${oe}`]:[],...G!=="none"?[`monitoring \u2192 configure ${G}`]:[],...q!=="none"?[`analytics \u2192 configure ${q}`]:[],...I!=="none"?[`sms \u2192 configure ${I}`]:[],...z!=="none"?[`queue \u2192 configure ${z}`]:[],...V!=="none"?[`search \u2192 configure ${V}`]:[],...A!=="none"?[`cache \u2192 configure ${A}`]:[],...Re!=="none"?[`notifications \u2192 configure ${Re}`]:[],...be!=="none"?[`webhooks \u2192 configure ${be}`]:[],...Je!=="none"?[`cms \u2192 configure ${Je}`]:[],...Qe!=="none"?[`feature-flags \u2192 configure ${Qe}`]:[],..._e!=="none"?[`captcha \u2192 configure ${_e}`]:[],`mcp \u2192 ${U==="on"?"enable MCP server":"remove packages/mcp"}`,`metering \u2192 ${P==="off"?"disabled":P==="auto"?E!=="none"?"enabled (auto: payment set)":"disabled (auto: no payment)":"enabled"}`,...l!=="usage"?[`billing-mode \u2192 ${l}`]:[],...y!=="clerk"?[`idp \u2192 ${y}`]:[],`cron-jobs \u2192 ${R.cronJobs?"enabled":"disabled"}`,`audit-log \u2192 ${R.auditLog?"enabled":"disabled"}`,`api-keys \u2192 ${R.apiKeys?"enabled":"disabled"}`,`command-palette \u2192 ${R.commandPalette?"enabled":"disabled"}`,`cookie-consent \u2192 ${R.cookieConsent?"enabled":"disabled"}`,`legal-pages \u2192 ${R.legalPages?"enabled":"disabled"}`,`china-compliance \u2192 ${R.chinaCompliance?"enabled (@nebutra/china-compliance + ICP footer)":"disabled"}`,`compliance \u2192 inject ${s} boilerplate (ICP/Cookie/AIGC/Privacy)`,"welcome \u2192 generate dev welcome page","env \u2192 generate random secrets (AUTH_SECRET, JWT_SECRET)","seed \u2192 generate prisma/seed.ts (1 admin + 3 tenants)",...h!=="none"?[`deploy \u2192 inject ${h} config`]:[],"inject .env.local",r.install===!1?"skip install":`run ${o} install`,r.git===!1?"skip git init":"run git init"];if(e){for(let _ of D)Ee(!0,{event:"plan",action:_});for(let _ of ve)Ee(!0,{event:"warn",step:_.flag,provider:_.provider,packageStatus:_.status});Ee(!0,{event:"done",dryRun:!0})}else{process.stdout.write(`
2926
+ `+x.bold(`Dry run \u2014 planned actions:
2927
+ `));for(let _ of D)process.stdout.write(` \u2022 ${_}
2928
+ `);if(ve.length>0){process.stdout.write(`
2929
+ `+x.bold(x.yellow(`Preview-status providers selected:
2930
+ `)));for(let _ of ve)process.stdout.write(x.yellow(`\u26A0 ${_.flag}=${_.provider}
2931
+ `))}process.stdout.write(x.dim(`
2917
2932
  No files were written.
2918
- `))}}async function yp(){let e=jn();e.parse(process.argv);let t=e.opts(),[n]=e.args;t.help&&(Hr(),process.exit(0));let o=!!t.json,r=!!t.dryRun,i=!!t.yes||!process.stdin.isTTY;if(o||(Qr(),Gr()),xe(o,{event:"start",version:z}),!t.pm)try{gp("pnpm --version",{stdio:"ignore"})}catch{o||process.stderr.write(`
2919
- ${L.red("\u2718")} ${L.bold("pnpm is required")} but was not found on PATH.
2933
+ `))}}async function Np(){let e=Gn();e.parse(process.argv);let t=e.opts(),[n]=e.args;t.help&&(ns(),process.exit(0));let o=!!t.json,r=!!t.dryRun,i=!!t.yes||!process.stdin.isTTY;if(o||(as(),ts()),Ee(o,{event:"start",version:Q}),!t.pm)try{Rp("pnpm --version",{stdio:"ignore"})}catch{o||process.stderr.write(`
2934
+ ${x.red("\u2718")} ${x.bold("pnpm is required")} but was not found on PATH.
2920
2935
 
2921
2936
  The scaffold uses pnpm workspaces + Turborepo. Install pnpm first:
2922
- ${L.cyan("npm i -g pnpm@10")}
2937
+ ${x.cyan("npm i -g pnpm@10")}
2938
+
2939
+ Then retry: ${x.cyan("pnpm dlx create-sailor@latest")}
2940
+ (or pass ${x.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
2923
2941
 
2924
- Then retry: ${L.cyan("pnpm dlx create-sailor@latest")}
2925
- (or pass ${L.dim("--pm=npm")} if you know workspace:* won't resolve in your setup)
2942
+ `),Ee(o,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let a=()=>{process.stdout.write(x.red(`\u2718 Cancelled
2943
+ `)),process.exit(130)},c,p;if(n)try{let l=ut(n);c=l.targetDir,p=l.projectName}catch(l){let y=l instanceof Error?l.message:String(l);process.stderr.write(`
2944
+ ${x.red("\u2718")} ${y}
2926
2945
 
2927
- `),xe(o,{event:"error",code:"PNPM_MISSING"}),process.exit(1)}let a=()=>{process.stdout.write(L.red(`\u2718 Cancelled
2928
- `)),process.exit(130)},c,p;if(n)try{let g=lt(n);c=g.targetDir,p=g.projectName}catch(g){let E=g instanceof Error?g.message:String(g);process.stderr.write(`
2929
- ${L.red("\u2718")} ${E}
2946
+ `),Ee(o,{event:"error",code:"INVALID_PROJECT_NAME",message:y}),process.exit(1)}else if(i){let l=ut(he);c=l.targetDir,p=l.projectName}else{let l=await ls({onCancel:a});c=l.targetDir,p=l.projectName,o||process.stdout.write(x.dim(` \u2192 ${l.absoluteDir}
2947
+ `))}{let l=It(Dn.resolve(c));if(l){let y=`Refusing to scaffold into ${l} (${Dn.resolve(c)}).
2948
+ Create a folder for the project instead: ${x.cyan("create-sailor my-app")}`;o||process.stderr.write(`
2949
+ ${x.red("\u2718")} ${y}
2930
2950
 
2931
- `),xe(o,{event:"error",code:"INVALID_PROJECT_NAME",message:E}),process.exit(1)}else if(i){let g=lt(Se);c=g.targetDir,p=g.projectName}else{let g=await ts({onCancel:a});c=g.targetDir,p=g.projectName,o||process.stdout.write(L.dim(` \u2192 ${g.absoluteDir}
2932
- `))}let d=t.pm??Yn(),u=await no(t,o),A=[["Project",p],["Region",u.region],["Auth",u.auth],["Payment",u.paymentChoice],["AI",`${u.aiMode}${u.aiProviders.length>0?` (${u.aiProviders.join(", ")})`:""}`],["Database",`${u.database} \xB7 ${u.databaseHost}`],["Email",u.email],["Storage",u.storage],["Deploy",u.deployTarget]];u.socialLoginIds.length>0&&A.push(["Social login",u.socialLoginIds.map(g=>Ze.find(E=>E.id===g)?.name??g).join(", ")]),o?A.forEach(([g,E],S)=>{xe(!0,{event:"step",step:g,value:E,index:S+1,total:A.length})}):(process.stdout.write(L.dim(`
2951
+ `),Ee(o,{event:"error",code:"UNSAFE_TARGET_DIR",message:y}),process.exit(1)}}let m=t.pm??zn(),d=await co(t,o),v=[["Project",p],["Region",d.region],["Auth",d.auth],["Payment",d.paymentChoice],["AI",`${d.aiMode}${d.aiProviders.length>0?` (${d.aiProviders.join(", ")})`:""}`],["Database",`${d.database} \xB7 ${d.databaseHost}`],["Email",d.email],["Storage",d.storage],["Deploy",d.deployTarget]];d.socialLoginIds.length>0&&v.push(["Social login",d.socialLoginIds.map(l=>et.find(y=>y.id===l)?.name??l).join(", ")]),o?v.forEach(([l,y],U)=>{Ee(!0,{event:"step",step:l,value:y,index:U+1,total:v.length})}):(process.stdout.write(x.dim(`
2933
2952
  Plan
2934
- `)),A.forEach(([g,E],S)=>{Xr({index:S+1,total:A.length,label:g,value:E})}),process.stdout.write(`
2935
- `)),!i&&!o&&(u=await ns(u,a)),r&&(fp(o,u,c,d,t),process.exit(0));let h=async()=>{process.stdout.write(`
2936
- `+L.red(`\u2718 Cancelled
2937
- `)),os.existsSync(c)&&await rs.confirm({message:`Cleanup partial install at ${c}?`,initialValue:!0})===!0&&(os.rmSync(c,{recursive:!0,force:!0}),process.stdout.write(L.dim(` \u2713 Removed ${c}
2938
- `))),process.exit(130)};process.on("SIGINT",h);try{await qr({resolvedTarget:c,projectName:p,resolvedPm:d,opts:t,useJson:o,resolved:u,startedAt:Date.now()}),process.exit(0)}catch(g){let E=g instanceof Error?g.message:String(g);o?xe(!0,{event:"error",message:E}):process.stdout.write(L.red(`
2939
- \u2718 Failed: ${E}
2940
- `)),process.exit(1)}}yp().catch(e=>{process.stderr.write(String(e)+`
2953
+ `)),v.forEach(([l,y],U)=>{rs({index:U+1,total:v.length,label:l,value:y})}),process.stdout.write(`
2954
+ `)),!i&&!o&&(d=await ds(d,a)),r&&(kp(o,d,c,m,t),process.exit(0));let g=us.existsSync(c),h=[],P=()=>h,E=async()=>{process.stdout.write(`
2955
+ `+x.red(`\u2718 Cancelled
2956
+ `));let l=P();l.length===0&&g&&process.exit(130);let y=g?l.map(R=>Dn.join(c,R)):[c];if(await ms.confirm({message:g?`Remove the ${y.length} item${y.length===1?"":"s"} added to ${c}?`:`Remove the partial install at ${c}?`,initialValue:!0})===!0){for(let R of y)try{us.rmSync(R,{recursive:!0,force:!0})}catch{}process.stdout.write(x.dim(` \u2713 Cleaned up ${c}
2957
+ `))}process.exit(130)};process.on("SIGINT",E);try{await es({resolvedTarget:c,projectName:p,resolvedPm:m,opts:t,useJson:o,resolved:d,startedAt:Date.now(),reportCreatedEntries:l=>{h=l}}),process.exit(0)}catch(l){let y=l instanceof Error?l.message:String(l);o?Ee(!0,{event:"error",message:y}):process.stdout.write(x.red(`
2958
+ \u2718 Failed: ${y}
2959
+ `)),process.exit(1)}}Np().catch(e=>{process.stderr.write(String(e)+`
2941
2960
  `),process.exit(1)});