nebutra 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/index.js +90 -63
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -19,6 +19,9 @@ nebutra init
|
|
|
19
19
|
# Check capability readiness (live / local-fallback / missing-key)
|
|
20
20
|
nebutra status
|
|
21
21
|
|
|
22
|
+
# Sync .env.example / .env.local with the capabilities declared in nebutra.config.json
|
|
23
|
+
nebutra sync
|
|
24
|
+
|
|
22
25
|
# Scaffold a new project (separate tool — one creation entry point)
|
|
23
26
|
npx create-sailor ./my-app
|
|
24
27
|
|
|
@@ -44,6 +47,7 @@ nebutra doctor
|
|
|
44
47
|
|---------|-------------|
|
|
45
48
|
| `init` | Initialize project with `nebutra.config.json` |
|
|
46
49
|
| `status` | Show capability readiness — live, local-fallback, or missing-key, per env (`--json`) |
|
|
50
|
+
| `sync` | Make `.env.example`/`.env.local` agree with declared capabilities, idempotently (`--dry-run`, `--json`) |
|
|
47
51
|
| `mcp` | Start the MCP server for AI agents and editors |
|
|
48
52
|
| `dev` | Start development server |
|
|
49
53
|
| `generate` | Scaffold apps, modules, and code |
|
|
@@ -61,6 +65,8 @@ nebutra doctor
|
|
|
61
65
|
| `secrets` | Encrypted secrets management |
|
|
62
66
|
| `completions` | Generate shell completions for the current command surface |
|
|
63
67
|
| `link` / `unlink` | Link or unlink the project to Nebutra platform metadata |
|
|
68
|
+
| `login` | Authorize this machine with your Nebutra account (device flow, agent-friendly with `--json`) |
|
|
69
|
+
| `whoami` | Show the Nebutra identity this machine is authorized as |
|
|
64
70
|
| `logout` / `upgrade` | Session and CLI lifecycle |
|
|
65
71
|
|
|
66
72
|
Scaffolding, registry, and platform-operations commands (`create`, `add`,
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as l}from"./chunk-JDX5NXDX.js";import{a as
|
|
3
|
-
`)}function ee(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function It(e){let t=Ne(),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 gr(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 _t(e){let t=ee(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,a])=>a.enabled).map(([a])=>a);return{path:Y(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function G(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??yr();return{...n,...t,...r?{format:r}:{}}}function yr(){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 he(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function br(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(a=>({name:a,value:he(process.env[a])}))})),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`)),M(n,e.format,"ai:models")}async function hr(e){e.format!=="json"&&l.info("Scanning for available agents...");try{let t=Xe(process.cwd(),"backends/gateway/src/routes/agents"),n=[];try{let o=await import("fs");o.existsSync(t)&&(n=o.readdirSync(t).filter(i=>i.endsWith(".ts")&&!i.endsWith(".d.ts")).map(i=>({name:i.replace(".ts",""),path:`backends/gateway/src/routes/agents/${i}`})))}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)`)),M(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 vr(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"),M(n,t.format,"ai:test")}async function Cr(e){e.format!=="json"&&l.info("Checking AI configuration...");let t={providers:{openai:{key:he(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:he(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:he(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=Xe(process.cwd(),"nebutra.config.ts"),o=await import("fs");if(o.existsSync(r)){let i=o.readFileSync(r,"utf-8").match(/preset:\s*["']([^"']+)["']/);i&&(t.preset=i[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(", ")}`)),M(t,e.format,"ai:config")}async function wr(e){let t=ce(),n=ee(t),r=Ne(),o=Object.values(r).map(i=>{let s=n.providers?.[i.id];return{id:i.id,name:i.name,enabled:s?.enabled===!0,configured:i.envVars.some(d=>!!process.env[d]),envVars:i.envVars.map(d=>({name:d,value:he(process.env[d])}))}}),a={configPath:Y(),providers:o,enabledCount:o.filter(i=>i.enabled).length,totalProviders:o.length};if(e.format!=="json"){let i=o.filter(s=>s.enabled);i.length===0?l.warn("No runtime AI providers enabled in nebutra.config.json."):l.success(`Enabled AI providers: ${i.map(s=>s.id).join(", ")}`)}M(a,e.format,"ai:provider:list")}async function Sr(e,t){let n=It(e),r=ce(),o=ee(r),a=Ne(),i=new Date().toISOString();for(let d of n)o.providers[d]={enabled:!0,envVars:a[d].envVars,enabledAt:o.providers?.[d]?.enabledAt??i};Pe(r);let s={configPath:Y(),enabled:n,env:t.env===!0?n.flatMap(d=>a[d].envVars.map(m=>({provider:d,name:m,example:`${m}=`}))):void 0,ai:_t(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 a[d].envVars)console.log(`${m}=`)}M(s,t.format,"ai:provider:enable")}async function Er(e,t){let n=It(e),r=ce(),o=ee(r),a=Ne(),i=new Date().toISOString();for(let d of n)o.providers[d]={enabled:!1,envVars:o.providers?.[d]?.envVars??a[d].envVars,disabledAt:i};Pe(r);let s={configPath:Y(),disabled:n,ai:_t(r)};t.format!=="json"&&l.success(`Disabled AI provider(s): ${n.join(", ")}`),M(s,t.format,"ai:provider:disable")}async function Rr(e){let t=ce(),n=ee(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},Pe(t);let o={configPath:Y(),gateway:n.gateway};e.format!=="json"&&l.success("AI gateway governance initialized in nebutra.config.json"),M(o,e.format,"ai:gateway:init")}async function xr(e){let t=ce(),n=ee(t),r={configPath:Y(),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")),M(r,e.format,"ai:gateway:status")}async function kr(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=gr(t.fallback),r=ce(),o=ee(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},Pe(r);let a={configPath:Y(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&l.success(`AI route '${e}' set with policy '${t.policy}'`),M(a,t.format,"ai:route:set")}async function Or(e){let t=ce(),n=ee(t),r=Object.entries(n.routes??{}).map(([a,i])=>({name:a,...i})),o={configPath:Y(),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(a=>a.name).join(", ")}`)),M(o,e.format,"ai:route:list")}function Nt(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 a=>{let i=G(a);await wr({format:i.format,interactive:i.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(a,i)=>{let s=G(i);await Sr(a,{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(a,i)=>{let s=G(i);await Er(a,{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 a=>{let i=G(a);await Rr({format:i.format,interactive:i.yes!==!0})}),r.command("status").description("Show local AI gateway governance status").option("--format <type>","Output format: json or plain").action(async a=>{let i=G(a);await xr({format:i.format,interactive:i.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(a,i)=>{let s=G(i);await kr(a,{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 a=>{let i=G(a);await Or({format:i.format,interactive:i.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 a=>{let i=G(a);await br({dryRun:i.dryRun===!0,format:i.format,interactive:i.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 a=>{let i=G(a);await hr({dryRun:i.dryRun===!0,format:i.format,interactive:i.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(a,i)=>{let s=G(i);await vr(a,{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 a=>{let i=G(a);await Cr({dryRun:i.dryRun===!0,format:i.format,interactive:i.yes!==!0})})}function ve(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 Pt(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function Ar(e){l.info("Initializing brand system...");let t=await P("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});ve(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand system initialized successfully")}async function Ir(e){l.info("Applying brand configuration...");let t=await P("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});ve(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand applied successfully")}async function _r(e){let t=[];e.primary&&(Pt(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&&(Pt(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 k({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});ve(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||l.success("Color palette generated successfully")}async function Nr(e){l.info("Syncing brand tokens across packages...");let t=await P("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});ve(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand tokens synced successfully")}async function Pr(e){l.info("Verifying brand token consistency...");let t=await P("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});ve(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 $t(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 Ar({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 Ir({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 _r({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 Nr({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 Pr({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import{appendFileSync as $r,existsSync as jr,readFileSync as Tr,writeFileSync as Dr}from"fs";import{homedir as Ce}from"os";import{join as ge}from"path";import*as j from"@clack/prompts";import $ from"picocolors";var W={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:"logout",description:"Clear local Nebutra CLI session state",usage:"nebutra logout"},{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:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var $e=(W.subcommands??[]).map(e=>e.name),jt={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",logout:"Clear local session state",upgrade:"Upgrade local CLI tooling",link:"Link local project metadata",unlink:"Unlink local project metadata",status:"Show capability readiness (live/local-fallback/missing-key)"},Lr=["--help","--version","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--json"],Fr=$e.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${jt[e]}"`).join(`
|
|
4
|
-
`);function
|
|
2
|
+
import{b as l}from"./chunk-JDX5NXDX.js";import{a as C,b as O,c as $,d as ne,e as Ce,f as ee}from"./chunk-LGUMYJ4Q.js";import{realpathSync as Zr}from"fs";import{resolve as Xr}from"path";import{fileURLToPath as Qr}from"url";import{Command as Zs}from"commander";import{existsSync as to,readFileSync as no,writeFileSync as ro}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 oo=["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",io=oo,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 W(e,t,n){if(t==="json"){let r={command:n||"ai",...e&&typeof e=="object"&&"exitCode"in e?{exitCode:e.exitCode}:{},...e};console.log(JSON.stringify(r,null,2))}else e&&typeof e=="object"&&"stdout"in e&&e.stdout&&console.log(e.stdout),e&&typeof e=="object"&&"stderr"in e&&e.stderr&&(e.exitCode??0)!==0&&console.error(e.stderr)}function ao(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function so(e){return Xt[e]?Xt[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function Me(){return Object.fromEntries(io.map(e=>[e,{id:e,name:ao(e),envVars:so(e)}]))}function q(){return yt(process.cwd(),Qt)}function de(){let e=q();if(!to(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(no(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){ro(q(),`${JSON.stringify(e,null,2)}
|
|
3
|
+
`)}function re(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function en(e){let t=Me(),n=[...new Set(e.map(o=>o.toLowerCase()))],r=n.filter(o=>!t[o]);return r.length>0&&(l.error(`Unknown AI provider(s): ${r.join(", ")}. Valid providers: ${Object.keys(t).join(", ")}`),process.exit(c.INVALID_ARGS)),n}function co(e){let t=e?.split(",").map(r=>r.trim()).filter(Boolean)??[];t.length===0&&(l.error("Route fallback cannot be empty. Use --fallback provider:model,provider:model"),process.exit(c.INVALID_ARGS));let n=t.filter(r=>!/^[a-z0-9-]+:[^,\s]+$/i.test(r));return n.length>0&&(l.error(`Invalid fallback target(s): ${n.join(", ")}. Expected provider:model.`),process.exit(c.INVALID_ARGS)),t}function tn(e){let t=re(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,i])=>i.enabled).map(([i])=>i);return{path:q(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function Y(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??lo();return{...n,...t,...r?{format:r}:{}}}function lo(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function _e(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function uo(e){e.format!=="json"&&l.info("Checking configured AI models and providers...");let t={openai:{name:"OpenAI",keyVars:["OPENAI_API_KEY"],configured:!1},anthropic:{name:"Anthropic Claude",keyVars:["ANTHROPIC_API_KEY"],configured:!1},openrouter:{name:"OpenRouter",keyVars:["OPENROUTER_API_KEY"],configured:!1},vercel:{name:"Vercel AI SDK",keyVars:["VERCEL_AI_API_KEY"],configured:!1}};for(let r of Object.values(t))r.configured=r.keyVars.some(o=>process.env[o]);let n={providers:Object.entries(t).map(([r,o])=>({id:r,name:o.name,configured:o.configured,keys:o.keyVars.map(i=>({name:i,value:_e(process.env[i])}))})),configuredCount:Object.values(t).filter(r=>r.configured).length,totalProviders:Object.keys(t).length};e.dryRun||(n.configuredCount===0?l.warn("No AI providers configured. Set API keys to enable AI features."):l.success(`${n.configuredCount} AI provider(s) configured`)),W(n,e.format,"ai:models")}async function mo(e){e.format!=="json"&&l.info("Scanning for available agents...");try{let t=yt(process.cwd(),"backends/gateway/src/routes/agents"),n=[];try{let o=await import("fs");o.existsSync(t)&&(n=o.readdirSync(t).filter(a=>a.endsWith(".ts")&&!a.endsWith(".d.ts")).map(a=>({name:a.replace(".ts",""),path:`backends/gateway/src/routes/agents/${a}`})))}catch{n=[]}let r={agents:n.length>0?n:[{name:"No agents found",path:"create agents in backends/gateway/src/routes/agents/"}],count:n.length};e.dryRun||(r.count===0?l.info("No agents configured. Create agents in backends/gateway/src/routes/agents/"):l.success(`Found ${r.count} agent(s)`)),W(r,e.format,"ai:agents")}catch(t){l.error(`Failed to scan agents: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}async function po(e,t){(!e||e.trim().length===0)&&(l.error("Prompt cannot be empty"),process.exit(c.INVALID_ARGS)),t.format!=="json"&&(l.info("Testing AI prompt against default model..."),l.info("Note: Ensure API gateway is running on http://localhost:3001"));let n={prompt:e,note:"To execute this test, the API gateway must be running locally. Run: pnpm --filter @nebutra/gateway dev",endpoint:"http://localhost:3001/api/ai/test",method:"POST",payload:{prompt:e.substring(0,100)}};t.dryRun||l.warn("AI test execution requires a running API gateway. Start it with: pnpm --filter @nebutra/gateway dev"),W(n,t.format,"ai:test")}async function fo(e){e.format!=="json"&&l.info("Checking AI configuration...");let t={providers:{openai:{key:_e(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:_e(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:_e(process.env.OPENROUTER_API_KEY),configured:!!process.env.OPENROUTER_API_KEY}},environment:{NODE_ENV:process.env.NODE_ENV||"development",NEBUTRA_LOG_LEVEL:process.env.NEBUTRA_LOG_LEVEL||"info"}};try{let r=yt(process.cwd(),"nebutra.config.ts"),o=await import("fs");if(o.existsSync(r)){let a=o.readFileSync(r,"utf-8").match(/preset:\s*["']([^"']+)["']/);a&&(t.preset=a[1])}}catch{}let n=Object.entries(t.providers).filter(([,r])=>r.configured).map(([r])=>r);e.dryRun||(n.length===0?l.warn("No AI providers configured. Set environment variables to enable AI features."):l.success(`Configuration loaded: ${n.join(", ")}`)),W(t,e.format,"ai:config")}async function go(e){let t=de(),n=re(t),r=Me(),o=Object.values(r).map(a=>{let s=n.providers?.[a.id];return{id:a.id,name:a.name,enabled:s?.enabled===!0,configured:a.envVars.some(d=>!!process.env[d]),envVars:a.envVars.map(d=>({name:d,value:_e(process.env[d])}))}}),i={configPath:q(),providers:o,enabledCount:o.filter(a=>a.enabled).length,totalProviders:o.length};if(e.format!=="json"){let a=o.filter(s=>s.enabled);a.length===0?l.warn("No runtime AI providers enabled in nebutra.config.json."):l.success(`Enabled AI providers: ${a.map(s=>s.id).join(", ")}`)}W(i,e.format,"ai:provider:list")}async function yo(e,t){let n=en(e),r=de(),o=re(r),i=Me(),a=new Date().toISOString();for(let d of n)o.providers[d]={enabled:!0,envVars:i[d].envVars,enabledAt:o.providers?.[d]?.enabledAt??a};Ge(r);let s={configPath:q(),enabled:n,env:t.env===!0?n.flatMap(d=>i[d].envVars.map(m=>({provider:d,name:m,example:`${m}=`}))):void 0,ai:tn(r)};if(t.format!=="json"&&(l.success(`Enabled AI provider(s): ${n.join(", ")}`),t.env)){l.info("Required environment variables:");for(let d of n)for(let m of i[d].envVars)console.log(`${m}=`)}W(s,t.format,"ai:provider:enable")}async function ho(e,t){let n=en(e),r=de(),o=re(r),i=Me(),a=new Date().toISOString();for(let d of n)o.providers[d]={enabled:!1,envVars:o.providers?.[d]?.envVars??i[d].envVars,disabledAt:a};Ge(r);let s={configPath:q(),disabled:n,ai:tn(r)};t.format!=="json"&&l.success(`Disabled AI provider(s): ${n.join(", ")}`),W(s,t.format,"ai:provider:disable")}async function bo(e){let t=de(),n=re(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},Ge(t);let o={configPath:q(),gateway:n.gateway};e.format!=="json"&&l.success("AI gateway governance initialized in nebutra.config.json"),W(o,e.format,"ai:gateway:init")}async function vo(e){let t=de(),n=re(t),r={configPath:q(),gateway:n.gateway??null,initialized:n.gateway?.enabled===!0};e.format!=="json"&&(r.initialized?l.success("AI gateway governance is initialized"):l.warn("AI gateway governance is not initialized. Run: nebutra ai gateway init")),W(r,e.format,"ai:gateway:status")}async function wo(e,t){(!e||e.trim().length===0)&&(l.error("Route name cannot be empty"),process.exit(c.INVALID_ARGS)),t.policy||(l.error("Route policy is required. Use --policy <policy>."),process.exit(c.INVALID_ARGS));let n=co(t.fallback),r=de(),o=re(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},Ge(r);let i={configPath:q(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&l.success(`AI route '${e}' set with policy '${t.policy}'`),W(i,t.format,"ai:route:set")}async function Co(e){let t=de(),n=re(t),r=Object.entries(n.routes??{}).map(([i,a])=>({name:i,...a})),o={configPath:q(),routes:r,count:r.length};e.format!=="json"&&(r.length===0?l.warn("No AI routes configured. Run: nebutra ai route set chat --policy cost-latency-balanced --fallback openai:gpt-5.4"):l.success(`Configured AI routes: ${r.map(i=>i.name).join(", ")}`)),W(o,e.format,"ai:route:list")}function nn(e){let t=e.command("ai").description("Manage AI models, agents, and configuration"),n=t.command("provider").description("Manage runtime AI provider governance");n.command("list").description("List supported and enabled AI providers").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await go({format:a.format,interactive:a.yes!==!0})}),n.command("enable <providers...>").description("Enable one or more runtime AI providers in nebutra.config.json").option("--env","Print required environment variable placeholders").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await yo(i,{env:s.env===!0,format:s.format,interactive:s.yes!==!0})}),n.command("disable <providers...>").description("Disable one or more runtime AI providers in nebutra.config.json").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await ho(i,{format:s.format,interactive:s.yes!==!0})});let r=t.command("gateway").description("Manage local AI gateway governance");r.command("init").description("Initialize the local AI gateway governance block").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await bo({format:a.format,interactive:a.yes!==!0})}),r.command("status").description("Show local AI gateway governance status").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await vo({format:a.format,interactive:a.yes!==!0})});let o=t.command("route").description("Manage AI routing policies");o.command("set <name>").description("Create or update an AI route policy").requiredOption("--policy <policy>","Routing policy id").requiredOption("--fallback <list>","Comma-separated provider:model fallback chain").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await wo(i,{policy:s.policy,fallback:s.fallback,format:s.format,interactive:s.yes!==!0})}),o.command("list").description("List configured AI routes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await Co({format:a.format,interactive:a.yes!==!0})}),t.command("models").description("List configured AI models and providers").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await uo({dryRun:a.dryRun===!0,format:a.format,interactive:a.yes!==!0})}),t.command("agents").description("List available agents in the project").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await mo({dryRun:a.dryRun===!0,format:a.format,interactive:a.yes!==!0})}),t.command("test <prompt>").description("Send a test prompt to the default AI model (requires running API gateway)").option("--dry-run","Preview without executing").option("--format <type>","Output format: json or plain").action(async(i,a)=>{let s=Y(a);await po(i,{dryRun:s.dryRun===!0,format:s.format,interactive:s.yes!==!0})}),t.command("config").description("Show current AI configuration and provider status").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async i=>{let a=Y(i);await fo({dryRun:a.dryRun===!0,format:a.format,interactive:a.yes!==!0})})}function Ie(e,t,n){if(t==="json"){let r={command:n||"brand",exitCode:e.exitCode,success:e.exitCode===0,...e.stdout&&{stdout:e.stdout},...e.stderr&&{stderr:e.stderr}};console.log(JSON.stringify(r,null,2))}else e.stdout&&console.log(e.stdout),e.stderr&&e.exitCode!==0&&console.error(e.stderr)}function rn(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function So(e){l.info("Initializing brand system...");let t=await $("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand system initialized successfully")}async function xo(e){l.info("Applying brand configuration...");let t=await $("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand applied successfully")}async function Eo(e){let t=[];e.primary&&(rn(e.primary)||(l.error(`Invalid primary color format: ${e.primary}. Expected hex format like #0033FE`),process.exit(c.INVALID_ARGS)),t.push(`--primary=${e.primary}`)),e.secondary&&(rn(e.secondary)||(l.error(`Invalid secondary color format: ${e.secondary}. Expected hex format like #0BF1C3`),process.exit(c.INVALID_ARGS)),t.push(`--secondary=${e.secondary}`)),t.length===0&&(l.warn("No colors specified. Usage: nebutra brand palette --primary=#HEX --secondary=#HEX"),l.info("Example: nebutra brand palette --primary=#0033FE --secondary=#0BF1C3"),process.exit(c.INVALID_ARGS)),l.info(`Generating color palette: ${t.join(" ")}`);let n=await O({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});Ie(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||l.success("Color palette generated successfully")}async function Ro(e){l.info("Syncing brand tokens across packages...");let t=await $("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||l.success("Brand tokens synced successfully")}async function ko(e){l.info("Verifying brand token consistency...");let t=await $("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});Ie(t,e.format,"brand:verify-tokens"),t.exitCode!==0&&(l.error("Brand token verification failed. There are inconsistencies in your design tokens."),process.exit(t.exitCode)),e.dryRun||l.success("All brand tokens are consistent")}function on(e){let t=e.command("brand").description("Manage Nebutra brand system and design tokens");t.command("init").description("Initialize brand system configuration").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await So({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("apply").description("Apply brand configuration to the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await xo({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("palette").description("Generate brand color palette from custom colors").option("--primary <hex>","Primary brand color (hex format, e.g. #0033FE)").option("--secondary <hex>","Secondary brand color (hex format, e.g. #0BF1C3)").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await Eo({primary:n.primary,secondary:n.secondary,dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("sync").description("Synchronize brand tokens across all packages").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await Ro({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("verify").description("Verify brand token consistency across the project").option("--dry-run","Preview changes without executing").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await ko({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import{appendFileSync as Oo,existsSync as Ao,readFileSync as _o,writeFileSync as Io}from"fs";import{homedir as Ne}from"os";import{join as Se}from"path";import*as L from"@clack/prompts";import D from"picocolors";var H={name:"nebutra",description:"Nebutra \u2014 the CLI for Sailor projects: status, dev, db, and codegen",usage:"nebutra [command] [options]",options:[{flags:"--format <type>",description:"Output format: json, table, plain"},{flags:"--yes, --no-interactive",description:"Skip all interactive prompts (Agent mode)"},{flags:"--no-color",description:"Disable colored output"},{flags:"--verbose",description:"Enable verbose output"},{flags:"--quiet",description:"Suppress non-essential output"}],subcommands:[{name:"init",description:"Initialize a Nebutra project and create nebutra.config.json",usage:"nebutra init [options]",options:[{flags:"--dry-run",description:"Preview changes without writing files (exits with code 10)"},{flags:"--yes",description:"Skip all interactive prompts (Agent mode)"},{flags:"--if-not-exists",description:"Skip initialization if nebutra.config.json already exists"}],arguments:[],examples:[{command:"nebutra init",description:"Initialize Nebutra configuration in the current directory"},{command:"nebutra init --dry-run",description:"Preview initialization changes without writing files"},{command:"nebutra init --yes --if-not-exists",description:"Initialize without prompts, skip if already configured"}]},{name:"mcp",description:"Start the Nebutra MCP server for AI agents and editors",usage:"nebutra mcp [options]",arguments:[],options:[{flags:"--stdio",description:"Use stdio transport for communication (default: enabled)",default:!0},{flags:"--verbose",description:"Enable verbose logging for MCP server"}],examples:[{command:"nebutra mcp",description:"Start the MCP server for AI-powered project context integration"},{command:"nebutra mcp --verbose",description:"Start the MCP server with detailed logging output"}]},{name:"schema",description:"Show command schema and argument documentation (Agent-friendly JSON output)",usage:"nebutra schema [command] [options]",arguments:[{name:"command",description:"Command name to show schema for (e.g., init, dev, db)",required:!1}],options:[{flags:"--all",description:"Show full schema for all commands as JSON",default:!1},{flags:"--list",description:"List all available command names",default:!1},{flags:"--exit-codes",description:"Show exit codes reference",default:!1}],examples:[{command:"nebutra schema --all",description:"Show complete JSON of all commands, args, options, value domains"},{command:"nebutra schema init",description:"Show schema for init command (arguments, options, defaults, examples)"},{command:"nebutra schema --list",description:"List just the command names (quick discovery)"},{command:"nebutra schema --exit-codes",description:"Show exit codes reference for all possible exit codes"}]},{name:"brand",description:"Manage governed brand tokens, palettes, and visual system outputs",usage:"nebutra brand [subcommand]",examples:[{command:"nebutra brand palette --primary=#0047FF",description:"Generate a token-aligned blue palette"}]},{name:"i18n",description:"Manage localization files and multilingual product copy",usage:"nebutra i18n [subcommand]"},{name:"infra",description:"Manage local infrastructure services for Nebutra development",usage:"nebutra infra [subcommand]",examples:[{command:"nebutra infra up --lite",description:"Start lightweight local infrastructure"}]},{name:"env",description:"Validate and manage environment variables across apps and packages",usage:"nebutra env [subcommand]"},{name:"license",description:"Manage Nebutra Sailor commercial license activation and status",usage:"nebutra license [subcommand]",arguments:[],options:[],subcommands:[{name:"activate",description:"Activate a commercial license key for local development",usage:"nebutra license activate <key>",arguments:[{name:"key",description:"Your Nebutra Sailor commercial license key",required:!0}],options:[{flags:"--quiet",description:"Suppress output"}],examples:[{command:"nebutra license activate liz_1234567890",description:"Activate your license key globally"}]},{name:"status",description:"Check the locally configured license status",usage:"nebutra license status",arguments:[],options:[{flags:"--quiet",description:"Suppress output"}],examples:[{command:"nebutra license status",description:"Check if you have an active license"}]}]},{name:"ai",description:"Configure AI providers, gateway routing, and agent-ready defaults",usage:"nebutra ai [subcommand]"},{name:"db",description:"Manage database schema, migrations, seeds, and generated clients",usage:"nebutra db [subcommand]"},{name:"generate",description:"Generate apps, modules, API surfaces, and typed project artifacts",usage:"nebutra generate [type] [name]"},{name:"dev",description:"Start development workflows for selected Nebutra apps or presets",usage:"nebutra dev [options]"},{name:"build",description:"Run build workflows through the Nebutra CLI",usage:"nebutra build [options]"},{name:"lint",description:"Run lint workflows through the Nebutra CLI",usage:"nebutra lint [options]"},{name:"typecheck",description:"Run TypeScript checks through the Nebutra CLI",usage:"nebutra typecheck [options]"},{name:"test",description:"Run unit, architecture, and E2E verification workflows",usage:"nebutra test [scope]"},{name:"e2e",description:"Run browser end-to-end verification suites",usage:"nebutra e2e [suite]"},{name:"theme",description:"Inspect registry-backed Nebutra themes and governance metadata",usage:"nebutra theme [subcommand]"},{name:"ui",description:"Search, inspect, validate, and plan migrations for @nebutra/ui components",usage:"nebutra ui [subcommand]"},{name:"services",description:"Inspect and manage microservice health, logs, scaling, and rollouts",usage:"nebutra services [subcommand]"},{name:"secrets",description:"Manage encrypted tenant and platform secrets",usage:"nebutra secrets [subcommand]"},{name:"completions",description:"Generate shell completions for the current Nebutra command surface",usage:"nebutra completions [shell]",arguments:[{name:"shell",description:"Shell to generate completions for: bash, zsh, fish, or install",required:!1}]},{name:"login",description:"Authorize this machine with your Nebutra account (device flow)",usage:"nebutra login [options]",options:[{flags:"--json",description:"Print verification details as JSON and exit immediately (agent mode)"},{flags:"--no-browser",description:"Don't try to open a browser"},{flags:"--poll",description:"Poll until approved/denied/expired, resuming a pending `login --json` if present"},{flags:"--format <type>",description:"Output format: json or plain"}],examples:[{command:"nebutra login",description:"Human flow: open browser, wait for approval"},{command:"nebutra login --json",description:"Agent flow: print verification link/code and exit immediately"},{command:"nebutra login --poll --json",description:"Resume and wait for a pending login"}]},{name:"logout",description:"Clear local Nebutra CLI session state",usage:"nebutra logout"},{name:"whoami",description:"Show the Nebutra identity this machine is authorized as",usage:"nebutra whoami [options]",options:[{flags:"--json",description:"Output as JSON"},{flags:"--format <type>",description:"Output format: json or plain"}]},{name:"upgrade",description:"Upgrade local Nebutra CLI tooling",usage:"nebutra upgrade"},{name:"link",description:"Link a local project to Nebutra platform metadata",usage:"nebutra link"},{name:"unlink",description:"Unlink local Nebutra project metadata",usage:"nebutra unlink"},{name:"status",description:"Show capability readiness \u2014 live, local-fallback, or missing-key, per environment",usage:"nebutra status [options]",arguments:[],options:[{flags:"--json",description:"Emit machine-readable JSON"}],examples:[{command:"nebutra status",description:"Show a readiness table for every capability in nebutra.config.json"},{command:"nebutra status --json",description:"Emit { stack, locale, capabilities } as JSON for agents"}]},{name:"sync",description:"Make .env.example / .env.local agree with the declared capabilities (idempotent)",usage:"nebutra sync [options]",arguments:[],options:[{flags:"--dry-run",description:"Preview planned additions without writing files (exits with code 10)"},{flags:"--json",description:"Emit machine-readable JSON"}],examples:[{command:"nebutra sync",description:"Add any env keys required by declared capabilities to .env.example, create .env.local if missing"},{command:"nebutra sync --dry-run",description:"Preview planned additions without writing files"},{command:"nebutra sync --json",description:"Emit { added, unchanged, warnings } as JSON for agents"}]},{name:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var Ve=(H.subcommands??[]).map(e=>e.name),an={init:"Initialize a Nebutra project and create nebutra.config.json",mcp:"Start the Nebutra MCP server for AI agents and editors",completions:"Generate shell completions",doctor:"Check your Nebutra project setup",schema:"Show command schema and argument documentation",brand:"Manage governed brand tokens and palettes",i18n:"Manage localization files and multilingual product copy",infra:"Manage local infrastructure services",env:"Validate and manage environment variables",license:"Manage Nebutra Sailor commercial license activation and status",db:"Database migration and management",generate:"Scaffold apps, modules, and code",dev:"Start development server",build:"Run build workflows",lint:"Run lint workflows",typecheck:"Run TypeScript checks",test:"Run unit and E2E tests",e2e:"Run browser E2E suites",theme:"Theme registry and governance metadata",ai:"AI provider and gateway routing configuration",services:"Microservice management",secrets:"Encrypted secrets management",login:"Authorize this machine with your Nebutra account (device flow)",logout:"Clear local session state",whoami:"Show the authorized Nebutra identity",upgrade:"Upgrade local CLI tooling",link:"Link local project metadata",unlink:"Unlink local project metadata",status:"Show capability readiness (live/local-fallback/missing-key)",sync:"Sync .env.example/.env.local with declared capabilities"},No=["--help","--version","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--json","--no-browser","--poll"],Po=Ve.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${an[e]}"`).join(`
|
|
4
|
+
`);function sn(){return`#!/usr/bin/env bash
|
|
5
5
|
|
|
6
6
|
_nebutra_completions() {
|
|
7
7
|
local cur prev opts cmd
|
|
@@ -10,10 +10,10 @@ _nebutra_completions() {
|
|
|
10
10
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
11
11
|
|
|
12
12
|
# Subcommands
|
|
13
|
-
local subcommands="${
|
|
13
|
+
local subcommands="${Ve.join(" ")}"
|
|
14
14
|
|
|
15
15
|
# Flags
|
|
16
|
-
local flags="${
|
|
16
|
+
local flags="${No.join(" ")}"
|
|
17
17
|
|
|
18
18
|
if [[ \${cur} == -* ]]; then
|
|
19
19
|
# Complete flags
|
|
@@ -30,11 +30,11 @@ _nebutra_completions() {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
complete -o bashdefault -o default -o nospace -F _nebutra_completions nebutra
|
|
33
|
-
`}function
|
|
33
|
+
`}function cn(){return`#compdef nebutra
|
|
34
34
|
|
|
35
35
|
_nebutra() {
|
|
36
36
|
local -a commands=(
|
|
37
|
-
${
|
|
37
|
+
${Ve.map(e=>`"${e}:${an[e]}"`).join(`
|
|
38
38
|
`)}
|
|
39
39
|
)
|
|
40
40
|
|
|
@@ -47,6 +47,11 @@ _nebutra() {
|
|
|
47
47
|
"--json[Emit machine-readable JSON]"
|
|
48
48
|
)
|
|
49
49
|
|
|
50
|
+
local -a sync_flags=(
|
|
51
|
+
"--dry-run[Preview planned additions without writing files]"
|
|
52
|
+
"--json[Emit machine-readable JSON]"
|
|
53
|
+
)
|
|
54
|
+
|
|
50
55
|
local -a mcp_flags=(
|
|
51
56
|
"--stdio[Use stdio transport (default)]"
|
|
52
57
|
)
|
|
@@ -74,6 +79,9 @@ _nebutra() {
|
|
|
74
79
|
status)
|
|
75
80
|
_arguments "*:options:($global_flags $status_flags)"
|
|
76
81
|
;;
|
|
82
|
+
sync)
|
|
83
|
+
_arguments "*:options:($global_flags $sync_flags)"
|
|
84
|
+
;;
|
|
77
85
|
*)
|
|
78
86
|
_arguments "*:options:($global_flags)"
|
|
79
87
|
;;
|
|
@@ -82,12 +90,12 @@ _nebutra() {
|
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
_nebutra
|
|
85
|
-
`}function
|
|
93
|
+
`}function ln(){return`# Fish shell completions for nebutra
|
|
86
94
|
|
|
87
|
-
complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${
|
|
95
|
+
complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${Ve.join(" ")}" -d "Nebutra governance CLI"
|
|
88
96
|
|
|
89
97
|
# Subcommands
|
|
90
|
-
${
|
|
98
|
+
${Po}
|
|
91
99
|
|
|
92
100
|
# Flags
|
|
93
101
|
complete -c nebutra -f -a "--help" -d "Show help message"
|
|
@@ -96,6 +104,10 @@ complete -c nebutra -f -a "--version" -d "Show version"
|
|
|
96
104
|
# status command flags
|
|
97
105
|
complete -c nebutra -n "__fish_seen_subcommand_from status" -f -a "--json" -d "Emit machine-readable JSON"
|
|
98
106
|
|
|
107
|
+
# sync command flags
|
|
108
|
+
complete -c nebutra -n "__fish_seen_subcommand_from sync" -f -a "--dry-run" -d "Preview planned additions without writing files"
|
|
109
|
+
complete -c nebutra -n "__fish_seen_subcommand_from sync" -f -a "--json" -d "Emit machine-readable JSON"
|
|
110
|
+
|
|
99
111
|
# mcp command flags
|
|
100
112
|
complete -c nebutra -n "__fish_seen_subcommand_from mcp" -f -a "--stdio" -d "Use stdio transport (default)"
|
|
101
113
|
|
|
@@ -109,24 +121,24 @@ complete -c nebutra -n "__fish_seen_subcommand_from completions" -f -a "install"
|
|
|
109
121
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--all" -d "Show full schema for all commands"
|
|
110
122
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--list" -d "List all available command names"
|
|
111
123
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--exit-codes" -d "Show exit codes reference"
|
|
112
|
-
`}function
|
|
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 jo(){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=Se(Ne(),".bashrc"),o=Se(Ne(),".bash_completion.d"),i="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=Se(Ne(),".zshrc"),o=Se(Ne(),".zsh/completions"),i="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=Se(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=Se(o,t==="fish"?"nebutra.fish":"nebutra"),d=t==="bash"?sn():t==="zsh"?cn():ln();Io(s,d),n.stop(D.green(`Completion script installed to ${s}`))}r&&i&&t!=="fish"&&(!Ao(r)||!_o(r,"utf8").includes("nebutra"))&&(Oo(r,(t==="bash"?`
|
|
113
125
|
# nebutra completions
|
|
114
126
|
[[ -f ~/.bash_completion.d/nebutra ]] && source ~/.bash_completion.d/nebutra`:`
|
|
115
127
|
# nebutra completions
|
|
116
128
|
fpath=(~/.zsh/completions $fpath)
|
|
117
129
|
autoload -Uz compinit && compinit`)+`
|
|
118
|
-
`),
|
|
119
|
-
`)}function
|
|
120
|
-
`)}function
|
|
121
|
-
`)}function u(e,t="info"){let n;switch(t){case"error":n=
|
|
122
|
-
`)}function
|
|
123
|
-
`),t&&Object.keys(t).length>0&&
|
|
124
|
-
`)}function
|
|
125
|
-
`),
|
|
126
|
-
`),
|
|
127
|
-
`),
|
|
128
|
-
`)}async function
|
|
129
|
-
`)}catch{process.stdout.write(t.stdout)}}else u("Failed to check migration status","error"),process.exit(t.exitCode||1)}function
|
|
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 jo():un(t)})}import*as ze from"@clack/prompts";import{stderr as oe,stdout as mn}from"process";import Z from"picocolors";function $o(){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:$o()?"plain":"json"}function To(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 Do(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=To(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"?oe:mn,o;switch(n){case"json":o=Do(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}`;oe.write(r+`
|
|
134
|
+
`)}function S(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=Z.dim(`[debug] ${e}`);oe.write(r+`
|
|
135
|
+
`),t&&Object.keys(t).length>0&&oe.write(Z.dim(JSON.stringify(t,null,2))+`
|
|
136
|
+
`)}function Ke(e){oe.write(`
|
|
137
|
+
`),oe.write(Z.bold(Z.cyan(e))+`
|
|
138
|
+
`),oe.write(Z.gray("-".repeat(e.length))+`
|
|
139
|
+
`),oe.write(`
|
|
140
|
+
`)}async function Lo(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 Fo(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 Uo(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 Bo(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 Mo(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 Go(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 Lo(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 Fo(a);break;case"seed":await Uo(a);break;case"studio":await Bo(a);break;case"reset":await Mo(a);break;case"status":await Go(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"),S("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
130
142
|
Examples:
|
|
131
143
|
nebutra db generate Generate Prisma client
|
|
132
144
|
nebutra db migrate Run all pending migrations
|
|
@@ -141,15 +153,15 @@ Flags:
|
|
|
141
153
|
--dry-run Show what would be run without executing
|
|
142
154
|
--yes Skip confirmations
|
|
143
155
|
--format <type> Output format: json, plain (default: plain)
|
|
144
|
-
`)}import*as
|
|
145
|
-
${n}`)}return t}async function
|
|
156
|
+
`)}import*as x 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 ie(e){if(e==="json"||e==="plain"||e==="table")return e}var xe=["landing","web","storybook","design-docs","idp","mail-preview","gateway","admin","auth","design","forge","router","pebble","typelens","sailor-docs","studio","sleptons"];function Ye(e){let t=`@nebutra/${e}`;if(!xe.includes(e)){let n=h.yellow(`Valid apps: ${xe.join(", ")}`);throw new Error(`Invalid app: ${h.red(e)}
|
|
157
|
+
${n}`)}return t}async function Vo(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:ie(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app){Ye(e.app);let n=`@nebutra/${e.app}`;e.quiet||x.log.info(h.cyan(`Starting dev server for ${h.bold(n)}...`));let r=await ne("dev",{filter:n});process.exit(r.exitCode)}e.quiet||x.log.info(h.cyan("Starting dev servers for all apps..."));let t=await ne("dev");process.exit(t.exitCode)}catch(t){t instanceof Error?x.log.error(h.red(t.message)):x.log.error(h.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Ko(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:ie(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.strict&&(x.log.error(h.red("Cannot use --strict with --app filter")),process.exit(c.INVALID_ARGS)),e.app){Ye(e.app);let r=`@nebutra/${e.app}`;e.quiet||x.log.info(h.cyan(`Building ${h.bold(r)}...`));let o=await ne("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...";x.log.info(h.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?x.log.error(h.red(t.message)):x.log.error(h.red("Unknown error occurred")),process.exit(c.ERROR)}}async function zo(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:ie(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.fix&&(x.log.error(h.red("Cannot use --fix with --app filter (lint:fix is global only)")),process.exit(c.INVALID_ARGS)),e.app){Ye(e.app);let r=`@nebutra/${e.app}`;e.quiet||x.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...";x.log.info(h.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?x.log.error(h.red(t.message)):x.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:"typecheck",options:{app:e.app},task:"turbo typecheck"},{format:ie(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app){Ye(e.app);let n=`@nebutra/${e.app}`;e.quiet||x.log.info(h.cyan(`Type-checking ${h.bold(n)}...`));let r=await ne("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||x.log.info(h.cyan("Type-checking all packages..."));let t=await ne("typecheck");process.exit(t.exitCode)}catch(t){t instanceof Error?x.log.error(h.red(t.message)):x.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: ${xe.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=A(t,n);await Vo({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ie(r.format)})}),e.command("build").description("Build all apps (pnpm build or turbo build)").option("--app <name>",`App to build: ${xe.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 Ko({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,strict:!!t.strict,quiet:!!r.quiet,verbose:!!r.verbose,format:ie(r.format)})}),e.command("lint").description("Lint with Biome (pnpm lint or pnpm lint:fix)").option("--app <name>",`App to lint: ${xe.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 zo({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,fix:!!t.fix,quiet:!!r.quiet,verbose:!!r.verbose,format:ie(r.format)})}),e.command("typecheck").description("Type-check with TypeScript (turbo typecheck)").option("--app <name>",`App to typecheck: ${xe.join(", ")}`).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,quiet:!!r.quiet,verbose:!!r.verbose,format:ie(r.format)})})};import hn from"fs";import bn from"path";import vt from"picocolors";var wt=["smoke","golden","sleptons"],Wo={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 Jo(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}=Wo[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}.
|
|
146
158
|
Expected config: ${r}
|
|
147
159
|
Remediation: scaffold the suite (analogous to 'nebutra workflow init <provider>')
|
|
148
|
-
or restore the directory from git.`),process.exit(c.NOT_FOUND)),t.dryRun&&(
|
|
149
|
-
`)){if(o.trim().startsWith("#")||!o.trim())continue;let
|
|
150
|
-
`)){if(
|
|
151
|
-
`);e.dryRun?(u("Dry-run: would write .env.local","info"),
|
|
152
|
-
`),u(`Environment template written to ${r}`,"success"))}async function
|
|
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 Jo(t,{dryRun:!!n.dryRun,quiet:!!o.quiet})})};import{existsSync as We,readFileSync as wn,writeFileSync as qo}from"fs";import{resolve as Je}from"path";import*as me from"@clack/prompts";import Ho from"picocolors";function qe(e){let t=Je(e,".env.example");if(!We(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=We(t)?t:n;if(!We(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 Zo(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function Xo(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 Qo(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 ei(e){let t=C(),n=qe(t),r=Je(t,".env.local");if(We(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"})):(qo(r,s+`
|
|
164
|
+
`),u(`Environment template written to ${r}`,"success"))}async function ti(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 ni(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]=Zo(i,a)?Xo(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:Ho.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 Qo(i);break;case"template":await ei(i);break;case"diff":await ti(i);break;case"show":await ni(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"),S("Full error",{error:a}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
153
165
|
Examples:
|
|
154
166
|
nebutra env validate Check all required vars are set
|
|
155
167
|
nebutra env template Generate .env.local from .env.example with prompts
|
|
@@ -166,7 +178,7 @@ Flags:
|
|
|
166
178
|
Sensitive Variables:
|
|
167
179
|
Variables with KEY, TOKEN, SECRET, PASSWORD in their names are masked in output.
|
|
168
180
|
This prevents accidental exposure of credentials.
|
|
169
|
-
`)}import{promises as
|
|
181
|
+
`)}import{promises as Sn}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 ri(e){return Pe.includes(e)}function St(e,t){if(!t)throw new Error(`--category is required. Valid categories: ${Pe.join(", ")}. Example: nebutra generate package ${e} --category iam`);if(!ri(t))throw new Error(`Unknown category "${t}". Valid categories: ${Pe.join(", ")}.`);return`packages/${t}/${e}`}function xn(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
|
|
170
182
|
"name": "@nebutra/${e}",
|
|
171
183
|
"version": "0.0.0",
|
|
172
184
|
"private": true,
|
|
@@ -251,7 +263,7 @@ export default function RootLayout({
|
|
|
251
263
|
|
|
252
264
|
@theme {
|
|
253
265
|
--color-*: var(--neutral-*);
|
|
254
|
-
}`}}function
|
|
266
|
+
}`}}function En(e){return{"package.json":`{
|
|
255
267
|
"name": "@nebutra/${e}",
|
|
256
268
|
"version": "0.0.0",
|
|
257
269
|
"type": "module",
|
|
@@ -288,7 +300,7 @@ export default function RootLayout({
|
|
|
288
300
|
|
|
289
301
|
export function hello(name: string): string {
|
|
290
302
|
return \`Hello, \${name}!\`;
|
|
291
|
-
}`}}function
|
|
303
|
+
}`}}function Rn(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
|
|
292
304
|
import { z } from "zod";
|
|
293
305
|
|
|
294
306
|
type Env = {
|
|
@@ -339,7 +351,7 @@ app.post("/", async (c) => {
|
|
|
339
351
|
);
|
|
340
352
|
});
|
|
341
353
|
|
|
342
|
-
export default app;`}}function
|
|
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";
|
|
343
355
|
import { cn } from "@nebutra/ui/utils";
|
|
344
356
|
|
|
345
357
|
const ${t}Variants = cva(
|
|
@@ -413,13 +425,13 @@ export const AllSizes: Story = {
|
|
|
413
425
|
<${n} size="lg">Large</\${pascalCase}>
|
|
414
426
|
</div>
|
|
415
427
|
),
|
|
416
|
-
};`}}async function
|
|
417
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
418
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
419
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
420
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
421
|
-
`),r.push({app:
|
|
422
|
-
Average coverage: ${i
|
|
428
|
+
};`}}async function He(e,t,n){let r=C(),o=[],i={};switch(e){case"app":i=xn(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"?St(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=xn(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"?St(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 Sn.mkdir(p,{recursive:!0}),await Sn.writeFile(m,d,"utf-8"),o.push(m)}return o}async function oi(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 ii(e,t){let n;try{n=St(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 ai(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 si(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 oi(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 ii(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 ai(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 si(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 xt,{lstatSync as ci,readdirSync as Et,readFileSync as li,writeFileSync as ui}from"fs";import X from"path";import{fileURLToPath as di}from"url";import U from"picocolors";var mi=X.dirname(di(import.meta.url));function Rt(){let e=new Map,t=X.join(mi,"../../../apps");if(!xt.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");xt.existsSync(i)&&ci(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=li(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 pi(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 fi(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 gi(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(xt.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}`):(ui(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 yi(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 pi({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 fi({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 gi(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 yi({format:n.format||r.format,interactive:r.yes!==!0})})}import*as Xe from"@clack/prompts";async function hi(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"),S("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function bi(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"),S("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}async function vi(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"),S("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}async function wi(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"),S("Docker compose output",{stderr:i.stderr}),process.exit(i.exitCode||1))}async function Ci(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"),S("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 hi(a);break;case"down":await bi(a);break;case"status":await vi(a);break;case"logs":await wi(r,a);break;case"reset":await Ci(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"),S("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
423
435
|
Examples:
|
|
424
436
|
nebutra infra up Start full stack
|
|
425
437
|
nebutra infra up --lite Start lite stack (PostgreSQL + Redis)
|
|
@@ -436,14 +448,19 @@ Flags:
|
|
|
436
448
|
--lite Use docker-compose.lite.yml (PostgreSQL + Redis only)
|
|
437
449
|
--profile <name> Enable Docker Compose profile (search, notifications, etc.)
|
|
438
450
|
--format <type> Output format: json, plain (default: plain, auto-json in non-TTY)
|
|
439
|
-
`)}import
|
|
440
|
-
`),o?(l.success("Configuration saved to nebutra.config.json"),l.info('Initialization complete! Run "nebutra status" to check capability readiness.')):(await new Promise(
|
|
441
|
-
`)}async function
|
|
442
|
-
|
|
451
|
+
`)}import kt from"fs";import Si from"path";import*as M from"@clack/prompts";import Qe from"picocolors";var xi=["auth","billing","email","storage","queue","cache","notifications","webhooks","ai","mcp"],Ei={stack:"sailor-2026-09",capabilities:[...xi]};function Ri(){return process.stdout.isTTY===!0}function ki(e){return e.yes===!0||e.dryRun===!0||!Ri()}function Oi(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function In(e={}){let t=process.cwd(),n=Si.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=ki(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={...Ei};if(e.dryRun){let a=r?JSON.parse(kt.readFileSync(n,"utf-8")):void 0,s=Oi(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 Ni from"os";import At from"path";import*as E from"@clack/prompts";import G from"picocolors";var Ai="https://analytics.nebutra.com";function _i(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function Ii(){return process.env.npm_package_version??"0.0.0-dev"}function et(e,t={}){_i(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??Ai},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",{action:e.action,cli_version:Ii(),...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=Ni.homedir(),t=At.join(e,".config","nebutra");try{await Ot.mkdir(t,{recursive:!0})}catch{}return t}async function Pi(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 ji(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 $i(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 Pi(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:ji(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 Ti(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 $i(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await Ti(n)})}import{existsSync as $n,readFileSync as Di,writeFileSync as Li}from"fs";import{dirname as Fi,join as Tn,parse as Ui}from"path";import*as tt from"@clack/prompts";function Bi(e){let t=e,{root:n}=Ui(t);for(;;){if($n(Tn(t,"package.json")))return t;if(t===n)return null;let r=Fi(t);if(r===t)return null;t=r}}function Mi(e){if(!$n(e))return{};try{let t=JSON.parse(Di(e,"utf-8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function Gi(e,t){Li(e,JSON.stringify(t,null,2)+`
|
|
453
|
+
`)}async function Vi(e,t){let n=t.format==="json",r=Bi(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={...Mi(i),projectId:o};Gi(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 Vi(t,{yes:o.yes||!1,format:n.format||o.format})})}import{spawn as na}from"child_process";import{platform as ra}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 zi}from"child_process";import{chmodSync as Yi,existsSync as ke,readFileSync as Fn,rmSync as Wi,unlinkSync as _t,writeFileSync as Un}from"fs";import{mkdir as Ji}from"fs/promises";import{platform as fe}from"os";import{join as Bn}from"path";import{promisify as qi}from"util";import{homedir as Ln,platform as Ki}from"os";import{join as nt}from"path";function Ee(){if(Ki()==="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=qi(zi),ye="nebutra-cli",Oe="default";function Re(){return Bn(Ee(),"credentials.json")}function rt(){return Bn(Ee(),"device-pending.json")}async function Mn(){await Ji(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 Hi(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 Zi(){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 Hi(t)){try{ke(Re())&&_t(Re())}catch{}return{storedIn:"keychain"}}Un(Re(),`${t}
|
|
454
|
+
`,{mode:384});try{Yi(Re(),384)}catch{}return{storedIn:"file"}}async function Xi(){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 Zi()&&e.push(`keychain:${ye}`);let t=Re();if(ke(t))try{_t(t),e.push(t)}catch{}let n=rt();if(ke(n))try{Wi(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 Yn(){let e=process.env.NEBUTRA_TOKEN?.trim();if(e)return{token:e,source:"env",expired:!1};let t=await Xi();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 Qi={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=Qi.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 Wn="nebutra-cli";function at(){let e=process.env.NEBUTRA_AUTH_URL?.trim();return e?e.replace(/\/+$/,""):it("auth")}var ae=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=fetch){let n=await t(`${e}/api/auth/device/code`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:Wn}),signal:AbortSignal.timeout(1e4)}),r=await jt(n);if(!n.ok)throw new ae(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 ea(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:Wn}),signal:AbortSignal.timeout(1e4)}),o=await jt(r);if(!r.ok)throw new ae(typeof o.error=="string"?o.error:"request_failed",typeof o.error_description=="string"?o.error_description:`HTTP ${r.status}`);return o}var ta=e=>new Promise(t=>setTimeout(t,e));async function qn(e,t,n){let r=n.fetchImpl??fetch,o=n.sleep??ta,i=n.intervalSeconds;for(;;){if(Date.now()>=n.deadline)throw new ae("expired_token","The device code expired before it was approved.");n.onWaiting?.(i),await o(i*1e3);try{return await ea(e,t,r)}catch(a){if(!(a instanceof ae))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 n(`${e}/api/auth/get-session`,{method:"GET",headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(1e4)});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 oa(e,t){return!!e.json||e.format==="json"||t==="json"}function ia(e){try{let t=ra(),[n,r]=t==="darwin"?["open",[e]]:t==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]],o=na(n,r,{stdio:"ignore",detached:!0});o.on("error",()=>{}),o.unref()}catch{}}async function aa(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 Hn(e,t,n){let r=0,o=await qn(e,t.deviceCode,{intervalSeconds:t.interval,deadline:t.expiresAt,onWaiting:()=>{n||(r++,process.stderr.write(r===1?"Waiting for approval":"."))}});n||process.stderr.write(`
|
|
456
|
+
`),await aa(e,o);let i=await st(e,o.access_token);return i?{userId:i.userId,email:i.email}:null}async function sa(e,t){let n=oa(e,t.format),r=at();if(e.poll){let s=zn();if(s&&s.expiresAt>Date.now()&&s.baseUrl===r)try{let d=await Hn(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 Jn(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&&ia(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 Hn(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 ae?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 Zn(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 sa(t,{format:r.format,yes:r.yes})})}import{existsSync as Xn,rmSync as ca,unlinkSync as la}from"fs";import{join as ua}from"path";var da=["auth.json","session.json","token","credentials.json"];async function ma(e){let t=Ee(),n=e.format==="json",r=0,o=[],i=await Kn();if(r+=i.length,o.push(...i),e.all){if(Xn(t))try{ca(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 da){let s=ua(t,a);if(Xn(s))try{la(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 Qn(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 ma({all:t.all||!1,format:t.format||r.format})})}import{spawn as pa}from"child_process";import{dirname as fa,resolve as ga}from"path";import{fileURLToPath as ya}from"url";import*as J from"@clack/prompts";import te from"picocolors";var ha=fa(ya(import.meta.url));function ba(){let e=[()=>ga(ha,"../../../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 er(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(te.bgCyan(te.black(" nebutra mcp ")));try{let n=ba();J.log.info(te.cyan("Starting Nebutra MCP server for Cursor/Windsurf integration...")),J.log.info(te.dim(`Press Ctrl+C to stop the server.
|
|
459
|
+
`));let r=pa(process.execPath,[n],{stdio:"inherit",env:{...process.env}});r.on("close",o=>{o===0?J.outro(te.green("MCP server stopped gracefully.")):o===null&&J.outro(te.yellow("MCP server terminated.")),process.exit(o??0)}),r.on("error",o=>{l.error(`
|
|
443
460
|
Failed to start MCP server: ${o.message}`),o.code==="ENOENT"&&(l.warn(`
|
|
444
|
-
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",()=>{
|
|
445
|
-
Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{
|
|
446
|
-
`)}function
|
|
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(te.yellow(`
|
|
462
|
+
Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{J.log.info(te.yellow("Terminating MCP server...")),r.kill("SIGTERM")})}catch(n){J.log.error(te.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 nr=Object.fromEntries(Object.entries(Zt).map(([e,t])=>[e,t]));function rr(e){return typeof e=="boolean"?"boolean":"string"}function or(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:rr(n.default)})),examples:e.examples||[]}}function va(e){let n=(H.subcommands||[]).find(r=>r.name===e);return n?or(n):null}function wa(){return(H.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:rr(e.default)}))}function Ca(e){let t=H.subcommands||[];return{name:H.name,version:e,description:H.description,usage:H.usage||"nebutra [command] [options]",globalOptions:wa(),commands:t.map(or),exitCodes:nr,timestamp:new Date().toISOString()}}function tr(){return(H.subcommands||[]).map(t=>t.name)}function ct(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
463
|
+
`)}function Sa(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function xa(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(ct(Ca(r)),process.exit(0)),t.list===!0&&(ct(tr()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(ct(nr),process.exit(0)),e){let o=va(e);o||(n||(l.error(`Unknown command '${e}'`),l.info(`Available commands: ${tr().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(Sa(o))throw o;n||l.error(o instanceof Error?o.message:String(o)),process.exit(c.ERROR)}}function ir(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 xa(t,n)})}import{stdin as De}from"process";import*as lt from"@clack/prompts";import R from"picocolors";async function Ea(){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 Ra(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 ka(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 Ea()}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 Oa(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 Aa(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 _a(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 Ia(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 ar(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 Ra(a);break;case"set":r.length===0&&(u("set requires a secret key: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS)),await ka(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 Oa(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 Aa(r[0],a);break;case"audit":await _a(a);break;case"verify":await Ia(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"),S("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
447
464
|
Examples:
|
|
448
465
|
nebutra secrets list List all secrets (metadata only)
|
|
449
466
|
nebutra secrets list --tenant org_456 List secrets for specific tenant
|
|
@@ -478,7 +495,7 @@ Security Notes:
|
|
|
478
495
|
- Never use --value in production (visible in shell history)
|
|
479
496
|
- Always use --unmask when viewing secrets in scripts
|
|
480
497
|
- Audit log tracks all access and modifications
|
|
481
|
-
`)}import*as
|
|
498
|
+
`)}import*as ut from"@clack/prompts";import P from"picocolors";function sr(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function Na(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 Pa(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"),S("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:sr(o.State),exitCode:o.ExitCode}));b(r,{format:"json"})}else{u("Service Status","info");let r=n.map(o=>({Service:Na(sr(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"),S("Parse error",{error:String(n)}),process.exit(c.ERROR)}}async function ja(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 $a(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"),S("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}async function Ta(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 Da(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"),S("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}function cr(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 Pa(a);break;case"logs":r.length===0&&(u("logs requires a service name: nebutra services logs <service>","error"),process.exit(c.INVALID_ARGS)),await ja(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 $a(r[0],a);break;case"health":await Ta(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 Da(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"),S("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
482
499
|
Examples:
|
|
483
500
|
nebutra services status Show all service status
|
|
484
501
|
nebutra services logs postgres Stream postgres logs
|
|
@@ -499,24 +516,34 @@ Flags:
|
|
|
499
516
|
--tail <n> Log lines to show (default: 100)
|
|
500
517
|
--since <duration> Show logs since (e.g., 10m, 1h)
|
|
501
518
|
--timeout <seconds> Timeout for restart
|
|
502
|
-
`)}import{existsSync as
|
|
503
|
-
`)}function
|
|
504
|
-
`)}function
|
|
505
|
-
`))}function
|
|
506
|
-
${n}`)}return t}async function za(e){e.dryRun&&(T({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:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&(e.watch||e.coverage)&&(N.log.error(x.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(c.INVALID_ARGS)),e.app){Ka(e.app);let r=`@nebutra/${e.app}`;e.quiet||N.log.info(x.cyan(`Running tests for ${x.bold(r)}...`));let o=await Q("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...";N.log.info(x.cyan(r))}let n=await P(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?N.log.error(x.red(t.message)):N.log.error(x.red("Unknown error occurred")),process.exit(c.ERROR)}}async function On(e){e.dryRun&&(T({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:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{e.ui&&e.ci&&(N.log.error(x.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...";N.log.info(x.cyan(r))}let n=await P(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?N.log.error(x.red(t.message)):N.log.error(x.red("Unknown error occurred")),process.exit(c.ERROR)}}async function An(e){e.dryRun&&(T({mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"},{format:ae(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...";N.log.info(x.cyan(r))}let n=await P(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?N.log.error(x.red(t.message)):N.log.error(x.red("Unknown error occurred")),process.exit(c.ERROR)}}async function In(e){e.dryRun&&(T({mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"},{format:ae(e.format)}),process.exit(c.DRY_RUN_OK));try{e.quiet||N.log.info(x.cyan("Running architecture tests..."));let t=await P("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?N.log.error(x.red(t.message)):N.log.error(x.red("Unknown error occurred")),process.exit(c.ERROR)}}var _n=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: ${gt.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r,o)=>{let a=O(r,o),i={dryRun:!!r.dryRun,quiet:!!a.quiet,verbose:!!a.verbose,format:ae(a.format)};n==="e2e"?await On({...i,ui:!!r.ui,ci:!!r.ci}):n==="size"?await An({...i,why:!!r.why}):n==="arch"?await In(i):await za({...i,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=O(n,r);await On({ui:!!n.ui,ci:!!n.ci,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ae(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=O(n,r);await An({why:!!n.why,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ae(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=O(n,r);await In({dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ae(o.format)})})};var Ya={$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}}]},ie=Ya,Wa=ie.languages.map(e=>e.id),yt=ie.defaultLanguage;function bt(e){return ie.languages.find(t=>t.id===e)}function Nn(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??qa()}function qa(){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 Ha(e="table"){let t=ie.languages;return e==="json"?JSON.stringify({version:ie.version,defaultLanguage:ie.defaultLanguage,count:t.length,languages:t},null,2):[`Nebutra design languages (${t.length}) \u2014 global product chrome swap`,`Default: ${yt} (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(`
|
|
507
|
-
`)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
519
|
+
`)}import{join as Wa}from"path";import be from"picocolors";import{existsSync as lr,readFileSync as ur}from"fs";import{dirname as Ka,join as dr,parse as za}from"path";import{stderr as La}from"process";import se from"picocolors";function Fa(){return process.stderr.isTTY===!0&&!process.env.CI&&!process.env.NEBUTRA_NON_TTY}function Ua(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 Ba(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=Fa()?Ua(e):Ba(e);La.write(t+`
|
|
521
|
+
`)}function Ma(e){Tt(e),process.exit(e.exitCode)}function Dt(e,t){Ma(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 Ga(e){return e instanceof K}function Va(e){return Ga(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=Va(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:"stripe",envKeys:["STRIPE_SECRET_KEY"]},{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 STRIPE_SECRET_KEY (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}=za(t);for(;;){if(lr(dr(t,"nebutra.config.json")))return t;if(t===n)return null;let r=Ka(t);if(r===t)return null;t=r}}function mt(e){let t=ur(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 Ya(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 mr(e){let t={...process.env};for(let n of[".env",".env.local"]){let r=dr(e,n);if(lr(r))try{let o=Ya(ur(r,"utf-8"));for(let[i,a]of Object.entries(o))process.env[i]===void 0&&(t[i]=a)}catch{}}return t}function pr(e,t,n){let r=[],o=[];for(let i of t.providers){let a=i.envKeys.filter(s=>!n[s]);a.length===0?r.push(i.id):o.length===0&&i.envKeys.length>0&&(o=a)}return r.length>0?{name:e,state:"live",provider:r,missing:[],next:t.next}:t.degrade.kind==="fallback"?{name:e,state:"local-fallback",provider:[t.degrade.provider],missing:o,next:t.next}:{name:e,state:"missing-key",provider:[],missing:o,next:t.next}}function fr(e){let t=Object.keys(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 Ja(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 qa(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=Wa(t,"nebutra.config.json"),r=mt(n),o=Array.isArray(r.capabilities)?r.capabilities:[],i=mr(t),a=i.NEBUTRA_LOCALE||"global",s=typeof r.stack=="string"?r.stack:"unknown",d=o.map(f=>{let v=Ae[f];return v?pr(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=Ja(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 gr(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 qa({json:t.json,format:r.format})}))}import{existsSync as yr,readFileSync as Ha,writeFileSync as hr}from"fs";import{join as Ft}from"path";import Fe from"picocolors";var br=".env.example",vr=".env.local",Za=["# Local secrets for this machine \u2014 never commit real values.","# `nebutra sync` created this file; add your own keys below.",""].join(`
|
|
523
|
+
`);function Xa(e){let t=new Set;for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.startsWith("export ")?r.slice(7):r,i=o.indexOf("=");if(i===-1)continue;let a=o.slice(0,i).trim();a&&t.add(a)}return t}function Qa(e,t){let n=Xa(e),r=[],o=[],i=[];for(let m of t){let p=Ae[m];if(p)for(let g of p.providers){if(g.envKeys.length===0)continue;let y=[];for(let f of g.envKeys)n.has(f)?o.push(f):y.push(f);if(y.length!==0){i.push([`# ${m} (${g.id})`,...y.map(f=>`${f}=`)].join(`
|
|
524
|
+
`));for(let f of y)n.add(f),r.push(f)}}}if(i.length===0)return{content:e,added:r,unchanged:o};let a=e.replace(/\s+$/,"");return{content:`${a.length>0?`${a}
|
|
525
|
+
|
|
526
|
+
`:""}${i.join(`
|
|
527
|
+
|
|
528
|
+
`)}
|
|
529
|
+
`,added:r,unchanged:o}}async function es(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}=fr(o),s=Ft(t,br),d=yr(s),m=d?Ha(s,"utf-8"):"",p=Qa(m,i),g=Ft(t,vr),y=yr(g),f={};p.added.length>0&&(f[br]=p.added),y||(f[vr]=[]);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)&&hr(s,p.content),y||hr(g,Za),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 wr(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 es({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 ts(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 ns(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test",options:{app:e.app,watch:e.watch,coverage:e.coverage},task:e.coverage?"pnpm test:coverage":e.watch?"pnpm test:watch":"pnpm test"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&(e.watch||e.coverage)&&(j.log.error(k.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(c.INVALID_ARGS)),e.app){ts(e.app);let r=`@nebutra/${e.app}`;e.quiet||j.log.info(k.cyan(`Running tests for ${k.bold(r)}...`));let o=await ne("test",{filter:r});process.exit(o.exitCode)}let t="test";if(e.coverage?t="test:coverage":e.watch&&(t="test:watch"),!e.quiet){let r=t==="test:coverage"?"Running tests with coverage...":t==="test:watch"?"Running tests in watch mode...":"Running tests...";j.log.info(k.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Cr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test e2e",options:{ui:e.ui,ci:e.ci},task:e.ci?"pnpm e2e:ci":e.ui?"pnpm e2e:ui":"pnpm e2e"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{e.ui&&e.ci&&(j.log.error(k.red("Cannot use --ui and --ci together")),process.exit(c.INVALID_ARGS));let t="e2e";if(e.ci?t="e2e:ci":e.ui&&(t="e2e:ui"),!e.quiet){let r=t==="e2e:ci"?"Running E2E tests (CI mode)...":t==="e2e:ui"?"Opening E2E tests in UI mode...":"Running E2E tests...";j.log.info(k.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Sr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{let t=e.why?"size:why":"size";if(!e.quiet){let r=e.why?"Analyzing bundle size (showing largest assets)...":"Checking bundle size...";j.log.info(k.cyan(r))}let n=await $(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}async function xr(e){e.dryRun&&(I({mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"},{format:ce(e.format)}),process.exit(c.DRY_RUN_OK));try{e.quiet||j.log.info(k.cyan("Running architecture tests..."));let t=await $("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?j.log.error(k.red(t.message)):j.log.error(k.red("Unknown error occurred")),process.exit(c.ERROR)}}var Er=e=>{let t=e.command("test [subcommand]").description("Run tests (Vitest, Playwright, bundle size, architecture)").option("--watch","Run tests in watch mode (unit tests only)").option("--coverage","Generate coverage report (unit tests only)").option("--app <name>",`Run tests for specific app: ${Ut.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r,o)=>{let i=A(r,o),a={dryRun:!!r.dryRun,quiet:!!i.quiet,verbose:!!i.verbose,format:ce(i.format)};n==="e2e"?await Cr({...a,ui:!!r.ui,ci:!!r.ci}):n==="size"?await Sr({...a,why:!!r.why}):n==="arch"?await xr(a):await ns({...a,watch:!!r.watch,coverage:!!r.coverage,app:typeof r.app=="string"?r.app:void 0})});t.command("e2e").description("Run end-to-end tests (Playwright)").option("--ui","Open interactive UI mode").option("--ci","Run in CI mode with strict options").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await Cr({ui:!!n.ui,ci:!!n.ci,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})}),t.command("size").description("Check bundle size (analyze largest assets)").option("--why","Show breakdown of largest bundle assets").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await Sr({why:!!n.why,dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})}),t.command("arch").description("Run architecture tests (verify design layer isolation)").option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=A(n,r);await xr({dryRun:!!n.dryRun,quiet:!!o.quiet,verbose:!!o.verbose,format:ce(o.format)})})};var rs={$schema:"https://nebutra.com/schemas/design-language-registry.json",version:"2026.07",defaultLanguage:"factory",description:"Design-language catalog for global product chrome swap (Create Center / SaaS theme). Not color moods \u2014 full Brand Packages (roles + recipe + elev + zones).",languages:[{id:"factory",name:"Nebutra Factory",kind:"design-language",description:"Default product chrome from @nebutra/tokens (no skin). Clear data-brand to restore.",tagline:"the token source, unskinned",shortName:"Factory",proves:["factory HSL SSOT","recipe defaults","action\u2261brand-mark until skin"],darkDefault:!0,brandPath:null,skinPath:null,install:{command:"nebutra theme use factory",cssImport:null},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"cosmos",name:"Cosmos",kind:"design-language",description:"Linen gallery canvas with a monochrome chrome: the filled Ink button and the brand mark are the same colour, there is no accent role at all. One 16px radius everywhere, zero elevation, serif display at weight 350.",tagline:"images sit; chrome recedes",shortName:"Cosmos",proves:["monochrome chrome (action \u2261 brand-mark, no accent role)","single-radius system (16px everywhere; 9999px only for the floating nav)","elevation=none by contract (flat surfaces, contrast-only depth)","serif display below weight 400 (headingWeight 350)","light-first dual mode (dark inverts the gallery)"],darkDefault:!1,brandPath:"brands/cosmos/brand.json",skinPath:"skins/cosmos.css",install:{command:"nebutra theme use cosmos",cssImport:"@nebutra/tokens/skins/cosmos.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"gsap",name:"GSAP",kind:"design-language",description:"Dark cream-on-void; shockingly-green is accent \u2014 CTA is gradient-stroke/outline, not solid green fill.",tagline:"saturated, fast easing",shortName:"GSAP",proves:["outline / gradient-stroke recipe","category extensions","marketing display zone"],darkDefault:!0,brandPath:"brands/gsap/brand.json",skinPath:"skins/gsap.css",install:{command:"nebutra theme use gsap",cssImport:"@nebutra/tokens/skins/gsap.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"linear",name:"Linear",kind:"design-language",description:"Dual-mode: dark void default + light paper; solid acid-lime CTA, compact density.",tagline:"tight radii, low-contrast chrome",shortName:"Linear",proves:["chromatic solid action","dark product chrome","dual-mode light/dark palettes"],darkDefault:!0,brandPath:"brands/linear/brand.json",skinPath:"skins/linear.css",install:{command:"nebutra theme use linear",cssImport:"@nebutra/tokens/skins/linear.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"notion",name:"Notion",kind:"design-language",description:"Warm paper notebook; Notion Blue sole filled CTA \u2260 Ink brand-mark; 8px buttons / 12px cards; elev=none + hairline; accent hues decorative only.",tagline:"paper surfaces, muted ink",shortName:"Notion",proves:["action \u2260 brand-mark (blue vs ink)","canvas\u2260card (paper-warmth vs pure-white)","elevation=none content cards + raised nav shadow slot","table radius priority (8/12 over tertiary 4px)","decorative accents never product CTA"],darkDefault:!1,brandPath:"brands/notion/brand.json",skinPath:"skins/notion.css",install:{command:"nebutra theme use notion",cssImport:"@nebutra/tokens/skins/notion.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"raycast",name:"Raycast",kind:"design-language",description:"Neutral Mist/Iron filled CTA; Coral is brand-mark only. Key elevation stack.",tagline:"dark glass and a coloured halo",shortName:"Raycast",proves:["action \u2260 brand-mark","elevation=key free CSS"],darkDefault:!0,brandPath:"brands/raycast/brand.json",skinPath:"skins/raycast.css",install:{command:"nebutra theme use raycast",cssImport:"@nebutra/tokens/skins/raycast.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"stripe",name:"Stripe",kind:"design-language",description:"Indigo-ink ledger on frost glass; Indigo action \u2260 Midnight brand-mark; 4px controls; elevation=none (tint + frost rules).",tagline:"soft elevation, generous type",shortName:"Stripe",proves:["action \u2260 brand-mark (chromatic indigo vs midnight)","elevation=none tint-ladder depth","4px squared controls (not pill)","whisper heading weight 300"],darkDefault:!1,brandPath:"brands/stripe/brand.json",skinPath:"skins/stripe.css",install:{command:"nebutra theme use stripe",cssImport:"@nebutra/tokens/skins/stripe.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"vanta",name:"Vanta",kind:"design-language",description:"Editorial violet on parchment; Vivid Violet action \u2260 Indigo Ink brand-mark; full pills; elevation=none (carbon hairlines).",tagline:"high-trust enterprise blues",shortName:"Vanta",proves:["action \u2260 brand-mark (chromatic)","elevation=none border-only","999px pill controls","serif display + sans UI zones"],darkDefault:!1,brandPath:"brands/vanta/brand.json",skinPath:"skins/vanta.css",install:{command:"nebutra theme use vanta",cssImport:"@nebutra/tokens/skins/vanta.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}},{id:"vercel",name:"Vercel",kind:"design-language",description:"Monochrome dual-mode: light paper + Obsidian CTA; dark carbon + white CTA; hairline elevation (no chromatic CTA).",tagline:"monochrome, hard edges, lit top edge",shortName:"Vercel",proves:["light monochrome action","elevation=hairline","dual-mode light/dark palettes"],darkDefault:!1,brandPath:"brands/vercel/brand.json",skinPath:"skins/vercel.css",install:{command:"nebutra theme use vercel",cssImport:"@nebutra/tokens/skins/vercel.css"},compatibility:{tailwind:"4",cssVariables:!0,brandPackage:!0,dataBrand:!0}}]},le=rs,os=le.languages.map(e=>e.id),Bt=le.defaultLanguage;function Mt(e){return le.languages.find(t=>t.id===e)}function Rr(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??is()}function is(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function as(e="table"){let t=le.languages;return e==="json"?JSON.stringify({version:le.version,defaultLanguage:le.defaultLanguage,count:t.length,languages:t},null,2):[`Nebutra design languages (${t.length}) \u2014 global product chrome swap`,`Default: ${Bt} (factory tokens; no skin)`,"Contract: roles.action \u2192 CTA; roles.brand \u2192 brand-mark; free elev/radii/zones","",...t.map(r=>`${r.id.padEnd(10)} ${r.darkDefault?"dark ":"light"} ${(r.proves[0]??"").slice(0,48)} ${r.description.slice(0,56)}`)].join(`
|
|
532
|
+
`)}function ss(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 kr(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(as(Rr(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=ss(n,Rr(r));o||(l.error(`Design language '${n}' not found. Run: nebutra theme list`),process.exit(c.NOT_FOUND)),console.log(o)})}import{existsSync as _r,readFileSync as Ir}from"fs";import{resolve as Or,join as Gt}from"path";function Nr(e={}){let t=e.manifestPath?Or(e.manifestPath):Gt(Or(e.root??process.cwd()),"apps","design-docs","public","agent-manifest.json");return{manifestPath:t,componentDir:Gt(t,"..","agent","components")}}function cs(e){return e.trim().toLowerCase()}function ls(e){let t=cs(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 Pr(e={}){let{manifestPath:t}=Nr(e);if(!_r(t))throw new Error(`Missing Nebutra UI agent manifest at ${t}. Run pnpm --filter @nebutra/design-docs build:registry.`);return JSON.parse(Ir(t,"utf8"))}function Vt(e,t={}){let n=ls(e),{componentDir:r}=Nr(t),o=Gt(r,`${n}.json`);if(!_r(o))throw new Error(`UI component contract not found: ${n}`);return JSON.parse(Ir(o,"utf8"))}function jr(e,t="",n={}){let r=t.trim().toLowerCase(),o=Ar(n.limit??20,1,100),i=Ar(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?us(p).includes(r):!0).map(p=>({component:p,score:ds(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 us(e){return[e.name,e.title,e.description,e.status,e.maturity,e.layer,e.source,...e.tags].join(" ").toLowerCase()}function ds(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 Ar(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??ms()}function ms(){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 Yt(e){let t=e.opts?e.opts():e;return{root:C(),manifestPath:t.manifest}}function $r(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function ps(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 fs(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 gs(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(`
|
|
511
536
|
`)}return[`${e.name}: ${e.valid?"valid":"invalid"}`,...e.errors.map(n=>`error: ${n}`),...e.warnings.map(n=>`warning: ${n}`)].join(`
|
|
512
|
-
`)}return JSON.stringify(e,null,2)}function
|
|
513
|
-
`):JSON.stringify(n,null,2)}function
|
|
514
|
-
`),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):l.success("Unlinked from project")}function zn(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 pi({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as Ii}from"child_process";import{existsSync as fi,readFileSync as Wn}from"fs";import{dirname as Yn,join as gi}from"path";import{fileURLToPath as yi}from"url";function bi(e=import.meta.url){let t=Yn(yi(e));for(let n=0;n<6;n+=1){let r=gi(t,"package.json");if(fi(r))try{if(JSON.parse(Wn(r,"utf8")).name==="nebutra")return r}catch{}let o=Yn(t);if(o===t)break;t=o}throw new Error("Unable to locate the nebutra CLI package.json")}function Je(e=import.meta.url){return JSON.parse(Wn(bi(e),"utf8")).version}import{promises as Ze}from"fs";import{homedir as hi}from"os";import{join as Hn}from"path";import vi from"p-timeout";import se from"picocolors";var Ci=1440*60*1e3,Jn=Hn(hi(),".nebutra"),Et=Hn(Jn,"update-check.json"),wi="https://registry.npmjs.org/nebutra",Si=5e3;async function Ei(){try{await Ze.mkdir(Jn,{recursive:!0})}catch{}}async function Ri(){try{let e=await Ze.readFile(Et,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<Ci?t:(await Ze.unlink(Et).catch(r=>{l.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function xi(e){try{await Ei();let t={timestamp:Date.now(),latestVersion:e};await Ze.writeFile(Et,JSON.stringify(t,null,2),"utf-8")}catch{}}async function ki(){try{let e=new AbortController,t=await vi(fetch(wi,{signal:e.signal,headers:{Accept:"application/json"}}),{milliseconds:Si,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 qn(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function Oi(e,t){let n=qn(e),r=qn(t);for(let o=0;o<3;o++){let a=n[o]??0,i=r[o]??0;if(i>a)return!0;if(i<a)return!1}return!1}async function Rt(e){let t=await Ri(),n=null;return t?n=t.latestVersion:(n=await ki(),n&&await xi(n)),!n||!Oi(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function Ai(e){let n=`Update available: ${e.currentVersion} \u2192 ${e.latestVersion}`,r="Run `npm i -g nebutra` to update",o=" ".repeat((43-n.length)/2),a=" ".repeat((43-r.length)/2),i=[se.cyan("\u256D"+"\u2500".repeat(41)+"\u256E"),se.cyan("\u2502")+se.yellow(o+n+o)+se.cyan("\u2502"),se.cyan("\u2502")+se.gray(a+r+a)+se.cyan("\u2502"),se.cyan("\u2570"+"\u2500".repeat(41)+"\u256F")]}async function Zn(e){let t=null;return Rt(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&Ai(t))}}var me=Je();function _i(){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 Ni(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 Pi(e){let t=_i(),n=Ni(t),r=e.format==="json",o=await Rt(me),a=o?.latestVersion??null,i=!!o?.isUpdate;e.dryRun&&(r?console.log(JSON.stringify({command:"upgrade",dryRun:!0,installer:t,command_to_run:n,currentVersion:me,latestVersion:a,hasUpdate:i},null,2)):(l.info(`Detected installer: ${t}`),l.info(`Current: ${me}${a?` \u2192 Latest: ${a}`:""}`),l.info(`Upgrade command: ${n}`)),process.exit(c.DRY_RUN_OK)),!i&&a&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,alreadyLatest:!0,version:me},null,2)):l.success(`Already on the latest version (${me})`),process.exit(c.SUCCESS)),e.yes||(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,command_to_run:n,currentVersion:me,latestVersion:a,requiresConfirmation:!0},null,2)):(l.info(`Current: ${me}${a?` \u2192 Latest: ${a}`:""}`),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=Ii(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 Xn(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return Pi({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)}import{existsSync as ji,mkdirSync as Ti,writeFileSync as Di}from"fs";import{homedir as tr,platform as Li}from"os";import{join as Ie}from"path";var Qn={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"}};var $i={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 er(e){let t=$i.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 xt from"picocolors";function Fi(){if(Li()==="win32"){let t=process.env.LOCALAPPDATA||Ie(tr(),"AppData","Local");return Ie(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Ie(e,"nebutra"):Ie(tr(),".config","nebutra")}function Ui(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function nr(e,t){try{Ti(e,{recursive:!0}),Di(t,"")}catch{}}function rr(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=Fi(),t=Ie(e,"first-run-acked");try{if(ji(t))return}catch{return}if(Ui()){nr(e,t);return}let r=[`${xt.cyan("\u2139")} ${Qn.name} collects anonymous usage analytics to improve the CLI.`,` Opt out at any time: ${xt.dim("export NEBUTRA_TELEMETRY=0")}`,` Privacy policy: ${xt.dim(`${er("landing")}/legal/cli-analytics`)}`,""];try{process.stderr.write(r.join(`
|
|
515
|
-
`))}catch{}
|
|
537
|
+
`)}return JSON.stringify(e,null,2)}function ys(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,Yt(t))}catch{Dt(`UI component contract not found: ${e}`,"Run `nebutra ui search <query> --format json` to discover available component ids.")}}function Tr(e){try{return Pr(Yt(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 hs(e,t){let n=e.components.map(o=>Kt(Vt(o.name,Yt(t)))),r=n.filter(o=>!o.valid).length;return{valid:r===0,total:n.length,invalid:r,results:n}}function Dr(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=Tr(r),i=jr(o,n??"",{limit:$r(r.limit,20),offset:$r(r.offset,0),tag:r.tag,status:r.status,maturity:r.maturity});console.log(ps(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(fs(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)):hs(Tr(r),r);console.log(gs(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(ys(o,pt(r)))})}import{existsSync as Lr,readFileSync as bs,unlinkSync as vs,writeFileSync as ws}from"fs";import{dirname as Cs,join as Fr,parse as Ss}from"path";function xs(e){let t=e,{root:n}=Ss(t);for(;;){if(Lr(Fr(t,"package.json")))return t;if(t===n)return null;let r=Cs(t);if(r===t)return null;t=r}}async function Es(e){let t=e.format==="json",n=xs(process.cwd())??process.cwd(),r=Fr(n,"nebutra.config.json");if(Lr(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{vs(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(bs(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;ws(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 Ur(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 Es({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as Bs}from"child_process";import{existsSync as Rs,readFileSync as Mr}from"fs";import{dirname as Br,join as ks}from"path";import{fileURLToPath as Os}from"url";function As(e=import.meta.url){let t=Br(Os(e));for(let n=0;n<6;n+=1){let r=ks(t,"package.json");if(Rs(r))try{if(JSON.parse(Mr(r,"utf8")).name==="nebutra")return r}catch{}let o=Br(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(Mr(As(e),"utf8")).version}import{promises as gt}from"fs";import{homedir as _s}from"os";import{join as Vr}from"path";import Is from"p-timeout";import ue from"picocolors";var Ns=1440*60*1e3,Kr=Vr(_s(),".nebutra"),Wt=Vr(Kr,"update-check.json"),Ps="https://registry.npmjs.org/nebutra",js=5e3;async function $s(){try{await gt.mkdir(Kr,{recursive:!0})}catch{}}async function Ts(){try{let e=await gt.readFile(Wt,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<Ns?t:(await gt.unlink(Wt).catch(r=>{l.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function Ds(e){try{await $s();let t={timestamp:Date.now(),latestVersion:e};await gt.writeFile(Wt,JSON.stringify(t,null,2),"utf-8")}catch{}}async function Ls(){try{let e=new AbortController,t=await Is(fetch(Ps,{signal:e.signal,headers:{Accept:"application/json"}}),{milliseconds:js,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 Gr(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function Fs(e,t){let n=Gr(e),r=Gr(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 Ts(),n=null;return t?n=t.latestVersion:(n=await Ls(),n&&await Ds(n)),!n||!Fs(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function Us(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 zr(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&&Us(t))}}var ve=ft();function Ms(){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 Gs(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 Vs(e){let t=Ms(),n=Gs(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=Bs(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 Yr(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return Vs({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 Ks(e,t){let n=!!e.json||e.format==="json"||t==="json",r=await Yn();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 Wr(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 Ks(t,r.format)})}import{existsSync as zs,mkdirSync as Ys,writeFileSync as Ws}from"fs";import{homedir as Jr,platform as Js}from"os";import{join as Ue}from"path";import Ht from"picocolors";function qs(){if(Js()==="win32"){let t=process.env.LOCALAPPDATA||Ue(Jr(),"AppData","Local");return Ue(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Ue(e,"nebutra"):Ue(Jr(),".config","nebutra")}function Hs(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function qr(e,t){try{Ys(e,{recursive:!0}),Ws(t,"")}catch{}}function Hr(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=qs(),t=Ue(e,"first-run-acked");try{if(zs(t))return}catch{return}if(Hs()){qr(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{}qr(e,t)}var eo=ft();function Xs(e){let t=new Zs,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})})),er(t),ir(t),on(t),An(t),_n(t),Cn(t),jn(t),nn(t),gn(t),On(t),yn(t),Er(t),vn(t),kr(t),Dr(t),cr(t),ar(t),dn(t),Zn(t),Qn(t),Wr(t),Yr(t),Dn(t),Ur(t),gr(t),wr(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",`
|
|
516
541
|
Examples:
|
|
517
542
|
$ nebutra init Initialize a new project
|
|
518
543
|
$ nebutra status Show capability readiness (live/local-fallback/missing-key)
|
|
519
544
|
$ nebutra status --json Machine-readable capability status
|
|
545
|
+
$ nebutra sync Sync .env.example/.env.local with declared capabilities
|
|
546
|
+
$ nebutra sync --dry-run Preview env-file additions without writing
|
|
520
547
|
$ nebutra dev --app=web Start dev for the web app
|
|
521
548
|
$ nebutra db migrate Run pending database migrations
|
|
522
549
|
$ nebutra generate app blog Scaffold a new app
|
|
@@ -545,4 +572,4 @@ Environment:
|
|
|
545
572
|
NEBUTRA_OUTPUT_FORMAT Output format (json|table|plain)
|
|
546
573
|
NO_COLOR Disable colored output
|
|
547
574
|
CI Auto-enable non-interactive mode
|
|
548
|
-
`),t}async function
|
|
575
|
+
`),t}async function Qs(){Hr();let e=await zr(eo),t=Xs({version:eo,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 ec(){if(!process.argv[1])return!1;try{return Zr(Qr(import.meta.url))===Zr(Xr(process.argv[1]))}catch{return Qr(import.meta.url)===Xr(process.argv[1])}}var tc=ec();tc&&Qs().catch(e=>{process.exitCode=Lt(e)});export{Xs as buildProgram};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nebutra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"nebutra": {
|
|
5
5
|
"status": "foundation",
|
|
6
6
|
"graph": "core",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"tsup": "^8.5.1",
|
|
45
45
|
"typescript": "^5.9.3",
|
|
46
46
|
"vitest": "^4.1.4",
|
|
47
|
-
"@nebutra/
|
|
47
|
+
"@nebutra/brand": "2.0.0",
|
|
48
48
|
"@nebutra/preset": "0.1.3",
|
|
49
|
-
"@nebutra/
|
|
50
|
-
"@nebutra/
|
|
49
|
+
"@nebutra/theme": "2.0.0",
|
|
50
|
+
"@nebutra/ui": "2.0.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"dev": "tsup --watch",
|