nebutra 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import{b as l}from"./chunk-JDX5NXDX.js";import{a as C,b as O,c as $,d as re,e as Ce,f as ee}from"./chunk-LGUMYJ4Q.js";import{realpathSync as eo}from"fs";import{resolve as to}from"path";import{fileURLToPath as no}from"url";import{Command as ec}from"commander";import{existsSync as oo,readFileSync as io,writeFileSync as ao}from"fs";import{resolve as yt}from"path";var c={SUCCESS:0,ERROR:1,INVALID_ARGS:2,NOT_FOUND:3,PERMISSION_DENIED:4,CONFLICT:5,NETWORK_ERROR:6,TIMEOUT:7,CANCELLED:8,CONFIG_ERROR:9,DRY_RUN_OK:10,INCOMPATIBLE:11,RESOURCE_EXHAUSTED:12},Zt={[c.SUCCESS]:"Command completed successfully",[c.ERROR]:"General or unknown error occurred",[c.INVALID_ARGS]:"Invalid arguments or options provided",[c.NOT_FOUND]:"Requested resource not found",[c.PERMISSION_DENIED]:"Permission denied or authentication required",[c.CONFLICT]:"Resource already exists",[c.NETWORK_ERROR]:"Network or external service error (may be retryable)",[c.TIMEOUT]:"Operation timed out (may be retryable)",[c.CANCELLED]:"Operation cancelled by user",[c.CONFIG_ERROR]:"Configuration error or missing configuration",[c.DRY_RUN_OK]:"Dry-run completed successfully",[c.INCOMPATIBLE]:"Incompatible version or dependency conflict",[c.RESOURCE_EXHAUSTED]:"System resource exhausted"};var so=["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"],Qt="nebutra.config.json",co=so,Xt={"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 Y(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 lo(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function uo(e){return Xt[e]?Xt[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function Me(){return Object.fromEntries(co.map(e=>[e,{id:e,name:lo(e),envVars:uo(e)}]))}function q(){return yt(process.cwd(),Qt)}function de(){let e=q();if(!oo(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(io(e,"utf-8"))}catch(t){l.error(`Failed to parse ${Qt}: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}function Ge(e){ao(q(),`${JSON.stringify(e,null,2)}
3
- `)}function oe(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 mo(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=oe(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 W(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??po();return{...n,...t,...r?{format:r}:{}}}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 _e(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function fo(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`)),Y(n,e.format,"ai:models")}async function go(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)`)),Y(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 yo(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"),Y(n,t.format,"ai:test")}async function ho(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(", ")}`)),Y(t,e.format,"ai:config")}async function bo(e){let t=de(),n=oe(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(", ")}`)}Y(i,e.format,"ai:provider:list")}async function vo(e,t){let n=en(e),r=de(),o=oe(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}=`)}Y(s,t.format,"ai:provider:enable")}async function wo(e,t){let n=en(e),r=de(),o=oe(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(", ")}`),Y(s,t.format,"ai:provider:disable")}async function Co(e){let t=de(),n=oe(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"),Y(o,e.format,"ai:gateway:init")}async function xo(e){let t=de(),n=oe(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")),Y(r,e.format,"ai:gateway:status")}async function So(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=mo(t.fallback),r=de(),o=oe(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}'`),Y(i,t.format,"ai:route:set")}async function Eo(e){let t=de(),n=oe(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(", ")}`)),Y(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=W(i);await bo({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=W(a);await vo(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=W(a);await wo(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=W(i);await Co({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=W(i);await xo({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=W(a);await So(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=W(i);await Eo({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=W(i);await fo({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=W(i);await go({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=W(a);await yo(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=W(i);await ho({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 Ro(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 ko(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 Oo(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 Ao(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 _o(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 Ro({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 ko({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 Oo({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 Ao({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 _o({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import{appendFileSync as Io,existsSync as No,readFileSync as Po,writeFileSync as jo}from"fs";import{homedir as Ne}from"os";import{join as xe}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"},$o=["--help","--version","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--json","--no-browser","--poll"],To=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 d}from"./chunk-JDX5NXDX.js";import{a as l,b as yn,c as He,d as bn,e as ae,f as _t,h as vn,i as y,j as R,k as F,l as se,m as ge,n as ne}from"./chunk-DTSPVLT5.js";import{realpathSync as Ho}from"fs";import{resolve as Zo}from"path";import{fileURLToPath as Xo}from"url";import{Command as El}from"commander";import*as $n from"@clack/prompts";var E=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 ei(e){return e instanceof E}function ti(e){return ei(e)?He({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?He({error:"unexpected_error",message:e.message,suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:l.ERROR,cause:e}):He({error:"unexpected_error",message:String(e),suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:l.ERROR})}function It(e){let t=ti(e);return bn(t),t.exitCode}async function z(e){try{await e()}catch(t){process.exitCode=It(t)}}var ni={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",kcq:"kcq.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 Z(e){let t=ni.domains[e];if(!t?.trim())throw new Error(`brand.domains.${String(e)} is empty \u2014 run brand:apply`);return`https://${t.replace(/^https?:\/\//,"").replace(/\/+$/,"")}`}import{execFile as oi}from"child_process";import{chmodSync as ii,existsSync as Oe,readFileSync as kn,rmSync as ai,unlinkSync as Pt,writeFileSync as xn}from"fs";import{mkdir as si}from"fs/promises";import{platform as he}from"os";import{join as Cn}from"path";import{promisify as ci}from"util";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",kcq:"kcq.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{homedir as wn,platform as ri}from"os";import{join as Ze}from"path";function Re(){if(ri()==="win32"){let t=process.env.LOCALAPPDATA||Ze(wn(),"AppData","Local");return Ze(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Ze(e,"nebutra"):Ze(wn(),".config","nebutra")}var ye=ci(oi),be="nebutra-cli",Ae="default";function Ee(){return Cn(Re(),"credentials.json")}function Xe(){return Cn(Re(),"device-pending.json")}async function Sn(){await si(Re(),{recursive:!0})}async function Nt(e){try{return await ye(he()==="win32"?"where":"which",[e]),!0}catch{return!1}}function $t(){return process.env.NEBUTRA_NO_KEYCHAIN==="1"}async function li(e){if($t())return!1;try{if(he()==="darwin")return await ye("security",["add-generic-password","-a",Ae,"-s",be,"-w",e,"-U"]),!0;if(he()==="linux"&&await Nt("secret-tool"))return await ye("secret-tool",["store","--label",`${M.name} CLI credentials`,"service",be,"account",Ae]),!0}catch{}return!1}async function Rn(){if($t())return null;try{if(he()==="darwin"){let{stdout:e}=await ye("security",["find-generic-password","-a",Ae,"-s",be,"-w"]);return e.trim()||null}if(he()==="linux"&&await Nt("secret-tool")){let{stdout:e}=await ye("secret-tool",["lookup","service",be,"account",Ae]);return e.trim()||null}}catch{}return null}async function di(){if($t())return!1;let e=!1;try{he()==="darwin"?(await ye("security",["delete-generic-password","-a",Ae,"-s",be]),e=!0):he()==="linux"&&await Nt("secret-tool")&&(await ye("secret-tool",["clear","service",be,"account",Ae]),e=!0)}catch{}return e}async function En(e){await Sn();let t=JSON.stringify(e);if(await li(t)){try{Oe(Ee())&&Pt(Ee())}catch{}return{storedIn:"keychain"}}xn(Ee(),`${t}
3
+ `,{mode:384});try{ii(Ee(),384)}catch{}return{storedIn:"file"}}async function ui(){let e=await Rn();if(e)try{return JSON.parse(e)}catch{return null}let t=Ee();if(!Oe(t))return null;try{return JSON.parse(kn(t,"utf-8"))}catch{return null}}async function On(){let e=[];await di()&&e.push(`keychain:${be}`);let t=Ee();if(Oe(t))try{Pt(t),e.push(t)}catch{}let n=Xe();if(Oe(n))try{ai(n,{force:!0}),e.push(n)}catch{}return e}async function jt(e){await Sn(),xn(Xe(),`${JSON.stringify(e)}
4
+ `,{mode:384})}function An(){let e=Xe();if(!Oe(e))return null;try{return JSON.parse(kn(e,"utf-8"))}catch{return null}}function Qe(){let e=Xe();if(Oe(e))try{Pt(e)}catch{}}async function ce(){let e=process.env.NEBUTRA_TOKEN?.trim();if(e)return{token:e,source:"env",expired:!1};let t=await ui();if(!t)return null;let n=!!t.expiresAt&&new Date(t.expiresAt).getTime()<=Date.now(),r=await Rn()!==null;return{token:t.accessToken,source:r?"keychain":"file",expired:n}}var et=["platform_owner","platform_operator","platform_support","platform_readonly"];function _n(e){let t=e.trim().toLowerCase(),n=t.startsWith("platform_")?t:`platform_${t}`;return et.includes(n)?n:null}var _e=class extends Error{constructor(n,r,o){super(o);this.status=n;this.code=r;this.name="StaffApiError"}status;code};async function mi(){let e=await ce();return e&&!e.expired?e.token:null}function pi(){return(process.env.NEBUTRA_API_URL??Z("api")).replace(/\/+$/,"")}function In(e={}){let t=e.fetch??fetch,n=e.token??mi;async function r(o,i,a){let s=await n();if(!s)throw new _e(401,"not_logged_in","Not logged in. Run `nebutra login` first.");let c=await t(`${e.baseUrl??pi()}/api/v1/platform/staff${i}`,{method:o,headers:{authorization:`Bearer ${s}`,...a===void 0?{}:{"content-type":"application/json"}},...a===void 0?{}:{body:JSON.stringify(a)},signal:AbortSignal.timeout(15e3)}),m=await c.json().catch(()=>null);if(!c.ok){let p=typeof m?.code=="string"?m.code:`http_${c.status}`,g=typeof m?.error=="string"?m.error:`The gateway answered ${c.status}.`;throw new _e(c.status,p,g)}return m}return{list:async()=>(await r("GET","")).staff,me:()=>r("GET","/me"),grant:o=>r("POST","",o),revoke:(o,i)=>r("POST",`/${encodeURIComponent(o)}/revoke`,{note:i})}}var fi=e=>e===400?l.INVALID_ARGS:e===401||e===403?l.PERMISSION_DENIED:e===404?l.NOT_FOUND:e===409?l.CONFLICT:l.ERROR;function tt(e){return e instanceof _e?new E({code:e.code,message:e.message,exitCode:fi(e.status),...e.code==="not_logged_in"||e.status===401?{suggestion:"Run `nebutra login`."}:{}}):e}function gi(e){let t=_n(e);if(!t)throw new E({code:"invalid_role",message:`Unknown role "${e}".`,exitCode:l.INVALID_ARGS,suggestion:`Use one of: ${et.join(", ")} (the platform_ prefix is optional).`});return t}function Pn(e){let t=e?.trim()??"";if(t.length<3)throw new E({code:"note_required",message:"A note is required: say why (ticket, rotation, handover).",exitCode:l.INVALID_ARGS,suggestion:'Add --note "<reason>".'});return t}function hi(e){if(e.length===0)return"No staff grants.";let t=n=>[(n.email??n.userId).padEnd(28),n.role.padEnd(18),(n.active?"active":`revoked ${n.revokedAt?.slice(0,10)}`).padEnd(22),`by ${n.grantedBy?.email??n.grantedBy?.userId??"bootstrap"}`.padEnd(28),n.note??""].join(" ");return e.map(t).join(`
5
+ `)}async function Nn(e,t,n){if(t!==!0){if(!e.isInteractive())throw new E({code:"confirmation_required",message:"This changes who can operate the platform and needs confirmation.",exitCode:l.INVALID_ARGS,suggestion:"Re-run with --yes once the person has agreed."});if(!await e.confirm(n))throw new E({code:"cancelled",message:"Cancelled. Nothing changed.",exitCode:l.CANCELLED})}}function jn(e,t={}){let n=t.out??(c=>console.log(c)),r=()=>t.client??In(),o={confirm:t.confirm??(async c=>await $n.confirm({message:c})===!0),isInteractive:t.isInteractive??(()=>process.stdin.isTTY===!0&&process.stdout.isTTY===!0)},i=(c,m,p)=>n(c.json?JSON.stringify(m,null,2):p),s=e.command("admin").description("Platform administration (platform staff only)").command("staff").description("Manage who may operate the platform");s.command("list").description("List staff grants, tombstones included").option("--json","Machine-readable output").action(c=>z(async()=>{try{let m=await r().list();i(c,{staff:m},hi(m))}catch(m){throw tt(m)}})),s.command("whoami").description("Your own platform standing").option("--json","Machine-readable output").action(c=>z(async()=>{try{let m=await r().me();i(c,m,`${m.email??m.userId} ${m.role}${m.canGrant?" (can grant and revoke)":""}`)}catch(m){throw tt(m)}})),s.command("grant <email>").description("Grant or change a platform role (platform_owner only)").requiredOption("--role <role>",`One of: ${et.join(", ")}`).requiredOption("--note <text>","Why this person has this role").option("--yes","Confirm without asking (agents: only after the person agreed)").option("--json","Machine-readable output").action((c,m)=>z(async()=>{let p=gi(m.role??""),g=Pn(m.note);await Nn(o,m.yes,`Grant ${p} to ${c}?`);try{let h=await r().grant({email:c,role:p,note:g});i(m,h,`Granted ${h.role} to ${c}. Audit entry: ${h.auditId??"not recorded"}`)}catch(h){throw tt(h)}})),s.command("revoke <email>").description("Revoke a grant by tombstone (platform_owner only)").requiredOption("--note <text>","Why the access ends").option("--yes","Confirm without asking (agents: only after the person agreed)").option("--json","Machine-readable output").action((c,m)=>z(async()=>{let p=Pn(m.note);await Nn(o,m.yes,`Revoke platform access for ${c}?`);try{let g=await r().revoke(c,p);i(m,g,`Revoked ${c}. Audit entry: ${g.auditId??"not recorded"}`)}catch(g){throw tt(g)}}))}import{existsSync as yi,readFileSync as bi,writeFileSync as vi}from"fs";import{resolve as Tt}from"path";var wi=["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"],Fn="nebutra.config.json",ki=wi,Tn={"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 H(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 xi(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function Ci(e){return Tn[e]?Tn[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function nt(){return Object.fromEntries(ki.map(e=>[e,{id:e,name:xi(e),envVars:Ci(e)}]))}function X(){return Tt(process.cwd(),Fn)}function ve(){let e=X();if(!yi(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(bi(e,"utf-8"))}catch(t){d.error(`Failed to parse ${Fn}: ${t instanceof Error?t.message:String(t)}`),process.exit(l.ERROR)}}function rt(e){vi(X(),`${JSON.stringify(e,null,2)}
6
+ `)}function le(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function Dn(e){let t=nt(),n=[...new Set(e.map(o=>o.toLowerCase()))],r=n.filter(o=>!t[o]);return r.length>0&&(d.error(`Unknown AI provider(s): ${r.join(", ")}. Valid providers: ${Object.keys(t).join(", ")}`),process.exit(l.INVALID_ARGS)),n}function Si(e){let t=e?.split(",").map(r=>r.trim()).filter(Boolean)??[];t.length===0&&(d.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&&(d.error(`Invalid fallback target(s): ${n.join(", ")}. Expected provider:model.`),process.exit(l.INVALID_ARGS)),t}function Ln(e){let t=le(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,i])=>i.enabled).map(([i])=>i);return{path:X(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function q(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??Ri();return{...r,...n,...o?{format:o}:{}}}function Ri(){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 Fe(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function Ei(e){e.format!=="json"&&d.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:Fe(process.env[i])}))})),configuredCount:Object.values(t).filter(r=>r.configured).length,totalProviders:Object.keys(t).length};e.dryRun||(n.configuredCount===0?d.warn("No AI providers configured. Set API keys to enable AI features."):d.success(`${n.configuredCount} AI provider(s) configured`)),H(n,e.format,"ai:models")}async function Oi(e){e.format!=="json"&&d.info("Scanning for available agents...");try{let t=Tt(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?d.info("No agents configured. Create agents in backends/gateway/src/routes/agents/"):d.success(`Found ${r.count} agent(s)`)),H(r,e.format,"ai:agents")}catch(t){d.error(`Failed to scan agents: ${t instanceof Error?t.message:String(t)}`),process.exit(l.ERROR)}}async function Ai(e,t){(!e||e.trim().length===0)&&(d.error("Prompt cannot be empty"),process.exit(l.INVALID_ARGS)),t.format!=="json"&&(d.info("Testing AI prompt against default model..."),d.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||d.warn("AI test execution requires a running API gateway. Start it with: pnpm --filter @nebutra/gateway dev"),H(n,t.format,"ai:test")}async function _i(e){e.format!=="json"&&d.info("Checking AI configuration...");let t={providers:{openai:{key:Fe(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:Fe(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:Fe(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=Tt(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?d.warn("No AI providers configured. Set environment variables to enable AI features."):d.success(`Configuration loaded: ${n.join(", ")}`)),H(t,e.format,"ai:config")}async function Ii(e){let t=ve(),n=le(t),r=nt(),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(c=>!!process.env[c]),envVars:a.envVars.map(c=>({name:c,value:Fe(process.env[c])}))}}),i={configPath:X(),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?d.warn("No runtime AI providers enabled in nebutra.config.json."):d.success(`Enabled AI providers: ${a.map(s=>s.id).join(", ")}`)}H(i,e.format,"ai:provider:list")}async function Pi(e,t){let n=Dn(e),r=ve(),o=le(r),i=nt(),a=new Date().toISOString();for(let c of n)o.providers[c]={enabled:!0,envVars:i[c].envVars,enabledAt:o.providers?.[c]?.enabledAt??a};rt(r);let s={configPath:X(),enabled:n,env:t.env===!0?n.flatMap(c=>i[c].envVars.map(m=>({provider:c,name:m,example:`${m}=`}))):void 0,ai:Ln(r)};if(t.format!=="json"&&(d.success(`Enabled AI provider(s): ${n.join(", ")}`),t.env)){d.info("Required environment variables:");for(let c of n)for(let m of i[c].envVars)console.log(`${m}=`)}H(s,t.format,"ai:provider:enable")}async function Ni(e,t){let n=Dn(e),r=ve(),o=le(r),i=nt(),a=new Date().toISOString();for(let c of n)o.providers[c]={enabled:!1,envVars:o.providers?.[c]?.envVars??i[c].envVars,disabledAt:a};rt(r);let s={configPath:X(),disabled:n,ai:Ln(r)};t.format!=="json"&&d.success(`Disabled AI provider(s): ${n.join(", ")}`),H(s,t.format,"ai:provider:disable")}async function $i(e){let t=ve(),n=le(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},rt(t);let o={configPath:X(),gateway:n.gateway};e.format!=="json"&&d.success("AI gateway governance initialized in nebutra.config.json"),H(o,e.format,"ai:gateway:init")}async function ji(e){let t=ve(),n=le(t),r={configPath:X(),gateway:n.gateway??null,initialized:n.gateway?.enabled===!0};e.format!=="json"&&(r.initialized?d.success("AI gateway governance is initialized"):d.warn("AI gateway governance is not initialized. Run: nebutra ai gateway init")),H(r,e.format,"ai:gateway:status")}async function Ti(e,t){(!e||e.trim().length===0)&&(d.error("Route name cannot be empty"),process.exit(l.INVALID_ARGS)),t.policy||(d.error("Route policy is required. Use --policy <policy>."),process.exit(l.INVALID_ARGS));let n=Si(t.fallback),r=ve(),o=le(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},rt(r);let i={configPath:X(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&d.success(`AI route '${e}' set with policy '${t.policy}'`),H(i,t.format,"ai:route:set")}async function Fi(e){let t=ve(),n=le(t),r=Object.entries(n.routes??{}).map(([i,a])=>({name:i,...a})),o={configPath:X(),routes:r,count:r.length};e.format!=="json"&&(r.length===0?d.warn("No AI routes configured. Run: nebutra ai route set chat --policy cost-latency-balanced --fallback openai:gpt-5.4"):d.success(`Configured AI routes: ${r.map(i=>i.name).join(", ")}`)),H(o,e.format,"ai:route:list")}function Un(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=q(i,a);await Ii({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 c=q(a,s);await Pi(i,{env:c.env===!0,format:c.format,interactive:c.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 c=q(a,s);await Ni(i,{format:c.format,interactive:c.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=q(i,a);await $i({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=q(i,a);await ji({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 c=q(a,s);await Ti(i,{policy:c.policy,fallback:c.fallback,format:c.format,interactive:c.yes!==!0})}),o.command("list").description("List configured AI routes").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=q(i,a);await Fi({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=q(i,a);await Ei({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=q(i,a);await Oi({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 c=q(a,s);await Ai(i,{dryRun:c.dryRun===!0,format:c.format,interactive:c.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=q(i,a);await _i({dryRun:s.dryRun===!0,format:s.format,interactive:s.yes!==!0})})}import{existsSync as Gt,mkdirSync as Mi,readFileSync as Gi,rmSync as Vi,writeFileSync as zi}from"fs";import{dirname as Ki,join as Le}from"path";var Ut=["factory","linear","gsap","notion","raycast","stripe","vanta","vercel","cosmos"],Mn=["base","cool","neutral","warm"],Gn=["base","none","sm","md","lg","full"],Vn=["base","compact","comfortable","spacious"],zn=["base","Geist","Inter","Inter Tight","DM Sans","Manrope","Plus Jakarta Sans","Figtree","Work Sans","Space Grotesk","Outfit","Sora","Lexend","Montserrat"],Kn=["base","sans","DM Sans","Inter Tight","Space Grotesk","Sora","Outfit","Manrope","Playfair Display","Fraunces","Source Serif 4"],Wn=["base","Geist Mono","JetBrains Mono","Fira Code","Roboto Mono","Source Code Pro"],Yn=["base",400,500,600,700],Jn=["base","light","dark"];var Dt=1,qn="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",O=class extends Error{constructor(e){super(e),this.name="PresetCodeError"}},Ie={version:{bits:3},base:{bits:5,list:Ut},neutral:{bits:2,list:Mn},radius:{bits:3,list:Gn},density:{bits:2,list:Vn},sans:{bits:4,list:zn},heading:{bits:4,list:Kn},mono:{bits:3,list:Wn},headingWeight:{bits:3,list:Yn},mode:{bits:2,list:Jn},hasColor:{bits:1},color:{bits:24},tintLogo:{bits:1}},Bt=Object.keys(Ie);for(let e of Bt){let t=Ie[e];if(t.list&&t.list.length>2**t.bits)throw new Error(`preset knob "${e}" outgrew its ${t.bits} bits`)}var Di=/^#[0-9a-f]{6}$/i;function re(e,t){let n=Ie[e].list;if(!n)throw new Error(`"${e}" is not a list knob`);let r=n.indexOf(t??"base");if(r<0)throw new O(`Unknown ${e}: ${String(t)}`);return r}function Mt(e){let t={version:Dt,base:re("base",e.base),neutral:re("neutral",e.neutral),radius:re("radius",e.radius),density:re("density",e.density),sans:re("sans",e.sans),heading:re("heading",e.heading),mono:re("mono",e.mono),headingWeight:re("headingWeight",e.headingWeight),mode:re("mode",e.mode),hasColor:e.brandColor?1:0,color:0,tintLogo:e.tintLogo?1:0};if(e.brandColor){if(!Di.test(e.brandColor))throw new O(`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 Bt)n|=BigInt(t[i])<<r,r+=BigInt(Ie[i].bits);let o="";for(;n>0n;)o=qn[Number(n%62n)]+o,n/=62n;return o}function Li(e){if(!/^[0-9a-zA-Z]{1,12}$/.test(e))throw new O(`"${e}" is not a preset code`);let t=0n;for(let a of e)t=t*62n+BigInt(qn.indexOf(a));let n={};for(let a of Bt){let s=BigInt(Ie[a].bits);n[a]=Number(t&(1n<<s)-1n),t>>=s}if(t!==0n)throw new O(`"${e}" is longer than any preset`);if(n.version!==Dt)throw new O(`"${e}" is preset format v${n.version}; this Sailor reads v${Dt}. Upgrade @nebutra/tokens.`);let r=a=>{let c=Ie[a].list[n[a]];if(c===void 0)throw new O(`"${e}" names an unknown ${a}`);return c},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.tintLogo&&(o.tintLogo=!0),n.hasColor&&(o.brandColor=`#${n.color.toString(16).padStart(6,"0")}`),o}function De(e){let t=e.trim();return Ut.includes(t)?{base:t}:Li(t)}var Lt={base:Ut,neutral:Mn,radius:Gn,density:Vn,sans:zn,heading:Kn,mono:Wn,headingWeight:Yn,mode:Jn},Ft={base:"The design language to start from. `factory` is the House tokens; the others are complete brand packages.",brandColor:"#rrggbb. Becomes the action fill (buttons) and the ring (focus, links). Omit to keep the base's.",neutral:"Temperature of neutral surfaces and text.",radius:"Corner radius scale for buttons, cards, badges and inputs.",density:"Control height and spacing scale.",sans:"Body face. Only self-hosted faces are offered.",heading:"Heading face. `sans` sets headings in the body face.",mono:"Code face.",headingWeight:"Heading weight.",mode:"Which mode a visitor sees first. Only a dual-mode base can change it.",tintLogo:"Paint the wordmark in the base's brand colour. Off by default: the wordmark reads in ink."},Hn=Z("landing"),Ui=`${Hn}/studio/preset.schema.json`;function Zn(){let e={brandColor:{type:"string",pattern:"^#[0-9a-fA-F]{6}$",description:Ft.brandColor}};for(let[t,n]of Object.entries(Lt))e[t]={enum:[...n],description:Ft[t]};return e.tintLogo={type:"boolean",default:!1,description:Ft.tintLogo},{$schema:"https://json-schema.org/draft/2020-12/schema",$id:Ui,title:"Sailor Studio preset",description:"A Sailor project's whole look in one object. Encode it with `nebutra studio preview` to review it in Sailor Studio, then `nebutra studio pull` or `create-sailor --preset` to apply it.",type:"object",required:["base"],additionalProperties:!1,properties:e}}function Bn(e){if(typeof e!="object"||e===null||Array.isArray(e))throw new O("A preset is a JSON object with at least `base`.");let t=e,n=new Set(["brandColor","tintLogo",...Object.keys(Lt)]);for(let o of Object.keys(t))if(!n.has(o))throw new O(`Unknown field "${o}". Fields: ${[...n].join(", ")}.`);let r={};for(let[o,i]of Object.entries(Lt)){let a=t[o];if(a!==void 0){if(!i.includes(a))throw new O(`"${o}" must be one of ${i.map(s=>JSON.stringify(s)).join(", ")}; got ${JSON.stringify(a)}.`);a!=="base"&&(r[o]=a)}}if(r.base===void 0)throw new O('"base" is required.');if(t.tintLogo!==void 0){if(typeof t.tintLogo!="boolean")throw new O(`"tintLogo" must be true or false; got ${JSON.stringify(t.tintLogo)}.`);t.tintLogo&&(r.tintLogo=!0)}if(t.brandColor!==void 0){if(typeof t.brandColor!="string"||!/^#[0-9a-fA-F]{6}$/.test(t.brandColor))throw new O(`"brandColor" must be #rrggbb; got ${JSON.stringify(t.brandColor)}.`);r.brandColor=t.brandColor.toLowerCase()}return r}function Xn(e){if(typeof e!="string")return Bn(e);let t=e.trim();if(t.startsWith("{")){let n;try{n=JSON.parse(t)}catch{throw new O("That looks like JSON but does not parse.")}return Bn(n)}if(/^https?:\/\//.test(t)){let n=new URL(t).searchParams.get("preset");if(!n)throw new O("That URL carries no ?preset= to read.");return De(n)}return De(t)}var Bi=`${Hn}/sailor/studio`;function ot(e){return Object.keys(e).length===1?e.base:Mt(e)}function Qn(e){let t=new URL(Bi);return t.searchParams.set("preset",ot(e)),t.searchParams.set("proposed","1"),t.toString()}var it=["packages","design","tokens"],er={theme:["base","brandColor","neutral","radius","density","mode"],fonts:["sans","heading","mono","headingWeight"]};function Wi(e=process.cwd()){let t=e;for(;;){if(Gt(Le(t,...it,"package.json")))return t;let n=Ki(t);if(n===t)return null;t=n}}function Yi(e,t,n){if(!n)return t;let r={...e??{base:"factory"}};for(let o of er[n]){let i=t[o];i===void 0?delete r[o]:r[o]=i}return r}var Ji=e=>e.base==="factory"&&Object.keys(e).length===1;function qi(e,t){let n=Le(e,...it,"project"),r=Le(n,"preset");if(Ji(t))return Vi(r,{force:!0}),{root:e,code:null,preset:t};let o=Mt(t);return Mi(n,{recursive:!0}),zi(r,`${o}
7
+ `),{root:e,code:o,preset:t}}function Hi(e){let t=Le(e,...it,"project","preset");return Gt(t)?De(Gi(t,"utf8")):null}function tr(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 er)&&(d.error(`--only takes "theme" or "fonts", not "${t.only}".`),process.exit(l.INVALID_ARGS));let r;try{r=De(t.preset??"")}catch(a){d.error(a instanceof O?a.message:String(a)),process.exit(l.INVALID_ARGS)}let o=Wi();o||(d.error("Run this inside a Sailor project (no packages/design/tokens found above here)."),process.exit(l.NOT_FOUND)),Gt(Le(o,...it,"project","brand.json"))&&(d.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=qi(o,Yi(Hi(o),r,n));if(t.build!==!1){let a=await R({command:"pnpm",args:["--filter","@nebutra/tokens","build"],cwd:o,label:"Rebuilding the tokens"});a.exitCode!==0&&(d.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}d.success(i.code?`Applied preset ${i.code} (base: ${i.preset.base}).`:"Back to factory: the House tokens, unchanged.")})}function Ue(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 nr(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function Zi(e){d.info("Initializing brand system...");let t=await F("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});Ue(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||d.success("Brand system initialized successfully")}async function Xi(e){d.info("Applying brand configuration...");let t=await F("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});Ue(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||d.success("Brand applied successfully")}async function Qi(e){let t=[];e.primary&&(nr(e.primary)||(d.error(`Invalid primary color format: ${e.primary}. Expected hex format like #0033FE`),process.exit(l.INVALID_ARGS)),t.push(`--primary=${e.primary}`)),e.secondary&&(nr(e.secondary)||(d.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&&(d.warn("No colors specified. Usage: nebutra brand palette --primary=#HEX --secondary=#HEX"),d.info("Example: nebutra brand palette --primary=#0033FE --secondary=#0BF1C3"),process.exit(l.INVALID_ARGS)),d.info(`Generating color palette: ${t.join(" ")}`);let n=await R({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});Ue(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||d.success("Color palette generated successfully")}async function ea(e){d.info("Syncing brand tokens across packages...");let t=await F("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});Ue(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||d.success("Brand tokens synced successfully")}async function ta(e){d.info("Verifying brand token consistency...");let t=await F("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});Ue(t,e.format,"brand:verify-tokens"),t.exitCode!==0&&(d.error("Brand token verification failed. There are inconsistencies in your design tokens."),process.exit(t.exitCode)),e.dryRun||d.success("All brand tokens are consistent")}function rr(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 Zi({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 Xi({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 Qi({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 ea({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 ta({dryRun:n.dryRun||!1,format:n.format||o.format,interactive:o.yes!==!0})})}import{appendFileSync as na,existsSync as ra,readFileSync as oa,writeFileSync as ia}from"fs";import{homedir as Be}from"os";import{join as Pe}from"path";import*as U from"@clack/prompts";import L from"picocolors";var Q={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:"studio",description:"Sailor Studio for agents: preset schema, review link in the browser, pull onto the project",usage:"nebutra studio <schema|preview|list|pull> [preset] [--latest] [--json]"},{name:"admin",description:"Platform administration for platform staff: list, grant and revoke staff access (confirmation required)",usage:"nebutra admin staff <list|whoami|grant <email> --role <role> --note <why>|revoke <email> --note <why>> [--yes] [--json]"},{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 at=(Q.subcommands??[]).map(e=>e.name),or={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",studio:"Sailor Studio for agents: preset schema, review link, pull",admin:"Platform staff administration: list, grant, revoke",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"},aa=["--help","--version","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--json","--no-browser","--poll"],sa=at.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${or[e]}"`).join(`
8
+ `);function ir(){return`#!/usr/bin/env bash
5
9
 
6
10
  _nebutra_completions() {
7
11
  local cur prev opts cmd
@@ -10,10 +14,10 @@ _nebutra_completions() {
10
14
  prev="\${COMP_WORDS[COMP_CWORD-1]}"
11
15
 
12
16
  # Subcommands
13
- local subcommands="${Ve.join(" ")}"
17
+ local subcommands="${at.join(" ")}"
14
18
 
15
19
  # Flags
16
- local flags="${$o.join(" ")}"
20
+ local flags="${aa.join(" ")}"
17
21
 
18
22
  if [[ \${cur} == -* ]]; then
19
23
  # Complete flags
@@ -30,11 +34,11 @@ _nebutra_completions() {
30
34
  }
31
35
 
32
36
  complete -o bashdefault -o default -o nospace -F _nebutra_completions nebutra
33
- `}function cn(){return`#compdef nebutra
37
+ `}function ar(){return`#compdef nebutra
34
38
 
35
39
  _nebutra() {
36
40
  local -a commands=(
37
- ${Ve.map(e=>`"${e}:${an[e]}"`).join(`
41
+ ${at.map(e=>`"${e}:${or[e]}"`).join(`
38
42
  `)}
39
43
  )
40
44
 
@@ -90,12 +94,12 @@ _nebutra() {
90
94
  }
91
95
 
92
96
  _nebutra
93
- `}function ln(){return`# Fish shell completions for nebutra
97
+ `}function sr(){return`# Fish shell completions for nebutra
94
98
 
95
- complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${Ve.join(" ")}" -d "Nebutra governance CLI"
99
+ complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${at.join(" ")}" -d "Nebutra governance CLI"
96
100
 
97
101
  # Subcommands
98
- ${To}
102
+ ${sa}
99
103
 
100
104
  # Flags
101
105
  complete -c nebutra -f -a "--help" -d "Show help message"
@@ -121,24 +125,24 @@ complete -c nebutra -n "__fish_seen_subcommand_from completions" -f -a "install"
121
125
  complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--all" -d "Show full schema for all commands"
122
126
  complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--list" -d "List all available command names"
123
127
  complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--exit-codes" -d "Show exit codes reference"
124
- `}function un(e){let n={bash:sn,zsh:cn,fish:ln}[e.toLowerCase()];n||(console.error(D.red(`Error: Unknown shell '${e}'. Supported: bash, zsh, fish`)),process.exit(c.INVALID_ARGS)),console.log(n())}async function Do(){let t=(process.env.SHELL||"/bin/bash").split("/").pop()||"bash";L.intro(D.bgCyan(D.black(" nebutra completions install ")));let n=L.spinner();n.start(D.cyan(`Detecting shell: ${t}...`));try{let r=null,o=null,i=null;if(t==="bash"?(r=xe(Ne(),".bashrc"),o=xe(Ne(),".bash_completion.d"),i="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=xe(Ne(),".zshrc"),o=xe(Ne(),".zsh/completions"),i="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=xe(Ne(),".config/fish/completions"),i="# Completions installed to ~/.config/fish/completions/nebutra.fish"):(n.stop(),L.log.warn(D.yellow(`Warning: Unsupported shell '${t}'. Please install completions manually.`)),un("bash"),L.outro(D.cyan("Run 'nebutra completions bash' (or zsh/fish) to generate completions for your shell.")),process.exit(c.SUCCESS)),o){(await import("fs")).mkdirSync(o,{recursive:!0});let s=xe(o,t==="fish"?"nebutra.fish":"nebutra"),d=t==="bash"?sn():t==="zsh"?cn():ln();jo(s,d),n.stop(D.green(`Completion script installed to ${s}`))}r&&i&&t!=="fish"&&(!No(r)||!Po(r,"utf8").includes("nebutra"))&&(Io(r,(t==="bash"?`
128
+ `}function cr(e){let n={bash:ir,zsh:ar,fish:sr}[e.toLowerCase()];n||(console.error(L.red(`Error: Unknown shell '${e}'. Supported: bash, zsh, fish`)),process.exit(l.INVALID_ARGS)),console.log(n())}async function ca(){let t=(process.env.SHELL||"/bin/bash").split("/").pop()||"bash";U.intro(L.bgCyan(L.black(" nebutra completions install ")));let n=U.spinner();n.start(L.cyan(`Detecting shell: ${t}...`));try{let r=null,o=null,i=null;if(t==="bash"?(r=Pe(Be(),".bashrc"),o=Pe(Be(),".bash_completion.d"),i="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=Pe(Be(),".zshrc"),o=Pe(Be(),".zsh/completions"),i="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=Pe(Be(),".config/fish/completions"),i="# Completions installed to ~/.config/fish/completions/nebutra.fish"):(n.stop(),U.log.warn(L.yellow(`Warning: Unsupported shell '${t}'. Please install completions manually.`)),cr("bash"),U.outro(L.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=Pe(o,t==="fish"?"nebutra.fish":"nebutra"),c=t==="bash"?ir():t==="zsh"?ar():sr();ia(s,c),n.stop(L.green(`Completion script installed to ${s}`))}r&&i&&t!=="fish"&&(!ra(r)||!oa(r,"utf8").includes("nebutra"))&&(na(r,(t==="bash"?`
125
129
  # nebutra completions
126
130
  [[ -f ~/.bash_completion.d/nebutra ]] && source ~/.bash_completion.d/nebutra`:`
127
131
  # nebutra completions
128
132
  fpath=(~/.zsh/completions $fpath)
129
133
  autoload -Uz compinit && compinit`)+`
130
- `),L.log.info(D.green(`Added nebutra completions to ${r}`))),L.log.info(D.cyan("Completions installed! Restart your shell or run:")),L.log.info(D.dim(` source "${t==="bash"?"~/.bashrc":"~/.zshrc"}"`)),L.outro(D.green("Installation complete!"))}catch(r){n.stop(),L.log.error(D.red("Error installing completions. You can manually add them by running:")),L.log.info(D.cyan(` nebutra completions ${t} >> ~/.${t}rc`)),r instanceof Error&&console.error(D.dim(r.message)),process.exit(c.ERROR)}}function dn(e){e.command("completions [shell]").description("Generate or install shell completions").action(async t=>{!t||t==="install"?await Do():un(t)})}import*as ze from"@clack/prompts";import{stderr as ie,stdout as mn}from"process";import Z from"picocolors";function Lo(){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:Lo()?"plain":"json"}function Fo(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 d of e){let m=String(d[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 d=n.map(m=>String(s[m]??"").padEnd(r[String(m)])).join(" | ");a.push(d)}return a.join(`
131
- `)}function Uo(e){return JSON.stringify(e)}function fn(e){if(!Array.isArray(e))return ht(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return ht(e);let t=Fo(e);return Z.gray(t)}function ht(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"?ie:mn,o;switch(n){case"json":o=Uo(e);break;case"table":o=fn(e);break;default:o=ht(e);break}r.write(o+`
132
- `)}function I(e,t={}){let n=pn(t.format),r;switch(n){case"json":r=JSON.stringify(e);break;case"table":r=fn(e);break;default:r=JSON.stringify(e,null,2);break}mn.write(r+`
133
- `)}function u(e,t="info"){let n;switch(t){case"error":n=Z.red("\u2716");break;case"warn":n=Z.yellow("\u26A0");break;case"success":n=Z.green("\u2713");break;default:n=Z.blue("\u2139");break}let r=`${n} ${e}`;ie.write(r+`
134
- `)}function x(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=Z.dim(`[debug] ${e}`);ie.write(r+`
135
- `),t&&Object.keys(t).length>0&&ie.write(Z.dim(JSON.stringify(t,null,2))+`
136
- `)}function Ke(e){ie.write(`
137
- `),ie.write(Z.bold(Z.cyan(e))+`
138
- `),ie.write(Z.gray("-".repeat(e.length))+`
139
- `),ie.write(`
140
- `)}async function Bo(e){u("Generating Prisma client"+"...","info");let n=await ee("generate",{dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?u("Prisma client generated successfully","success"):(u("Failed to generate Prisma client","error"),process.exit(n.exitCode||1))}async function bt(e,t){let n=t||{};if(e){u(`Creating migration: ${e}`,"info");let r=await ee("migrate",{args:["dev","--name",e],dryRun:n.dryRun,interactive:!n.dryRun});r.exitCode===0?u(`Migration '${e}' created successfully`,"success"):(u(`Failed to create migration '${e}'`,"error"),process.exit(r.exitCode||1))}else{u("Running pending migrations...","info");let r=await ee("migrate",{args:["deploy"],dryRun:n.dryRun,interactive:!n.dryRun});r.exitCode===0?u("All pending migrations completed","success"):(u("Migration deployment failed","error"),process.exit(r.exitCode||1))}}async function Mo(e){u("Pushing schema to database...","info");let t=await ee("db",{args:["push"],dryRun:e.dryRun,interactive:!e.dryRun});t.exitCode===0?u("Schema pushed successfully","success"):(u("Failed to push schema","error"),process.exit(t.exitCode||1))}async function Go(e){u("Seeding database...","info");let t=await ee("db",{args:["seed"],dryRun:e.dryRun,interactive:!e.dryRun});t.exitCode===0?u("Database seeded successfully","success"):(u("Failed to seed database","error"),process.exit(t.exitCode||1))}async function Vo(e){u("Launching Prisma Studio...","info");let t=await ee("studio",{dryRun:e.dryRun,interactive:!0});t.exitCode!==0&&(u("Failed to launch Prisma Studio","error"),process.exit(t.exitCode||1))}async function Ko(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await ze.confirm({message:"Reset database? This will delete all data.",initialValue:!1});(ze.isCancel(r)||!r)&&(u("Reset cancelled","warn"),process.exit(c.CANCELLED))}else u("Database reset requires explicit --yes confirmation (use: nebutra db reset --yes)","error"),process.exit(c.INVALID_ARGS);u("Resetting database...","warn");let n=await ee("migrate",{args:["reset",...e.yes?["--force"]:[]],dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?u("Database reset successfully","success"):(u("Failed to reset database","error"),process.exit(n.exitCode||1))}async function zo(e){u("Checking migration status...","info");let t=await ee("migrate",{args:["status"],dryRun:e.dryRun,interactive:!e.dryRun});if(t.exitCode===0){if(e.format==="json")try{let n=JSON.parse(t.stdout);process.stdout.write(JSON.stringify(n,null,2)+`
141
- `)}catch{process.stdout.write(t.stdout)}}else u("Failed to check migration status","error"),process.exit(t.exitCode||1)}function gn(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)=>{let i=o.optsWithGlobals?.(),a={dryRun:o.dryRun||i?.dryRun,yes:o.yes||i?.yes,format:o.format||i?.format};try{switch(n){case"generate":await Bo(a);break;case"migrate":r.length>0?r[0]==="create"&&r[1]?await bt(r[1],a):await bt(r[0],a):await bt(void 0,a);break;case"push":await Mo(a);break;case"seed":await Go(a);break;case"studio":await Vo(a);break;case"reset":await Ko(a);break;case"status":await zo(a);break;default:u(`Unknown db subcommand: ${n}. Valid commands: generate, migrate, migrate create, push, seed, studio, reset, status`,"error"),process.exit(c.INVALID_ARGS)}}catch(s){let d=s instanceof Error?s.message:String(s);u(`Database command failed: ${d}`,"error"),x("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
134
+ `),U.log.info(L.green(`Added nebutra completions to ${r}`))),U.log.info(L.cyan("Completions installed! Restart your shell or run:")),U.log.info(L.dim(` source "${t==="bash"?"~/.bashrc":"~/.zshrc"}"`)),U.outro(L.green("Installation complete!"))}catch(r){n.stop(),U.log.error(L.red("Error installing completions. You can manually add them by running:")),U.log.info(L.cyan(` nebutra completions ${t} >> ~/.${t}rc`)),r instanceof Error&&console.error(L.dim(r.message)),process.exit(l.ERROR)}}function lr(e){e.command("completions [shell]").description("Generate or install shell completions").action(async t=>{!t||t==="install"?await ca():cr(t)})}import{existsSync as ma,readFileSync as pa}from"fs";import{resolve as fa}from"path";import*as ct from"@clack/prompts";import{stderr as de,stdout as dr}from"process";import ee from"picocolors";function la(){return process.env.NEBUTRA_NON_TTY||process.env.CI||process.env.GITHUB_ACTIONS?!1:process.stderr.isTTY===!0}function ur(e){if(e)return e;let t=process.env.NEBUTRA_OUTPUT_FORMAT;return t&&["json","table","plain"].includes(t)?t:la()?"plain":"json"}function da(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 c of e){let m=String(c[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 c=n.map(m=>String(s[m]??"").padEnd(r[String(m)])).join(" | ");a.push(c)}return a.join(`
135
+ `)}function ua(e){return JSON.stringify(e)}function mr(e){if(!Array.isArray(e))return Vt(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return Vt(e);let t=da(e);return ee.gray(t)}function Vt(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=ur(t?.format),r=t?.stream==="stderr"?de:dr,o;switch(n){case"json":o=ua(e);break;case"table":o=mr(e);break;default:o=Vt(e);break}r.write(o+`
136
+ `)}function N(e,t={}){let n=ur(t.format),r;switch(n){case"json":r=JSON.stringify(e);break;case"table":r=mr(e);break;default:r=JSON.stringify(e,null,2);break}dr.write(r+`
137
+ `)}function u(e,t="info"){let n;switch(t){case"error":n=ee.red("\u2716");break;case"warn":n=ee.yellow("\u26A0");break;case"success":n=ee.green("\u2713");break;default:n=ee.blue("\u2139");break}let r=`${n} ${e}`;de.write(r+`
138
+ `)}function x(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=ee.dim(`[debug] ${e}`);de.write(r+`
139
+ `),t&&Object.keys(t).length>0&&de.write(ee.dim(JSON.stringify(t,null,2))+`
140
+ `)}function st(e){de.write(`
141
+ `),de.write(ee.bold(ee.cyan(e))+`
142
+ `),de.write(ee.gray("-".repeat(e.length))+`
143
+ `),de.write(`
144
+ `)}var K=2e4;function ga(e){if(process.env.DATABASE_URL)return!0;for(let t of[".env.local",".env"]){let n=fa(e,t);if(ma(n))try{let r=pa(n,"utf-8");if(/^DATABASE_URL\s*=\s*\S+/m.test(r))return!0}catch{}}return!1}function Ne(){let e=y();ga(e)||ae("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 ha(e){u("Generating Prisma client"+"...","info");let n=await ne("generate",{dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?u("Prisma client generated successfully","success"):(u("Failed to generate Prisma client","error"),process.exit(n.exitCode||1))}async function zt(e,t){let n=t||{};if(n.dryRun||Ne(),e){u(`Creating migration: ${e}`,"info");let r=await ne("migrate",{args:["dev","--name",e],dryRun:n.dryRun,interactive:!n.dryRun,timeoutMs:n.dryRun?void 0:K});r.timedOut&&ae(`Creating migration '${e}' timed out after ${K}ms.`,"Check that DATABASE_URL points to a reachable database."),r.exitCode===0?u(`Migration '${e}' created successfully`,"success"):(u(`Failed to create migration '${e}'`,"error"),process.exit(r.exitCode||1))}else{u("Running pending migrations...","info");let r=await ne("migrate",{args:["deploy"],dryRun:n.dryRun,interactive:!n.dryRun,timeoutMs:n.dryRun?void 0:K});r.timedOut&&ae(`Migration deploy timed out after ${K}ms.`,"Check that DATABASE_URL points to a reachable database."),r.exitCode===0?u("All pending migrations completed","success"):(u("Migration deployment failed","error"),process.exit(r.exitCode||1))}}async function ya(e){e.dryRun||Ne(),u("Pushing schema to database...","info");let t=await ne("db",{args:["push"],dryRun:e.dryRun,interactive:!e.dryRun,timeoutMs:e.dryRun?void 0:K});t.timedOut&&ae(`Schema push timed out after ${K}ms.`,"Check that DATABASE_URL points to a reachable database."),t.exitCode===0?u("Schema pushed successfully","success"):(u("Failed to push schema","error"),process.exit(t.exitCode||1))}async function ba(e){e.dryRun||Ne(),u("Seeding database...","info");let t=await ne("db",{args:["seed"],dryRun:e.dryRun,interactive:!e.dryRun,timeoutMs:e.dryRun?void 0:K});t.timedOut&&ae(`Seeding timed out after ${K}ms.`,"Check that DATABASE_URL points to a reachable database."),t.exitCode===0?u("Database seeded successfully","success"):(u("Failed to seed database","error"),process.exit(t.exitCode||1))}async function va(e){e.dryRun||Ne(),u("Launching Prisma Studio...","info");let t=await ne("studio",{dryRun:e.dryRun,interactive:!0});t.exitCode!==0&&(u("Failed to launch Prisma Studio","error"),process.exit(t.exitCode||1))}async function wa(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await ct.confirm({message:"Reset database? This will delete all data.",initialValue:!1});(ct.isCancel(r)||!r)&&(u("Reset cancelled","warn"),process.exit(l.CANCELLED))}else u("Database reset requires explicit --yes confirmation (use: nebutra db reset --yes)","error"),process.exit(l.INVALID_ARGS);e.dryRun||Ne(),u("Resetting database...","warn");let n=await ne("migrate",{args:["reset",...e.yes?["--force"]:[]],dryRun:e.dryRun,interactive:!e.dryRun,timeoutMs:e.dryRun?void 0:K});n.timedOut&&ae(`Database reset timed out after ${K}ms.`,"Check that DATABASE_URL points to a reachable database."),n.exitCode===0?u("Database reset successfully","success"):(u("Failed to reset database","error"),process.exit(n.exitCode||1))}async function ka(e){e.dryRun||Ne(),u("Checking migration status...","info");let t=await ne("migrate",{args:["status"],dryRun:e.dryRun,interactive:!1,timeoutMs:e.dryRun?void 0:K});if(t.timedOut&&ae(`\`db status\` timed out after ${K}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)+`
145
+ `)}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 u("Failed to check migration status","error"),t.stderr.trim()&&x("Prisma stderr",{stderr:t.stderr}),process.exit(t.exitCode||1)}function pr(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 ha(s);break;case"migrate":r.length>0?r[0]==="create"&&r[1]?await zt(r[1],s):await zt(r[0],s):await zt(void 0,s);break;case"push":await ya(s);break;case"seed":await ba(s);break;case"studio":await va(s);break;case"reset":await wa(s);break;case"status":await ka(s);break;default:u(`Unknown db subcommand: ${n}. Valid commands: generate, migrate, migrate create, push, seed, studio, reset, status`,"error"),process.exit(l.INVALID_ARGS)}}catch(c){let m=c instanceof Error?c.message:String(c);u(`Database command failed: ${m}`,"error"),x("Full error",{error:c}),process.exit(l.ERROR)}}).addHelpText("after",`
142
146
  Examples:
143
147
  nebutra db generate Generate Prisma client
144
148
  nebutra db migrate Run all pending migrations
@@ -153,15 +157,15 @@ Flags:
153
157
  --dry-run Show what would be run without executing
154
158
  --yes Skip confirmations
155
159
  --format <type> Output format: json, plain (default: plain)
156
- `)}import*as S from"@clack/prompts";import h from"picocolors";function A(e,t){let n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():void 0;return{...t&&typeof t.optsWithGlobals=="function"?t.optsWithGlobals():void 0,...n,...e}}function ae(e){if(e==="json"||e==="plain"||e==="table")return e}var Se=["landing","web","storybook","design-docs","idp","mail-preview","gateway","admin","auth","design","forge","router","pebble","typelens","sailor-docs","studio","sleptons"];function We(e){let t=`@nebutra/${e}`;if(!Se.includes(e)){let n=h.yellow(`Valid apps: ${Se.join(", ")}`);throw new Error(`Invalid app: ${h.red(e)}
157
- ${n}`)}return t}async function Wo(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:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app){We(e.app);let n=`@nebutra/${e.app}`;e.quiet||S.log.info(h.cyan(`Starting dev server for ${h.bold(n)}...`));let r=await re("dev",{filter:n});process.exit(r.exitCode)}e.quiet||S.log.info(h.cyan("Starting dev servers for all apps..."));let t=await re("dev");process.exit(t.exitCode)}catch(t){t instanceof Error?S.log.error(h.red(t.message)):S.log.error(h.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Yo(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:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.strict&&(S.log.error(h.red("Cannot use --strict with --app filter")),process.exit(c.INVALID_ARGS)),e.app){We(e.app);let r=`@nebutra/${e.app}`;e.quiet||S.log.info(h.cyan(`Building ${h.bold(r)}...`));let o=await re("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(h.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?S.log.error(h.red(t.message)):S.log.error(h.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Jo(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:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.fix&&(S.log.error(h.red("Cannot use --fix with --app filter (lint:fix is global only)")),process.exit(c.INVALID_ARGS)),e.app){We(e.app);let r=`@nebutra/${e.app}`;e.quiet||S.log.info(h.cyan(`Linting ${h.bold(r)}...`));let o=await O({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(h.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?S.log.error(h.red(t.message)):S.log.error(h.red("Unknown error occurred")),process.exit(c.ERROR)}}async function qo(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"typecheck",options:{app:e.app},task:"turbo typecheck"},{format:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app){We(e.app);let n=`@nebutra/${e.app}`;e.quiet||S.log.info(h.cyan(`Type-checking ${h.bold(n)}...`));let r=await re("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||S.log.info(h.cyan("Type-checking all packages..."));let t=await re("typecheck");process.exit(t.exitCode)}catch(t){t instanceof Error?S.log.error(h.red(t.message)):S.log.error(h.red("Unknown error occurred")),process.exit(c.ERROR)}}var yn=e=>{e.command("dev").description("Start development servers (turbo dev)").option("--app <name>",`App to run: ${Se.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await Wo({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ae(r.format)})}),e.command("build").description("Build all apps (pnpm build or turbo build)").option("--app <name>",`App to build: ${Se.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 Yo({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,strict:!!t.strict,quiet:!!r.quiet,verbose:!!r.verbose,format:ae(r.format)})}),e.command("lint").description("Lint with Biome (pnpm lint or pnpm lint:fix)").option("--app <name>",`App to lint: ${Se.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 Jo({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,fix:!!t.fix,quiet:!!r.quiet,verbose:!!r.verbose,format:ae(r.format)})}),e.command("typecheck").description("Type-check with TypeScript (turbo typecheck)").option("--app <name>",`App to typecheck: ${Se.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await qo({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ae(r.format)})})};import hn from"fs";import bn from"path";import vt from"picocolors";var wt=["smoke","golden","sleptons"],Ho={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 Zo(e,t={}){wt.includes(e)||(l.error(`Invalid suite: ${vt.red(e)}. Valid: ${wt.join(", ")}`),process.exit(c.INVALID_ARGS));let n=C(),{config:r,suiteDir:o}=Ho[e],i=bn.join(n,r),a=bn.join(n,o);(!hn.existsSync(a)||!hn.existsSync(i))&&(l.error(`Suite ${vt.red(e)} not found at ${o}.
160
+ `)}import*as S from"@clack/prompts";import v from"picocolors";function I(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 $e=["landing","web","storybook","design-docs","idp","mail-preview","gateway","admin","auth","design","forge","router","pebble","typelens","sailor-docs","studio","sleptons"];function lt(e){let t=`@nebutra/${e}`;if(!$e.includes(e)){let n=v.yellow(`Valid apps: ${$e.join(", ")}`);throw new Error(`Invalid app: ${v.red(e)}
161
+ ${n}`)}return t}async function xa(e){e.dryRun&&(N({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){lt(e.app);let n=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Starting dev server for ${v.bold(n)}...`));let r=await se("dev",{filter:n});process.exit(r.exitCode)}e.quiet||S.log.info(v.cyan("Starting dev servers for all apps..."));let t=await se("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 Ca(e){e.dryRun&&(N({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){lt(e.app);let r=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Building ${v.bold(r)}...`));let o=await se("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 F(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 Sa(e){e.dryRun&&(N({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){lt(e.app);let r=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Linting ${v.bold(r)}...`));let o=await R({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 F(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 Ra(e){e.dryRun&&(N({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){lt(e.app);let n=`@nebutra/${e.app}`;e.quiet||S.log.info(v.cyan(`Type-checking ${v.bold(n)}...`));let r=await se("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||S.log.info(v.cyan("Type-checking all packages..."));let t=await se("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 fr=e=>{e.command("dev").description("Start development servers (turbo dev)").option("--app <name>",`App to run: ${$e.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=I(t,n);await xa({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: ${$e.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=I(t,n);await Ca({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: ${$e.join(", ")}`).option("--fix","Fix linting issues automatically").option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=I(t,n);await Sa({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: ${$e.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=I(t,n);await Ra({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ue(r.format)})})};import gr from"fs";import hr from"path";import Kt from"picocolors";var Wt=["smoke","golden","sleptons"],Ea={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 Oa(e,t={}){Wt.includes(e)||(d.error(`Invalid suite: ${Kt.red(e)}. Valid: ${Wt.join(", ")}`),process.exit(l.INVALID_ARGS));let n=y(),{config:r,suiteDir:o}=Ea[e],i=hr.join(n,r),a=hr.join(n,o);(!gr.existsSync(a)||!gr.existsSync(i))&&(d.error(`Suite ${Kt.red(e)} not found at ${o}.
158
162
  Expected config: ${r}
159
163
  Remediation: scaffold the suite (analogous to 'nebutra workflow init <provider>')
160
- or restore the directory from git.`),process.exit(c.NOT_FOUND)),t.dryRun&&(I({mode:"dry-run",command:`e2e ${e}`,task:`pnpm exec playwright test --config ${r}`}),process.exit(c.DRY_RUN_OK)),t.quiet||l.info(`Running Playwright suite: ${vt.bold(e)}`);let s=await O({command:"pnpm",args:["exec","playwright","test","--config",r],interactive:!0,label:`playwright ${e}`});process.exit(s.exitCode)}var vn=e=>{e.command("e2e <suite>").description(`Run a Playwright suite (${wt.join(" | ")})`).option("--dry-run","Preview the command that would run (exit code 10)").action(async(t,n,r)=>{let o=A(n,r);await Zo(t,{dryRun:!!n.dryRun,quiet:!!o.quiet})})};import{existsSync as Ye,readFileSync as wn,writeFileSync as Xo}from"fs";import{resolve as Je}from"path";import*as me from"@clack/prompts";import Qo from"picocolors";function qe(e){let t=Je(e,".env.example");if(!Ye(t))throw new Error(`.env.example not found at ${t}`);let n=wn(t,"utf-8"),r={};for(let o of n.split(`
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 Ct(e){let t=Je(e,".env.local"),n=Je(e,".env"),r=Ye(t)?t:n;if(!Ye(r))return{};let o=wn(r,"utf-8"),i={};for(let a of o.split(`
162
- `)){if(a.trim().startsWith("#")||!a.trim())continue;let s=a.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(s){let[,d,m]=s;i[d]=m.replace(/^["'](.*)["']$/,"$1")}}return i}function ei(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function ti(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 ni(e){u("Validating environment variables...","info");let t=C(),n=qe(t),r=Ct(t),o=process.env,i={},a=!0;for(let s of Object.keys(n)){let d=s in r||s in o;i[s]=d,d||(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{Ke("Environment Validation");let s=Object.entries(i).filter(([,d])=>!d).map(([d])=>d);if(s.length===0)u("All required environment variables are set","success");else{u(`${s.length} missing environment variable(s):`,"warn");for(let d of s)u(` - ${d}`,"warn")}}a||process.exit(c.CONFIG_ERROR)}async function ri(e){let t=C(),n=qe(t),r=Je(t,".env.local");if(Ye(r)&&!e.yes&&!e.dryRun){let d=await me.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(me.isCancel(d)||!d)&&(u("Template generation cancelled","warn"),process.exit(c.CANCELLED))}u("Generating .env.local from template...","info");let o={},i=0,a=Object.keys(n).length;for(let[d,m]of Object.entries(n))if(i++,e.yes)o[d]=m;else if(process.stdin.isTTY===!0){let p=`[${i}/${a}] ${d}`,g=await me.text({message:p,defaultValue:m});me.isCancel(g)&&(u("Template generation cancelled","warn"),process.exit(c.CANCELLED)),o[d]=g}else o[d]=m;let s=Object.entries(o).map(([d,m])=>{let g=/[\s=]/.test(m)?`"${m}"`:m;return`${d}=${g}`}).join(`
163
- `);e.dryRun?(u("Dry-run: would write .env.local","info"),b(s,{format:"plain"})):(Xo(r,s+`
164
- `),u(`Environment template written to ${r}`,"success"))}async function oi(e){u("Comparing environment variables...","info");let t=C(),n=qe(t),r=Ct(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(Ke("Environment Diff"),a.length>0&&u(`Matching (${a.length}): ${a.join(", ")}`,"success"),o.length>0){u(`Missing (${o.length}):`,"warn");for(let s of o)u(` - ${s}`,"warn")}if(i.length>0){u(`Extra (${i.length}):`,"info");for(let s of i)u(` - ${s}`,"info")}}}async function ii(e){u("Reading environment variables...","info");let t=C(),n=Ct(t),r=qe(t),o={};for(let i of Object.keys(r))if(i in n){let a=n[i];o[i]=ei(i,a)?ti(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{Ke("Current Environment Variables");let i=Object.entries(o).map(([a,s])=>({Variable:Qo.cyan(a),Value:s}));b(i,{format:"table"}),u("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function Cn(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)=>{let o=r.optsWithGlobals?.(),i={dryRun:r.dryRun||o?.dryRun,yes:r.yes||o?.yes,format:r.format||o?.format};try{switch(n){case"validate":await ni(i);break;case"template":await ri(i);break;case"diff":await oi(i);break;case"show":await ii(i);break;default:u(`Unknown env subcommand: ${n}. Valid commands: validate, template, diff, show`,"error"),process.exit(c.INVALID_ARGS)}}catch(a){let s=a instanceof Error?a.message:String(a);u(`Environment command failed: ${s}`,"error"),x("Full error",{error:a}),process.exit(c.ERROR)}}).addHelpText("after",`
164
+ or restore the directory from git.`),process.exit(l.NOT_FOUND)),t.dryRun&&(N({mode:"dry-run",command:`e2e ${e}`,task:`pnpm exec playwright test --config ${r}`}),process.exit(l.DRY_RUN_OK)),t.quiet||d.info(`Running Playwright suite: ${Kt.bold(e)}`);let s=await R({command:"pnpm",args:["exec","playwright","test","--config",r],interactive:!0,label:`playwright ${e}`});process.exit(s.exitCode)}var yr=e=>{e.command("e2e <suite>").description(`Run a Playwright suite (${Wt.join(" | ")})`).option("--dry-run","Preview the command that would run (exit code 10)").action(async(t,n,r)=>{let o=I(n,r);await Oa(t,{dryRun:!!n.dryRun,quiet:!!o.quiet})})};import{existsSync as dt,readFileSync as br,writeFileSync as Aa}from"fs";import{resolve as ut}from"path";import*as we from"@clack/prompts";import _a from"picocolors";function mt(e){let t=ut(e,".env.example");if(!dt(t))throw new Error(`.env.example not found at ${t}`);let n=br(t,"utf-8"),r={};for(let o of n.split(`
165
+ `)){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 Yt(e){let t=ut(e,".env.local"),n=ut(e,".env"),r=dt(t)?t:n;if(!dt(r))return{};let o=br(r,"utf-8"),i={};for(let a of o.split(`
166
+ `)){if(a.trim().startsWith("#")||!a.trim())continue;let s=a.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(s){let[,c,m]=s;i[c]=m.replace(/^["'](.*)["']$/,"$1")}}return i}function Ia(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function Pa(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 Na(e){u("Validating environment variables...","info");let t=y(),n=mt(t),r=Yt(t),o=process.env,i={},a=!0;for(let s of Object.keys(n)){let c=s in r||s in o;i[s]=c,c||(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{st("Environment Validation");let s=Object.entries(i).filter(([,c])=>!c).map(([c])=>c);if(s.length===0)u("All required environment variables are set","success");else{u(`${s.length} missing environment variable(s):`,"warn");for(let c of s)u(` - ${c}`,"warn")}}a||process.exit(l.CONFIG_ERROR)}async function $a(e){let t=y(),n=mt(t),r=ut(t,".env.local");if(dt(r)&&!e.yes&&!e.dryRun){let c=await we.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(we.isCancel(c)||!c)&&(u("Template generation cancelled","warn"),process.exit(l.CANCELLED))}u("Generating .env.local from template...","info");let o={},i=0,a=Object.keys(n).length;for(let[c,m]of Object.entries(n))if(i++,e.yes)o[c]=m;else if(process.stdin.isTTY===!0){let p=`[${i}/${a}] ${c}`,g=await we.text({message:p,defaultValue:m});we.isCancel(g)&&(u("Template generation cancelled","warn"),process.exit(l.CANCELLED)),o[c]=g}else o[c]=m;let s=Object.entries(o).map(([c,m])=>{let g=/[\s=]/.test(m)?`"${m}"`:m;return`${c}=${g}`}).join(`
167
+ `);e.dryRun?(u("Dry-run: would write .env.local","info"),b(s,{format:"plain"})):(Aa(r,s+`
168
+ `),u(`Environment template written to ${r}`,"success"))}async function ja(e){u("Comparing environment variables...","info");let t=y(),n=mt(t),r=Yt(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(st("Environment Diff"),a.length>0&&u(`Matching (${a.length}): ${a.join(", ")}`,"success"),o.length>0){u(`Missing (${o.length}):`,"warn");for(let s of o)u(` - ${s}`,"warn")}if(i.length>0){u(`Extra (${i.length}):`,"info");for(let s of i)u(` - ${s}`,"info")}}}async function Ta(e){u("Reading environment variables...","info");let t=y(),n=Yt(t),r=mt(t),o={};for(let i of Object.keys(r))if(i in n){let a=n[i];o[i]=Ia(i,a)?Pa(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{st("Current Environment Variables");let i=Object.entries(o).map(([a,s])=>({Variable:_a.cyan(a),Value:s}));b(i,{format:"table"}),u("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function vr(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 Na(a);break;case"template":await $a(a);break;case"diff":await ja(a);break;case"show":await Ta(a);break;default:u(`Unknown env subcommand: ${n}. Valid commands: validate, template, diff, show`,"error"),process.exit(l.INVALID_ARGS)}}catch(s){let c=s instanceof Error?s.message:String(s);u(`Environment command failed: ${c}`,"error"),x("Full error",{error:s}),process.exit(l.ERROR)}}).addHelpText("after",`
165
169
  Examples:
166
170
  nebutra env validate Check all required vars are set
167
171
  nebutra env template Generate .env.local from .env.example with prompts
@@ -178,7 +182,7 @@ Flags:
178
182
  Sensitive Variables:
179
183
  Variables with KEY, TOKEN, SECRET, PASSWORD in their names are masked in output.
180
184
  This prevents accidental exposure of credentials.
181
- `)}import{promises as xn}from"fs";import{join as pe}from"path";import*as je from"@clack/prompts";import _ from"picocolors";var Pe=["design","iam","commerce","integrations","platform","ops","ai"];function ai(e){return Pe.includes(e)}function xt(e,t){if(!t)throw new Error(`--category is required. Valid categories: ${Pe.join(", ")}. Example: nebutra generate package ${e} --category iam`);if(!ai(t))throw new Error(`Unknown category "${t}". Valid categories: ${Pe.join(", ")}.`);return`packages/${t}/${e}`}function Sn(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
185
+ `)}import{promises as wr}from"fs";import{join as ke}from"path";import*as Ge from"@clack/prompts";import P from"picocolors";var Me=["design","iam","commerce","integrations","platform","ops","ai"];function Fa(e){return Me.includes(e)}function Jt(e,t){if(!t)throw new Error(`--category is required. Valid categories: ${Me.join(", ")}. Example: nebutra generate package ${e} --category iam`);if(!Fa(t))throw new Error(`Unknown category "${t}". Valid categories: ${Me.join(", ")}.`);return`packages/${t}/${e}`}function kr(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
182
186
  "name": "@nebutra/${e}",
183
187
  "version": "0.0.0",
184
188
  "private": true,
@@ -263,7 +267,7 @@ export default function RootLayout({
263
267
 
264
268
  @theme {
265
269
  --color-*: var(--neutral-*);
266
- }`}}function En(e){return{"package.json":`{
270
+ }`}}function xr(e){return{"package.json":`{
267
271
  "name": "@nebutra/${e}",
268
272
  "version": "0.0.0",
269
273
  "type": "module",
@@ -300,7 +304,7 @@ export default function RootLayout({
300
304
 
301
305
  export function hello(name: string): string {
302
306
  return \`Hello, \${name}!\`;
303
- }`}}function Rn(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
307
+ }`}}function Cr(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
304
308
  import { z } from "zod";
305
309
 
306
310
  type Env = {
@@ -351,7 +355,7 @@ app.post("/", async (c) => {
351
355
  );
352
356
  });
353
357
 
354
- export default app;`}}function kn(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";
358
+ export default app;`}}function Sr(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
359
  import { cn } from "@nebutra/ui/utils";
356
360
 
357
361
  const ${t}Variants = cva(
@@ -425,13 +429,13 @@ export const AllSizes: Story = {
425
429
  <${n} size="lg">Large</\${pascalCase}>
426
430
  </div>
427
431
  ),
428
- };`}}async function He(e,t,n){let r=C(),o=[],i={};switch(e){case"app":i=Sn(t);break;case"package":i=En(t);break;case"route":i=Rn(t);break;case"component":i=kn(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let a=e==="package"?xt(t,n.category):void 0;for(let[s,d]of Object.entries(i)){let m=e==="app"?pe(r,"apps",t,s):e==="package"?pe(r,a??`packages/${t}`,s):pe(r,"backends/gateway",s);o.push({path:m,size:Buffer.byteLength(d)})}return o}async function Ze(e,t,n={}){let r=C(),o=[],i={};switch(e){case"app":i=Sn(t);break;case"package":i=En(t);break;case"route":i=Rn(t);break;case"component":i=kn(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let a=e==="package"?xt(t,n.category):void 0;for(let[s,d]of Object.entries(i)){let m;e==="app"?m=pe(r,"apps",t,s):e==="package"?m=pe(r,a??`packages/${t}`,s):e==="component"?m=pe(r,"packages/design/ui",s):m=pe(r,"backends/gateway",s);let p=m.substring(0,m.lastIndexOf("/"));await xn.mkdir(p,{recursive:!0}),await xn.writeFile(m,d,"utf-8"),o.push(m)}return o}async function si(e,t){if(t.dryRun){let r=await He("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)+`
429
- `),process.exit(c.DRY_RUN_OK)}je.intro(_.bgCyan(_.black(" nebutra generate app ")));let n=l.spinner();try{n.start(`Generating app ${_.cyan(e)}...`);let r=await Ze("app",e);n.stop(`Created app ${_.cyan(e)}`,0),l.success(`App created with ${r.length} files`),l.info("Next steps:"),l.info(` cd apps/${e}`),l.info(" pnpm install"),l.info(" pnpm run dev"),process.exit(c.SUCCESS)}catch(r){n.stop(`Failed to generate app: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function ci(e,t){let n;try{n=xt(e,t.category)}catch(o){l.error(o instanceof Error?o.message:String(o)),process.exit(c.INVALID_ARGS)}if(t.dryRun){let o=await He("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)+`
430
- `),process.exit(c.DRY_RUN_OK)}je.intro(_.bgCyan(_.black(" nebutra generate package ")));let r=l.spinner();try{r.start(`Generating package ${_.cyan(e)} in ${_.dim(n)}...`);let o=await Ze("package",e,{category:t.category});r.stop(`Created package ${_.cyan(e)}`,0),l.success(`Package created with ${o.length} files`),l.info("Next steps:"),l.info(` Edit ${n}/src/index.ts`),l.info(` Run: pnpm --filter @nebutra/${e} build`),process.exit(c.SUCCESS)}catch(o){r.stop(`Failed to generate package: ${o instanceof Error?o.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function li(e,t){if(t.dryRun){let r=await He("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)+`
431
- `),process.exit(c.DRY_RUN_OK)}je.intro(_.bgCyan(_.black(" nebutra generate route ")));let n=l.spinner();try{n.start(`Generating route ${_.cyan(e)}...`);let r=await Ze("route",e);n.stop(`Created route ${_.cyan(e)}`,0),l.success(`Route created with ${r.length} files`),l.info(`File: backends/gateway/src/routes/${e}.ts`),l.info(`Add to your main app.ts: app.route("/${e}", routes)`),process.exit(c.SUCCESS)}catch(r){n.stop(`Failed to generate route: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function ui(e,t){if(t.dryRun){let r=await He("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)+`
432
- `),process.exit(c.DRY_RUN_OK)}je.intro(_.bgCyan(_.black(" nebutra generate component ")));let n=l.spinner();try{n.start(`Generating component ${_.cyan(e)}...`);let r=await Ze("component",e);n.stop(`Created component ${_.cyan(e)}`,0),l.success(`Component created with ${r.length} files`),l.info("Files created in packages/design/ui/src/components/"),l.info("Next steps:"),l.info(" 1. Add export to packages/design/ui/src/components/index.ts"),l.info(" 2. pnpm --filter @nebutra/ui typecheck"),l.info(" 3. pnpm --filter @nebutra/storybook dev"),process.exit(c.SUCCESS)}catch(r){n.stop(`Failed to generate component: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(c.ERROR)}}var On=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 si(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: ${Pe.join(", ")}`).requiredOption("--category <category>",`Package category: ${Pe.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 ci(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 li(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 ui(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 St,{lstatSync as di,readdirSync as Et,readFileSync as mi,writeFileSync as pi}from"fs";import X from"path";import{fileURLToPath as fi}from"url";import U from"picocolors";var gi=X.dirname(fi(import.meta.url));function Rt(){let e=new Map,t=X.join(gi,"../../../apps");if(!St.existsSync(t))return e;try{let n=Et(t);for(let r of n){let o=X.join(t,r),i=X.join(o,"messages");St.existsSync(i)&&di(i).isDirectory()&&e.set(r,i)}}catch(n){l.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function $e(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=$e(o,i);for(let s of a)n.add(s)}else n.add(i)}return n}function Te(e){try{let t=mi(e,"utf-8");return JSON.parse(t)}catch(t){return l.debug(`Failed to parse ${e}: ${t instanceof Error?t.message:String(t)}`),null}}async function yi(e){if(l.info("Syncing language files across the project..."),(await $("translate",{filter:"landing",dryRun:e.dryRun,interactive:e.interactive??!0})).exitCode!==0){l.warn("Landing page translate script not found or failed. Trying sync-lang.mjs...");let n=await O({command:"node",args:["scripts/sync-lang.mjs"],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Sync language files"});n.exitCode!==0&&(l.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||l.success("Language files synced successfully")}else e.format==="json"?console.log(JSON.stringify({command:"i18n:sync",exitCode:0,success:!0},null,2)):e.dryRun||l.success("Language files synced successfully")}async function hi(e){l.info("Validating translation files...");let t=Rt();t.size===0&&(l.warn("No message directories found in the project"),process.exit(c.NOT_FOUND));let n=new Map,r=!1;for(let[o,i]of t){let a=[];try{let s=Et(i).filter(g=>g.endsWith(".json"));if(s.length===0)continue;let d=X.join(i,"en.json"),m=Te(d);if(!m){l.warn(`Could not load reference locale en.json from ${o}`);continue}let p=$e(m);for(let g of s){if(g==="en.json")continue;let y=g.replace(".json",""),f=X.join(i,g),v=Te(f);if(!v){l.debug(`Could not parse ${g}`);continue}let T=$e(v),w=Array.from(p).filter(F=>!T.has(F)),z=Array.from(T).filter(F=>!p.has(F)),Q=p.size>0?(p.size-w.length)/p.size*100:100;(w.length>0||z.length>0)&&(r=!0),a.push({locale:y,totalKeys:p.size,missingKeys:w,extraKeys:z,coverage:Math.round(Q*100)/100})}a.length>0&&n.set(o,a)}catch(s){l.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){l.info(`${U.bold(o)}:`);for(let a of i){let d=(a.coverage>=100?U.green:a.coverage>=80?U.yellow:U.red)(`${a.coverage}%`);l.info(` ${U.cyan(a.locale.padEnd(5))} ${d.padEnd(20)} [${a.totalKeys} keys]`),a.missingKeys.length>0&&l.warn(` Missing: ${a.missingKeys.slice(0,5).join(", ")}${a.missingKeys.length>5?` (+ ${a.missingKeys.length-5} more)`:""}`),a.extraKeys.length>0&&l.warn(` Extra: ${a.extraKeys.slice(0,5).join(", ")}${a.extraKeys.length>5?` (+ ${a.extraKeys.length-5} more)`:""}`)}}r&&process.exit(c.CONFLICT)}async function bi(e,t){/^[a-z]{2}(-[A-Z]{2})?$/.test(e)||(l.error(`Invalid locale format: ${e}. Use 'en', 'es', 'zh-CN', etc.`),process.exit(c.INVALID_ARGS));let n=Rt();n.size===0&&(l.error("No message directories found in the project"),process.exit(c.NOT_FOUND));let r=[],o=!1;for(let[a,s]of n){let d=X.join(s,`${e}.json`);if(St.existsSync(d)){l.warn(`Locale ${e} already exists in ${a}`);continue}try{let y=function(f){for(let v in f)typeof f[v]=="string"?f[v]="":typeof f[v]=="object"&&f[v]!==null&&y(f[v])};var i=y;let m=X.join(s,"en.json"),p=Te(m);if(!p){l.warn(`Could not load reference en.json from ${a}, skipping...`);continue}let g=JSON.parse(JSON.stringify(p));y(g),t.dryRun?l.info(`Would create ${e} locale in ${a}`):(pi(d,JSON.stringify(g,null,2)+`
433
- `),r.push({app:a,path:d}),l.success(`Created ${e} locale in ${a}`))}catch(m){l.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||l.success(`Locale '${e}' added to ${r.length} app(s)`),o&&process.exit(c.ERROR)}async function vi(e){l.info("Checking translation coverage...");let t=Rt();t.size===0&&(l.warn("No message directories found in the project"),process.exit(c.NOT_FOUND));let n=new Map,r=0,o=0;for(let[i,a]of t){let s=[];try{let d=Et(a).filter(y=>y.endsWith(".json"));if(d.length===0)continue;let m=X.join(a,"en.json"),p=Te(m);if(!p){l.debug(`Could not load reference locale from ${i}`);continue}let g=$e(p);for(let y of d){let f=y.replace(".json",""),v=X.join(a,y),T=Te(v);if(!T)continue;let w=$e(T),z=Array.from(w).filter(we=>{let Be=T[we.split(".")[0]];return Be!==void 0&&Be!==""}).length,Q=g.size-z,F=g.size>0?z/g.size*100:0;s.push({locale:f,coverage:Math.round(F*100)/100,totalKeys:g.size,translatedKeys:z,missingKeys:Q})}s.length>0&&(n.set(i,s),o++,r+=s.reduce((y,f)=>y+f.coverage,0)/s.length)}catch(d){l.debug(`Error checking status for ${i}: ${d instanceof Error?d.message:String(d)}`)}}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,d])=>(a[s]=d,a),{})};console.log(JSON.stringify(i,null,2))}else{for(let[i,a]of n){l.info(`${U.bold(i)}:`);for(let s of a){let d="",p=Math.round(s.coverage/100*20);d="\u2588".repeat(p)+"\u2591".repeat(20-p);let y=(s.coverage>=100?U.green:s.coverage>=80?U.yellow:U.red)(`${s.coverage.toFixed(1)}%`);l.info(` ${U.cyan(s.locale.padEnd(5))} [${d}] ${y}`),l.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;l.info(`
434
- Average coverage: ${a(i.toFixed(1)+"%")}`)}}}function An(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=>{let r=n.optsWithGlobals?.()||n;await yi({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.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=>{let r=n.optsWithGlobals?.()||n;await hi({format:n.format||r.format,interactive:r.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)=>{let o=r.optsWithGlobals?.()||r;await bi(n,{dryRun:r.dryRun||!1,format:r.format||o.format,interactive:o.yes!==!0})}),t.command("status").description("Show translation coverage per locale and app").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await vi({format:n.format||r.format,interactive:r.yes!==!0})})}import*as Xe from"@clack/prompts";async function wi(e){let t=e.lite?"docker-compose.lite.yml":void 0,n=e.lite?"Starting lite stack (PostgreSQL + Redis)":"Starting full stack";u(n+"...","info");let r=await Ce("up -d",{file:t,profile:e.profile,dryRun:e.dryRun});r.exitCode===0?u("Infrastructure stack started successfully","success"):(u("Failed to start infrastructure stack","error"),x("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function Ci(e){u("Stopping infrastructure stack...","info");let t=await Ce("down",{dryRun:e.dryRun});t.exitCode===0?u("Infrastructure stack stopped","success"):(u("Failed to stop infrastructure stack","error"),x("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}async function xi(e){u("Checking infrastructure status...","info");let t=await Ce("ps --format json",{dryRun:e.dryRun});if(t.exitCode===0)try{let n=JSON.parse(t.stdout);if(e.format==="json")b(n,{format:"json"});else{let r=n.map(o=>({name:o.Name,status:o.Status,ports:o.Ports||"-"}));b(r,{format:"table"})}}catch{b(t.stdout,{format:"plain"})}else u("Failed to check infrastructure status","error"),x("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}async function Si(e,t){let n=t||{},r=e?`Fetching logs for ${e}...`:"Fetching infrastructure logs...";u(r,"info");let o=["logs","--tail","50"];e&&o.push(e);let i=await Ce(o.join(" "),{dryRun:n.dryRun});i.exitCode===0?b(i.stdout,{format:"plain"}):(u("Failed to fetch logs","error"),x("Docker compose output",{stderr:i.stderr}),process.exit(i.exitCode||1))}async function Ei(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 infrastructure? This will remove all containers and volumes.",initialValue:!1});(Xe.isCancel(r)||!r)&&(u("Reset cancelled","warn"),process.exit(c.CANCELLED))}else u("Infrastructure reset requires explicit --yes confirmation (use: nebutra infra reset --yes)","error"),process.exit(c.INVALID_ARGS);u("Resetting infrastructure stack...","warn");let n=await Ce("down -v",{dryRun:e.dryRun});n.exitCode===0?u("Infrastructure reset successfully","success"):(u("Failed to reset infrastructure","error"),x("Docker compose output",{stderr:n.stderr}),process.exit(n.exitCode||1))}function _n(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)=>{let i=o.optsWithGlobals?.(),a={dryRun:o.dryRun||i?.dryRun,yes:o.yes||i?.yes,format:o.format||i?.format,lite:o.lite||!1,profile:o.profile};try{switch(n){case"up":await wi(a);break;case"down":await Ci(a);break;case"status":await xi(a);break;case"logs":await Si(r,a);break;case"reset":await Ei(a);break;default:u(`Unknown infra subcommand: ${n}. Valid commands: up, down, status, logs, reset`,"error"),process.exit(c.INVALID_ARGS)}}catch(s){let d=s instanceof Error?s.message:String(s);u(`Infrastructure command failed: ${d}`,"error"),x("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
432
+ };`}}async function pt(e,t,n){let r=y(),o=[],i={};switch(e){case"app":i=kr(t);break;case"package":i=xr(t);break;case"route":i=Cr(t);break;case"component":i=Sr(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let a=e==="package"?Jt(t,n.category):void 0;for(let[s,c]of Object.entries(i)){let m=e==="app"?ke(r,"apps",t,s):e==="package"?ke(r,a??`packages/${t}`,s):ke(r,"backends/gateway",s);o.push({path:m,size:Buffer.byteLength(c)})}return o}async function ft(e,t,n={}){let r=y(),o=[],i={};switch(e){case"app":i=kr(t);break;case"package":i=xr(t);break;case"route":i=Cr(t);break;case"component":i=Sr(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let a=e==="package"?Jt(t,n.category):void 0;for(let[s,c]of Object.entries(i)){let m;e==="app"?m=ke(r,"apps",t,s):e==="package"?m=ke(r,a??`packages/${t}`,s):e==="component"?m=ke(r,"packages/design/ui",s):m=ke(r,"backends/gateway",s);let p=m.substring(0,m.lastIndexOf("/"));await wr.mkdir(p,{recursive:!0}),await wr.writeFile(m,c,"utf-8"),o.push(m)}return o}async function Da(e,t){if(t.dryRun){let r=await pt("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)+`
433
+ `),process.exit(l.DRY_RUN_OK)}Ge.intro(P.bgCyan(P.black(" nebutra generate app ")));let n=d.spinner();try{n.start(`Generating app ${P.cyan(e)}...`);let r=await ft("app",e);n.stop(`Created app ${P.cyan(e)}`,0),d.success(`App created with ${r.length} files`),d.info("Next steps:"),d.info(` cd apps/${e}`),d.info(" pnpm install"),d.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 La(e,t){let n;try{n=Jt(e,t.category)}catch(o){d.error(o instanceof Error?o.message:String(o)),process.exit(l.INVALID_ARGS)}if(t.dryRun){let o=await pt("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)+`
434
+ `),process.exit(l.DRY_RUN_OK)}Ge.intro(P.bgCyan(P.black(" nebutra generate package ")));let r=d.spinner();try{r.start(`Generating package ${P.cyan(e)} in ${P.dim(n)}...`);let o=await ft("package",e,{category:t.category});r.stop(`Created package ${P.cyan(e)}`,0),d.success(`Package created with ${o.length} files`),d.info("Next steps:"),d.info(` Edit ${n}/src/index.ts`),d.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 Ua(e,t){if(t.dryRun){let r=await pt("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)+`
435
+ `),process.exit(l.DRY_RUN_OK)}Ge.intro(P.bgCyan(P.black(" nebutra generate route ")));let n=d.spinner();try{n.start(`Generating route ${P.cyan(e)}...`);let r=await ft("route",e);n.stop(`Created route ${P.cyan(e)}`,0),d.success(`Route created with ${r.length} files`),d.info(`File: backends/gateway/src/routes/${e}.ts`),d.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 Ba(e,t){if(t.dryRun){let r=await pt("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)+`
436
+ `),process.exit(l.DRY_RUN_OK)}Ge.intro(P.bgCyan(P.black(" nebutra generate component ")));let n=d.spinner();try{n.start(`Generating component ${P.cyan(e)}...`);let r=await ft("component",e);n.stop(`Created component ${P.cyan(e)}`,0),d.success(`Component created with ${r.length} files`),d.info("Files created in packages/design/ui/src/components/"),d.info("Next steps:"),d.info(" 1. Add export to packages/design/ui/src/components/index.ts"),d.info(" 2. pnpm --filter @nebutra/ui typecheck"),d.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 Rr=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=I(r,o);await Da(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: ${Me.join(", ")}`).requiredOption("--category <category>",`Package category: ${Me.join(" | ")}`).option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r,o)=>{let i=I(r,o);await La(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=I(r,o);await Ua(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=I(r,o);await Ba(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 qt,{lstatSync as Ma,readdirSync as Ht,readFileSync as Ga,writeFileSync as Va}from"fs";import oe from"path";import G from"picocolors";function Zt(){let e=new Map,t=oe.join(y(),"apps");if(!qt.existsSync(t))return e;try{let n=Ht(t);for(let r of n){let o=oe.join(t,r),i=oe.join(o,"messages");qt.existsSync(i)&&Ma(i).isDirectory()&&e.set(r,i)}}catch(n){d.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function Ve(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=Ve(o,i);for(let s of a)n.add(s)}else n.add(i)}return n}function ze(e){try{let t=Ga(e,"utf-8");return JSON.parse(t)}catch(t){return d.debug(`Failed to parse ${e}: ${t instanceof Error?t.message:String(t)}`),null}}async function za(e){if(d.info("Syncing language files across the project..."),(await F("translate",{filter:"landing",dryRun:e.dryRun,interactive:e.interactive??!0})).exitCode!==0){d.warn("Landing page translate script not found or failed. Trying sync-lang.mjs...");let n=await R({command:"node",args:["scripts/sync-lang.mjs"],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Sync language files"});n.exitCode!==0&&(d.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||d.success("Language files synced successfully")}else e.format==="json"?console.log(JSON.stringify({command:"i18n:sync",exitCode:0,success:!0},null,2)):e.dryRun||d.success("Language files synced successfully")}async function Ka(e){d.info("Validating translation files...");let t=Zt();t.size===0&&(d.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=Ht(i).filter(g=>g.endsWith(".json"));if(s.length===0)continue;let c=oe.join(i,"en.json"),m=ze(c);if(!m){d.warn(`Could not load reference locale en.json from ${o}`);continue}let p=Ve(m);for(let g of s){if(g==="en.json")continue;let h=g.replace(".json",""),f=oe.join(i,g),w=ze(f);if(!w){d.debug(`Could not parse ${g}`);continue}let D=Ve(w),k=Array.from(p).filter(B=>!D.has(B)),J=Array.from(D).filter(B=>!p.has(B)),te=p.size>0?(p.size-k.length)/p.size*100:100;(k.length>0||J.length>0)&&(r=!0),a.push({locale:h,totalKeys:p.size,missingKeys:k,extraKeys:J,coverage:Math.round(te*100)/100})}a.length>0&&n.set(o,a)}catch(s){d.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){d.info(`${G.bold(o)}:`);for(let a of i){let c=(a.coverage>=100?G.green:a.coverage>=80?G.yellow:G.red)(`${a.coverage}%`);d.info(` ${G.cyan(a.locale.padEnd(5))} ${c.padEnd(20)} [${a.totalKeys} keys]`),a.missingKeys.length>0&&d.warn(` Missing: ${a.missingKeys.slice(0,5).join(", ")}${a.missingKeys.length>5?` (+ ${a.missingKeys.length-5} more)`:""}`),a.extraKeys.length>0&&d.warn(` Extra: ${a.extraKeys.slice(0,5).join(", ")}${a.extraKeys.length>5?` (+ ${a.extraKeys.length-5} more)`:""}`)}}r&&process.exit(l.CONFLICT)}async function Wa(e,t){/^[a-z]{2}(-[A-Z]{2})?$/.test(e)||(d.error(`Invalid locale format: ${e}. Use 'en', 'es', 'zh-CN', etc.`),process.exit(l.INVALID_ARGS));let n=Zt();n.size===0&&(d.error("No message directories found in the project"),process.exit(l.NOT_FOUND));let r=[],o=!1;for(let[a,s]of n){let c=oe.join(s,`${e}.json`);if(qt.existsSync(c)){d.warn(`Locale ${e} already exists in ${a}`);continue}try{let h=function(f){for(let w in f)typeof f[w]=="string"?f[w]="":typeof f[w]=="object"&&f[w]!==null&&h(f[w])};var i=h;let m=oe.join(s,"en.json"),p=ze(m);if(!p){d.warn(`Could not load reference en.json from ${a}, skipping...`);continue}let g=JSON.parse(JSON.stringify(p));h(g),t.dryRun?d.info(`Would create ${e} locale in ${a}`):(Va(c,JSON.stringify(g,null,2)+`
437
+ `),r.push({app:a,path:c}),d.success(`Created ${e} locale in ${a}`))}catch(m){d.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||d.success(`Locale '${e}' added to ${r.length} app(s)`),o&&process.exit(l.ERROR)}async function Ya(e){d.info("Checking translation coverage...");let t=Zt();t.size===0&&(d.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 c=Ht(a).filter(h=>h.endsWith(".json"));if(c.length===0)continue;let m=oe.join(a,"en.json"),p=ze(m);if(!p){d.debug(`Could not load reference locale from ${i}`);continue}let g=Ve(p);for(let h of c){let f=h.replace(".json",""),w=oe.join(a,h),D=ze(w);if(!D)continue;let k=Ve(D),J=Array.from(k).filter(Se=>{let qe=D[Se.split(".")[0]];return qe!==void 0&&qe!==""}).length,te=g.size-J,B=g.size>0?J/g.size*100:0;s.push({locale:f,coverage:Math.round(B*100)/100,totalKeys:g.size,translatedKeys:J,missingKeys:te})}s.length>0&&(n.set(i,s),o++,r+=s.reduce((h,f)=>h+f.coverage,0)/s.length)}catch(c){d.debug(`Error checking status for ${i}: ${c instanceof Error?c.message:String(c)}`)}}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,c])=>(a[s]=c,a),{})};console.log(JSON.stringify(i,null,2))}else{for(let[i,a]of n){d.info(`${G.bold(i)}:`);for(let s of a){let c="",p=Math.round(s.coverage/100*20);c="\u2588".repeat(p)+"\u2591".repeat(20-p);let h=(s.coverage>=100?G.green:s.coverage>=80?G.yellow:G.red)(`${s.coverage.toFixed(1)}%`);d.info(` ${G.cyan(s.locale.padEnd(5))} [${c}] ${h}`),d.info(` ${s.translatedKeys}/${s.totalKeys} keys (${s.missingKeys} missing)`)}}if(o>0){let i=r/o,a=i>=100?G.green:i>=80?G.yellow:G.red;d.info(`
438
+ Average coverage: ${a(i.toFixed(1)+"%")}`)}}}function Er(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 za({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 Ka({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 Wa(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 Ya({format:n.format||o.format,interactive:o.yes!==!0})})}import*as gt from"@clack/prompts";async function Ja(e){let t=e.lite?"docker-compose.lite.yml":void 0,n=e.lite?"Starting lite stack (PostgreSQL + Redis)":"Starting full stack";u(n+"...","info");let r=await ge("up -d",{file:t,profile:e.profile,dryRun:e.dryRun});r.exitCode===0?u("Infrastructure stack started successfully","success"):(u(Ke(r)??"Failed to start infrastructure stack","error"),x("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function qa(e){u("Stopping infrastructure stack...","info");let t=await ge("down",{dryRun:e.dryRun});t.exitCode===0?u("Infrastructure stack stopped","success"):(u(Ke(t)??"Failed to stop infrastructure stack","error"),x("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}function Ke(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 Ha(e){u("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=Ke(t);u(r??"Failed to check infrastructure status","error"),x("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}if(n){e.format==="json"&&u("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 Za(e,t){let n=t||{},r=e?`Fetching logs for ${e}...`:"Fetching infrastructure logs...";u(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"}):(u(Ke(i)??"Failed to fetch logs","error"),x("Docker compose output",{stderr:i.stderr}),process.exit(i.exitCode||1))}async function Xa(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await gt.confirm({message:"Reset infrastructure? This will remove all containers and volumes.",initialValue:!1});(gt.isCancel(r)||!r)&&(u("Reset cancelled","warn"),process.exit(l.CANCELLED))}else u("Infrastructure reset requires explicit --yes confirmation (use: nebutra infra reset --yes)","error"),process.exit(l.INVALID_ARGS);u("Resetting infrastructure stack...","warn");let n=await ge("down -v",{dryRun:e.dryRun});n.exitCode===0?u("Infrastructure reset successfully","success"):(u(Ke(n)??"Failed to reset infrastructure","error"),x("Docker compose output",{stderr:n.stderr}),process.exit(n.exitCode||1))}function Or(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 Ja(s);break;case"down":await qa(s);break;case"status":await Ha(s);break;case"logs":await Za(r,s);break;case"reset":await Xa(s);break;default:u(`Unknown infra subcommand: ${n}. Valid commands: up, down, status, logs, reset`,"error"),process.exit(l.INVALID_ARGS)}}catch(c){let m=c instanceof Error?c.message:String(c);u(`Infrastructure command failed: ${m}`,"error"),x("Full error",{error:c}),process.exit(l.ERROR)}}).addHelpText("after",`
435
439
  Examples:
436
440
  nebutra infra up Start full stack
437
441
  nebutra infra up --lite Start lite stack (PostgreSQL + Redis)
@@ -448,19 +452,21 @@ Flags:
448
452
  --lite Use docker-compose.lite.yml (PostgreSQL + Redis only)
449
453
  --profile <name> Enable Docker Compose profile (search, notifications, etc.)
450
454
  --format <type> Output format: json, plain (default: plain, auto-json in non-TTY)
451
- `)}import kt from"fs";import Ri from"path";import*as M from"@clack/prompts";import Qe from"picocolors";var ki=["auth","billing","email","storage","queue","cache","notifications","webhooks","ai","mcp"],Oi={stack:"sailor-2026-09",capabilities:[...ki]};function Ai(){return process.stdout.isTTY===!0}function _i(e){return e.yes===!0||e.dryRun===!0||!Ai()}function Ii(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function In(e={}){let t=process.cwd(),n=Ri.join(t,"nebutra.config.json"),r=kt.existsSync(n);e.ifNotExists&&r&&(l.info("nebutra.config.json already exists, skipping initialization."),process.exit(c.SUCCESS));let o=_i(e);o||M.intro(Qe.bgCyan(Qe.black(" nebutra init "))),r&&!o&&(M.log.warn("nebutra.config.json already exists in this directory."),await M.confirm({message:"Do you want to overwrite it?",initialValue:!1})||(M.outro("Operation aborted."),process.exit(c.CANCELLED)));let i={...Oi};if(e.dryRun){let a=r?JSON.parse(kt.readFileSync(n,"utf-8")):void 0,s=Ii(n,i,a);I(s),u("Dry-run completed. No changes made."),process.exit(c.DRY_RUN_OK)}o?l.info("Initializing Nebutra CLI configuration..."):M.spinner().start("Initializing Nebutra CLI configuration..."),kt.writeFileSync(n,JSON.stringify(i,null,2)+`
452
- `),o?(l.success("Configuration saved to nebutra.config.json"),l.info('Initialization complete! Run "nebutra status" to check capability readiness.')):(await new Promise(a=>setTimeout(a,800)),M.spinner().stop(Qe.green("Configuration saved to nebutra.config.json")),M.outro(Qe.cyan('Initialization complete! Run "nebutra status" to check capability readiness.'))),process.exit(c.SUCCESS)}import Ot from"fs/promises";import $i from"os";import At from"path";import*as E from"@clack/prompts";import G from"picocolors";var Ni="https://analytics.nebutra.com";function Pi(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function ji(){return process.env.npm_package_version??"0.0.0-dev"}function et(e,t={}){Pi(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??Ni},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",{action:e.action,cli_version:ji(),...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 Nn=process.env.NEBUTRA_LICENSE_API_URL??"https://nebutra.com";async function Pn(){let e=$i.homedir(),t=At.join(e,".config","nebutra");try{await Ot.mkdir(t,{recursive:!0})}catch{}return t}async function Ti(e){let t=`${Nn}/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 (${Nn}). 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 Di(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 Li(e,t){let n=t.quiet===!0;n||E.intro(G.bgCyan(G.black(" Nebutra License Activation "))),et({action:"activate_attempted"});try{if(e.length<10)throw new Error("Invalid license key format.");n||E.log.step("Validating license key with Nebutra...");let{tier:r,type:o}=await Ti(e),i=await Pn(),a=At.join(i,"license.json");await Ot.writeFile(a,JSON.stringify({licenseKey:e,tier:r,type:o,activatedAt:new Date().toISOString()},null,2),"utf-8"),n||(E.log.success(G.green(`${r} license activated and saved to ${a}`)),E.outro(G.cyan("Premium CLI capabilities are now unlocked!"))),et({action:"activated",tier:r,type:o})}catch(r){et({action:"failed",error_code:Di(r)}),n||(E.log.error(G.red("Activation failed")),l.error(r instanceof Error?r.message:String(r)),E.outro("Please check your key and try again.")),process.exit(c.ERROR)}}async function Fi(e){let t=e.quiet===!0;t||E.intro(G.bgCyan(G.black(" Nebutra License Status ")));try{let n=await Pn(),r=At.join(n,"license.json"),o=await Ot.readFile(r,"utf-8"),i=JSON.parse(o);if(i.licenseKey)t||(E.log.success(G.green("License is active!")),E.log.info(`Key: ${i.licenseKey.substring(0,8)}...`),i.tier&&E.log.info(`Tier: ${G.bold(i.tier)}`),i.type&&E.log.info(`Type: ${i.type}`),E.log.info(`Activated: ${new Date(i.activatedAt).toLocaleString()}`),E.outro(G.cyan("You are ready to use premium features.")));else throw new Error("License key not found in config.")}catch{t||(E.log.warn(G.yellow("No active license found locally.")),E.log.message(G.dim("Run `nebutra license activate <key>` to unlock premium features.")),E.outro("")),process.exit(c.NOT_FOUND)}}function jn(e){let t=e.command("license").description("Manage your Nebutra-Sailor commercial license");t.command("activate <key>").description("Activate a commercial license key for local development").option("--quiet","Suppress output").action(async(n,r)=>{await Li(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await Fi(n)})}import{existsSync as $n,readFileSync as Ui,writeFileSync as Bi}from"fs";import{dirname as Mi,join as Tn,parse as Gi}from"path";import*as tt from"@clack/prompts";function Vi(e){let t=e,{root:n}=Gi(t);for(;;){if($n(Tn(t,"package.json")))return t;if(t===n)return null;let r=Mi(t);if(r===t)return null;t=r}}function Ki(e){if(!$n(e))return{};try{let t=JSON.parse(Ui(e,"utf-8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function zi(e,t){Bi(e,JSON.stringify(t,null,2)+`
453
- `)}async function Wi(e,t){let n=t.format==="json",r=Vi(process.cwd());r||(n?console.log(JSON.stringify({command:"link",success:!1,error:"No package.json found upstream"},null,2)):l.error("No package.json found in current or parent directories."),process.exit(c.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)):l.error("project-id is required when running with --yes / non-interactive."),process.exit(c.INVALID_ARGS));let d=await tt.text({message:"Project ID to link to:",placeholder:"proj_abc123",validate:m=>m&&m.trim().length>0?void 0:"Project ID cannot be empty"});tt.isCancel(d)&&(l.warn("Cancelled"),process.exit(c.CANCELLED)),o=String(d).trim()}let i=Tn(r,"nebutra.config.json"),s={...Ki(i),projectId:o};zi(i,s),n?console.log(JSON.stringify({command:"link",success:!0,projectId:o,configPath:i},null,2)):l.success(`Linked to project: ${o}`)}function Dn(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 Wi(t,{yes:o.yes||!1,format:n.format||o.format})})}import{spawn as ia}from"child_process";import{platform as aa}from"os";var B={name:"Nebutra",nameCn:"\u4E91\u6BD3\u667A\u80FD",nameFull:"\u65E0\u9521\u4E91\u6BD3\u667A\u80FD\u79D1\u6280\u6709\u9650\u516C\u53F8",nameFullEn:"Wuxi Nebutra Intelligence Technology Co., Ltd.",tagline:"Ship AI products, not boilerplate.",taglineCn:"AI\u539F\u751F\xB7\u5FEB\u901F\u51FA\u6D77\xB7\u5373\u523B\u4EA4\u4ED8",description:"Production-ready Next.js monorepo template for AI SaaS products. Auth, billing, multi-tenancy, AI services, design system, and enterprise infrastructure \u2014 pre-configured.",descriptionCn:"\u9762\u5411AI\u521B\u4E1A\u8005\u7684\u4E00\u4F53\u5316SaaS\u57FA\u7840\u8BBE\u65BD\u6A21\u677F\uFF0C\u8986\u76D6\u8BA4\u8BC1\u3001\u8BA1\u8D39\u3001\u591A\u79DF\u6237\u3001AI\u670D\u52A1\u4E0E\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u5F00\u7BB1\u5373\u4EA7\u54C1",story:{concept:"Logo\u4EE5\u9996\u5B57\u6BCDN\u7684\u57FA\u7840\u9020\u578B\u6982\u5FF5\u4E3A\u4E3B\u8981\u8BBE\u8BA1\u6846\u67B6\uFF0C\u901A\u8FC7\u51E0\u4F55\u6B63\u8D1F\u7A7A\u95F4\u6784\u5EFA\u9690\u5F62'N'\uFF0C\u5F62\u6210\u8FD1\u4F3C\u516D\u8FB9\u5F62\u7684\u7A33\u5B9A\u7ED3\u6784",colorMeaning:"\u84DD\u7EFF\u6E10\u53D8\u4F53\u73B0\u672A\u6765\u611F\u4E0E\u79D1\u6280\u950B\u8292\uFF0C'\u4E91'\u4EE3\u8868\u4E91\u7AEF\u5E73\u53F0\uFF0C'\u6BD3'\u5BD3\u610F\u5B55\u80B2\u4E0E\u8F6C\u5316",values:["AI Native","Ship Fast","Open by Default","Global-Ready","Enterprise-Grade"],missionStatement:"Help AI founders and SaaS teams go from idea to production 10x faster by providing the infrastructure layer they shouldn't have to build."},domains:{landing:"nebutra.com",app:"app.nebutra.com",api:"api.nebutra.com",auth:"auth.nebutra.com",sso:"sso.nebutra.com",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 Ji}from"child_process";import{chmodSync as qi,existsSync as ke,readFileSync as Fn,rmSync as Hi,unlinkSync as _t,writeFileSync as Un}from"fs";import{mkdir as Zi}from"fs/promises";import{platform as fe}from"os";import{join as Bn}from"path";import{promisify as Xi}from"util";import{homedir as Ln,platform as Yi}from"os";import{join as nt}from"path";function Ee(){if(Yi()==="win32"){let t=process.env.LOCALAPPDATA||nt(Ln(),"AppData","Local");return nt(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?nt(e,"nebutra"):nt(Ln(),".config","nebutra")}var ge=Xi(Ji),ye="nebutra-cli",Oe="default";function Re(){return Bn(Ee(),"credentials.json")}function rt(){return Bn(Ee(),"device-pending.json")}async function Mn(){await Zi(Ee(),{recursive:!0})}async function It(e){try{return await ge(fe()==="win32"?"where":"which",[e]),!0}catch{return!1}}function Nt(){return process.env.NEBUTRA_NO_KEYCHAIN==="1"}async function Qi(e){if(Nt())return!1;try{if(fe()==="darwin")return await ge("security",["add-generic-password","-a",Oe,"-s",ye,"-w",e,"-U"]),!0;if(fe()==="linux"&&await It("secret-tool"))return await ge("secret-tool",["store","--label",`${B.name} CLI credentials`,"service",ye,"account",Oe]),!0}catch{}return!1}async function Gn(){if(Nt())return null;try{if(fe()==="darwin"){let{stdout:e}=await ge("security",["find-generic-password","-a",Oe,"-s",ye,"-w"]);return e.trim()||null}if(fe()==="linux"&&await It("secret-tool")){let{stdout:e}=await ge("secret-tool",["lookup","service",ye,"account",Oe]);return e.trim()||null}}catch{}return null}async function ea(){if(Nt())return!1;let e=!1;try{fe()==="darwin"?(await ge("security",["delete-generic-password","-a",Oe,"-s",ye]),e=!0):fe()==="linux"&&await It("secret-tool")&&(await ge("secret-tool",["clear","service",ye,"account",Oe]),e=!0)}catch{}return e}async function Vn(e){await Mn();let t=JSON.stringify(e);if(await Qi(t)){try{ke(Re())&&_t(Re())}catch{}return{storedIn:"keychain"}}Un(Re(),`${t}
454
- `,{mode:384});try{qi(Re(),384)}catch{}return{storedIn:"file"}}async function ta(){let e=await Gn();if(e)try{return JSON.parse(e)}catch{return null}let t=Re();if(!ke(t))return null;try{return JSON.parse(Fn(t,"utf-8"))}catch{return null}}async function Kn(){let e=[];await ea()&&e.push(`keychain:${ye}`);let t=Re();if(ke(t))try{_t(t),e.push(t)}catch{}let n=rt();if(ke(n))try{Hi(n,{force:!0}),e.push(n)}catch{}return e}async function Pt(e){await Mn(),Un(rt(),`${JSON.stringify(e)}
455
- `,{mode:384})}function zn(){let e=rt();if(!ke(e))return null;try{return JSON.parse(Fn(e,"utf-8"))}catch{return null}}function ot(){let e=rt();if(ke(e))try{_t(e)}catch{}}async function Wn(){let e=process.env.NEBUTRA_TOKEN?.trim();if(e)return{token:e,source:"env",expired:!1};let t=await ta();if(!t)return null;let n=!!t.expiresAt&&new Date(t.expiresAt).getTime()<=Date.now(),r=await Gn()!==null;return{token:t.accessToken,source:r?"keychain":"file",expired:n}}var na={name:"Nebutra",nameCn:"\u4E91\u6BD3\u667A\u80FD",nameFull:"\u65E0\u9521\u4E91\u6BD3\u667A\u80FD\u79D1\u6280\u6709\u9650\u516C\u53F8",nameFullEn:"Wuxi Nebutra Intelligence Technology Co., Ltd.",tagline:"Ship AI products, not boilerplate.",taglineCn:"AI\u539F\u751F\xB7\u5FEB\u901F\u51FA\u6D77\xB7\u5373\u523B\u4EA4\u4ED8",description:"Production-ready Next.js monorepo template for AI SaaS products. Auth, billing, multi-tenancy, AI services, design system, and enterprise infrastructure \u2014 pre-configured.",descriptionCn:"\u9762\u5411AI\u521B\u4E1A\u8005\u7684\u4E00\u4F53\u5316SaaS\u57FA\u7840\u8BBE\u65BD\u6A21\u677F\uFF0C\u8986\u76D6\u8BA4\u8BC1\u3001\u8BA1\u8D39\u3001\u591A\u79DF\u6237\u3001AI\u670D\u52A1\u4E0E\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u5F00\u7BB1\u5373\u4EA7\u54C1",story:{concept:"Logo\u4EE5\u9996\u5B57\u6BCDN\u7684\u57FA\u7840\u9020\u578B\u6982\u5FF5\u4E3A\u4E3B\u8981\u8BBE\u8BA1\u6846\u67B6\uFF0C\u901A\u8FC7\u51E0\u4F55\u6B63\u8D1F\u7A7A\u95F4\u6784\u5EFA\u9690\u5F62'N'\uFF0C\u5F62\u6210\u8FD1\u4F3C\u516D\u8FB9\u5F62\u7684\u7A33\u5B9A\u7ED3\u6784",colorMeaning:"\u84DD\u7EFF\u6E10\u53D8\u4F53\u73B0\u672A\u6765\u611F\u4E0E\u79D1\u6280\u950B\u8292\uFF0C'\u4E91'\u4EE3\u8868\u4E91\u7AEF\u5E73\u53F0\uFF0C'\u6BD3'\u5BD3\u610F\u5B55\u80B2\u4E0E\u8F6C\u5316",values:["AI Native","Ship Fast","Open by Default","Global-Ready","Enterprise-Grade"],missionStatement:"Help AI founders and SaaS teams go from idea to production 10x faster by providing the infrastructure layer they shouldn't have to build."},domains:{landing:"nebutra.com",app:"app.nebutra.com",api:"api.nebutra.com",auth:"auth.nebutra.com",sso:"sso.nebutra.com",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 it(e){let t=na.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 Yn="nebutra-cli";function at(){let e=process.env.NEBUTRA_AUTH_URL?.trim();return e?e.replace(/\/+$/,""):it("auth")}var te=class extends Error{constructor(n,r){super(r);this.code=n;this.name="DeviceAuthError"}code};async function jt(e){try{return await e.json()}catch{return{}}}async function Jn(e,t,n,r={}){let o=r.attempts??3,i=r.sleep??Hn,a;for(let s=1;s<=o;s++){try{let d=await e(t,{...n,signal:AbortSignal.timeout(r.timeoutMs??1e4)});if(d.status<500||s===o)return d;a=new Error(`HTTP ${d.status}`)}catch(d){if(!Zn(d)||s===o)throw d;a=d}await i(1e3*s)}throw a}async function qn(e,t=fetch){let n=await Jn(t,`${e}/api/auth/device/code`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:Yn})}),r=await jt(n);if(!n.ok)throw new te(typeof r.error=="string"?r.error:"request_failed",typeof r.error_description=="string"?r.error_description:`Could not reach ${B.name}'s auth center (${n.status}).`);return r}async function ra(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:Yn}),signal:AbortSignal.timeout(1e4)}),o=await jt(r);if(!r.ok)throw new te(typeof o.error=="string"?o.error:"request_failed",typeof o.error_description=="string"?o.error_description:`HTTP ${r.status}`);return o}var Hn=e=>new Promise(t=>setTimeout(t,e)),oa=30;function Zn(e){if(e instanceof te)return e.code==="request_failed";if(e instanceof TypeError)return!0;let t=e?.name;return t==="TimeoutError"||t==="AbortError"}async function Xn(e,t,n){let r=n.fetchImpl??fetch,o=n.sleep??Hn,i=n.intervalSeconds;for(;;){if(Date.now()>=n.deadline)throw new te("expired_token","The device code expired before it was approved.");n.onWaiting?.(i),await o(i*1e3);try{return await ra(e,t,r)}catch(a){if(Zn(a)){i=Math.min(i+5,oa),n.onTransientFailure?.(a);continue}if(!(a instanceof te))throw a;if(a.code==="authorization_pending")continue;if(a.code==="slow_down"){i+=5;continue}throw a}}}async function st(e,t,n=fetch){let r=await Jn(n,`${e}/api/auth/get-session`,{method:"GET",headers:{authorization:`Bearer ${t}`}});if(!r.ok)return null;let i=(await jt(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 sa(e,t){return!!e.json||e.format==="json"||t==="json"}function ca(e){try{let t=aa(),[n,r]=t==="darwin"?["open",[e]]:t==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]],o=ia(n,r,{stdio:"ignore",detached:!0});o.on("error",()=>{}),o.unref()}catch{}}async function la(e,t){let n=new Date;await Vn({accessToken:t.access_token,tokenType:t.token_type,expiresAt:new Date(n.getTime()+t.expires_in*1e3).toISOString(),scope:t.scope,obtainedAt:n.toISOString()}),ot()}async function Qn(e,t,n){let r=0,o=await Xn(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(`
456
- `),await la(e,o);let i=await st(e,o.access_token);return i?{userId:i.userId,email:i.email}:null}async function ua(e,t){let n=sa(e,t.format),r=at();if(e.poll){let s=zn();if(s&&s.expiresAt>Date.now()&&s.baseUrl===r)try{let d=await Qn(r,{deviceCode:s.deviceCode,interval:s.interval,expiresAt:s.expiresAt},n);n?console.log(JSON.stringify({command:"login",success:!0,...d},null,2)):l.success(d?.email?`Logged in as ${d.email}`:`Logged in to ${B.name}.`);return}catch(d){return ot(),$t(d,n)}}let o;try{o=await qn(r)}catch(s){return $t(s,n)}let i=Date.now()+o.expires_in*1e3;if(n&&!e.poll){await Pt({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||(l.info(`First, confirm this code matches what's shown in the browser:
457
- `),l.info(` ${o.user_code}
458
- `),l.info(`Visiting: ${o.verification_uri_complete}`)),e.browser!==!1&&process.stdout.isTTY!==!1&&!t.yes&&ca(o.verification_uri_complete);try{await Pt({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 Qn(r,{deviceCode:o.device_code,interval:o.interval,expiresAt:i},n);n?console.log(JSON.stringify({command:"login",success:!0,...s},null,2)):l.success(s?.email?`Logged in as ${s.email}`:`Logged in to ${B.name}.`)}catch(s){return ot(),$t(s,n)}}function $t(e,t){let n=e instanceof te?e.code:"login_failed",r=e instanceof Error?e.message:String(e),o=n==="access_denied"?c.PERMISSION_DENIED:n==="expired_token"?c.TIMEOUT:c.NETWORK_ERROR;t?console.log(JSON.stringify({command:"login",success:!1,error:n,message:r},null,2)):l.error(r),process.exit(o)}function er(e){e.command("login").description(`Authorize this machine with your ${B.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 ua(t,{format:r.format,yes:r.yes})})}import{existsSync as tr,rmSync as da,unlinkSync as ma}from"fs";import{join as pa}from"path";var fa=["auth.json","session.json","token","credentials.json"];async function ga(e){let t=Ee(),n=e.format==="json",r=0,o=[],i=await Kn();if(r+=i.length,o.push(...i),e.all){if(tr(t))try{da(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)):l.error(`Failed to clear config directory: ${s}`),process.exit(c.PERMISSION_DENIED)}}else for(let a of fa){let s=pa(t,a);if(tr(s))try{ma(s),r++,o.push(s)}catch{}}r===0&&(n?console.log(JSON.stringify({command:"logout",success:!0,alreadyLoggedOut:!0,removed:[]},null,2)):l.info("Already logged out"),process.exit(c.SUCCESS)),n?console.log(JSON.stringify({command:"logout",success:!0,removed:o,clearedAll:!!e.all},null,2)):l.success(e.all?"Cleared all nebutra config":"Logged out of nebutra.com")}function nr(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 ga({all:t.all||!1,format:t.format||r.format})})}import{spawn as ya}from"child_process";import{dirname as ha,resolve as ba}from"path";import{fileURLToPath as va}from"url";import*as J from"@clack/prompts";import ne from"picocolors";var wa=ha(va(import.meta.url));function Ca(){let e=[()=>ba(wa,"../../../mcp/dist/server/contextServer.js")];for(let t of e)try{return t()}catch(n){l.debug("MCP server binary resolution strategy failed",{error:n})}return"nebutra-mcp"}function rr(e){e.command("mcp").description("Start the Nebutra MCP server for Cursor/Windsurf").option("--stdio","Use stdio transport (default)",!0).action(async t=>{J.intro(ne.bgCyan(ne.black(" nebutra mcp ")));try{let n=Ca();J.log.info(ne.cyan("Starting Nebutra MCP server for Cursor/Windsurf integration...")),J.log.info(ne.dim(`Press Ctrl+C to stop the server.
459
- `));let r=ya(process.execPath,[n],{stdio:"inherit",env:{...process.env}});r.on("close",o=>{o===0?J.outro(ne.green("MCP server stopped gracefully.")):o===null&&J.outro(ne.yellow("MCP server terminated.")),process.exit(o??0)}),r.on("error",o=>{l.error(`
460
- Failed to start MCP server: ${o.message}`),o.code==="ENOENT"&&(l.warn(`
461
- Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),l.info(" Install globally: npm install -g @nebutra/mcp"),process.exit(c.NOT_FOUND)),process.exit(c.ERROR)}),process.on("SIGINT",()=>{J.log.info(ne.yellow(`
462
- Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{J.log.info(ne.yellow("Terminating MCP server...")),r.kill("SIGTERM")})}catch(n){J.log.error(ne.red("Error: Unable to start MCP server. Ensure @nebutra/mcp is properly installed.")),n instanceof Error&&l.error(n.message),process.exit(c.ERROR)}})}import*as N from"@clack/prompts";import V from"picocolors";var ir=Object.fromEntries(Object.entries(Zt).map(([e,t])=>[e,t]));function ar(e){return typeof e=="boolean"?"boolean":"string"}function sr(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:ar(n.default)})),examples:e.examples||[]}}function xa(e){let n=(H.subcommands||[]).find(r=>r.name===e);return n?sr(n):null}function Sa(){return(H.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:ar(e.default)}))}function Ea(e){let t=H.subcommands||[];return{name:H.name,version:e,description:H.description,usage:H.usage||"nebutra [command] [options]",globalOptions:Sa(),commands:t.map(sr),exitCodes:ir,timestamp:new Date().toISOString()}}function or(){return(H.subcommands||[]).map(t=>t.name)}function ct(e){process.stdout.write(`${JSON.stringify(e,null,2)}
463
- `)}function Ra(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function ka(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(ct(Ea(r)),process.exit(0)),t.list===!0&&(ct(or()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(ct(ir),process.exit(0)),e){let o=xa(e);o||(n||(l.error(`Unknown command '${e}'`),l.info(`Available commands: ${or().join(", ")}`)),process.exit(c.NOT_FOUND)),ct(o),process.exit(0)}n||(N.intro(V.bgCyan(V.black(" nebutra schema "))),N.log.info(V.cyan("Agent-friendly introspection of CLI commands, arguments, and value domains.")),N.log.message(""),N.log.info(V.bold("Usage:")),N.log.message(V.dim(" nebutra schema --all Show full command tree as JSON")),N.log.message(V.dim(" nebutra schema <command> Show schema for a specific command")),N.log.message(V.dim(" nebutra schema --list List available command names")),N.log.message(V.dim(" nebutra schema --exit-codes Show exit codes reference")),N.log.message(""),N.log.info(V.bold("Example:")),N.log.message(V.dim(" nebutra schema status")),N.log.message(V.dim(" nebutra schema --all | jq '.commands[0]'")),N.outro(V.cyan("All output is JSON for easy parsing by agents and automation tools."))),process.exit(0)}catch(o){if(Ra(o))throw o;n||l.error(o instanceof Error?o.message:String(o)),process.exit(c.ERROR)}}function cr(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 ka(t,n)})}import{stdin as De}from"process";import*as lt from"@clack/prompts";import R from"picocolors";async function Oa(){return new Promise((e,t)=>{let n="";De.setEncoding("utf8"),De.on("readable",()=>{let r;for(;(r=De.read())!==null;)n+=r}),De.on("end",()=>{e(n.trim())}),De.on("error",t)})}async function Aa(e){u("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{u("Secrets for tenant: "+(e.tenant||"org_123"),"info");for(let n of t){let r=n.description?` \u2014 ${n.description}`:"";u(`${R.cyan(n.key)}${R.gray(r)}`,"info"),u(` Updated: ${n.updatedAt}`,"info")}}}async function _a(e,t){e||(u("Secret key is required: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS));let n;if(t.value)u("WARNING: Using --value flag exposes secret in shell history. Prefer stdin.","warn"),n=t.value;else{u("Enter secret value (will not echo). Press Ctrl+D when done:","info");try{n=await Oa()}catch{u("Failed to read secret from stdin","error"),process.exit(c.ERROR)}}if(n||(u("Secret value cannot be empty","error"),process.exit(c.INVALID_ARGS)),u(`Setting secret ${R.cyan(e)}...`,"info"),t.dryRun){u(`Would encrypt and store secret ${e} for tenant ${t.tenant||"org_123"}`,"info");return}u(`Secret ${R.cyan(e)} encrypted and stored successfully`,"success"),t.description&&u(`Description: ${t.description}`,"info")}async function Ia(e,t){e||(u("Secret key is required: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),u(`Retrieving secret ${R.cyan(e)}...`,"info");let r=t.unmask?"sk_live_abc123xyz789...":"***masked***";t.unmask||u(`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"}):u(`${R.cyan(e)}: ${r}`,"info")}async function Na(e,t){e||(u("Secret key is required: nebutra secrets rotate <key>","error"),process.exit(c.INVALID_ARGS));let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let r=await lt.confirm({message:`Rotate encryption key for ${R.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});(lt.isCancel(r)||!r)&&(u("Rotation cancelled","warn"),process.exit(c.CANCELLED))}if(!t.yes&&!t.dryRun&&!n&&(u("Key rotation requires --yes confirmation","error"),process.exit(c.INVALID_ARGS)),u(`Rotating encryption key for ${R.cyan(e)}...`,"info"),t.dryRun){u(`Would rotate encryption key for ${e}`,"info");return}u(`Encryption key for ${R.cyan(e)} rotated successfully`,"success"),u(`New key version: ${R.dim("v2")}`,"info")}async function Pa(e){u("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{u("Secret Access Audit Log","info");for(let r of n){let o=r.success?R.green("\u2713"):R.red("\u2716");u(`${o} ${r.timestamp} ${R.cyan(r.action)} ${r.key}`,r.success?"success":"error"),u(` Actor: ${r.actor}${r.message?` \u2014 ${r.message}`:""}`,"info")}}}async function ja(e){u("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{u("Vault Configuration Check","info");for(let r of t){let o=r.healthy?R.green("\u2713"):R.red("\u2716");u(`${o} ${r.name}: ${r.message}`,r.healthy?"success":"error")}let n=t.every(r=>r.healthy);u(`Overall: ${n?R.green("HEALTHY"):R.red("UNHEALTHY")}`,n?"success":"error")}}function lr(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)=>{let i=o.optsWithGlobals?.(),a={dryRun:o.dryRun||i?.dryRun,yes:o.yes||i?.yes,format:o.format||i?.format,tenant:o.tenant||i?.tenant,unmask:o.unmask||!1,description:o.description,value:o.value,since:o.since,limit:o.limit??50};try{switch(n){case"list":await Aa(a);break;case"set":r.length===0&&(u("set requires a secret key: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS)),await _a(r[0],a);break;case"get":r.length===0&&(u("get requires a secret key: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),await Ia(r[0],a);break;case"rotate":r.length===0&&(u("rotate requires a secret key: nebutra secrets rotate <key>","error"),process.exit(c.INVALID_ARGS)),await Na(r[0],a);break;case"audit":await Pa(a);break;case"verify":await ja(a);break;default:u(`Unknown secrets subcommand: ${n}. Valid commands: list, set, get, rotate, audit, verify`,"error"),process.exit(c.ERROR)}}catch(s){let d=s instanceof Error?s.message:String(s);u(`Secrets command failed: ${d}`,"error"),x("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
455
+ `)}import Xt from"fs";import Qa from"path";import*as W from"@clack/prompts";import ht from"picocolors";var es=["auth","billing","email","storage","queue","cache","notifications","webhooks","ai","mcp"],ts={stack:"sailor-2026-09",capabilities:[...es]};function ns(){return process.stdout.isTTY===!0}function rs(e){return e.yes===!0||e.dryRun===!0||!ns()}function os(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function Ar(e={}){let t=process.cwd(),n=Qa.join(t,"nebutra.config.json"),r=Xt.existsSync(n);e.ifNotExists&&r&&(d.info("nebutra.config.json already exists, skipping initialization."),process.exit(l.SUCCESS));let o=rs(e);o||W.intro(ht.bgCyan(ht.black(" nebutra init "))),r&&!o&&(W.log.warn("nebutra.config.json already exists in this directory."),await W.confirm({message:"Do you want to overwrite it?",initialValue:!1})||(W.outro("Operation aborted."),process.exit(l.CANCELLED)));let i={...ts};if(e.dryRun){let a=r?JSON.parse(Xt.readFileSync(n,"utf-8")):void 0,s=os(n,i,a);N(s),u("Dry-run completed. No changes made."),process.exit(l.DRY_RUN_OK)}o?d.info("Initializing Nebutra CLI configuration..."):W.spinner().start("Initializing Nebutra CLI configuration..."),Xt.writeFileSync(n,JSON.stringify(i,null,2)+`
456
+ `),o?(d.success("Configuration saved to nebutra.config.json"),d.info('Initialization complete! Run "nebutra status" to check capability readiness.')):(await new Promise(a=>setTimeout(a,800)),W.spinner().stop(ht.green("Configuration saved to nebutra.config.json")),W.outro(ht.cyan('Initialization complete! Run "nebutra status" to check capability readiness.'))),process.exit(l.SUCCESS)}import Qt from"fs/promises";import cs from"os";import en from"path";import*as C from"@clack/prompts";import V from"picocolors";var is="https://analytics.nebutra.com";function as(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function ss(){return process.env.npm_package_version??"0.0.0-dev"}function yt(e,t={}){as(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??is},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",{action:e.action,cli_version:ss(),...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 _r=process.env.NEBUTRA_LICENSE_API_URL??"https://nebutra.com";async function Ir(){let e=cs.homedir(),t=en.join(e,".config","nebutra");try{await Qt.mkdir(t,{recursive:!0})}catch{}return t}async function ls(e){let t=`${_r}/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 (${_r}). 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 ds(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 us(e,t){let n=t.quiet===!0;n||C.intro(V.bgCyan(V.black(" Nebutra License Activation "))),yt({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 ls(e),i=await Ir(),a=en.join(i,"license.json");await Qt.writeFile(a,JSON.stringify({licenseKey:e,tier:r,type:o,activatedAt:new Date().toISOString()},null,2),"utf-8"),n||(C.log.success(V.green(`${r} license activated and saved to ${a}`)),C.outro(V.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."))),yt({action:"activated",tier:r,type:o})}catch(r){yt({action:"failed",error_code:ds(r)}),n||(C.log.error(V.red("Activation failed")),d.error(r instanceof Error?r.message:String(r)),C.outro("Please check your key and try again.")),process.exit(l.ERROR)}}async function ms(e){let t=e.quiet===!0;t||C.intro(V.bgCyan(V.black(" Nebutra License Status ")));try{let n=await Ir(),r=en.join(n,"license.json"),o=await Qt.readFile(r,"utf-8"),i=JSON.parse(o);if(i.licenseKey)t||(C.log.success(V.green("License is active!")),C.log.info(`Key: ${i.licenseKey.substring(0,8)}...`),i.tier&&C.log.info(`Tier: ${V.bold(i.tier)}`),i.type&&C.log.info(`Type: ${i.type}`),C.log.info(`Activated: ${new Date(i.activatedAt).toLocaleString()}`),C.log.message(V.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(V.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(V.yellow("No active license found locally.")),C.log.message(V.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 Pr(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 us(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await ms(n)})}import{existsSync as Nr,readFileSync as ps,writeFileSync as fs}from"fs";import{dirname as gs,join as $r,parse as hs}from"path";import*as bt from"@clack/prompts";function ys(e){let t=e,{root:n}=hs(t);for(;;){if(Nr($r(t,"package.json")))return t;if(t===n)return null;let r=gs(t);if(r===t)return null;t=r}}function bs(e){if(!Nr(e))return{};try{let t=JSON.parse(ps(e,"utf-8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function vs(e,t){fs(e,JSON.stringify(t,null,2)+`
457
+ `)}async function ws(e,t){let n=t.format==="json",r=ys(process.cwd());r||(n?console.log(JSON.stringify({command:"link",success:!1,error:"No package.json found upstream"},null,2)):d.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)):d.error("project-id is required when running with --yes / non-interactive."),process.exit(l.INVALID_ARGS));let c=await bt.text({message:"Project ID to link to:",placeholder:"proj_abc123",validate:m=>m&&m.trim().length>0?void 0:"Project ID cannot be empty"});bt.isCancel(c)&&(d.warn("Cancelled"),process.exit(l.CANCELLED)),o=String(c).trim()}let i=$r(r,"nebutra.config.json"),s={...bs(i),projectId:o};vs(i,s),n?console.log(JSON.stringify({command:"link",success:!0,projectId:o,configPath:i},null,2)):d.success(`Linked to project: ${o}`)}function jr(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 ws(t,{yes:o.yes||!1,format:n.format||o.format})})}import{spawn as Cs}from"child_process";import{platform as Ss}from"os";var Tr="nebutra-cli";function vt(){let e=process.env.NEBUTRA_AUTH_URL?.trim();return e?e.replace(/\/+$/,""):Z("auth")}var ie=class extends Error{constructor(n,r){super(r);this.code=n;this.name="DeviceAuthError"}code};async function tn(e){try{return await e.json()}catch{return{}}}async function Fr(e,t,n,r={}){let o=r.attempts??3,i=r.sleep??Lr,a;for(let s=1;s<=o;s++){try{let c=await e(t,{...n,signal:AbortSignal.timeout(r.timeoutMs??1e4)});if(c.status<500||s===o)return c;a=new Error(`HTTP ${c.status}`)}catch(c){if(!Ur(c)||s===o)throw c;a=c}await i(1e3*s)}throw a}async function Dr(e,t=fetch){let n=await Fr(t,`${e}/api/auth/device/code`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:Tr})}),r=await tn(n);if(!n.ok)throw new ie(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 ks(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:Tr}),signal:AbortSignal.timeout(1e4)}),o=await tn(r);if(!r.ok)throw new ie(typeof o.error=="string"?o.error:"request_failed",typeof o.error_description=="string"?o.error_description:`HTTP ${r.status}`);return o}var Lr=e=>new Promise(t=>setTimeout(t,e)),xs=30;function Ur(e){if(e instanceof ie)return e.code==="request_failed";if(e instanceof TypeError)return!0;let t=e?.name;return t==="TimeoutError"||t==="AbortError"}async function Br(e,t,n){let r=n.fetchImpl??fetch,o=n.sleep??Lr,i=n.intervalSeconds;for(;;){if(Date.now()>=n.deadline)throw new ie("expired_token","The device code expired before it was approved.");n.onWaiting?.(i),await o(i*1e3);try{return await ks(e,t,r)}catch(a){if(Ur(a)){i=Math.min(i+5,xs),n.onTransientFailure?.(a);continue}if(!(a instanceof ie))throw a;if(a.code==="authorization_pending")continue;if(a.code==="slow_down"){i+=5;continue}throw a}}}async function wt(e,t,n=fetch){let r=await Fr(n,`${e}/api/auth/get-session`,{method:"GET",headers:{authorization:`Bearer ${t}`}});if(!r.ok)return null;let i=(await tn(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 Rs(e,t){return!!e.json||e.format==="json"||t==="json"}function Es(e){try{let t=Ss(),[n,r]=t==="darwin"?["open",[e]]:t==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]],o=Cs(n,r,{stdio:"ignore",detached:!0});o.on("error",()=>{}),o.unref()}catch{}}async function Os(e,t){let n=new Date;await En({accessToken:t.access_token,tokenType:t.token_type,expiresAt:new Date(n.getTime()+t.expires_in*1e3).toISOString(),scope:t.scope,obtainedAt:n.toISOString()}),Qe()}async function Mr(e,t,n){let r=0,o=await Br(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(`
458
+ `),await Os(e,o);let i=await wt(e,o.access_token);return i?{userId:i.userId,email:i.email}:null}async function As(e,t){let n=Rs(e,t.format),r=vt();if(e.poll){let s=An();if(s&&s.expiresAt>Date.now()&&s.baseUrl===r)try{let c=await Mr(r,{deviceCode:s.deviceCode,interval:s.interval,expiresAt:s.expiresAt},n);n?console.log(JSON.stringify({command:"login",success:!0,...c},null,2)):d.success(c?.email?`Logged in as ${c.email}`:`Logged in to ${M.name}.`);return}catch(c){return Qe(),nn(c,n)}}let o;try{o=await Dr(r)}catch(s){return nn(s,n)}let i=Date.now()+o.expires_in*1e3;if(n&&!e.poll){await jt({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||(d.info(`First, confirm this code matches what's shown in the browser:
459
+ `),d.info(` ${o.user_code}
460
+ `),d.info(`Visiting: ${o.verification_uri_complete}`)),e.browser!==!1&&process.stdout.isTTY!==!1&&!t.yes&&Es(o.verification_uri_complete);try{await jt({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 Mr(r,{deviceCode:o.device_code,interval:o.interval,expiresAt:i},n);n?console.log(JSON.stringify({command:"login",success:!0,...s},null,2)):d.success(s?.email?`Logged in as ${s.email}`:`Logged in to ${M.name}.`)}catch(s){return Qe(),nn(s,n)}}function nn(e,t){let n=e instanceof ie?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)):d.error(r),process.exit(o)}function Gr(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 As(t,{format:r.format,yes:r.yes})})}import{existsSync as Vr,rmSync as _s,unlinkSync as Is}from"fs";import{join as Ps}from"path";var Ns=["auth.json","session.json","token","credentials.json"];async function $s(e){let t=Re(),n=e.format==="json",r=0,o=[],i=await On();if(r+=i.length,o.push(...i),e.all){if(Vr(t))try{_s(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)):d.error(`Failed to clear config directory: ${s}`),process.exit(l.PERMISSION_DENIED)}}else for(let a of Ns){let s=Ps(t,a);if(Vr(s))try{Is(s),r++,o.push(s)}catch{}}r===0&&(n?console.log(JSON.stringify({command:"logout",success:!0,alreadyLoggedOut:!0,removed:[]},null,2)):d.info("Already logged out"),process.exit(l.SUCCESS)),n?console.log(JSON.stringify({command:"logout",success:!0,removed:o,clearedAll:!!e.all},null,2)):d.success(e.all?"Cleared all nebutra config":"Logged out of nebutra.com")}function zr(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 $s({all:t.all||!1,format:t.format||r.format})})}import{spawn as js}from"child_process";import{existsSync as Ts}from"fs";import{createRequire as Fs}from"module";import{dirname as Ds,resolve as Kr}from"path";import{fileURLToPath as Ls}from"url";import*as Yr from"@clack/prompts";import je from"picocolors";var Wr=Ds(Ls(import.meta.url));function Us(){let e=[Kr(Wr,"../../../../ai/mcp/dist/server/contextServer.js"),Kr(Wr,"../../../ai/mcp/dist/server/contextServer.js")];for(let t of e)if(Ts(t))return{command:process.execPath,args:[t]};try{let t=Fs(import.meta.url).resolve("@nebutra/mcp/bin/nebutra-mcp.js");return{command:process.execPath,args:[t]}}catch(t){d.debug("@nebutra/mcp is not installed next to the CLI",{error:t})}return{command:"nebutra-mcp",args:[]}}function Jr(e){e.command("mcp").description("Start the Nebutra MCP server for Cursor/Windsurf").option("--stdio","Use stdio transport (default)",!0).action(async t=>{try{let n=Us();process.stderr.write(je.dim(`nebutra mcp: stdio server running \u2014 Ctrl+C to stop
461
+ `));let r={...process.env};if(!r.NEBUTRA_TOKEN){let i=await ce();i&&!i.expired&&(r.NEBUTRA_TOKEN=i.token)}let o=js(n.command,n.args,{stdio:"inherit",env:r});o.on("close",i=>{i===0?process.stderr.write(je.green(`MCP server stopped.
462
+ `)):i===null&&process.stderr.write(je.yellow(`MCP server terminated.
463
+ `)),process.exit(i??0)}),o.on("error",i=>{d.error(`
464
+ Failed to start MCP server: ${i.message}`),i.code==="ENOENT"&&(d.warn(`
465
+ Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),d.info(" Install globally: npm install -g @nebutra/mcp"),process.exit(l.NOT_FOUND)),process.exit(l.ERROR)}),process.on("SIGINT",()=>{process.stderr.write(je.yellow(`
466
+ Shutting down MCP server...
467
+ `)),o.kill("SIGINT")}),process.on("SIGTERM",()=>{process.stderr.write(je.yellow(`Terminating MCP server...
468
+ `)),o.kill("SIGTERM")})}catch(n){Yr.log.error(je.red("Error: Unable to start MCP server. Ensure @nebutra/mcp is properly installed.")),n instanceof Error&&d.error(n.message),process.exit(l.ERROR)}})}import*as $ from"@clack/prompts";import Y from"picocolors";var Hr=Object.fromEntries(Object.entries(yn).map(([e,t])=>[e,t]));function Zr(e){return typeof e=="boolean"?"boolean":"string"}function Xr(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:Zr(n.default)})),examples:e.examples||[]}}function Bs(e){let n=(Q.subcommands||[]).find(r=>r.name===e);return n?Xr(n):null}function Ms(){return(Q.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:Zr(e.default)}))}function Gs(e){let t=Q.subcommands||[];return{name:Q.name,version:e,description:Q.description,usage:Q.usage||"nebutra [command] [options]",globalOptions:Ms(),commands:t.map(Xr),exitCodes:Hr,timestamp:new Date().toISOString()}}function qr(){return(Q.subcommands||[]).map(t=>t.name)}function kt(e){process.stdout.write(`${JSON.stringify(e,null,2)}
469
+ `)}function Vs(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function zs(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(kt(Gs(r)),process.exit(0)),t.list===!0&&(kt(qr()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(kt(Hr),process.exit(0)),e){let o=Bs(e);o||(n||(d.error(`Unknown command '${e}'`),d.info(`Available commands: ${qr().join(", ")}`)),process.exit(l.NOT_FOUND)),kt(o),process.exit(0)}n||($.intro(Y.bgCyan(Y.black(" nebutra schema "))),$.log.info(Y.cyan("Agent-friendly introspection of CLI commands, arguments, and value domains.")),$.log.message(""),$.log.info(Y.bold("Usage:")),$.log.message(Y.dim(" nebutra schema --all Show full command tree as JSON")),$.log.message(Y.dim(" nebutra schema <command> Show schema for a specific command")),$.log.message(Y.dim(" nebutra schema --list List available command names")),$.log.message(Y.dim(" nebutra schema --exit-codes Show exit codes reference")),$.log.message(""),$.log.info(Y.bold("Example:")),$.log.message(Y.dim(" nebutra schema status")),$.log.message(Y.dim(" nebutra schema --all | jq '.commands[0]'")),$.outro(Y.cyan("All output is JSON for easy parsing by agents and automation tools."))),process.exit(0)}catch(o){if(Vs(o))throw o;n||d.error(o instanceof Error?o.message:String(o)),process.exit(l.ERROR)}}function Qr(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 zs(t,n)})}import{stdin as We}from"process";import*as xt from"@clack/prompts";import A from"picocolors";async function Ks(){return new Promise((e,t)=>{let n="";We.setEncoding("utf8"),We.on("readable",()=>{let r;for(;(r=We.read())!==null;)n+=r}),We.on("end",()=>{e(n.trim())}),We.on("error",t)})}async function Ws(e){u("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{u("Secrets for tenant: "+(e.tenant||"org_123"),"info");for(let n of t){let r=n.description?` \u2014 ${n.description}`:"";u(`${A.cyan(n.key)}${A.gray(r)}`,"info"),u(` Updated: ${n.updatedAt}`,"info")}}}async function Ys(e,t){e||(u("Secret key is required: nebutra secrets set <key>","error"),process.exit(l.INVALID_ARGS));let n;if(t.value)u("WARNING: Using --value flag exposes secret in shell history. Prefer stdin.","warn"),n=t.value;else{u("Enter secret value (will not echo). Press Ctrl+D when done:","info");try{n=await Ks()}catch{u("Failed to read secret from stdin","error"),process.exit(l.ERROR)}}if(n||(u("Secret value cannot be empty","error"),process.exit(l.INVALID_ARGS)),u(`Setting secret ${A.cyan(e)}...`,"info"),t.dryRun){u(`Would encrypt and store secret ${e} for tenant ${t.tenant||"org_123"}`,"info");return}u(`Secret ${A.cyan(e)} encrypted and stored successfully`,"success"),t.description&&u(`Description: ${t.description}`,"info")}async function Js(e,t){e||(u("Secret key is required: nebutra secrets get <key>","error"),process.exit(l.INVALID_ARGS)),u(`Retrieving secret ${A.cyan(e)}...`,"info");let r=t.unmask?"sk_live_abc123xyz789...":"***masked***";t.unmask||u(`Secret value is ${A.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"}):u(`${A.cyan(e)}: ${r}`,"info")}async function qs(e,t){e||(u("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 xt.confirm({message:`Rotate encryption key for ${A.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});(xt.isCancel(r)||!r)&&(u("Rotation cancelled","warn"),process.exit(l.CANCELLED))}if(!t.yes&&!t.dryRun&&!n&&(u("Key rotation requires --yes confirmation","error"),process.exit(l.INVALID_ARGS)),u(`Rotating encryption key for ${A.cyan(e)}...`,"info"),t.dryRun){u(`Would rotate encryption key for ${e}`,"info");return}u(`Encryption key for ${A.cyan(e)} rotated successfully`,"success"),u(`New key version: ${A.dim("v2")}`,"info")}async function Hs(e){u("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{u("Secret Access Audit Log","info");for(let r of n){let o=r.success?A.green("\u2713"):A.red("\u2716");u(`${o} ${r.timestamp} ${A.cyan(r.action)} ${r.key}`,r.success?"success":"error"),u(` Actor: ${r.actor}${r.message?` \u2014 ${r.message}`:""}`,"info")}}}async function Zs(e){u("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{u("Vault Configuration Check","info");for(let r of t){let o=r.healthy?A.green("\u2713"):A.red("\u2716");u(`${o} ${r.name}: ${r.message}`,r.healthy?"success":"error")}let n=t.every(r=>r.healthy);u(`Overall: ${n?A.green("HEALTHY"):A.red("UNHEALTHY")}`,n?"success":"error")}}function eo(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 Ws(s);break;case"set":r.length===0&&(u("set requires a secret key: nebutra secrets set <key>","error"),process.exit(l.INVALID_ARGS)),await Ys(r[0],s);break;case"get":r.length===0&&(u("get requires a secret key: nebutra secrets get <key>","error"),process.exit(l.INVALID_ARGS)),await Js(r[0],s);break;case"rotate":r.length===0&&(u("rotate requires a secret key: nebutra secrets rotate <key>","error"),process.exit(l.INVALID_ARGS)),await qs(r[0],s);break;case"audit":await Hs(s);break;case"verify":await Zs(s);break;default:u(`Unknown secrets subcommand: ${n}. Valid commands: list, set, get, rotate, audit, verify`,"error"),process.exit(l.ERROR)}}catch(c){let m=c instanceof Error?c.message:String(c);u(`Secrets command failed: ${m}`,"error"),x("Full error",{error:c}),process.exit(l.ERROR)}}).addHelpText("after",`
464
470
  Examples:
465
471
  nebutra secrets list List all secrets (metadata only)
466
472
  nebutra secrets list --tenant org_456 List secrets for specific tenant
@@ -495,19 +501,19 @@ Security Notes:
495
501
  - Never use --value in production (visible in shell history)
496
502
  - Always use --unmask when viewing secrets in scripts
497
503
  - Audit log tracks all access and modifications
498
- `)}import*as ut from"@clack/prompts";import P from"picocolors";function ur(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function $a(e){switch(e){case"running":return P.green("\u25CF");case"exited":return P.red("\u25CF");case"restarting":return P.yellow("\u25CF");case"paused":return P.gray("\u25CF");default:return P.gray("\u25CF")}}async function Ta(e){u("Checking service status...","info");let t=await O({command:"docker",args:["compose","ps","--format","json"],cwd:C(),interactive:!1,label:"Docker Compose PS",dryRun:e.dryRun});t.exitCode!==0&&(u("Failed to fetch service status","error"),x("Docker error",{stderr:t.stderr}),process.exit(c.ERROR));try{let n=JSON.parse(t.stdout);if(e.format==="json"){let r=n.map(o=>({name:o.Name,status:ur(o.State),exitCode:o.ExitCode}));b(r,{format:"json"})}else{u("Service Status","info");let r=n.map(o=>({Service:$a(ur(o.State))+" "+o.Name,Status:o.State,"Exit Code":o.ExitCode||"\u2014"}));for(let o of r)u(`${o.Service} (${o.Status})`,"info")}}catch(n){u("Failed to parse service status","error"),x("Parse error",{error:String(n)}),process.exit(c.ERROR)}}async function Da(e,t){u(`Streaming logs for ${P.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 O({command:"docker",args:n,cwd:C(),interactive:!0,label:`Docker Compose Logs (${e})`,dryRun:t.dryRun})).exitCode!==0&&(u(`Failed to stream logs for ${e}`,"error"),process.exit(c.ERROR))}async function La(e,t){let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let i=await ut.confirm({message:`Restart service ${P.cyan(e)}?`,initialValue:!1});(ut.isCancel(i)||!i)&&(u("Restart cancelled","warn"),process.exit(c.CANCELLED))}u(`Restarting service ${P.cyan(e)}...`,"info");let r=["compose","restart"];t.timeout&&r.push("--timeout",String(t.timeout)),r.push(e);let o=await O({command:"docker",args:r,cwd:C(),interactive:!1,label:`Docker Compose Restart (${e})`,dryRun:t.dryRun});o.exitCode===0?u(`Service ${P.cyan(e)} restarted successfully`,"success"):(u(`Failed to restart service ${e}`,"error"),x("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}async function Fa(e){u("Running deep health check...","info");let t=[],n=await O({command:"docker",args:["compose","exec","-T","postgres","pg_isready"],cwd:C(),interactive:!1,label:"PostgreSQL Health",dryRun:e.dryRun});t.push({service:"PostgreSQL",healthy:n.exitCode===0,message:n.exitCode===0?"Ready":"Not responding"});let r=await O({command:"docker",args:["compose","exec","-T","redis","redis-cli","ping"],cwd:C(),interactive:!1,label:"Redis Health",dryRun:e.dryRun});t.push({service:"Redis",healthy:r.exitCode===0,message:r.exitCode===0?"Ready":"Not responding"});let o=await O({command:"docker",args:["compose","exec","-T","clickhouse","curl","-s","http://localhost:8123/ping"],cwd:C(),interactive:!1,label:"ClickHouse Health",dryRun:e.dryRun});t.push({service:"ClickHouse",healthy:o.exitCode===0,message:o.exitCode===0?"Ready":"Not responding"});let i=await O({command:"docker",args:["compose","exec","-T","meilisearch","curl","-s","http://localhost:7700/health"],cwd:C(),interactive:!1,label:"Meilisearch Health",dryRun:e.dryRun});if(t.push({service:"Meilisearch",healthy:i.exitCode===0,message:i.exitCode===0?"Healthy":"Not responding"}),e.format==="json")b(t,{format:"json"});else{for(let s of t){let d=s.healthy?P.green("\u2713"):P.red("\u2716");u(`${d} ${s.service}: ${s.message}`,s.healthy?"success":"error")}let a=t.every(s=>s.healthy);u(`Overall health: ${a?P.green("HEALTHY"):P.red("UNHEALTHY")}`,a?"success":"error")}}async function Ua(e,t,n){let r=parseInt(t,10);(Number.isNaN(r)||r<0)&&(u("Invalid replica count (must be a non-negative number)","error"),process.exit(c.INVALID_ARGS)),u(`Scaling ${P.cyan(e)} to ${P.cyan(String(r))} replicas...`,"info");let o=await O({command:"docker",args:["compose","up","-d","--scale",`${e}=${r}`],cwd:C(),interactive:!1,label:`Docker Compose Scale (${e})`,dryRun:n.dryRun});o.exitCode===0?u(`Service ${P.cyan(e)} scaled to ${r} replicas`,"success"):(u(`Failed to scale service ${e}`,"error"),x("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}function dr(e){e.command("services <verb> [args...]").description("Manage Docker Compose microservices (postgres, redis, clickhouse, meilisearch, novu, openfga, etc.)").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)=>{let i=o.optsWithGlobals?.(),a={dryRun:o.dryRun||i?.dryRun,yes:o.yes||i?.yes,format:o.format||i?.format,tail:o.tail??100,since:o.since,timeout:o.timeout};try{switch(n){case"status":await Ta(a);break;case"logs":r.length===0&&(u("logs requires a service name: nebutra services logs <service>","error"),process.exit(c.INVALID_ARGS)),await Da(r[0],a);break;case"restart":r.length===0&&(u("restart requires a service name: nebutra services restart <service>","error"),process.exit(c.INVALID_ARGS)),await La(r[0],a);break;case"health":await Fa(a);break;case"scale":r.length<2&&(u("scale requires a service name and replica count: nebutra services scale <service> <count>","error"),process.exit(c.INVALID_ARGS)),await Ua(r[0],r[1],a);break;default:u(`Unknown services subcommand: ${n}. Valid commands: status, logs, restart, health, scale`,"error"),process.exit(c.ERROR)}}catch(s){let d=s instanceof Error?s.message:String(s);u(`Services command failed: ${d}`,"error"),x("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
504
+ `)}import{existsSync as Xs,readFileSync as Qs}from"fs";import{resolve as ec}from"path";import*as Ct from"@clack/prompts";import j from"picocolors";function tc(e){let t=["postgres","redis","clickhouse"],n=ec(e,"docker-compose.yml");if(!Xs(n))return t;try{let o=Qs(n,"utf-8").split(`
505
+ `),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 c=o[s];if(/^[a-zA-Z]/.test(c))break;let m=c.match(/^ {2}([a-zA-Z0-9_-]+):\s*$/);m&&a.push(m[1])}return a.length>0?a:t}catch{return t}}function to(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function nc(e){switch(e){case"running":return j.green("\u25CF");case"exited":return j.red("\u25CF");case"restarting":return j.yellow("\u25CF");case"paused":return j.gray("\u25CF");default:return j.gray("\u25CF")}}async function rc(e){u("Checking service status...","info");let t=await R({command:"docker",args:["compose","ps","--format","json"],cwd:y(),interactive:!1,label:"Docker Compose PS",dryRun:e.dryRun});t.exitCode!==0&&(u("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:to(o.State),exitCode:o.ExitCode}));b(r,{format:"json"})}else{u("Service Status","info");let r=n.map(o=>({Service:nc(to(o.State))+" "+o.Name,Status:o.State,"Exit Code":o.ExitCode||"\u2014"}));for(let o of r)u(`${o.Service} (${o.Status})`,"info")}}catch(n){u("Failed to parse service status","error"),x("Parse error",{error:String(n)}),process.exit(l.ERROR)}}async function oc(e,t){u(`Streaming logs for ${j.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 R({command:"docker",args:n,cwd:y(),interactive:!0,label:`Docker Compose Logs (${e})`,dryRun:t.dryRun})).exitCode!==0&&(u(`Failed to stream logs for ${e}`,"error"),process.exit(l.ERROR))}async function ic(e,t){let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let i=await Ct.confirm({message:`Restart service ${j.cyan(e)}?`,initialValue:!1});(Ct.isCancel(i)||!i)&&(u("Restart cancelled","warn"),process.exit(l.CANCELLED))}u(`Restarting service ${j.cyan(e)}...`,"info");let r=["compose","restart"];t.timeout&&r.push("--timeout",String(t.timeout)),r.push(e);let o=await R({command:"docker",args:r,cwd:y(),interactive:!1,label:`Docker Compose Restart (${e})`,dryRun:t.dryRun});o.exitCode===0?u(`Service ${j.cyan(e)} restarted successfully`,"success"):(u(`Failed to restart service ${e}`,"error"),x("Docker error",{stderr:o.stderr}),process.exit(l.ERROR))}async function ac(e){u("Running deep health check...","info");let t=[],n=1e4,r=await R({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 R({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 R({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 c=s.healthy?j.green("\u2713"):j.red("\u2716");u(`${c} ${s.service}: ${s.message}`,s.healthy?"success":"error")}let a=t.every(s=>s.healthy);u(`Overall health: ${a?j.green("HEALTHY"):j.red("UNHEALTHY")}`,a?"success":"error")}}async function sc(e,t,n){let r=parseInt(t,10);(Number.isNaN(r)||r<0)&&(u("Invalid replica count (must be a non-negative number)","error"),process.exit(l.INVALID_ARGS)),u(`Scaling ${j.cyan(e)} to ${j.cyan(String(r))} replicas...`,"info");let o=await R({command:"docker",args:["compose","up","-d","--scale",`${e}=${r}`],cwd:y(),interactive:!1,label:`Docker Compose Scale (${e})`,dryRun:n.dryRun});o.exitCode===0?u(`Service ${j.cyan(e)} scaled to ${r} replicas`,"success"):(u(`Failed to scale service ${e}`,"error"),x("Docker error",{stderr:o.stderr}),process.exit(l.ERROR))}function no(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 rc(s);break;case"logs":r.length===0&&(u("logs requires a service name: nebutra services logs <service>","error"),process.exit(l.INVALID_ARGS)),await oc(r[0],s);break;case"restart":r.length===0&&(u("restart requires a service name: nebutra services restart <service>","error"),process.exit(l.INVALID_ARGS)),await ic(r[0],s);break;case"health":await ac(s);break;case"scale":r.length<2&&(u("scale requires a service name and replica count: nebutra services scale <service> <count>","error"),process.exit(l.INVALID_ARGS)),await sc(r[0],r[1],s);break;default:u(`Unknown services subcommand: ${n}. Valid commands: status, list, logs, restart, health, scale`,"error"),process.exit(l.ERROR)}}catch(c){let m=c instanceof Error?c.message:String(c);u(`Services command failed: ${m}`,"error"),x("Full error",{error:c}),process.exit(l.ERROR)}}).addHelpText("after",()=>{let n="postgres, redis, clickhouse (run `nebutra services status` for the live list)";try{n=tc(vn()).join(", ")}catch{}return`
499
506
  Examples:
500
507
  nebutra services status Show all service status
508
+ nebutra services list Alias for \`status\`
501
509
  nebutra services logs postgres Stream postgres logs
502
510
  nebutra services logs postgres --tail 50 Show last 50 postgres logs
503
511
  nebutra services restart redis Restart redis service
504
- nebutra services health Deep health check (pg, redis, clickhouse, meilisearch)
512
+ nebutra services health Deep health check (postgres, redis, clickhouse)
505
513
  nebutra services scale ai-service 3 Scale ai-service to 3 replicas
506
514
 
507
- Services Available:
508
- postgres, redis, clickhouse, meilisearch, novu, openfga, ai-service, content-service,
509
- recsys-service, ecommerce-service, web3-service, billing-service, event-ingest, idp,
510
- jaeger, nginx
515
+ Services Available (from docker-compose.yml):
516
+ ${n}
511
517
 
512
518
  Flags:
513
519
  --dry-run Show what would be run without executing
@@ -516,28 +522,28 @@ Flags:
516
522
  --tail <n> Log lines to show (default: 100)
517
523
  --since <duration> Show logs since (e.g., 10m, 1h)
518
524
  --timeout <seconds> Timeout for restart
519
- `)}import{join as Ha}from"path";import be from"picocolors";import{existsSync as mr,readFileSync as pr}from"fs";import{dirname as Ya,join as fr,parse as Ja}from"path";import{stderr as Ba}from"process";import se from"picocolors";function Ma(){return process.stderr.isTTY===!0&&!process.env.CI&&!process.env.NEBUTRA_NON_TTY}function Ga(e){let t=[];return t.push(se.red(`\u2716 ${e.error}`)),t.push(se.white(e.message)),e.suggestion&&(t.push(""),t.push(se.cyan("\u{1F4A1} Suggestion:")),t.push(se.gray(` ${e.suggestion}`))),process.env.NEBUTRA_DEBUG&&e.context&&Object.keys(e.context).length>0&&(t.push(""),t.push(se.dim("Debug context:")),t.push(se.dim(JSON.stringify(e.context,null,2)))),process.env.NEBUTRA_DEBUG&&e.stack&&(t.push(""),t.push(se.dim("Stack trace:")),t.push(se.dim(e.stack))),t.join(`
520
- `)}function Va(e){let t={error:e.error,message:e.message,...e.suggestion&&{suggestion:e.suggestion},retryable:e.retryable,exitCode:e.exitCode,...e.context&&Object.keys(e.context).length>0&&{context:e.context},...process.env.NEBUTRA_DEBUG&&e.stack&&{stack:e.stack}};return JSON.stringify(t)}function Le(e){return{error:e.error,message:e.message,suggestion:e.suggestion,retryable:e.retryable??!1,exitCode:e.exitCode??c.ERROR,context:e.context,stack:e.cause?.stack}}function Tt(e){let t=Ma()?Ga(e):Va(e);Ba.write(t+`
521
- `)}function Ka(e){Tt(e),process.exit(e.exitCode)}function Dt(e,t){Ka(Le({error:"not_found",message:e,suggestion:t??"Check the resource path and try again",exitCode:c.NOT_FOUND}))}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??c.ERROR,this.suggestion=t.suggestion,this.retryable=t.retryable??!1,this.context=t.context,this.cause=t.cause}};function za(e){return e instanceof K}function Wa(e){return za(e)?Le({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?Le({error:"unexpected_error",message:e.message,suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:c.ERROR,cause:e}):Le({error:"unexpected_error",message:String(e),suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:c.ERROR})}function Lt(e){let t=Wa(e);return Tt(t),t.exitCode}async function he(e){try{await e()}catch(t){process.exitCode=Lt(t)}}var Ae={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 dt(e){let t=e,{root:n}=Ja(t);for(;;){if(mr(fr(t,"nebutra.config.json")))return t;if(t===n)return null;let r=Ya(t);if(r===t)return null;t=r}}function mt(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:c.CONFIG_ERROR});return n}function qa(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 gr(e){let t={...process.env};for(let n of[".env",".env.local"]){let r=fr(e,n);if(mr(r))try{let o=qa(pr(r,"utf-8"));for(let[i,a]of Object.entries(o))process.env[i]===void 0&&(t[i]=a)}catch{}}return t}function yr(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 hr(e){let t=Object.keys(Ae),n=e.filter(a=>!Ae[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:c.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 Za(e,t){switch(e){case"live":return be.green(t);case"local-fallback":return be.yellow(t);case"missing-key":return be.red(t);default:return t}}async function Xa(e){let t=dt(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:c.CONFIG_ERROR});let n=Ha(t,"nebutra.config.json"),r=mt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],i=gr(t),a=i.NEBUTRA_LOCALE||"global",s=typeof r.stack=="string"?r.stack:"unknown",d=o.map(f=>{let v=Ae[f];return v?yr(f,v,i):{name:f,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:d},{format:"json"});return}let p=[];p.push(be.bold("nebutra status")),p.push(be.dim(`stack: ${s} locale: ${a} project: ${t}`)),p.push("");let g=Math.max(10,...d.map(f=>f.name.length)),y=Math.max(14,...d.map(f=>f.state.length));for(let f of d){let v=f.name.padEnd(g),T=Za(f.state,f.state.padEnd(y)),w=f.provider.length>0?f.provider.join(", "):"-";p.push(`${v} ${T} ${be.dim(w)}`),f.state!=="live"&&p.push(`${" ".repeat(g)} ${be.dim(`\u2192 ${f.next}`)}`)}console.log(p.join(`
522
- `))}function br(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)=>he(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await Xa({json:t.json,format:r.format})}))}import{existsSync as vr,readFileSync as Qa,writeFileSync as wr}from"fs";import{join as Ft}from"path";import Fe from"picocolors";var Cr=".env.example",xr=".env.local",es=["# Local secrets for this machine \u2014 never commit real values.","# `nebutra sync` created this file; add your own keys below.",""].join(`
523
- `);function ts(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 ns(e,t){let n=ts(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}
525
+ `})}import{join as uc}from"path";import xe from"picocolors";import{existsSync as ro,readFileSync as oo}from"fs";import{dirname as cc,join as io,parse as lc}from"path";var Te={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 St(e){let t=e,{root:n}=lc(t);for(;;){if(ro(io(t,"nebutra.config.json")))return t;if(t===n)return null;let r=cc(t);if(r===t)return null;t=r}}function Rt(e){let t=oo(e,"utf-8"),n=JSON.parse(t);if(!n||typeof n!="object"||Array.isArray(n))throw new E({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 dc(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 ao(e){let t={...process.env};for(let n of[".env",".env.local"]){let r=io(e,n);if(ro(r))try{let o=dc(oo(r,"utf-8"));for(let[i,a]of Object.entries(o))process.env[i]===void 0&&(t[i]=a)}catch{}}return t}function so(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 co(e){let t=Object.keys(Te),n=e.filter(a=>!Te[a]);if(n.length>0)throw new E({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 mc(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 pc(e){let t=St(process.cwd());if(!t)throw new E({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=uc(t,"nebutra.config.json"),r=Rt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],i=ao(t),a=i.NEBUTRA_LOCALE||"global",s=typeof r.stack=="string"?r.stack:"unknown",c=o.map(f=>{let w=Te[f];return w?so(f,w,i):{name:f,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:c},{format:"json"});return}let p=[];p.push(xe.bold("nebutra status")),p.push(xe.dim(`stack: ${s} locale: ${a} project: ${t}`)),p.push("");let g=Math.max(10,...c.map(f=>f.name.length)),h=Math.max(14,...c.map(f=>f.state.length));for(let f of c){let w=f.name.padEnd(g),D=mc(f.state,f.state.padEnd(h)),k=f.provider.length>0?f.provider.join(", "):"-";p.push(`${w} ${D} ${xe.dim(k)}`),f.state!=="live"&&p.push(`${" ".repeat(g)} ${xe.dim(`\u2192 ${f.next}`)}`)}console.log(p.join(`
526
+ `))}function lo(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)=>z(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await pc({json:t.json,format:r.format})}))}import{spawn as fc}from"child_process";import{existsSync as gc,readFileSync as hc}from"fs";function uo(e){let t=e.trim(),n=!t.startsWith("{")&&!/^https?:/.test(t)&&gc(t)?hc(t,"utf8"):t;return Xn(n)}function yc(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";fc(t,[e],{stdio:"ignore",detached:!0,shell:process.platform==="win32"}).on("error",()=>d.warn(`Could not open a browser. Open ${e} yourself.`)).unref()}function mo(e){d.error(e instanceof O?e.message:String(e)),process.exit(l.INVALID_ARGS)}var bc=()=>(process.env.NEBUTRA_API_URL??Z("api")).replace(/\/+$/,"");async function vc(){let e=await ce();return e&&!e.expired?e.token:null}async function wc(e,t,n={}){return fetch(`${bc()}/api/v1/studio${e}`,{...n,headers:{authorization:`Bearer ${t}`,"content-type":"application/json",...n.headers},signal:AbortSignal.timeout(1e4)})}async function kc(){let e=await vc();if(!e)return null;let t=await wc("/presets",e);if(!t.ok)throw new Error(`The gateway answered ${t.status}.`);return(await t.json()).presets}function xc(e){let t=ot(e);return{code:t,preset:e,reviewUrl:Qn(e),apply:`nebutra studio pull ${t}`,create:`npx create-sailor@latest my-app --preset ${t}`}}function po(e){let t=e.command("studio").description("Sailor Studio for agents: write a preset, review it in the browser, pull it");t.command("schema").description("Print the preset JSON Schema (what a preset may contain)").action(()=>{console.log(JSON.stringify(Zn(),null,2))}),t.command("preview <preset>").description("Validate a preset and print the Sailor Studio link to review it").option("--open","Open the link in the browser").option("--json","Machine-readable output").action((n,r)=>{let o;try{o=xc(uo(n))}catch(i){mo(i)}if(r.open&&yc(o.reviewUrl),r.json){console.log(JSON.stringify(o,null,2));return}d.success(`Preset ${o.code} is valid.`),console.log(`
527
+ Review it: ${o.reviewUrl}`),console.log(` Apply here: ${o.apply}`),console.log(` New project: ${o.create}
528
+ `)}),t.command("list").description("The looks you saved in Studio (nebutra login), newest first").option("--json","Machine-readable output").action(async n=>{let r;try{r=await kc()}catch(o){d.error(String(o instanceof Error?o.message:o)),process.exit(l.ERROR)}if(r===null&&(d.error("Not logged in. Run `nebutra login` to sync presets with Studio."),process.exit(l.PERMISSION_DENIED)),n.json){console.log(JSON.stringify({presets:r},null,2));return}if(r.length===0){console.log("No saved looks yet. Save one in Sailor Studio.");return}for(let o of r)console.log(` ${o.code.padEnd(12)} ${o.name}`)}),t.command("pull [preset]").description("Put a preset (code, JSON, file or Studio link) on this project; --latest takes your newest saved one").option("--latest","Use the newest preset saved to your account").option("--only <group>","Change only one group of knobs: theme | fonts").option("--no-build","Write the preset without rebuilding the tokens").option("--json","Machine-readable output").action(async(n,r)=>{let o;try{o=ot(uo(n))}catch(a){mo(a)}let i=["apply","--preset",o];r.only&&i.push("--only",r.only),r.build===!1&&i.push("--no-build"),r.json&&i.push("--format","json"),await e.parseAsync(i,{from:"user"})})}import{existsSync as fo,readFileSync as Cc,writeFileSync as go}from"fs";import{join as rn}from"path";import Ye from"picocolors";var ho=".env.example",yo=".env.local",Sc=["# Local secrets for this machine \u2014 never commit real values.","# `nebutra sync` created this file; add your own keys below.",""].join(`
529
+ `);function Rc(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 Ec(e,t){let n=Rc(e),r=[],o=[],i=[];for(let m of t){let p=Te[m];if(p)for(let g of p.providers){if(g.envKeys.length===0)continue;let h=[];for(let f of g.envKeys)n.has(f)?o.push(f):h.push(f);if(h.length!==0){i.push([`# ${m} (${g.id})`,...h.map(f=>`${f}=`)].join(`
530
+ `));for(let f of h)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}
525
531
 
526
532
  `:""}${i.join(`
527
533
 
528
534
  `)}
529
- `,added:r,unchanged:o}}async function rs(e){let t=dt(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:c.CONFIG_ERROR});let n=Ft(t,"nebutra.config.json"),r=mt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],{capabilities:i,warnings:a}=hr(o),s=Ft(t,Cr),d=vr(s),m=d?Qa(s,"utf-8"):"",p=ns(m,i),g=Ft(t,xr),y=vr(g),f={};p.added.length>0&&(f[Cr]=p.added),y||(f[xr]=[]);let v={added:f,unchanged:p.unchanged,warnings:a},T=e.json===!0||e.format==="json";if(e.dryRun){I({mode:"dry-run",command:"sync",projectRoot:t,...v},{format:T?"json":e.format});for(let w of a)u(w,"warn");process.exit(c.DRY_RUN_OK)}if((p.added.length>0||!d)&&wr(s,p.content),y||wr(g,es),T)b(v,{format:"json"});else{let w=[];w.push(Fe.bold("nebutra sync")),w.push(Fe.dim(`project: ${t}`)),w.push("");let z=Object.keys(f);if(z.length===0)w.push(Fe.dim("Env files already match declared capabilities. Nothing to do."));else for(let Q of z){let F=f[Q]??[];F.length>0?w.push(`${Fe.green("+")} ${Q}: added ${F.join(", ")}`):w.push(`${Fe.green("+")} ${Q}: created`)}console.log(w.join(`
530
- `))}for(let w of a)u(w,"warn");u("Run `nebutra status` to check capability readiness.")}function Sr(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)=>he(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await rs({dryRun:t.dryRun,json:t.json,format:r.format})}))}import*as j from"@clack/prompts";import k from"picocolors";function ce(e){if(e==="json"||e==="plain"||e==="table")return e}var Ut=["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 os(e){let t=`@nebutra/${e}`;if(!Ut.includes(e)){let n=k.yellow(`Valid apps: ${Ut.join(", ")}`);throw new Error(`Invalid app: ${k.red(e)}
531
- ${n}`)}return t}async function is(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){os(e.app);let r=`@nebutra/${e.app}`;e.quiet||j.log.info(k.cyan(`Running tests for ${k.bold(r)}...`));let o=await re("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 Er(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 Rr(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 kr(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 Or=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 Er({...a,ui:!!r.ui,ci:!!r.ci}):n==="size"?await Rr({...a,why:!!r.why}):n==="arch"?await kr(a):await is({...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 Er({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 Rr({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 kr({dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})})};var as={$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=as,ss=le.languages.map(e=>e.id),Bt=le.defaultLanguage;function Mt(e){return le.languages.find(t=>t.id===e)}function Ar(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??cs()}function cs(){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 ls(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 us(e,t="table"){let n=Mt(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(`
533
- `)}function _r(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(ls(Ar(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=us(n,Ar(r));o||(l.error(`Design language '${n}' not found. Run: nebutra theme list`),process.exit(c.NOT_FOUND)),console.log(o)})}import{existsSync as Pr,readFileSync as jr}from"fs";import{resolve as Ir,join as Gt}from"path";function $r(e={}){let t=e.manifestPath?Ir(e.manifestPath):Gt(Ir(e.root??process.cwd()),"apps","design-docs","public","agent-manifest.json");return{manifestPath:t,componentDir:Gt(t,"..","agent","components")}}function ds(e){return e.trim().toLowerCase()}function ms(e){let t=ds(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 Tr(e={}){let{manifestPath:t}=$r(e);if(!Pr(t))throw new Error(`Missing Nebutra UI agent manifest at ${t}. Run pnpm --filter @nebutra/design-docs build:registry.`);return JSON.parse(jr(t,"utf8"))}function Vt(e,t={}){let n=ms(e),{componentDir:r}=$r(t),o=Gt(r,`${n}.json`);if(!Pr(o))throw new Error(`UI component contract not found: ${n}`);return JSON.parse(jr(o,"utf8"))}function Dr(e,t="",n={}){let r=t.trim().toLowerCase(),o=Nr(n.limit??20,1,100),i=Nr(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?ps(p).includes(r):!0).map(p=>({component:p,score:fs(p,r)})).sort((p,g)=>g.score-p.score||p.component.name.localeCompare(g.component.name)).map(({component:p})=>p),d=s.slice(i,i+o),m=i+d.length;return{query:t,total:s.length,count:d.length,offset:i,limit:o,hasMore:m<s.length,...m<s.length&&{nextOffset:m},items:d}}function Kt(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 ps(e){return[e.name,e.title,e.description,e.status,e.maturity,e.layer,e.source,...e.tags].join(" ").toLowerCase()}function fs(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 Nr(e,t,n){return Number.isFinite(e)?Math.min(Math.max(Math.trunc(e),t),n):t}function pt(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??gs()}function gs(){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 Wt(e){let t=e.opts?e.opts():e;return{root:C(),manifestPath:t.manifest}}function Lr(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function ys(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(`
534
- `)}return JSON.stringify(e,null,2)}function hs(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(`
535
- `):JSON.stringify(e,null,2)}function bs(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(`
535
+ `,added:r,unchanged:o}}async function Oc(e){let t=St(process.cwd());if(!t)throw new E({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=rn(t,"nebutra.config.json"),r=Rt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],{capabilities:i,warnings:a}=co(o),s=rn(t,ho),c=fo(s),m=c?Cc(s,"utf-8"):"",p=Ec(m,i),g=rn(t,yo),h=fo(g),f={};p.added.length>0&&(f[ho]=p.added),h||(f[yo]=[]);let w={added:f,unchanged:p.unchanged,warnings:a},D=e.json===!0||e.format==="json";if(e.dryRun){N({mode:"dry-run",command:"sync",projectRoot:t,...w},{format:D?"json":e.format});for(let k of a)u(k,"warn");process.exit(l.DRY_RUN_OK)}if((p.added.length>0||!c)&&go(s,p.content),h||go(g,Sc),D)b(w,{format:"json"});else{let k=[];k.push(Ye.bold("nebutra sync")),k.push(Ye.dim(`project: ${t}`)),k.push("");let J=Object.keys(f);if(J.length===0)k.push(Ye.dim("Env files already match declared capabilities. Nothing to do."));else for(let te of J){let B=f[te]??[];B.length>0?k.push(`${Ye.green("+")} ${te}: added ${B.join(", ")}`):k.push(`${Ye.green("+")} ${te}: created`)}console.log(k.join(`
536
+ `))}for(let k of a)u(k,"warn");u("Run `nebutra status` to check capability readiness.")}function bo(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)=>z(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await Oc({dryRun:t.dryRun,json:t.json,format:r.format})}))}import*as T from"@clack/prompts";import _ from"picocolors";function me(e){if(e==="json"||e==="plain"||e==="table")return e}var on=["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 Ac(e){let t=`@nebutra/${e}`;if(!on.includes(e)){let n=_.yellow(`Valid apps: ${on.join(", ")}`);throw new Error(`Invalid app: ${_.red(e)}
537
+ ${n}`)}return t}async function _c(e){e.dryRun&&(N({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:me(e.format)}),process.exit(l.DRY_RUN_OK));try{if(e.app&&(e.watch||e.coverage)&&(T.log.error(_.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(l.INVALID_ARGS)),e.app){Ac(e.app);let r=`@nebutra/${e.app}`;e.quiet||T.log.info(_.cyan(`Running tests for ${_.bold(r)}...`));let o=await se("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...";T.log.info(_.cyan(r))}let n=await F(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?T.log.error(_.red(t.message)):T.log.error(_.red("Unknown error occurred")),process.exit(l.ERROR)}}async function vo(e){e.dryRun&&(N({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:me(e.format)}),process.exit(l.DRY_RUN_OK));try{e.ui&&e.ci&&(T.log.error(_.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...";T.log.info(_.cyan(r))}let n=await F(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?T.log.error(_.red(t.message)):T.log.error(_.red("Unknown error occurred")),process.exit(l.ERROR)}}async function wo(e){e.dryRun&&(N({mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"},{format:me(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...";T.log.info(_.cyan(r))}let n=await F(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?T.log.error(_.red(t.message)):T.log.error(_.red("Unknown error occurred")),process.exit(l.ERROR)}}async function ko(e){e.dryRun&&(N({mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"},{format:me(e.format)}),process.exit(l.DRY_RUN_OK));try{e.quiet||T.log.info(_.cyan("Running architecture tests..."));let t=await F("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?T.log.error(_.red(t.message)):T.log.error(_.red("Unknown error occurred")),process.exit(l.ERROR)}}var xo=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: ${on.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r,o)=>{let i=I(r,o),a={dryRun:!!r.dryRun,quiet:!!i.quiet,verbose:!!i.verbose,format:me(i.format)};n==="e2e"?await vo({...a,ui:!!r.ui,ci:!!r.ci}):n==="size"?await wo({...a,why:!!r.why}):n==="arch"?await ko(a):await _c({...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=I(n,r);await vo({ui:!!n.ui,ci:!!n.ci,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:me(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=I(n,r);await wo({why:!!n.why,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:me(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=I(n,r);await ko({dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:me(o.format)})})};var Ic={$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}}]},pe=Ic,Pc=pe.languages.map(e=>e.id),an=pe.defaultLanguage;function sn(e){return pe.languages.find(t=>t.id===e)}function Co(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??Nc()}function Nc(){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 $c(e="table"){let t=pe.languages;return e==="json"?JSON.stringify({version:pe.version,defaultLanguage:pe.defaultLanguage,count:t.length,languages:t},null,2):[`Nebutra design languages (${t.length}) \u2014 global product chrome swap`,`Default: ${an} (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(`
538
+ `)}function jc(e,t="table"){let n=sn(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(`
539
+ `)}function So(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($c(Co(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=jc(n,Co(r));o||(d.error(`Design language '${n}' not found. Run: nebutra theme list`),process.exit(l.NOT_FOUND)),console.log(o)})}import{existsSync as Oo,readFileSync as Ao}from"fs";import{resolve as Ro,join as cn}from"path";function _o(e={}){let t=e.manifestPath?Ro(e.manifestPath):cn(Ro(e.root??process.cwd()),"apps","design-docs","public","agent-manifest.json");return{manifestPath:t,componentDir:cn(t,"..","agent","components")}}function Tc(e){return e.trim().toLowerCase()}function Fc(e){let t=Tc(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 Io(e={}){let{manifestPath:t}=_o(e);if(!Oo(t))throw new Error(`Missing Nebutra UI agent manifest at ${t}. Run pnpm --filter @nebutra/design-docs build:registry.`);return JSON.parse(Ao(t,"utf8"))}function ln(e,t={}){let n=Fc(e),{componentDir:r}=_o(t),o=cn(r,`${n}.json`);if(!Oo(o))throw new Error(`UI component contract not found: ${n}`);return JSON.parse(Ao(o,"utf8"))}function Po(e,t="",n={}){let r=t.trim().toLowerCase(),o=Eo(n.limit??20,1,100),i=Eo(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?Dc(p).includes(r):!0).map(p=>({component:p,score:Lc(p,r)})).sort((p,g)=>g.score-p.score||p.component.name.localeCompare(g.component.name)).map(({component:p})=>p),c=s.slice(i,i+o),m=i+c.length;return{query:t,total:s.length,count:c.length,offset:i,limit:o,hasMore:m<s.length,...m<s.length&&{nextOffset:m},items:c}}function dn(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 Dc(e){return[e.name,e.title,e.description,e.status,e.maturity,e.layer,e.source,...e.tags].join(" ").toLowerCase()}function Lc(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 Eo(e,t,n){return Number.isFinite(e)?Math.min(Math.max(Math.trunc(e),t),n):t}function Et(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??Uc()}function Uc(){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 mn(e){let t=e.opts?e.opts():e;return{root:y(),manifestPath:t.manifest}}function No(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function Bc(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(`
540
+ `)}return JSON.stringify(e,null,2)}function Mc(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(`
541
+ `):JSON.stringify(e,null,2)}function Gc(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
542
  `)}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 vs(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(`
538
- `):JSON.stringify(n,null,2)}function zt(e,t){try{return Vt(e,Wt(t))}catch{Dt(`UI component contract not found: ${e}`,"Run `nebutra ui search <query> --format json` to discover available component ids.")}}function Fr(e){try{return Tr(Wt(e))}catch(t){Dt(t instanceof Error?t.message:"UI agent manifest not found","Run `pnpm --filter @nebutra/design-docs build:registry` from the Nebutra monorepo.")}}function ws(e,t){let n=e.components.map(o=>Kt(Vt(o.name,Wt(t)))),r=n.filter(o=>!o.valid).length;return{valid:r===0,total:n.length,invalid:r,results:n}}function Ur(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=Fr(r),i=Dr(o,n??"",{limit:Lr(r.limit,20),offset:Lr(r.offset,0),tag:r.tag,status:r.status,maturity:r.maturity});console.log(ys(i,pt(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=zt(n,r);console.log(hs(o,pt(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?Kt(zt(n,r)):ws(Fr(r),r);console.log(bs(o,pt(r))),!o.valid&&!r.warnOnly&&process.exit(c.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(c.INCOMPATIBLE));let o=zt(n,r);console.log(vs(o,pt(r)))})}import{existsSync as Br,readFileSync as Cs,unlinkSync as xs,writeFileSync as Ss}from"fs";import{dirname as Es,join as Mr,parse as Rs}from"path";function ks(e){let t=e,{root:n}=Rs(t);for(;;){if(Br(Mr(t,"package.json")))return t;if(t===n)return null;let r=Es(t);if(r===t)return null;t=r}}async function Os(e){let t=e.format==="json",n=ks(process.cwd())??process.cwd(),r=Mr(n,"nebutra.config.json");if(Br(r)||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):l.info("Already unlinked"),process.exit(c.SUCCESS)),e.force){try{xs(r)}catch(s){let d=s instanceof Error?s.message:String(s);t?console.log(JSON.stringify({command:"unlink",success:!1,error:d},null,2)):l.error(`Failed to delete config: ${d}`),process.exit(c.PERMISSION_DENIED)}t?console.log(JSON.stringify({command:"unlink",success:!0,deletedConfig:!0,configPath:r},null,2)):l.success("Removed nebutra.config.json");return}let o={};try{o=JSON.parse(Cs(r,"utf-8"))}catch{o={}}"projectId"in o||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):l.info("Already unlinked"),process.exit(c.SUCCESS));let{projectId:i,...a}=o;Ss(r,JSON.stringify(a,null,2)+`
539
- `),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):l.success("Unlinked from project")}function Gr(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 Os({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as Vs}from"child_process";import{existsSync as As,readFileSync as Kr}from"fs";import{dirname as Vr,join as _s}from"path";import{fileURLToPath as Is}from"url";function Ns(e=import.meta.url){let t=Vr(Is(e));for(let n=0;n<6;n+=1){let r=_s(t,"package.json");if(As(r))try{if(JSON.parse(Kr(r,"utf8")).name==="nebutra")return r}catch{}let o=Vr(t);if(o===t)break;t=o}throw new Error("Unable to locate the nebutra CLI package.json")}function ft(e=import.meta.url){return JSON.parse(Kr(Ns(e),"utf8")).version}import{promises as gt}from"fs";import{homedir as Ps}from"os";import{join as Wr}from"path";import js from"p-timeout";import ue from"picocolors";var $s=1440*60*1e3,Yr=Wr(Ps(),".nebutra"),Yt=Wr(Yr,"update-check.json"),Ts="https://registry.npmjs.org/nebutra",Ds=5e3;async function Ls(){try{await gt.mkdir(Yr,{recursive:!0})}catch{}}async function Fs(){try{let e=await gt.readFile(Yt,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<$s?t:(await gt.unlink(Yt).catch(r=>{l.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function Us(e){try{await Ls();let t={timestamp:Date.now(),latestVersion:e};await gt.writeFile(Yt,JSON.stringify(t,null,2),"utf-8")}catch{}}async function Bs(){try{let e=new AbortController,t=await js(fetch(Ts,{signal:e.signal,headers:{Accept:"application/json"}}),{milliseconds:Ds,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 zr(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function Ms(e,t){let n=zr(e),r=zr(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 Jt(e){let t=await Fs(),n=null;return t?n=t.latestVersion:(n=await Bs(),n&&await Us(n)),!n||!Ms(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function Gs(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=[ue.cyan("\u256D"+"\u2500".repeat(41)+"\u256E"),ue.cyan("\u2502")+ue.yellow(o+n+o)+ue.cyan("\u2502"),ue.cyan("\u2502")+ue.gray(i+r+i)+ue.cyan("\u2502"),ue.cyan("\u2570"+"\u2500".repeat(41)+"\u256F")]}async function Jr(e){let t=null;return Jt(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&Gs(t))}}var ve=ft();function Ks(){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 zs(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 Ws(e){let t=Ks(),n=zs(t),r=e.format==="json",o=await Jt(ve),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:ve,latestVersion:i,hasUpdate:a},null,2)):(l.info(`Detected installer: ${t}`),l.info(`Current: ${ve}${i?` \u2192 Latest: ${i}`:""}`),l.info(`Upgrade command: ${n}`)),process.exit(c.DRY_RUN_OK)),!a&&i&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,alreadyLatest:!0,version:ve},null,2)):l.success(`Already on the latest version (${ve})`),process.exit(c.SUCCESS)),e.yes||(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,command_to_run:n,currentVersion:ve,latestVersion:i,requiresConfirmation:!0},null,2)):(l.info(`Current: ${ve}${i?` \u2192 Latest: ${i}`:""}`),l.info("To upgrade, run:"),l.info(` ${n}`),l.info("Or re-run this command with --yes to execute it now.")),process.exit(c.SUCCESS));let[s,...d]=n.split(" ");r||l.info(`Running: ${n}`);let m=Vs(s,d,{stdio:r?"pipe":"inherit"});m.status===0&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,ran:n},null,2)):l.success("Upgrade complete"),process.exit(c.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)):l.error(p),process.exit(c.ERROR)}function qr(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return Ws({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 qt(e,t){let n=t==="expired"?`Your ${B.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)):l.error(n),process.exit(c.PERMISSION_DENIED)}async function Ys(e,t){let n=!!e.json||e.format==="json"||t==="json",r=await Wn();if(!r)return qt(n,"missing");if(r.expired)return qt(n,"expired");let o=at(),i=await st(o,r.token);if(!i)return qt(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)):(l.success(i.email??i.userId),i.name&&l.info(i.name))}function Hr(e){e.command("whoami").description(`Show the ${B.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 Ys(t,r.format)})}import{existsSync as Js,mkdirSync as qs,writeFileSync as Hs}from"fs";import{homedir as Zr,platform as Zs}from"os";import{join as Ue}from"path";import Ht from"picocolors";function Xs(){if(Zs()==="win32"){let t=process.env.LOCALAPPDATA||Ue(Zr(),"AppData","Local");return Ue(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Ue(e,"nebutra"):Ue(Zr(),".config","nebutra")}function Qs(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function Xr(e,t){try{qs(e,{recursive:!0}),Hs(t,"")}catch{}}function Qr(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=Xs(),t=Ue(e,"first-run-acked");try{if(Js(t))return}catch{return}if(Qs()){Xr(e,t);return}let r=[`${Ht.cyan("\u2139")} ${B.name} collects anonymous usage analytics to improve the CLI.`,` Opt out at any time: ${Ht.dim("export NEBUTRA_TELEMETRY=0")}`,` Privacy policy: ${Ht.dim(`${it("landing")}/legal/cli-analytics`)}`,""];try{process.stderr.write(r.join(`
540
- `))}catch{}Xr(e,t)}var ro=ft();function tc(e){let t=new ec,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=>he(async()=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await In({dryRun:r.dryRun||!1,yes:o.yes||!1,ifNotExists:r.ifNotExists||!1})})),rr(t),cr(t),on(t),An(t),_n(t),Cn(t),jn(t),nn(t),gn(t),On(t),yn(t),Or(t),vn(t),_r(t),Ur(t),dr(t),lr(t),dn(t),er(t),nr(t),Hr(t),qr(t),Dn(t),Gr(t),br(t),Sr(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(()=>he(async()=>{let{logger:r}=await import("./logger-QMYN56HK.js"),{findMonorepoRoot:o}=await import("./delegate-GIJ3G5CK.js"),i=await import("fs"),a=await import("path");r.info("Running project health check...");let s=!1,d=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(d,"nebutra.config.json"))?r.success("nebutra.config.json found"):r.warn("nebutra.config.json missing. Try running 'nebutra init'"),i.existsSync(a.join(d,"package.json"))?r.success("package.json found"):(r.error("No package.json found in root directory"),s=!0),i.existsSync(a.join(d,".env"))||i.existsSync(a.join(d,".env.local"))?r.success("Environment variables configured"):r.warn("No .env or .env.local found. Some features may not work properly.");let y=a.join(d,"apps/api-gateway");i.existsSync(y)&&r.warn("Legacy `apps/api-gateway/` present. Expected `backends/gateway/` \u2014 see CLAUDE.md for the W2.x restructure.");let f=a.join(d,"backends/gateway");i.existsSync(f)?r.success("backends/gateway/ present"):i.existsSync(a.join(d,"backends"));let v=a.join(d,"packages");if(i.existsSync(v)){let z=new Set(["design","iam","commerce","integrations","platform","ops","ai"]);try{let Q=i.readdirSync(v,{withFileTypes:!0}),F=[];for(let we of Q){if(!we.isDirectory()||z.has(we.name))continue;let Be=a.join(v,we.name,"package.json");i.existsSync(Be)&&F.push(we.name)}F.length>0?r.warn(`Found ${F.length} uncategorized package(s) under packages/: ${F.join(", ")}. Expected packages/<category>/<name>/ \u2014 see CLAUDE.md.`):r.success("Packages follow categorized layout")}catch{}}let T=a.join(d,".nebutra"),w=a.join(T,"scaffold-meta.json");if(i.existsSync(w)?r.success(".nebutra/scaffold-meta.json present (CLI-scaffolded project)"):i.existsSync(T)&&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(d,"nebutra.config.json")))&&(r.info(""),r.info("Golden path to a running app:"),r.info(" 1. Fill .env.local (copy keys from .env.example)"),r.info(" 2. pnpm infra:up # local Postgres/Redis if needed"),r.info(" 3. pnpm db:migrate && pnpm db:seed"),r.info(" 4. pnpm dev # http://localhost:3000")),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:c.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",`
543
+ `)}return JSON.stringify(e,null,2)}function Vc(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(`
544
+ `):JSON.stringify(n,null,2)}function un(e,t){try{return ln(e,mn(t))}catch{_t(`UI component contract not found: ${e}`,"Run `nebutra ui search <query> --format json` to discover available component ids.")}}function $o(e){try{return Io(mn(e))}catch{_t("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 zc(e,t){let n=e.components.map(o=>dn(ln(o.name,mn(t)))),r=n.filter(o=>!o.valid).length;return{valid:r===0,total:n.length,invalid:r,results:n}}function jo(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=$o(r),i=Po(o,n??"",{limit:No(r.limit,20),offset:No(r.offset,0),tag:r.tag,status:r.status,maturity:r.maturity});console.log(Bc(i,Et(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=un(n,r);console.log(Mc(o,Et(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?dn(un(n,r)):zc($o(r),r);console.log(Gc(o,Et(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=un(n,r);console.log(Vc(o,Et(r)))})}import{existsSync as To,readFileSync as Kc,unlinkSync as Wc,writeFileSync as Yc}from"fs";import{dirname as Jc,join as Fo,parse as qc}from"path";function Hc(e){let t=e,{root:n}=qc(t);for(;;){if(To(Fo(t,"package.json")))return t;if(t===n)return null;let r=Jc(t);if(r===t)return null;t=r}}async function Zc(e){let t=e.format==="json",n=Hc(process.cwd())??process.cwd(),r=Fo(n,"nebutra.config.json");if(To(r)||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):d.info("Already unlinked"),process.exit(l.SUCCESS)),e.force){try{Wc(r)}catch(s){let c=s instanceof Error?s.message:String(s);t?console.log(JSON.stringify({command:"unlink",success:!1,error:c},null,2)):d.error(`Failed to delete config: ${c}`),process.exit(l.PERMISSION_DENIED)}t?console.log(JSON.stringify({command:"unlink",success:!0,deletedConfig:!0,configPath:r},null,2)):d.success("Removed nebutra.config.json");return}let o={};try{o=JSON.parse(Kc(r,"utf-8"))}catch{o={}}"projectId"in o||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):d.info("Already unlinked"),process.exit(l.SUCCESS));let{projectId:i,...a}=o;Yc(r,JSON.stringify(a,null,2)+`
545
+ `),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):d.success("Unlinked from project")}function Do(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 Zc({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as pl}from"child_process";import{existsSync as Xc,readFileSync as Uo}from"fs";import{dirname as Lo,join as Qc}from"path";import{fileURLToPath as el}from"url";function tl(e=import.meta.url){let t=Lo(el(e));for(let n=0;n<6;n+=1){let r=Qc(t,"package.json");if(Xc(r))try{if(JSON.parse(Uo(r,"utf8")).name==="nebutra")return r}catch{}let o=Lo(t);if(o===t)break;t=o}throw new Error("Unable to locate the nebutra CLI package.json")}function Ot(e=import.meta.url){return JSON.parse(Uo(tl(e),"utf8")).version}import{promises as At}from"fs";import{homedir as nl}from"os";import{join as Mo}from"path";import rl from"p-timeout";import fe from"picocolors";var ol=1440*60*1e3,Go=Mo(nl(),".nebutra"),pn=Mo(Go,"update-check.json"),il="https://registry.npmjs.org/nebutra",al=5e3;async function sl(){try{await At.mkdir(Go,{recursive:!0})}catch{}}async function cl(){try{let e=await At.readFile(pn,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<ol?t:(await At.unlink(pn).catch(r=>{d.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function ll(e){try{await sl();let t={timestamp:Date.now(),latestVersion:e};await At.writeFile(pn,JSON.stringify(t,null,2),"utf-8")}catch{}}async function dl(){try{let e=new AbortController,t=await rl(fetch(il,{signal:e.signal,headers:{Accept:"application/json"}}),{milliseconds:al,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 Bo(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function ul(e,t){let n=Bo(e),r=Bo(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 fn(e){let t=await cl(),n=null;return t?n=t.latestVersion:(n=await dl(),n&&await ll(n)),!n||!ul(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function ml(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=[fe.cyan("\u256D"+"\u2500".repeat(41)+"\u256E"),fe.cyan("\u2502")+fe.yellow(o+n+o)+fe.cyan("\u2502"),fe.cyan("\u2502")+fe.gray(i+r+i)+fe.cyan("\u2502"),fe.cyan("\u2570"+"\u2500".repeat(41)+"\u256F")]}async function Vo(e){let t=null;return fn(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&ml(t))}}var Ce=Ot();function fl(){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 gl(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 hl(e){let t=fl(),n=gl(t),r=e.format==="json",o=await fn(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)):(d.info(`Detected installer: ${t}`),d.info(`Current: ${Ce}${i?` \u2192 Latest: ${i}`:""}`),d.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)):d.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)):(d.info(`Current: ${Ce}${i?` \u2192 Latest: ${i}`:""}`),d.info("To upgrade, run:"),d.info(` ${n}`),d.info("Or re-run this command with --yes to execute it now.")),process.exit(l.SUCCESS));let[s,...c]=n.split(" ");r||d.info(`Running: ${n}`);let m=pl(s,c,{stdio:r?"pipe":"inherit"});m.status===0&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,ran:n},null,2)):d.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)):d.error(p),process.exit(l.ERROR)}function zo(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return hl({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 gn(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)):d.error(n),process.exit(l.PERMISSION_DENIED)}async function yl(e,t){let n=!!e.json||e.format==="json"||t==="json",r=await ce();if(!r)return gn(n,"missing");if(r.expired)return gn(n,"expired");let o=vt(),i=await wt(o,r.token);if(!i)return gn(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)):(d.success(i.email??i.userId),i.name&&d.info(i.name))}function Ko(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 yl(t,r.format)})}import bl from"http";var vl=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy"];function Wo(e=process.env,t=bl){return!vl.some(n=>e[n])||typeof t.setGlobalProxyFromEnv!="function"?!1:(t.setGlobalProxyFromEnv(e),!0)}import{existsSync as wl,mkdirSync as kl,writeFileSync as xl}from"fs";import{homedir as Yo,platform as Cl}from"os";import{join as Je}from"path";import hn from"picocolors";function Sl(){if(Cl()==="win32"){let t=process.env.LOCALAPPDATA||Je(Yo(),"AppData","Local");return Je(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Je(e,"nebutra"):Je(Yo(),".config","nebutra")}function Rl(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function Jo(e,t){try{kl(e,{recursive:!0}),xl(t,"")}catch{}}function qo(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=Sl(),t=Je(e,"first-run-acked");try{if(wl(t))return}catch{return}if(Rl()){Jo(e,t);return}let r=[`${hn.cyan("\u2139")} ${M.name} collects anonymous usage analytics to improve the CLI.`,` Opt out at any time: ${hn.dim("export NEBUTRA_TELEMETRY=0")}`,` Privacy policy: ${hn.dim(`${Z("landing")}/legal/cli-analytics`)}`,""];try{process.stderr.write(r.join(`
546
+ `))}catch{}Jo(e,t)}Wo();var Qo=Ot();function Ol(e){let t=new El,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=>z(async()=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Ar({dryRun:r.dryRun||!1,yes:o.yes||!1,ifNotExists:r.ifNotExists||!1})})),Jr(t),Qr(t),rr(t),Er(t),Or(t),vr(t),Pr(t),Un(t),pr(t),Rr(t),fr(t),xo(t),yr(t),So(t),tr(t),po(t),jn(t),jo(t),no(t),eo(t),lr(t),Gr(t),zr(t),Ko(t),zo(t),jr(t),Do(t),lo(t),bo(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(()=>z(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,c=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(c,"nebutra.config.json"))?r.success("nebutra.config.json found"):r.warn("nebutra.config.json missing. Try running 'nebutra init'"),i.existsSync(a.join(c,"package.json"))?r.success("package.json found"):(r.error("No package.json found in root directory"),s=!0),i.existsSync(a.join(c,".env"))||i.existsSync(a.join(c,".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(c,"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 f=a.join(c,"backends/gateway");i.existsSync(f)?r.success("backends/gateway/ present"):i.existsSync(a.join(c,"backends"));let w=a.join(c,"packages");if(i.existsSync(w)){let J=new Set(["design","iam","commerce","integrations","platform","ops","ai"]);try{let te=i.readdirSync(w,{withFileTypes:!0}),B=[];for(let Se of te){if(!Se.isDirectory()||J.has(Se.name))continue;let qe=a.join(w,Se.name,"package.json");i.existsSync(qe)&&B.push(Se.name)}B.length>0?r.warn(`Found ${B.length} uncategorized package(s) under packages/: ${B.join(", ")}. Expected packages/<category>/<name>/ \u2014 see CLAUDE.md.`):r.success("Packages follow categorized layout")}catch{}}let D=a.join(c,".nebutra"),k=a.join(D,"scaffold-meta.json");if(i.existsSync(k)?r.success(".nebutra/scaffold-meta.json present (CLI-scaffolded project)"):i.existsSync(D)&&r.warn(".nebutra/ directory exists but scaffold-meta.json is missing. Harmless \u2014 the marker is provenance only and grants nothing."),(i.existsSync(k)||i.existsSync(a.join(c,"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 E({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
547
  Examples:
542
548
  $ nebutra init Initialize a new project
543
549
  $ nebutra status Show capability readiness (live/local-fallback/missing-key)
@@ -572,4 +578,4 @@ Environment:
572
578
  NEBUTRA_OUTPUT_FORMAT Output format (json|table|plain)
573
579
  NO_COLOR Disable colored output
574
580
  CI Auto-enable non-interactive mode
575
- `),t}async function nc(){Qr();let e=await Jr(ro),t=tc({version:ro,isInteractive:process.stdin.isTTY!==!1&&process.stdout.isTTY!==!1});process.argv.length<=2&&(t.outputHelp(),process.exit(c.SUCCESS)),await t.parseAsync(process.argv),await e()}function rc(){if(!process.argv[1])return!1;try{return eo(no(import.meta.url))===eo(to(process.argv[1]))}catch{return no(import.meta.url)===to(process.argv[1])}}var oc=rc();oc&&nc().catch(e=>{process.exitCode=Lt(e)});export{tc as buildProgram};
581
+ `),t}async function Al(){qo();let e=await Vo(Qo),t=Ol({version:Qo,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 _l(){if(!process.argv[1])return!1;try{return Ho(Xo(import.meta.url))===Ho(Zo(process.argv[1]))}catch{return Xo(import.meta.url)===Zo(process.argv[1])}}var Il=_l();Il&&Al().catch(e=>{process.exitCode=It(e)});export{Ol as buildProgram};