nebutra 0.6.0 → 0.6.2
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/chunk-DTSPVLT5.js +9 -0
- package/dist/delegate-MQWQZT5V.js +1 -0
- package/dist/index.js +77 -78
- package/package.json +6 -5
- package/dist/chunk-LGUMYJ4Q.js +0 -6
- package/dist/delegate-GIJ3G5CK.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as
|
|
3
|
-
`)}function re(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function en(e){let t=Me(),n=[...new Set(e.map(o=>o.toLowerCase()))],r=n.filter(o=>!t[o]);return r.length>0&&(l.error(`Unknown AI provider(s): ${r.join(", ")}. Valid providers: ${Object.keys(t).join(", ")}`),process.exit(c.INVALID_ARGS)),n}function co(e){let t=e?.split(",").map(r=>r.trim()).filter(Boolean)??[];t.length===0&&(l.error("Route fallback cannot be empty. Use --fallback provider:model,provider:model"),process.exit(c.INVALID_ARGS));let n=t.filter(r=>!/^[a-z0-9-]+:[^,\s]+$/i.test(r));return n.length>0&&(l.error(`Invalid fallback target(s): ${n.join(", ")}. Expected provider:model.`),process.exit(c.INVALID_ARGS)),t}function tn(e){let t=re(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,i])=>i.enabled).map(([i])=>i);return{path:q(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function Y(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??lo();return{...n,...t,...r?{format:r}:{}}}function lo(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function _e(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function uo(e){e.format!=="json"&&l.info("Checking configured AI models and providers...");let t={openai:{name:"OpenAI",keyVars:["OPENAI_API_KEY"],configured:!1},anthropic:{name:"Anthropic Claude",keyVars:["ANTHROPIC_API_KEY"],configured:!1},openrouter:{name:"OpenRouter",keyVars:["OPENROUTER_API_KEY"],configured:!1},vercel:{name:"Vercel AI SDK",keyVars:["VERCEL_AI_API_KEY"],configured:!1}};for(let r of Object.values(t))r.configured=r.keyVars.some(o=>process.env[o]);let n={providers:Object.entries(t).map(([r,o])=>({id:r,name:o.name,configured:o.configured,keys:o.keyVars.map(i=>({name:i,value:_e(process.env[i])}))})),configuredCount:Object.values(t).filter(r=>r.configured).length,totalProviders:Object.keys(t).length};e.dryRun||(n.configuredCount===0?l.warn("No AI providers configured. Set API keys to enable AI features."):l.success(`${n.configuredCount} AI provider(s) configured`)),W(n,e.format,"ai:models")}async function mo(e){e.format!=="json"&&l.info("Scanning for available agents...");try{let t=yt(process.cwd(),"backends/gateway/src/routes/agents"),n=[];try{let o=await import("fs");o.existsSync(t)&&(n=o.readdirSync(t).filter(a=>a.endsWith(".ts")&&!a.endsWith(".d.ts")).map(a=>({name:a.replace(".ts",""),path:`backends/gateway/src/routes/agents/${a}`})))}catch{n=[]}let r={agents:n.length>0?n:[{name:"No agents found",path:"create agents in backends/gateway/src/routes/agents/"}],count:n.length};e.dryRun||(r.count===0?l.info("No agents configured. Create agents in backends/gateway/src/routes/agents/"):l.success(`Found ${r.count} agent(s)`)),W(r,e.format,"ai:agents")}catch(t){l.error(`Failed to scan agents: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}async function po(e,t){(!e||e.trim().length===0)&&(l.error("Prompt cannot be empty"),process.exit(c.INVALID_ARGS)),t.format!=="json"&&(l.info("Testing AI prompt against default model..."),l.info("Note: Ensure API gateway is running on http://localhost:3001"));let n={prompt:e,note:"To execute this test, the API gateway must be running locally. Run: pnpm --filter @nebutra/gateway dev",endpoint:"http://localhost:3001/api/ai/test",method:"POST",payload:{prompt:e.substring(0,100)}};t.dryRun||l.warn("AI test execution requires a running API gateway. Start it with: pnpm --filter @nebutra/gateway dev"),W(n,t.format,"ai:test")}async function fo(e){e.format!=="json"&&l.info("Checking AI configuration...");let t={providers:{openai:{key:_e(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:_e(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:_e(process.env.OPENROUTER_API_KEY),configured:!!process.env.OPENROUTER_API_KEY}},environment:{NODE_ENV:process.env.NODE_ENV||"development",NEBUTRA_LOG_LEVEL:process.env.NEBUTRA_LOG_LEVEL||"info"}};try{let r=yt(process.cwd(),"nebutra.config.ts"),o=await import("fs");if(o.existsSync(r)){let a=o.readFileSync(r,"utf-8").match(/preset:\s*["']([^"']+)["']/);a&&(t.preset=a[1])}}catch{}let n=Object.entries(t.providers).filter(([,r])=>r.configured).map(([r])=>r);e.dryRun||(n.length===0?l.warn("No AI providers configured. Set environment variables to enable AI features."):l.success(`Configuration loaded: ${n.join(", ")}`)),W(t,e.format,"ai:config")}async function go(e){let t=de(),n=re(t),r=Me(),o=Object.values(r).map(a=>{let s=n.providers?.[a.id];return{id:a.id,name:a.name,enabled:s?.enabled===!0,configured:a.envVars.some(d=>!!process.env[d]),envVars:a.envVars.map(d=>({name:d,value:_e(process.env[d])}))}}),i={configPath:q(),providers:o,enabledCount:o.filter(a=>a.enabled).length,totalProviders:o.length};if(e.format!=="json"){let a=o.filter(s=>s.enabled);a.length===0?l.warn("No runtime AI providers enabled in nebutra.config.json."):l.success(`Enabled AI providers: ${a.map(s=>s.id).join(", ")}`)}W(i,e.format,"ai:provider:list")}async function yo(e,t){let n=en(e),r=de(),o=re(r),i=Me(),a=new Date().toISOString();for(let d of n)o.providers[d]={enabled:!0,envVars:i[d].envVars,enabledAt:o.providers?.[d]?.enabledAt??a};Ge(r);let s={configPath:q(),enabled:n,env:t.env===!0?n.flatMap(d=>i[d].envVars.map(m=>({provider:d,name:m,example:`${m}=`}))):void 0,ai:tn(r)};if(t.format!=="json"&&(l.success(`Enabled AI provider(s): ${n.join(", ")}`),t.env)){l.info("Required environment variables:");for(let d of n)for(let m of i[d].envVars)console.log(`${m}=`)}W(s,t.format,"ai:provider:enable")}async function ho(e,t){let n=en(e),r=de(),o=re(r),i=Me(),a=new Date().toISOString();for(let d of n)o.providers[d]={enabled:!1,envVars:o.providers?.[d]?.envVars??i[d].envVars,disabledAt:a};Ge(r);let s={configPath:q(),disabled:n,ai:tn(r)};t.format!=="json"&&l.success(`Disabled AI provider(s): ${n.join(", ")}`),W(s,t.format,"ai:provider:disable")}async function bo(e){let t=de(),n=re(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},Ge(t);let o={configPath:q(),gateway:n.gateway};e.format!=="json"&&l.success("AI gateway governance initialized in nebutra.config.json"),W(o,e.format,"ai:gateway:init")}async function vo(e){let t=de(),n=re(t),r={configPath:q(),gateway:n.gateway??null,initialized:n.gateway?.enabled===!0};e.format!=="json"&&(r.initialized?l.success("AI gateway governance is initialized"):l.warn("AI gateway governance is not initialized. Run: nebutra ai gateway init")),W(r,e.format,"ai:gateway:status")}async function wo(e,t){(!e||e.trim().length===0)&&(l.error("Route name cannot be empty"),process.exit(c.INVALID_ARGS)),t.policy||(l.error("Route policy is required. Use --policy <policy>."),process.exit(c.INVALID_ARGS));let n=co(t.fallback),r=de(),o=re(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},Ge(r);let i={configPath:q(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&l.success(`AI route '${e}' set with policy '${t.policy}'`),W(i,t.format,"ai:route:set")}async function Co(e){let t=de(),n=re(t),r=Object.entries(n.routes??{}).map(([i,a])=>({name:i,...a})),o={configPath:q(),routes:r,count:r.length};e.format!=="json"&&(r.length===0?l.warn("No AI routes configured. Run: nebutra ai route set chat --policy cost-latency-balanced --fallback openai:gpt-5.4"):l.success(`Configured AI routes: ${r.map(i=>i.name).join(", ")}`)),W(o,e.format,"ai:route:list")}function nn(e){let t=e.command("ai").description("Manage AI models, agents, and configuration"),n=t.command("provider").description("Manage runtime AI provider governance");n.command("list").description("List supported and enabled AI providers").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await go({format:a.format,interactive:a.yes!==!0})}),n.command("enable <providers...>").description("Enable one or more runtime AI providers in nebutra.config.json").option("--env","Print required environment variable placeholders").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await yo(i,{env:s.env===!0,format:s.format,interactive:s.yes!==!0})}),n.command("disable <providers...>").description("Disable one or more runtime AI providers in nebutra.config.json").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await ho(i,{format:s.format,interactive:s.yes!==!0})});let r=t.command("gateway").description("Manage local AI gateway governance");r.command("init").description("Initialize the local AI gateway governance block").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await bo({format:a.format,interactive:a.yes!==!0})}),r.command("status").description("Show local AI gateway governance status").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await vo({format:a.format,interactive:a.yes!==!0})});let o=t.command("route").description("Manage AI routing policies");o.command("set <name>").description("Create or update an AI route policy").requiredOption("--policy <policy>","Routing policy id").requiredOption("--fallback <list>","Comma-separated provider:model fallback chain").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await wo(i,{policy:s.policy,fallback:s.fallback,format:s.format,interactive:s.yes!==!0})}),o.command("list").description("List configured AI routes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await Co({format:a.format,interactive:a.yes!==!0})}),t.command("models").description("List configured AI models and providers").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await uo({dryRun:a.dryRun===!0,format:a.format,interactive:a.yes!==!0})}),t.command("agents").description("List available agents in the project").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await mo({dryRun:a.dryRun===!0,format:a.format,interactive:a.yes!==!0})}),t.command("test <prompt>").description("Send a test prompt to the default AI model (requires running API gateway)").option("--dry-run","Preview without executing").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await po(i,{dryRun:s.dryRun===!0,format:s.format,interactive:s.yes!==!0})}),t.command("config").description("Show current AI configuration and provider status").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await fo({dryRun:a.dryRun===!0,format:a.format,interactive:a.yes!==!0})})}function Ie(e,t,n){if(t==="json"){let r={command:n||"brand",exitCode:e.exitCode,success:e.exitCode===0,...e.stdout&&{stdout:e.stdout},...e.stderr&&{stderr:e.stderr}};console.log(JSON.stringify(r,null,2))}else e.stdout&&console.log(e.stdout),e.stderr&&e.exitCode!==0&&console.error(e.stderr)}function rn(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function So(e){l.info("Initializing brand system...");let t=await $("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand system initialized successfully")}async function xo(e){l.info("Applying brand configuration...");let t=await $("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand applied successfully")}async function Eo(e){let t=[];e.primary&&(rn(e.primary)||(l.error(`Invalid primary color format: ${e.primary}. Expected hex format like #0033FE`),process.exit(c.INVALID_ARGS)),t.push(`--primary=${e.primary}`)),e.secondary&&(rn(e.secondary)||(l.error(`Invalid secondary color format: ${e.secondary}. Expected hex format like #0BF1C3`),process.exit(c.INVALID_ARGS)),t.push(`--secondary=${e.secondary}`)),t.length===0&&(l.warn("No colors specified. Usage: nebutra brand palette --primary=#HEX --secondary=#HEX"),l.info("Example: nebutra brand palette --primary=#0033FE --secondary=#0BF1C3"),process.exit(c.INVALID_ARGS)),l.info(`Generating color palette: ${t.join(" ")}`);let n=await O({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});Ie(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||l.success("Color palette generated successfully")}async function Ro(e){l.info("Syncing brand tokens across packages...");let t=await $("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand tokens synced successfully")}async function ko(e){l.info("Verifying brand token consistency...");let t=await $("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:verify-tokens"),t.exitCode!==0&&(l.error("Brand token verification failed. There are inconsistencies in your design tokens."),process.exit(t.exitCode)),e.dryRun||l.success("All brand tokens are consistent")}function on(e){let t=e.command("brand").description("Manage Nebutra brand system and design tokens");t.command("init").description("Initialize brand system configuration").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await So({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("apply").description("Apply brand configuration to the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await xo({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("palette").description("Generate brand color palette from custom colors").option("--primary <hex>","Primary brand color (hex format, e.g. #0033FE)").option("--secondary <hex>","Secondary brand color (hex format, e.g. #0BF1C3)").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await Eo({primary:n.primary,secondary:n.secondary,dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("sync").description("Synchronize brand tokens across all packages").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await Ro({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("verify").description("Verify brand token consistency across the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await ko({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import{appendFileSync as Oo,existsSync as Ao,readFileSync as _o,writeFileSync as Io}from"fs";import{homedir as Ne}from"os";import{join as Se}from"path";import*as L from"@clack/prompts";import D from"picocolors";var H={name:"nebutra",description:"Nebutra \u2014 the CLI for Sailor projects: status, dev, db, and codegen",usage:"nebutra [command] [options]",options:[{flags:"--format <type>",description:"Output format: json, table, plain"},{flags:"--yes, --no-interactive",description:"Skip all interactive prompts (Agent mode)"},{flags:"--no-color",description:"Disable colored output"},{flags:"--verbose",description:"Enable verbose output"},{flags:"--quiet",description:"Suppress non-essential output"}],subcommands:[{name:"init",description:"Initialize a Nebutra project and create nebutra.config.json",usage:"nebutra init [options]",options:[{flags:"--dry-run",description:"Preview changes without writing files (exits with code 10)"},{flags:"--yes",description:"Skip all interactive prompts (Agent mode)"},{flags:"--if-not-exists",description:"Skip initialization if nebutra.config.json already exists"}],arguments:[],examples:[{command:"nebutra init",description:"Initialize Nebutra configuration in the current directory"},{command:"nebutra init --dry-run",description:"Preview initialization changes without writing files"},{command:"nebutra init --yes --if-not-exists",description:"Initialize without prompts, skip if already configured"}]},{name:"mcp",description:"Start the Nebutra MCP server for AI agents and editors",usage:"nebutra mcp [options]",arguments:[],options:[{flags:"--stdio",description:"Use stdio transport for communication (default: enabled)",default:!0},{flags:"--verbose",description:"Enable verbose logging for MCP server"}],examples:[{command:"nebutra mcp",description:"Start the MCP server for AI-powered project context integration"},{command:"nebutra mcp --verbose",description:"Start the MCP server with detailed logging output"}]},{name:"schema",description:"Show command schema and argument documentation (Agent-friendly JSON output)",usage:"nebutra schema [command] [options]",arguments:[{name:"command",description:"Command name to show schema for (e.g., init, dev, db)",required:!1}],options:[{flags:"--all",description:"Show full schema for all commands as JSON",default:!1},{flags:"--list",description:"List all available command names",default:!1},{flags:"--exit-codes",description:"Show exit codes reference",default:!1}],examples:[{command:"nebutra schema --all",description:"Show complete JSON of all commands, args, options, value domains"},{command:"nebutra schema init",description:"Show schema for init command (arguments, options, defaults, examples)"},{command:"nebutra schema --list",description:"List just the command names (quick discovery)"},{command:"nebutra schema --exit-codes",description:"Show exit codes reference for all possible exit codes"}]},{name:"brand",description:"Manage governed brand tokens, palettes, and visual system outputs",usage:"nebutra brand [subcommand]",examples:[{command:"nebutra brand palette --primary=#0047FF",description:"Generate a token-aligned blue palette"}]},{name:"i18n",description:"Manage localization files and multilingual product copy",usage:"nebutra i18n [subcommand]"},{name:"infra",description:"Manage local infrastructure services for Nebutra development",usage:"nebutra infra [subcommand]",examples:[{command:"nebutra infra up --lite",description:"Start lightweight local infrastructure"}]},{name:"env",description:"Validate and manage environment variables across apps and packages",usage:"nebutra env [subcommand]"},{name:"license",description:"Manage Nebutra Sailor commercial license activation and status",usage:"nebutra license [subcommand]",arguments:[],options:[],subcommands:[{name:"activate",description:"Activate a commercial license key for local development",usage:"nebutra license activate <key>",arguments:[{name:"key",description:"Your Nebutra Sailor commercial license key",required:!0}],options:[{flags:"--quiet",description:"Suppress output"}],examples:[{command:"nebutra license activate liz_1234567890",description:"Activate your license key globally"}]},{name:"status",description:"Check the locally configured license status",usage:"nebutra license status",arguments:[],options:[{flags:"--quiet",description:"Suppress output"}],examples:[{command:"nebutra license status",description:"Check if you have an active license"}]}]},{name:"ai",description:"Configure AI providers, gateway routing, and agent-ready defaults",usage:"nebutra ai [subcommand]"},{name:"db",description:"Manage database schema, migrations, seeds, and generated clients",usage:"nebutra db [subcommand]"},{name:"generate",description:"Generate apps, modules, API surfaces, and typed project artifacts",usage:"nebutra generate [type] [name]"},{name:"dev",description:"Start development workflows for selected Nebutra apps or presets",usage:"nebutra dev [options]"},{name:"build",description:"Run build workflows through the Nebutra CLI",usage:"nebutra build [options]"},{name:"lint",description:"Run lint workflows through the Nebutra CLI",usage:"nebutra lint [options]"},{name:"typecheck",description:"Run TypeScript checks through the Nebutra CLI",usage:"nebutra typecheck [options]"},{name:"test",description:"Run unit, architecture, and E2E verification workflows",usage:"nebutra test [scope]"},{name:"e2e",description:"Run browser end-to-end verification suites",usage:"nebutra e2e [suite]"},{name:"theme",description:"Inspect registry-backed Nebutra themes and governance metadata",usage:"nebutra theme [subcommand]"},{name:"ui",description:"Search, inspect, validate, and plan migrations for @nebutra/ui components",usage:"nebutra ui [subcommand]"},{name:"services",description:"Inspect and manage microservice health, logs, scaling, and rollouts",usage:"nebutra services [subcommand]"},{name:"secrets",description:"Manage encrypted tenant and platform secrets",usage:"nebutra secrets [subcommand]"},{name:"completions",description:"Generate shell completions for the current Nebutra command surface",usage:"nebutra completions [shell]",arguments:[{name:"shell",description:"Shell to generate completions for: bash, zsh, fish, or install",required:!1}]},{name:"login",description:"Authorize this machine with your Nebutra account (device flow)",usage:"nebutra login [options]",options:[{flags:"--json",description:"Print verification details as JSON and exit immediately (agent mode)"},{flags:"--no-browser",description:"Don't try to open a browser"},{flags:"--poll",description:"Poll until approved/denied/expired, resuming a pending `login --json` if present"},{flags:"--format <type>",description:"Output format: json or plain"}],examples:[{command:"nebutra login",description:"Human flow: open browser, wait for approval"},{command:"nebutra login --json",description:"Agent flow: print verification link/code and exit immediately"},{command:"nebutra login --poll --json",description:"Resume and wait for a pending login"}]},{name:"logout",description:"Clear local Nebutra CLI session state",usage:"nebutra logout"},{name:"whoami",description:"Show the Nebutra identity this machine is authorized as",usage:"nebutra whoami [options]",options:[{flags:"--json",description:"Output as JSON"},{flags:"--format <type>",description:"Output format: json or plain"}]},{name:"upgrade",description:"Upgrade local Nebutra CLI tooling",usage:"nebutra upgrade"},{name:"link",description:"Link a local project to Nebutra platform metadata",usage:"nebutra link"},{name:"unlink",description:"Unlink local Nebutra project metadata",usage:"nebutra unlink"},{name:"status",description:"Show capability readiness \u2014 live, local-fallback, or missing-key, per environment",usage:"nebutra status [options]",arguments:[],options:[{flags:"--json",description:"Emit machine-readable JSON"}],examples:[{command:"nebutra status",description:"Show a readiness table for every capability in nebutra.config.json"},{command:"nebutra status --json",description:"Emit { stack, locale, capabilities } as JSON for agents"}]},{name:"sync",description:"Make .env.example / .env.local agree with the declared capabilities (idempotent)",usage:"nebutra sync [options]",arguments:[],options:[{flags:"--dry-run",description:"Preview planned additions without writing files (exits with code 10)"},{flags:"--json",description:"Emit machine-readable JSON"}],examples:[{command:"nebutra sync",description:"Add any env keys required by declared capabilities to .env.example, create .env.local if missing"},{command:"nebutra sync --dry-run",description:"Preview planned additions without writing files"},{command:"nebutra sync --json",description:"Emit { added, unchanged, warnings } as JSON for agents"}]},{name:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var Ve=(H.subcommands??[]).map(e=>e.name),an={init:"Initialize a Nebutra project and create nebutra.config.json",mcp:"Start the Nebutra MCP server for AI agents and editors",completions:"Generate shell completions",doctor:"Check your Nebutra project setup",schema:"Show command schema and argument documentation",brand:"Manage governed brand tokens and palettes",i18n:"Manage localization files and multilingual product copy",infra:"Manage local infrastructure services",env:"Validate and manage environment variables",license:"Manage Nebutra Sailor commercial license activation and status",db:"Database migration and management",generate:"Scaffold apps, modules, and code",dev:"Start development server",build:"Run build workflows",lint:"Run lint workflows",typecheck:"Run TypeScript checks",test:"Run unit and E2E tests",e2e:"Run browser E2E suites",theme:"Theme registry and governance metadata",ai:"AI provider and gateway routing configuration",services:"Microservice management",secrets:"Encrypted secrets management",login:"Authorize this machine with your Nebutra account (device flow)",logout:"Clear local session state",whoami:"Show the authorized Nebutra identity",upgrade:"Upgrade local CLI tooling",link:"Link local project metadata",unlink:"Unlink local project metadata",status:"Show capability readiness (live/local-fallback/missing-key)",sync:"Sync .env.example/.env.local with declared capabilities"},No=["--help","--version","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--json","--no-browser","--poll"],Po=Ve.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${an[e]}"`).join(`
|
|
4
|
-
`);function sn(){return`#!/usr/bin/env bash
|
|
2
|
+
import{b as c}from"./chunk-JDX5NXDX.js";import{a as l,b as ln,c as Ye,d as un,e as ie,f as St,h as dn,i as y,j as E,k as j,l as ae,m as ge,n as ee}from"./chunk-DTSPVLT5.js";import{realpathSync as vo}from"fs";import{resolve as ko}from"path";import{fileURLToPath as wo}from"url";import{Command as Uc}from"commander";import{existsSync as Co,readFileSync as So,writeFileSync as Eo}from"fs";import{resolve as Et}from"path";var Ro=["openai","anthropic","deepseek","xai","moonshot","google","mistral","cohere","perplexity","ai21","upstage","siliconflow","volcengine-ark","bailian","zhipu","baichuan","minimax","stepfun","sensetime","tencent","lingyi","openrouter","vercel-gateway","litellm","portkey","aws-bedrock","azure-openai","gcp-vertex","groq","fireworks","together","huggingface","replicate","lepton","anyscale","octoai","deepinfra","novita","custom"],pn="nebutra.config.json",Oo=Ro,mn={"aws-bedrock":["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_REGION"],"azure-openai":["AZURE_OPENAI_API_KEY","AZURE_OPENAI_ENDPOINT"],"gcp-vertex":["GOOGLE_APPLICATION_CREDENTIALS","GOOGLE_CLOUD_PROJECT"],"vercel-gateway":["AI_GATEWAY_API_KEY"],"volcengine-ark":["VOLCENGINE_ARK_API_KEY"],bailian:["DASHSCOPE_API_KEY"],litellm:["LITELLM_API_KEY","LITELLM_BASE_URL"],portkey:["PORTKEY_API_KEY"],custom:["AI_CUSTOM_API_KEY","AI_CUSTOM_BASE_URL"]};function J(e,t,n){if(t==="json"){let r={command:n||"ai",...e&&typeof e=="object"&&"exitCode"in e?{exitCode:e.exitCode}:{},...e};console.log(JSON.stringify(r,null,2))}else e&&typeof e=="object"&&"stdout"in e&&e.stdout&&console.log(e.stdout),e&&typeof e=="object"&&"stderr"in e&&e.stderr&&(e.exitCode??0)!==0&&console.error(e.stderr)}function Ao(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function _o(e){return mn[e]?mn[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function Je(){return Object.fromEntries(Oo.map(e=>[e,{id:e,name:Ao(e),envVars:_o(e)}]))}function H(){return Et(process.cwd(),pn)}function fe(){let e=H();if(!Co(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(So(e,"utf-8"))}catch(t){c.error(`Failed to parse ${pn}: ${t instanceof Error?t.message:String(t)}`),process.exit(l.ERROR)}}function qe(e){Eo(H(),`${JSON.stringify(e,null,2)}
|
|
3
|
+
`)}function se(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function gn(e){let t=Je(),n=[...new Set(e.map(o=>o.toLowerCase()))],r=n.filter(o=>!t[o]);return r.length>0&&(c.error(`Unknown AI provider(s): ${r.join(", ")}. Valid providers: ${Object.keys(t).join(", ")}`),process.exit(l.INVALID_ARGS)),n}function Io(e){let t=e?.split(",").map(r=>r.trim()).filter(Boolean)??[];t.length===0&&(c.error("Route fallback cannot be empty. Use --fallback provider:model,provider:model"),process.exit(l.INVALID_ARGS));let n=t.filter(r=>!/^[a-z0-9-]+:[^,\s]+$/i.test(r));return n.length>0&&(c.error(`Invalid fallback target(s): ${n.join(", ")}. Expected provider:model.`),process.exit(l.INVALID_ARGS)),t}function fn(e){let t=se(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,i])=>i.enabled).map(([i])=>i);return{path:H(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function Y(e,t){let n=typeof e.opts=="function"?e.opts():e,r=typeof t?.optsWithGlobals=="function"?t.optsWithGlobals():typeof e.optsWithGlobals=="function"?e.optsWithGlobals():n,o=n.format??r.format??Po();return{...r,...n,...o?{format:o}:{}}}function Po(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function je(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function No(e){e.format!=="json"&&c.info("Checking configured AI models and providers...");let t={openai:{name:"OpenAI",keyVars:["OPENAI_API_KEY"],configured:!1},anthropic:{name:"Anthropic Claude",keyVars:["ANTHROPIC_API_KEY"],configured:!1},openrouter:{name:"OpenRouter",keyVars:["OPENROUTER_API_KEY"],configured:!1},vercel:{name:"Vercel AI SDK",keyVars:["VERCEL_AI_API_KEY"],configured:!1}};for(let r of Object.values(t))r.configured=r.keyVars.some(o=>process.env[o]);let n={providers:Object.entries(t).map(([r,o])=>({id:r,name:o.name,configured:o.configured,keys:o.keyVars.map(i=>({name:i,value:je(process.env[i])}))})),configuredCount:Object.values(t).filter(r=>r.configured).length,totalProviders:Object.keys(t).length};e.dryRun||(n.configuredCount===0?c.warn("No AI providers configured. Set API keys to enable AI features."):c.success(`${n.configuredCount} AI provider(s) configured`)),J(n,e.format,"ai:models")}async function $o(e){e.format!=="json"&&c.info("Scanning for available agents...");try{let t=Et(process.cwd(),"backends/gateway/src/routes/agents"),n=[];try{let o=await import("fs");o.existsSync(t)&&(n=o.readdirSync(t).filter(a=>a.endsWith(".ts")&&!a.endsWith(".d.ts")).map(a=>({name:a.replace(".ts",""),path:`backends/gateway/src/routes/agents/${a}`})))}catch{n=[]}let r={agents:n.length>0?n:[{name:"No agents found",path:"create agents in backends/gateway/src/routes/agents/"}],count:n.length};e.dryRun||(r.count===0?c.info("No agents configured. Create agents in backends/gateway/src/routes/agents/"):c.success(`Found ${r.count} agent(s)`)),J(r,e.format,"ai:agents")}catch(t){c.error(`Failed to scan agents: ${t instanceof Error?t.message:String(t)}`),process.exit(l.ERROR)}}async function jo(e,t){(!e||e.trim().length===0)&&(c.error("Prompt cannot be empty"),process.exit(l.INVALID_ARGS)),t.format!=="json"&&(c.info("Testing AI prompt against default model..."),c.info("Note: Ensure API gateway is running on http://localhost:3001"));let n={prompt:e,note:"To execute this test, the API gateway must be running locally. Run: pnpm --filter @nebutra/gateway dev",endpoint:"http://localhost:3001/api/ai/test",method:"POST",payload:{prompt:e.substring(0,100)}};t.dryRun||c.warn("AI test execution requires a running API gateway. Start it with: pnpm --filter @nebutra/gateway dev"),J(n,t.format,"ai:test")}async function Fo(e){e.format!=="json"&&c.info("Checking AI configuration...");let t={providers:{openai:{key:je(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:je(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:je(process.env.OPENROUTER_API_KEY),configured:!!process.env.OPENROUTER_API_KEY}},environment:{NODE_ENV:process.env.NODE_ENV||"development",NEBUTRA_LOG_LEVEL:process.env.NEBUTRA_LOG_LEVEL||"info"}};try{let r=Et(process.cwd(),"nebutra.config.ts"),o=await import("fs");if(o.existsSync(r)){let a=o.readFileSync(r,"utf-8").match(/preset:\s*["']([^"']+)["']/);a&&(t.preset=a[1])}}catch{}let n=Object.entries(t.providers).filter(([,r])=>r.configured).map(([r])=>r);e.dryRun||(n.length===0?c.warn("No AI providers configured. Set environment variables to enable AI features."):c.success(`Configuration loaded: ${n.join(", ")}`)),J(t,e.format,"ai:config")}async function Do(e){let t=fe(),n=se(t),r=Je(),o=Object.values(r).map(a=>{let s=n.providers?.[a.id];return{id:a.id,name:a.name,enabled:s?.enabled===!0,configured:a.envVars.some(u=>!!process.env[u]),envVars:a.envVars.map(u=>({name:u,value:je(process.env[u])}))}}),i={configPath:H(),providers:o,enabledCount:o.filter(a=>a.enabled).length,totalProviders:o.length};if(e.format!=="json"){let a=o.filter(s=>s.enabled);a.length===0?c.warn("No runtime AI providers enabled in nebutra.config.json."):c.success(`Enabled AI providers: ${a.map(s=>s.id).join(", ")}`)}J(i,e.format,"ai:provider:list")}async function To(e,t){let n=gn(e),r=fe(),o=se(r),i=Je(),a=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!0,envVars:i[u].envVars,enabledAt:o.providers?.[u]?.enabledAt??a};qe(r);let s={configPath:H(),enabled:n,env:t.env===!0?n.flatMap(u=>i[u].envVars.map(m=>({provider:u,name:m,example:`${m}=`}))):void 0,ai:fn(r)};if(t.format!=="json"&&(c.success(`Enabled AI provider(s): ${n.join(", ")}`),t.env)){c.info("Required environment variables:");for(let u of n)for(let m of i[u].envVars)console.log(`${m}=`)}J(s,t.format,"ai:provider:enable")}async function Lo(e,t){let n=gn(e),r=fe(),o=se(r),i=Je(),a=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!1,envVars:o.providers?.[u]?.envVars??i[u].envVars,disabledAt:a};qe(r);let s={configPath:H(),disabled:n,ai:fn(r)};t.format!=="json"&&c.success(`Disabled AI provider(s): ${n.join(", ")}`),J(s,t.format,"ai:provider:disable")}async function Uo(e){let t=fe(),n=se(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},qe(t);let o={configPath:H(),gateway:n.gateway};e.format!=="json"&&c.success("AI gateway governance initialized in nebutra.config.json"),J(o,e.format,"ai:gateway:init")}async function Bo(e){let t=fe(),n=se(t),r={configPath:H(),gateway:n.gateway??null,initialized:n.gateway?.enabled===!0};e.format!=="json"&&(r.initialized?c.success("AI gateway governance is initialized"):c.warn("AI gateway governance is not initialized. Run: nebutra ai gateway init")),J(r,e.format,"ai:gateway:status")}async function Mo(e,t){(!e||e.trim().length===0)&&(c.error("Route name cannot be empty"),process.exit(l.INVALID_ARGS)),t.policy||(c.error("Route policy is required. Use --policy <policy>."),process.exit(l.INVALID_ARGS));let n=Io(t.fallback),r=fe(),o=se(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},qe(r);let i={configPath:H(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&c.success(`AI route '${e}' set with policy '${t.policy}'`),J(i,t.format,"ai:route:set")}async function Go(e){let t=fe(),n=se(t),r=Object.entries(n.routes??{}).map(([i,a])=>({name:i,...a})),o={configPath:H(),routes:r,count:r.length};e.format!=="json"&&(r.length===0?c.warn("No AI routes configured. Run: nebutra ai route set chat --policy cost-latency-balanced --fallback openai:gpt-5.4"):c.success(`Configured AI routes: ${r.map(i=>i.name).join(", ")}`)),J(o,e.format,"ai:route:list")}function hn(e){let t=e.command("ai").description("Manage AI models, agents, and configuration"),n=t.command("provider").description("Manage runtime AI provider governance");n.command("list").description("List supported and enabled AI providers").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await Do({format:s.format,interactive:s.yes!==!0})}),n.command("enable <providers...>").description("Enable one or more runtime AI providers in nebutra.config.json").option("--env","Print required environment variable placeholders").option("--format <type>","Output format: json or plain").action(async(i,a,s)=>{let u=Y(a,s);await To(i,{env:u.env===!0,format:u.format,interactive:u.yes!==!0})}),n.command("disable <providers...>").description("Disable one or more runtime AI providers in nebutra.config.json").option("--format <type>","Output format: json or plain").action(async(i,a,s)=>{let u=Y(a,s);await Lo(i,{format:u.format,interactive:u.yes!==!0})});let r=t.command("gateway").description("Manage local AI gateway governance");r.command("init").description("Initialize the local AI gateway governance block").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await Uo({format:s.format,interactive:s.yes!==!0})}),r.command("status").description("Show local AI gateway governance status").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await Bo({format:s.format,interactive:s.yes!==!0})});let o=t.command("route").description("Manage AI routing policies");o.command("set <name>").description("Create or update an AI route policy").requiredOption("--policy <policy>","Routing policy id").requiredOption("--fallback <list>","Comma-separated provider:model fallback chain").option("--format <type>","Output format: json or plain").action(async(i,a,s)=>{let u=Y(a,s);await Mo(i,{policy:u.policy,fallback:u.fallback,format:u.format,interactive:u.yes!==!0})}),o.command("list").description("List configured AI routes").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await Go({format:s.format,interactive:s.yes!==!0})}),t.command("models").description("List configured AI models and providers").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await No({dryRun:s.dryRun===!0,format:s.format,interactive:s.yes!==!0})}),t.command("agents").description("List available agents in the project").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await $o({dryRun:s.dryRun===!0,format:s.format,interactive:s.yes!==!0})}),t.command("test <prompt>").description("Send a test prompt to the default AI model (requires running API gateway)").option("--dry-run","Preview without executing").option("--format <type>","Output format: json or plain").action(async(i,a,s)=>{let u=Y(a,s);await jo(i,{dryRun:u.dryRun===!0,format:u.format,interactive:u.yes!==!0})}),t.command("config").description("Show current AI configuration and provider status").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(i,a);await Fo({dryRun:s.dryRun===!0,format:s.format,interactive:s.yes!==!0})})}import{existsSync as _t,mkdirSync as Xo,readFileSync as ei,rmSync as ti,writeFileSync as ni}from"fs";import{dirname as ri,join as Fe}from"path";var yn=["factory","linear","gsap","notion","raycast","stripe","vanta","vercel","cosmos"],Vo=["base","cool","neutral","warm"],zo=["base","none","sm","md","lg","full"],Ko=["base","compact","comfortable","spacious"],Wo=["base","Geist","Inter","Inter Tight","DM Sans","Manrope","Plus Jakarta Sans","Figtree","Work Sans","Space Grotesk","Outfit","Sora","Lexend","Montserrat"],Yo=["base","sans","DM Sans","Inter Tight","Space Grotesk","Sora","Outfit","Manrope","Playfair Display","Fraunces","Source Serif 4"],Jo=["base","Geist Mono","JetBrains Mono","Fira Code","Roboto Mono","Source Code Pro"],qo=["base",400,500,600,700],Ho=["base","light","dark"];var Rt=1,bn="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",ce=class extends Error{constructor(e){super(e),this.name="PresetCodeError"}},Ee={version:{bits:3},base:{bits:5,list:yn},neutral:{bits:2,list:Vo},radius:{bits:3,list:zo},density:{bits:2,list:Ko},sans:{bits:4,list:Wo},heading:{bits:4,list:Yo},mono:{bits:3,list:Jo},headingWeight:{bits:3,list:qo},mode:{bits:2,list:Ho},hasColor:{bits:1},color:{bits:24}},Ot=Object.keys(Ee);for(let e of Ot){let t=Ee[e];if(t.list&&t.list.length>2**t.bits)throw new Error(`preset knob "${e}" outgrew its ${t.bits} bits`)}var Zo=/^#[0-9a-f]{6}$/i;function te(e,t){let n=Ee[e].list;if(!n)throw new Error(`"${e}" is not a list knob`);let r=n.indexOf(t??"base");if(r<0)throw new ce(`Unknown ${e}: ${String(t)}`);return r}function vn(e){let t={version:Rt,base:te("base",e.base),neutral:te("neutral",e.neutral),radius:te("radius",e.radius),density:te("density",e.density),sans:te("sans",e.sans),heading:te("heading",e.heading),mono:te("mono",e.mono),headingWeight:te("headingWeight",e.headingWeight),mode:te("mode",e.mode),hasColor:e.brandColor?1:0,color:0};if(e.brandColor){if(!Zo.test(e.brandColor))throw new ce(`Brand colour must be #rrggbb, got ${e.brandColor}`);t.color=Number.parseInt(e.brandColor.slice(1),16)}let n=0n,r=0n;for(let i of Ot)n|=BigInt(t[i])<<r,r+=BigInt(Ee[i].bits);let o="";for(;n>0n;)o=bn[Number(n%62n)]+o,n/=62n;return o}function Qo(e){if(!/^[0-9a-zA-Z]{1,12}$/.test(e))throw new ce(`"${e}" is not a preset code`);let t=0n;for(let a of e)t=t*62n+BigInt(bn.indexOf(a));let n={};for(let a of Ot){let s=BigInt(Ee[a].bits);n[a]=Number(t&(1n<<s)-1n),t>>=s}if(t!==0n)throw new ce(`"${e}" is longer than any preset`);if(n.version!==Rt)throw new ce(`"${e}" is preset format v${n.version}; this Sailor reads v${Rt}. Upgrade @nebutra/tokens.`);let r=a=>{let u=Ee[a].list[n[a]];if(u===void 0)throw new ce(`"${e}" names an unknown ${a}`);return u},o={base:r("base")},i=["neutral","radius","density","sans","heading","mono","headingWeight","mode"];for(let a of i){let s=r(a);s!=="base"&&(o[a]=s)}return n.hasColor&&(o.brandColor=`#${n.color.toString(16).padStart(6,"0")}`),o}function At(e){let t=e.trim();return yn.includes(t)?{base:t}:Qo(t)}var He=["packages","design","tokens"],kn={theme:["base","brandColor","neutral","radius","density","mode"],fonts:["sans","heading","mono","headingWeight"]};function oi(e=process.cwd()){let t=e;for(;;){if(_t(Fe(t,...He,"package.json")))return t;let n=ri(t);if(n===t)return null;t=n}}function ii(e,t,n){if(!n)return t;let r={...e??{base:"factory"}};for(let o of kn[n]){let i=t[o];i===void 0?delete r[o]:r[o]=i}return r}var ai=e=>e.base==="factory"&&Object.keys(e).length===1;function si(e,t){let n=Fe(e,...He,"project"),r=Fe(n,"preset");if(ai(t))return ti(r,{force:!0}),{root:e,code:null,preset:t};let o=vn(t);return Xo(n,{recursive:!0}),ni(r,`${o}
|
|
4
|
+
`),{root:e,code:o,preset:t}}function ci(e){let t=Fe(e,...He,"project","preset");return _t(t)?At(ei(t,"utf8")):null}function wn(e){e.command("apply").description("Put a Sailor Studio preset on this project (its look, in one code)").requiredOption("--preset <code>","Preset code from Sailor Studio, or a design language id").option("--only <group>","Change only one group of knobs: theme | fonts").option("--no-build","Write the preset without rebuilding the tokens").option("--format <type>","Output format: json or table").action(async t=>{let n=t.only;n&&!(n in kn)&&(c.error(`--only takes "theme" or "fonts", not "${t.only}".`),process.exit(l.INVALID_ARGS));let r;try{r=At(t.preset??"")}catch(a){c.error(a instanceof ce?a.message:String(a)),process.exit(l.INVALID_ARGS)}let o=oi();o||(c.error("Run this inside a Sailor project (no packages/design/tokens found above here)."),process.exit(l.NOT_FOUND)),_t(Fe(o,...He,"project","brand.json"))&&(c.error("packages/design/tokens/project/brand.json is hand-authored and takes precedence over any preset. Remove it to use presets."),process.exit(l.CONFLICT));let i=si(o,ii(ci(o),r,n));if(t.build!==!1){let a=await E({command:"pnpm",args:["--filter","@nebutra/tokens","build"],cwd:o,label:"Rebuilding the tokens"});a.exitCode!==0&&(c.error(a.stderr||"The tokens build failed."),process.exit(l.ERROR))}if(t.format==="json"){console.log(JSON.stringify({code:i.code,preset:i.preset},null,2));return}c.success(i.code?`Applied preset ${i.code} (base: ${i.preset.base}).`:"Back to factory: the House tokens, unchanged.")})}function De(e,t,n){if(t==="json"){let r={command:n||"brand",exitCode:e.exitCode,success:e.exitCode===0,...e.stdout&&{stdout:e.stdout},...e.stderr&&{stderr:e.stderr}};console.log(JSON.stringify(r,null,2))}else e.stdout&&console.log(e.stdout),e.stderr&&e.exitCode!==0&&console.error(e.stderr)}function xn(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function li(e){c.info("Initializing brand system...");let t=await j("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});De(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||c.success("Brand system initialized successfully")}async function ui(e){c.info("Applying brand configuration...");let t=await j("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});De(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||c.success("Brand applied successfully")}async function di(e){let t=[];e.primary&&(xn(e.primary)||(c.error(`Invalid primary color format: ${e.primary}. Expected hex format like #0033FE`),process.exit(l.INVALID_ARGS)),t.push(`--primary=${e.primary}`)),e.secondary&&(xn(e.secondary)||(c.error(`Invalid secondary color format: ${e.secondary}. Expected hex format like #0BF1C3`),process.exit(l.INVALID_ARGS)),t.push(`--secondary=${e.secondary}`)),t.length===0&&(c.warn("No colors specified. Usage: nebutra brand palette --primary=#HEX --secondary=#HEX"),c.info("Example: nebutra brand palette --primary=#0033FE --secondary=#0BF1C3"),process.exit(l.INVALID_ARGS)),c.info(`Generating color palette: ${t.join(" ")}`);let n=await E({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});De(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||c.success("Color palette generated successfully")}async function mi(e){c.info("Syncing brand tokens across packages...");let t=await j("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});De(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||c.success("Brand tokens synced successfully")}async function pi(e){c.info("Verifying brand token consistency...");let t=await j("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});De(t,e.format,"brand:verify-tokens"),t.exitCode!==0&&(c.error("Brand token verification failed. There are inconsistencies in your design tokens."),process.exit(t.exitCode)),e.dryRun||c.success("All brand tokens are consistent")}function Cn(e){let t=e.command("brand").description("Manage Nebutra brand system and design tokens");t.command("init").description("Initialize brand system configuration").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await li({dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})}),t.command("apply").description("Apply brand configuration to the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await ui({dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})}),t.command("palette").description("Generate brand color palette from custom colors").option("--primary <hex>","Primary brand color (hex format, e.g. #0033FE)").option("--secondary <hex>","Secondary brand color (hex format, e.g. #0BF1C3)").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await di({primary:n.primary,secondary:n.secondary,dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})}),t.command("sync").description("Synchronize brand tokens across all packages").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await mi({dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})}),t.command("verify").description("Verify brand token consistency across the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await pi({dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})})}import{appendFileSync as gi,existsSync as fi,readFileSync as hi,writeFileSync as yi}from"fs";import{homedir as Te}from"os";import{join as Re}from"path";import*as T from"@clack/prompts";import D from"picocolors";var Z={name:"nebutra",description:"Nebutra \u2014 the CLI for Sailor projects: status, dev, db, and codegen",usage:"nebutra [command] [options]",options:[{flags:"--format <type>",description:"Output format: json, table, plain"},{flags:"--yes, --no-interactive",description:"Skip all interactive prompts (Agent mode)"},{flags:"--no-color",description:"Disable colored output"},{flags:"--verbose",description:"Enable verbose output"},{flags:"--quiet",description:"Suppress non-essential output"}],subcommands:[{name:"init",description:"Initialize a Nebutra project and create nebutra.config.json",usage:"nebutra init [options]",options:[{flags:"--dry-run",description:"Preview changes without writing files (exits with code 10)"},{flags:"--yes",description:"Skip all interactive prompts (Agent mode)"},{flags:"--if-not-exists",description:"Skip initialization if nebutra.config.json already exists"}],arguments:[],examples:[{command:"nebutra init",description:"Initialize Nebutra configuration in the current directory"},{command:"nebutra init --dry-run",description:"Preview initialization changes without writing files"},{command:"nebutra init --yes --if-not-exists",description:"Initialize without prompts, skip if already configured"}]},{name:"mcp",description:"Start the Nebutra MCP server for AI agents and editors",usage:"nebutra mcp [options]",arguments:[],options:[{flags:"--stdio",description:"Use stdio transport for communication (default: enabled)",default:!0},{flags:"--verbose",description:"Enable verbose logging for MCP server"}],examples:[{command:"nebutra mcp",description:"Start the MCP server for AI-powered project context integration"},{command:"nebutra mcp --verbose",description:"Start the MCP server with detailed logging output"}]},{name:"schema",description:"Show command schema and argument documentation (Agent-friendly JSON output)",usage:"nebutra schema [command] [options]",arguments:[{name:"command",description:"Command name to show schema for (e.g., init, dev, db)",required:!1}],options:[{flags:"--all",description:"Show full schema for all commands as JSON",default:!1},{flags:"--list",description:"List all available command names",default:!1},{flags:"--exit-codes",description:"Show exit codes reference",default:!1}],examples:[{command:"nebutra schema --all",description:"Show complete JSON of all commands, args, options, value domains"},{command:"nebutra schema init",description:"Show schema for init command (arguments, options, defaults, examples)"},{command:"nebutra schema --list",description:"List just the command names (quick discovery)"},{command:"nebutra schema --exit-codes",description:"Show exit codes reference for all possible exit codes"}]},{name:"brand",description:"Manage governed brand tokens, palettes, and visual system outputs",usage:"nebutra brand [subcommand]",examples:[{command:"nebutra brand palette --primary=#0047FF",description:"Generate a token-aligned blue palette"}]},{name:"i18n",description:"Manage localization files and multilingual product copy",usage:"nebutra i18n [subcommand]"},{name:"infra",description:"Manage local infrastructure services for Nebutra development",usage:"nebutra infra [subcommand]",examples:[{command:"nebutra infra up --lite",description:"Start lightweight local infrastructure"}]},{name:"env",description:"Validate and manage environment variables across apps and packages",usage:"nebutra env [subcommand]"},{name:"license",description:"Record a Nebutra support/billing license key locally (Sailor scaffolds are MIT \u2014 nothing in the CLI is gated by this)",usage:"nebutra license [subcommand]",arguments:[],options:[],subcommands:[{name:"activate",description:"Validate and record a license key locally (support/billing record, not a feature unlock)",usage:"nebutra license activate <key>",arguments:[{name:"key",description:"Your Nebutra support/billing license key",required:!0}],options:[{flags:"--quiet",description:"Suppress output"}],examples:[{command:"nebutra license activate liz_1234567890",description:"Record your license key locally"}]},{name:"status",description:"Check the locally configured license status",usage:"nebutra license status",arguments:[],options:[{flags:"--quiet",description:"Suppress output"}],examples:[{command:"nebutra license status",description:"Check if you have an active license"}]}]},{name:"ai",description:"Configure AI providers, gateway routing, and agent-ready defaults",usage:"nebutra ai [subcommand]"},{name:"db",description:"Manage database schema, migrations, seeds, and generated clients",usage:"nebutra db [subcommand]"},{name:"generate",description:"Generate apps, modules, API surfaces, and typed project artifacts",usage:"nebutra generate [type] [name]"},{name:"dev",description:"Start development workflows for selected Nebutra apps or presets",usage:"nebutra dev [options]"},{name:"build",description:"Run build workflows through the Nebutra CLI",usage:"nebutra build [options]"},{name:"lint",description:"Run lint workflows through the Nebutra CLI",usage:"nebutra lint [options]"},{name:"typecheck",description:"Run TypeScript checks through the Nebutra CLI",usage:"nebutra typecheck [options]"},{name:"test",description:"Run unit, architecture, and E2E verification workflows",usage:"nebutra test [scope]"},{name:"e2e",description:"Run browser end-to-end verification suites",usage:"nebutra e2e [suite]"},{name:"theme",description:"Inspect registry-backed Nebutra themes and governance metadata",usage:"nebutra theme [subcommand]"},{name:"apply",description:"Put a Sailor Studio preset on this project (its look, in one code)",usage:"nebutra apply --preset <code> [--only theme|fonts]"},{name:"ui",description:"Search, inspect, validate, and plan migrations for @nebutra/ui components",usage:"nebutra ui [subcommand]"},{name:"services",description:"Inspect and manage microservice health, logs, scaling, and rollouts",usage:"nebutra services [subcommand]"},{name:"secrets",description:"Manage encrypted tenant and platform secrets",usage:"nebutra secrets [subcommand]"},{name:"completions",description:"Generate shell completions for the current Nebutra command surface",usage:"nebutra completions [shell]",arguments:[{name:"shell",description:"Shell to generate completions for: bash, zsh, fish, or install",required:!1}]},{name:"login",description:"Authorize this machine with your Nebutra account (device flow)",usage:"nebutra login [options]",options:[{flags:"--json",description:"Print verification details as JSON and exit immediately (agent mode)"},{flags:"--no-browser",description:"Don't try to open a browser"},{flags:"--poll",description:"Poll until approved/denied/expired, resuming a pending `login --json` if present"},{flags:"--format <type>",description:"Output format: json or plain"}],examples:[{command:"nebutra login",description:"Human flow: open browser, wait for approval"},{command:"nebutra login --json",description:"Agent flow: print verification link/code and exit immediately"},{command:"nebutra login --poll --json",description:"Resume and wait for a pending login"}]},{name:"logout",description:"Clear local Nebutra CLI session state",usage:"nebutra logout"},{name:"whoami",description:"Show the Nebutra identity this machine is authorized as",usage:"nebutra whoami [options]",options:[{flags:"--json",description:"Output as JSON"},{flags:"--format <type>",description:"Output format: json or plain"}]},{name:"upgrade",description:"Upgrade local Nebutra CLI tooling",usage:"nebutra upgrade"},{name:"link",description:"Link a local project to Nebutra platform metadata",usage:"nebutra link"},{name:"unlink",description:"Unlink local Nebutra project metadata",usage:"nebutra unlink"},{name:"status",description:"Show capability readiness \u2014 live, local-fallback, or missing-key, per environment",usage:"nebutra status [options]",arguments:[],options:[{flags:"--json",description:"Emit machine-readable JSON"}],examples:[{command:"nebutra status",description:"Show a readiness table for every capability in nebutra.config.json"},{command:"nebutra status --json",description:"Emit { stack, locale, capabilities } as JSON for agents"}]},{name:"sync",description:"Make .env.example / .env.local agree with the declared capabilities (idempotent)",usage:"nebutra sync [options]",arguments:[],options:[{flags:"--dry-run",description:"Preview planned additions without writing files (exits with code 10)"},{flags:"--json",description:"Emit machine-readable JSON"}],examples:[{command:"nebutra sync",description:"Add any env keys required by declared capabilities to .env.example, create .env.local if missing"},{command:"nebutra sync --dry-run",description:"Preview planned additions without writing files"},{command:"nebutra sync --json",description:"Emit { added, unchanged, warnings } as JSON for agents"}]},{name:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var Ze=(Z.subcommands??[]).map(e=>e.name),Sn={init:"Initialize a Nebutra project and create nebutra.config.json",mcp:"Start the Nebutra MCP server for AI agents and editors",completions:"Generate shell completions",doctor:"Check your Nebutra project setup",schema:"Show command schema and argument documentation",brand:"Manage governed brand tokens and palettes",i18n:"Manage localization files and multilingual product copy",infra:"Manage local infrastructure services",env:"Validate and manage environment variables",license:"Manage Nebutra Sailor commercial license activation and status",db:"Database migration and management",generate:"Scaffold apps, modules, and code",dev:"Start development server",build:"Run build workflows",lint:"Run lint workflows",typecheck:"Run TypeScript checks",test:"Run unit and E2E tests",e2e:"Run browser E2E suites",theme:"Theme registry and governance metadata",apply:"Put a Sailor Studio preset on this project",ai:"AI provider and gateway routing configuration",services:"Microservice management",secrets:"Encrypted secrets management",login:"Authorize this machine with your Nebutra account (device flow)",logout:"Clear local session state",whoami:"Show the authorized Nebutra identity",upgrade:"Upgrade local CLI tooling",link:"Link local project metadata",unlink:"Unlink local project metadata",status:"Show capability readiness (live/local-fallback/missing-key)",sync:"Sync .env.example/.env.local with declared capabilities"},bi=["--help","--version","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--json","--no-browser","--poll"],vi=Ze.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${Sn[e]}"`).join(`
|
|
5
|
+
`);function En(){return`#!/usr/bin/env bash
|
|
5
6
|
|
|
6
7
|
_nebutra_completions() {
|
|
7
8
|
local cur prev opts cmd
|
|
@@ -10,10 +11,10 @@ _nebutra_completions() {
|
|
|
10
11
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
11
12
|
|
|
12
13
|
# Subcommands
|
|
13
|
-
local subcommands="${
|
|
14
|
+
local subcommands="${Ze.join(" ")}"
|
|
14
15
|
|
|
15
16
|
# Flags
|
|
16
|
-
local flags="${
|
|
17
|
+
local flags="${bi.join(" ")}"
|
|
17
18
|
|
|
18
19
|
if [[ \${cur} == -* ]]; then
|
|
19
20
|
# Complete flags
|
|
@@ -30,11 +31,11 @@ _nebutra_completions() {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
complete -o bashdefault -o default -o nospace -F _nebutra_completions nebutra
|
|
33
|
-
`}function
|
|
34
|
+
`}function Rn(){return`#compdef nebutra
|
|
34
35
|
|
|
35
36
|
_nebutra() {
|
|
36
37
|
local -a commands=(
|
|
37
|
-
${
|
|
38
|
+
${Ze.map(e=>`"${e}:${Sn[e]}"`).join(`
|
|
38
39
|
`)}
|
|
39
40
|
)
|
|
40
41
|
|
|
@@ -90,12 +91,12 @@ _nebutra() {
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
_nebutra
|
|
93
|
-
`}function
|
|
94
|
+
`}function On(){return`# Fish shell completions for nebutra
|
|
94
95
|
|
|
95
|
-
complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${
|
|
96
|
+
complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${Ze.join(" ")}" -d "Nebutra governance CLI"
|
|
96
97
|
|
|
97
98
|
# Subcommands
|
|
98
|
-
${
|
|
99
|
+
${vi}
|
|
99
100
|
|
|
100
101
|
# Flags
|
|
101
102
|
complete -c nebutra -f -a "--help" -d "Show help message"
|
|
@@ -121,24 +122,24 @@ complete -c nebutra -n "__fish_seen_subcommand_from completions" -f -a "install"
|
|
|
121
122
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--all" -d "Show full schema for all commands"
|
|
122
123
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--list" -d "List all available command names"
|
|
123
124
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--exit-codes" -d "Show exit codes reference"
|
|
124
|
-
`}function
|
|
125
|
+
`}function An(e){let n={bash:En,zsh:Rn,fish:On}[e.toLowerCase()];n||(console.error(D.red(`Error: Unknown shell '${e}'. Supported: bash, zsh, fish`)),process.exit(l.INVALID_ARGS)),console.log(n())}async function ki(){let t=(process.env.SHELL||"/bin/bash").split("/").pop()||"bash";T.intro(D.bgCyan(D.black(" nebutra completions install ")));let n=T.spinner();n.start(D.cyan(`Detecting shell: ${t}...`));try{let r=null,o=null,i=null;if(t==="bash"?(r=Re(Te(),".bashrc"),o=Re(Te(),".bash_completion.d"),i="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=Re(Te(),".zshrc"),o=Re(Te(),".zsh/completions"),i="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=Re(Te(),".config/fish/completions"),i="# Completions installed to ~/.config/fish/completions/nebutra.fish"):(n.stop(),T.log.warn(D.yellow(`Warning: Unsupported shell '${t}'. Please install completions manually.`)),An("bash"),T.outro(D.cyan("Run 'nebutra completions bash' (or zsh/fish) to generate completions for your shell.")),process.exit(l.SUCCESS)),o){(await import("fs")).mkdirSync(o,{recursive:!0});let s=Re(o,t==="fish"?"nebutra.fish":"nebutra"),u=t==="bash"?En():t==="zsh"?Rn():On();yi(s,u),n.stop(D.green(`Completion script installed to ${s}`))}r&&i&&t!=="fish"&&(!fi(r)||!hi(r,"utf8").includes("nebutra"))&&(gi(r,(t==="bash"?`
|
|
125
126
|
# nebutra completions
|
|
126
127
|
[[ -f ~/.bash_completion.d/nebutra ]] && source ~/.bash_completion.d/nebutra`:`
|
|
127
128
|
# nebutra completions
|
|
128
129
|
fpath=(~/.zsh/completions $fpath)
|
|
129
130
|
autoload -Uz compinit && compinit`)+`
|
|
130
|
-
`),
|
|
131
|
-
`)}function
|
|
132
|
-
`)}function I(e,t={}){let n=
|
|
133
|
-
`)}function
|
|
134
|
-
`)}function
|
|
135
|
-
`),t&&Object.keys(t).length>0&&
|
|
136
|
-
`)}function
|
|
137
|
-
`),
|
|
138
|
-
`),
|
|
139
|
-
`),
|
|
140
|
-
`)}async function
|
|
141
|
-
`)}catch{process.stdout.write(t.stdout)}
|
|
131
|
+
`),T.log.info(D.green(`Added nebutra completions to ${r}`))),T.log.info(D.cyan("Completions installed! Restart your shell or run:")),T.log.info(D.dim(` source "${t==="bash"?"~/.bashrc":"~/.zshrc"}"`)),T.outro(D.green("Installation complete!"))}catch(r){n.stop(),T.log.error(D.red("Error installing completions. You can manually add them by running:")),T.log.info(D.cyan(` nebutra completions ${t} >> ~/.${t}rc`)),r instanceof Error&&console.error(D.dim(r.message)),process.exit(l.ERROR)}}function _n(e){e.command("completions [shell]").description("Generate or install shell completions").action(async t=>{!t||t==="install"?await ki():An(t)})}import{existsSync as Si,readFileSync as Ei}from"fs";import{resolve as Ri}from"path";import*as Xe from"@clack/prompts";import{stderr as le,stdout as In}from"process";import Q from"picocolors";function wi(){return process.env.NEBUTRA_NON_TTY||process.env.CI||process.env.GITHUB_ACTIONS?!1:process.stderr.isTTY===!0}function Pn(e){if(e)return e;let t=process.env.NEBUTRA_OUTPUT_FORMAT;return t&&["json","table","plain"].includes(t)?t:wi()?"plain":"json"}function xi(e,t){if(e.length===0)return"";let n=t||Object.keys(e[0]),r={};for(let s of n){r[String(s)]=String(s).length;for(let u of e){let m=String(u[s]??"");r[String(s)]=Math.max(r[String(s)],m.length)}}let o=n.map(s=>String(s).padEnd(r[String(s)])).join(" | "),i=n.map(s=>"-".repeat(r[String(s)])).join("-+-"),a=[o,i];for(let s of e){let u=n.map(m=>String(s[m]??"").padEnd(r[String(m)])).join(" | ");a.push(u)}return a.join(`
|
|
132
|
+
`)}function Ci(e){return JSON.stringify(e)}function Nn(e){if(!Array.isArray(e))return It(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return It(e);let t=xi(e);return Q.gray(t)}function It(e){return typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):e==null?"":Array.isArray(e)?e.length===0?"(empty list)":e.every(t=>typeof t=="string"||typeof t=="number")?e.join(", "):JSON.stringify(e,null,2):typeof e=="object"?JSON.stringify(e,null,2):String(e)}function b(e,t){let n=Pn(t?.format),r=t?.stream==="stderr"?le:In,o;switch(n){case"json":o=Ci(e);break;case"table":o=Nn(e);break;default:o=It(e);break}r.write(o+`
|
|
133
|
+
`)}function I(e,t={}){let n=Pn(t.format),r;switch(n){case"json":r=JSON.stringify(e);break;case"table":r=Nn(e);break;default:r=JSON.stringify(e,null,2);break}In.write(r+`
|
|
134
|
+
`)}function d(e,t="info"){let n;switch(t){case"error":n=Q.red("\u2716");break;case"warn":n=Q.yellow("\u26A0");break;case"success":n=Q.green("\u2713");break;default:n=Q.blue("\u2139");break}let r=`${n} ${e}`;le.write(r+`
|
|
135
|
+
`)}function x(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=Q.dim(`[debug] ${e}`);le.write(r+`
|
|
136
|
+
`),t&&Object.keys(t).length>0&&le.write(Q.dim(JSON.stringify(t,null,2))+`
|
|
137
|
+
`)}function Qe(e){le.write(`
|
|
138
|
+
`),le.write(Q.bold(Q.cyan(e))+`
|
|
139
|
+
`),le.write(Q.gray("-".repeat(e.length))+`
|
|
140
|
+
`),le.write(`
|
|
141
|
+
`)}var G=2e4;function Oi(e){if(process.env.DATABASE_URL)return!0;for(let t of[".env.local",".env"]){let n=Ri(e,t);if(Si(n))try{let r=Ei(n,"utf-8");if(/^DATABASE_URL\s*=\s*\S+/m.test(r))return!0}catch{}}return!1}function Oe(){let e=y();Oi(e)||ie("DATABASE_URL is not set (checked the environment, .env.local, and .env).","Set DATABASE_URL, or run `pnpm infra:up` for a local Postgres and add it to .env.local.")}async function Ai(e){d("Generating Prisma client"+"...","info");let n=await ee("generate",{dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?d("Prisma client generated successfully","success"):(d("Failed to generate Prisma client","error"),process.exit(n.exitCode||1))}async function Pt(e,t){let n=t||{};if(n.dryRun||Oe(),e){d(`Creating migration: ${e}`,"info");let r=await ee("migrate",{args:["dev","--name",e],dryRun:n.dryRun,interactive:!n.dryRun,timeoutMs:n.dryRun?void 0:G});r.timedOut&&ie(`Creating migration '${e}' timed out after ${G}ms.`,"Check that DATABASE_URL points to a reachable database."),r.exitCode===0?d(`Migration '${e}' created successfully`,"success"):(d(`Failed to create migration '${e}'`,"error"),process.exit(r.exitCode||1))}else{d("Running pending migrations...","info");let r=await ee("migrate",{args:["deploy"],dryRun:n.dryRun,interactive:!n.dryRun,timeoutMs:n.dryRun?void 0:G});r.timedOut&&ie(`Migration deploy timed out after ${G}ms.`,"Check that DATABASE_URL points to a reachable database."),r.exitCode===0?d("All pending migrations completed","success"):(d("Migration deployment failed","error"),process.exit(r.exitCode||1))}}async function _i(e){e.dryRun||Oe(),d("Pushing schema to database...","info");let t=await ee("db",{args:["push"],dryRun:e.dryRun,interactive:!e.dryRun,timeoutMs:e.dryRun?void 0:G});t.timedOut&&ie(`Schema push timed out after ${G}ms.`,"Check that DATABASE_URL points to a reachable database."),t.exitCode===0?d("Schema pushed successfully","success"):(d("Failed to push schema","error"),process.exit(t.exitCode||1))}async function Ii(e){e.dryRun||Oe(),d("Seeding database...","info");let t=await ee("db",{args:["seed"],dryRun:e.dryRun,interactive:!e.dryRun,timeoutMs:e.dryRun?void 0:G});t.timedOut&&ie(`Seeding timed out after ${G}ms.`,"Check that DATABASE_URL points to a reachable database."),t.exitCode===0?d("Database seeded successfully","success"):(d("Failed to seed database","error"),process.exit(t.exitCode||1))}async function Pi(e){e.dryRun||Oe(),d("Launching Prisma Studio...","info");let t=await ee("studio",{dryRun:e.dryRun,interactive:!0});t.exitCode!==0&&(d("Failed to launch Prisma Studio","error"),process.exit(t.exitCode||1))}async function Ni(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await Xe.confirm({message:"Reset database? This will delete all data.",initialValue:!1});(Xe.isCancel(r)||!r)&&(d("Reset cancelled","warn"),process.exit(l.CANCELLED))}else d("Database reset requires explicit --yes confirmation (use: nebutra db reset --yes)","error"),process.exit(l.INVALID_ARGS);e.dryRun||Oe(),d("Resetting database...","warn");let n=await ee("migrate",{args:["reset",...e.yes?["--force"]:[]],dryRun:e.dryRun,interactive:!e.dryRun,timeoutMs:e.dryRun?void 0:G});n.timedOut&&ie(`Database reset timed out after ${G}ms.`,"Check that DATABASE_URL points to a reachable database."),n.exitCode===0?d("Database reset successfully","success"):(d("Failed to reset database","error"),process.exit(n.exitCode||1))}async function $i(e){e.dryRun||Oe(),d("Checking migration status...","info");let t=await ee("migrate",{args:["status"],dryRun:e.dryRun,interactive:!1,timeoutMs:e.dryRun?void 0:G});if(t.timedOut&&ie(`\`db status\` timed out after ${G}ms waiting on the database.`,"Check that DATABASE_URL points to a reachable database."),t.exitCode===0)if(e.format==="json")try{let n=JSON.parse(t.stdout);process.stdout.write(JSON.stringify(n,null,2)+`
|
|
142
|
+
`)}catch{process.stdout.write(t.stdout)}else e.dryRun||(t.stdout.trim()&&process.stdout.write(t.stdout),t.stderr.trim()&&process.stderr.write(t.stderr));else d("Failed to check migration status","error"),t.stderr.trim()&&x("Prisma stderr",{stderr:t.stderr}),process.exit(t.exitCode||1)}function $n(e){e.command("db <verb> [args...]").description("Manage database schema, migrations, and state").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations (especially for reset)").option("--format <type>","Output format: json, plain","plain").action(async(n,r,o,i)=>{let a=i.optsWithGlobals?.(),s={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:a?.format||o.format};try{switch(n){case"generate":await Ai(s);break;case"migrate":r.length>0?r[0]==="create"&&r[1]?await Pt(r[1],s):await Pt(r[0],s):await Pt(void 0,s);break;case"push":await _i(s);break;case"seed":await Ii(s);break;case"studio":await Pi(s);break;case"reset":await Ni(s);break;case"status":await $i(s);break;default:d(`Unknown db subcommand: ${n}. Valid commands: generate, migrate, migrate create, push, seed, studio, reset, status`,"error"),process.exit(l.INVALID_ARGS)}}catch(u){let m=u instanceof Error?u.message:String(u);d(`Database command failed: ${m}`,"error"),x("Full error",{error:u}),process.exit(l.ERROR)}}).addHelpText("after",`
|
|
142
143
|
Examples:
|
|
143
144
|
nebutra db generate Generate Prisma client
|
|
144
145
|
nebutra db migrate Run all pending migrations
|
|
@@ -153,15 +154,15 @@ Flags:
|
|
|
153
154
|
--dry-run Show what would be run without executing
|
|
154
155
|
--yes Skip confirmations
|
|
155
156
|
--format <type> Output format: json, plain (default: plain)
|
|
156
|
-
`)}import*as
|
|
157
|
-
${n}`)}return t}async function
|
|
157
|
+
`)}import*as S from"@clack/prompts";import v from"picocolors";function A(e,t){let n=t&&typeof t.optsWithGlobals=="function"?t.optsWithGlobals():void 0,r=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():void 0,o=n??r??{},i={};for(let[a,s]of Object.entries(e))a==="optsWithGlobals"||s===void 0||t?.getOptionValueSource?.(a)==="default"||(i[a]=s);return{...o,...i}}function ue(e){if(e==="json"||e==="plain"||e==="table")return e}var Ae=["landing","web","storybook","design-docs","idp","mail-preview","gateway","admin","auth","design","forge","router","pebble","typelens","sailor-docs","studio","sleptons"];function et(e){let t=`@nebutra/${e}`;if(!Ae.includes(e)){let n=v.yellow(`Valid apps: ${Ae.join(", ")}`);throw new Error(`Invalid app: ${v.red(e)}
|
|
158
|
+
${n}`)}return t}async function ji(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"dev",options:{app:e.app},task:e.app?"turbo dev":"turbo dev (all apps)"},{format:ue(e.format)}),process.exit(l.DRY_RUN_OK));try{if(e.app){et(e.app);let n=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Starting dev server for ${v.bold(n)}...`));let r=await ae("dev",{filter:n});process.exit(r.exitCode)}e.quiet||S.log.info(v.cyan("Starting dev servers for all apps..."));let t=await ae("dev");process.exit(t.exitCode)}catch(t){t instanceof Error?S.log.error(v.red(t.message)):S.log.error(v.red("Unknown error occurred")),process.exit(l.ERROR)}}async function Fi(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"build",options:{app:e.app,strict:e.strict},task:e.strict?"pnpm build:strict":"pnpm build"},{format:ue(e.format)}),process.exit(l.DRY_RUN_OK));try{if(e.app&&e.strict&&(S.log.error(v.red("Cannot use --strict with --app filter")),process.exit(l.INVALID_ARGS)),e.app){et(e.app);let r=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Building ${v.bold(r)}...`));let o=await ae("build",{filter:r});process.exit(o.exitCode)}let t=e.strict?"build:strict":"build";if(!e.quiet){let r=e.strict?"Running strict build (with UI governance verification)...":"Building all apps...";S.log.info(v.cyan(r))}let n=await j(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?S.log.error(v.red(t.message)):S.log.error(v.red("Unknown error occurred")),process.exit(l.ERROR)}}async function Di(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"lint",options:{app:e.app,fix:e.fix},task:e.fix?"pnpm lint:fix":"pnpm lint"},{format:ue(e.format)}),process.exit(l.DRY_RUN_OK));try{if(e.app&&e.fix&&(S.log.error(v.red("Cannot use --fix with --app filter (lint:fix is global only)")),process.exit(l.INVALID_ARGS)),e.app){et(e.app);let r=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Linting ${v.bold(r)}...`));let o=await E({command:"turbo",args:["run","lint","--filter",r],interactive:!0,label:`turbo lint --filter ${r}`,dryRun:e.dryRun});process.exit(o.exitCode)}let t=e.fix?"lint:fix":"lint";if(!e.quiet){let r=e.fix?"Fixing linting issues...":"Linting codebase...";S.log.info(v.cyan(r))}let n=await j(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?S.log.error(v.red(t.message)):S.log.error(v.red("Unknown error occurred")),process.exit(l.ERROR)}}async function Ti(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"typecheck",options:{app:e.app},task:"turbo typecheck"},{format:ue(e.format)}),process.exit(l.DRY_RUN_OK));try{if(e.app){et(e.app);let n=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Type-checking ${v.bold(n)}...`));let r=await ae("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||S.log.info(v.cyan("Type-checking all packages..."));let t=await ae("typecheck");process.exit(t.exitCode)}catch(t){t instanceof Error?S.log.error(v.red(t.message)):S.log.error(v.red("Unknown error occurred")),process.exit(l.ERROR)}}var jn=e=>{e.command("dev").description("Start development servers (turbo dev)").option("--app <name>",`App to run: ${Ae.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await ji({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ue(r.format)})}),e.command("build").description("Build all apps (pnpm build or turbo build)").option("--app <name>",`App to build: ${Ae.join(", ")}`).option("--strict","Run strict build with UI governance verification (pnpm build:strict)").option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await Fi({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,strict:!!t.strict,quiet:!!r.quiet,verbose:!!r.verbose,format:ue(r.format)})}),e.command("lint").description("Lint with Biome (pnpm lint or pnpm lint:fix)").option("--app <name>",`App to lint: ${Ae.join(", ")}`).option("--fix","Fix linting issues automatically").option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await Di({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,fix:!!t.fix,quiet:!!r.quiet,verbose:!!r.verbose,format:ue(r.format)})}),e.command("typecheck").description("Type-check with TypeScript (turbo typecheck)").option("--app <name>",`App to typecheck: ${Ae.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await Ti({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ue(r.format)})})};import Fn from"fs";import Dn from"path";import Nt from"picocolors";var $t=["smoke","golden","sleptons"],Li={smoke:{config:"e2e/playwright.config.ts",suiteDir:"e2e/smoke"},golden:{config:"e2e/playwright.golden.config.ts",suiteDir:"e2e/golden"},sleptons:{config:"e2e/playwright.sleptons.config.ts",suiteDir:"e2e/sleptons"}};async function Ui(e,t={}){$t.includes(e)||(c.error(`Invalid suite: ${Nt.red(e)}. Valid: ${$t.join(", ")}`),process.exit(l.INVALID_ARGS));let n=y(),{config:r,suiteDir:o}=Li[e],i=Dn.join(n,r),a=Dn.join(n,o);(!Fn.existsSync(a)||!Fn.existsSync(i))&&(c.error(`Suite ${Nt.red(e)} not found at ${o}.
|
|
158
159
|
Expected config: ${r}
|
|
159
160
|
Remediation: scaffold the suite (analogous to 'nebutra workflow init <provider>')
|
|
160
|
-
or restore the directory from git.`),process.exit(
|
|
161
|
-
`)){if(o.trim().startsWith("#")||!o.trim())continue;let i=o.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(i){let[,a,s]=i;r[a]=s.replace(/^["'](.*)["']$/,"$1")}}return r}function
|
|
162
|
-
`)){if(a.trim().startsWith("#")||!a.trim())continue;let s=a.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(s){let[,
|
|
163
|
-
`);e.dryRun?(
|
|
164
|
-
`),
|
|
161
|
+
or restore the directory from git.`),process.exit(l.NOT_FOUND)),t.dryRun&&(I({mode:"dry-run",command:`e2e ${e}`,task:`pnpm exec playwright test --config ${r}`}),process.exit(l.DRY_RUN_OK)),t.quiet||c.info(`Running Playwright suite: ${Nt.bold(e)}`);let s=await E({command:"pnpm",args:["exec","playwright","test","--config",r],interactive:!0,label:`playwright ${e}`});process.exit(s.exitCode)}var Tn=e=>{e.command("e2e <suite>").description(`Run a Playwright suite (${$t.join(" | ")})`).option("--dry-run","Preview the command that would run (exit code 10)").action(async(t,n,r)=>{let o=A(n,r);await Ui(t,{dryRun:!!n.dryRun,quiet:!!o.quiet})})};import{existsSync as tt,readFileSync as Ln,writeFileSync as Bi}from"fs";import{resolve as nt}from"path";import*as he from"@clack/prompts";import Mi from"picocolors";function rt(e){let t=nt(e,".env.example");if(!tt(t))throw new Error(`.env.example not found at ${t}`);let n=Ln(t,"utf-8"),r={};for(let o of n.split(`
|
|
162
|
+
`)){if(o.trim().startsWith("#")||!o.trim())continue;let i=o.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(i){let[,a,s]=i;r[a]=s.replace(/^["'](.*)["']$/,"$1")}}return r}function jt(e){let t=nt(e,".env.local"),n=nt(e,".env"),r=tt(t)?t:n;if(!tt(r))return{};let o=Ln(r,"utf-8"),i={};for(let a of o.split(`
|
|
163
|
+
`)){if(a.trim().startsWith("#")||!a.trim())continue;let s=a.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(s){let[,u,m]=s;i[u]=m.replace(/^["'](.*)["']$/,"$1")}}return i}function Gi(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function Vi(e){return e.length<=8?"*".repeat(Math.max(e.length,4)):e.substring(0,4)+"*".repeat(e.length-8)+e.substring(e.length-4)}async function zi(e){d("Validating environment variables...","info");let t=y(),n=rt(t),r=jt(t),o=process.env,i={},a=!0;for(let s of Object.keys(n)){let u=s in r||s in o;i[s]=u,u||(a=!1)}if(e.format==="json")b({valid:a,checked:Object.keys(n).length,missing:Object.entries(i).filter(([,s])=>!s).map(([s])=>s)},{format:"json"});else{Qe("Environment Validation");let s=Object.entries(i).filter(([,u])=>!u).map(([u])=>u);if(s.length===0)d("All required environment variables are set","success");else{d(`${s.length} missing environment variable(s):`,"warn");for(let u of s)d(` - ${u}`,"warn")}}a||process.exit(l.CONFIG_ERROR)}async function Ki(e){let t=y(),n=rt(t),r=nt(t,".env.local");if(tt(r)&&!e.yes&&!e.dryRun){let u=await he.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(he.isCancel(u)||!u)&&(d("Template generation cancelled","warn"),process.exit(l.CANCELLED))}d("Generating .env.local from template...","info");let o={},i=0,a=Object.keys(n).length;for(let[u,m]of Object.entries(n))if(i++,e.yes)o[u]=m;else if(process.stdin.isTTY===!0){let p=`[${i}/${a}] ${u}`,f=await he.text({message:p,defaultValue:m});he.isCancel(f)&&(d("Template generation cancelled","warn"),process.exit(l.CANCELLED)),o[u]=f}else o[u]=m;let s=Object.entries(o).map(([u,m])=>{let f=/[\s=]/.test(m)?`"${m}"`:m;return`${u}=${f}`}).join(`
|
|
164
|
+
`);e.dryRun?(d("Dry-run: would write .env.local","info"),b(s,{format:"plain"})):(Bi(r,s+`
|
|
165
|
+
`),d(`Environment template written to ${r}`,"success"))}async function Wi(e){d("Comparing environment variables...","info");let t=y(),n=rt(t),r=jt(t),o=[],i=[],a=[];for(let s of Object.keys(n))s in r?a.push(s):o.push(s);for(let s of Object.keys(r))s in n||i.push(s);if(e.format==="json")b({matching:a.length,missing:o.length,extra:i.length,missing_vars:o,extra_vars:i},{format:"json"});else{if(Qe("Environment Diff"),a.length>0&&d(`Matching (${a.length}): ${a.join(", ")}`,"success"),o.length>0){d(`Missing (${o.length}):`,"warn");for(let s of o)d(` - ${s}`,"warn")}if(i.length>0){d(`Extra (${i.length}):`,"info");for(let s of i)d(` - ${s}`,"info")}}}async function Yi(e){d("Reading environment variables...","info");let t=y(),n=jt(t),r=rt(t),o={};for(let i of Object.keys(r))if(i in n){let a=n[i];o[i]=Gi(i,a)?Vi(a):a||"(empty)"}else o[i]="(not set)";if(e.format==="json"){let i={};for(let[a,s]of Object.entries(o))i[a]=s;b(i,{format:"json"})}else{Qe("Current Environment Variables");let i=Object.entries(o).map(([a,s])=>({Variable:Mi.cyan(a),Value:s}));b(i,{format:"table"}),d("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function Un(e){e.command("env <verb>").description("Manage environment variables and configuration").option("--dry-run","Show what would be done without making changes").option("--yes","Skip confirmations and use defaults").option("--format <type>","Output format: json, plain","plain").action(async(n,r,o)=>{let i=o.optsWithGlobals?.(),a={dryRun:r.dryRun||i?.dryRun,yes:r.yes||i?.yes,format:i?.format||r.format};try{switch(n){case"validate":await zi(a);break;case"template":await Ki(a);break;case"diff":await Wi(a);break;case"show":await Yi(a);break;default:d(`Unknown env subcommand: ${n}. Valid commands: validate, template, diff, show`,"error"),process.exit(l.INVALID_ARGS)}}catch(s){let u=s instanceof Error?s.message:String(s);d(`Environment command failed: ${u}`,"error"),x("Full error",{error:s}),process.exit(l.ERROR)}}).addHelpText("after",`
|
|
165
166
|
Examples:
|
|
166
167
|
nebutra env validate Check all required vars are set
|
|
167
168
|
nebutra env template Generate .env.local from .env.example with prompts
|
|
@@ -178,7 +179,7 @@ Flags:
|
|
|
178
179
|
Sensitive Variables:
|
|
179
180
|
Variables with KEY, TOKEN, SECRET, PASSWORD in their names are masked in output.
|
|
180
181
|
This prevents accidental exposure of credentials.
|
|
181
|
-
`)}import{promises as
|
|
182
|
+
`)}import{promises as Bn}from"fs";import{join as ye}from"path";import*as Ue from"@clack/prompts";import _ from"picocolors";var Le=["design","iam","commerce","integrations","platform","ops","ai"];function Ji(e){return Le.includes(e)}function Ft(e,t){if(!t)throw new Error(`--category is required. Valid categories: ${Le.join(", ")}. Example: nebutra generate package ${e} --category iam`);if(!Ji(t))throw new Error(`Unknown category "${t}". Valid categories: ${Le.join(", ")}.`);return`packages/${t}/${e}`}function Mn(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
|
|
182
183
|
"name": "@nebutra/${e}",
|
|
183
184
|
"version": "0.0.0",
|
|
184
185
|
"private": true,
|
|
@@ -263,7 +264,7 @@ export default function RootLayout({
|
|
|
263
264
|
|
|
264
265
|
@theme {
|
|
265
266
|
--color-*: var(--neutral-*);
|
|
266
|
-
}`}}function
|
|
267
|
+
}`}}function Gn(e){return{"package.json":`{
|
|
267
268
|
"name": "@nebutra/${e}",
|
|
268
269
|
"version": "0.0.0",
|
|
269
270
|
"type": "module",
|
|
@@ -300,7 +301,7 @@ export default function RootLayout({
|
|
|
300
301
|
|
|
301
302
|
export function hello(name: string): string {
|
|
302
303
|
return \`Hello, \${name}!\`;
|
|
303
|
-
}`}}function
|
|
304
|
+
}`}}function Vn(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
|
|
304
305
|
import { z } from "zod";
|
|
305
306
|
|
|
306
307
|
type Env = {
|
|
@@ -351,7 +352,7 @@ app.post("/", async (c) => {
|
|
|
351
352
|
);
|
|
352
353
|
});
|
|
353
354
|
|
|
354
|
-
export default app;`}}function
|
|
355
|
+
export default app;`}}function zn(e){let t=e.replace(/([A-Z])/g,"-$1").toLowerCase().replace(/^-/,""),n=e.split("-").map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join("");return{[`src/components/${t}.tsx`]:`import { cva, type VariantProps } from "class-variance-authority";
|
|
355
356
|
import { cn } from "@nebutra/ui/utils";
|
|
356
357
|
|
|
357
358
|
const ${t}Variants = cva(
|
|
@@ -425,13 +426,13 @@ export const AllSizes: Story = {
|
|
|
425
426
|
<${n} size="lg">Large</\${pascalCase}>
|
|
426
427
|
</div>
|
|
427
428
|
),
|
|
428
|
-
};`}}async function
|
|
429
|
-
`),process.exit(
|
|
430
|
-
`),process.exit(
|
|
431
|
-
`),process.exit(
|
|
432
|
-
`),process.exit(
|
|
433
|
-
`),r.push({app:a,path:
|
|
434
|
-
Average coverage: ${a(i.toFixed(1)+"%")}`)}}}function
|
|
429
|
+
};`}}async function ot(e,t,n){let r=y(),o=[],i={};switch(e){case"app":i=Mn(t);break;case"package":i=Gn(t);break;case"route":i=Vn(t);break;case"component":i=zn(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let a=e==="package"?Ft(t,n.category):void 0;for(let[s,u]of Object.entries(i)){let m=e==="app"?ye(r,"apps",t,s):e==="package"?ye(r,a??`packages/${t}`,s):ye(r,"backends/gateway",s);o.push({path:m,size:Buffer.byteLength(u)})}return o}async function it(e,t,n={}){let r=y(),o=[],i={};switch(e){case"app":i=Mn(t);break;case"package":i=Gn(t);break;case"route":i=Vn(t);break;case"component":i=zn(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let a=e==="package"?Ft(t,n.category):void 0;for(let[s,u]of Object.entries(i)){let m;e==="app"?m=ye(r,"apps",t,s):e==="package"?m=ye(r,a??`packages/${t}`,s):e==="component"?m=ye(r,"packages/design/ui",s):m=ye(r,"backends/gateway",s);let p=m.substring(0,m.lastIndexOf("/"));await Bn.mkdir(p,{recursive:!0}),await Bn.writeFile(m,u,"utf-8"),o.push(m)}return o}async function qi(e,t){if(t.dryRun){let r=await ot("app",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"app",name:e,location:`apps/${e}`,files:r.map(i=>({path:i.path,sizeBytes:i.size})),instructions:[`cd apps/${e}`,"pnpm install","pnpm run dev"]};process.stdout.write(JSON.stringify(o,null,2)+`
|
|
430
|
+
`),process.exit(l.DRY_RUN_OK)}Ue.intro(_.bgCyan(_.black(" nebutra generate app ")));let n=c.spinner();try{n.start(`Generating app ${_.cyan(e)}...`);let r=await it("app",e);n.stop(`Created app ${_.cyan(e)}`,0),c.success(`App created with ${r.length} files`),c.info("Next steps:"),c.info(` cd apps/${e}`),c.info(" pnpm install"),c.info(" pnpm run dev"),process.exit(l.SUCCESS)}catch(r){n.stop(`Failed to generate app: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(l.ERROR)}}async function Hi(e,t){let n;try{n=Ft(e,t.category)}catch(o){c.error(o instanceof Error?o.message:String(o)),process.exit(l.INVALID_ARGS)}if(t.dryRun){let o=await ot("package",e,t),i={mode:"dry-run",timestamp:new Date().toISOString(),type:"package",name:e,category:t.category,location:n,files:o.map(a=>({path:a.path,sizeBytes:a.size}))};process.stdout.write(JSON.stringify(i,null,2)+`
|
|
431
|
+
`),process.exit(l.DRY_RUN_OK)}Ue.intro(_.bgCyan(_.black(" nebutra generate package ")));let r=c.spinner();try{r.start(`Generating package ${_.cyan(e)} in ${_.dim(n)}...`);let o=await it("package",e,{category:t.category});r.stop(`Created package ${_.cyan(e)}`,0),c.success(`Package created with ${o.length} files`),c.info("Next steps:"),c.info(` Edit ${n}/src/index.ts`),c.info(` Run: pnpm --filter @nebutra/${e} build`),process.exit(l.SUCCESS)}catch(o){r.stop(`Failed to generate package: ${o instanceof Error?o.message:"Unknown error"}`,1),process.exit(l.ERROR)}}async function Zi(e,t){if(t.dryRun){let r=await ot("route",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"route",path:e,location:`backends/gateway/src/routes/${e}.ts`,files:r.map(i=>({path:i.path,sizeBytes:i.size}))};process.stdout.write(JSON.stringify(o,null,2)+`
|
|
432
|
+
`),process.exit(l.DRY_RUN_OK)}Ue.intro(_.bgCyan(_.black(" nebutra generate route ")));let n=c.spinner();try{n.start(`Generating route ${_.cyan(e)}...`);let r=await it("route",e);n.stop(`Created route ${_.cyan(e)}`,0),c.success(`Route created with ${r.length} files`),c.info(`File: backends/gateway/src/routes/${e}.ts`),c.info(`Add to your main app.ts: app.route("/${e}", routes)`),process.exit(l.SUCCESS)}catch(r){n.stop(`Failed to generate route: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(l.ERROR)}}async function Qi(e,t){if(t.dryRun){let r=await ot("component",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"component",name:e,location:"packages/design/ui/src/components/",files:r.map(i=>({path:i.path,sizeBytes:i.size})),nextSteps:["Add export to packages/design/ui/src/components/index.ts","Run: pnpm --filter @nebutra/ui typecheck","View in Storybook: pnpm --filter @nebutra/storybook dev"]};process.stdout.write(JSON.stringify(o,null,2)+`
|
|
433
|
+
`),process.exit(l.DRY_RUN_OK)}Ue.intro(_.bgCyan(_.black(" nebutra generate component ")));let n=c.spinner();try{n.start(`Generating component ${_.cyan(e)}...`);let r=await it("component",e);n.stop(`Created component ${_.cyan(e)}`,0),c.success(`Component created with ${r.length} files`),c.info("Files created in packages/design/ui/src/components/"),c.info("Next steps:"),c.info(" 1. Add export to packages/design/ui/src/components/index.ts"),c.info(" 2. pnpm --filter @nebutra/ui typecheck"),c.info(" 3. pnpm --filter @nebutra/storybook dev"),process.exit(l.SUCCESS)}catch(r){n.stop(`Failed to generate component: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(l.ERROR)}}var Kn=e=>{let t=e.command("generate").description("Scaffold a new app, package, route, or component").alias("gen");t.command("app <name>").description("Scaffold a new Next.js app (Next.js 16 + Tailwind v4)").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").option("--template <type>","App template (default: nextjs)","nextjs").option("--port <number>","Dev server port","3000").action(async(n,r,o)=>{let i=A(r,o);await qi(n,{dryRun:!!r.dryRun,yes:!!i.yes,interactive:!!process.stdin.isTTY,template:(r.template==="nextjs","nextjs"),port:typeof r.port=="string"?Number(r.port):void 0})}),t.command("package <name>").description(`Scaffold a new categorized package (@nebutra/<name>). Categories: ${Le.join(", ")}`).requiredOption("--category <category>",`Package category: ${Le.join(" | ")}`).option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r,o)=>{let i=A(r,o);await Hi(n,{category:String(r.category??""),dryRun:!!r.dryRun,yes:!!i.yes})}),t.command("route <path>").description("Scaffold a Hono API route in backends/gateway").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r,o)=>{let i=A(r,o);await Zi(n,{dryRun:!!r.dryRun,yes:!!i.yes})}),t.command("component <name>").description("Scaffold a UI component with Storybook story").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").option("--variants <list>","Comma-separated variant names (e.g., 'primary,secondary')").option("--sizes <list>","Comma-separated size names (e.g., 'sm,md,lg')").action(async(n,r,o)=>{let i=A(r,o);await Qi(n,{dryRun:!!r.dryRun,yes:!!i.yes,variants:typeof r.variants=="string"?r.variants:void 0,sizes:typeof r.sizes=="string"?r.sizes:void 0})})};import Dt,{lstatSync as Xi,readdirSync as Tt,readFileSync as ea,writeFileSync as ta}from"fs";import ne from"path";import U from"picocolors";function Lt(){let e=new Map,t=ne.join(y(),"apps");if(!Dt.existsSync(t))return e;try{let n=Tt(t);for(let r of n){let o=ne.join(t,r),i=ne.join(o,"messages");Dt.existsSync(i)&&Xi(i).isDirectory()&&e.set(r,i)}}catch(n){c.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function Be(e,t=""){let n=new Set;for(let[r,o]of Object.entries(e)){let i=t?`${t}.${r}`:r;if(typeof o=="object"&&o!==null&&!Array.isArray(o)){let a=Be(o,i);for(let s of a)n.add(s)}else n.add(i)}return n}function Me(e){try{let t=ea(e,"utf-8");return JSON.parse(t)}catch(t){return c.debug(`Failed to parse ${e}: ${t instanceof Error?t.message:String(t)}`),null}}async function na(e){if(c.info("Syncing language files across the project..."),(await j("translate",{filter:"landing",dryRun:e.dryRun,interactive:e.interactive??!0})).exitCode!==0){c.warn("Landing page translate script not found or failed. Trying sync-lang.mjs...");let n=await E({command:"node",args:["scripts/sync-lang.mjs"],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Sync language files"});n.exitCode!==0&&(c.error("Failed to sync language files"),process.exit(n.exitCode)),e.format==="json"?console.log(JSON.stringify({command:"i18n:sync",exitCode:0,success:!0},null,2)):e.dryRun||c.success("Language files synced successfully")}else e.format==="json"?console.log(JSON.stringify({command:"i18n:sync",exitCode:0,success:!0},null,2)):e.dryRun||c.success("Language files synced successfully")}async function ra(e){c.info("Validating translation files...");let t=Lt();t.size===0&&(c.warn("No message directories found in the project"),process.exit(l.NOT_FOUND));let n=new Map,r=!1;for(let[o,i]of t){let a=[];try{let s=Tt(i).filter(f=>f.endsWith(".json"));if(s.length===0)continue;let u=ne.join(i,"en.json"),m=Me(u);if(!m){c.warn(`Could not load reference locale en.json from ${o}`);continue}let p=Be(m);for(let f of s){if(f==="en.json")continue;let h=f.replace(".json",""),g=ne.join(i,f),k=Me(g);if(!k){c.debug(`Could not parse ${f}`);continue}let F=Be(k),w=Array.from(p).filter(L=>!F.has(L)),W=Array.from(F).filter(L=>!p.has(L)),X=p.size>0?(p.size-w.length)/p.size*100:100;(w.length>0||W.length>0)&&(r=!0),a.push({locale:h,totalKeys:p.size,missingKeys:w,extraKeys:W,coverage:Math.round(X*100)/100})}a.length>0&&n.set(o,a)}catch(s){c.debug(`Error validating ${o}: ${s instanceof Error?s.message:String(s)}`)}}if(e.format==="json"){let o={command:"i18n:validate",success:!r,results:Array.from(n.entries()).reduce((i,[a,s])=>(i[a]=s,i),{})};console.log(JSON.stringify(o,null,2))}else for(let[o,i]of n){c.info(`${U.bold(o)}:`);for(let a of i){let u=(a.coverage>=100?U.green:a.coverage>=80?U.yellow:U.red)(`${a.coverage}%`);c.info(` ${U.cyan(a.locale.padEnd(5))} ${u.padEnd(20)} [${a.totalKeys} keys]`),a.missingKeys.length>0&&c.warn(` Missing: ${a.missingKeys.slice(0,5).join(", ")}${a.missingKeys.length>5?` (+ ${a.missingKeys.length-5} more)`:""}`),a.extraKeys.length>0&&c.warn(` Extra: ${a.extraKeys.slice(0,5).join(", ")}${a.extraKeys.length>5?` (+ ${a.extraKeys.length-5} more)`:""}`)}}r&&process.exit(l.CONFLICT)}async function oa(e,t){/^[a-z]{2}(-[A-Z]{2})?$/.test(e)||(c.error(`Invalid locale format: ${e}. Use 'en', 'es', 'zh-CN', etc.`),process.exit(l.INVALID_ARGS));let n=Lt();n.size===0&&(c.error("No message directories found in the project"),process.exit(l.NOT_FOUND));let r=[],o=!1;for(let[a,s]of n){let u=ne.join(s,`${e}.json`);if(Dt.existsSync(u)){c.warn(`Locale ${e} already exists in ${a}`);continue}try{let h=function(g){for(let k in g)typeof g[k]=="string"?g[k]="":typeof g[k]=="object"&&g[k]!==null&&h(g[k])};var i=h;let m=ne.join(s,"en.json"),p=Me(m);if(!p){c.warn(`Could not load reference en.json from ${a}, skipping...`);continue}let f=JSON.parse(JSON.stringify(p));h(f),t.dryRun?c.info(`Would create ${e} locale in ${a}`):(ta(u,JSON.stringify(f,null,2)+`
|
|
434
|
+
`),r.push({app:a,path:u}),c.success(`Created ${e} locale in ${a}`))}catch(m){c.error(`Failed to create locale in ${a}: ${m instanceof Error?m.message:String(m)}`),o=!0}}t.format==="json"?console.log(JSON.stringify({command:"i18n:add",locale:e,dryRun:t.dryRun||!1,created:r,success:!o},null,2)):t.dryRun||c.success(`Locale '${e}' added to ${r.length} app(s)`),o&&process.exit(l.ERROR)}async function ia(e){c.info("Checking translation coverage...");let t=Lt();t.size===0&&(c.warn("No message directories found in the project"),process.exit(l.NOT_FOUND));let n=new Map,r=0,o=0;for(let[i,a]of t){let s=[];try{let u=Tt(a).filter(h=>h.endsWith(".json"));if(u.length===0)continue;let m=ne.join(a,"en.json"),p=Me(m);if(!p){c.debug(`Could not load reference locale from ${i}`);continue}let f=Be(p);for(let h of u){let g=h.replace(".json",""),k=ne.join(a,h),F=Me(k);if(!F)continue;let w=Be(F),W=Array.from(w).filter(Se=>{let We=F[Se.split(".")[0]];return We!==void 0&&We!==""}).length,X=f.size-W,L=f.size>0?W/f.size*100:0;s.push({locale:g,coverage:Math.round(L*100)/100,totalKeys:f.size,translatedKeys:W,missingKeys:X})}s.length>0&&(n.set(i,s),o++,r+=s.reduce((h,g)=>h+g.coverage,0)/s.length)}catch(u){c.debug(`Error checking status for ${i}: ${u instanceof Error?u.message:String(u)}`)}}if(e.format==="json"){let i={command:"i18n:status",averageCoverage:o>0?Math.round(r/o*100)/100:0,results:Array.from(n.entries()).reduce((a,[s,u])=>(a[s]=u,a),{})};console.log(JSON.stringify(i,null,2))}else{for(let[i,a]of n){c.info(`${U.bold(i)}:`);for(let s of a){let u="",p=Math.round(s.coverage/100*20);u="\u2588".repeat(p)+"\u2591".repeat(20-p);let h=(s.coverage>=100?U.green:s.coverage>=80?U.yellow:U.red)(`${s.coverage.toFixed(1)}%`);c.info(` ${U.cyan(s.locale.padEnd(5))} [${u}] ${h}`),c.info(` ${s.translatedKeys}/${s.totalKeys} keys (${s.missingKeys} missing)`)}}if(o>0){let i=r/o,a=i>=100?U.green:i>=80?U.yellow:U.red;c.info(`
|
|
435
|
+
Average coverage: ${a(i.toFixed(1)+"%")}`)}}}function Wn(e){let t=e.command("i18n").description("Manage internationalization and translations");t.command("sync").description("Synchronize language translations across the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await na({dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})}),t.command("validate").description("Validate all locale files for missing or extra keys").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await ra({format:n.format||o.format,interactive:o.yes!==!0})}),t.command("add <locale>").description("Add a new locale with template files (e.g. 'en', 'es', 'zh-CN')").option("--dry-run","Preview what would be created without writing files").option("--format <type>","Output format: json or plain").action(async(n,r,o)=>{let i=o.optsWithGlobals?.()||r;await oa(n,{dryRun:r.dryRun||!1,format:r.format||i.format,interactive:i.yes!==!0})}),t.command("status").description("Show translation coverage per locale and app").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||n;await ia({format:n.format||o.format,interactive:o.yes!==!0})})}import*as at from"@clack/prompts";async function aa(e){let t=e.lite?"docker-compose.lite.yml":void 0,n=e.lite?"Starting lite stack (PostgreSQL + Redis)":"Starting full stack";d(n+"...","info");let r=await ge("up -d",{file:t,profile:e.profile,dryRun:e.dryRun});r.exitCode===0?d("Infrastructure stack started successfully","success"):(d(Ge(r)??"Failed to start infrastructure stack","error"),x("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function sa(e){d("Stopping infrastructure stack...","info");let t=await ge("down",{dryRun:e.dryRun});t.exitCode===0?d("Infrastructure stack stopped","success"):(d(Ge(t)??"Failed to stop infrastructure stack","error"),x("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}function Ge(e){let t=e.stderr||"";if(e.exitCode===127||/command not found|ENOENT/i.test(t))return"Docker CLI not found. Install Docker Desktop (or the docker CLI) and make sure it's on your PATH.";if(/cannot connect to the docker daemon|is the docker daemon running/i.test(t))return"Docker daemon is not running. Start Docker Desktop (or `dockerd`) and try again."}async function ca(e){d("Checking infrastructure status...","info");let t=await ge("ps --format json",{dryRun:e.dryRun,interactive:!1});if(e.dryRun)return;let n=t.exitCode!==0&&/unknown (flag|shorthand flag)/i.test(t.stderr);if(n&&(x("docker compose ps --format json unsupported, falling back to plain ps",{stderr:t.stderr}),t=await ge("ps",{interactive:!1})),t.exitCode!==0){let r=Ge(t);d(r??"Failed to check infrastructure status","error"),x("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}if(n){e.format==="json"&&d("This Docker Compose version doesn't support `--format json`; showing plain text instead.","warn"),b(t.stdout,{format:"plain"});return}try{let r=JSON.parse(t.stdout);if(e.format==="json")b(r,{format:"json"});else{let o=r.map(i=>({name:i.Name,status:i.Status,ports:i.Ports||"-"}));b(o,{format:"table"})}}catch{b(t.stdout,{format:"plain"})}}async function la(e,t){let n=t||{},r=e?`Fetching logs for ${e}...`:"Fetching infrastructure logs...";d(r,"info");let o=["logs","--tail","50"];e&&o.push(e);let i=await ge(o.join(" "),{dryRun:n.dryRun});i.exitCode===0?b(i.stdout,{format:"plain"}):(d(Ge(i)??"Failed to fetch logs","error"),x("Docker compose output",{stderr:i.stderr}),process.exit(i.exitCode||1))}async function ua(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await at.confirm({message:"Reset infrastructure? This will remove all containers and volumes.",initialValue:!1});(at.isCancel(r)||!r)&&(d("Reset cancelled","warn"),process.exit(l.CANCELLED))}else d("Infrastructure reset requires explicit --yes confirmation (use: nebutra infra reset --yes)","error"),process.exit(l.INVALID_ARGS);d("Resetting infrastructure stack...","warn");let n=await ge("down -v",{dryRun:e.dryRun});n.exitCode===0?d("Infrastructure reset successfully","success"):(d(Ge(n)??"Failed to reset infrastructure","error"),x("Docker compose output",{stderr:n.stderr}),process.exit(n.exitCode||1))}function Yn(e){e.command("infra <verb> [service]").description("Manage Docker Compose infrastructure (PostgreSQL, Redis, etc.)").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations (especially for reset)").option("--lite","Use lite stack (PostgreSQL + Redis only)").option("--profile <name>","Docker Compose profile to use (e.g., search)").option("--format <type>","Output format: json, plain","plain").action(async(n,r,o,i)=>{let a=i.optsWithGlobals?.(),s={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:a?.format||o.format,lite:o.lite||!1,profile:o.profile};try{switch(n){case"up":await aa(s);break;case"down":await sa(s);break;case"status":await ca(s);break;case"logs":await la(r,s);break;case"reset":await ua(s);break;default:d(`Unknown infra subcommand: ${n}. Valid commands: up, down, status, logs, reset`,"error"),process.exit(l.INVALID_ARGS)}}catch(u){let m=u instanceof Error?u.message:String(u);d(`Infrastructure command failed: ${m}`,"error"),x("Full error",{error:u}),process.exit(l.ERROR)}}).addHelpText("after",`
|
|
435
436
|
Examples:
|
|
436
437
|
nebutra infra up Start full stack
|
|
437
438
|
nebutra infra up --lite Start lite stack (PostgreSQL + Redis)
|
|
@@ -448,19 +449,19 @@ Flags:
|
|
|
448
449
|
--lite Use docker-compose.lite.yml (PostgreSQL + Redis only)
|
|
449
450
|
--profile <name> Enable Docker Compose profile (search, notifications, etc.)
|
|
450
451
|
--format <type> Output format: json, plain (default: plain, auto-json in non-TTY)
|
|
451
|
-
`)}import
|
|
452
|
-
`),o?(
|
|
453
|
-
`)}async function
|
|
454
|
-
`,{mode:384});try{
|
|
455
|
-
`,{mode:384})}function
|
|
456
|
-
`),await
|
|
457
|
-
`),
|
|
458
|
-
`),
|
|
459
|
-
`));let r=
|
|
460
|
-
Failed to start MCP server: ${o.message}`),o.code==="ENOENT"&&(
|
|
461
|
-
Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),
|
|
462
|
-
Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{
|
|
463
|
-
`)}function
|
|
452
|
+
`)}import Ut from"fs";import da from"path";import*as V from"@clack/prompts";import st from"picocolors";var ma=["auth","billing","email","storage","queue","cache","notifications","webhooks","ai","mcp"],pa={stack:"sailor-2026-09",capabilities:[...ma]};function ga(){return process.stdout.isTTY===!0}function fa(e){return e.yes===!0||e.dryRun===!0||!ga()}function ha(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function Jn(e={}){let t=process.cwd(),n=da.join(t,"nebutra.config.json"),r=Ut.existsSync(n);e.ifNotExists&&r&&(c.info("nebutra.config.json already exists, skipping initialization."),process.exit(l.SUCCESS));let o=fa(e);o||V.intro(st.bgCyan(st.black(" nebutra init "))),r&&!o&&(V.log.warn("nebutra.config.json already exists in this directory."),await V.confirm({message:"Do you want to overwrite it?",initialValue:!1})||(V.outro("Operation aborted."),process.exit(l.CANCELLED)));let i={...pa};if(e.dryRun){let a=r?JSON.parse(Ut.readFileSync(n,"utf-8")):void 0,s=ha(n,i,a);I(s),d("Dry-run completed. No changes made."),process.exit(l.DRY_RUN_OK)}o?c.info("Initializing Nebutra CLI configuration..."):V.spinner().start("Initializing Nebutra CLI configuration..."),Ut.writeFileSync(n,JSON.stringify(i,null,2)+`
|
|
453
|
+
`),o?(c.success("Configuration saved to nebutra.config.json"),c.info('Initialization complete! Run "nebutra status" to check capability readiness.')):(await new Promise(a=>setTimeout(a,800)),V.spinner().stop(st.green("Configuration saved to nebutra.config.json")),V.outro(st.cyan('Initialization complete! Run "nebutra status" to check capability readiness.'))),process.exit(l.SUCCESS)}import Bt from"fs/promises";import ka from"os";import Mt from"path";import*as C from"@clack/prompts";import B from"picocolors";var ya="https://analytics.nebutra.com";function ba(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function va(){return process.env.npm_package_version??"0.0.0-dev"}function ct(e,t={}){ba(t)||(async()=>{try{let n=await import("@nebutra/analytics");if(typeof n.createProductAnalyticsClient!="function")return;let r=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??ya},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",{action:e.action,cli_version:va(),...e.tier?{license_tier:e.tier}:{},...e.type?{license_type:e.type}:{},...e.error_code?{error_code:e.error_code}:{}});o&&typeof o.then=="function"&&await o.catch(()=>{})}catch{}})()}var qn=process.env.NEBUTRA_LICENSE_API_URL??"https://nebutra.com";async function Hn(){let e=ka.homedir(),t=Mt.join(e,".config","nebutra");try{await Bt.mkdir(t,{recursive:!0})}catch{}return t}async function wa(e){let t=`${qn}/api/license/validate?key=${encodeURIComponent(e)}`,n;try{n=await fetch(t,{signal:AbortSignal.timeout(1e4)})}catch{throw new Error(`Could not reach the Nebutra license server (${qn}). Check your internet connection or set NEBUTRA_LICENSE_API_URL.`)}if(n.status===404)throw new Error("License key not found. Please check the key and try again.");if(n.status===410)throw new Error("License key has expired. Please renew your license at nebutra.com.");if(!n.ok)throw new Error(`License validation failed (HTTP ${n.status}). Please try again later.`);let r=await n.json();if(!r.valid)throw new Error("License key is not valid. Please check the key and try again.");return{tier:r.tier??"UNKNOWN",type:r.type??"UNKNOWN"}}function xa(e){let t=e instanceof Error?e.message:String(e);return/Invalid license key format/i.test(t)?"invalid_format":/license server/i.test(t)?"network_error":/not found/i.test(t)?"not_found":/expired/i.test(t)?"expired":/not valid/i.test(t)?"invalid_key":/HTTP \d+/i.test(t)?"http_error":"unknown"}async function Ca(e,t){let n=t.quiet===!0;n||C.intro(B.bgCyan(B.black(" Nebutra License Activation "))),ct({action:"activate_attempted"});try{if(e.length<10)throw new Error("Invalid license key format.");n||C.log.step("Validating license key with Nebutra...");let{tier:r,type:o}=await wa(e),i=await Hn(),a=Mt.join(i,"license.json");await Bt.writeFile(a,JSON.stringify({licenseKey:e,tier:r,type:o,activatedAt:new Date().toISOString()},null,2),"utf-8"),n||(C.log.success(B.green(`${r} license activated and saved to ${a}`)),C.outro(B.cyan("Recorded locally. Sailor scaffolds are MIT-licensed \u2014 this doesn't unlock CLI features; paid tiers are support and hosting, see nebutra.com/pricing."))),ct({action:"activated",tier:r,type:o})}catch(r){ct({action:"failed",error_code:xa(r)}),n||(C.log.error(B.red("Activation failed")),c.error(r instanceof Error?r.message:String(r)),C.outro("Please check your key and try again.")),process.exit(l.ERROR)}}async function Sa(e){let t=e.quiet===!0;t||C.intro(B.bgCyan(B.black(" Nebutra License Status ")));try{let n=await Hn(),r=Mt.join(n,"license.json"),o=await Bt.readFile(r,"utf-8"),i=JSON.parse(o);if(i.licenseKey)t||(C.log.success(B.green("License is active!")),C.log.info(`Key: ${i.licenseKey.substring(0,8)}...`),i.tier&&C.log.info(`Tier: ${B.bold(i.tier)}`),i.type&&C.log.info(`Type: ${i.type}`),C.log.info(`Activated: ${new Date(i.activatedAt).toLocaleString()}`),C.log.message(B.dim("Note: this record is informational. Sailor scaffolds are MIT-licensed and the CLI has no premium features gated behind a license key.")),C.outro(B.cyan("See nebutra.com/pricing for paid support and hosting tiers.")));else throw new Error("License key not found in config.")}catch{t||(C.log.warn(B.yellow("No active license found locally.")),C.log.message(B.dim("This is expected \u2014 Sailor scaffolds are MIT-licensed and nothing in the CLI is gated behind a license. `nebutra license activate <key>` only records a key for support/billing purposes.")),C.outro("")),process.exit(l.NOT_FOUND)}}function Zn(e){let t=e.command("license").description("Record a Nebutra support/billing license key locally (Sailor scaffolds are MIT \u2014 nothing in the CLI is gated by this)");t.command("activate <key>").description("Validate and record a license key locally (support/billing record, not a feature unlock)").option("--quiet","Suppress output").action(async(n,r)=>{await Ca(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await Sa(n)})}import{existsSync as Qn,readFileSync as Ea,writeFileSync as Ra}from"fs";import{dirname as Oa,join as Xn,parse as Aa}from"path";import*as lt from"@clack/prompts";function _a(e){let t=e,{root:n}=Aa(t);for(;;){if(Qn(Xn(t,"package.json")))return t;if(t===n)return null;let r=Oa(t);if(r===t)return null;t=r}}function Ia(e){if(!Qn(e))return{};try{let t=JSON.parse(Ea(e,"utf-8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function Pa(e,t){Ra(e,JSON.stringify(t,null,2)+`
|
|
454
|
+
`)}async function Na(e,t){let n=t.format==="json",r=_a(process.cwd());r||(n?console.log(JSON.stringify({command:"link",success:!1,error:"No package.json found upstream"},null,2)):c.error("No package.json found in current or parent directories."),process.exit(l.NOT_FOUND));let o=e;if(!o){t.yes&&(n?console.log(JSON.stringify({command:"link",success:!1,error:"project-id required in --yes mode"},null,2)):c.error("project-id is required when running with --yes / non-interactive."),process.exit(l.INVALID_ARGS));let u=await lt.text({message:"Project ID to link to:",placeholder:"proj_abc123",validate:m=>m&&m.trim().length>0?void 0:"Project ID cannot be empty"});lt.isCancel(u)&&(c.warn("Cancelled"),process.exit(l.CANCELLED)),o=String(u).trim()}let i=Xn(r,"nebutra.config.json"),s={...Ia(i),projectId:o};Pa(i,s),n?console.log(JSON.stringify({command:"link",success:!0,projectId:o,configPath:i},null,2)):c.success(`Linked to project: ${o}`)}function er(e){e.command("link [project-id]").description("Link the current project to a Nebutra project id").option("--format <type>","Output format: json or plain").action(async(t,n,r)=>{let o=r?.optsWithGlobals?.()||n;await Na(t,{yes:o.yes||!1,format:n.format||o.format})})}import{spawn as Ka}from"child_process";import{platform as Wa}from"os";var M={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",logo:"image",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",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"}};import{execFile as ja}from"child_process";import{chmodSync as Fa,existsSync as Pe,readFileSync as nr,rmSync as Da,unlinkSync as Gt,writeFileSync as rr}from"fs";import{mkdir as Ta}from"fs/promises";import{platform as be}from"os";import{join as or}from"path";import{promisify as La}from"util";import{homedir as tr,platform as $a}from"os";import{join as ut}from"path";function _e(){if($a()==="win32"){let t=process.env.LOCALAPPDATA||ut(tr(),"AppData","Local");return ut(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?ut(e,"nebutra"):ut(tr(),".config","nebutra")}var ve=La(ja),ke="nebutra-cli",Ne="default";function Ie(){return or(_e(),"credentials.json")}function dt(){return or(_e(),"device-pending.json")}async function ir(){await Ta(_e(),{recursive:!0})}async function Vt(e){try{return await ve(be()==="win32"?"where":"which",[e]),!0}catch{return!1}}function zt(){return process.env.NEBUTRA_NO_KEYCHAIN==="1"}async function Ua(e){if(zt())return!1;try{if(be()==="darwin")return await ve("security",["add-generic-password","-a",Ne,"-s",ke,"-w",e,"-U"]),!0;if(be()==="linux"&&await Vt("secret-tool"))return await ve("secret-tool",["store","--label",`${M.name} CLI credentials`,"service",ke,"account",Ne]),!0}catch{}return!1}async function ar(){if(zt())return null;try{if(be()==="darwin"){let{stdout:e}=await ve("security",["find-generic-password","-a",Ne,"-s",ke,"-w"]);return e.trim()||null}if(be()==="linux"&&await Vt("secret-tool")){let{stdout:e}=await ve("secret-tool",["lookup","service",ke,"account",Ne]);return e.trim()||null}}catch{}return null}async function Ba(){if(zt())return!1;let e=!1;try{be()==="darwin"?(await ve("security",["delete-generic-password","-a",Ne,"-s",ke]),e=!0):be()==="linux"&&await Vt("secret-tool")&&(await ve("secret-tool",["clear","service",ke,"account",Ne]),e=!0)}catch{}return e}async function sr(e){await ir();let t=JSON.stringify(e);if(await Ua(t)){try{Pe(Ie())&&Gt(Ie())}catch{}return{storedIn:"keychain"}}rr(Ie(),`${t}
|
|
455
|
+
`,{mode:384});try{Fa(Ie(),384)}catch{}return{storedIn:"file"}}async function Ma(){let e=await ar();if(e)try{return JSON.parse(e)}catch{return null}let t=Ie();if(!Pe(t))return null;try{return JSON.parse(nr(t,"utf-8"))}catch{return null}}async function cr(){let e=[];await Ba()&&e.push(`keychain:${ke}`);let t=Ie();if(Pe(t))try{Gt(t),e.push(t)}catch{}let n=dt();if(Pe(n))try{Da(n,{force:!0}),e.push(n)}catch{}return e}async function Kt(e){await ir(),rr(dt(),`${JSON.stringify(e)}
|
|
456
|
+
`,{mode:384})}function lr(){let e=dt();if(!Pe(e))return null;try{return JSON.parse(nr(e,"utf-8"))}catch{return null}}function mt(){let e=dt();if(Pe(e))try{Gt(e)}catch{}}async function ur(){let e=process.env.NEBUTRA_TOKEN?.trim();if(e)return{token:e,source:"env",expired:!1};let t=await Ma();if(!t)return null;let n=!!t.expiresAt&&new Date(t.expiresAt).getTime()<=Date.now(),r=await ar()!==null;return{token:t.accessToken,source:r?"keychain":"file",expired:n}}var Ga={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",logo:"image",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",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 pt(e){let t=Ga.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 dr="nebutra-cli";function gt(){let e=process.env.NEBUTRA_AUTH_URL?.trim();return e?e.replace(/\/+$/,""):pt("auth")}var re=class extends Error{constructor(n,r){super(r);this.code=n;this.name="DeviceAuthError"}code};async function Wt(e){try{return await e.json()}catch{return{}}}async function mr(e,t,n,r={}){let o=r.attempts??3,i=r.sleep??gr,a;for(let s=1;s<=o;s++){try{let u=await e(t,{...n,signal:AbortSignal.timeout(r.timeoutMs??1e4)});if(u.status<500||s===o)return u;a=new Error(`HTTP ${u.status}`)}catch(u){if(!fr(u)||s===o)throw u;a=u}await i(1e3*s)}throw a}async function pr(e,t=fetch){let n=await mr(t,`${e}/api/auth/device/code`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:dr})}),r=await Wt(n);if(!n.ok)throw new re(typeof r.error=="string"?r.error:"request_failed",typeof r.error_description=="string"?r.error_description:`Could not reach ${M.name}'s auth center (${n.status}).`);return r}async function Va(e,t,n=fetch){let r=await n(`${e}/api/auth/device/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({grant_type:"urn:ietf:params:oauth:grant-type:device_code",device_code:t,client_id:dr}),signal:AbortSignal.timeout(1e4)}),o=await Wt(r);if(!r.ok)throw new re(typeof o.error=="string"?o.error:"request_failed",typeof o.error_description=="string"?o.error_description:`HTTP ${r.status}`);return o}var gr=e=>new Promise(t=>setTimeout(t,e)),za=30;function fr(e){if(e instanceof re)return e.code==="request_failed";if(e instanceof TypeError)return!0;let t=e?.name;return t==="TimeoutError"||t==="AbortError"}async function hr(e,t,n){let r=n.fetchImpl??fetch,o=n.sleep??gr,i=n.intervalSeconds;for(;;){if(Date.now()>=n.deadline)throw new re("expired_token","The device code expired before it was approved.");n.onWaiting?.(i),await o(i*1e3);try{return await Va(e,t,r)}catch(a){if(fr(a)){i=Math.min(i+5,za),n.onTransientFailure?.(a);continue}if(!(a instanceof re))throw a;if(a.code==="authorization_pending")continue;if(a.code==="slow_down"){i+=5;continue}throw a}}}async function ft(e,t,n=fetch){let r=await mr(n,`${e}/api/auth/get-session`,{method:"GET",headers:{authorization:`Bearer ${t}`}});if(!r.ok)return null;let i=(await Wt(r)).user;return!i||typeof i.id!="string"?null:{userId:i.id,email:typeof i.email=="string"?i.email:null,name:typeof i.name=="string"?i.name:null}}function Ya(e,t){return!!e.json||e.format==="json"||t==="json"}function Ja(e){try{let t=Wa(),[n,r]=t==="darwin"?["open",[e]]:t==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]],o=Ka(n,r,{stdio:"ignore",detached:!0});o.on("error",()=>{}),o.unref()}catch{}}async function qa(e,t){let n=new Date;await sr({accessToken:t.access_token,tokenType:t.token_type,expiresAt:new Date(n.getTime()+t.expires_in*1e3).toISOString(),scope:t.scope,obtainedAt:n.toISOString()}),mt()}async function yr(e,t,n){let r=0,o=await hr(e,t.deviceCode,{intervalSeconds:t.interval,deadline:t.expiresAt,onWaiting:()=>{n||(r++,process.stderr.write(r===1?"Waiting for approval":"."))},onTransientFailure:()=>{n||process.stderr.write("!")}});n||process.stderr.write(`
|
|
457
|
+
`),await qa(e,o);let i=await ft(e,o.access_token);return i?{userId:i.userId,email:i.email}:null}async function Ha(e,t){let n=Ya(e,t.format),r=gt();if(e.poll){let s=lr();if(s&&s.expiresAt>Date.now()&&s.baseUrl===r)try{let u=await yr(r,{deviceCode:s.deviceCode,interval:s.interval,expiresAt:s.expiresAt},n);n?console.log(JSON.stringify({command:"login",success:!0,...u},null,2)):c.success(u?.email?`Logged in as ${u.email}`:`Logged in to ${M.name}.`);return}catch(u){return mt(),Yt(u,n)}}let o;try{o=await pr(r)}catch(s){return Yt(s,n)}let i=Date.now()+o.expires_in*1e3;if(n&&!e.poll){await Kt({deviceCode:o.device_code,userCode:o.user_code,verificationUri:o.verification_uri,verificationUriComplete:o.verification_uri_complete,interval:o.interval,expiresAt:i,baseUrl:r}),console.log(JSON.stringify({command:"login",success:!0,pending:!0,verification_uri:o.verification_uri,verification_uri_complete:o.verification_uri_complete,user_code:o.user_code,expires_in:o.expires_in,interval:o.interval},null,2));return}n||(c.info(`First, confirm this code matches what's shown in the browser:
|
|
458
|
+
`),c.info(` ${o.user_code}
|
|
459
|
+
`),c.info(`Visiting: ${o.verification_uri_complete}`)),e.browser!==!1&&process.stdout.isTTY!==!1&&!t.yes&&Ja(o.verification_uri_complete);try{await Kt({deviceCode:o.device_code,userCode:o.user_code,verificationUri:o.verification_uri,verificationUriComplete:o.verification_uri_complete,interval:o.interval,expiresAt:i,baseUrl:r});let s=await yr(r,{deviceCode:o.device_code,interval:o.interval,expiresAt:i},n);n?console.log(JSON.stringify({command:"login",success:!0,...s},null,2)):c.success(s?.email?`Logged in as ${s.email}`:`Logged in to ${M.name}.`)}catch(s){return mt(),Yt(s,n)}}function Yt(e,t){let n=e instanceof re?e.code:"login_failed",r=e instanceof Error?e.message:String(e),o=n==="access_denied"?l.PERMISSION_DENIED:n==="expired_token"?l.TIMEOUT:l.NETWORK_ERROR;t?console.log(JSON.stringify({command:"login",success:!1,error:n,message:r},null,2)):c.error(r),process.exit(o)}function br(e){e.command("login").description(`Authorize this machine with your ${M.name} account (device flow)`).option("--json","Print verification details as JSON and exit immediately (agent mode)").option("--no-browser","Don't try to open a browser").option("--poll","Poll until approved/denied/expired, resuming a pending `login --json` if present").option("--format <type>","Output format: json or plain").action(async(t,n)=>{let r=n?.optsWithGlobals?.()||t;await Ha(t,{format:r.format,yes:r.yes})})}import{existsSync as vr,rmSync as Za,unlinkSync as Qa}from"fs";import{join as Xa}from"path";var es=["auth.json","session.json","token","credentials.json"];async function ts(e){let t=_e(),n=e.format==="json",r=0,o=[],i=await cr();if(r+=i.length,o.push(...i),e.all){if(vr(t))try{Za(t,{recursive:!0,force:!0}),r=1,o.push(t)}catch(a){let s=a instanceof Error?a.message:String(a);n?console.log(JSON.stringify({command:"logout",success:!1,error:s},null,2)):c.error(`Failed to clear config directory: ${s}`),process.exit(l.PERMISSION_DENIED)}}else for(let a of es){let s=Xa(t,a);if(vr(s))try{Qa(s),r++,o.push(s)}catch{}}r===0&&(n?console.log(JSON.stringify({command:"logout",success:!0,alreadyLoggedOut:!0,removed:[]},null,2)):c.info("Already logged out"),process.exit(l.SUCCESS)),n?console.log(JSON.stringify({command:"logout",success:!0,removed:o,clearedAll:!!e.all},null,2)):c.success(e.all?"Cleared all nebutra config":"Logged out of nebutra.com")}function kr(e){e.command("logout").description("Clear stored authentication credentials").option("--all","Clear ALL local config, not just auth tokens").option("--format <type>","Output format: json or plain").action(async(t,n)=>{let r=n?.optsWithGlobals?.()||t;await ts({all:t.all||!1,format:t.format||r.format})})}import{spawn as ns}from"child_process";import{dirname as rs,resolve as os}from"path";import{fileURLToPath as is}from"url";import*as q from"@clack/prompts";import oe from"picocolors";var as=rs(is(import.meta.url));function ss(){let e=[()=>os(as,"../../../mcp/dist/server/contextServer.js")];for(let t of e)try{return t()}catch(n){c.debug("MCP server binary resolution strategy failed",{error:n})}return"nebutra-mcp"}function wr(e){e.command("mcp").description("Start the Nebutra MCP server for Cursor/Windsurf").option("--stdio","Use stdio transport (default)",!0).action(async t=>{q.intro(oe.bgCyan(oe.black(" nebutra mcp ")));try{let n=ss();q.log.info(oe.cyan("Starting Nebutra MCP server for Cursor/Windsurf integration...")),q.log.info(oe.dim(`Press Ctrl+C to stop the server.
|
|
460
|
+
`));let r=ns(process.execPath,[n],{stdio:"inherit",env:{...process.env}});r.on("close",o=>{o===0?q.outro(oe.green("MCP server stopped gracefully.")):o===null&&q.outro(oe.yellow("MCP server terminated.")),process.exit(o??0)}),r.on("error",o=>{c.error(`
|
|
461
|
+
Failed to start MCP server: ${o.message}`),o.code==="ENOENT"&&(c.warn(`
|
|
462
|
+
Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),c.info(" Install globally: npm install -g @nebutra/mcp"),process.exit(l.NOT_FOUND)),process.exit(l.ERROR)}),process.on("SIGINT",()=>{q.log.info(oe.yellow(`
|
|
463
|
+
Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{q.log.info(oe.yellow("Terminating MCP server...")),r.kill("SIGTERM")})}catch(n){q.log.error(oe.red("Error: Unable to start MCP server. Ensure @nebutra/mcp is properly installed.")),n instanceof Error&&c.error(n.message),process.exit(l.ERROR)}})}import*as P from"@clack/prompts";import z from"picocolors";var Cr=Object.fromEntries(Object.entries(ln).map(([e,t])=>[e,t]));function Sr(e){return typeof e=="boolean"?"boolean":"string"}function Er(e){return{name:e.name,description:e.description,usage:e.usage,arguments:e.arguments||[],options:(e.options||[]).map(n=>({flags:n.flags,description:n.description,default:n.default,required:!1,type:Sr(n.default)})),examples:e.examples||[]}}function cs(e){let n=(Z.subcommands||[]).find(r=>r.name===e);return n?Er(n):null}function ls(){return(Z.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:Sr(e.default)}))}function us(e){let t=Z.subcommands||[];return{name:Z.name,version:e,description:Z.description,usage:Z.usage||"nebutra [command] [options]",globalOptions:ls(),commands:t.map(Er),exitCodes:Cr,timestamp:new Date().toISOString()}}function xr(){return(Z.subcommands||[]).map(t=>t.name)}function ht(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
464
|
+
`)}function ds(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function ms(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(ht(us(r)),process.exit(0)),t.list===!0&&(ht(xr()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(ht(Cr),process.exit(0)),e){let o=cs(e);o||(n||(c.error(`Unknown command '${e}'`),c.info(`Available commands: ${xr().join(", ")}`)),process.exit(l.NOT_FOUND)),ht(o),process.exit(0)}n||(P.intro(z.bgCyan(z.black(" nebutra schema "))),P.log.info(z.cyan("Agent-friendly introspection of CLI commands, arguments, and value domains.")),P.log.message(""),P.log.info(z.bold("Usage:")),P.log.message(z.dim(" nebutra schema --all Show full command tree as JSON")),P.log.message(z.dim(" nebutra schema <command> Show schema for a specific command")),P.log.message(z.dim(" nebutra schema --list List available command names")),P.log.message(z.dim(" nebutra schema --exit-codes Show exit codes reference")),P.log.message(""),P.log.info(z.bold("Example:")),P.log.message(z.dim(" nebutra schema status")),P.log.message(z.dim(" nebutra schema --all | jq '.commands[0]'")),P.outro(z.cyan("All output is JSON for easy parsing by agents and automation tools."))),process.exit(0)}catch(o){if(ds(o))throw o;n||c.error(o instanceof Error?o.message:String(o)),process.exit(l.ERROR)}}function Rr(e){e.command("schema [command]").description("Show command schema and argument documentation (Agent-friendly JSON output)").option("--all","Show full schema for all commands").option("--list","List all available command names").option("--exit-codes","Show exit codes reference").action(async(t,n)=>{await ms(t,n)})}import{stdin as Ve}from"process";import*as yt from"@clack/prompts";import R from"picocolors";async function ps(){return new Promise((e,t)=>{let n="";Ve.setEncoding("utf8"),Ve.on("readable",()=>{let r;for(;(r=Ve.read())!==null;)n+=r}),Ve.on("end",()=>{e(n.trim())}),Ve.on("error",t)})}async function gs(e){d("Fetching secret metadata...","info");let t=[{key:"openai_key",tenant:e.tenant||"org_123",createdAt:"2024-03-15T10:30:00Z",updatedAt:"2024-03-30T14:22:00Z",description:"OpenAI API key for embeddings",masked:!0},{key:"stripe_sk",tenant:e.tenant||"org_123",createdAt:"2024-03-10T08:15:00Z",updatedAt:"2024-03-25T09:45:00Z",description:"Stripe secret key",masked:!0},{key:"github_token",tenant:e.tenant||"org_123",createdAt:"2024-03-20T16:30:00Z",updatedAt:"2024-03-29T11:20:00Z",description:"GitHub API token",masked:!0}];if(e.format==="json")b(t,{format:"json"});else{d("Secrets for tenant: "+(e.tenant||"org_123"),"info");for(let n of t){let r=n.description?` \u2014 ${n.description}`:"";d(`${R.cyan(n.key)}${R.gray(r)}`,"info"),d(` Updated: ${n.updatedAt}`,"info")}}}async function fs(e,t){e||(d("Secret key is required: nebutra secrets set <key>","error"),process.exit(l.INVALID_ARGS));let n;if(t.value)d("WARNING: Using --value flag exposes secret in shell history. Prefer stdin.","warn"),n=t.value;else{d("Enter secret value (will not echo). Press Ctrl+D when done:","info");try{n=await ps()}catch{d("Failed to read secret from stdin","error"),process.exit(l.ERROR)}}if(n||(d("Secret value cannot be empty","error"),process.exit(l.INVALID_ARGS)),d(`Setting secret ${R.cyan(e)}...`,"info"),t.dryRun){d(`Would encrypt and store secret ${e} for tenant ${t.tenant||"org_123"}`,"info");return}d(`Secret ${R.cyan(e)} encrypted and stored successfully`,"success"),t.description&&d(`Description: ${t.description}`,"info")}async function hs(e,t){e||(d("Secret key is required: nebutra secrets get <key>","error"),process.exit(l.INVALID_ARGS)),d(`Retrieving secret ${R.cyan(e)}...`,"info");let r=t.unmask?"sk_live_abc123xyz789...":"***masked***";t.unmask||d(`Secret value is ${R.yellow("masked")}. Use --unmask to display.`,"warn");let o={key:e,tenant:t.tenant||"org_123",value:r,encrypted:!0};t.format==="json"?b(o,{format:"json"}):d(`${R.cyan(e)}: ${r}`,"info")}async function ys(e,t){e||(d("Secret key is required: nebutra secrets rotate <key>","error"),process.exit(l.INVALID_ARGS));let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let r=await yt.confirm({message:`Rotate encryption key for ${R.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});(yt.isCancel(r)||!r)&&(d("Rotation cancelled","warn"),process.exit(l.CANCELLED))}if(!t.yes&&!t.dryRun&&!n&&(d("Key rotation requires --yes confirmation","error"),process.exit(l.INVALID_ARGS)),d(`Rotating encryption key for ${R.cyan(e)}...`,"info"),t.dryRun){d(`Would rotate encryption key for ${e}`,"info");return}d(`Encryption key for ${R.cyan(e)} rotated successfully`,"success"),d(`New key version: ${R.dim("v2")}`,"info")}async function bs(e){d("Fetching audit log...","info");let n=[{timestamp:"2024-03-30T14:52:00Z",action:"read",key:"openai_key",actor:"api_service",success:!0},{timestamp:"2024-03-30T14:22:00Z",action:"write",key:"openai_key",actor:"claude_user",success:!0},{timestamp:"2024-03-30T13:45:00Z",action:"read",key:"stripe_sk",actor:"billing_worker",success:!0},{timestamp:"2024-03-30T11:30:00Z",action:"rotate",key:"github_token",actor:"admin_user",success:!0},{timestamp:"2024-03-30T10:15:00Z",action:"read",key:"unknown_key",actor:"unauthorized_service",success:!1,message:"Key not found"}];if(e.limit&&(n=n.slice(0,e.limit)),e.format==="json")b(n,{format:"json"});else{d("Secret Access Audit Log","info");for(let r of n){let o=r.success?R.green("\u2713"):R.red("\u2716");d(`${o} ${r.timestamp} ${R.cyan(r.action)} ${r.key}`,r.success?"success":"error"),d(` Actor: ${r.actor}${r.message?` \u2014 ${r.message}`:""}`,"info")}}}async function vs(e){d("Verifying vault configuration...","info");let t=[];if(t.push({name:"KMS Connectivity",healthy:!0,message:"Connected to AWS KMS"}),t.push({name:"Master Key",healthy:!0,message:"Master encryption key available"}),t.push({name:"Envelope Encryption",healthy:!0,message:"HKDF envelope encryption configured"}),t.push({name:"Storage Backend",healthy:!0,message:"PostgreSQL backend healthy"}),e.format==="json")b(t,{format:"json"});else{d("Vault Configuration Check","info");for(let r of t){let o=r.healthy?R.green("\u2713"):R.red("\u2716");d(`${o} ${r.name}: ${r.message}`,r.healthy?"success":"error")}let n=t.every(r=>r.healthy);d(`Overall: ${n?R.green("HEALTHY"):R.red("UNHEALTHY")}`,n?"success":"error")}}function Or(e){e.command("secrets <verb> [args...]").description("Manage encrypted secrets via @nebutra/vault (AWS KMS + HKDF envelope encryption)").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations").option("--format <type>","Output format: json, plain, table","plain").option("--tenant <id>","Tenant ID for multi-tenant access").option("--unmask","Unmask secret values (required to view)").option("--description <text>","Description for secret").option("--value <text>","Secret value (prefer stdin for security)").option("--since <date>","Audit log start date (ISO 8601)").option("--limit <n>","Maximum audit log entries (default: 50)").action(async(n,r,o,i)=>{let a=i.optsWithGlobals?.(),s={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:a?.format||o.format,tenant:o.tenant||a?.tenant,unmask:o.unmask||!1,description:o.description,value:o.value,since:o.since,limit:o.limit??50};try{switch(n){case"list":await gs(s);break;case"set":r.length===0&&(d("set requires a secret key: nebutra secrets set <key>","error"),process.exit(l.INVALID_ARGS)),await fs(r[0],s);break;case"get":r.length===0&&(d("get requires a secret key: nebutra secrets get <key>","error"),process.exit(l.INVALID_ARGS)),await hs(r[0],s);break;case"rotate":r.length===0&&(d("rotate requires a secret key: nebutra secrets rotate <key>","error"),process.exit(l.INVALID_ARGS)),await ys(r[0],s);break;case"audit":await bs(s);break;case"verify":await vs(s);break;default:d(`Unknown secrets subcommand: ${n}. Valid commands: list, set, get, rotate, audit, verify`,"error"),process.exit(l.ERROR)}}catch(u){let m=u instanceof Error?u.message:String(u);d(`Secrets command failed: ${m}`,"error"),x("Full error",{error:u}),process.exit(l.ERROR)}}).addHelpText("after",`
|
|
464
465
|
Examples:
|
|
465
466
|
nebutra secrets list List all secrets (metadata only)
|
|
466
467
|
nebutra secrets list --tenant org_456 List secrets for specific tenant
|
|
@@ -495,19 +496,19 @@ Security Notes:
|
|
|
495
496
|
- Never use --value in production (visible in shell history)
|
|
496
497
|
- Always use --unmask when viewing secrets in scripts
|
|
497
498
|
- Audit log tracks all access and modifications
|
|
498
|
-
`)}import
|
|
499
|
+
`)}import{existsSync as ks,readFileSync as ws}from"fs";import{resolve as xs}from"path";import*as bt from"@clack/prompts";import N from"picocolors";function Cs(e){let t=["postgres","redis","clickhouse"],n=xs(e,"docker-compose.yml");if(!ks(n))return t;try{let o=ws(n,"utf-8").split(`
|
|
500
|
+
`),i=o.findIndex(s=>/^services:\s*$/.test(s));if(i===-1)return t;let a=[];for(let s=i+1;s<o.length;s++){let u=o[s];if(/^[a-zA-Z]/.test(u))break;let m=u.match(/^ {2}([a-zA-Z0-9_-]+):\s*$/);m&&a.push(m[1])}return a.length>0?a:t}catch{return t}}function Ar(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function Ss(e){switch(e){case"running":return N.green("\u25CF");case"exited":return N.red("\u25CF");case"restarting":return N.yellow("\u25CF");case"paused":return N.gray("\u25CF");default:return N.gray("\u25CF")}}async function Es(e){d("Checking service status...","info");let t=await E({command:"docker",args:["compose","ps","--format","json"],cwd:y(),interactive:!1,label:"Docker Compose PS",dryRun:e.dryRun});t.exitCode!==0&&(d("Failed to fetch service status","error"),x("Docker error",{stderr:t.stderr}),process.exit(l.ERROR));try{let n=JSON.parse(t.stdout);if(e.format==="json"){let r=n.map(o=>({name:o.Name,status:Ar(o.State),exitCode:o.ExitCode}));b(r,{format:"json"})}else{d("Service Status","info");let r=n.map(o=>({Service:Ss(Ar(o.State))+" "+o.Name,Status:o.State,"Exit Code":o.ExitCode||"\u2014"}));for(let o of r)d(`${o.Service} (${o.Status})`,"info")}}catch(n){d("Failed to parse service status","error"),x("Parse error",{error:String(n)}),process.exit(l.ERROR)}}async function Rs(e,t){d(`Streaming logs for ${N.cyan(e)}...`,"info");let n=["compose","logs"];t.tail?n.push("--tail",String(t.tail)):n.push("--tail","100"),t.since&&n.push("--since",t.since),n.push("-f",e),(await E({command:"docker",args:n,cwd:y(),interactive:!0,label:`Docker Compose Logs (${e})`,dryRun:t.dryRun})).exitCode!==0&&(d(`Failed to stream logs for ${e}`,"error"),process.exit(l.ERROR))}async function Os(e,t){let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let i=await bt.confirm({message:`Restart service ${N.cyan(e)}?`,initialValue:!1});(bt.isCancel(i)||!i)&&(d("Restart cancelled","warn"),process.exit(l.CANCELLED))}d(`Restarting service ${N.cyan(e)}...`,"info");let r=["compose","restart"];t.timeout&&r.push("--timeout",String(t.timeout)),r.push(e);let o=await E({command:"docker",args:r,cwd:y(),interactive:!1,label:`Docker Compose Restart (${e})`,dryRun:t.dryRun});o.exitCode===0?d(`Service ${N.cyan(e)} restarted successfully`,"success"):(d(`Failed to restart service ${e}`,"error"),x("Docker error",{stderr:o.stderr}),process.exit(l.ERROR))}async function As(e){d("Running deep health check...","info");let t=[],n=1e4,r=await E({command:"docker",args:["compose","exec","-T","postgres","pg_isready"],cwd:y(),interactive:!1,label:"PostgreSQL Health",dryRun:e.dryRun,timeoutMs:n});t.push({service:"PostgreSQL",healthy:r.exitCode===0,message:r.timedOut?"Timed out":r.exitCode===0?"Ready":"Not responding"});let o=await E({command:"docker",args:["compose","exec","-T","redis","redis-cli","ping"],cwd:y(),interactive:!1,label:"Redis Health",dryRun:e.dryRun,timeoutMs:n});t.push({service:"Redis",healthy:o.exitCode===0,message:o.timedOut?"Timed out":o.exitCode===0?"Ready":"Not responding"});let i=await E({command:"docker",args:["compose","exec","-T","clickhouse","curl","-s","http://localhost:8123/ping"],cwd:y(),interactive:!1,label:"ClickHouse Health",dryRun:e.dryRun,timeoutMs:n});if(t.push({service:"ClickHouse",healthy:i.exitCode===0,message:i.timedOut?"Timed out":i.exitCode===0?"Ready":"Not responding"}),e.format==="json")b(t,{format:"json"});else{for(let s of t){let u=s.healthy?N.green("\u2713"):N.red("\u2716");d(`${u} ${s.service}: ${s.message}`,s.healthy?"success":"error")}let a=t.every(s=>s.healthy);d(`Overall health: ${a?N.green("HEALTHY"):N.red("UNHEALTHY")}`,a?"success":"error")}}async function _s(e,t,n){let r=parseInt(t,10);(Number.isNaN(r)||r<0)&&(d("Invalid replica count (must be a non-negative number)","error"),process.exit(l.INVALID_ARGS)),d(`Scaling ${N.cyan(e)} to ${N.cyan(String(r))} replicas...`,"info");let o=await E({command:"docker",args:["compose","up","-d","--scale",`${e}=${r}`],cwd:y(),interactive:!1,label:`Docker Compose Scale (${e})`,dryRun:n.dryRun});o.exitCode===0?d(`Service ${N.cyan(e)} scaled to ${r} replicas`,"success"):(d(`Failed to scale service ${e}`,"error"),x("Docker error",{stderr:o.stderr}),process.exit(l.ERROR))}function _r(e){e.command("services <verb> [args...]").description("Manage Docker Compose microservices (see `nebutra services --help` for the list)").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations").option("--format <type>","Output format: json, plain, table","plain").option("--tail <n>","Number of log lines to show (default: 100)").option("--since <duration>","Show logs since duration (e.g., 10m, 1h)").option("--timeout <seconds>","Timeout for service restart").action(async(n,r,o,i)=>{let a=i.optsWithGlobals?.(),s={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:a?.format||o.format,tail:o.tail??100,since:o.since,timeout:o.timeout};try{switch(n){case"status":case"list":await Es(s);break;case"logs":r.length===0&&(d("logs requires a service name: nebutra services logs <service>","error"),process.exit(l.INVALID_ARGS)),await Rs(r[0],s);break;case"restart":r.length===0&&(d("restart requires a service name: nebutra services restart <service>","error"),process.exit(l.INVALID_ARGS)),await Os(r[0],s);break;case"health":await As(s);break;case"scale":r.length<2&&(d("scale requires a service name and replica count: nebutra services scale <service> <count>","error"),process.exit(l.INVALID_ARGS)),await _s(r[0],r[1],s);break;default:d(`Unknown services subcommand: ${n}. Valid commands: status, list, logs, restart, health, scale`,"error"),process.exit(l.ERROR)}}catch(u){let m=u instanceof Error?u.message:String(u);d(`Services command failed: ${m}`,"error"),x("Full error",{error:u}),process.exit(l.ERROR)}}).addHelpText("after",()=>{let n="postgres, redis, clickhouse (run `nebutra services status` for the live list)";try{n=Cs(dn()).join(", ")}catch{}return`
|
|
499
501
|
Examples:
|
|
500
502
|
nebutra services status Show all service status
|
|
503
|
+
nebutra services list Alias for \`status\`
|
|
501
504
|
nebutra services logs postgres Stream postgres logs
|
|
502
505
|
nebutra services logs postgres --tail 50 Show last 50 postgres logs
|
|
503
506
|
nebutra services restart redis Restart redis service
|
|
504
|
-
nebutra services health Deep health check (
|
|
507
|
+
nebutra services health Deep health check (postgres, redis, clickhouse)
|
|
505
508
|
nebutra services scale ai-service 3 Scale ai-service to 3 replicas
|
|
506
509
|
|
|
507
|
-
Services Available:
|
|
508
|
-
|
|
509
|
-
recsys-service, ecommerce-service, web3-service, billing-service, event-ingest, idp,
|
|
510
|
-
jaeger, nginx
|
|
510
|
+
Services Available (from docker-compose.yml):
|
|
511
|
+
${n}
|
|
511
512
|
|
|
512
513
|
Flags:
|
|
513
514
|
--dry-run Show what would be run without executing
|
|
@@ -516,28 +517,26 @@ Flags:
|
|
|
516
517
|
--tail <n> Log lines to show (default: 100)
|
|
517
518
|
--since <duration> Show logs since (e.g., 10m, 1h)
|
|
518
519
|
--timeout <seconds> Timeout for restart
|
|
519
|
-
`)}import{join as
|
|
520
|
-
`)}function
|
|
521
|
-
`)
|
|
522
|
-
`))
|
|
523
|
-
`);function Xa(e){let t=new Set;for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.startsWith("export ")?r.slice(7):r,i=o.indexOf("=");if(i===-1)continue;let a=o.slice(0,i).trim();a&&t.add(a)}return t}function Qa(e,t){let n=Xa(e),r=[],o=[],i=[];for(let m of t){let p=Ae[m];if(p)for(let g of p.providers){if(g.envKeys.length===0)continue;let y=[];for(let f of g.envKeys)n.has(f)?o.push(f):y.push(f);if(y.length!==0){i.push([`# ${m} (${g.id})`,...y.map(f=>`${f}=`)].join(`
|
|
524
|
-
`));for(let f of y)n.add(f),r.push(f)}}}if(i.length===0)return{content:e,added:r,unchanged:o};let a=e.replace(/\s+$/,"");return{content:`${a.length>0?`${a}
|
|
520
|
+
`})}import{join as Fs}from"path";import xe from"picocolors";import{existsSync as Ir,readFileSync as Pr}from"fs";import{dirname as Ns,join as Nr,parse as $s}from"path";var K=class extends Error{code;exitCode;suggestion;retryable;context;cause;constructor(t){super(t.message),this.name="CommandError",this.code=t.code,this.exitCode=t.exitCode??l.ERROR,this.suggestion=t.suggestion,this.retryable=t.retryable??!1,this.context=t.context,this.cause=t.cause}};function Is(e){return e instanceof K}function Ps(e){return Is(e)?Ye({error:e.code,message:e.message,suggestion:e.suggestion,retryable:e.retryable,exitCode:e.exitCode,context:e.context,cause:e.cause instanceof Error?e.cause:e}):e instanceof Error?Ye({error:"unexpected_error",message:e.message,suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:l.ERROR,cause:e}):Ye({error:"unexpected_error",message:String(e),suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:l.ERROR})}function Jt(e){let t=Ps(e);return un(t),t.exitCode}async function we(e){try{await e()}catch(t){process.exitCode=Jt(t)}}var $e={auth:{providers:[{id:"better-auth",envKeys:["BETTER_AUTH_SECRET"]}],degrade:{kind:"fallback",provider:"dev"},next:"set BETTER_AUTH_SECRET to run Better Auth (dev fallback runs without it)"},billing:{providers:[{id:"creem",envKeys:["CREEM_API_KEY","CREEM_PRODUCT_ID"]},{id:"wechat-pay",envKeys:["WECHATPAY_MCHID","WECHATPAY_APP_ID","WECHATPAY_PRIVATE_KEY","WECHATPAY_SERIAL_NO","WECHATPAY_API_V3_KEY"]},{id:"alipay",envKeys:["ALIPAY_APP_ID","ALIPAY_PRIVATE_KEY","ALIPAY_PUBLIC_KEY"]}],degrade:{kind:"missing-key"},next:"set CREEM_API_KEY/CREEM_PRODUCT_ID (or WECHATPAY_* / ALIPAY_* for mainland China)"},email:{providers:[{id:"resend",envKeys:["RESEND_API_KEY"]}],degrade:{kind:"fallback",provider:"console"},next:"set RESEND_API_KEY to send real email (console fallback logs instead)"},sms:{providers:[{id:"twilio-verify",envKeys:["TWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN","TWILIO_VERIFY_SERVICE_SID"]},{id:"aliyun",envKeys:["ALIYUN_SMS_ACCESS_KEY_ID","ALIYUN_SMS_ACCESS_KEY_SECRET"]}],degrade:{kind:"missing-key"},next:"set TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN/TWILIO_VERIFY_SERVICE_SID (or ALIYUN_SMS_* for mainland China)"},storage:{providers:[{id:"s3-compatible",envKeys:["S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY","S3_ENDPOINT"]}],degrade:{kind:"fallback",provider:"local"},next:"set S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEY/S3_ENDPOINT (or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY) for S3/R2 storage"},queue:{providers:[{id:"qstash",envKeys:["QSTASH_TOKEN"]}],degrade:{kind:"fallback",provider:"memory"},next:"set QSTASH_TOKEN to run the QStash queue (memory fallback is dev/test only)"},cache:{providers:[{id:"redis",envKeys:["UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"]}],degrade:{kind:"fallback",provider:"memory"},next:"set UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN to run Redis (memory fallback is dev/test only)"},notifications:{providers:[{id:"direct",envKeys:[]}],degrade:{kind:"missing-key"},next:"always live \u2014 no configuration required"},webhooks:{providers:[{id:"custom",envKeys:[]}],degrade:{kind:"missing-key"},next:"always live \u2014 no configuration required"},ai:{providers:[{id:"openai",envKeys:["OPENAI_API_KEY"]},{id:"anthropic",envKeys:["ANTHROPIC_API_KEY"]},{id:"deepseek",envKeys:["DEEPSEEK_API_KEY"]},{id:"bailian",envKeys:["DASHSCOPE_API_KEY"]}],degrade:{kind:"missing-key"},next:"set one of OPENAI_API_KEY / ANTHROPIC_API_KEY / DEEPSEEK_API_KEY / DASHSCOPE_API_KEY"},mcp:{providers:[{id:"built-in",envKeys:[]}],degrade:{kind:"missing-key"},next:"always live \u2014 no configuration required"},monitoring:{providers:[{id:"sentry",envKeys:["SENTRY_DSN"]}],degrade:{kind:"missing-key"},next:"set SENTRY_DSN to enable error monitoring"},analytics:{providers:[{id:"posthog",envKeys:["NEXT_PUBLIC_POSTHOG_KEY"]}],degrade:{kind:"missing-key"},next:"set NEXT_PUBLIC_POSTHOG_KEY to enable analytics"},captcha:{providers:[{id:"turnstile",envKeys:["TURNSTILE_SECRET_KEY"]}],degrade:{kind:"missing-key"},next:"set TURNSTILE_SECRET_KEY to enable captcha"}};function vt(e){let t=e,{root:n}=$s(t);for(;;){if(Ir(Nr(t,"nebutra.config.json")))return t;if(t===n)return null;let r=Ns(t);if(r===t)return null;t=r}}function kt(e){let t=Pr(e,"utf-8"),n=JSON.parse(t);if(!n||typeof n!="object"||Array.isArray(n))throw new K({code:"invalid_manifest",message:`nebutra.config.json at ${e} is not a JSON object.`,suggestion:"Re-run `create-sailor` or fix the file by hand.",exitCode:l.CONFIG_ERROR});return n}function js(e){let t={};for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.startsWith("export ")?r.slice(7):r,i=o.indexOf("=");if(i===-1)continue;let a=o.slice(0,i).trim();if(!a)continue;let s=o.slice(i+1).trim();(s.startsWith('"')&&s.endsWith('"')&&s.length>=2||s.startsWith("'")&&s.endsWith("'")&&s.length>=2)&&(s=s.slice(1,-1)),t[a]=s}return t}function $r(e){let t={...process.env};for(let n of[".env",".env.local"]){let r=Nr(e,n);if(Ir(r))try{let o=js(Pr(r,"utf-8"));for(let[i,a]of Object.entries(o))process.env[i]===void 0&&(t[i]=a)}catch{}}return t}function jr(e,t,n){let r=[],o=[];for(let i of t.providers){let a=i.envKeys.filter(s=>!n[s]);a.length===0?r.push(i.id):o.length===0&&i.envKeys.length>0&&(o=a)}return r.length>0?{name:e,state:"live",provider:r,missing:[],next:t.next}:t.degrade.kind==="fallback"?{name:e,state:"local-fallback",provider:[t.degrade.provider],missing:o,next:t.next}:{name:e,state:"missing-key",provider:[],missing:o,next:t.next}}function Fr(e){let t=Object.keys($e),n=e.filter(a=>!$e[a]);if(n.length>0)throw new K({code:"unknown_capability",message:`Unknown capabilit${n.length===1?"y":"ies"} in nebutra.config.json: ${n.join(", ")}.`,suggestion:`Valid capabilities: ${t.join(", ")}.`,exitCode:l.CONFIG_ERROR,context:{unknown:n,valid:t}});let r=new Set,o=[],i=[];for(let a of e){if(r.has(a)){o.push(`duplicate capability "${a}" in nebutra.config.json \u2014 ignoring repeat`);continue}r.add(a),i.push(a)}return{capabilities:i,warnings:o}}function Ds(e,t){switch(e){case"live":return xe.green(t);case"local-fallback":return xe.yellow(t);case"missing-key":return xe.red(t);default:return t}}async function Ts(e){let t=vt(process.cwd());if(!t)throw new K({code:"manifest_not_found",message:"No nebutra.config.json found in this directory or any parent directory.",suggestion:"Run `npx create-sailor` to scaffold a Sailor project first.",exitCode:l.CONFIG_ERROR});let n=Fs(t,"nebutra.config.json"),r=kt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],i=$r(t),a=i.NEBUTRA_LOCALE||"global",s=typeof r.stack=="string"?r.stack:"unknown",u=o.map(g=>{let k=$e[g];return k?jr(g,k,i):{name:g,state:"missing-key",provider:[],missing:[],next:"unknown capability \u2014 no readiness rule registered in `nebutra status`"}});if(e.json===!0||e.format==="json"){b({stack:s,locale:a,capabilities:u},{format:"json"});return}let p=[];p.push(xe.bold("nebutra status")),p.push(xe.dim(`stack: ${s} locale: ${a} project: ${t}`)),p.push("");let f=Math.max(10,...u.map(g=>g.name.length)),h=Math.max(14,...u.map(g=>g.state.length));for(let g of u){let k=g.name.padEnd(f),F=Ds(g.state,g.state.padEnd(h)),w=g.provider.length>0?g.provider.join(", "):"-";p.push(`${k} ${F} ${xe.dim(w)}`),g.state!=="live"&&p.push(`${" ".repeat(f)} ${xe.dim(`\u2192 ${g.next}`)}`)}console.log(p.join(`
|
|
521
|
+
`))}function Dr(e){e.command("status").description("Show capability readiness \u2014 live, local-fallback, or missing-key, per env").option("--json","Emit machine-readable JSON").action((t,n)=>we(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await Ts({json:t.json,format:r.format})}))}import{existsSync as Tr,readFileSync as Ls,writeFileSync as Lr}from"fs";import{join as qt}from"path";import ze from"picocolors";var Ur=".env.example",Br=".env.local",Us=["# Local secrets for this machine \u2014 never commit real values.","# `nebutra sync` created this file; add your own keys below.",""].join(`
|
|
522
|
+
`);function Bs(e){let t=new Set;for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.startsWith("export ")?r.slice(7):r,i=o.indexOf("=");if(i===-1)continue;let a=o.slice(0,i).trim();a&&t.add(a)}return t}function Ms(e,t){let n=Bs(e),r=[],o=[],i=[];for(let m of t){let p=$e[m];if(p)for(let f of p.providers){if(f.envKeys.length===0)continue;let h=[];for(let g of f.envKeys)n.has(g)?o.push(g):h.push(g);if(h.length!==0){i.push([`# ${m} (${f.id})`,...h.map(g=>`${g}=`)].join(`
|
|
523
|
+
`));for(let g of h)n.add(g),r.push(g)}}}if(i.length===0)return{content:e,added:r,unchanged:o};let a=e.replace(/\s+$/,"");return{content:`${a.length>0?`${a}
|
|
525
524
|
|
|
526
525
|
`:""}${i.join(`
|
|
527
526
|
|
|
528
527
|
`)}
|
|
529
|
-
`,added:r,unchanged:o}}async function
|
|
530
|
-
`))}for(let w of a)
|
|
531
|
-
${n}`)}return t}async function ns(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test",options:{app:e.app,watch:e.watch,coverage:e.coverage},task:e.coverage?"pnpm test:coverage":e.watch?"pnpm test:watch":"pnpm test"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&(e.watch||e.coverage)&&(j.log.error(k.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(c.INVALID_ARGS)),e.app){ts(e.app);let r=`@nebutra/${e.app}`;e.quiet||j.log.info(k.cyan(`Running tests for ${k.bold(r)}...`));let o=await ne("test",{filter:r});process.exit(o.exitCode)}let t="test";if(e.coverage?t="test:coverage":e.watch&&(t="test:watch"),!e.quiet){let r=t==="test:coverage"?"Running tests with coverage...":t==="test:watch"?"Running tests in watch mode...":"Running tests...";j.log.info(k.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Cr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test e2e",options:{ui:e.ui,ci:e.ci},task:e.ci?"pnpm e2e:ci":e.ui?"pnpm e2e:ui":"pnpm e2e"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{e.ui&&e.ci&&(j.log.error(k.red("Cannot use --ui and --ci together")),process.exit(c.INVALID_ARGS));let t="e2e";if(e.ci?t="e2e:ci":e.ui&&(t="e2e:ui"),!e.quiet){let r=t==="e2e:ci"?"Running E2E tests (CI mode)...":t==="e2e:ui"?"Opening E2E tests in UI mode...":"Running E2E tests...";j.log.info(k.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Sr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{let t=e.why?"size:why":"size";if(!e.quiet){let r=e.why?"Analyzing bundle size (showing largest assets)...":"Checking bundle size...";j.log.info(k.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}async function xr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{e.quiet||j.log.info(k.cyan("Running architecture tests..."));let t=await $("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}var Er=e=>{let t=e.command("test [subcommand]").description("Run tests (Vitest, Playwright, bundle size, architecture)").option("--watch","Run tests in watch mode (unit tests only)").option("--coverage","Generate coverage report (unit tests only)").option("--app <name>",`Run tests for specific app: ${Ut.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r,o)=>{let i=A(r,o),a={dryRun:!!r.dryRun,quiet:!!i.quiet,verbose:!!i.verbose,format:ce(i.format)};n==="e2e"?await Cr({...a,ui:!!r.ui,ci:!!r.ci}):n==="size"?await Sr({...a,why:!!r.why}):n==="arch"?await xr(a):await ns({...a,watch:!!r.watch,coverage:!!r.coverage,app:typeof r.app=="string"?r.app:void 0})});t.command("e2e").description("Run end-to-end tests (Playwright)").option("--ui","Open interactive UI mode").option("--ci","Run in CI mode with strict options").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await Cr({ui:!!n.ui,ci:!!n.ci,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})}),t.command("size").description("Check bundle size (analyze largest assets)").option("--why","Show breakdown of largest bundle assets").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await Sr({why:!!n.why,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})}),t.command("arch").description("Run architecture tests (verify design layer isolation)").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await xr({dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})})};var rs={$schema:"https://nebutra.com/schemas/design-language-registry.json",version:"2026.07",defaultLanguage:"factory",description:"Design-language catalog for global product chrome swap (Create Center / SaaS theme). Not color moods \u2014 full Brand Packages (roles + recipe + elev + zones).",languages:[{id:"factory",name:"Nebutra Factory",kind:"design-language",description:"Default product chrome from @nebutra/tokens (no skin). Clear data-brand to restore.",tagline:"the token source, unskinned",shortName:"Factory",proves:["factory HSL SSOT","recipe defaults","action\u2261brand-mark until skin"],darkDefault:!0,brandPath:null,skinPath:null,install:{command:"nebutra theme use factory",cssImport:null},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"cosmos",name:"Cosmos",kind:"design-language",description:"Linen gallery canvas with a monochrome chrome: the filled Ink button and the brand mark are the same colour, there is no accent role at all. One 16px radius everywhere, zero elevation, serif display at weight 350.",tagline:"images sit; chrome recedes",shortName:"Cosmos",proves:["monochrome chrome (action \u2261 brand-mark, no accent role)","single-radius system (16px everywhere; 9999px only for the floating nav)","elevation=none by contract (flat surfaces, contrast-only depth)","serif display below weight 400 (headingWeight 350)","light-first dual mode (dark inverts the gallery)"],darkDefault:!1,brandPath:"brands/cosmos/brand.json",skinPath:"skins/cosmos.css",install:{command:"nebutra theme use cosmos",cssImport:"@nebutra/tokens/skins/cosmos.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"gsap",name:"GSAP",kind:"design-language",description:"Dark cream-on-void; shockingly-green is accent \u2014 CTA is gradient-stroke/outline, not solid green fill.",tagline:"saturated, fast easing",shortName:"GSAP",proves:["outline / gradient-stroke recipe","category extensions","marketing display zone"],darkDefault:!0,brandPath:"brands/gsap/brand.json",skinPath:"skins/gsap.css",install:{command:"nebutra theme use gsap",cssImport:"@nebutra/tokens/skins/gsap.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"linear",name:"Linear",kind:"design-language",description:"Dual-mode: dark void default + light paper; solid acid-lime CTA, compact density.",tagline:"tight radii, low-contrast chrome",shortName:"Linear",proves:["chromatic solid action","dark product chrome","dual-mode light/dark palettes"],darkDefault:!0,brandPath:"brands/linear/brand.json",skinPath:"skins/linear.css",install:{command:"nebutra theme use linear",cssImport:"@nebutra/tokens/skins/linear.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"notion",name:"Notion",kind:"design-language",description:"Warm paper notebook; Notion Blue sole filled CTA \u2260 Ink brand-mark; 8px buttons / 12px cards; elev=none + hairline; accent hues decorative only.",tagline:"paper surfaces, muted ink",shortName:"Notion",proves:["action \u2260 brand-mark (blue vs ink)","canvas\u2260card (paper-warmth vs pure-white)","elevation=none content cards + raised nav shadow slot","table radius priority (8/12 over tertiary 4px)","decorative accents never product CTA"],darkDefault:!1,brandPath:"brands/notion/brand.json",skinPath:"skins/notion.css",install:{command:"nebutra theme use notion",cssImport:"@nebutra/tokens/skins/notion.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"raycast",name:"Raycast",kind:"design-language",description:"Neutral Mist/Iron filled CTA; Coral is brand-mark only. Key elevation stack.",tagline:"dark glass and a coloured halo",shortName:"Raycast",proves:["action \u2260 brand-mark","elevation=key free CSS"],darkDefault:!0,brandPath:"brands/raycast/brand.json",skinPath:"skins/raycast.css",install:{command:"nebutra theme use raycast",cssImport:"@nebutra/tokens/skins/raycast.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"stripe",name:"Stripe",kind:"design-language",description:"Indigo-ink ledger on frost glass; Indigo action \u2260 Midnight brand-mark; 4px controls; elevation=none (tint + frost rules).",tagline:"soft elevation, generous type",shortName:"Stripe",proves:["action \u2260 brand-mark (chromatic indigo vs midnight)","elevation=none tint-ladder depth","4px squared controls (not pill)","whisper heading weight 300"],darkDefault:!1,brandPath:"brands/stripe/brand.json",skinPath:"skins/stripe.css",install:{command:"nebutra theme use stripe",cssImport:"@nebutra/tokens/skins/stripe.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"vanta",name:"Vanta",kind:"design-language",description:"Editorial violet on parchment; Vivid Violet action \u2260 Indigo Ink brand-mark; full pills; elevation=none (carbon hairlines).",tagline:"high-trust enterprise blues",shortName:"Vanta",proves:["action \u2260 brand-mark (chromatic)","elevation=none border-only","999px pill controls","serif display + sans UI zones"],darkDefault:!1,brandPath:"brands/vanta/brand.json",skinPath:"skins/vanta.css",install:{command:"nebutra theme use vanta",cssImport:"@nebutra/tokens/skins/vanta.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"vercel",name:"Vercel",kind:"design-language",description:"Monochrome dual-mode: light paper + Obsidian CTA; dark carbon + white CTA; hairline elevation (no chromatic CTA).",tagline:"monochrome, hard edges, lit top edge",shortName:"Vercel",proves:["light monochrome action","elevation=hairline","dual-mode light/dark palettes"],darkDefault:!1,brandPath:"brands/vercel/brand.json",skinPath:"skins/vercel.css",install:{command:"nebutra theme use vercel",cssImport:"@nebutra/tokens/skins/vercel.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}}]},le=rs,os=le.languages.map(e=>e.id),Bt=le.defaultLanguage;function Mt(e){return le.languages.find(t=>t.id===e)}function Rr(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??is()}function is(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function as(e="table"){let t=le.languages;return e==="json"?JSON.stringify({version:le.version,defaultLanguage:le.defaultLanguage,count:t.length,languages:t},null,2):[`Nebutra design languages (${t.length}) \u2014 global product chrome swap`,`Default: ${Bt} (factory tokens; no skin)`,"Contract: roles.action \u2192 CTA; roles.brand \u2192 brand-mark; free elev/radii/zones","",...t.map(r=>`${r.id.padEnd(10)} ${r.darkDefault?"dark ":"light"} ${(r.proves[0]??"").slice(0,48)} ${r.description.slice(0,56)}`)].join(`
|
|
532
|
-
`)}function
|
|
533
|
-
`)}function
|
|
534
|
-
`)}return JSON.stringify(e,null,2)}function
|
|
535
|
-
`):JSON.stringify(e,null,2)}function
|
|
528
|
+
`,added:r,unchanged:o}}async function Gs(e){let t=vt(process.cwd());if(!t)throw new K({code:"manifest_not_found",message:"No nebutra.config.json found in this directory or any parent directory.",suggestion:"Run `npx create-sailor` to scaffold a Sailor project first.",exitCode:l.CONFIG_ERROR});let n=qt(t,"nebutra.config.json"),r=kt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],{capabilities:i,warnings:a}=Fr(o),s=qt(t,Ur),u=Tr(s),m=u?Ls(s,"utf-8"):"",p=Ms(m,i),f=qt(t,Br),h=Tr(f),g={};p.added.length>0&&(g[Ur]=p.added),h||(g[Br]=[]);let k={added:g,unchanged:p.unchanged,warnings:a},F=e.json===!0||e.format==="json";if(e.dryRun){I({mode:"dry-run",command:"sync",projectRoot:t,...k},{format:F?"json":e.format});for(let w of a)d(w,"warn");process.exit(l.DRY_RUN_OK)}if((p.added.length>0||!u)&&Lr(s,p.content),h||Lr(f,Us),F)b(k,{format:"json"});else{let w=[];w.push(ze.bold("nebutra sync")),w.push(ze.dim(`project: ${t}`)),w.push("");let W=Object.keys(g);if(W.length===0)w.push(ze.dim("Env files already match declared capabilities. Nothing to do."));else for(let X of W){let L=g[X]??[];L.length>0?w.push(`${ze.green("+")} ${X}: added ${L.join(", ")}`):w.push(`${ze.green("+")} ${X}: created`)}console.log(w.join(`
|
|
529
|
+
`))}for(let w of a)d(w,"warn");d("Run `nebutra status` to check capability readiness.")}function Mr(e){e.command("sync").description("Make .env.example / .env.local agree with the declared capabilities (idempotent)").option("--dry-run","Preview planned additions without writing files (exits with code 10)").option("--json","Emit machine-readable JSON").action((t,n)=>we(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await Gs({dryRun:t.dryRun,json:t.json,format:r.format})}))}import*as $ from"@clack/prompts";import O from"picocolors";function de(e){if(e==="json"||e==="plain"||e==="table")return e}var Ht=["landing","web","storybook","backends/gateway","design-docs","studio","docs","ui","tokens","brand","theme","icons","preset","queue","search","notifications","permissions","webhooks","metering","uploads","vault","tenant"];function Vs(e){let t=`@nebutra/${e}`;if(!Ht.includes(e)){let n=O.yellow(`Valid apps: ${Ht.join(", ")}`);throw new Error(`Invalid app: ${O.red(e)}
|
|
530
|
+
${n}`)}return t}async function zs(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test",options:{app:e.app,watch:e.watch,coverage:e.coverage},task:e.coverage?"pnpm test:coverage":e.watch?"pnpm test:watch":"pnpm test"},{format:de(e.format)}),process.exit(l.DRY_RUN_OK));try{if(e.app&&(e.watch||e.coverage)&&($.log.error(O.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(l.INVALID_ARGS)),e.app){Vs(e.app);let r=`@nebutra/${e.app}`;e.quiet||$.log.info(O.cyan(`Running tests for ${O.bold(r)}...`));let o=await ae("test",{filter:r});process.exit(o.exitCode)}let t="test";if(e.coverage?t="test:coverage":e.watch&&(t="test:watch"),!e.quiet){let r=t==="test:coverage"?"Running tests with coverage...":t==="test:watch"?"Running tests in watch mode...":"Running tests...";$.log.info(O.cyan(r))}let n=await j(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?$.log.error(O.red(t.message)):$.log.error(O.red("Unknown error occurred")),process.exit(l.ERROR)}}async function Gr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test e2e",options:{ui:e.ui,ci:e.ci},task:e.ci?"pnpm e2e:ci":e.ui?"pnpm e2e:ui":"pnpm e2e"},{format:de(e.format)}),process.exit(l.DRY_RUN_OK));try{e.ui&&e.ci&&($.log.error(O.red("Cannot use --ui and --ci together")),process.exit(l.INVALID_ARGS));let t="e2e";if(e.ci?t="e2e:ci":e.ui&&(t="e2e:ui"),!e.quiet){let r=t==="e2e:ci"?"Running E2E tests (CI mode)...":t==="e2e:ui"?"Opening E2E tests in UI mode...":"Running E2E tests...";$.log.info(O.cyan(r))}let n=await j(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?$.log.error(O.red(t.message)):$.log.error(O.red("Unknown error occurred")),process.exit(l.ERROR)}}async function Vr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"},{format:de(e.format)}),process.exit(l.DRY_RUN_OK));try{let t=e.why?"size:why":"size";if(!e.quiet){let r=e.why?"Analyzing bundle size (showing largest assets)...":"Checking bundle size...";$.log.info(O.cyan(r))}let n=await j(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?$.log.error(O.red(t.message)):$.log.error(O.red("Unknown error occurred")),process.exit(l.ERROR)}}async function zr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"},{format:de(e.format)}),process.exit(l.DRY_RUN_OK));try{e.quiet||$.log.info(O.cyan("Running architecture tests..."));let t=await j("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?$.log.error(O.red(t.message)):$.log.error(O.red("Unknown error occurred")),process.exit(l.ERROR)}}var Kr=e=>{let t=e.command("test [subcommand]").description("Run tests (Vitest, Playwright, bundle size, architecture)").option("--watch","Run tests in watch mode (unit tests only)").option("--coverage","Generate coverage report (unit tests only)").option("--app <name>",`Run tests for specific app: ${Ht.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r,o)=>{let i=A(r,o),a={dryRun:!!r.dryRun,quiet:!!i.quiet,verbose:!!i.verbose,format:de(i.format)};n==="e2e"?await Gr({...a,ui:!!r.ui,ci:!!r.ci}):n==="size"?await Vr({...a,why:!!r.why}):n==="arch"?await zr(a):await zs({...a,watch:!!r.watch,coverage:!!r.coverage,app:typeof r.app=="string"?r.app:void 0})});t.command("e2e").description("Run end-to-end tests (Playwright)").option("--ui","Open interactive UI mode").option("--ci","Run in CI mode with strict options").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await Gr({ui:!!n.ui,ci:!!n.ci,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:de(o.format)})}),t.command("size").description("Check bundle size (analyze largest assets)").option("--why","Show breakdown of largest bundle assets").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await Vr({why:!!n.why,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:de(o.format)})}),t.command("arch").description("Run architecture tests (verify design layer isolation)").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await zr({dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:de(o.format)})})};var Ks={$schema:"https://nebutra.com/schemas/design-language-registry.json",version:"2026.07",defaultLanguage:"factory",description:"Design-language catalog for global product chrome swap (Create Center / SaaS theme). Not color moods \u2014 full Brand Packages (roles + recipe + elev + zones).",languages:[{id:"factory",name:"Nebutra Factory",kind:"design-language",description:"Default product chrome from @nebutra/tokens (no skin). Clear data-brand to restore.",tagline:"the token source, unskinned",shortName:"Factory",proves:["factory HSL SSOT","recipe defaults","action\u2261brand-mark until skin"],darkDefault:!0,brandPath:null,skinPath:null,install:{command:"nebutra apply --preset factory",cssImport:null},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"cosmos",name:"Cosmos",kind:"design-language",description:"Linen gallery canvas with a monochrome chrome: the filled Ink button and the brand mark are the same colour, there is no accent role at all. One 16px radius everywhere, zero elevation, serif display at weight 350.",tagline:"images sit; chrome recedes",shortName:"Cosmos",proves:["monochrome chrome (action \u2261 brand-mark, no accent role)","single-radius system (16px everywhere; 9999px only for the floating nav)","elevation=none by contract (flat surfaces, contrast-only depth)","serif display below weight 400 (headingWeight 350)","light-first dual mode (dark inverts the gallery)"],darkDefault:!1,brandPath:"brands/cosmos/brand.json",skinPath:"skins/cosmos.css",install:{command:"nebutra apply --preset cosmos",cssImport:"@nebutra/tokens/skins/cosmos.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"gsap",name:"GSAP",kind:"design-language",description:"Dark cream-on-void; shockingly-green is accent \u2014 CTA is gradient-stroke/outline, not solid green fill.",tagline:"saturated, fast easing",shortName:"GSAP",proves:["outline / gradient-stroke recipe","category extensions","marketing display zone"],darkDefault:!0,brandPath:"brands/gsap/brand.json",skinPath:"skins/gsap.css",install:{command:"nebutra apply --preset gsap",cssImport:"@nebutra/tokens/skins/gsap.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"linear",name:"Linear",kind:"design-language",description:"Dual-mode: dark void default + light paper; solid acid-lime CTA, compact density.",tagline:"tight radii, low-contrast chrome",shortName:"Linear",proves:["chromatic solid action","dark product chrome","dual-mode light/dark palettes"],darkDefault:!0,brandPath:"brands/linear/brand.json",skinPath:"skins/linear.css",install:{command:"nebutra apply --preset linear",cssImport:"@nebutra/tokens/skins/linear.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"notion",name:"Notion",kind:"design-language",description:"Warm paper notebook; Notion Blue sole filled CTA \u2260 Ink brand-mark; 8px buttons / 12px cards; elev=none + hairline; accent hues decorative only.",tagline:"paper surfaces, muted ink",shortName:"Notion",proves:["action \u2260 brand-mark (blue vs ink)","canvas\u2260card (paper-warmth vs pure-white)","elevation=none content cards + raised nav shadow slot","table radius priority (8/12 over tertiary 4px)","decorative accents never product CTA"],darkDefault:!1,brandPath:"brands/notion/brand.json",skinPath:"skins/notion.css",install:{command:"nebutra apply --preset notion",cssImport:"@nebutra/tokens/skins/notion.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"raycast",name:"Raycast",kind:"design-language",description:"Neutral Mist/Iron filled CTA; Coral is brand-mark only. Key elevation stack.",tagline:"dark glass and a coloured halo",shortName:"Raycast",proves:["action \u2260 brand-mark","elevation=key free CSS"],darkDefault:!0,brandPath:"brands/raycast/brand.json",skinPath:"skins/raycast.css",install:{command:"nebutra apply --preset raycast",cssImport:"@nebutra/tokens/skins/raycast.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"stripe",name:"Stripe",kind:"design-language",description:"Indigo-ink ledger on frost glass; Indigo action \u2260 Midnight brand-mark; 4px controls; elevation=none (tint + frost rules).",tagline:"soft elevation, generous type",shortName:"Stripe",proves:["action \u2260 brand-mark (chromatic indigo vs midnight)","elevation=none tint-ladder depth","4px squared controls (not pill)","whisper heading weight 300"],darkDefault:!1,brandPath:"brands/stripe/brand.json",skinPath:"skins/stripe.css",install:{command:"nebutra apply --preset stripe",cssImport:"@nebutra/tokens/skins/stripe.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"vanta",name:"Vanta",kind:"design-language",description:"Editorial violet on parchment; Vivid Violet action \u2260 Indigo Ink brand-mark; full pills; elevation=none (carbon hairlines).",tagline:"high-trust enterprise blues",shortName:"Vanta",proves:["action \u2260 brand-mark (chromatic)","elevation=none border-only","999px pill controls","serif display + sans UI zones"],darkDefault:!1,brandPath:"brands/vanta/brand.json",skinPath:"skins/vanta.css",install:{command:"nebutra apply --preset vanta",cssImport:"@nebutra/tokens/skins/vanta.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"vercel",name:"Vercel",kind:"design-language",description:"Monochrome dual-mode: light paper + Obsidian CTA; dark carbon + white CTA; hairline elevation (no chromatic CTA).",tagline:"monochrome, hard edges, lit top edge",shortName:"Vercel",proves:["light monochrome action","elevation=hairline","dual-mode light/dark palettes"],darkDefault:!1,brandPath:"brands/vercel/brand.json",skinPath:"skins/vercel.css",install:{command:"nebutra apply --preset vercel",cssImport:"@nebutra/tokens/skins/vercel.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}}]},me=Ks,Ws=me.languages.map(e=>e.id),Zt=me.defaultLanguage;function Qt(e){return me.languages.find(t=>t.id===e)}function Wr(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??Ys()}function Ys(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function Js(e="table"){let t=me.languages;return e==="json"?JSON.stringify({version:me.version,defaultLanguage:me.defaultLanguage,count:t.length,languages:t},null,2):[`Nebutra design languages (${t.length}) \u2014 global product chrome swap`,`Default: ${Zt} (factory tokens; no skin)`,"Contract: roles.action \u2192 CTA; roles.brand \u2192 brand-mark; free elev/radii/zones","",...t.map(r=>`${r.id.padEnd(10)} ${r.darkDefault?"dark ":"light"} ${(r.proves[0]??"").slice(0,48)} ${r.description.slice(0,56)}`)].join(`
|
|
531
|
+
`)}function qs(e,t="table"){let n=Qt(e);if(n)return t==="json"?JSON.stringify(n,null,2):[`${n.name} (${n.id}) \u2014 design language`,`Description: ${n.description}`,`Dark default: ${n.darkDefault}`,`Brand JSON: ${n.brandPath??"(factory \u2014 none)"}`,`Skin CSS: ${n.skinPath??"(factory \u2014 none)"}`,`Install: ${n.install.command}`,`CSS import: ${n.install.cssImport??"(clear data-brand)"}`,`Proves: ${n.proves.join("; ")}`].join(`
|
|
532
|
+
`)}function Yr(e){let t=e.command("theme").description("Design languages (Brand Package global product chrome swap)");t.command("list").description("List design languages").option("--format <type>","Output format: json or table").action(n=>{console.log(Js(Wr(n)))}),t.command("inspect <id>").description("Show a design language by id").option("--format <type>","Output format: json or table").action((n,r)=>{let o=qs(n,Wr(r));o||(c.error(`Design language '${n}' not found. Run: nebutra theme list`),process.exit(l.NOT_FOUND)),console.log(o)})}import{existsSync as Hr,readFileSync as Zr}from"fs";import{resolve as Jr,join as Xt}from"path";function Qr(e={}){let t=e.manifestPath?Jr(e.manifestPath):Xt(Jr(e.root??process.cwd()),"apps","design-docs","public","agent-manifest.json");return{manifestPath:t,componentDir:Xt(t,"..","agent","components")}}function Hs(e){return e.trim().toLowerCase()}function Zs(e){let t=Hs(e);if(!/^[a-z0-9-]+$/.test(t))throw new Error(`Invalid UI component name "${e}". Use a registry kebab-case id such as "button".`);return t}function Xr(e={}){let{manifestPath:t}=Qr(e);if(!Hr(t))throw new Error(`Missing Nebutra UI agent manifest at ${t}. Run pnpm --filter @nebutra/design-docs build:registry.`);return JSON.parse(Zr(t,"utf8"))}function en(e,t={}){let n=Zs(e),{componentDir:r}=Qr(t),o=Xt(r,`${n}.json`);if(!Hr(o))throw new Error(`UI component contract not found: ${n}`);return JSON.parse(Zr(o,"utf8"))}function eo(e,t="",n={}){let r=t.trim().toLowerCase(),o=qr(n.limit??20,1,100),i=qr(n.offset??0,0,Number.MAX_SAFE_INTEGER),a=n.tag?.trim().toLowerCase(),s=e.components.filter(p=>n.status&&p.status!==n.status||n.maturity&&p.maturity!==n.maturity||a&&!p.tags.includes(a)?!1:r?Qs(p).includes(r):!0).map(p=>({component:p,score:Xs(p,r)})).sort((p,f)=>f.score-p.score||p.component.name.localeCompare(f.component.name)).map(({component:p})=>p),u=s.slice(i,i+o),m=i+u.length;return{query:t,total:s.length,count:u.length,offset:i,limit:o,hasMore:m<s.length,...m<s.length&&{nextOffset:m},items:u}}function tn(e){let t=[],n=[];return e.evidence.source||t.push("Missing source evidence."),e.evidence.docs||t.push("Missing docs evidence."),e.evidence.registry||t.push("Missing registry evidence."),(e.status==="stable"||e.maturity==="canonical")&&!e.evidence.storybook&&t.push("Stable/canonical components must have Storybook evidence."),!e.evidence.tokens&&e.package==="@nebutra/ui"&&n.push("No token evidence was detected; confirm this primitive intentionally has no CSS variables."),e.migration.requiredForBreakingChanges&&e.migration.hints.length===0&&n.push("Breaking-change migration policy is enabled but no migration hints are present."),{name:e.name,valid:t.length===0,errors:t,warnings:n,evidence:e.evidence,migration:e.migration}}function Qs(e){return[e.name,e.title,e.description,e.status,e.maturity,e.layer,e.source,...e.tags].join(" ").toLowerCase()}function Xs(e,t){return t?e.name===t?100:e.name.startsWith(t)?80:e.title.toLowerCase().startsWith(t)?70:e.tags.includes(t)?60:e.name.includes(t)?50:e.title.toLowerCase().includes(t)?40:e.description.toLowerCase().includes(t)?20:1:e.maturity==="canonical"?20:10}function qr(e,t,n){return Number.isFinite(e)?Math.min(Math.max(Math.trunc(e),t),n):t}function wt(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??ec()}function ec(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function rn(e){let t=e.opts?e.opts():e;return{root:y(),manifestPath:t.manifest}}function to(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function tc(e,t="json"){if(t==="plain"||t==="table"){let n=[`Nebutra UI components (${e.total})`,""];for(let r of e.items)n.push(`${r.name.padEnd(22)} ${r.status.padEnd(12)} ${r.maturity.padEnd(10)} ${r.title}`);return e.hasMore&&n.push("",`Next offset: ${e.nextOffset}`),n.join(`
|
|
533
|
+
`)}return JSON.stringify(e,null,2)}function nc(e,t="json"){return t==="plain"||t==="table"?[`${e.title} (${e.name})`,`Status: ${e.status}`,`Maturity: ${e.maturity}`,`Source: ${e.source}`,`Package import: ${e.imports.package}`,`Registry: ${e.imports.registry}`,`Docs: ${e.docs.routes.join(", ")||"missing"}`,`Storybook: ${e.docs.storybook??"missing"}`,`Tokens: ${e.tokens.join(", ")||"none detected"}`].join(`
|
|
534
|
+
`):JSON.stringify(e,null,2)}function rc(e,t="json"){if(t==="plain"||t==="table"){if("results"in e){let n=[`Nebutra UI validation: ${e.valid?"valid":"invalid"}`,`Total: ${e.total}`,`Invalid: ${e.invalid}`];for(let r of e.results.filter(o=>!o.valid))n.push(`- ${r.name}: ${r.errors.join("; ")}`);return n.join(`
|
|
536
535
|
`)}return[`${e.name}: ${e.valid?"valid":"invalid"}`,...e.errors.map(n=>`error: ${n}`),...e.warnings.map(n=>`warning: ${n}`)].join(`
|
|
537
|
-
`)}return JSON.stringify(e,null,2)}function
|
|
538
|
-
`):JSON.stringify(n,null,2)}function
|
|
539
|
-
`),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):
|
|
540
|
-
`))}catch{}
|
|
536
|
+
`)}return JSON.stringify(e,null,2)}function oc(e,t="json"){let n={component:e.name,dryRun:!0,codemods:e.migration.codemods,hints:e.migration.hints,requiredForBreakingChanges:e.migration.requiredForBreakingChanges};return t==="plain"||t==="table"?[`Migration hints for ${e.name}`,`Codemods: ${n.codemods.length===0?"none registered":n.codemods.join(", ")}`,...n.hints.map(r=>`- ${r}`)].join(`
|
|
537
|
+
`):JSON.stringify(n,null,2)}function nn(e,t){try{return en(e,rn(t))}catch{St(`UI component contract not found: ${e}`,"Run `nebutra ui search <query> --format json` to discover available component ids.")}}function no(e){try{return Xr(rn(e))}catch{St("The Nebutra UI component catalog (agent-manifest.json) isn't available in this project.","This is an internal Nebutra doc-site feature, not part of the Sailor scaffold \u2014 `nebutra ui <search|component|validate|migrate>` only works inside the Nebutra-Sailor monorepo itself.")}}function ic(e,t){let n=e.components.map(o=>tn(en(o.name,rn(t)))),r=n.filter(o=>!o.valid).length;return{valid:r===0,total:n.length,invalid:r,results:n}}function ro(e){let t=e.command("ui").description("Inspect Nebutra UI agent contracts, production evidence, and migration hints");t.command("search [query]").description("Search the agent-readable @nebutra/ui component contract").option("--limit <number>","Maximum number of results","20").option("--offset <number>","Pagination offset","0").option("--tag <tag>","Filter by generated tag").option("--status <status>","Filter by status").option("--maturity <maturity>","Filter by maturity").option("--manifest <path>","Read a specific agent-manifest.json").option("--format <type>","Output format: json, table, plain").action((n,r)=>{let o=no(r),i=eo(o,n??"",{limit:to(r.limit,20),offset:to(r.offset,0),tag:r.tag,status:r.status,maturity:r.maturity});console.log(tc(i,wt(r)))}),t.command("component <name>").description("Print one component contract with imports, evidence, and migration policy").option("--manifest <path>","Read a specific agent-manifest.json").option("--format <type>","Output format: json, table, plain").action((n,r)=>{let o=nn(n,r);console.log(nc(o,wt(r)))}),t.command("validate [name]").description("Validate production evidence for one component or the full UI contract").option("--manifest <path>","Read a specific agent-manifest.json").option("--warn-only","Report validation failures without a non-zero exit").option("--format <type>","Output format: json, table, plain").action((n,r)=>{let o=n?tn(nn(n,r)):ic(no(r),r);console.log(rc(o,wt(r))),!o.valid&&!r.warnOnly&&process.exit(l.INCOMPATIBLE)}),t.command("migrate <name>").description("Print dry-run codemod and migration hints for a component").option("--manifest <path>","Read a specific agent-manifest.json").option("--apply","Reserved for future codemod execution").option("--format <type>","Output format: json, table, plain").action((n,r)=>{r.apply&&(console.error("Codemod execution is not implemented yet. Use `nebutra ui migrate <name>` for the dry-run plan."),process.exit(l.INCOMPATIBLE));let o=nn(n,r);console.log(oc(o,wt(r)))})}import{existsSync as oo,readFileSync as ac,unlinkSync as sc,writeFileSync as cc}from"fs";import{dirname as lc,join as io,parse as uc}from"path";function dc(e){let t=e,{root:n}=uc(t);for(;;){if(oo(io(t,"package.json")))return t;if(t===n)return null;let r=lc(t);if(r===t)return null;t=r}}async function mc(e){let t=e.format==="json",n=dc(process.cwd())??process.cwd(),r=io(n,"nebutra.config.json");if(oo(r)||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):c.info("Already unlinked"),process.exit(l.SUCCESS)),e.force){try{sc(r)}catch(s){let u=s instanceof Error?s.message:String(s);t?console.log(JSON.stringify({command:"unlink",success:!1,error:u},null,2)):c.error(`Failed to delete config: ${u}`),process.exit(l.PERMISSION_DENIED)}t?console.log(JSON.stringify({command:"unlink",success:!0,deletedConfig:!0,configPath:r},null,2)):c.success("Removed nebutra.config.json");return}let o={};try{o=JSON.parse(ac(r,"utf-8"))}catch{o={}}"projectId"in o||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):c.info("Already unlinked"),process.exit(l.SUCCESS));let{projectId:i,...a}=o;cc(r,JSON.stringify(a,null,2)+`
|
|
538
|
+
`),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):c.success("Unlinked from project")}function ao(e){e.command("unlink").description("Remove the project link from nebutra.config.json").option("--force","Delete the entire nebutra.config.json").option("--format <type>","Output format: json or plain").action(async(t,n)=>{let r=n?.optsWithGlobals?.()||t;await mc({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as Ac}from"child_process";import{existsSync as pc,readFileSync as co}from"fs";import{dirname as so,join as gc}from"path";import{fileURLToPath as fc}from"url";function hc(e=import.meta.url){let t=so(fc(e));for(let n=0;n<6;n+=1){let r=gc(t,"package.json");if(pc(r))try{if(JSON.parse(co(r,"utf8")).name==="nebutra")return r}catch{}let o=so(t);if(o===t)break;t=o}throw new Error("Unable to locate the nebutra CLI package.json")}function xt(e=import.meta.url){return JSON.parse(co(hc(e),"utf8")).version}import{promises as Ct}from"fs";import{homedir as yc}from"os";import{join as uo}from"path";import bc from"p-timeout";import pe from"picocolors";var vc=1440*60*1e3,mo=uo(yc(),".nebutra"),on=uo(mo,"update-check.json"),kc="https://registry.npmjs.org/nebutra",wc=5e3;async function xc(){try{await Ct.mkdir(mo,{recursive:!0})}catch{}}async function Cc(){try{let e=await Ct.readFile(on,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<vc?t:(await Ct.unlink(on).catch(r=>{c.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function Sc(e){try{await xc();let t={timestamp:Date.now(),latestVersion:e};await Ct.writeFile(on,JSON.stringify(t,null,2),"utf-8")}catch{}}async function Ec(){try{let e=new AbortController,t=await bc(fetch(kc,{signal:e.signal,headers:{Accept:"application/json"}}),{milliseconds:wc,fallback:()=>(e.abort(),null)});if(!t?.ok)return null;let r=(await t.json())["dist-tags"];return!r||typeof r.latest!="string"?null:r.latest}catch{return null}}function lo(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function Rc(e,t){let n=lo(e),r=lo(t);for(let o=0;o<3;o++){let i=n[o]??0,a=r[o]??0;if(a>i)return!0;if(a<i)return!1}return!1}async function an(e){let t=await Cc(),n=null;return t?n=t.latestVersion:(n=await Ec(),n&&await Sc(n)),!n||!Rc(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function Oc(e){let n=`Update available: ${e.currentVersion} \u2192 ${e.latestVersion}`,r="Run `npm i -g nebutra` to update",o=" ".repeat((43-n.length)/2),i=" ".repeat((43-r.length)/2),a=[pe.cyan("\u256D"+"\u2500".repeat(41)+"\u256E"),pe.cyan("\u2502")+pe.yellow(o+n+o)+pe.cyan("\u2502"),pe.cyan("\u2502")+pe.gray(i+r+i)+pe.cyan("\u2502"),pe.cyan("\u2570"+"\u2500".repeat(41)+"\u256F")]}async function po(e){let t=null;return an(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&Oc(t))}}var Ce=xt();function _c(){let t=(process.argv[1]||"").toLowerCase();if(t.includes("/homebrew/")||t.includes("/cellar/"))return"brew";if(t.includes("/.bun/")||t.includes("/bun/"))return"bun";if(t.includes("/pnpm/")||t.includes("/.pnpm/"))return"pnpm";if(t.includes("/yarn/")||t.includes("/.yarn/"))return"yarn";if(t.includes("/npm/")||t.includes("/node_modules/"))return"npm";let n=process.env.npm_config_user_agent||"";return n.startsWith("pnpm")?"pnpm":n.startsWith("yarn")?"yarn":n.startsWith("bun")?"bun":n.startsWith("npm")?"npm":"unknown"}function Ic(e){switch(e){case"pnpm":return"pnpm add -g nebutra@latest";case"yarn":return"yarn global add nebutra@latest";case"bun":return"bun add -g nebutra@latest";case"brew":return"brew upgrade nebutra";case"npm":return"npm i -g nebutra@latest";default:return"npm i -g nebutra@latest"}}async function Pc(e){let t=_c(),n=Ic(t),r=e.format==="json",o=await an(Ce),i=o?.latestVersion??null,a=!!o?.isUpdate;e.dryRun&&(r?console.log(JSON.stringify({command:"upgrade",dryRun:!0,installer:t,command_to_run:n,currentVersion:Ce,latestVersion:i,hasUpdate:a},null,2)):(c.info(`Detected installer: ${t}`),c.info(`Current: ${Ce}${i?` \u2192 Latest: ${i}`:""}`),c.info(`Upgrade command: ${n}`)),process.exit(l.DRY_RUN_OK)),!a&&i&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,alreadyLatest:!0,version:Ce},null,2)):c.success(`Already on the latest version (${Ce})`),process.exit(l.SUCCESS)),e.yes||(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,command_to_run:n,currentVersion:Ce,latestVersion:i,requiresConfirmation:!0},null,2)):(c.info(`Current: ${Ce}${i?` \u2192 Latest: ${i}`:""}`),c.info("To upgrade, run:"),c.info(` ${n}`),c.info("Or re-run this command with --yes to execute it now.")),process.exit(l.SUCCESS));let[s,...u]=n.split(" ");r||c.info(`Running: ${n}`);let m=Ac(s,u,{stdio:r?"pipe":"inherit"});m.status===0&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,ran:n},null,2)):c.success("Upgrade complete"),process.exit(l.SUCCESS));let p=m.stderr?.toString()||`Upgrade failed (exit ${m.status})`;r?console.log(JSON.stringify({command:"upgrade",success:!1,installer:t,ran:n,error:p},null,2)):c.error(p),process.exit(l.ERROR)}function go(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return Pc({yes:n.yes||o.yes||!1,dryRun:n.dryRun||!1,format:n.format||o.format})};e.command("upgrade").alias("self-update").description("Upgrade the nebutra CLI to the latest version").option("--yes","Execute the upgrade command without confirmation").option("--dry-run","Show the upgrade command without executing (exit 10)").option("--format <type>","Output format: json or plain").action(t)}function sn(e,t){let n=t==="expired"?`Your ${M.name} session has expired. Run \`nebutra login\` to sign in again.`:"Not logged in. Run `nebutra login` to authorize this machine.";e?console.log(JSON.stringify({command:"whoami",success:!1,error:t,message:n},null,2)):c.error(n),process.exit(l.PERMISSION_DENIED)}async function Nc(e,t){let n=!!e.json||e.format==="json"||t==="json",r=await ur();if(!r)return sn(n,"missing");if(r.expired)return sn(n,"expired");let o=gt(),i=await ft(o,r.token);if(!i)return sn(n,"expired");n?console.log(JSON.stringify({command:"whoami",success:!0,userId:i.userId,email:i.email,name:i.name,tokenSource:r.source},null,2)):(c.success(i.email??i.userId),i.name&&c.info(i.name))}function fo(e){e.command("whoami").description(`Show the ${M.name} identity this machine is authorized as`).option("--json","Output as JSON").option("--format <type>","Output format: json or plain").action(async(t,n)=>{let r=n?.optsWithGlobals?.()||t;await Nc(t,r.format)})}import{existsSync as $c,mkdirSync as jc,writeFileSync as Fc}from"fs";import{homedir as ho,platform as Dc}from"os";import{join as Ke}from"path";import cn from"picocolors";function Tc(){if(Dc()==="win32"){let t=process.env.LOCALAPPDATA||Ke(ho(),"AppData","Local");return Ke(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Ke(e,"nebutra"):Ke(ho(),".config","nebutra")}function Lc(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function yo(e,t){try{jc(e,{recursive:!0}),Fc(t,"")}catch{}}function bo(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=Tc(),t=Ke(e,"first-run-acked");try{if($c(t))return}catch{return}if(Lc()){yo(e,t);return}let r=[`${cn.cyan("\u2139")} ${M.name} collects anonymous usage analytics to improve the CLI.`,` Opt out at any time: ${cn.dim("export NEBUTRA_TELEMETRY=0")}`,` Privacy policy: ${cn.dim(`${pt("landing")}/legal/cli-analytics`)}`,""];try{process.stderr.write(r.join(`
|
|
539
|
+
`))}catch{}yo(e,t)}var xo=xt();function Bc(e){let t=new Uc,n=e.isInteractive??(process.stdin.isTTY!==!1&&process.stdout.isTTY!==!1);return t.name("nebutra").description("Nebutra \u2014 the CLI for Sailor projects: status, dev, db, and codegen").version(e.version).option("--verbose","Enable verbose output").option("--quiet","Suppress non-essential output").option("--format <type>","Output format: json, table, plain").option("--yes","Skip all interactive prompts (Agent mode)").option("--no-interactive","Alias for --yes").option("--no-color","Disable colored output"),t.command("init").description("Initialize a Nebutra project and create nebutra.config.json").option("--dry-run","Preview changes without writing files (exits with code 10)").option("--if-not-exists","Skip initialization if nebutra.config.json already exists").action(r=>we(async()=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Jn({dryRun:r.dryRun||!1,yes:o.yes||!1,ifNotExists:r.ifNotExists||!1})})),wr(t),Rr(t),Cn(t),Wn(t),Yn(t),Un(t),Zn(t),hn(t),$n(t),Kn(t),jn(t),Kr(t),Tn(t),Yr(t),wn(t),ro(t),_r(t),Or(t),_n(t),br(t),kr(t),fo(t),go(t),er(t),ao(t),Dr(t),Mr(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(()=>we(async()=>{let{logger:r}=await import("./logger-QMYN56HK.js"),{findMonorepoRootOrExit:o}=await import("./delegate-MQWQZT5V.js"),i=await import("fs"),a=await import("path");r.info("Running project health check...");let s=!1,u=o(),m=process.version;parseInt(m.replace("v","").split(".")[0]??"0",10)<22?(r.error(`Node.js >= 22 required, found ${m}`),s=!0):r.success(`Node.js version OK (${m})`),i.existsSync(a.join(u,"nebutra.config.json"))?r.success("nebutra.config.json found"):r.warn("nebutra.config.json missing. Try running 'nebutra init'"),i.existsSync(a.join(u,"package.json"))?r.success("package.json found"):(r.error("No package.json found in root directory"),s=!0),i.existsSync(a.join(u,".env"))||i.existsSync(a.join(u,".env.local"))?r.success("Environment variables configured"):r.warn("No .env or .env.local found. Some features may not work properly.");let h=a.join(u,"apps/api-gateway");i.existsSync(h)&&r.warn("Legacy `apps/api-gateway/` present. Expected `backends/gateway/` \u2014 see CLAUDE.md for the W2.x restructure.");let g=a.join(u,"backends/gateway");i.existsSync(g)?r.success("backends/gateway/ present"):i.existsSync(a.join(u,"backends"));let k=a.join(u,"packages");if(i.existsSync(k)){let W=new Set(["design","iam","commerce","integrations","platform","ops","ai"]);try{let X=i.readdirSync(k,{withFileTypes:!0}),L=[];for(let Se of X){if(!Se.isDirectory()||W.has(Se.name))continue;let We=a.join(k,Se.name,"package.json");i.existsSync(We)&&L.push(Se.name)}L.length>0?r.warn(`Found ${L.length} uncategorized package(s) under packages/: ${L.join(", ")}. Expected packages/<category>/<name>/ \u2014 see CLAUDE.md.`):r.success("Packages follow categorized layout")}catch{}}let F=a.join(u,".nebutra"),w=a.join(F,"scaffold-meta.json");if(i.existsSync(w)?r.success(".nebutra/scaffold-meta.json present (CLI-scaffolded project)"):i.existsSync(F)&&r.warn(".nebutra/ directory exists but scaffold-meta.json is missing. Harmless \u2014 the marker is provenance only and grants nothing."),(i.existsSync(w)||i.existsSync(a.join(u,"nebutra.config.json")))&&(r.info(""),r.info("Golden path to a running app:"),r.info(" 1. nebutra status # what is live, what needs a key"),r.info(" 2. pnpm dev # http://localhost:3001"),r.info(""),r.info("Optional, once you want your own Postgres:"),r.info(" pnpm infra:up && pnpm db:migrate")),s)throw new K({code:"doctor_failed",message:"Doctor found critical issues that require your attention.",suggestion:"Fix the errors above, then re-run `nebutra doctor`.",exitCode:l.CONFIG_ERROR});r.success("Doctor is happy. Your project looks healthy!")})),t.hook("preAction",r=>{let o=r.optsWithGlobals();(!n||o.noInteractive)&&(o.yes=!0)}),t.addHelpText("after",`
|
|
541
540
|
Examples:
|
|
542
541
|
$ nebutra init Initialize a new project
|
|
543
542
|
$ nebutra status Show capability readiness (live/local-fallback/missing-key)
|
|
@@ -572,4 +571,4 @@ Environment:
|
|
|
572
571
|
NEBUTRA_OUTPUT_FORMAT Output format (json|table|plain)
|
|
573
572
|
NO_COLOR Disable colored output
|
|
574
573
|
CI Auto-enable non-interactive mode
|
|
575
|
-
`),t}async function
|
|
574
|
+
`),t}async function Mc(){bo();let e=await po(xo),t=Bc({version:xo,isInteractive:process.stdin.isTTY!==!1&&process.stdout.isTTY!==!1});process.argv.length<=2&&(t.outputHelp(),process.exit(l.SUCCESS)),await t.parseAsync(process.argv),await e()}function Gc(){if(!process.argv[1])return!1;try{return vo(wo(import.meta.url))===vo(ko(process.argv[1]))}catch{return wo(import.meta.url)===ko(process.argv[1])}}var Vc=Gc();Vc&&Mc().catch(e=>{process.exitCode=Jt(e)});export{Bc as buildProgram};
|