nebutra 0.4.2 → 0.5.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 +20 -21
- package/bin/nebutra.js +28 -0
- package/dist/delegate-GIJ3G5CK.js +1 -0
- package/dist/index.js +74 -467
- package/dist/logger-QMYN56HK.js +1 -0
- package/package.json +13 -6
- package/dist/aws-kms-GSHDWA4I.js +0 -1
- package/dist/bowser-2VXD6AQS.js +0 -11
- package/dist/chunk-5ECPN42W.js +0 -1
- package/dist/chunk-6MSNEPUX.js +0 -0
- package/dist/chunk-A3H5SUSR.js +0 -8
- package/dist/chunk-AN6QWW3N.js +0 -1
- package/dist/chunk-CVCZBECH.js +0 -1
- package/dist/chunk-GA44DNS2.js +0 -1
- package/dist/chunk-ICFXBVJ4.js +0 -17
- package/dist/chunk-IYWUY3VA.js +0 -1
- package/dist/chunk-LDZWCNWB.js +0 -0
- package/dist/chunk-M3NEWJ7L.js +0 -1
- package/dist/chunk-MGGNSWUA.js +0 -3
- package/dist/chunk-MYIHTCRS.js +0 -4
- package/dist/chunk-PA4CKDRJ.js +0 -1
- package/dist/chunk-QSLKOXQ6.js +0 -1
- package/dist/chunk-S4HCBMFP.js +0 -1
- package/dist/chunk-SYWJHPRX.js +0 -0
- package/dist/chunk-TW5BOTVX.js +0 -0
- package/dist/chunk-UWHWNXNX.js +0 -19
- package/dist/chunk-WJLTO7JW.js +0 -0
- package/dist/chunk-X6LE6K3W.js +0 -0
- package/dist/chunk-XE3I3HCZ.js +0 -40
- package/dist/chunk-Z4YWESTY.js +0 -2
- package/dist/chunk-ZIBRKYXP.js +0 -23
- package/dist/credits-33DQE7XK.js +0 -2802
- package/dist/delegate-7HQKV277.js +0 -1
- package/dist/dist-GMNPO44T.js +0 -1
- package/dist/dist-WSEDRKMF.js +0 -5
- package/dist/dist-es-5AMXVNUC.js +0 -1
- package/dist/dist-es-5XQLJX7S.js +0 -2
- package/dist/dist-es-H47VUS6Q.js +0 -2
- package/dist/dist-es-HTJP4AFM.js +0 -1
- package/dist/dist-es-PAB65TG2.js +0 -5
- package/dist/dist-es-QD75XXED.js +0 -1
- package/dist/dist-es-QREIURMO.js +0 -2
- package/dist/dist-es-TCZQ4KMP.js +0 -2
- package/dist/dist-es-TDPJBG34.js +0 -1
- package/dist/dist-es-VD25UO4M.js +0 -1
- package/dist/dist-es-VZPXKLZQ.js +0 -1
- package/dist/dist-es-WOF2PBAL.js +0 -5
- package/dist/event-streams-TNY7XPBF.js +0 -1
- package/dist/loadSso-7ASJ2L6X.js +0 -1
- package/dist/loadSso-CDEOXPSD.js +0 -1
- package/dist/local-6WWVOMA7.js +0 -1
- package/dist/logger-WOLJCPZK.js +0 -1
- package/dist/query_compiler_fast_bg.postgresql-JA2BFVW5.js +0 -2
- package/dist/query_compiler_fast_bg.postgresql.wasm-base64-URHQ2Y3Y.js +0 -1
- package/dist/signin-VC4RXV33.js +0 -1
- package/dist/sso-oidc-T7YTOO4A.js +0 -1
- package/dist/sts-GE4BCXER.js +0 -1
- package/dist/sts-HDZNXPJY.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,237 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
name: "{{feature}}",
|
|
6
|
-
provider: "{{provider}}",
|
|
7
|
-
} as const;
|
|
8
|
-
|
|
9
|
-
export function assertFeatureEnv(env: NodeJS.ProcessEnv = process.env) {
|
|
10
|
-
const missing = featureEnvKeys.filter((key) => !env[key]);
|
|
11
|
-
if (missing.length > 0) {
|
|
12
|
-
throw new Error(\`Missing {{feature}} environment variables: \${missing.join(", ")}\`);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getFeatureProvider() {
|
|
17
|
-
return {
|
|
18
|
-
...platformFeature,
|
|
19
|
-
envKeys: featureEnvKeys,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
`,Vo=`# {{feature}} Feature
|
|
23
|
-
|
|
24
|
-
Installed by \`nebutra add {{feature}}\`.
|
|
25
|
-
|
|
26
|
-
- Provider: \`{{provider}}\`
|
|
27
|
-
- Provider details: {{providerDescription}}
|
|
28
|
-
- Required env keys: {{envKeysCsv}}
|
|
29
|
-
|
|
30
|
-
Next steps:
|
|
31
|
-
1. Set the required environment variables in \`{{envFile}}\`.
|
|
32
|
-
2. Wire this starter into the generated package or app surface.
|
|
33
|
-
3. Replace the placeholder helper with your production adapter.
|
|
34
|
-
`,Ko="integrations";function Fe(e,t=Ko){let n=`packages/${t}/${e}`;return[{path:`${n}/src/index.ts`,content:Go},{path:`${n}/README.md`,content:Vo}]}var qo={queue:{name:"queue",description:"Background job queue starter for Nebutra-style monorepos.",envFile:".env.local",providers:[{id:"upstash",description:"HTTP queue transport powered by Upstash QStash.",dependencies:[{name:"@upstash/qstash",version:"latest"}],env:[{key:"QSTASH_TOKEN",description:"Upstash QStash REST token"},{key:"QSTASH_CURRENT_SIGNING_KEY",description:"Upstash current signing key for webhook verification"},{key:"QSTASH_NEXT_SIGNING_KEY",description:"Upstash next signing key for webhook rotation"}]},{id:"bullmq",description:"Redis-backed worker queue powered by BullMQ.",dependencies:[{name:"bullmq",version:"latest"},{name:"ioredis",version:"latest"}],env:[{key:"REDIS_URL",description:"Redis connection string for BullMQ workers"}]}],files:[{path:"packages/integrations/queue/src/index.ts",content:`const queueEnvKeys = {{envKeysArray}} as const;
|
|
35
|
-
|
|
36
|
-
export const queueFeature = {
|
|
37
|
-
name: "queue",
|
|
38
|
-
provider: "{{provider}}",
|
|
39
|
-
} as const;
|
|
40
|
-
|
|
41
|
-
export function assertQueueEnv(env: NodeJS.ProcessEnv = process.env) {
|
|
42
|
-
const missing = queueEnvKeys.filter((key) => !env[key]);
|
|
43
|
-
if (missing.length > 0) {
|
|
44
|
-
throw new Error(\`Missing queue environment variables: \${missing.join(", ")}\`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function getQueueProvider() {
|
|
49
|
-
return {
|
|
50
|
-
...queueFeature,
|
|
51
|
-
envKeys: queueEnvKeys,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
`},{path:"packages/integrations/queue/README.md",content:`# Queue Feature
|
|
55
|
-
|
|
56
|
-
Installed by \`nebutra add queue\`.
|
|
57
|
-
|
|
58
|
-
- Provider: \`{{provider}}\`
|
|
59
|
-
- Provider details: {{providerDescription}}
|
|
60
|
-
- Required env keys: {{envKeysCsv}}
|
|
61
|
-
|
|
62
|
-
Next steps:
|
|
63
|
-
1. Set the required environment variables in \`{{envFile}}\`.
|
|
64
|
-
2. Wire this starter into your app or worker runtime.
|
|
65
|
-
3. Replace the placeholder provider helpers with production job handlers.
|
|
66
|
-
`}]},search:{name:"search",description:"Search service starter for Nebutra-style monorepos.",envFile:".env.local",providers:[{id:"meilisearch",description:"Meilisearch client starter for full-text indexing.",dependencies:[{name:"meilisearch",version:"latest"}],env:[{key:"MEILISEARCH_HOST",description:"Meilisearch base URL"},{key:"MEILISEARCH_ADMIN_KEY",description:"Meilisearch admin API key"}]},{id:"typesense",description:"Typesense client starter for typed search queries.",dependencies:[{name:"typesense",version:"latest"}],env:[{key:"TYPESENSE_HOST",description:"Typesense host URL"},{key:"TYPESENSE_API_KEY",description:"Typesense admin API key"},{key:"TYPESENSE_COLLECTION",description:"Default Typesense collection name"}]}],files:[{path:"packages/integrations/search/src/index.ts",content:`const searchEnvKeys = {{envKeysArray}} as const;
|
|
67
|
-
|
|
68
|
-
export const searchFeature = {
|
|
69
|
-
name: "search",
|
|
70
|
-
provider: "{{provider}}",
|
|
71
|
-
} as const;
|
|
72
|
-
|
|
73
|
-
export function assertSearchEnv(env: NodeJS.ProcessEnv = process.env) {
|
|
74
|
-
const missing = searchEnvKeys.filter((key) => !env[key]);
|
|
75
|
-
if (missing.length > 0) {
|
|
76
|
-
throw new Error(\`Missing search environment variables: \${missing.join(", ")}\`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function getSearchProvider() {
|
|
81
|
-
return {
|
|
82
|
-
...searchFeature,
|
|
83
|
-
envKeys: searchEnvKeys,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
`},{path:"packages/integrations/search/README.md",content:`# Search Feature
|
|
87
|
-
|
|
88
|
-
Installed by \`nebutra add search\`.
|
|
89
|
-
|
|
90
|
-
- Provider: \`{{provider}}\`
|
|
91
|
-
- Provider details: {{providerDescription}}
|
|
92
|
-
- Required env keys: {{envKeysCsv}}
|
|
93
|
-
|
|
94
|
-
Next steps:
|
|
95
|
-
1. Add credentials to \`{{envFile}}\`.
|
|
96
|
-
2. Point your indexing jobs at the configured provider.
|
|
97
|
-
3. Replace the placeholder helpers with production query/index code.
|
|
98
|
-
`}]},cache:{name:"cache",description:"Cache adapter starter aligned with create-sailor cache providers.",envFile:".env.local",providers:[{id:"upstash-redis",description:"Serverless Redis cache powered by Upstash.",dependencies:[{name:"@upstash/redis",version:"latest"}],env:[{key:"UPSTASH_REDIS_REST_URL",description:"Upstash Redis REST URL"}]},{id:"vercel-kv",description:"Vercel KV compatible cache adapter.",dependencies:[{name:"@vercel/kv",version:"latest"}],env:[{key:"KV_REST_API_URL",description:"Vercel KV REST API URL"}]},{id:"redis",description:"Self-hosted Redis cache adapter.",dependencies:[{name:"ioredis",version:"latest"}],env:[{key:"REDIS_URL",description:"Redis connection URL"}]},{id:"dragonfly",description:"Dragonfly Redis-compatible cache adapter.",dependencies:[{name:"ioredis",version:"latest"}],env:[{key:"DRAGONFLY_URL",description:"Dragonfly connection URL"}]}],files:Fe("cache")},notifications:{name:"notifications",description:"Notification workflow starter for product and lifecycle messages.",envFile:".env.local",providers:[{id:"novu",description:"Novu notification workflow provider.",dependencies:[{name:"@novu/node",version:"latest"}],env:[{key:"NOVU_API_KEY",description:"Novu API key"}]},{id:"knock",description:"Knock notification workflow provider.",dependencies:[{name:"@knocklabs/node",version:"latest"}],env:[{key:"KNOCK_API_KEY",description:"Knock API key"}]},{id:"custom",description:"Custom notification adapter surface.",env:[{key:"NOTIFICATIONS_WEBHOOK_URL",description:"Custom notification webhook URL"}]}],files:Fe("notifications")},webhooks:{name:"webhooks",description:"Outbound webhook starter with provider-specific signing hooks.",envFile:".env.local",providers:[{id:"svix",description:"Svix-backed outbound webhook delivery.",dependencies:[{name:"svix",version:"latest"}],env:[{key:"SVIX_AUTH_TOKEN",description:"Svix authentication token"}]},{id:"custom",description:"Custom outbound webhook adapter.",env:[{key:"WEBHOOK_SIGNING_SECRET",description:"Webhook signing secret"}]}],files:Fe("webhooks")},cms:{name:"cms",description:"Headless CMS integration starter for marketing and docs content.",envFile:".env.local",providers:[{id:"sanity",description:"Sanity content lake client starter.",dependencies:[{name:"next-sanity",version:"latest"}],env:[{key:"NEXT_PUBLIC_SANITY_PROJECT_ID",description:"Sanity project ID"},{key:"NEXT_PUBLIC_SANITY_DATASET",description:"Sanity dataset"}]},{id:"contentful",description:"Contentful content API starter.",dependencies:[{name:"contentful",version:"latest"}],env:[{key:"CONTENTFUL_SPACE_ID",description:"Contentful space ID"},{key:"CONTENTFUL_ACCESS_TOKEN",description:"Contentful access token"}]},{id:"strapi",description:"Strapi REST client starter.",env:[{key:"STRAPI_URL",description:"Strapi base URL"},{key:"STRAPI_API_TOKEN",description:"Strapi API token"}]}],files:Fe("cms")},"feature-flags":{name:"feature-flags",description:"Feature flag starter for gradual rollout and runtime controls.",envFile:".env.local",providers:[{id:"vercel-flags",description:"Vercel Flags SDK starter.",dependencies:[{name:"@vercel/flags",version:"latest"}],env:[{key:"FLAGS_SECRET",description:"Feature flag signing secret"}]},{id:"growthbook",description:"GrowthBook feature flag client starter.",dependencies:[{name:"@growthbook/growthbook",version:"latest"}],env:[{key:"GROWTHBOOK_CLIENT_KEY",description:"GrowthBook client key"}]},{id:"configcat",description:"ConfigCat feature flag client starter.",dependencies:[{name:"configcat-node",version:"latest"}],env:[{key:"CONFIGCAT_SDK_KEY",description:"ConfigCat SDK key"}]}],files:Fe("feature-flags","platform")},captcha:{name:"captcha",description:"Captcha verification starter for abuse prevention.",envFile:".env.local",providers:[{id:"turnstile",description:"Cloudflare Turnstile verification surface.",env:[{key:"NEXT_PUBLIC_TURNSTILE_SITE_KEY",description:"Turnstile site key"},{key:"TURNSTILE_SECRET_KEY",description:"Turnstile secret key"}]},{id:"hcaptcha",description:"hCaptcha verification surface.",env:[{key:"NEXT_PUBLIC_HCAPTCHA_SITE_KEY",description:"hCaptcha site key"},{key:"HCAPTCHA_SECRET_KEY",description:"hCaptcha secret key"}]},{id:"aliyun-slide",description:"Aliyun slide captcha verification surface.",env:[{key:"ALIYUN_CAPTCHA_SCENE_ID",description:"Aliyun captcha scene ID"},{key:"ALIYUN_CAPTCHA_SECRET",description:"Aliyun captcha secret"}]}],files:Fe("captcha","iam")}},zo=["iam","commerce","integrations","ai","design","platform","ops"];function Yo(){let e;try{e=xn(Mo(import.meta.url))}catch{e=process.cwd()}for(;e&&e!==Bo(e).root;){try{let t=On(e);if(t.includes("pnpm-workspace.yaml")||t.includes("packages")){let n=Ft(e,"packages");if(Lo(n)&&Fo(n).isDirectory())return n}}catch{}e=xn(e)}return null}function Ho(e,t,n,r,o){let a=(t.env??[]).map(l=>({key:l,description:`${l} (declared by ${o})`})),i=ut(o)??"latest";return{name:e,description:t.summary??n.description??`${e} feature`,group:t.category??r,dependencies:[{name:o,version:i}],env:a,envFile:t.envFile??".env.local",files:[]}}var mt=null;function Wo(){if(mt)return mt;let e={},t=Yo();if(!t)return mt=e,e;for(let n of zo){let r=Ft(t,n),o;try{o=On(r)}catch{continue}for(let a of o){let i=Ft(r,a,"package.json"),l;try{l=Do(i,"utf-8")}catch{continue}let u;try{u=JSON.parse(l)}catch{continue}let m=u.nebutra,f=m?.featureId;!m||!f||!u.name||(e[f]=Ho(f,m,u,n,u.name))}}return mt=e,e}function An(){return{...Wo(),...qo}}function _n(){return Object.values(An())}async function Pn(e){return An()[e]??null}function Bt(e){return e instanceof Error&&e.message.startsWith("EXIT:")}function In(e){try{return Mt("npm",["list",e],{stdio:"pipe"}),!0}catch{return!1}}function Nn(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
99
|
-
`)}function Jo(e,t){let n=[];if(t["21st"]){let r=t["21st"],o=r.startsWith("http")?r:`https://21st.dev/r/${r}`;n.push({type:"run-command",source:"21st",component:r,resolvedUrl:o,command:`pnpm dlx shadcn@latest add "${o}"`})}return t.v0&&n.push({type:"run-command",source:"v0",component:"v0-component",resolvedUrl:t.v0,command:`pnpm dlx shadcn@latest add "${t.v0}"`}),e.length>0&&!t["21st"]&&!t.v0&&s.warn("Local feature installs are handled separately from external registry flows."),{mode:"dry-run",planType:"external-add",cwd:process.cwd(),timestamp:new Date().toISOString(),operations:n,summary:{execute:n.length}}}function $n(e,t){if(!t||t.length===0)return[];let n=new Map;for(let r of t)n.set(`${e}:${r.name}`,r);return Array.from(n.values())}function Tn(e){let t=new Map;for(let n of e)t.has(n.key)||t.set(n.key,n);return Array.from(t.values())}function Xo(e,t){let n=t.envEntries.map(r=>r.key);return e.replaceAll("{{feature}}",t.feature).replaceAll("{{provider}}",t.provider??"default").replaceAll("{{providerDescription}}",t.providerDescription??"No provider selected").replaceAll("{{envFile}}",t.envFile).replaceAll("{{envKeysCsv}}",n.join(", ")).replaceAll("{{envKeysArray}}",JSON.stringify(n))}async function pt(e){try{return await Pe.readFile(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}async function Qo(e,t){if(t)return X.join(e,t);let n=[".env.local",".env"];for(let r of n)try{return await Pe.access(X.join(e,r)),X.join(e,r)}catch{}return X.join(e,".env.local")}function Zo(e){let t=new Set;for(let n of e.matchAll(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=/gm))n[1]&&t.add(n[1]);return t}function es(e){return e?Object.fromEntries(Object.entries(e).sort(([t],[n])=>t.localeCompare(n))):{}}function Un(e,t){if(!(!e.providers||e.providers.length===0))return t?e.providers.find(n=>n.id===t):e.providers[0]}async function ts(e,t,n){let r=X.join(t,"package.json"),o=await pt(r);if(!o)throw new Error(`No package.json found in ${t}. Run this command from a project root.`);let a=JSON.parse(o),i=Tn(e.flatMap(p=>[...p.descriptor.env??[],...p.provider?.env??[]])),l=await Qo(t,e[0]?.descriptor.envFile),u=await pt(l)??"",m=Zo(u),f=i.filter(p=>!m.has(p.key)),y=i.filter(p=>m.has(p.key)),E=[];for(let p of e){let B=Tn([...p.descriptor.env??[],...p.provider?.env??[]]),Le={feature:p.name,provider:p.provider?.id,providerDescription:p.provider?.description,envFile:X.relative(t,l)||X.basename(l),envEntries:B};for(let Lt of p.descriptor.files??[]){let Dt=X.join(t,Lt.path),Uo=X.relative(t,Dt)||Lt.path,Rn=Xo(Lt.content,Le),Sn=await pt(Dt),lt,dt;Sn===null?(lt="create",dt="file missing"):Sn===Rn?(lt="skip",dt="already matches registry template"):(lt="conflict",dt="file exists with different content"),E.push({type:"write-file",feature:p.name,path:Dt,relativePath:Uo,status:lt,reason:dt,content:Rn})}}let D=$n("dependencies",e.flatMap(p=>[...p.descriptor.dependencies??[],...p.provider?.dependencies??[]])),F=$n("devDependencies",e.flatMap(p=>[...p.descriptor.devDependencies??[],...p.provider?.devDependencies??[]])),q=[];for(let p of D){let B=a.dependencies?.[p.name];q.push({section:"dependencies",name:p.name,action:B?B===p.version?"keep":"update":"add",from:B,to:p.version})}for(let p of F){let B=a.devDependencies?.[p.name];q.push({section:"devDependencies",name:p.name,action:B?B===p.version?"keep":"update":"add",from:B,to:p.version})}let ye={type:"merge-env",path:l,relativePath:X.relative(t,l)||X.basename(l),created:u.length===0,add:f,keep:y},ue={type:"update-package-json",path:r,relativePath:X.relative(t,r)||"package.json",changes:q},_e={create:E.filter(p=>p.status==="create").length,update:q.filter(p=>p.action==="add"||p.action==="update").length,append:f.length,skip:E.filter(p=>p.status==="skip").length+q.filter(p=>p.action==="keep").length+y.length,conflict:E.filter(p=>p.status==="conflict").length};return{mode:n,planType:"local-feature-install",cwd:t,timestamp:new Date().toISOString(),features:e.map(p=>({name:p.name,description:p.descriptor.description,provider:p.provider?.id,providerDescription:p.provider?.description})),operations:[...E,ye,ue],summary:_e}}function jn(e){return e.summary.create>0||e.summary.update>0||e.summary.append>0}function ns(e){return e.summary.conflict>0}async function rs(e){let t=e.operations.find(o=>o.type==="update-package-json"),n=e.operations.find(o=>o.type==="merge-env"),r=e.operations.filter(o=>o.type==="write-file");for(let o of r)o.status==="create"&&(await Pe.mkdir(X.dirname(o.path),{recursive:!0}),await Pe.writeFile(o.path,o.content,"utf8"));if(n&&n.add.length>0){let o=await pt(n.path)??"",a=n.add.map(u=>`# ${u.description}
|
|
100
|
-
${u.key}=`),i=o.trim().length>0?`
|
|
101
|
-
|
|
102
|
-
`:"",l=`${o.replace(/\s+$/,"")}${i}${a.join(`
|
|
103
|
-
|
|
104
|
-
`)}
|
|
105
|
-
`;await Pe.writeFile(n.path,l,"utf8")}if(t){let o=await Pe.readFile(t.path,"utf8"),a=JSON.parse(o);for(let i of t.changes){if(i.action==="keep")continue;let l=i.section==="dependencies"?"dependencies":"devDependencies";a[l]={...a[l]??{},[i.name]:i.to},a[l]=es(a[l])}await Pe.writeFile(t.path,`${JSON.stringify(a,null,2)}
|
|
106
|
-
`,"utf8")}}async function os(e,t,n){let r=[];for(let o of e){let a=await Pn(o);a||(s.error(`Feature '${o}' not found in the local registry.`),s.info("Use one of the supported local features or choose --21st / --v0 for external UI installs."),process.exit(c.INVALID_ARGS));let i=Un(a,t.provider);if(t.provider&&!i&&(s.error(`Provider '${t.provider}' is not supported for feature '${o}'.`),process.exit(c.INVALID_ARGS)),!i&&a.providers&&a.providers.length>0)if(n)i=a.providers[0];else{let l=await w.select({message:`Select a provider for ${o}`,options:a.providers.map(u=>({value:u.id,label:u.id,hint:u.description}))});w.isCancel(l)&&(w.log.info("Installation cancelled."),process.exit(c.CANCELLED)),i=Un(a,String(l))}r.push({name:o,descriptor:a,provider:i})}return r}function ss(e){w.log.info(qe.yellow("Planned local install:"));for(let t of e.features)w.log.message(` - ${t.name}${t.provider?` (${t.provider})`:""}: ${t.description}`);for(let t of e.operations)if(t.type==="write-file"&&w.log.message(` - ${t.status.toUpperCase()} ${t.relativePath}`),t.type==="merge-env"&&t.add.length>0&&w.log.message(` - APPEND ${t.add.map(n=>n.key).join(", ")} to ${t.relativePath}`),t.type==="update-package-json"){let n=t.changes.filter(r=>r.action==="add"||r.action==="update");n.length>0&&w.log.message(` - UPDATE ${t.relativePath}: ${n.map(r=>`${r.name}@${r.to}`).join(", ")}`)}}async function Ln(e,t){t.dryRun||w.intro(qe.bgCyan(qe.black(" nebutra add ")));let n=t.yes||!process.stdin.isTTY;if(e.length===0&&!t["21st"]&&!t.v0&&(t.dryRun?s.warn("No components specified."):(w.log.warn("No components specified."),w.outro("Operation aborted.")),process.exit(c.INVALID_ARGS)),t.dryRun&&(t["21st"]||t.v0)&&(Nn(Jo(e,t)),process.exit(c.DRY_RUN_OK)),t.ifNotExists&&(t["21st"]||t.v0)&&(t["21st"]&&In(t["21st"])||t.v0&&In("shadcn-component"))&&(s.info("Component already exists. Skipping installation."),process.exit(c.SUCCESS)),t["21st"]){let r=n||await w.confirm({message:`Install 21st.dev component: ${t["21st"]}?`,initialValue:!0});(w.isCancel(r)||!r)&&(w.log.info("Installation cancelled."),process.exit(c.CANCELLED)),w.log.info(qe.cyan(`Invoking shadcn integration for 21st.dev component: ${t["21st"]}...`));try{let o=t["21st"],a=o.startsWith("http")?o:`https://21st.dev/r/${o}`;Mt("pnpm",["dlx","shadcn@latest","add",a],{stdio:"inherit"}),s.success(`Successfully installed ${o}`),process.exit(c.SUCCESS)}catch(o){if(Bt(o))throw o;s.error(`Failed to install component: ${o instanceof Error?o.message:"Unknown error"}`),process.exit(c.ERROR)}}if(t.v0){let r=n||await w.confirm({message:`Install v0 component from: ${t.v0}?`,initialValue:!0});(w.isCancel(r)||!r)&&(w.log.info("Installation cancelled."),process.exit(c.CANCELLED)),w.log.info(qe.cyan(`Invoking shadcn integration for v0 URL: ${t.v0}...`));try{Mt("pnpm",["dlx","shadcn@latest","add",t.v0],{stdio:"inherit"}),s.success("Successfully installed v0 component"),process.exit(c.SUCCESS)}catch(o){if(Bt(o))throw o;s.error(`Failed to install component: ${o instanceof Error?o.message:"Unknown error"}`),process.exit(c.ERROR)}}try{let r=await os(e,t,n),o=await ts(r,process.cwd(),t.dryRun?"dry-run":"apply");if(t.dryRun&&(Nn(o),process.exit(c.DRY_RUN_OK)),ns(o)){let i=o.operations.filter(l=>l.type==="write-file"&&l.status==="conflict").map(l=>l.relativePath);t.ifNotExists&&!jn(o)&&(s.info("Feature already appears to be installed. Skipping because --if-not-exists was set."),process.exit(c.SUCCESS)),s.error(`Refusing to overwrite existing files: ${i.join(", ")}`),process.exit(c.CONFLICT)}jn(o)||(s.info("Feature install already satisfied. No files, env keys, or dependencies needed changes."),process.exit(c.SUCCESS)),ss(o);let a=n||await w.confirm({message:`Proceed with installing ${o.features.map(i=>i.name).join(", ")}?`,initialValue:!0});(w.isCancel(a)||!a)&&(w.log.info("Installation cancelled."),process.exit(c.CANCELLED)),await rs(o),s.success(`Installed ${o.features.map(i=>i.name).join(", ")} into ${o.cwd}`),process.exit(c.SUCCESS)}catch(r){if(Bt(r))throw r;s.error(r instanceof Error?r.message:String(r)),process.exit(c.CONFIG_ERROR)}}import T from"picocolors";import{stderr as Re,stdout as Dn}from"process";import me from"picocolors";function as(){return process.env.NEBUTRA_NON_TTY||process.env.CI||process.env.GITHUB_ACTIONS?!1:process.stderr.isTTY===!0}function Fn(e){if(e)return e;let t=process.env.NEBUTRA_OUTPUT_FORMAT;return t&&["json","table","plain"].includes(t)?t:as()?"plain":"json"}function is(e,t){if(e.length===0)return"";let n=t||Object.keys(e[0]),r={};for(let l of n){r[String(l)]=String(l).length;for(let u of e){let m=String(u[l]??"");r[String(l)]=Math.max(r[String(l)],m.length)}}let o=n.map(l=>String(l).padEnd(r[String(l)])).join(" | "),a=n.map(l=>"-".repeat(r[String(l)])).join("-+-"),i=[o,a];for(let l of e){let u=n.map(m=>String(l[m]??"").padEnd(r[String(m)])).join(" | ");i.push(u)}return i.join(`
|
|
107
|
-
`)}function cs(e){return JSON.stringify(e)}function Bn(e){if(!Array.isArray(e))return Gt(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return Gt(e);let t=is(e);return me.gray(t)}function Gt(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 S(e,t){let n=Fn(t?.format),r=t?.stream==="stderr"?Re:Dn,o;switch(n){case"json":o=cs(e);break;case"table":o=Bn(e);break;default:o=Gt(e);break}r.write(o+`
|
|
108
|
-
`)}function A(e,t={}){let n=Fn(t.format),r;switch(n){case"json":r=JSON.stringify(e);break;case"table":r=Bn(e);break;default:r=JSON.stringify(e,null,2);break}Dn.write(r+`
|
|
109
|
-
`)}function d(e,t="info"){let n;switch(t){case"error":n=me.red("\u2716");break;case"warn":n=me.yellow("\u26A0");break;case"success":n=me.green("\u2713");break;default:n=me.blue("\u2139");break}let r=`${n} ${e}`;Re.write(r+`
|
|
110
|
-
`)}function k(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=me.dim(`[debug] ${e}`);Re.write(r+`
|
|
111
|
-
`),t&&Object.keys(t).length>0&&Re.write(me.dim(JSON.stringify(t,null,2))+`
|
|
112
|
-
`)}function ft(e){Re.write(`
|
|
113
|
-
`),Re.write(me.bold(me.cyan(e))+`
|
|
114
|
-
`),Re.write(me.gray("-".repeat(e.length))+`
|
|
115
|
-
`),Re.write(`
|
|
116
|
-
`)}function U(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function Ye(e){return Array.isArray(e)?e:[]}function ze(e,t){return U(e)[t]}function Be(e,t,n=0){let r=ze(e,t);return typeof r=="number"?r:n}function R(e,t=""){return e==null?t:String(e)}async function Q(e,t={}){let n=process.env.NEBUTRA_API_URL||"http://localhost:3100",r=process.env.NEBUTRA_ADMIN_KEY;if(!r)return{ok:!1,status:401,error:"NEBUTRA_ADMIN_KEY environment variable not set. Set it to your admin API key."};let o=new URL(e,n).toString(),a=t.method||"GET",i=t.body?JSON.stringify(t.body):void 0;if(t.dryRun){let l={mode:"dry-run",timestamp:new Date().toISOString(),method:a,url:o,...i&&{body:JSON.parse(i)},headers:{"X-Admin-Key":"***","Content-Type":"application/json"}};return A(l),{ok:!0,status:0,data:l}}try{let l=await fetch(o,{method:a,headers:{"X-Admin-Key":r,"Content-Type":"application/json"},...i&&{body:i}}),u=await l.json().catch(()=>null);if(!l.ok){let m=ze(u,"error");return{ok:!1,status:l.status,error:typeof m=="string"?m:`HTTP ${l.status}`}}return{ok:!0,status:l.status,data:u}}catch(l){return{ok:!1,status:0,error:`Network error: ${l instanceof Error?l.message:String(l)}`}}}function Y(e,t,n){if(t==="json"){let r={command:n||"admin",...e};console.log(JSON.stringify(r,null,2))}else console.log(JSON.stringify(e,null,2))}function Z(e,t,n){Y(U(e),t,n)}async function ls(e){s.info("Fetching tenants...");let t=new URLSearchParams;e.limit&&t.append("limit",String(e.limit)),e.offset&&t.append("offset",String(e.offset)),e.status&&t.append("status",e.status);let n=`/api/v1/admin/tenants${t.toString()?`?${t.toString()}`:""}`,r=await Q(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch tenants: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(r.data,e.format,"admin:tenants");return}let o=U(r.data),a={tenants:Ye(o.tenants??o.data),total:Be(o,"total")||Be(o.meta,"total"),limit:o.limit??ze(o.meta,"limit"),offset:o.offset??ze(o.meta,"offset")};e.format==="json"?Y(a,e.format,"admin:tenants"):(s.info(`Found ${a.total} tenant(s)`),a.tenants.length>0&&(console.log(`
|
|
117
|
-
Tenants:`),a.tenants.forEach(i=>{let l=U(i);console.log(` ${T.blue(R(l.id))} \u2014 ${R(l.name,"(unnamed)")}`),console.log(` Status: ${R(l.status)}`),l.plan&&console.log(` Plan: ${R(l.plan)}`)})))}async function ds(e,t){s.info(`Fetching tenant ${e}...`);let n=await Q(`/api/v1/admin/tenants/${e}`,{dryRun:t.dryRun});if(n.ok||(s.error(`Failed to fetch tenant: ${n.error}`),process.exit(c.NETWORK_ERROR)),t.dryRun){Z(n.data,t.format,"admin:tenant");return}if(t.format==="json")Y({tenant:U(n.data)},t.format,"admin:tenant");else{let r=U(n.data);s.success(`Tenant ${T.blue(R(r.id))}`),console.log(` Name: ${R(r.name)}`),console.log(` Status: ${R(r.status)}`),console.log(` Plan: ${R(r.plan)}`),console.log(` Created: ${R(r.createdAt)}`),r.suspendedAt&&console.log(` Suspended: ${R(r.suspendedAt)}`)}}async function us(e,t){t.yes||(s.warn(`Suspending tenant ${e} will disable all operations`),s.info("Use --yes to confirm"),process.exit(c.CANCELLED)),s.info(`Suspending tenant ${e}...`);let n=await Q(`/api/v1/admin/tenants/${e}/suspend`,{method:"POST",dryRun:t.dryRun});if(n.ok||(s.error(`Failed to suspend tenant: ${n.error}`),process.exit(c.NETWORK_ERROR)),t.dryRun){Z(n.data,t.format,"admin:suspend");return}s.success(`Tenant ${T.blue(e)} suspended`),t.format==="json"&&Y({suspended:!0,tenantId:e},t.format,"admin:suspend")}async function ms(e,t){s.info(`Unsuspending tenant ${e}...`);let n=await Q(`/api/v1/admin/tenants/${e}/unsuspend`,{method:"POST",dryRun:t.dryRun});if(n.ok||(s.error(`Failed to unsuspend tenant: ${n.error}`),process.exit(c.NETWORK_ERROR)),t.dryRun){Z(n.data,t.format,"admin:unsuspend");return}s.success(`Tenant ${T.blue(e)} unsuspended`),t.format==="json"&&Y({unsuspended:!0,tenantId:e},t.format,"admin:unsuspend")}async function ps(e){s.info("Fetching usage report...");let t=new URLSearchParams;e.period&&t.append("period",e.period),e.top&&t.append("top",String(e.top));let n=`/api/v1/admin/usage/report${t.toString()?`?${t.toString()}`:""}`,r=await Q(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch usage report: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(r.data,e.format,"admin:usage");return}let o=U(r.data),a={period:o.period,topTenants:Ye(o.topTenants??o.data),totalUsage:o.totalUsage};e.format==="json"?Y(a,e.format,"admin:usage"):(s.info(`Usage report for period: ${R(a.period)}`),console.log(`Total usage: ${R(a.totalUsage)}`),a.topTenants.length>0&&(console.log(`
|
|
118
|
-
Top tenants:`),a.topTenants.forEach((i,l)=>{let u=U(i);console.log(` ${l+1}. ${R(u.tenantName||u.tenantId||u.name)} \u2014 ${R(u.usage)}`)})))}async function fs(e){s.info("Fetching dead letter queue...");let t=await Q("/api/v1/admin/dlq/list",{dryRun:e.dryRun});if(t.ok||(s.error(`Failed to fetch DLQ: ${t.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(t.data,e.format,"admin:dlq:list");return}let n=U(t.data),r={messages:Ye(n.messages??n.data),count:Be(n,"count")||Be(n,"total")};e.format==="json"?Y(r,e.format,"admin:dlq:list"):(s.info(`Found ${r.count} message(s) in DLQ`),r.messages.length>0&&(console.log(`
|
|
119
|
-
Messages:`),r.messages.forEach(o=>{let a=U(o);console.log(` ${T.blue(R(a.id))}`),console.log(` Type: ${R(a.type)}`),console.log(` Error: ${R(a.error)}`),console.log(` Created: ${R(a.createdAt)}`)})))}async function gs(e,t){s.info(`Replaying DLQ message ${e}...`);let n=await Q(`/api/v1/admin/dlq/replay/${e}`,{method:"POST",dryRun:t.dryRun});if(n.ok||(s.error(`Failed to replay message: ${n.error}`),process.exit(c.NETWORK_ERROR)),t.dryRun){Z(n.data,t.format,"admin:dlq:replay");return}s.success(`Message ${T.blue(e)} replayed`),t.format==="json"&&Y({replayed:!0,messageId:e},t.format,"admin:dlq:replay")}async function ys(e){e.yes||(s.warn("This will permanently delete all messages in the DLQ"),s.info("Use --yes to confirm"),process.exit(c.CANCELLED)),s.info("Purging DLQ...");let t=await Q("/api/v1/admin/dlq/purge",{method:"POST",dryRun:e.dryRun});if(t.ok||(s.error(`Failed to purge DLQ: ${t.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(t.data,e.format,"admin:dlq:purge");return}s.success("DLQ purged"),e.format==="json"&&Y({purged:!0,count:ze(t.data,"count")},e.format,"admin:dlq:purge")}async function hs(e){s.info("Fetching feature flags...");let t=await Q("/api/v1/admin/feature-flags",{dryRun:e.dryRun});if(t.ok||(s.error(`Failed to fetch flags: ${t.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(t.data,e.format,"admin:flags:list");return}let n=U(t.data),r={flags:Ye(n.flags??n.data),total:Be(n,"total")};e.format==="json"?Y(r,e.format,"admin:flags:list"):(s.info(`Found ${r.total} flag(s)`),r.flags.length>0&&(console.log(`
|
|
120
|
-
Flags:`),r.flags.forEach(o=>{let a=U(o),i=a.override!==void 0?T.yellow(String(a.override)):T.gray(String(a.default??""));console.log(` ${T.blue(R(a.name))} = ${i}`)})))}async function bs(e,t,n){s.info(`Setting flag ${e}...`);let r=t;t==="true"?r=!0:t==="false"?r=!1:Number.isNaN(Number(t))||(r=Number(t));let o=await Q(`/api/v1/admin/feature-flags/${e}`,{method:"POST",body:{value:r},dryRun:n.dryRun});if(o.ok||(s.error(`Failed to set flag: ${o.error}`),process.exit(c.NETWORK_ERROR)),n.dryRun){Z(o.data,n.format,"admin:flags:set");return}s.success(`Flag ${T.blue(e)} set to ${r}`),n.format==="json"&&Y({flag:e,value:r},n.format,"admin:flags:set")}async function vs(e,t){s.info(`Unsetting flag ${e}...`);let n=await Q(`/api/v1/admin/feature-flags/${e}`,{method:"DELETE",dryRun:t.dryRun});if(n.ok||(s.error(`Failed to unset flag: ${n.error}`),process.exit(c.NETWORK_ERROR)),t.dryRun){Z(n.data,t.format,"admin:flags:unset");return}s.success(`Flag ${T.blue(e)} unset`),t.format==="json"&&Y({flag:e,unset:!0},t.format,"admin:flags:unset")}async function ws(e){s.info("Fetching audit log...");let t=new URLSearchParams;e.actor&&t.append("actor",e.actor),e.action&&t.append("action",e.action),e.since&&t.append("since",e.since),e.limit&&t.append("limit",String(e.limit));let n=`/api/v1/admin/audit${t.toString()?`?${t.toString()}`:""}`,r=await Q(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch audit log: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(r.data,e.format,"admin:audit");return}let o=U(r.data),a={entries:Ye(o.entries??o.data),total:Be(o,"total")};e.format==="json"?Y(a,e.format,"admin:audit"):(s.info(`Found ${a.total} audit log entries`),a.entries.length>0&&(console.log(`
|
|
121
|
-
Audit entries:`),a.entries.forEach(i=>{let l=U(i);console.log(` ${R(l.timestamp)} \u2014 ${T.blue(R(l.action))} by ${R(l.actor)}`),l.details&&console.log(` ${R(l.details)}`)})))}async function Rs(e){s.info("Running platform health check...");let t=await Q("/api/v1/system/status",{dryRun:e.dryRun});if(t.ok||(s.error(`Failed to fetch health status: ${t.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){Z(t.data,e.format,"admin:health");return}let n=U(t.data),r={status:R(n.status,"unknown"),services:U(n.services),timestamp:n.timestamp};if(e.format==="json")Y(r,e.format,"admin:health");else{let o=r.status==="healthy"?T.green:r.status==="degraded"?T.yellow:T.red;s.info(`Platform status: ${o(r.status)}`),Object.keys(r.services).length>0&&(console.log(`
|
|
122
|
-
Services:`),Object.entries(r.services).forEach(([a,i])=>{let l=U(i),u=l.status==="healthy"?T.green("\u2713"):T.red("\u2717");console.log(` ${u} ${a}: ${R(l.status)}`),l.latency&&console.log(` Latency: ${R(l.latency)}ms`),l.error&&console.log(` Error: ${R(l.error)}`)}))}}function Mn(e){let t=e.command("admin").description("Platform admin operations");t.command("tenants").description("List all tenants/organizations").option("--limit <n>","Maximum number of tenants to return",o=>parseInt(o,10)).option("--offset <n>","Offset for pagination",o=>parseInt(o,10)).option("--status <status>","Filter by status (active|suspended)").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await ls({limit:o.limit,offset:o.offset,status:o.status,format:o.format||a.format,dryRun:o.dryRun||a.dryRun})}),t.command("tenant <id>").description("Get tenant details").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async(o,a)=>{let i=a.optsWithGlobals?.()||a;await ds(o,{format:a.format||i.format,dryRun:a.dryRun||i.dryRun})}),t.command("suspend <id>").description("Suspend a tenant (requires --yes)").option("--yes","Confirm suspension").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async(o,a)=>{let i=a.optsWithGlobals?.()||a;await us(o,{yes:a.yes||i.yes,format:a.format||i.format,dryRun:a.dryRun||i.dryRun})}),t.command("unsuspend <id>").description("Unsuspend a tenant").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async(o,a)=>{let i=a.optsWithGlobals?.()||a;await ms(o,{format:a.format||i.format,dryRun:a.dryRun||i.dryRun})}),t.command("usage").description("Cross-tenant usage report").option("--period <period>","Report period (daily|weekly|monthly)").option("--top <n>","Show top N tenants",o=>parseInt(o,10)).option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await ps({period:o.period,top:o.top,format:o.format||a.format,dryRun:o.dryRun||a.dryRun})});let n=t.command("dlq").description("Dead letter queue management");n.command("list").description("List failed messages in DLQ").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await fs({format:o.format||a.format,dryRun:o.dryRun||a.dryRun})}),n.command("replay <id>").description("Replay a failed message").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async(o,a)=>{let i=a.optsWithGlobals?.()||a;await gs(o,{format:a.format||i.format,dryRun:a.dryRun||i.dryRun})}),n.command("purge").description("Purge the dead letter queue (requires --yes)").option("--yes","Confirm purge").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await ys({yes:o.yes||a.yes,format:o.format||a.format,dryRun:o.dryRun||a.dryRun})});let r=t.command("flags").description("Feature flag management");r.command("list").description("List all feature flags").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await hs({format:o.format||a.format,dryRun:o.dryRun||a.dryRun})}),r.command("set <flag> <value>").description("Set a feature flag override").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async(o,a,i)=>{let l=i.optsWithGlobals?.()||i;await bs(o,a,{format:i.format||l.format,dryRun:i.dryRun||l.dryRun})}),r.command("unset <flag>").description("Remove a feature flag override").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async(o,a)=>{let i=a.optsWithGlobals?.()||a;await vs(o,{format:a.format||i.format,dryRun:a.dryRun||i.dryRun})}),t.command("audit").description("Query audit log with optional filters").option("--actor <userId>","Filter by actor/user ID").option("--action <type>","Filter by action type").option("--since <date>","Filter entries since date (ISO format)").option("--limit <n>","Maximum number of entries to return",o=>parseInt(o,10)).option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await ws({actor:o.actor,action:o.action,since:o.since,limit:o.limit,format:o.format||a.format,dryRun:o.dryRun||a.dryRun})}),t.command("health").description("Platform-wide health check").option("--format <type>","Output format: json or plain").option("--dry-run","Show request without executing").action(async o=>{let a=o.optsWithGlobals?.()||o;await Rs({format:o.format||a.format,dryRun:o.dryRun||a.dryRun})})}import{existsSync as Cs,readFileSync as Es,writeFileSync as ks}from"fs";import{resolve as Vt}from"path";var b={pm:["npm","pnpm","yarn","bun"],region:["global","cn","hybrid"],orm:["prisma","drizzle","none"],db:["postgres","mysql","sqlite","none"],auth:["clerk","betterauth","none"],socialLogin:["wechat","qq","dingtalk","workweixin","feishu","weibo"],payment:["stripe","lemon","wechat","alipay","none"],ai:["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","none"],deploy:["vercel","railway","cloudflare","selfhost","none"],docs:["fumadocs","mintlify","docusaurus","nextra","vitepress","none"],email:["resend","postmark","ses","aliyun-dm","tencent-ses","netease","none"],storage:["r2","s3","supabase-storage","aliyun-oss","tencent-cos","qiniu","none"],monitoring:["sentry","datadog","bugsnag","aliyun-arms","tingyun","none"],analytics:["posthog","plausible","umami","mixpanel","baidu","sensors","growingio","none"],sms:["twilio","messagebird","plivo","aliyun-sms","tencent-sms","yunpian","none"],queue:["qstash","bullmq","upstash","sqs","none"],search:["meilisearch","typesense","algolia","pgvector","none"],cache:["upstash-redis","vercel-kv","redis","dragonfly","none"],notifications:["novu","knock","custom","none"],webhooks:["svix","custom","none"],cms:["sanity","contentful","strapi","none"],featureFlags:["vercel-flags","growthbook","configcat","none"],captcha:["turnstile","hcaptcha","aliyun-slide","none"],mcp:["on","off"],metering:["auto","on","off"],billingMode:["usage","seat","credits"],idp:["clerk","oauth-server"]},Ss=[{flags:"-p, --pm <id>",description:"Package manager: npm, pnpm, yarn, or bun"},{flags:"--region <id>",description:"Target region: global, cn, or hybrid"},{flags:"--orm <id>",description:"ORM: prisma, drizzle, or none"},{flags:"--db <id>",description:"Database: postgres, mysql, sqlite, or none"},{flags:"--auth <id>",description:"Auth provider: clerk, betterauth, or none"},{flags:"--social-login <ids>",description:"Comma-separated CN social login providers"},{flags:"--payment <id>",description:"Payment provider: stripe, lemon, wechat, alipay, or none"},{flags:"--ai <ids>",description:"Expert/non-interactive AI provider seed ids"},{flags:"--deploy <target>",description:"Deploy target: vercel, railway, cloudflare, selfhost, or none"},{flags:"--docs <id>",description:"Docs framework: fumadocs, mintlify, docusaurus, nextra, vitepress, or none"},{flags:"--email <id>",description:"Transactional email provider"},{flags:"--storage <id>",description:"Object storage provider"},{flags:"--monitoring <id>",description:"Monitoring provider"},{flags:"--analytics <id>",description:"Analytics provider"},{flags:"--sms <id>",description:"SMS provider"},{flags:"--queue <id>",description:"Queue provider"},{flags:"--search <id>",description:"Search provider"},{flags:"--cache <id>",description:"Cache provider"},{flags:"--notifications <id>",description:"Notifications provider"},{flags:"--webhooks <id>",description:"Outbound webhooks provider"},{flags:"--cms <id>",description:"Headless CMS provider"},{flags:"--feature-flags <id>",description:"Feature flag provider"},{flags:"--captcha <id>",description:"Captcha provider"},{flags:"--mcp <mode>",description:"MCP server mode: on or off"},{flags:"--metering <mode>",description:"Metering mode: auto, on, or off"},{flags:"--billing-mode <mode>",description:"Billing mode: usage, seat, or credits"},{flags:"--idp <id>",description:"Identity provider: clerk or oauth-server"},{flags:"--i18n",description:"Enable i18n",default:!0},{flags:"--no-i18n",description:"Disable i18n"},{flags:"--no-install",description:"Skip package install"},{flags:"--no-git",description:"Skip git init"},{flags:"--dry-run",description:"Preview project scaffolding without creating files (exit code 10)"},{flags:"--json",description:"Emit machine-readable JSON events"},{flags:"--yes",description:"Skip all interactive prompts (Agent mode)"}],pe={name:"nebutra",description:"Governance-first CLI for Nebutra Sailor scaffolding, registry-backed features, and platform operations",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:"add",description:"Add a registry-backed platform feature or external UI component",usage:"nebutra add [components...] [options]",arguments:[{name:"components",description:"Local feature names to install from the Nebutra registry",required:!1,variadic:!0}],options:[{flags:"--21st <id>",description:"Fetch and install a component from 21st.dev registry"},{flags:"--v0 <url>",description:"Fetch and install a component from v0.dev by URL"},{flags:"--dry-run",description:"Preview what would be installed without making changes (exit code 10)"},{flags:"--yes",description:"Skip all interactive prompts and use defaults (Agent mode)"},{flags:"--if-not-exists",description:"Skip installation if component already exists"}],examples:[{command:"nebutra add cache --provider upstash-redis --yes",description:"Install the local cache feature with the Upstash Redis provider"},{command:"nebutra add --21st button-01",description:"Add a component from 21st.dev (shadcn-style registry)"},{command:'nebutra add --v0 "https://v0.dev/r/..." --dry-run',description:"Preview adding a component from v0.dev without making changes"},{command:"nebutra add webhooks --provider svix --yes --if-not-exists",description:"Install webhooks without prompts, skip if already configured"}]},{name:"create",description:"Scaffold a topology-first Nebutra Sailor project with governed defaults",usage:"nebutra create [dir] [options]",arguments:[{name:"dir",description:"Target directory for the new project (optional, will prompt if not provided)",required:!1}],options:Ss,examples:[{command:"nebutra create my-saas-app --region=hybrid --ai=openai,deepseek",description:"Create a topology-first project with hybrid defaults and selected AI providers"},{command:"nebutra create my-cn-app --region=cn --payment=wechat --storage=aliyun-oss --deploy=selfhost -y",description:"Create a non-interactive China-ready scaffold"},{command:"nebutra create my-app --storage=supabase-storage --dry-run --json",description:"Preview scaffolding with structured JSON output"}]},{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, add, create)",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 add",description:"Show schema for add command with enum values"},{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:"auth",description:"Configure authentication providers and tenant access defaults",usage:"nebutra auth [subcommand]"},{name:"billing",description:"Manage billing providers, subscriptions, usage, and return flows",usage:"nebutra billing [subcommand]"},{name:"stats",description:"Show monorepo statistics, health signals, and platform inventory",usage:"nebutra stats [options]"},{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:"workflow",description:"Initialize and inspect workflow runtime adapters",usage:"nebutra workflow [subcommand]"},{name:"backend",description:"Manage backend runtime service workflows",usage:"nebutra backend [subcommand]"},{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:"admin",description:"Operate tenant, platform health, and administrative workflows",usage:"nebutra admin [subcommand]"},{name:"community",description:"Inspect community health, showcases, and external adoption signals",usage:"nebutra community [subcommand]"},{name:"growth",description:"Analyze product growth, funnels, retention, and lifecycle signals",usage:"nebutra growth [subcommand]"},{name:"ecosystem",description:"Manage template marketplace, ideas, project showcase, and ecosystem sync",usage:"nebutra ecosystem [subcommand]"},{name:"services",description:"Inspect and manage microservice health, logs, scaling, and rollouts",usage:"nebutra services [subcommand]"},{name:"search",description:"Manage search indexes, reindexing, and search diagnostics",usage:"nebutra search [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:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var Vn="nebutra.config.json",xs=b.ai.filter(e=>e!=="none"),Gn={"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 ce(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 Os(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function As(e){return Gn[e]?Gn[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function gt(){return Object.fromEntries(xs.map(e=>[e,{id:e,name:Os(e),envVars:As(e)}]))}function fe(){return Vt(process.cwd(),Vn)}function Ie(){let e=fe();if(!Cs(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(Es(e,"utf-8"))}catch(t){s.error(`Failed to parse ${Vn}: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}function yt(e){ks(fe(),`${JSON.stringify(e,null,2)}
|
|
123
|
-
`)}function Se(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function Kn(e){let t=gt(),n=[...new Set(e.map(o=>o.toLowerCase()))],r=n.filter(o=>!t[o]);return r.length>0&&(s.error(`Unknown AI provider(s): ${r.join(", ")}. Valid providers: ${Object.keys(t).join(", ")}`),process.exit(c.INVALID_ARGS)),n}function _s(e){let t=e?.split(",").map(r=>r.trim()).filter(Boolean)??[];t.length===0&&(s.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&&(s.error(`Invalid fallback target(s): ${n.join(", ")}. Expected provider:model.`),process.exit(c.INVALID_ARGS)),t}function qn(e){let t=Se(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,a])=>a.enabled).map(([a])=>a);return{path:fe(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function ie(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??Ps();return{...n,...t,...r?{format:r}:{}}}function Ps(){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 Is(e){e.format!=="json"&&s.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?s.warn("No AI providers configured. Set API keys to enable AI features."):s.success(`${n.configuredCount} AI provider(s) configured`)),ce(n,e.format,"ai:models")}async function Ns(e){e.format!=="json"&&s.info("Scanning for available agents...");try{let t=Vt(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?s.info("No agents configured. Create agents in backends/gateway/src/routes/agents/"):s.success(`Found ${r.count} agent(s)`)),ce(r,e.format,"ai:agents")}catch(t){s.error(`Failed to scan agents: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}async function $s(e,t){(!e||e.trim().length===0)&&(s.error("Prompt cannot be empty"),process.exit(c.INVALID_ARGS)),t.format!=="json"&&(s.info("Testing AI prompt against default model..."),s.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||s.warn("AI test execution requires a running API gateway. Start it with: pnpm --filter @nebutra/gateway dev"),ce(n,t.format,"ai:test")}async function Ts(e){e.format!=="json"&&s.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=Vt(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?s.warn("No AI providers configured. Set environment variables to enable AI features."):s.success(`Configuration loaded: ${n.join(", ")}`)),ce(t,e.format,"ai:config")}async function Us(e){let t=Ie(),n=Se(t),r=gt(),o=Object.values(r).map(i=>{let l=n.providers?.[i.id];return{id:i.id,name:i.name,enabled:l?.enabled===!0,configured:i.envVars.some(u=>!!process.env[u]),envVars:i.envVars.map(u=>({name:u,value:He(process.env[u])}))}}),a={configPath:fe(),providers:o,enabledCount:o.filter(i=>i.enabled).length,totalProviders:o.length};if(e.format!=="json"){let i=o.filter(l=>l.enabled);i.length===0?s.warn("No runtime AI providers enabled in nebutra.config.json."):s.success(`Enabled AI providers: ${i.map(l=>l.id).join(", ")}`)}ce(a,e.format,"ai:provider:list")}async function js(e,t){let n=Kn(e),r=Ie(),o=Se(r),a=gt(),i=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!0,envVars:a[u].envVars,enabledAt:o.providers?.[u]?.enabledAt??i};yt(r);let l={configPath:fe(),enabled:n,env:t.env===!0?n.flatMap(u=>a[u].envVars.map(m=>({provider:u,name:m,example:`${m}=`}))):void 0,ai:qn(r)};if(t.format!=="json"&&(s.success(`Enabled AI provider(s): ${n.join(", ")}`),t.env)){s.info("Required environment variables:");for(let u of n)for(let m of a[u].envVars)console.log(`${m}=`)}ce(l,t.format,"ai:provider:enable")}async function Ls(e,t){let n=Kn(e),r=Ie(),o=Se(r),a=gt(),i=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!1,envVars:o.providers?.[u]?.envVars??a[u].envVars,disabledAt:i};yt(r);let l={configPath:fe(),disabled:n,ai:qn(r)};t.format!=="json"&&s.success(`Disabled AI provider(s): ${n.join(", ")}`),ce(l,t.format,"ai:provider:disable")}async function Ds(e){let t=Ie(),n=Se(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},yt(t);let o={configPath:fe(),gateway:n.gateway};e.format!=="json"&&s.success("AI gateway governance initialized in nebutra.config.json"),ce(o,e.format,"ai:gateway:init")}async function Fs(e){let t=Ie(),n=Se(t),r={configPath:fe(),gateway:n.gateway??null,initialized:n.gateway?.enabled===!0};e.format!=="json"&&(r.initialized?s.success("AI gateway governance is initialized"):s.warn("AI gateway governance is not initialized. Run: nebutra ai gateway init")),ce(r,e.format,"ai:gateway:status")}async function Bs(e,t){(!e||e.trim().length===0)&&(s.error("Route name cannot be empty"),process.exit(c.INVALID_ARGS)),t.policy||(s.error("Route policy is required. Use --policy <policy>."),process.exit(c.INVALID_ARGS));let n=_s(t.fallback),r=Ie(),o=Se(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},yt(r);let a={configPath:fe(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&s.success(`AI route '${e}' set with policy '${t.policy}'`),ce(a,t.format,"ai:route:set")}async function Ms(e){let t=Ie(),n=Se(t),r=Object.entries(n.routes??{}).map(([a,i])=>({name:a,...i})),o={configPath:fe(),routes:r,count:r.length};e.format!=="json"&&(r.length===0?s.warn("No AI routes configured. Run: nebutra ai route set chat --policy cost-latency-balanced --fallback openai:gpt-5.4"):s.success(`Configured AI routes: ${r.map(a=>a.name).join(", ")}`)),ce(o,e.format,"ai:route:list")}function zn(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=ie(a);await Us({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 l=ie(i);await js(a,{env:l.env===!0,format:l.format,interactive:l.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 l=ie(i);await Ls(a,{format:l.format,interactive:l.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=ie(a);await Ds({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=ie(a);await Fs({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 l=ie(i);await Bs(a,{policy:l.policy,fallback:l.fallback,format:l.format,interactive:l.yes!==!0})}),o.command("list").description("List configured AI routes").option("--format <type>","Output format: json or plain").action(async a=>{let i=ie(a);await Ms({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=ie(a);await Is({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=ie(a);await Ns({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 l=ie(i);await $s(a,{dryRun:l.dryRun===!0,format:l.format,interactive:l.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=ie(a);await Ts({dryRun:i.dryRun===!0,format:i.format,interactive:i.yes!==!0})})}import{resolve as Gs}from"path";function Kt(e,t,n){if(t==="json"){let r={command:n||"auth",...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 v(e,t){return e?e.length<=8?"***":`${e.substring(0,8)}*** (${t||e.length} chars)`:"not set"}function Vs(){try{let e=Gs(process.cwd(),"nebutra.config.ts"),t=jo("fs");if(t.existsSync(e)){let n=t.readFileSync(e,"utf-8");if(n.includes("clerk"))return"clerk";if(n.includes("better-auth"))return"better-auth";if(n.includes("nextauth"))return"nextauth";if(n.includes("supabase"))return"supabase"}}catch{}return"clerk"}async function Ks(e){s.info("Checking authentication configuration...");let t=Vs(),n={provider:t,configured:!1,keys:{}};t==="clerk"?(n.keys={CLERK_SECRET_KEY:v(process.env.CLERK_SECRET_KEY,"secret"),NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:v(process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,"publishable"),CLERK_WEBHOOK_SECRET:v(process.env.CLERK_WEBHOOK_SECRET,"webhook")},n.configured=!!process.env.CLERK_SECRET_KEY&&!!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY):t==="better-auth"?(n.keys={BETTER_AUTH_SECRET:v(process.env.BETTER_AUTH_SECRET,"secret"),BETTER_AUTH_URL:process.env.BETTER_AUTH_URL||"not set"},n.configured=!!process.env.BETTER_AUTH_SECRET):t==="nextauth"?(n.keys={AUTH_SECRET:v(process.env.AUTH_SECRET,"secret"),NEXTAUTH_SECRET:v(process.env.NEXTAUTH_SECRET,"legacy secret"),NEXTAUTH_URL:process.env.NEXTAUTH_URL||"not set",AUTH_URL:process.env.AUTH_URL||"not set",GOOGLE_CLIENT_ID:v(process.env.GOOGLE_CLIENT_ID,"google client"),GITHUB_CLIENT_ID:v(process.env.GITHUB_CLIENT_ID,"github client")},n.configured=!!(process.env.AUTH_SECRET||process.env.NEXTAUTH_SECRET)):(n.keys={NEXT_PUBLIC_SUPABASE_URL:process.env.NEXT_PUBLIC_SUPABASE_URL||"not set",NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY:v(process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY,"publishable"),NEXT_PUBLIC_SUPABASE_ANON_KEY:v(process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,"anon"),SUPABASE_URL:process.env.SUPABASE_URL||"not set",SUPABASE_PUBLISHABLE_KEY:v(process.env.SUPABASE_PUBLISHABLE_KEY,"publishable"),SUPABASE_ANON_KEY:v(process.env.SUPABASE_ANON_KEY,"anon"),SUPABASE_SERVICE_ROLE_KEY:v(process.env.SUPABASE_SERVICE_ROLE_KEY,"service role"),SUPABASE_WEBHOOK_SECRET:v(process.env.SUPABASE_WEBHOOK_SECRET,"webhook")},n.configured=!!((process.env.SUPABASE_URL||process.env.NEXT_PUBLIC_SUPABASE_URL)&&(process.env.SUPABASE_PUBLISHABLE_KEY||process.env.SUPABASE_ANON_KEY||process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY||process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)&&process.env.SUPABASE_SERVICE_ROLE_KEY)),e.dryRun||(n.configured?s.success(`Auth provider configured: ${t}`):s.warn(`Auth provider ${t} is not fully configured`)),Kt({...n},e.format,"auth:status")}async function qs(e,t){let n=["clerk","better-auth","nextauth","supabase"];n.includes(e.toLowerCase())||(s.error(`Invalid provider: ${e}. Choose from: ${n.join(", ")}`),process.exit(c.INVALID_ARGS));let r=e.toLowerCase();s.info(`Setting up ${r} authentication...`),r==="clerk"?(s.info("Clerk setup requires:"),s.info("1. A Clerk account (https://clerk.com)"),s.info("2. A Clerk application created"),s.info("3. API keys from the Clerk dashboard"),s.info(""),s.info("To complete setup:"),s.info("1. Go to https://dashboard.clerk.com"),s.info("2. Copy your Secret Key and Publishable Key"),s.info("3. Add them to .env.local:"),s.info(' CLERK_SECRET_KEY="sk_..."'),s.info(' NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_..."'),s.info(""),s.info("Webhook setup (optional):"),s.info("1. In Clerk dashboard, go to Webhooks"),s.info("2. Create endpoint: https://yourdomain.com/api/webhooks/clerk"),s.info("3. Copy the signing secret to .env.local:"),s.info(' CLERK_WEBHOOK_SECRET="whsec_..."')):r==="better-auth"?(s.info("Better Auth setup requires:"),s.info("1. Database URL configured (DATABASE_URL env var)"),s.info("2. A generated auth secret"),s.info(""),s.info("To complete setup:"),s.info("1. Ensure DATABASE_URL is set in .env.local"),s.info("2. Generate a new secret:"),s.info(" openssl rand -base64 32"),s.info("3. Add to .env.local:"),s.info(' BETTER_AUTH_SECRET="<generated_secret>"'),s.info(' BETTER_AUTH_URL="http://localhost:3000"'),s.info(""),s.info("4. Run database migration:"),s.info(" pnpm --filter @nebutra/web db:push")):r==="nextauth"?(s.info("NextAuth / Auth.js setup requires:"),s.info("1. A generated Auth.js secret"),s.info("2. NEXTAUTH_URL or AUTH_URL pointing at the web app origin"),s.info("3. OAuth provider credentials for each enabled provider"),s.info(""),s.info("To complete setup:"),s.info("1. Generate a new secret:"),s.info(" openssl rand -base64 32"),s.info("2. Add to the production environment:"),s.info(' AUTH_PROVIDER="nextauth"'),s.info(' NEXT_PUBLIC_AUTH_PROVIDER="nextauth"'),s.info(' AUTH_SECRET="<generated_secret>"'),s.info(' NEXTAUTH_URL="https://app.nebutra.com"'),s.info(' GOOGLE_CLIENT_ID="..."'),s.info(' GOOGLE_CLIENT_SECRET="..."')):(s.info("Supabase Auth setup requires:"),s.info("1. Supabase project URL"),s.info("2. Public anon key for browser auth"),s.info("3. Service role key for server-side user/session validation"),s.info(""),s.info("To complete setup:"),s.info(' AUTH_PROVIDER="supabase"'),s.info(' NEXT_PUBLIC_AUTH_PROVIDER="supabase"'),s.info(' NEXT_PUBLIC_SUPABASE_URL="https://xxx.supabase.co"'),s.info(' NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY="sb_publishable_..."'),s.info(' NEXT_PUBLIC_SUPABASE_ANON_KEY="..."'),s.info(' SUPABASE_URL="https://xxx.supabase.co"'),s.info(' SUPABASE_PUBLISHABLE_KEY="sb_publishable_..."'),s.info(' SUPABASE_ANON_KEY="..."'),s.info(' SUPABASE_SERVICE_ROLE_KEY="..."')),t.dryRun||s.success(`Setup instructions for ${r} displayed above`),Kt({provider:r,setupGuide:"Complete setup by following the instructions above",documentationUrl:r==="clerk"?"https://clerk.com/docs":r==="better-auth"?"https://www.better-auth.com":r==="nextauth"?"https://authjs.dev":"https://supabase.com/docs/guides/auth"},t.format,"auth:setup")}async function zs(e){s.info("Checking authentication keys and secrets...");let n={keys:{clerk:{CLERK_SECRET_KEY:v(process.env.CLERK_SECRET_KEY,"secret key"),NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:v(process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,"publishable key"),CLERK_WEBHOOK_SECRET:v(process.env.CLERK_WEBHOOK_SECRET,"webhook secret")},betterAuth:{BETTER_AUTH_SECRET:v(process.env.BETTER_AUTH_SECRET,"secret"),BETTER_AUTH_URL:process.env.BETTER_AUTH_URL||"not set"},nextAuth:{AUTH_SECRET:v(process.env.AUTH_SECRET,"secret"),NEXTAUTH_SECRET:v(process.env.NEXTAUTH_SECRET,"legacy secret"),NEXTAUTH_URL:process.env.NEXTAUTH_URL||"not set",AUTH_URL:process.env.AUTH_URL||"not set",GOOGLE_CLIENT_ID:v(process.env.GOOGLE_CLIENT_ID,"google client"),GITHUB_CLIENT_ID:v(process.env.GITHUB_CLIENT_ID,"github client")},supabase:{NEXT_PUBLIC_SUPABASE_URL:process.env.NEXT_PUBLIC_SUPABASE_URL||"not set",NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY:v(process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY,"publishable"),NEXT_PUBLIC_SUPABASE_ANON_KEY:v(process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,"anon"),SUPABASE_URL:process.env.SUPABASE_URL||"not set",SUPABASE_PUBLISHABLE_KEY:v(process.env.SUPABASE_PUBLISHABLE_KEY,"publishable"),SUPABASE_ANON_KEY:v(process.env.SUPABASE_ANON_KEY,"anon"),SUPABASE_SERVICE_ROLE_KEY:v(process.env.SUPABASE_SERVICE_ROLE_KEY,"service role")},common:{DATABASE_URL:v(process.env.DATABASE_URL,"database url"),JWT_SECRET:v(process.env.JWT_SECRET,"jwt secret")}},configured:{clerk:{secret:!!process.env.CLERK_SECRET_KEY,publishable:!!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY},betterAuth:{secret:!!process.env.BETTER_AUTH_SECRET,url:!!process.env.BETTER_AUTH_URL},nextAuth:{secret:!!(process.env.AUTH_SECRET||process.env.NEXTAUTH_SECRET),url:!!(process.env.NEXTAUTH_URL||process.env.AUTH_URL)},supabase:{url:!!(process.env.SUPABASE_URL||process.env.NEXT_PUBLIC_SUPABASE_URL),publishableKey:!!(process.env.SUPABASE_PUBLISHABLE_KEY||process.env.SUPABASE_ANON_KEY||process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY||process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY),serviceRole:!!process.env.SUPABASE_SERVICE_ROLE_KEY}}};if(!e.dryRun){let r=n.configured.clerk.secret&&n.configured.clerk.publishable,o=n.configured.betterAuth.secret&&n.configured.betterAuth.url,a=n.configured.nextAuth.secret&&n.configured.nextAuth.url,i=n.configured.supabase.url&&n.configured.supabase.publishableKey&&n.configured.supabase.serviceRole;!r&&!o&&!a&&!i?s.warn("No authentication keys configured"):(s.info("Auth keys status:"),r&&s.success("Clerk configured"),o&&s.success("Better Auth configured"),a&&s.success("NextAuth configured"),i&&s.success("Supabase configured"))}Kt(n,e.format,"auth:keys")}function Yn(e){let t=e.command("auth").description("Manage authentication configuration (Clerk, Better Auth, NextAuth, or Supabase)");t.command("status").description("Check current authentication provider configuration").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await Ks({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("setup <provider>").description("Configure Clerk, Better Auth, NextAuth, or Supabase (interactive wizard)").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||r;await qs(n,{dryRun:r.dryRun||!1,format:r.format||o.format,interactive:o.yes!==!0})}),t.command("keys").description("Show authentication-related environment variables (masked)").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await zs({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import Ce from"fs";import le from"path";import*as ht from"@clack/prompts";import Jn from"picocolors";function x(e,t){let n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():void 0;return{...t&&typeof t.optsWithGlobals=="function"?t.optsWithGlobals():void 0,...n,...e}}var Hn=["ts","py"],Ys=`{
|
|
124
|
-
"name": "@nebutra/gateway",
|
|
125
|
-
"version": "0.1.0",
|
|
126
|
-
"private": true,
|
|
127
|
-
"type": "module",
|
|
128
|
-
"main": "src/index.ts",
|
|
129
|
-
"scripts": {
|
|
130
|
-
"dev": "tsx watch src/index.ts",
|
|
131
|
-
"build": "tsup src/index.ts --format esm --dts",
|
|
132
|
-
"start": "node dist/index.js"
|
|
133
|
-
},
|
|
134
|
-
"dependencies": {
|
|
135
|
-
"hono": "^4.6.0"
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
`,Hs=`import { Hono } from "hono";
|
|
139
|
-
|
|
140
|
-
const app = new Hono();
|
|
141
|
-
|
|
142
|
-
app.get("/healthz", (c) => c.json({ status: "ok" }));
|
|
143
|
-
|
|
144
|
-
export default app;
|
|
145
|
-
`,Ws=`# @nebutra/gateway
|
|
146
|
-
|
|
147
|
-
TypeScript / Hono BFF \u2014 auth, tenancy, rate-limit, and routing.
|
|
148
|
-
|
|
149
|
-
Per ADR 2026-05-10, this is the DEFAULT for new backend work.
|
|
150
|
-
`;function Js(e){return`[project]
|
|
151
|
-
name = "${e}"
|
|
152
|
-
version = "0.1.0"
|
|
153
|
-
description = "Nebutra Python backend service: ${e}"
|
|
154
|
-
requires-python = ">=3.11"
|
|
155
|
-
dependencies = [
|
|
156
|
-
"fastapi>=0.115.0",
|
|
157
|
-
"uvicorn[standard]>=0.32.0",
|
|
158
|
-
"pydantic>=2.9.0",
|
|
159
|
-
]
|
|
160
|
-
|
|
161
|
-
[build-system]
|
|
162
|
-
requires = ["hatchling"]
|
|
163
|
-
build-backend = "hatchling.build"
|
|
164
|
-
|
|
165
|
-
[tool.hatch.build.targets.wheel]
|
|
166
|
-
packages = ["src"]
|
|
167
|
-
`}function Xs(e){return`# backends/python/${e}
|
|
168
|
-
|
|
169
|
-
A Python (FastAPI) backend service.
|
|
170
|
-
|
|
171
|
-
## ADR 2026-05-10 \u2014 TS-by-Default
|
|
172
|
-
|
|
173
|
-
Per [docs/architecture/2026-05-10-ts-by-default-python-only-when-justified.md](../../../docs/architecture/2026-05-10-ts-by-default-python-only-when-justified.md),
|
|
174
|
-
new Python services are acceptable **only** when at least one of the following applies:
|
|
175
|
-
|
|
176
|
-
1. **Batch / queued work** that is too long for edge runtimes (>5s typical)
|
|
177
|
-
2. **ML / scientific compute** depending on the Python ecosystem (transformers, vLLM, etc.)
|
|
178
|
-
3. **Specialized libraries** with no comparable TS port
|
|
179
|
-
|
|
180
|
-
If your service is CRUD, webhooks, billing, content management, or third-party API proxying,
|
|
181
|
-
it belongs in \`backends/gateway\` (TypeScript) instead.
|
|
182
|
-
|
|
183
|
-
## Justification
|
|
184
|
-
|
|
185
|
-
> _Replace this line with the concrete reason this service is Python (cite one of 1/2/3 above)._
|
|
186
|
-
|
|
187
|
-
## Run
|
|
188
|
-
|
|
189
|
-
\`\`\`bash
|
|
190
|
-
uv sync
|
|
191
|
-
uv run uvicorn src.main:app --reload --port 8000
|
|
192
|
-
\`\`\`
|
|
193
|
-
`}var Qs=`from fastapi import FastAPI
|
|
194
|
-
from pydantic import BaseModel
|
|
195
|
-
|
|
196
|
-
app = FastAPI(title="nebutra-python-service")
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
class HealthResponse(BaseModel):
|
|
200
|
-
status: str
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
@app.get("/healthz", response_model=HealthResponse)
|
|
204
|
-
async def healthz() -> HealthResponse:
|
|
205
|
-
return HealthResponse(status="ok")
|
|
206
|
-
`;async function Zs(e,t){let n=le.join(e,"backends/gateway");Ce.existsSync(n)&&(s.info(`backends/gateway already exists in this monorepo \u2014 nothing to do.
|
|
207
|
-
(This command is primarily for downstream consumers using create-sailor.)`),process.exit(c.SUCCESS)),t.dryRun&&(process.stdout.write(JSON.stringify({mode:"dry-run",command:"backend init ts",files:["backends/gateway/package.json","backends/gateway/src/index.ts","backends/gateway/README.md"]},null,2)+`
|
|
208
|
-
`),process.exit(c.DRY_RUN_OK)),Ce.mkdirSync(le.join(n,"src"),{recursive:!0}),Ce.writeFileSync(le.join(n,"package.json"),Ys),Ce.writeFileSync(le.join(n,"src/index.ts"),Hs),Ce.writeFileSync(le.join(n,"README.md"),Ws),s.success("Created backends/gateway scaffold"),process.exit(c.SUCCESS)}function Wn(e){return/^[a-z][a-z0-9_-]{0,40}$/.test(e)}async function ea(e,t){let n=t.name,r=process.stdout.isTTY===!0&&!t.yes;if(!n&&r){let i=await ht.text({message:"Service name (lowercase, hyphens or underscores):",placeholder:"translator",validate:l=>Wn(l)?void 0:"Invalid name"});ht.isCancel(i)&&(s.warn("Cancelled."),process.exit(c.CANCELLED)),n=i}n||(s.error("Missing --name. Required in non-interactive mode."),process.exit(c.INVALID_ARGS)),Wn(n)||(s.error(`Invalid name: ${Jn.red(n)}. Use lowercase letters, digits, hyphen, underscore.`),process.exit(c.INVALID_ARGS));let o=le.join(e,"backends/python",n);Ce.existsSync(o)&&(s.error(`backends/python/${n} already exists \u2014 refusing to overwrite.`),process.exit(c.CONFLICT));let a=[[le.join(o,"pyproject.toml"),Js(n)],[le.join(o,"README.md"),Xs(n)],[le.join(o,"src/main.py"),Qs],[le.join(o,"src/__init__.py"),""]];t.dryRun&&(process.stdout.write(JSON.stringify({mode:"dry-run",command:`backend init py --name ${n}`,files:a.map(([i])=>i)},null,2)+`
|
|
209
|
-
`),process.exit(c.DRY_RUN_OK));for(let[i,l]of a)Ce.mkdirSync(le.dirname(i),{recursive:!0}),Ce.writeFileSync(i,l);s.success(`Created backends/python/${n} scaffold`),s.info("Update README.md to cite which ADR justification applies (batch | ML | specialized libs)."),process.exit(c.SUCCESS)}async function ta(e,t={}){Hn.includes(e)||(s.error(`Invalid runtime: ${Jn.red(e)}. Valid: ${Hn.join(", ")}`),process.exit(c.INVALID_ARGS));let n=h();e==="ts"?await Zs(n,t):await ea(n,t)}var Xn=e=>{e.command("backend").description("Scaffold backend services (ts | py)").command("init <runtime>").description("Scaffold a backend service (runtime: ts | py)").option("--name <name>","Service name (Python only; prompted if omitted)").option("--dry-run","Preview files that would be created (exit code 10)").action(async(n,r,o)=>{let a=x(r,o);await ta(n,{name:typeof r.name=="string"?r.name:void 0,dryRun:!!r.dryRun,yes:!!a.yes,quiet:!!a.quiet})})};function qt(e,t,n){if(t==="json"){let r={command:n||"billing",...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 na(e,t){return e?e.length<=8?"***":`${e.substring(0,8)}*** (${t||e.length} chars)`:"not set"}var bt={stripe:{name:"Stripe",keyVars:["STRIPE_SECRET_KEY","STRIPE_PUBLISHABLE_KEY"],webhookUrl:"/api/webhooks/stripe",setupUrl:"https://dashboard.stripe.com"},lemonsqueezy:{name:"Lemon Squeezy",keyVars:["LEMONSQUEEZY_API_KEY"],webhookUrl:"/api/webhooks/lemonsqueezy",setupUrl:"https://app.lemonsqueezy.com/settings/api"},polar:{name:"Polar",keyVars:["POLAR_ACCESS_TOKEN"],webhookUrl:"/api/webhooks/polar",setupUrl:"https://app.polar.sh/settings/api"},chinapay:{name:"ChinaPay",keyVars:["CHINAPAY_MERCHANT_ID","CHINAPAY_SECRET_KEY"],webhookUrl:"/api/webhooks/chinapay",setupUrl:"https://www.chinapay.com"}};async function ra(e){s.info("Checking payment provider configuration...");let t=Object.entries(bt).map(([o,a])=>{let i=a.keyVars.every(l=>process.env[l]);return{id:o,name:a.name,configured:i,keys:a.keyVars.map(l=>({name:l,value:na(process.env[l],"key")}))}}),n=t.filter(o=>o.configured),r={providers:t,configuredCount:n.length,totalProviders:t.length,configuredList:n.map(o=>o.name)};e.dryRun||(r.configuredCount===0?s.warn("No payment providers configured. Set API keys to enable billing."):s.success(`${r.configuredCount} payment provider(s) configured`)),qt(r,e.format,"billing:status")}async function oa(e,t){let n=Object.keys(bt);n.includes(e.toLowerCase())||(s.error(`Invalid provider: ${e}. Choose from: ${n.join(", ")}`),process.exit(c.INVALID_ARGS));let r=e.toLowerCase(),o=bt[r];s.info(`Setting up ${o.name} payment provider...`),s.info(""),s.info("Setup steps:"),s.info(`1. Go to ${o.setupUrl}`),s.info("2. Create or log in to your account"),s.info("3. Generate API credentials"),s.info("4. Add the following to .env.local:"),s.info(""),o.keyVars.forEach(i=>{s.info(` ${i}="<your_${i.toLowerCase()}>"`.padStart(45))}),s.info(""),s.info("5. (Optional) Configure webhook in provider dashboard:"),s.info(` Webhook URL: https://yourdomain.com${o.webhookUrl}`),t.dryRun||s.success(`Setup instructions for ${o.name} displayed above`);let a={provider:r,name:o.name,requiredKeys:o.keyVars,webhookUrl:o.webhookUrl,setupGuide:"Follow the instructions above to complete setup",documentationUrl:o.setupUrl};qt(a,t.format,"billing:setup")}async function sa(e){s.info("Checking billing webhook configuration...");let t=process.env.NEXT_PUBLIC_APP_URL||"https://yourdomain.com",n=Object.entries(bt).map(([o,a])=>({provider:o,name:a.name,url:`${t}${a.webhookUrl}`,endpoint:a.webhookUrl,configured:a.keyVars.every(i=>process.env[i])})),r={baseUrl:t,webhooks:n,configurationSteps:["1. Set NEXT_PUBLIC_APP_URL in .env.local to your domain","2. Copy the webhook URL for each provider","3. Configure in the provider's dashboard","4. Ensure the API key is also set"]};e.dryRun||(s.info("Webhook endpoints:"),n.forEach(o=>{o.configured?s.success(`${o.name}: configured`):s.warn(`${o.name}: not configured (missing API key)`)})),qt(r,e.format,"billing:webhooks")}function Qn(e){let t=e.command("billing").description("Manage payment providers and billing configuration");t.command("status").description("Check which payment providers are configured").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await ra({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("setup <provider>").description("Configure payment provider (Stripe, Lemon Squeezy, Polar, or ChinaPay)").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async(n,r)=>{let o=r.optsWithGlobals?.()||r;await oa(n,{dryRun:r.dryRun||!1,format:r.format||o.format,interactive:o.yes!==!0})}),t.command("webhooks").description("Show webhook endpoints for each payment provider").option("--dry-run","Preview without making changes").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await sa({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}function We(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 Zn(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function aa(e){s.info("Initializing brand system...");let t=await z("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});We(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand system initialized successfully")}async function ia(e){s.info("Applying brand configuration...");let t=await z("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});We(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand applied successfully")}async function ca(e){let t=[];e.primary&&(Zn(e.primary)||(s.error(`Invalid primary color format: ${e.primary}. Expected hex format like #0033FE`),process.exit(c.INVALID_ARGS)),t.push(`--primary=${e.primary}`)),e.secondary&&(Zn(e.secondary)||(s.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&&(s.warn("No colors specified. Usage: nebutra brand palette --primary=#HEX --secondary=#HEX"),s.info("Example: nebutra brand palette --primary=#0033FE --secondary=#0BF1C3"),process.exit(c.INVALID_ARGS)),s.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"});We(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||s.success("Color palette generated successfully")}async function la(e){s.info("Syncing brand tokens across packages...");let t=await z("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});We(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand tokens synced successfully")}async function da(e){s.info("Verifying brand token consistency...");let t=await z("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});We(t,e.format,"brand:verify-tokens"),t.exitCode!==0&&(s.error("Brand token verification failed. There are inconsistencies in your design tokens."),process.exit(t.exitCode)),e.dryRun||s.success("All brand tokens are consistent")}function er(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 aa({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 ia({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 ca({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 la({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 da({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import be from"picocolors";var ua=process.env.NEBUTRA_API_URL||"http://localhost:3001/api";function ee(e){return Array.isArray(e)?e.map(t=>t&&typeof t=="object"&&!Array.isArray(t)?t:{}):[]}function ma(e){if(!e||typeof e!="object"||Array.isArray(e))return{};let t={};for(let[n,r]of Object.entries(e))typeof r=="number"&&(t[n]=r);return t}async function j(e,t={}){let n=`${ua}${e}`,r=await fetch(n,{...t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${process.env.NEBUTRA_ADMIN_TOKEN||""}`,...t.headers}});if(!r.ok){let a=await r.text().catch(()=>r.statusText);throw new Error(`API Error (${r.status}): ${a}`)}let o=await r.json();return o&&typeof o=="object"&&!Array.isArray(o)?o:{value:o}}function pa(e){let t={dau_retention:.25,engagement_rate:.25,content_velocity:.2,response_time:.15,member_retention:.15},n={},r=0;for(let[o,a]of Object.entries(t)){let i=Math.min(100,(e[o]||0)*100);n[o]=i,r+=i*a}return{score:Math.round(r),breakdown:n}}async function fa(e){try{s.info("Fetching showcase submissions...");let t=new URLSearchParams;e.status&&t.append("status",e.status),e.category&&t.append("category",e.category);let n=await j(`/community/showcase?${t.toString()}`);if(ee(n.submissions).length===0)return s.warn("No showcase submissions found"),c.SUCCESS;s.info(`
|
|
210
|
-
Showcase Submissions (${ee(n.submissions).length})
|
|
211
|
-
`);for(let r of ee(n.submissions));return c.SUCCESS}catch(t){return s.error(`Failed to list showcase: ${t.message}`),c.ERROR}}async function ga(e,t){try{if(!t.yes)return s.warn(`Approve showcase submission ${e}? Use --yes to confirm`),c.SUCCESS;s.info(`Approving showcase submission ${e}...`);let n=await j(`/community/showcase/${e}/approve`,{method:"POST"});return s.success(`Approved: ${n.title}`),c.SUCCESS}catch(n){return s.error(`Failed to approve showcase: ${n.message}`),c.ERROR}}async function ya(e,t){try{if(!t.yes)return s.warn(`Reject showcase submission ${e}? Use --yes to confirm`),c.SUCCESS;let n=t.reason||"Does not meet guidelines";s.info(`Rejecting showcase submission ${e}...`);let r=await j(`/community/showcase/${e}/reject`,{method:"POST",body:JSON.stringify({reason:n})});return s.success(`Rejected: ${r.title}`),c.SUCCESS}catch(n){return s.error(`Failed to reject showcase: ${n.message}`),c.ERROR}}async function ha(e,t){try{if(!t.yes)return s.warn(`Mark showcase as featured: ${e}? Use --yes to confirm`),c.SUCCESS;s.info(`Featuring showcase submission ${e}...`);let n=await j(`/community/showcase/${e}/feature`,{method:"POST"});return s.success(`Featured: ${n.title}`),c.SUCCESS}catch(n){return s.error(`Failed to feature showcase: ${n.message}`),c.ERROR}}async function ba(e){try{s.info("Fetching showcase statistics...");let t=await j("/community/showcase/stats");return s.info(`
|
|
212
|
-
Showcase Statistics
|
|
213
|
-
`),c.SUCCESS}catch(t){return s.error(`Failed to fetch showcase stats: ${t.message}`),c.ERROR}}async function va(e){try{s.info("Fetching community content...");let t=new URLSearchParams;e.status&&t.append("status",e.status),e.type&&t.append("type",e.type);let n=await j(`/community/content?${t.toString()}`);if(ee(n.items).length===0)return s.warn("No content found"),c.SUCCESS;s.info(`
|
|
214
|
-
Community Content (${ee(n.items).length})
|
|
215
|
-
`);for(let r of ee(n.items));return c.SUCCESS}catch(t){return s.error(`Failed to list content: ${t.message}`),c.ERROR}}async function wa(e,t){try{let n=["approve","flag","archive","delete"];if(!t.action||!n.includes(t.action))return s.error(`Invalid action. Must be one of: ${n.join(", ")}`),c.ERROR;if(!t.yes)return s.warn(`${t.action} content ${e}? Use --yes to confirm`),c.SUCCESS;s.info(`Moderating content ${e} (${t.action})...`);let r=await j(`/community/content/${e}/moderate`,{method:"POST",body:JSON.stringify({action:t.action})});return s.success(`Content ${t.action}d: ${r.title}`),c.SUCCESS}catch(n){return s.error(`Failed to moderate content: ${n.message}`),c.ERROR}}async function Ra(e,t){try{if(!t.yes)return s.warn(`Publish content ${e}? Use --yes to confirm`),c.SUCCESS;s.info(`Publishing content ${e}...`);let n=await j(`/community/content/${e}/publish`,{method:"POST"});return s.success(`Published: ${n.title}`),c.SUCCESS}catch(n){return s.error(`Failed to publish content: ${n.message}`),c.ERROR}}async function Sa(e){try{s.info("Fetching content analytics...");let t=await j("/community/content/analytics");s.info(`
|
|
216
|
-
Content Performance Metrics
|
|
217
|
-
`);for(let n of ee(t.topContent).slice(0,5));return e.format,c.SUCCESS}catch(t){return s.error(`Failed to fetch analytics: ${t.message}`),c.ERROR}}async function Ca(e){try{s.info("Fetching community members...");let t=new URLSearchParams;e.role&&t.append("role",e.role),e.sort&&t.append("sort",e.sort);let n=await j(`/community/members?${t.toString()}`);if(ee(n.members).length===0)return s.warn("No members found"),c.SUCCESS;s.info(`
|
|
218
|
-
Community Members (${ee(n.members).length})
|
|
219
|
-
`);for(let r of ee(n.members)){let a={owner:be.red,admin:be.yellow,moderator:be.blue,member:be.gray}[String(r.role)]??be.gray}return c.SUCCESS}catch(t){return s.error(`Failed to list members: ${t.message}`),c.ERROR}}async function Ea(e,t){try{s.info(`Fetching profile for ${e}...`);let n=await j(`/community/members/${e}`);return s.info(`
|
|
220
|
-
Member Profile
|
|
221
|
-
`),c.SUCCESS}catch(n){return s.error(`Failed to fetch member profile: ${n.message}`),c.ERROR}}async function ka(e,t,n){try{let r=["member","moderator","admin","owner"];if(!r.includes(t))return s.error(`Invalid role. Must be one of: ${r.join(", ")}`),c.ERROR;if(!n.yes)return s.warn(`Change ${e} role to ${t}? Use --yes to confirm`),c.SUCCESS;s.info("Updating member role...");let o=await j(`/community/members/${e}/role`,{method:"POST",body:JSON.stringify({role:t})});return s.success(`Updated ${o.name} \u2192 ${be.bold(t)}`),c.SUCCESS}catch(r){return s.error(`Failed to update member role: ${r.message}`),c.ERROR}}async function xa(e,t){try{s.info(`Sending invite to ${e}...`);let n=await j("/community/members/invite",{method:"POST",body:JSON.stringify({email:e})});return s.success(`Invite sent to ${e}`),c.SUCCESS}catch(n){return s.error(`Failed to send invite: ${n.message}`),c.ERROR}}async function Oa(e,t){try{if(!t.yes)return s.warn(`Ban member ${e}? Use --yes to confirm`),c.SUCCESS;let n=t.reason||"Violation of community guidelines";s.info(`Banning member ${e}...`);let r=await j(`/community/members/${e}/ban`,{method:"POST",body:JSON.stringify({reason:n})});return s.success(`Banned: ${r.name}`),c.SUCCESS}catch(n){return s.error(`Failed to ban member: ${n.message}`),c.ERROR}}async function Aa(e){try{s.info("Computing community health score...");let t=e.period||"30d",n=await j(`/community/health?period=${t}`),{score:r,breakdown:o}=pa(ma(n.metrics));s.info(`
|
|
222
|
-
Community Health Report (${t}) \u2014 score ${r}
|
|
223
|
-
`);for(let[a,i]of Object.entries(o)){let l=a.replace(/_/g," ").toLowerCase(),u="\u2588".repeat(Math.round(i/5))+"\u2591".repeat(20-Math.round(i/5));s.info(` ${l.padEnd(24)} ${String(i).padStart(3)} ${u}`)}return e.format,c.SUCCESS}catch(t){return s.error(`Failed to compute health: ${t.message}`),c.ERROR}}async function _a(e){try{s.info("Fetching moderation queue...");let t=await j("/community/moderation/queue");if(ee(t.items).length===0)return s.success("No pending moderation items"),c.SUCCESS;s.info(`
|
|
224
|
-
Moderation Queue (${ee(t.items).length} pending)
|
|
225
|
-
`);for(let n of ee(t.items)){let o={low:be.gray("\u25CF"),medium:be.yellow("\u25CF"),high:be.red("\u25CF")}[String(n.severity)]??"\u25CF"}return c.SUCCESS}catch(t){return s.error(`Failed to fetch queue: ${t.message}`),c.ERROR}}async function Pa(e){try{s.info("Running AI-assisted moderation sweep..."),e.dryRun&&s.warn("DRY RUN MODE - no changes will be made");let t=await j("/community/moderation/auto",{method:"POST",body:JSON.stringify({dryRun:e.dryRun||!1})});return s.info(`
|
|
226
|
-
Moderation Results
|
|
227
|
-
`),e.dryRun?s.info("DRY RUN COMPLETE - no changes committed"):s.success("Moderation sweep complete"),c.SUCCESS}catch(t){return s.error(`Failed to run moderation: ${t.message}`),c.ERROR}}function tr(e){let t=e.command("community").description("Manage Nebutra-Sailor community dimension"),n=t.command("showcase").description("Project showcase management");n.command("list").description("List submitted projects").option("--status <status>","Filter by status (pending|approved|rejected|featured)").option("--category <category>","Filter by category").action(i=>fa(i).then(process.exit)),n.command("approve <id>").description("Approve a showcase submission").option("--yes","Skip confirmation").action((i,l)=>ga(i,l).then(process.exit)),n.command("reject <id>").description("Reject a showcase submission").option("--reason <text>","Rejection reason").option("--yes","Skip confirmation").action((i,l)=>ya(i,l).then(process.exit)),n.command("feature <id>").description("Mark as featured").option("--yes","Skip confirmation").action((i,l)=>ha(i,l).then(process.exit)),n.command("stats").description("Showcase engagement metrics").action(i=>ba(i).then(process.exit));let r=t.command("content").description("Content moderation pipeline");r.command("list").description("List community content").option("--status <status>","Filter by status (draft|published|flagged|archived)").option("--type <type>","Filter by type (article|discussion|announcement)").action(i=>va(i).then(process.exit)),r.command("moderate <id>").description("Moderate content").option("--action <action>","Action (approve|flag|archive|delete)").option("--yes","Skip confirmation").action((i,l)=>wa(i,l).then(process.exit)),r.command("publish <id>").description("Publish approved content").option("--yes","Skip confirmation").action((i,l)=>Ra(i,l).then(process.exit)),r.command("analytics").description("Content performance metrics").option("--format <format>","Output format (json|text)").action(i=>Sa(i).then(process.exit));let o=t.command("members").description("Member management");o.command("list").description("List members").option("--role <role>","Filter by role (member|admin|owner|moderator)").option("--sort <sort>","Sort by (engagement|joined|name)").action(i=>Ca(i).then(process.exit)),o.command("profile <userId>").description("View member profile + activity").action((i,l)=>Ea(i,l).then(process.exit)),o.command("role <userId> <role>").description("Update member role").option("--yes","Skip confirmation").action((i,l,u)=>ka(i,l,u).then(process.exit)),o.command("invite <email>").description("Invite to community").action((i,l)=>xa(i,l).then(process.exit)),o.command("ban <userId>").description("Ban member").option("--reason <text>","Ban reason").option("--yes","Skip confirmation").action((i,l)=>Oa(i,l).then(process.exit)),t.command("health").description("Community health dashboard").option("--period <period>","Time period (7d|30d|90d)","30d").option("--format <format>","Output format (json|text)").action(i=>Aa(i).then(process.exit));let a=t.command("moderate").description("AI-assisted moderation queue");a.command("queue").description("Show pending moderation items").action(i=>_a(i).then(process.exit)),a.command("auto").description("Run AI moderation sweep").option("--dry-run","Preview without committing").action(i=>Pa(i).then(process.exit))}import{appendFileSync as Ia,existsSync as Na,readFileSync as $a,writeFileSync as Ta}from"fs";import{homedir as Je}from"os";import{join as Me}from"path";import*as W from"@clack/prompts";import H from"picocolors";var vt=(pe.subcommands??[]).map(e=>e.name),nr={init:"Initialize a Nebutra project and create nebutra.config.json",add:"Add a registry-backed platform feature or external UI component",create:"Scaffold a topology-first Nebutra Sailor project",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",workflow:"Workflow provider scaffolding",backend:"Backend runtime service workflows",e2e:"Run browser E2E suites",theme:"Theme registry and governance metadata",ai:"AI provider and gateway routing configuration",auth:"Authentication setup",billing:"Billing and subscription management",stats:"Project statistics and health checks",admin:"Platform administration",community:"Community health and showcase",growth:"Growth analytics and insights",ecosystem:"Template marketplace, ideas, showcase, and ecosystem sync",services:"Microservice management",search:"Search index 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"},Ua=["--help","--version","--21st","--v0","--stdio","--format","--yes","--no-interactive","--no-color","--verbose","--quiet","--dry-run","--if-not-exists","--provider","-p","--pm","--region","--orm","--db","--auth","--social-login","--payment","--ai","--deploy","--docs","--email","--storage","--monitoring","--analytics","--sms","--queue","--search","--cache","--notifications","--webhooks","--cms","--feature-flags","--captcha","--mcp","--metering","--billing-mode","--idp","--i18n","--no-i18n","--no-install","--no-git","--json"],zt=["-p","--pm","--region","--orm","--db","--auth","--social-login","--payment","--ai","--deploy","--docs","--email","--storage","--monitoring","--analytics","--sms","--queue","--search","--cache","--notifications","--webhooks","--cms","--feature-flags","--captcha","--mcp","--metering","--billing-mode","--idp","--i18n","--no-i18n","--no-install","--no-git","--dry-run","--json","--yes"],ja={"-p":b.pm,"--pm":b.pm,"--region":b.region,"--orm":b.orm,"--db":b.db,"--auth":b.auth,"--payment":b.payment,"--deploy":b.deploy,"--docs":b.docs,"--email":b.email,"--storage":b.storage,"--monitoring":b.monitoring,"--analytics":b.analytics,"--sms":b.sms,"--queue":b.queue,"--search":b.search,"--cache":b.cache,"--notifications":b.notifications,"--webhooks":b.webhooks,"--cms":b.cms,"--feature-flags":b.featureFlags,"--captcha":b.captcha,"--mcp":b.mcp,"--metering":b.metering,"--billing-mode":b.billingMode,"--idp":b.idp},La=Object.entries(ja).map(([e,t])=>` ${e})
|
|
228
|
-
COMPREPLY=( $(compgen -W "${t.join(" ")}" -- \${cur}) )
|
|
229
|
-
return 0
|
|
230
|
-
;;`).join(`
|
|
231
|
-
`),Da=zt.map(e=>` "${e}"`).join(`
|
|
232
|
-
`),Fa=vt.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${nr[e]}"`).join(`
|
|
233
|
-
`),Ba=zt.map(e=>`complete -c nebutra -n "__fish_seen_subcommand_from create" -f -a "${e}" -d "create-sailor option"`).join(`
|
|
234
|
-
`);function rr(){return`#!/usr/bin/env bash
|
|
2
|
+
import{b as l}from"./chunk-JDX5NXDX.js";import{a as b,b as k,c as P,d as Q,e as fe,f as J}from"./chunk-LGUMYJ4Q.js";import{realpathSync as or}from"fs";import{resolve as ar}from"path";import{fileURLToPath as ir}from"url";import{Command as Bi}from"commander";import{existsSync as cr,readFileSync as lr,writeFileSync as ur}from"fs";import{resolve as Xe}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},kt={[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 dr=["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"],At="nebutra.config.json",mr=dr,Ot={"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 M(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 pr(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function fr(e){return Ot[e]?Ot[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function Ne(){return Object.fromEntries(mr.map(e=>[e,{id:e,name:pr(e),envVars:fr(e)}]))}function Y(){return Xe(process.cwd(),At)}function ce(){let e=Y();if(!cr(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(lr(e,"utf-8"))}catch(t){l.error(`Failed to parse ${At}: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}function Pe(e){ur(Y(),`${JSON.stringify(e,null,2)}
|
|
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 Tt(){return`#!/usr/bin/env bash
|
|
235
5
|
|
|
236
6
|
_nebutra_completions() {
|
|
237
7
|
local cur prev opts cmd
|
|
@@ -240,14 +10,10 @@ _nebutra_completions() {
|
|
|
240
10
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
241
11
|
|
|
242
12
|
# Subcommands
|
|
243
|
-
local subcommands="${
|
|
13
|
+
local subcommands="${$e.join(" ")}"
|
|
244
14
|
|
|
245
15
|
# Flags
|
|
246
|
-
local flags="${
|
|
247
|
-
|
|
248
|
-
case "\${prev}" in
|
|
249
|
-
${La}
|
|
250
|
-
esac
|
|
16
|
+
local flags="${Lr.join(" ")}"
|
|
251
17
|
|
|
252
18
|
if [[ \${cur} == -* ]]; then
|
|
253
19
|
# Complete flags
|
|
@@ -255,12 +21,6 @@ ${La}
|
|
|
255
21
|
elif [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
256
22
|
# Complete subcommands at position 1
|
|
257
23
|
COMPREPLY=( $(compgen -W "\${subcommands}" -- \${cur}) )
|
|
258
|
-
elif [[ "\${prev}" == "add" ]]; then
|
|
259
|
-
# add command takes component names
|
|
260
|
-
COMPREPLY=( $(compgen -W "--21st --v0 --provider --dry-run --yes --if-not-exists" -- \${cur}) )
|
|
261
|
-
elif [[ "\${prev}" == "create" ]]; then
|
|
262
|
-
# create delegates to create-sailor
|
|
263
|
-
COMPREPLY=( $(compgen -W "${zt.join(" ")}" -- \${cur}) )
|
|
264
24
|
elif [[ "\${prev}" == "completions" ]]; then
|
|
265
25
|
# completions command takes shell type
|
|
266
26
|
COMPREPLY=( $(compgen -W "bash zsh fish install" -- \${cur}) )
|
|
@@ -270,11 +30,11 @@ ${La}
|
|
|
270
30
|
}
|
|
271
31
|
|
|
272
32
|
complete -o bashdefault -o default -o nospace -F _nebutra_completions nebutra
|
|
273
|
-
`}function
|
|
33
|
+
`}function Dt(){return`#compdef nebutra
|
|
274
34
|
|
|
275
35
|
_nebutra() {
|
|
276
36
|
local -a commands=(
|
|
277
|
-
${
|
|
37
|
+
${$e.map(e=>`"${e}:${jt[e]}"`).join(`
|
|
278
38
|
`)}
|
|
279
39
|
)
|
|
280
40
|
|
|
@@ -283,15 +43,8 @@ _nebutra() {
|
|
|
283
43
|
"--version[Show version]"
|
|
284
44
|
)
|
|
285
45
|
|
|
286
|
-
local -a
|
|
287
|
-
"--
|
|
288
|
-
"--v0[Fetch and install a component from v0.dev]:URL"
|
|
289
|
-
"--provider[Specify a backend provider for a local feature]:provider"
|
|
290
|
-
"--dry-run[Preview local feature install plan]"
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
local -a create_flags=(
|
|
294
|
-
${Da}
|
|
46
|
+
local -a status_flags=(
|
|
47
|
+
"--json[Emit machine-readable JSON]"
|
|
295
48
|
)
|
|
296
49
|
|
|
297
50
|
local -a mcp_flags=(
|
|
@@ -309,12 +62,6 @@ ${Da}
|
|
|
309
62
|
_describe "command" commands
|
|
310
63
|
else
|
|
311
64
|
case "\${words[2]}" in
|
|
312
|
-
add)
|
|
313
|
-
_arguments "*:component:($global_flags $add_flags)"
|
|
314
|
-
;;
|
|
315
|
-
create)
|
|
316
|
-
_arguments "*:options:($global_flags $create_flags)"
|
|
317
|
-
;;
|
|
318
65
|
completions)
|
|
319
66
|
_values "shell type" bash zsh fish install
|
|
320
67
|
;;
|
|
@@ -324,6 +71,9 @@ ${Da}
|
|
|
324
71
|
schema)
|
|
325
72
|
_arguments "*:options:($global_flags $schema_flags)"
|
|
326
73
|
;;
|
|
74
|
+
status)
|
|
75
|
+
_arguments "*:options:($global_flags $status_flags)"
|
|
76
|
+
;;
|
|
327
77
|
*)
|
|
328
78
|
_arguments "*:options:($global_flags)"
|
|
329
79
|
;;
|
|
@@ -332,24 +82,19 @@ ${Da}
|
|
|
332
82
|
}
|
|
333
83
|
|
|
334
84
|
_nebutra
|
|
335
|
-
`}function
|
|
85
|
+
`}function Lt(){return`# Fish shell completions for nebutra
|
|
336
86
|
|
|
337
|
-
complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${
|
|
87
|
+
complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${$e.join(" ")}" -d "Nebutra governance CLI"
|
|
338
88
|
|
|
339
89
|
# Subcommands
|
|
340
|
-
${
|
|
90
|
+
${Fr}
|
|
341
91
|
|
|
342
92
|
# Flags
|
|
343
93
|
complete -c nebutra -f -a "--help" -d "Show help message"
|
|
344
94
|
complete -c nebutra -f -a "--version" -d "Show version"
|
|
345
95
|
|
|
346
|
-
#
|
|
347
|
-
complete -c nebutra -n "__fish_seen_subcommand_from
|
|
348
|
-
complete -c nebutra -n "__fish_seen_subcommand_from add" -f -a "--v0" -d "Fetch and install a component from v0.dev"
|
|
349
|
-
complete -c nebutra -n "__fish_seen_subcommand_from add" -f -a "--provider" -d "Specify a backend provider"
|
|
350
|
-
|
|
351
|
-
# create command flags
|
|
352
|
-
${Ba}
|
|
96
|
+
# status command flags
|
|
97
|
+
complete -c nebutra -n "__fish_seen_subcommand_from status" -f -a "--json" -d "Emit machine-readable JSON"
|
|
353
98
|
|
|
354
99
|
# mcp command flags
|
|
355
100
|
complete -c nebutra -n "__fish_seen_subcommand_from mcp" -f -a "--stdio" -d "Use stdio transport (default)"
|
|
@@ -364,16 +109,24 @@ complete -c nebutra -n "__fish_seen_subcommand_from completions" -f -a "install"
|
|
|
364
109
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--all" -d "Show full schema for all commands"
|
|
365
110
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--list" -d "List all available command names"
|
|
366
111
|
complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--exit-codes" -d "Show exit codes reference"
|
|
367
|
-
`}function
|
|
112
|
+
`}function Ft(e){let n={bash:Tt,zsh:Dt,fish:Lt}[e.toLowerCase()];n||(console.error($.red(`Error: Unknown shell '${e}'. Supported: bash, zsh, fish`)),process.exit(c.INVALID_ARGS)),console.log(n())}async function Ur(){let t=(process.env.SHELL||"/bin/bash").split("/").pop()||"bash";j.intro($.bgCyan($.black(" nebutra completions install ")));let n=j.spinner();n.start($.cyan(`Detecting shell: ${t}...`));try{let r=null,o=null,a=null;if(t==="bash"?(r=ge(Ce(),".bashrc"),o=ge(Ce(),".bash_completion.d"),a="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=ge(Ce(),".zshrc"),o=ge(Ce(),".zsh/completions"),a="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=ge(Ce(),".config/fish/completions"),a="# Completions installed to ~/.config/fish/completions/nebutra.fish"):(n.stop(),j.log.warn($.yellow(`Warning: Unsupported shell '${t}'. Please install completions manually.`)),Ft("bash"),j.outro($.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=ge(o,t==="fish"?"nebutra.fish":"nebutra"),d=t==="bash"?Tt():t==="zsh"?Dt():Lt();Dr(s,d),n.stop($.green(`Completion script installed to ${s}`))}r&&a&&t!=="fish"&&(!jr(r)||!Tr(r,"utf8").includes("nebutra"))&&($r(r,(t==="bash"?`
|
|
368
113
|
# nebutra completions
|
|
369
114
|
[[ -f ~/.bash_completion.d/nebutra ]] && source ~/.bash_completion.d/nebutra`:`
|
|
370
115
|
# nebutra completions
|
|
371
116
|
fpath=(~/.zsh/completions $fpath)
|
|
372
117
|
autoload -Uz compinit && compinit`)+`
|
|
373
|
-
`),
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
`)}
|
|
118
|
+
`),j.log.info($.green(`Added nebutra completions to ${r}`))),j.log.info($.cyan("Completions installed! Restart your shell or run:")),j.log.info($.dim(` source "${t==="bash"?"~/.bashrc":"~/.zshrc"}"`)),j.outro($.green("Installation complete!"))}catch(r){n.stop(),j.log.error($.red("Error installing completions. You can manually add them by running:")),j.log.info($.cyan(` nebutra completions ${t} >> ~/.${t}rc`)),r instanceof Error&&console.error($.dim(r.message)),process.exit(c.ERROR)}}function Ut(e){e.command("completions [shell]").description("Generate or install shell completions").action(async t=>{!t||t==="install"?await Ur():Ft(t)})}import*as Te from"@clack/prompts";import{stderr as te,stdout as Bt}from"process";import q from"picocolors";function Br(){return process.env.NEBUTRA_NON_TTY||process.env.CI||process.env.GITHUB_ACTIONS?!1:process.stderr.isTTY===!0}function Gt(e){if(e)return e;let t=process.env.NEBUTRA_OUTPUT_FORMAT;return t&&["json","table","plain"].includes(t)?t:Br()?"plain":"json"}function Gr(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(" | "),a=n.map(s=>"-".repeat(r[String(s)])).join("-+-"),i=[o,a];for(let s of e){let d=n.map(m=>String(s[m]??"").padEnd(r[String(m)])).join(" | ");i.push(d)}return i.join(`
|
|
119
|
+
`)}function Mr(e){return JSON.stringify(e)}function Mt(e){if(!Array.isArray(e))return Qe(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return Qe(e);let t=Gr(e);return q.gray(t)}function Qe(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 h(e,t){let n=Gt(t?.format),r=t?.stream==="stderr"?te:Bt,o;switch(n){case"json":o=Mr(e);break;case"table":o=Mt(e);break;default:o=Qe(e);break}r.write(o+`
|
|
120
|
+
`)}function T(e,t={}){let n=Gt(t.format),r;switch(n){case"json":r=JSON.stringify(e);break;case"table":r=Mt(e);break;default:r=JSON.stringify(e,null,2);break}Bt.write(r+`
|
|
121
|
+
`)}function u(e,t="info"){let n;switch(t){case"error":n=q.red("\u2716");break;case"warn":n=q.yellow("\u26A0");break;case"success":n=q.green("\u2713");break;default:n=q.blue("\u2139");break}let r=`${n} ${e}`;te.write(r+`
|
|
122
|
+
`)}function C(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=q.dim(`[debug] ${e}`);te.write(r+`
|
|
123
|
+
`),t&&Object.keys(t).length>0&&te.write(q.dim(JSON.stringify(t,null,2))+`
|
|
124
|
+
`)}function je(e){te.write(`
|
|
125
|
+
`),te.write(q.bold(q.cyan(e))+`
|
|
126
|
+
`),te.write(q.gray("-".repeat(e.length))+`
|
|
127
|
+
`),te.write(`
|
|
128
|
+
`)}async function Vr(e){u("Generating Prisma client"+"...","info");let n=await J("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 et(e,t){let n=t||{};if(e){u(`Creating migration: ${e}`,"info");let r=await J("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 J("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 Kr(e){u("Pushing schema to database...","info");let t=await J("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 zr(e){u("Seeding database...","info");let t=await J("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 Yr(e){u("Launching Prisma Studio...","info");let t=await J("studio",{dryRun:e.dryRun,interactive:!0});t.exitCode!==0&&(u("Failed to launch Prisma Studio","error"),process.exit(t.exitCode||1))}async function Wr(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await Te.confirm({message:"Reset database? This will delete all data.",initialValue:!1});(Te.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 J("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 qr(e){u("Checking migration status...","info");let t=await J("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)+`
|
|
129
|
+
`)}catch{process.stdout.write(t.stdout)}}else u("Failed to check migration status","error"),process.exit(t.exitCode||1)}function Vt(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 a=o.optsWithGlobals?.(),i={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:o.format||a?.format};try{switch(n){case"generate":await Vr(i);break;case"migrate":r.length>0?r[0]==="create"&&r[1]?await et(r[1],i):await et(r[0],i):await et(void 0,i);break;case"push":await Kr(i);break;case"seed":await zr(i);break;case"studio":await Yr(i);break;case"reset":await Wr(i);break;case"status":await qr(i);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"),C("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
377
130
|
Examples:
|
|
378
131
|
nebutra db generate Generate Prisma client
|
|
379
132
|
nebutra db migrate Run all pending migrations
|
|
@@ -388,53 +141,15 @@ Flags:
|
|
|
388
141
|
--dry-run Show what would be run without executing
|
|
389
142
|
--yes Skip confirmations
|
|
390
143
|
--format <type> Output format: json, plain (default: plain)
|
|
391
|
-
`)}import*as
|
|
392
|
-
${n}`)}return t}async function
|
|
144
|
+
`)}import*as w from"@clack/prompts";import y from"picocolors";function O(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 ne(e){if(e==="json"||e==="plain"||e==="table")return e}var ye=["landing","web","storybook","design-docs","idp","mail-preview","gateway","admin","auth","design","forge","router","pebble","typelens","sailor-docs","studio","sleptons"];function De(e){let t=`@nebutra/${e}`;if(!ye.includes(e)){let n=y.yellow(`Valid apps: ${ye.join(", ")}`);throw new Error(`Invalid app: ${y.red(e)}
|
|
145
|
+
${n}`)}return t}async function Hr(e){e.dryRun&&(T({mode:"dry-run",timestamp:new Date().toISOString(),command:"dev",options:{app:e.app},task:e.app?"turbo dev":"turbo dev (all apps)"},{format:ne(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app){De(e.app);let n=`@nebutra/${e.app}`;e.quiet||w.log.info(y.cyan(`Starting dev server for ${y.bold(n)}...`));let r=await Q("dev",{filter:n});process.exit(r.exitCode)}e.quiet||w.log.info(y.cyan("Starting dev servers for all apps..."));let t=await Q("dev");process.exit(t.exitCode)}catch(t){t instanceof Error?w.log.error(y.red(t.message)):w.log.error(y.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Jr(e){e.dryRun&&(T({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:ne(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.strict&&(w.log.error(y.red("Cannot use --strict with --app filter")),process.exit(c.INVALID_ARGS)),e.app){De(e.app);let r=`@nebutra/${e.app}`;e.quiet||w.log.info(y.cyan(`Building ${y.bold(r)}...`));let o=await Q("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...";w.log.info(y.cyan(r))}let n=await P(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?w.log.error(y.red(t.message)):w.log.error(y.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Zr(e){e.dryRun&&(T({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:ne(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.fix&&(w.log.error(y.red("Cannot use --fix with --app filter (lint:fix is global only)")),process.exit(c.INVALID_ARGS)),e.app){De(e.app);let r=`@nebutra/${e.app}`;e.quiet||w.log.info(y.cyan(`Linting ${y.bold(r)}...`));let o=await k({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...";w.log.info(y.cyan(r))}let n=await P(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?w.log.error(y.red(t.message)):w.log.error(y.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Xr(e){e.dryRun&&(T({mode:"dry-run",timestamp:new Date().toISOString(),command:"typecheck",options:{app:e.app},task:"turbo typecheck"},{format:ne(e.format)}),process.exit(c.DRY_RUN_OK));try{if(e.app){De(e.app);let n=`@nebutra/${e.app}`;e.quiet||w.log.info(y.cyan(`Type-checking ${y.bold(n)}...`));let r=await Q("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||w.log.info(y.cyan("Type-checking all packages..."));let t=await Q("typecheck");process.exit(t.exitCode)}catch(t){t instanceof Error?w.log.error(y.red(t.message)):w.log.error(y.red("Unknown error occurred")),process.exit(c.ERROR)}}var Kt=e=>{e.command("dev").description("Start development servers (turbo dev)").option("--app <name>",`App to run: ${ye.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=O(t,n);await Hr({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ne(r.format)})}),e.command("build").description("Build all apps (pnpm build or turbo build)").option("--app <name>",`App to build: ${ye.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=O(t,n);await Jr({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,strict:!!t.strict,quiet:!!r.quiet,verbose:!!r.verbose,format:ne(r.format)})}),e.command("lint").description("Lint with Biome (pnpm lint or pnpm lint:fix)").option("--app <name>",`App to lint: ${ye.join(", ")}`).option("--fix","Fix linting issues automatically").option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=O(t,n);await Zr({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,fix:!!t.fix,quiet:!!r.quiet,verbose:!!r.verbose,format:ne(r.format)})}),e.command("typecheck").description("Type-check with TypeScript (turbo typecheck)").option("--app <name>",`App to typecheck: ${ye.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(t,n)=>{let r=O(t,n);await Xr({app:typeof t.app=="string"?t.app:void 0,dryRun:!!t.dryRun,quiet:!!r.quiet,verbose:!!r.verbose,format:ne(r.format)})})};import zt from"fs";import Yt from"path";import tt from"picocolors";var nt=["smoke","golden","sleptons"],Qr={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 eo(e,t={}){nt.includes(e)||(l.error(`Invalid suite: ${tt.red(e)}. Valid: ${nt.join(", ")}`),process.exit(c.INVALID_ARGS));let n=b(),{config:r,suiteDir:o}=Qr[e],a=Yt.join(n,r),i=Yt.join(n,o);(!zt.existsSync(i)||!zt.existsSync(a))&&(l.error(`Suite ${tt.red(e)} not found at ${o}.
|
|
393
146
|
Expected config: ${r}
|
|
394
147
|
Remediation: scaffold the suite (analogous to 'nebutra workflow init <provider>')
|
|
395
|
-
or restore the directory from git.`),process.exit(c.NOT_FOUND)),t.dryRun&&(
|
|
396
|
-
`))
|
|
397
|
-
`));let t=e.
|
|
398
|
-
`)
|
|
399
|
-
`),s.
|
|
400
|
-
`),s.info(`Next steps: Run ${g.yellow("nebutra ecosystem publish")} to share your project`),c.SUCCESS)}catch(r){return s.error(`Connection failed: ${r}`),c.ERROR}}async function di(e){s.info(g.cyan(`\u{1F4E4} Publish to Ecosystem Marketplace
|
|
401
|
-
`));let t=e.tag||"latest",n=e.visibility||"public",r=ii();s.info(`${g.bold("Pre-Publish Checklist")}
|
|
402
|
-
`);for(let o of r.checks){let a=o.pass?g.green("\u2713"):g.red("\u2717")}if(!r.valid)return s.error(`
|
|
403
|
-
Fix the checks above before publishing`),c.ERROR;if(n==="public"&&!e.yes&&(s.info(`This project will be ${g.yellow("publicly listed")} in the ecosystem`),s.info(`Continue? Run with ${g.yellow("--yes")} to skip confirmation`),!e.yes))return c.CANCELLED;try{let a=await(await P("/projects/publish",{method:"POST",body:{projectName:"My Template",description:"A production-ready SaaS template",repository:"https://github.com/user/project",tags:["saas","nextjs","ai"],tag:t,visibility:n},dryRun:e.dryRun})).json();return e.dryRun?(d("[DRY RUN] Would publish to ecosystem","success"),c.SUCCESS):(s.success(`\u2713 Published successfully!
|
|
404
|
-
`),s.info(`Marketplace URL: ${g.blue(`https://nebutra.com/templates/${a.projectId}`)}`),s.info(`Visibility: ${n}`),s.info(`Tag: ${t}
|
|
405
|
-
`),c.SUCCESS)}catch(o){return s.error(`Publish failed: ${o}`),c.ERROR}}async function ui(e){s.info(g.cyan(`\u{1F4DA} Template Marketplace
|
|
406
|
-
`));try{let n=await(await P(`/templates?category=${e.category||""}&sort=${e.sort||"downloads"}`)).json();return e.format==="json"||s.info(`Run ${g.yellow("nebutra ecosystem templates info <id>")} for details`),c.SUCCESS}catch(t){return s.error(`Failed to list templates: ${t}`),c.ERROR}}async function mi(e,t){s.info(g.cyan(`\u{1F50D} Searching templates for "${e}"
|
|
407
|
-
`));try{let r=await(await P(`/templates/search?q=${encodeURIComponent(e)}`)).json();return t.format,c.SUCCESS}catch(n){return s.error(`Search failed: ${n}`),c.ERROR}}async function pi(e){s.info(g.cyan(`\u{1F4D6} Template Details
|
|
408
|
-
`));try{let n=await(await P(`/templates/${e}`)).json();return s.info(`Install: ${g.yellow("nebutra ecosystem templates install multi-tenant-saas")}`),c.SUCCESS}catch(t){return s.error(`Failed to fetch template info: ${t}`),c.ERROR}}async function fi(e,t){s.info(g.cyan(`\u2B07\uFE0F Installing template "${e}"
|
|
409
|
-
`));try{let n=await P(`/templates/${e}/install`,{method:"POST",body:{projectName:"my-saas"},dryRun:t.dryRun});return t.dryRun?(d("[DRY RUN] Would install template","success"),c.SUCCESS):(s.success(`\u2713 Template installed!
|
|
410
|
-
`),s.info("Project: ./my-saas"),s.info(`Next: ${g.yellow("cd my-saas && pnpm install && pnpm dev")}`),c.SUCCESS)}catch(n){return s.error(`Installation failed: ${n}`),c.ERROR}}async function gi(e){s.info(g.cyan(`\u{1F4A1} Ideas Marketplace
|
|
411
|
-
`));try{let n=await(await P(`/ideas?status=${e.status||""}&sort=${e.sort||"recent"}`)).json();return e.format==="json"||(s.info(`Vote: ${g.yellow("nebutra ecosystem ideas vote <id>")}`),s.info(`Claim: ${g.yellow("nebutra ecosystem ideas claim <id>")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list ideas: ${t}`),c.ERROR}}async function yi(e){if(s.info(g.cyan(`\u2728 Submit New Idea
|
|
412
|
-
`)),!e.title||!e.description)return s.error("Missing required fields: --title and --description"),c.INVALID_ARGS;try{let n=await(await P("/ideas",{method:"POST",body:{title:e.title,description:e.description,tags:e.tags?.split(",")||[],authorId:"user_current"},dryRun:e.dryRun})).json();return e.dryRun?(d("[DRY RUN] Would submit idea","success"),c.SUCCESS):(s.success(`\u2713 Idea submitted!
|
|
413
|
-
`),s.info(`Idea URL: ${g.blue(`https://nebutra.com/ideas/${n.ideaId}`)}`),s.info(`Start voting and discussing! Community will help shape it.
|
|
414
|
-
`),c.SUCCESS)}catch(t){return s.error(`Submission failed: ${t}`),c.ERROR}}async function hi(e,t){s.info(g.cyan(`\u{1F44D} Voting on idea "${e}"
|
|
415
|
-
`));try{let n=await P(`/ideas/${e}/vote`,{method:"POST",body:{action:"upvote"},dryRun:t.dryRun});return t.dryRun?(d("[DRY RUN] Would upvote idea","success"),c.SUCCESS):(s.success(`\u2713 Vote recorded! This idea now has more momentum.
|
|
416
|
-
`),c.SUCCESS)}catch(n){return s.error(`Vote failed: ${n}`),c.ERROR}}async function bi(e,t){s.info(g.cyan(`\u{1F3AF} Claiming idea "${e}"
|
|
417
|
-
`));try{let n=await P(`/ideas/${e}/claim`,{method:"POST",body:{claimerId:"user_current",status:"in-progress"},dryRun:t.dryRun});return t.dryRun?(d("[DRY RUN] Would claim idea","success"),c.SUCCESS):(s.success(`\u2713 Idea claimed! You're now working on this.
|
|
418
|
-
`),s.info("Post updates in the comments to keep the community informed."),c.SUCCESS)}catch(n){return s.error(`Claim failed: ${n}`),c.ERROR}}async function vi(e,t){if(s.info(g.cyan(`\u{1F4AC} Adding comment to idea "${e}"
|
|
419
|
-
`)),!t.message)return s.error("Missing --message parameter"),c.INVALID_ARGS;try{let n=await P(`/ideas/${e}/comments`,{method:"POST",body:{authorId:"user_current",message:t.message},dryRun:t.dryRun});return t.dryRun?(d("[DRY RUN] Would post comment","success"),c.SUCCESS):(s.success(`\u2713 Comment posted!
|
|
420
|
-
`),c.SUCCESS)}catch(n){return s.error(`Comment failed: ${n}`),c.ERROR}}async function wi(e){s.info(g.cyan(`\u{1F465} Legacy Member Directory
|
|
421
|
-
`));try{let n=await(await P(`/opc?skill=${e.skill||""}&industry=${e.industry||""}&sort=${e.sort||"active"}`)).json();return e.format==="json"||(s.info(`View profile: ${g.yellow("nebutra ecosystem opc profile <handle>")}`),s.info(`Register: ${g.yellow("nebutra ecosystem opc register")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list members: ${t}`),c.ERROR}}async function Ri(){s.info(g.cyan(`\u{1F464} Legacy Member Profile
|
|
422
|
-
`));try{let t=await(await P("/opc/me")).json();return s.info(`Edit profile: ${g.yellow("nebutra ecosystem opc register")}`),c.SUCCESS}catch(e){return s.error(`Failed to load profile: ${e}`),c.ERROR}}async function Si(e){s.info(g.cyan(`\u{1F4DD} Register Legacy Member Profile
|
|
423
|
-
`));let t={name:"Your Name",handle:"your-handle",bio:"Building amazing products",skills:["nextjs","ai","devtools"],industry:"startup"};if(e.dryRun)return s.info(`[DRY RUN] Would register profile:
|
|
424
|
-
`),c.SUCCESS;if(!e.yes)return s.info("This will create your public legacy member profile."),s.info(`Run with ${g.yellow("--yes")} to confirm`),c.CANCELLED;try{let n=await P("/opc/register",{method:"POST",body:t});return s.success(`\u2713 Legacy member profile created!
|
|
425
|
-
`),s.info(`View at: ${g.blue("https://nebutra.com/members/your-handle")}`),s.info(`Compatibility command: ${g.yellow("nebutra ecosystem opc profile --share")}`),c.SUCCESS}catch(n){return s.error(`Registration failed: ${n}`),c.ERROR}}async function Ci(e){s.info(g.cyan(`\u2B50 Project Showcase
|
|
426
|
-
`));try{let n=await(await P(`/showcase?category=${e.category||""}&featured=${e.featured?"true":""}`)).json();return e.format==="json"||(s.info(`Vote: ${g.yellow("nebutra ecosystem showcase vote <id>")}`),s.info(`Submit yours: ${g.yellow("nebutra ecosystem showcase submit")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list showcase: ${t}`),c.ERROR}}async function Ei(e){s.info(g.cyan(`\u{1F389} Submit Project to Showcase
|
|
427
|
-
`));let t={projectName:"My Awesome Project",url:"https://example.com",description:"A production product built with Nebutra",monthlyVisitors:1e4,builtWith:["nextjs","tailwind","prisma"]};if(!e.yes)return s.info("This will add your project to the public showcase."),s.info(`Run with ${g.yellow("--yes")} to confirm`),c.CANCELLED;try{let n=await P("/showcase/submit",{method:"POST",body:t,dryRun:e.dryRun});return e.dryRun?(d("[DRY RUN] Would submit to showcase","success"),c.SUCCESS):(s.success(`\u2713 Project added to showcase!
|
|
428
|
-
`),s.info(`View at: ${g.blue("https://nebutra.com/showcase/my-project")}`),s.info("Community can now discover your work!"),c.SUCCESS)}catch(n){return s.error(`Submission failed: ${n}`),c.ERROR}}async function ki(e,t){s.info(g.cyan(`\u{1F44D} Voting on showcase project "${e}"
|
|
429
|
-
`));try{let n=await P(`/showcase/${e}/vote`,{method:"POST",body:{action:"upvote"},dryRun:t.dryRun});return t.dryRun?(d("[DRY RUN] Would upvote project","success"),c.SUCCESS):(s.success(`\u2713 Vote recorded! You're supporting this project.
|
|
430
|
-
`),c.SUCCESS)}catch(n){return s.error(`Vote failed: ${n}`),c.ERROR}}async function xi(e){s.info(g.cyan(`\u{1F504} Sync with Ecosystem
|
|
431
|
-
`));let t=!e.push,n=e.push?"push":"pull";try{let r=await P("/sync",{method:"POST",body:{direction:n,timestamp:new Date().toISOString()},dryRun:e.dryRun});return e.dryRun?(s.info(g.green(`\u2713 [DRY RUN] Would sync (${n})
|
|
432
|
-
`)),c.SUCCESS):(s.success(`\u2713 Synced!
|
|
433
|
-
`),t?s.info("Downloaded: ecosystem config, stats, badges"):s.info("Uploaded: project updates, metrics"),c.SUCCESS)}catch(r){return s.error(`Sync failed: ${r}`),c.ERROR}}function gr(e){let t=e.command("ecosystem").description("Nebutra ecosystem marketplace, ideas, showcase, and sync workflows");t.command("status").description("Ecosystem overview dashboard").option("--format <format>","Output format: json","text").action(async i=>{await ci(i)}),t.command("connect").description("Connect local project to Nebutra ecosystem").option("--token <token>","Ecosystem API token").option("--org <orgId>","Organization ID").option("--dry-run","Preview without making changes").option("--yes","Skip confirmations").action(async i=>{await li(i)}),t.command("publish").description("Publish project/template to ecosystem marketplace").option("--tag <tag>","Release tag: latest|beta|canary","latest").option("--visibility <visibility>","Project visibility: public|private|unlisted","public").option("--dry-run","Preview without making changes").option("--yes","Skip confirmations").action(async i=>{await di(i)});let n=t.command("templates").description("Template marketplace");n.command("list").description("Browse available templates").option("--category <category>","Filter by category").option("--sort <sort>","Sort by: stars|downloads|recent","downloads").option("--format <format>","Output format","text").action(async i=>{await ui(i)}),n.command("search <query>").description("Search templates").option("--format <format>","Output format","text").action(async(i,l)=>{await mi(i,l)}),n.command("info <id>").description("Template details").action(async i=>{await pi(i)}),n.command("install <id>").description("Install/fork a template").option("--dry-run","Preview without making changes").action(async(i,l)=>{await fi(i,l)});let r=t.command("ideas").description("Ideas marketplace");r.command("list").description("Browse ideas").option("--status <status>","Filter by status").option("--sort <sort>","Sort by: votes|recent|trending","recent").option("--format <format>","Output format","text").action(async i=>{await gi(i)}),r.command("submit").description("Submit new idea").option("--title <title>","Idea title").option("--description <description>","Idea description").option("--tags <tags>","Comma-separated tags").option("--dry-run","Preview without making changes").action(async i=>{await yi(i)}),r.command("vote <id>").description("Upvote an idea").option("--dry-run","Preview without making changes").action(async(i,l)=>{await hi(i,l)}),r.command("claim <id>").description("Claim an idea to work on").option("--dry-run","Preview without making changes").action(async(i,l)=>{await bi(i,l)}),r.command("comment <id>").description("Comment on an idea").option("--message <message>","Comment text").option("--dry-run","Preview without making changes").action(async(i,l)=>{await vi(i,l)});let o=t.command("opc",{hidden:!0}).description("Legacy member directory");o.command("list").description("Browse legacy member profiles").option("--skill <skill>","Filter by skill tag").option("--industry <industry>","Filter by industry").option("--sort <sort>","Sort by: active|joined","active").option("--format <format>","Output format","text").action(async i=>{await wi(i)}),o.command("profile").description("View/edit your legacy member profile").action(async()=>{await Ri()}),o.command("register").description("Register a legacy member profile").option("--yes","Skip confirmations").option("--dry-run","Preview without making changes").action(async i=>{await Si(i)});let a=t.command("showcase").description("Project showcase");a.command("list").description("Browse showcased projects").option("--category <category>","Filter by category").option("--featured","Show featured only").option("--format <format>","Output format","text").action(async i=>{await Ci(i)}),a.command("submit").description("Submit your project to showcase").option("--yes","Skip confirmations").option("--dry-run","Preview without making changes").action(async i=>{await Ei(i)}),a.command("vote <id>").description("Upvote a project (Product Hunt style)").option("--dry-run","Preview without making changes").action(async(i,l)=>{await ki(i,l)}),t.command("sync").description("Sync local project with ecosystem").option("--pull","Pull remote changes").option("--push","Push local changes").option("--dry-run","Preview without making changes").action(async i=>{await xi(i)})}import{existsSync as St,readFileSync as yr,writeFileSync as Oi}from"fs";import{resolve as Ct}from"path";import*as Ne from"@clack/prompts";import Ai from"picocolors";function Et(e){let t=Ct(e,".env.example");if(!St(t))throw new Error(`.env.example not found at ${t}`);let n=yr(t,"utf-8"),r={};for(let o of n.split(`
|
|
434
|
-
`)){if(o.trim().startsWith("#")||!o.trim())continue;let a=o.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(a){let[,i,l]=a;r[i]=l.replace(/^["'](.*)["']$/,"$1")}}return r}function Jt(e){let t=Ct(e,".env.local"),n=Ct(e,".env"),r=St(t)?t:n;if(!St(r))return{};let o=yr(r,"utf-8"),a={};for(let i of o.split(`
|
|
435
|
-
`)){if(i.trim().startsWith("#")||!i.trim())continue;let l=i.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(l){let[,u,m]=l;a[u]=m.replace(/^["'](.*)["']$/,"$1")}}return a}function _i(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function Pi(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 Ii(e){d("Validating environment variables...","info");let t=h(),n=Et(t),r=Jt(t),o=process.env,a={},i=!0;for(let l of Object.keys(n)){let u=l in r||l in o;a[l]=u,u||(i=!1)}if(e.format==="json")S({valid:i,checked:Object.keys(n).length,missing:Object.entries(a).filter(([,l])=>!l).map(([l])=>l)},{format:"json"});else{ft("Environment Validation");let l=Object.entries(a).filter(([,u])=>!u).map(([u])=>u);if(l.length===0)d("All required environment variables are set","success");else{d(`${l.length} missing environment variable(s):`,"warn");for(let u of l)d(` - ${u}`,"warn")}}i||process.exit(c.CONFIG_ERROR)}async function Ni(e){let t=h(),n=Et(t),r=Ct(t,".env.local");if(St(r)&&!e.yes&&!e.dryRun){let u=await Ne.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(Ne.isCancel(u)||!u)&&(d("Template generation cancelled","warn"),process.exit(c.CANCELLED))}d("Generating .env.local from template...","info");let o={},a=0,i=Object.keys(n).length;for(let[u,m]of Object.entries(n))if(a++,e.yes)o[u]=m;else if(process.stdin.isTTY===!0){let f=`[${a}/${i}] ${u}`,y=await Ne.text({message:f,defaultValue:m});Ne.isCancel(y)&&(d("Template generation cancelled","warn"),process.exit(c.CANCELLED)),o[u]=y}else o[u]=m;let l=Object.entries(o).map(([u,m])=>{let y=/[\s=]/.test(m)?`"${m}"`:m;return`${u}=${y}`}).join(`
|
|
436
|
-
`);e.dryRun?(d("Dry-run: would write .env.local","info"),S(l,{format:"plain"})):(Oi(r,l+`
|
|
437
|
-
`),d(`Environment template written to ${r}`,"success"))}async function $i(e){d("Comparing environment variables...","info");let t=h(),n=Et(t),r=Jt(t),o=[],a=[],i=[];for(let l of Object.keys(n))l in r?i.push(l):o.push(l);for(let l of Object.keys(r))l in n||a.push(l);if(e.format==="json")S({matching:i.length,missing:o.length,extra:a.length,missing_vars:o,extra_vars:a},{format:"json"});else{if(ft("Environment Diff"),i.length>0&&d(`Matching (${i.length}): ${i.join(", ")}`,"success"),o.length>0){d(`Missing (${o.length}):`,"warn");for(let l of o)d(` - ${l}`,"warn")}if(a.length>0){d(`Extra (${a.length}):`,"info");for(let l of a)d(` - ${l}`,"info")}}}async function Ti(e){d("Reading environment variables...","info");let t=h(),n=Jt(t),r=Et(t),o={};for(let a of Object.keys(r))if(a in n){let i=n[a];o[a]=_i(a,i)?Pi(i):i||"(empty)"}else o[a]="(not set)";if(e.format==="json"){let a={};for(let[i,l]of Object.entries(o))a[i]=l;S(a,{format:"json"})}else{ft("Current Environment Variables");let a=Object.entries(o).map(([i,l])=>({Variable:Ai.cyan(i),Value:l}));S(a,{format:"table"}),d("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function hr(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?.(),a={dryRun:r.dryRun||o?.dryRun,yes:r.yes||o?.yes,format:r.format||o?.format};try{switch(n){case"validate":await Ii(a);break;case"template":await Ni(a);break;case"diff":await $i(a);break;case"show":await Ti(a);break;default:d(`Unknown env subcommand: ${n}. Valid commands: validate, template, diff, show`,"error"),process.exit(c.INVALID_ARGS)}}catch(i){let l=i instanceof Error?i.message:String(i);d(`Environment command failed: ${l}`,"error"),k("Full error",{error:i}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
148
|
+
or restore the directory from git.`),process.exit(c.NOT_FOUND)),t.dryRun&&(T({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: ${tt.bold(e)}`);let s=await k({command:"pnpm",args:["exec","playwright","test","--config",r],interactive:!0,label:`playwright ${e}`});process.exit(s.exitCode)}var Wt=e=>{e.command("e2e <suite>").description(`Run a Playwright suite (${nt.join(" | ")})`).option("--dry-run","Preview the command that would run (exit code 10)").action(async(t,n,r)=>{let o=O(n,r);await eo(t,{dryRun:!!n.dryRun,quiet:!!o.quiet})})};import{existsSync as Le,readFileSync as qt,writeFileSync as to}from"fs";import{resolve as Fe}from"path";import*as le from"@clack/prompts";import no from"picocolors";function Ue(e){let t=Fe(e,".env.example");if(!Le(t))throw new Error(`.env.example not found at ${t}`);let n=qt(t,"utf-8"),r={};for(let o of n.split(`
|
|
149
|
+
`)){if(o.trim().startsWith("#")||!o.trim())continue;let a=o.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(a){let[,i,s]=a;r[i]=s.replace(/^["'](.*)["']$/,"$1")}}return r}function rt(e){let t=Fe(e,".env.local"),n=Fe(e,".env"),r=Le(t)?t:n;if(!Le(r))return{};let o=qt(r,"utf-8"),a={};for(let i of o.split(`
|
|
150
|
+
`)){if(i.trim().startsWith("#")||!i.trim())continue;let s=i.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(s){let[,d,m]=s;a[d]=m.replace(/^["'](.*)["']$/,"$1")}}return a}function ro(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function oo(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 ao(e){u("Validating environment variables...","info");let t=b(),n=Ue(t),r=rt(t),o=process.env,a={},i=!0;for(let s of Object.keys(n)){let d=s in r||s in o;a[s]=d,d||(i=!1)}if(e.format==="json")h({valid:i,checked:Object.keys(n).length,missing:Object.entries(a).filter(([,s])=>!s).map(([s])=>s)},{format:"json"});else{je("Environment Validation");let s=Object.entries(a).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")}}i||process.exit(c.CONFIG_ERROR)}async function io(e){let t=b(),n=Ue(t),r=Fe(t,".env.local");if(Le(r)&&!e.yes&&!e.dryRun){let d=await le.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(le.isCancel(d)||!d)&&(u("Template generation cancelled","warn"),process.exit(c.CANCELLED))}u("Generating .env.local from template...","info");let o={},a=0,i=Object.keys(n).length;for(let[d,m]of Object.entries(n))if(a++,e.yes)o[d]=m;else if(process.stdin.isTTY===!0){let p=`[${a}/${i}] ${d}`,g=await le.text({message:p,defaultValue:m});le.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(`
|
|
151
|
+
`);e.dryRun?(u("Dry-run: would write .env.local","info"),h(s,{format:"plain"})):(to(r,s+`
|
|
152
|
+
`),u(`Environment template written to ${r}`,"success"))}async function so(e){u("Comparing environment variables...","info");let t=b(),n=Ue(t),r=rt(t),o=[],a=[],i=[];for(let s of Object.keys(n))s in r?i.push(s):o.push(s);for(let s of Object.keys(r))s in n||a.push(s);if(e.format==="json")h({matching:i.length,missing:o.length,extra:a.length,missing_vars:o,extra_vars:a},{format:"json"});else{if(je("Environment Diff"),i.length>0&&u(`Matching (${i.length}): ${i.join(", ")}`,"success"),o.length>0){u(`Missing (${o.length}):`,"warn");for(let s of o)u(` - ${s}`,"warn")}if(a.length>0){u(`Extra (${a.length}):`,"info");for(let s of a)u(` - ${s}`,"info")}}}async function co(e){u("Reading environment variables...","info");let t=b(),n=rt(t),r=Ue(t),o={};for(let a of Object.keys(r))if(a in n){let i=n[a];o[a]=ro(a,i)?oo(i):i||"(empty)"}else o[a]="(not set)";if(e.format==="json"){let a={};for(let[i,s]of Object.entries(o))a[i]=s;h(a,{format:"json"})}else{je("Current Environment Variables");let a=Object.entries(o).map(([i,s])=>({Variable:no.cyan(i),Value:s}));h(a,{format:"table"}),u("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function Ht(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?.(),a={dryRun:r.dryRun||o?.dryRun,yes:r.yes||o?.yes,format:r.format||o?.format};try{switch(n){case"validate":await ao(a);break;case"template":await io(a);break;case"diff":await so(a);break;case"show":await co(a);break;default:u(`Unknown env subcommand: ${n}. Valid commands: validate, template, diff, show`,"error"),process.exit(c.INVALID_ARGS)}}catch(i){let s=i instanceof Error?i.message:String(i);u(`Environment command failed: ${s}`,"error"),C("Full error",{error:i}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
438
153
|
Examples:
|
|
439
154
|
nebutra env validate Check all required vars are set
|
|
440
155
|
nebutra env template Generate .env.local from .env.example with prompts
|
|
@@ -451,7 +166,7 @@ Flags:
|
|
|
451
166
|
Sensitive Variables:
|
|
452
167
|
Variables with KEY, TOKEN, SECRET, PASSWORD in their names are masked in output.
|
|
453
168
|
This prevents accidental exposure of credentials.
|
|
454
|
-
`)}import{promises as
|
|
169
|
+
`)}import{promises as Jt}from"fs";import{join as ue}from"path";import*as Se from"@clack/prompts";import A from"picocolors";var we=["design","iam","commerce","integrations","platform","ops","ai"];function lo(e){return we.includes(e)}function ot(e,t){if(!t)throw new Error(`--category is required. Valid categories: ${we.join(", ")}. Example: nebutra generate package ${e} --category iam`);if(!lo(t))throw new Error(`Unknown category "${t}". Valid categories: ${we.join(", ")}.`);return`packages/${t}/${e}`}function Zt(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
|
|
455
170
|
"name": "@nebutra/${e}",
|
|
456
171
|
"version": "0.0.0",
|
|
457
172
|
"private": true,
|
|
@@ -536,7 +251,7 @@ export default function RootLayout({
|
|
|
536
251
|
|
|
537
252
|
@theme {
|
|
538
253
|
--color-*: var(--neutral-*);
|
|
539
|
-
}`}}function
|
|
254
|
+
}`}}function Xt(e){return{"package.json":`{
|
|
540
255
|
"name": "@nebutra/${e}",
|
|
541
256
|
"version": "0.0.0",
|
|
542
257
|
"type": "module",
|
|
@@ -573,7 +288,7 @@ export default function RootLayout({
|
|
|
573
288
|
|
|
574
289
|
export function hello(name: string): string {
|
|
575
290
|
return \`Hello, \${name}!\`;
|
|
576
|
-
}`}}function
|
|
291
|
+
}`}}function Qt(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
|
|
577
292
|
import { z } from "zod";
|
|
578
293
|
|
|
579
294
|
type Env = {
|
|
@@ -624,7 +339,7 @@ app.post("/", async (c) => {
|
|
|
624
339
|
);
|
|
625
340
|
});
|
|
626
341
|
|
|
627
|
-
export default app;`}}function
|
|
342
|
+
export default app;`}}function en(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";
|
|
628
343
|
import { cn } from "@nebutra/ui/utils";
|
|
629
344
|
|
|
630
345
|
const ${t}Variants = cva(
|
|
@@ -698,13 +413,13 @@ export const AllSizes: Story = {
|
|
|
698
413
|
<${n} size="lg">Large</\${pascalCase}>
|
|
699
414
|
</div>
|
|
700
415
|
),
|
|
701
|
-
};`}}async function
|
|
702
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
703
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
704
|
-
`),process.exit(c.DRY_RUN_OK)}
|
|
705
|
-
`),process.exit(c.DRY_RUN_OK)}Ze.intro(L.bgCyan(L.black(" nebutra generate component ")));let n=s.spinner();try{n.start(`Generating component ${L.cyan(e)}...`);let r=await xt("component",e);n.stop(`Created component ${L.cyan(e)}`,0),s.success(`Component created with ${r.length} files`),s.info("Files created in packages/design/ui/src/components/"),s.info("Next steps:"),s.info(" 1. Add export to packages/design/ui/src/components/index.ts"),s.info(" 2. pnpm --filter @nebutra/ui typecheck"),s.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 Cr=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 a=x(r,o);await ji(n,{dryRun:!!r.dryRun,yes:!!a.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: ${Qe.join(", ")}`).requiredOption("--category <category>",`Package category: ${Qe.join(" | ")}`).option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r,o)=>{let a=x(r,o);await Li(n,{category:String(r.category??""),dryRun:!!r.dryRun,yes:!!a.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 a=x(r,o);await Di(n,{dryRun:!!r.dryRun,yes:!!a.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 a=x(r,o);await Fi(n,{dryRun:!!r.dryRun,yes:!!a.yes,variants:typeof r.variants=="string"?r.variants:void 0,sizes:typeof r.sizes=="string"?r.sizes:void 0})})};import Ve from"picocolors";async function J(e,t){let n=await h(),r=new URL(e,"http://localhost:3000/api/growth");t?.query&&Object.entries(t.query).forEach(([a,i])=>{r.searchParams.set(a,i)});let o=await fetch(r,{method:t?.method||"GET",headers:{"Content-Type":"application/json"},body:t?.body?JSON.stringify(t.body):void 0});if(!o.ok)throw new Error(`Growth API error (${o.status}): ${await o.text()}`);return o.json()}async function Bi(e){try{let t=e.period||"7d",n=e.compare;s.info(`Fetching growth metrics for ${t}...`);let r=await J("/summary",{query:{period:t,compare:n?"true":"false"}});return c.SUCCESS}catch(t){return s.error(`Dashboard error: ${t instanceof Error?t.message:String(t)}`),c.ERROR}}async function Mi(e){try{let t=e.period||"7d",n=e.segment||"all";s.info(`Fetching funnel data for ${t} (${n})...`);let r=await J("/funnel",{query:{period:t,segment:n}});return r.forEach((a,i)=>{let l="\u2588".repeat(Math.ceil(a.rate*20)),u="\u2591".repeat(20-Math.ceil(a.rate*20)),m=i<r.length-1?Ve.red(`\u2193 ${(a.dropoff_rate*100).toFixed(1)}% drop`):""}),r.reduce((a,i)=>i.dropoff_rate>a.dropoff_rate?i:a).dropoff_rate>.2,c.SUCCESS}catch(t){return s.error(`Funnel error: ${t instanceof Error?t.message:String(t)}`),c.ERROR}}async function Gi(e){try{let t=e.period||"weekly",n=parseInt(e.cohorts,10)||8;s.info(`Fetching ${t} cohort data (${n} cohorts)...`);let r=await J("/cohort",{query:{period:t,cohorts:String(n)}});if(r.length===0)return c.SUCCESS;let o=Object.keys(r[0]).slice(1);return r.forEach(a=>{let l=String(a.cohort).padEnd(15);o.forEach(u=>{let m=a[u];if(typeof m=="number"){let f=m/100,y=String(Math.round(m)).padEnd(8);f>=.7?y=Ve.green(y):f>=.4?y=Ve.yellow(y):y=Ve.red(y),l+=y+" "}})}),c.SUCCESS}catch(t){return s.error(`Cohort error: ${t instanceof Error?t.message:String(t)}`),c.ERROR}}async function Vi(e,t){try{if(e==="stats"){s.info("Fetching newsletter stats...");let n=await J("/newsletter/stats");return c.SUCCESS}if(e==="subscribers"){let n=parseInt(t.limit,10)||10,r=parseInt(t.offset,10)||0;return s.info(`Fetching ${n} newsletter subscribers (offset ${r})...`),(await J("/newsletter/subscribers",{query:{limit:String(n),offset:String(r)}})).forEach(a=>{}),c.SUCCESS}if(e==="send"){let n=t.template;return n?t.yes?(s.info(`Sending newsletter with template: ${n}`),await J("/newsletter/send",{method:"POST",body:{template_id:n}}),c.SUCCESS):(s.warn("Use --yes to confirm newsletter send"),c.ERROR):(s.error("--template is required"),c.ERROR)}return s.error(`Unknown newsletter subcommand: ${e}`),c.ERROR}catch(n){return s.error(`Newsletter error: ${n instanceof Error?n.message:String(n)}`),c.ERROR}}async function Ki(e,t){try{if(e==="status"){s.info("Fetching referral program status...");let n=await J("/referral/status");return c.SUCCESS}if(e==="config"){s.info("Fetching referral config...");let n=await J("/referral/config");return Object.entries(n).forEach(([r,o])=>{}),c.SUCCESS}return e==="leaderboard"?(s.info("Fetching referral leaderboard..."),(await J("/referral/leaderboard")).forEach(r=>{let o=r.rank===1?"\u{1F947}":r.rank===2?"\u{1F948}":"\u{1F949}"}),c.SUCCESS):(s.error(`Unknown referral subcommand: ${e}`),c.ERROR)}catch(n){return s.error(`Referral error: ${n instanceof Error?n.message:String(n)}`),c.ERROR}}async function qi(e,t){try{if(e==="list"){s.info("Fetching active experiments...");let n=await J("/experiment");return n.length===0?c.SUCCESS:(n.forEach(r=>{let o=r.status==="running"?Ve.yellow("\u25CF"):Ve.green("\u2713")}),c.SUCCESS)}if(e==="create"){let n=t.name,r=t.variants?.split(","),o=t.metric;if(!n||!r||!o)return s.error("Required: --name <name> --variants <A,B> --metric <metric>"),c.ERROR;s.info(`Creating experiment: ${n}`);let a=await J("/experiment",{method:"POST",body:{name:n,variants:r,metric:o}});return c.SUCCESS}if(e==="results"){let n=t.id;if(!n)return s.error("--id is required"),c.ERROR;s.info(`Fetching results for experiment ${n}...`);let r=await J(`/experiment/${n}`);return r.winner,r.significance,c.SUCCESS}if(e==="conclude"){let n=t.id,r=t.winner;return!n||!r?(s.error("Required: --id <id> --winner <variant>"),c.ERROR):t.yes?(s.info(`Concluding experiment ${n} with winner: ${r}`),await J(`/experiment/${n}`,{method:"POST",body:{action:"conclude",winner:r}}),c.SUCCESS):(s.warn("Use --yes to confirm experiment conclusion"),c.ERROR)}return s.error(`Unknown experiment subcommand: ${e}`),c.ERROR}catch(n){return s.error(`Experiment error: ${n instanceof Error?n.message:String(n)}`),c.ERROR}}async function zi(e){try{let t=e.focus||"activation",n=e.depth||"quick";s.info(`Generating growth insights (focus: ${t}, depth: ${n})...`);let r=await J("/pulse",{query:{focus:t,depth:n}});return r.insights.forEach(o=>{}),r.recommendations.forEach(o=>{}),c.SUCCESS}catch(t){return s.error(`Pulse error: ${t instanceof Error?t.message:String(t)}`),c.ERROR}}function Er(e){let t=e.command("growth").description("Growth engine operations \u2014 metrics, funnel, cohorts, AI insights");t.command("dashboard").description("Growth metrics overview").option("--period <7d|30d|90d>","Time period","7d").option("--compare","Show period-over-period deltas").action(async a=>{process.exit(await Bi(a))}),t.command("funnel").description("Conversion funnel analysis").option("--period <7d|30d|90d>","Time period","7d").option("--segment <organic|paid|referral>","Traffic segment","all").action(async a=>{process.exit(await Mi(a))}),t.command("cohort").description("Cohort retention analysis").option("--period <weekly|monthly>","Cohort period","weekly").option("--cohorts <n>","Number of cohorts","8").action(async a=>{process.exit(await Gi(a))}),t.command("newsletter <subcommand>").description("Newsletter management").action(async(a,i)=>{process.exit(await Vi(a,i))}),t.command("referral <subcommand>").description("Referral program management").action(async(a,i)=>{process.exit(await Ki(a,i))}),t.command("experiment <subcommand>").description("A/B testing and experiment management").option("--id <id>","Experiment ID").option("--name <name>","Experiment name").option("--variants <A,B>","Comma-separated variants").option("--metric <metric>","Success metric").option("--winner <variant>","Winning variant").action(async(a,i)=>{process.exit(await qi(a,i))}),t.command("pulse").description("AI-generated growth insights (AARRR: Acquisition, Activation, Retention, Revenue, Referral)").option("--focus <aarrr>","Focus area (acquisition|activation|retention|revenue|referral)","activation").option("--depth <quick|deep>","Analysis depth","quick").action(async a=>{process.exit(await zi(a))}),t.option("--dry-run","Preview changes without applying them").option("--format <json|text>","Output format","text").option("--yes","Skip confirmation prompts")}import Qt,{lstatSync as Yi,readdirSync as Zt,readFileSync as Hi,writeFileSync as Wi}from"fs";import ge from"path";import{fileURLToPath as Ji}from"url";import te from"picocolors";var Xi=ge.dirname(Ji(import.meta.url));function en(){let e=new Map,t=ge.join(Xi,"../../../apps");if(!Qt.existsSync(t))return e;try{let n=Zt(t);for(let r of n){let o=ge.join(t,r),a=ge.join(o,"messages");Qt.existsSync(a)&&Yi(a).isDirectory()&&e.set(r,a)}}catch(n){s.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function et(e,t=""){let n=new Set;for(let[r,o]of Object.entries(e)){let a=t?`${t}.${r}`:r;if(typeof o=="object"&&o!==null&&!Array.isArray(o)){let i=et(o,a);for(let l of i)n.add(l)}else n.add(a)}return n}function tt(e){try{let t=Hi(e,"utf-8");return JSON.parse(t)}catch(t){return s.debug(`Failed to parse ${e}: ${t instanceof Error?t.message:String(t)}`),null}}async function Qi(e){if(s.info("Syncing language files across the project..."),(await z("translate",{filter:"landing",dryRun:e.dryRun,interactive:e.interactive??!0})).exitCode!==0){s.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&&(s.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||s.success("Language files synced successfully")}else e.format==="json"?console.log(JSON.stringify({command:"i18n:sync",exitCode:0,success:!0},null,2)):e.dryRun||s.success("Language files synced successfully")}async function Zi(e){s.info("Validating translation files...");let t=en();t.size===0&&(s.warn("No message directories found in the project"),process.exit(c.NOT_FOUND));let n=new Map,r=!1;for(let[o,a]of t){let i=[];try{let l=Zt(a).filter(y=>y.endsWith(".json"));if(l.length===0)continue;let u=ge.join(a,"en.json"),m=tt(u);if(!m){s.warn(`Could not load reference locale en.json from ${o}`);continue}let f=et(m);for(let y of l){if(y==="en.json")continue;let E=y.replace(".json",""),D=ge.join(a,y),F=tt(D);if(!F){s.debug(`Could not parse ${y}`);continue}let q=et(F),ye=Array.from(f).filter(p=>!q.has(p)),ue=Array.from(q).filter(p=>!f.has(p)),_e=f.size>0?(f.size-ye.length)/f.size*100:100;(ye.length>0||ue.length>0)&&(r=!0),i.push({locale:E,totalKeys:f.size,missingKeys:ye,extraKeys:ue,coverage:Math.round(_e*100)/100})}i.length>0&&n.set(o,i)}catch(l){s.debug(`Error validating ${o}: ${l instanceof Error?l.message:String(l)}`)}}if(e.format==="json"){let o={command:"i18n:validate",success:!r,results:Array.from(n.entries()).reduce((a,[i,l])=>(a[i]=l,a),{})};console.log(JSON.stringify(o,null,2))}else for(let[o,a]of n){s.info(`${te.bold(o)}:`);for(let i of a){let u=(i.coverage>=100?te.green:i.coverage>=80?te.yellow:te.red)(`${i.coverage}%`);s.info(` ${te.cyan(i.locale.padEnd(5))} ${u.padEnd(20)} [${i.totalKeys} keys]`),i.missingKeys.length>0&&s.warn(` Missing: ${i.missingKeys.slice(0,5).join(", ")}${i.missingKeys.length>5?` (+ ${i.missingKeys.length-5} more)`:""}`),i.extraKeys.length>0&&s.warn(` Extra: ${i.extraKeys.slice(0,5).join(", ")}${i.extraKeys.length>5?` (+ ${i.extraKeys.length-5} more)`:""}`)}}r&&process.exit(c.CONFLICT)}async function ec(e,t){/^[a-z]{2}(-[A-Z]{2})?$/.test(e)||(s.error(`Invalid locale format: ${e}. Use 'en', 'es', 'zh-CN', etc.`),process.exit(c.INVALID_ARGS));let n=en();n.size===0&&(s.error("No message directories found in the project"),process.exit(c.NOT_FOUND));let r=[],o=!1;for(let[i,l]of n){let u=ge.join(l,`${e}.json`);if(Qt.existsSync(u)){s.warn(`Locale ${e} already exists in ${i}`);continue}try{let E=function(D){for(let F in D)typeof D[F]=="string"?D[F]="":typeof D[F]=="object"&&D[F]!==null&&E(D[F])};var a=E;let m=ge.join(l,"en.json"),f=tt(m);if(!f){s.warn(`Could not load reference en.json from ${i}, skipping...`);continue}let y=JSON.parse(JSON.stringify(f));E(y),t.dryRun?s.info(`Would create ${e} locale in ${i}`):(Wi(u,JSON.stringify(y,null,2)+`
|
|
706
|
-
`),r.push({app:i,path:
|
|
707
|
-
Average coverage: ${i(a.toFixed(1)+"%")}`)}}}function
|
|
416
|
+
};`}}async function Be(e,t,n){let r=b(),o=[],a={};switch(e){case"app":a=Zt(t);break;case"package":a=Xt(t);break;case"route":a=Qt(t);break;case"component":a=en(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let i=e==="package"?ot(t,n.category):void 0;for(let[s,d]of Object.entries(a)){let m=e==="app"?ue(r,"apps",t,s):e==="package"?ue(r,i??`packages/${t}`,s):ue(r,"backends/gateway",s);o.push({path:m,size:Buffer.byteLength(d)})}return o}async function Ge(e,t,n={}){let r=b(),o=[],a={};switch(e){case"app":a=Zt(t);break;case"package":a=Xt(t);break;case"route":a=Qt(t);break;case"component":a=en(t);break;default:throw new Error(`Unknown generate type: ${e}`)}let i=e==="package"?ot(t,n.category):void 0;for(let[s,d]of Object.entries(a)){let m;e==="app"?m=ue(r,"apps",t,s):e==="package"?m=ue(r,i??`packages/${t}`,s):e==="component"?m=ue(r,"packages/design/ui",s):m=ue(r,"backends/gateway",s);let p=m.substring(0,m.lastIndexOf("/"));await Jt.mkdir(p,{recursive:!0}),await Jt.writeFile(m,d,"utf-8"),o.push(m)}return o}async function uo(e,t){if(t.dryRun){let r=await Be("app",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"app",name:e,location:`apps/${e}`,files:r.map(a=>({path:a.path,sizeBytes:a.size})),instructions:[`cd apps/${e}`,"pnpm install","pnpm run dev"]};process.stdout.write(JSON.stringify(o,null,2)+`
|
|
417
|
+
`),process.exit(c.DRY_RUN_OK)}Se.intro(A.bgCyan(A.black(" nebutra generate app ")));let n=l.spinner();try{n.start(`Generating app ${A.cyan(e)}...`);let r=await Ge("app",e);n.stop(`Created app ${A.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 mo(e,t){let n;try{n=ot(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 Be("package",e,t),a={mode:"dry-run",timestamp:new Date().toISOString(),type:"package",name:e,category:t.category,location:n,files:o.map(i=>({path:i.path,sizeBytes:i.size}))};process.stdout.write(JSON.stringify(a,null,2)+`
|
|
418
|
+
`),process.exit(c.DRY_RUN_OK)}Se.intro(A.bgCyan(A.black(" nebutra generate package ")));let r=l.spinner();try{r.start(`Generating package ${A.cyan(e)} in ${A.dim(n)}...`);let o=await Ge("package",e,{category:t.category});r.stop(`Created package ${A.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 po(e,t){if(t.dryRun){let r=await Be("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(a=>({path:a.path,sizeBytes:a.size}))};process.stdout.write(JSON.stringify(o,null,2)+`
|
|
419
|
+
`),process.exit(c.DRY_RUN_OK)}Se.intro(A.bgCyan(A.black(" nebutra generate route ")));let n=l.spinner();try{n.start(`Generating route ${A.cyan(e)}...`);let r=await Ge("route",e);n.stop(`Created route ${A.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 fo(e,t){if(t.dryRun){let r=await Be("component",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"component",name:e,location:"packages/design/ui/src/components/",files:r.map(a=>({path:a.path,sizeBytes:a.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)+`
|
|
420
|
+
`),process.exit(c.DRY_RUN_OK)}Se.intro(A.bgCyan(A.black(" nebutra generate component ")));let n=l.spinner();try{n.start(`Generating component ${A.cyan(e)}...`);let r=await Ge("component",e);n.stop(`Created component ${A.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 tn=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 a=O(r,o);await uo(n,{dryRun:!!r.dryRun,yes:!!a.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: ${we.join(", ")}`).requiredOption("--category <category>",`Package category: ${we.join(" | ")}`).option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r,o)=>{let a=O(r,o);await mo(n,{category:String(r.category??""),dryRun:!!r.dryRun,yes:!!a.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 a=O(r,o);await po(n,{dryRun:!!r.dryRun,yes:!!a.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 a=O(r,o);await fo(n,{dryRun:!!r.dryRun,yes:!!a.yes,variants:typeof r.variants=="string"?r.variants:void 0,sizes:typeof r.sizes=="string"?r.sizes:void 0})})};import at,{lstatSync as go,readdirSync as it,readFileSync as yo,writeFileSync as bo}from"fs";import H from"path";import{fileURLToPath as ho}from"url";import D from"picocolors";var vo=H.dirname(ho(import.meta.url));function st(){let e=new Map,t=H.join(vo,"../../../apps");if(!at.existsSync(t))return e;try{let n=it(t);for(let r of n){let o=H.join(t,r),a=H.join(o,"messages");at.existsSync(a)&&go(a).isDirectory()&&e.set(r,a)}}catch(n){l.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function Ee(e,t=""){let n=new Set;for(let[r,o]of Object.entries(e)){let a=t?`${t}.${r}`:r;if(typeof o=="object"&&o!==null&&!Array.isArray(o)){let i=Ee(o,a);for(let s of i)n.add(s)}else n.add(a)}return n}function Re(e){try{let t=yo(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 Co(e){if(l.info("Syncing language files across the project..."),(await P("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 k({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 wo(e){l.info("Validating translation files...");let t=st();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,a]of t){let i=[];try{let s=it(a).filter(g=>g.endsWith(".json"));if(s.length===0)continue;let d=H.join(a,"en.json"),m=Re(d);if(!m){l.warn(`Could not load reference locale en.json from ${o}`);continue}let p=Ee(m);for(let g of s){if(g==="en.json")continue;let E=g.replace(".json",""),f=H.join(a,g),v=Re(f);if(!v){l.debug(`Could not parse ${g}`);continue}let B=Ee(v),K=Array.from(p).filter(z=>!B.has(z)),X=Array.from(B).filter(z=>!p.has(z)),be=p.size>0?(p.size-K.length)/p.size*100:100;(K.length>0||X.length>0)&&(r=!0),i.push({locale:E,totalKeys:p.size,missingKeys:K,extraKeys:X,coverage:Math.round(be*100)/100})}i.length>0&&n.set(o,i)}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((a,[i,s])=>(a[i]=s,a),{})};console.log(JSON.stringify(o,null,2))}else for(let[o,a]of n){l.info(`${D.bold(o)}:`);for(let i of a){let d=(i.coverage>=100?D.green:i.coverage>=80?D.yellow:D.red)(`${i.coverage}%`);l.info(` ${D.cyan(i.locale.padEnd(5))} ${d.padEnd(20)} [${i.totalKeys} keys]`),i.missingKeys.length>0&&l.warn(` Missing: ${i.missingKeys.slice(0,5).join(", ")}${i.missingKeys.length>5?` (+ ${i.missingKeys.length-5} more)`:""}`),i.extraKeys.length>0&&l.warn(` Extra: ${i.extraKeys.slice(0,5).join(", ")}${i.extraKeys.length>5?` (+ ${i.extraKeys.length-5} more)`:""}`)}}r&&process.exit(c.CONFLICT)}async function So(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=st();n.size===0&&(l.error("No message directories found in the project"),process.exit(c.NOT_FOUND));let r=[],o=!1;for(let[i,s]of n){let d=H.join(s,`${e}.json`);if(at.existsSync(d)){l.warn(`Locale ${e} already exists in ${i}`);continue}try{let E=function(f){for(let v in f)typeof f[v]=="string"?f[v]="":typeof f[v]=="object"&&f[v]!==null&&E(f[v])};var a=E;let m=H.join(s,"en.json"),p=Re(m);if(!p){l.warn(`Could not load reference en.json from ${i}, skipping...`);continue}let g=JSON.parse(JSON.stringify(p));E(g),t.dryRun?l.info(`Would create ${e} locale in ${i}`):(bo(d,JSON.stringify(g,null,2)+`
|
|
421
|
+
`),r.push({app:i,path:d}),l.success(`Created ${e} locale in ${i}`))}catch(m){l.error(`Failed to create locale in ${i}: ${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 Eo(e){l.info("Checking translation coverage...");let t=st();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[a,i]of t){let s=[];try{let d=it(i).filter(E=>E.endsWith(".json"));if(d.length===0)continue;let m=H.join(i,"en.json"),p=Re(m);if(!p){l.debug(`Could not load reference locale from ${a}`);continue}let g=Ee(p);for(let E of d){let f=E.replace(".json",""),v=H.join(i,E),B=Re(v);if(!B)continue;let K=Ee(B),X=Array.from(K).filter(pe=>{let _e=B[pe.split(".")[0]];return _e!==void 0&&_e!==""}).length,be=g.size-X,z=g.size>0?X/g.size*100:0;s.push({locale:f,coverage:Math.round(z*100)/100,totalKeys:g.size,translatedKeys:X,missingKeys:be})}s.length>0&&(n.set(a,s),o++,r+=s.reduce((E,f)=>E+f.coverage,0)/s.length)}catch(d){l.debug(`Error checking status for ${a}: ${d instanceof Error?d.message:String(d)}`)}}if(e.format==="json"){let a={command:"i18n:status",averageCoverage:o>0?Math.round(r/o*100)/100:0,results:Array.from(n.entries()).reduce((i,[s,d])=>(i[s]=d,i),{})};console.log(JSON.stringify(a,null,2))}else{for(let[a,i]of n){l.info(`${D.bold(a)}:`);for(let s of i){let d="",p=Math.round(s.coverage/100*20);d="\u2588".repeat(p)+"\u2591".repeat(20-p);let E=(s.coverage>=100?D.green:s.coverage>=80?D.yellow:D.red)(`${s.coverage.toFixed(1)}%`);l.info(` ${D.cyan(s.locale.padEnd(5))} [${d}] ${E}`),l.info(` ${s.translatedKeys}/${s.totalKeys} keys (${s.missingKeys} missing)`)}}if(o>0){let a=r/o,i=a>=100?D.green:a>=80?D.yellow:D.red;l.info(`
|
|
422
|
+
Average coverage: ${i(a.toFixed(1)+"%")}`)}}}function nn(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 Co({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 wo({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 So(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 Eo({format:n.format||r.format,interactive:r.yes!==!0})})}import*as Me from"@clack/prompts";async function Ro(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 fe("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"),C("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function xo(e){u("Stopping infrastructure stack...","info");let t=await fe("down",{dryRun:e.dryRun});t.exitCode===0?u("Infrastructure stack stopped","success"):(u("Failed to stop infrastructure stack","error"),C("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}async function ko(e){u("Checking infrastructure status...","info");let t=await fe("ps --format json",{dryRun:e.dryRun});if(t.exitCode===0)try{let n=JSON.parse(t.stdout);if(e.format==="json")h(n,{format:"json"});else{let r=n.map(o=>({name:o.Name,status:o.Status,ports:o.Ports||"-"}));h(r,{format:"table"})}}catch{h(t.stdout,{format:"plain"})}else u("Failed to check infrastructure status","error"),C("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}async function Oo(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 a=await fe(o.join(" "),{dryRun:n.dryRun});a.exitCode===0?h(a.stdout,{format:"plain"}):(u("Failed to fetch logs","error"),C("Docker compose output",{stderr:a.stderr}),process.exit(a.exitCode||1))}async function Ao(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await Me.confirm({message:"Reset infrastructure? This will remove all containers and volumes.",initialValue:!1});(Me.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 fe("down -v",{dryRun:e.dryRun});n.exitCode===0?u("Infrastructure reset successfully","success"):(u("Failed to reset infrastructure","error"),C("Docker compose output",{stderr:n.stderr}),process.exit(n.exitCode||1))}function rn(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 a=o.optsWithGlobals?.(),i={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:o.format||a?.format,lite:o.lite||!1,profile:o.profile};try{switch(n){case"up":await Ro(i);break;case"down":await xo(i);break;case"status":await ko(i);break;case"logs":await Oo(r,i);break;case"reset":await Ao(i);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"),C("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
708
423
|
Examples:
|
|
709
424
|
nebutra infra up Start full stack
|
|
710
425
|
nebutra infra up --lite Start lite stack (PostgreSQL + Redis)
|
|
@@ -721,37 +436,14 @@ Flags:
|
|
|
721
436
|
--lite Use docker-compose.lite.yml (PostgreSQL + Redis only)
|
|
722
437
|
--profile <name> Enable Docker Compose profile (search, notifications, etc.)
|
|
723
438
|
--format <type> Output format: json, plain (default: plain, auto-json in non-TTY)
|
|
724
|
-
`)}import
|
|
725
|
-
`),o?(
|
|
726
|
-
`)}async function
|
|
727
|
-
`));let r=
|
|
728
|
-
Failed to start MCP server: ${o.message}`),o.code==="ENOENT"&&(
|
|
729
|
-
Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),
|
|
730
|
-
Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{
|
|
731
|
-
`)}function
|
|
732
|
-
Examples:
|
|
733
|
-
nebutra search status Show search provider status
|
|
734
|
-
nebutra search indexes List all indexes
|
|
735
|
-
nebutra search reindex products Reindex products index
|
|
736
|
-
nebutra search reindex --force --yes Force reindex all indexes
|
|
737
|
-
nebutra search query products "laptop" Search products for "laptop"
|
|
738
|
-
nebutra search query products "laptop" --limit 20 Search with custom limit
|
|
739
|
-
nebutra search stats Show index statistics
|
|
740
|
-
|
|
741
|
-
Supported Providers:
|
|
742
|
-
Meilisearch (self-hosted) \u2014 MEILISEARCH_URL env var
|
|
743
|
-
Typesense (self-hosted) \u2014 TYPESENSE_URL env var
|
|
744
|
-
Algolia (managed) \u2014 ALGOLIA_APP_ID env var
|
|
745
|
-
|
|
746
|
-
Flags:
|
|
747
|
-
--dry-run Show what would be run without executing
|
|
748
|
-
--yes Skip confirmations
|
|
749
|
-
--format <type> Output format: json, plain, table (default: plain)
|
|
750
|
-
--force Force operation (e.g., recreate index)
|
|
751
|
-
--limit <n> Result limit for queries (default: 10)
|
|
752
|
-
--filters <json> Filters for search query
|
|
753
|
-
--tenant <id> Tenant ID for multi-tenant searches
|
|
754
|
-
`)}import{stdin as ot}from"process";import*as $t from"@clack/prompts";import N from"picocolors";async function Qc(){return new Promise((e,t)=>{let n="";ot.setEncoding("utf8"),ot.on("readable",()=>{let r;for(;(r=ot.read())!==null;)n+=r}),ot.on("end",()=>{e(n.trim())}),ot.on("error",t)})}async function Zc(e){d("Fetching secret metadata...","info");let t=[{key:"openai_key",tenant:e.tenant||"org_123",createdAt:"2024-03-15T10:30:00Z",updatedAt:"2024-03-30T14:22:00Z",description:"OpenAI API key for embeddings",masked:!0},{key:"stripe_sk",tenant:e.tenant||"org_123",createdAt:"2024-03-10T08:15:00Z",updatedAt:"2024-03-25T09:45:00Z",description:"Stripe secret key",masked:!0},{key:"github_token",tenant:e.tenant||"org_123",createdAt:"2024-03-20T16:30:00Z",updatedAt:"2024-03-29T11:20:00Z",description:"GitHub API token",masked:!0}];if(e.format==="json")S(t,{format:"json"});else{d("Secrets for tenant: "+(e.tenant||"org_123"),"info");for(let n of t){let r=n.description?` \u2014 ${n.description}`:"";d(`${N.cyan(n.key)}${N.gray(r)}`,"info"),d(` Updated: ${n.updatedAt}`,"info")}}}async function el(e,t){e||(d("Secret key is required: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS));let n;if(t.value)d("WARNING: Using --value flag exposes secret in shell history. Prefer stdin.","warn"),n=t.value;else{d("Enter secret value (will not echo). Press Ctrl+D when done:","info");try{n=await Qc()}catch{d("Failed to read secret from stdin","error"),process.exit(c.ERROR)}}if(n||(d("Secret value cannot be empty","error"),process.exit(c.INVALID_ARGS)),d(`Setting secret ${N.cyan(e)}...`,"info"),t.dryRun){d(`Would encrypt and store secret ${e} for tenant ${t.tenant||"org_123"}`,"info");return}d(`Secret ${N.cyan(e)} encrypted and stored successfully`,"success"),t.description&&d(`Description: ${t.description}`,"info")}async function tl(e,t){e||(d("Secret key is required: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),d(`Retrieving secret ${N.cyan(e)}...`,"info");let r=t.unmask?"sk_live_abc123xyz789...":"***masked***";t.unmask||d(`Secret value is ${N.yellow("masked")}. Use --unmask to display.`,"warn");let o={key:e,tenant:t.tenant||"org_123",value:r,encrypted:!0};t.format==="json"?S(o,{format:"json"}):d(`${N.cyan(e)}: ${r}`,"info")}async function nl(e,t){e||(d("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 $t.confirm({message:`Rotate encryption key for ${N.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});($t.isCancel(r)||!r)&&(d("Rotation cancelled","warn"),process.exit(c.CANCELLED))}if(!t.yes&&!t.dryRun&&!n&&(d("Key rotation requires --yes confirmation","error"),process.exit(c.INVALID_ARGS)),d(`Rotating encryption key for ${N.cyan(e)}...`,"info"),t.dryRun){d(`Would rotate encryption key for ${e}`,"info");return}d(`Encryption key for ${N.cyan(e)} rotated successfully`,"success"),d(`New key version: ${N.dim("v2")}`,"info")}async function rl(e){d("Fetching audit log...","info");let n=[{timestamp:"2024-03-30T14:52:00Z",action:"read",key:"openai_key",actor:"api_service",success:!0},{timestamp:"2024-03-30T14:22:00Z",action:"write",key:"openai_key",actor:"claude_user",success:!0},{timestamp:"2024-03-30T13:45:00Z",action:"read",key:"stripe_sk",actor:"billing_worker",success:!0},{timestamp:"2024-03-30T11:30:00Z",action:"rotate",key:"github_token",actor:"admin_user",success:!0},{timestamp:"2024-03-30T10:15:00Z",action:"read",key:"unknown_key",actor:"unauthorized_service",success:!1,message:"Key not found"}];if(e.limit&&(n=n.slice(0,e.limit)),e.format==="json")S(n,{format:"json"});else{d("Secret Access Audit Log","info");for(let r of n){let o=r.success?N.green("\u2713"):N.red("\u2716");d(`${o} ${r.timestamp} ${N.cyan(r.action)} ${r.key}`,r.success?"success":"error"),d(` Actor: ${r.actor}${r.message?` \u2014 ${r.message}`:""}`,"info")}}}async function ol(e){d("Verifying vault configuration...","info");let t=[];if(t.push({name:"KMS Connectivity",healthy:!0,message:"Connected to AWS KMS"}),t.push({name:"Master Key",healthy:!0,message:"Master encryption key available"}),t.push({name:"Envelope Encryption",healthy:!0,message:"HKDF envelope encryption configured"}),t.push({name:"Storage Backend",healthy:!0,message:"PostgreSQL backend healthy"}),e.format==="json")S(t,{format:"json"});else{d("Vault Configuration Check","info");for(let r of t){let o=r.healthy?N.green("\u2713"):N.red("\u2716");d(`${o} ${r.name}: ${r.message}`,r.healthy?"success":"error")}let n=t.every(r=>r.healthy);d(`Overall: ${n?N.green("HEALTHY"):N.red("UNHEALTHY")}`,n?"success":"error")}}function qr(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 a=o.optsWithGlobals?.(),i={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:o.format||a?.format,tenant:o.tenant||a?.tenant,unmask:o.unmask||!1,description:o.description,value:o.value,since:o.since,limit:o.limit??50};try{switch(n){case"list":await Zc(i);break;case"set":r.length===0&&(d("set requires a secret key: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS)),await el(r[0],i);break;case"get":r.length===0&&(d("get requires a secret key: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),await tl(r[0],i);break;case"rotate":r.length===0&&(d("rotate requires a secret key: nebutra secrets rotate <key>","error"),process.exit(c.INVALID_ARGS)),await nl(r[0],i);break;case"audit":await rl(i);break;case"verify":await ol(i);break;default:d(`Unknown secrets subcommand: ${n}. Valid commands: list, set, get, rotate, audit, verify`,"error"),process.exit(c.ERROR)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Secrets command failed: ${u}`,"error"),k("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
439
|
+
`)}import ct from"fs";import Io from"path";import*as L from"@clack/prompts";import Ve from"picocolors";var _o=["auth","billing","email","storage","queue","cache","notifications","webhooks","ai","mcp"],No={stack:"sailor-2026-09",capabilities:[..._o]};function Po(){return process.stdout.isTTY===!0}function $o(e){return e.yes===!0||e.dryRun===!0||!Po()}function jo(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function on(e={}){let t=process.cwd(),n=Io.join(t,"nebutra.config.json"),r=ct.existsSync(n);e.ifNotExists&&r&&(l.info("nebutra.config.json already exists, skipping initialization."),process.exit(c.SUCCESS));let o=$o(e);o||L.intro(Ve.bgCyan(Ve.black(" nebutra init "))),r&&!o&&(L.log.warn("nebutra.config.json already exists in this directory."),await L.confirm({message:"Do you want to overwrite it?",initialValue:!1})||(L.outro("Operation aborted."),process.exit(c.CANCELLED)));let a={...No};if(e.dryRun){let i=r?JSON.parse(ct.readFileSync(n,"utf-8")):void 0,s=jo(n,a,i);T(s),u("Dry-run completed. No changes made."),process.exit(c.DRY_RUN_OK)}o?l.info("Initializing Nebutra CLI configuration..."):L.spinner().start("Initializing Nebutra CLI configuration..."),ct.writeFileSync(n,JSON.stringify(a,null,2)+`
|
|
440
|
+
`),o?(l.success("Configuration saved to nebutra.config.json"),l.info('Initialization complete! Run "nebutra status" to check capability readiness.')):(await new Promise(i=>setTimeout(i,800)),L.spinner().stop(Ve.green("Configuration saved to nebutra.config.json")),L.outro(Ve.cyan('Initialization complete! Run "nebutra status" to check capability readiness.'))),process.exit(c.SUCCESS)}import lt from"fs/promises";import Fo from"os";import ut from"path";import*as S from"@clack/prompts";import F from"picocolors";var To="https://analytics.nebutra.com";function Do(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function Lo(){return process.env.npm_package_version??"0.0.0-dev"}function Ke(e,t={}){Do(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??To},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",{action:e.action,cli_version:Lo(),...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 an=process.env.NEBUTRA_LICENSE_API_URL??"https://nebutra.com";async function sn(){let e=Fo.homedir(),t=ut.join(e,".config","nebutra");try{await lt.mkdir(t,{recursive:!0})}catch{}return t}async function Uo(e){let t=`${an}/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 (${an}). 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 Bo(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 Go(e,t){let n=t.quiet===!0;n||S.intro(F.bgCyan(F.black(" Nebutra License Activation "))),Ke({action:"activate_attempted"});try{if(e.length<10)throw new Error("Invalid license key format.");n||S.log.step("Validating license key with Nebutra...");let{tier:r,type:o}=await Uo(e),a=await sn(),i=ut.join(a,"license.json");await lt.writeFile(i,JSON.stringify({licenseKey:e,tier:r,type:o,activatedAt:new Date().toISOString()},null,2),"utf-8"),n||(S.log.success(F.green(`${r} license activated and saved to ${i}`)),S.outro(F.cyan("Premium CLI capabilities are now unlocked!"))),Ke({action:"activated",tier:r,type:o})}catch(r){Ke({action:"failed",error_code:Bo(r)}),n||(S.log.error(F.red("Activation failed")),l.error(r instanceof Error?r.message:String(r)),S.outro("Please check your key and try again.")),process.exit(c.ERROR)}}async function Mo(e){let t=e.quiet===!0;t||S.intro(F.bgCyan(F.black(" Nebutra License Status ")));try{let n=await sn(),r=ut.join(n,"license.json"),o=await lt.readFile(r,"utf-8"),a=JSON.parse(o);if(a.licenseKey)t||(S.log.success(F.green("License is active!")),S.log.info(`Key: ${a.licenseKey.substring(0,8)}...`),a.tier&&S.log.info(`Tier: ${F.bold(a.tier)}`),a.type&&S.log.info(`Type: ${a.type}`),S.log.info(`Activated: ${new Date(a.activatedAt).toLocaleString()}`),S.outro(F.cyan("You are ready to use premium features.")));else throw new Error("License key not found in config.")}catch{t||(S.log.warn(F.yellow("No active license found locally.")),S.log.message(F.dim("Run `nebutra license activate <key>` to unlock premium features.")),S.outro("")),process.exit(c.NOT_FOUND)}}function cn(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 Go(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await Mo(n)})}import{existsSync as ln,readFileSync as Vo,writeFileSync as Ko}from"fs";import{dirname as zo,join as un,parse as Yo}from"path";import*as ze from"@clack/prompts";function Wo(e){let t=e,{root:n}=Yo(t);for(;;){if(ln(un(t,"package.json")))return t;if(t===n)return null;let r=zo(t);if(r===t)return null;t=r}}function qo(e){if(!ln(e))return{};try{let t=JSON.parse(Vo(e,"utf-8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function Ho(e,t){Ko(e,JSON.stringify(t,null,2)+`
|
|
441
|
+
`)}async function Jo(e,t){let n=t.format==="json",r=Wo(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 ze.text({message:"Project ID to link to:",placeholder:"proj_abc123",validate:m=>m&&m.trim().length>0?void 0:"Project ID cannot be empty"});ze.isCancel(d)&&(l.warn("Cancelled"),process.exit(c.CANCELLED)),o=String(d).trim()}let a=un(r,"nebutra.config.json"),s={...qo(a),projectId:o};Ho(a,s),n?console.log(JSON.stringify({command:"link",success:!0,projectId:o,configPath:a},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 Jo(t,{yes:o.yes||!1,format:n.format||o.format})})}import{existsSync as mn,rmSync as Zo,unlinkSync as Xo}from"fs";import{homedir as pn,platform as Qo}from"os";import{join as xe}from"path";function ea(){if(Qo()==="win32"){let t=process.env.LOCALAPPDATA||xe(pn(),"AppData","Local");return xe(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?xe(e,"nebutra"):xe(pn(),".config","nebutra")}var ta=["auth.json","session.json","token","credentials.json"];async function na(e){let t=ea(),n=e.format==="json",r=0,o=[];if(e.all){if(mn(t))try{Zo(t,{recursive:!0,force:!0}),r=1,o.push(t)}catch(a){let i=a instanceof Error?a.message:String(a);n?console.log(JSON.stringify({command:"logout",success:!1,error:i},null,2)):l.error(`Failed to clear config directory: ${i}`),process.exit(c.PERMISSION_DENIED)}}else for(let a of ta){let i=xe(t,a);if(mn(i))try{Xo(i),r++,o.push(i)}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 fn(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 na({all:t.all||!1,format:t.format||r.format})})}import{spawn as ra}from"child_process";import{dirname as oa,resolve as aa}from"path";import{fileURLToPath as ia}from"url";import*as V from"@clack/prompts";import Z from"picocolors";var sa=oa(ia(import.meta.url));function ca(){let e=[()=>aa(sa,"../../../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 gn(e){e.command("mcp").description("Start the Nebutra MCP server for Cursor/Windsurf").option("--stdio","Use stdio transport (default)",!0).action(async t=>{V.intro(Z.bgCyan(Z.black(" nebutra mcp ")));try{let n=ca();V.log.info(Z.cyan("Starting Nebutra MCP server for Cursor/Windsurf integration...")),V.log.info(Z.dim(`Press Ctrl+C to stop the server.
|
|
442
|
+
`));let r=ra(process.execPath,[n],{stdio:"inherit",env:{...process.env}});r.on("close",o=>{o===0?V.outro(Z.green("MCP server stopped gracefully.")):o===null&&V.outro(Z.yellow("MCP server terminated.")),process.exit(o??0)}),r.on("error",o=>{l.error(`
|
|
443
|
+
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",()=>{V.log.info(Z.yellow(`
|
|
445
|
+
Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{V.log.info(Z.yellow("Terminating MCP server...")),r.kill("SIGTERM")})}catch(n){V.log.error(Z.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 I from"@clack/prompts";import U from"picocolors";var bn=Object.fromEntries(Object.entries(kt).map(([e,t])=>[e,t]));function hn(e){return typeof e=="boolean"?"boolean":"string"}function vn(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:hn(n.default)})),examples:e.examples||[]}}function la(e){let n=(W.subcommands||[]).find(r=>r.name===e);return n?vn(n):null}function ua(){return(W.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:hn(e.default)}))}function da(e){let t=W.subcommands||[];return{name:W.name,version:e,description:W.description,usage:W.usage||"nebutra [command] [options]",globalOptions:ua(),commands:t.map(vn),exitCodes:bn,timestamp:new Date().toISOString()}}function yn(){return(W.subcommands||[]).map(t=>t.name)}function Ye(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
446
|
+
`)}function ma(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function pa(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(Ye(da(r)),process.exit(0)),t.list===!0&&(Ye(yn()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(Ye(bn),process.exit(0)),e){let o=la(e);o||(n||(l.error(`Unknown command '${e}'`),l.info(`Available commands: ${yn().join(", ")}`)),process.exit(c.NOT_FOUND)),Ye(o),process.exit(0)}n||(I.intro(U.bgCyan(U.black(" nebutra schema "))),I.log.info(U.cyan("Agent-friendly introspection of CLI commands, arguments, and value domains.")),I.log.message(""),I.log.info(U.bold("Usage:")),I.log.message(U.dim(" nebutra schema --all Show full command tree as JSON")),I.log.message(U.dim(" nebutra schema <command> Show schema for a specific command")),I.log.message(U.dim(" nebutra schema --list List available command names")),I.log.message(U.dim(" nebutra schema --exit-codes Show exit codes reference")),I.log.message(""),I.log.info(U.bold("Example:")),I.log.message(U.dim(" nebutra schema status")),I.log.message(U.dim(" nebutra schema --all | jq '.commands[0]'")),I.outro(U.cyan("All output is JSON for easy parsing by agents and automation tools."))),process.exit(0)}catch(o){if(ma(o))throw o;n||l.error(o instanceof Error?o.message:String(o)),process.exit(c.ERROR)}}function Cn(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 pa(t,n)})}import{stdin as ke}from"process";import*as We from"@clack/prompts";import R from"picocolors";async function fa(){return new Promise((e,t)=>{let n="";ke.setEncoding("utf8"),ke.on("readable",()=>{let r;for(;(r=ke.read())!==null;)n+=r}),ke.on("end",()=>{e(n.trim())}),ke.on("error",t)})}async function ga(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")h(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 ya(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 fa()}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 ba(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"?h(o,{format:"json"}):u(`${R.cyan(e)}: ${r}`,"info")}async function ha(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 We.confirm({message:`Rotate encryption key for ${R.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});(We.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 va(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")h(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 Ca(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")h(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 wn(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 a=o.optsWithGlobals?.(),i={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:o.format||a?.format,tenant:o.tenant||a?.tenant,unmask:o.unmask||!1,description:o.description,value:o.value,since:o.since,limit:o.limit??50};try{switch(n){case"list":await ga(i);break;case"set":r.length===0&&(u("set requires a secret key: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS)),await ya(r[0],i);break;case"get":r.length===0&&(u("get requires a secret key: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),await ba(r[0],i);break;case"rotate":r.length===0&&(u("rotate requires a secret key: nebutra secrets rotate <key>","error"),process.exit(c.INVALID_ARGS)),await ha(r[0],i);break;case"audit":await va(i);break;case"verify":await Ca(i);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"),C("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
755
447
|
Examples:
|
|
756
448
|
nebutra secrets list List all secrets (metadata only)
|
|
757
449
|
nebutra secrets list --tenant org_456 List secrets for specific tenant
|
|
@@ -786,7 +478,7 @@ Security Notes:
|
|
|
786
478
|
- Never use --value in production (visible in shell history)
|
|
787
479
|
- Always use --unmask when viewing secrets in scripts
|
|
788
480
|
- Audit log tracks all access and modifications
|
|
789
|
-
`)}import*as
|
|
481
|
+
`)}import*as qe from"@clack/prompts";import _ from"picocolors";function Sn(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function wa(e){switch(e){case"running":return _.green("\u25CF");case"exited":return _.red("\u25CF");case"restarting":return _.yellow("\u25CF");case"paused":return _.gray("\u25CF");default:return _.gray("\u25CF")}}async function Sa(e){u("Checking service status...","info");let t=await k({command:"docker",args:["compose","ps","--format","json"],cwd:b(),interactive:!1,label:"Docker Compose PS",dryRun:e.dryRun});t.exitCode!==0&&(u("Failed to fetch service status","error"),C("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:Sn(o.State),exitCode:o.ExitCode}));h(r,{format:"json"})}else{u("Service Status","info");let r=n.map(o=>({Service:wa(Sn(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"),C("Parse error",{error:String(n)}),process.exit(c.ERROR)}}async function Ea(e,t){u(`Streaming logs for ${_.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 k({command:"docker",args:n,cwd:b(),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 Ra(e,t){let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let a=await qe.confirm({message:`Restart service ${_.cyan(e)}?`,initialValue:!1});(qe.isCancel(a)||!a)&&(u("Restart cancelled","warn"),process.exit(c.CANCELLED))}u(`Restarting service ${_.cyan(e)}...`,"info");let r=["compose","restart"];t.timeout&&r.push("--timeout",String(t.timeout)),r.push(e);let o=await k({command:"docker",args:r,cwd:b(),interactive:!1,label:`Docker Compose Restart (${e})`,dryRun:t.dryRun});o.exitCode===0?u(`Service ${_.cyan(e)} restarted successfully`,"success"):(u(`Failed to restart service ${e}`,"error"),C("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}async function xa(e){u("Running deep health check...","info");let t=[],n=await k({command:"docker",args:["compose","exec","-T","postgres","pg_isready"],cwd:b(),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 k({command:"docker",args:["compose","exec","-T","redis","redis-cli","ping"],cwd:b(),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 k({command:"docker",args:["compose","exec","-T","clickhouse","curl","-s","http://localhost:8123/ping"],cwd:b(),interactive:!1,label:"ClickHouse Health",dryRun:e.dryRun});t.push({service:"ClickHouse",healthy:o.exitCode===0,message:o.exitCode===0?"Ready":"Not responding"});let a=await k({command:"docker",args:["compose","exec","-T","meilisearch","curl","-s","http://localhost:7700/health"],cwd:b(),interactive:!1,label:"Meilisearch Health",dryRun:e.dryRun});if(t.push({service:"Meilisearch",healthy:a.exitCode===0,message:a.exitCode===0?"Healthy":"Not responding"}),e.format==="json")h(t,{format:"json"});else{for(let s of t){let d=s.healthy?_.green("\u2713"):_.red("\u2716");u(`${d} ${s.service}: ${s.message}`,s.healthy?"success":"error")}let i=t.every(s=>s.healthy);u(`Overall health: ${i?_.green("HEALTHY"):_.red("UNHEALTHY")}`,i?"success":"error")}}async function ka(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 ${_.cyan(e)} to ${_.cyan(String(r))} replicas...`,"info");let o=await k({command:"docker",args:["compose","up","-d","--scale",`${e}=${r}`],cwd:b(),interactive:!1,label:`Docker Compose Scale (${e})`,dryRun:n.dryRun});o.exitCode===0?u(`Service ${_.cyan(e)} scaled to ${r} replicas`,"success"):(u(`Failed to scale service ${e}`,"error"),C("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}function En(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 a=o.optsWithGlobals?.(),i={dryRun:o.dryRun||a?.dryRun,yes:o.yes||a?.yes,format:o.format||a?.format,tail:o.tail??100,since:o.since,timeout:o.timeout};try{switch(n){case"status":await Sa(i);break;case"logs":r.length===0&&(u("logs requires a service name: nebutra services logs <service>","error"),process.exit(c.INVALID_ARGS)),await Ea(r[0],i);break;case"restart":r.length===0&&(u("restart requires a service name: nebutra services restart <service>","error"),process.exit(c.INVALID_ARGS)),await Ra(r[0],i);break;case"health":await xa(i);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 ka(r[0],r[1],i);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"),C("Full error",{error:s}),process.exit(c.ERROR)}}).addHelpText("after",`
|
|
790
482
|
Examples:
|
|
791
483
|
nebutra services status Show all service status
|
|
792
484
|
nebutra services logs postgres Stream postgres logs
|
|
@@ -807,97 +499,24 @@ Flags:
|
|
|
807
499
|
--tail <n> Log lines to show (default: 100)
|
|
808
500
|
--since <duration> Show logs since (e.g., 10m, 1h)
|
|
809
501
|
--timeout <seconds> Timeout for restart
|
|
810
|
-
`)}import{existsSync as
|
|
811
|
-
|
|
812
|
-
`),
|
|
813
|
-
|
|
814
|
-
`),r.forEach(a=>{let i=a.status==="ready"?Ke.green("\u2713"):Ke.gray("\u25CB");console.log(` ${i} ${Ke.blue(a.name)}`),a.version&&console.log(` version: ${a.version}`),a.description&&console.log(` ${a.description}`),console.log(` files: ${a.files}`)}),console.log(""))}function Xr(e){let t=e.command("stats").description("Project statistics and health checks");t.command("*",{isDefault:!0}).description("Show monorepo overview").option("--format <type>","Output format: json or plain").action(async n=>{let r=typeof n.optsWithGlobals=="function"?n.optsWithGlobals():n;await ul({format:typeof n.format=="string"?n.format:typeof r.format=="string"?r.format:void 0})}),t.command("size").description("Analyze bundle and package sizes").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await ml({format:n.format||r.format})}),t.command("deps").description("Analyze dependencies (unused, missing, duplicate)").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await pl({format:n.format||r.format})}),t.command("packages").description("List all packages with metadata").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await fl({format:n.format||r.format})}),t.command("apps").description("List all apps with status").option("--format <type>","Output format: json or plain").action(async n=>{let r=n.optsWithGlobals?.()||n;await gl({format:n.format||r.format})})}import*as K from"@clack/prompts";import $ from"picocolors";function xe(e){if(e==="json"||e==="plain"||e==="table")return e}var on=["landing","web","storybook","backends/gateway","design-docs","studio","docs","ui","tokens","brand","theme","icons","preset","queue","search","notifications","permissions","webhooks","metering","uploads","vault","tenant"];function yl(e){let t=`@nebutra/${e}`;if(!on.includes(e)){let n=$.yellow(`Valid apps: ${on.join(", ")}`);throw new Error(`Invalid app: ${$.red(e)}
|
|
815
|
-
|
|
816
|
-
`)}function
|
|
817
|
-
`)}
|
|
818
|
-
`)}function
|
|
819
|
-
`)}function Pl(e){ln(e),process.exit(e.exitCode)}function dn(e,t){Pl(at({error:"not_found",message:e,suggestion:t??"Check the resource path and try again",exitCode:c.NOT_FOUND}))}function Ut(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??Il()}function Il(){let e=process.argv.find(n=>n.startsWith("--format="));if(e)return e.slice(9);let t=process.argv.indexOf("--format");if(t>=0)return process.argv[t+1]}function mn(e){let t=e.opts?e.opts():e;return{root:h(),manifestPath:t.manifest}}function go(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function Nl(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(`
|
|
820
|
-
`)}return JSON.stringify(e,null,2)}function $l(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(`
|
|
821
|
-
`):JSON.stringify(e,null,2)}function Tl(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(`
|
|
502
|
+
`)}import{existsSync as Rn,readFileSync as xn}from"fs";import{dirname as ja,join as ft,parse as Ta}from"path";import de from"picocolors";import{stderr as Oa}from"process";import re from"picocolors";function Aa(){return process.stderr.isTTY===!0&&!process.env.CI&&!process.env.NEBUTRA_NON_TTY}function Ia(e){let t=[];return t.push(re.red(`\u2716 ${e.error}`)),t.push(re.white(e.message)),e.suggestion&&(t.push(""),t.push(re.cyan("\u{1F4A1} Suggestion:")),t.push(re.gray(` ${e.suggestion}`))),process.env.NEBUTRA_DEBUG&&e.context&&Object.keys(e.context).length>0&&(t.push(""),t.push(re.dim("Debug context:")),t.push(re.dim(JSON.stringify(e.context,null,2)))),process.env.NEBUTRA_DEBUG&&e.stack&&(t.push(""),t.push(re.dim("Stack trace:")),t.push(re.dim(e.stack))),t.join(`
|
|
503
|
+
`)}function _a(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 Oe(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 dt(e){let t=Aa()?Ia(e):_a(e);Oa.write(t+`
|
|
504
|
+
`)}function Na(e){dt(e),process.exit(e.exitCode)}function mt(e,t){Na(Oe({error:"not_found",message:e,suggestion:t??"Check the resource path and try again",exitCode:c.NOT_FOUND}))}var oe=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 Pa(e){return e instanceof oe}function $a(e){return Pa(e)?Oe({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?Oe({error:"unexpected_error",message:e.message,suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:c.ERROR,cause:e}):Oe({error:"unexpected_error",message:String(e),suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:c.ERROR})}function pt(e){let t=$a(e);return dt(t),t.exitCode}async function Ae(e){try{await e()}catch(t){process.exitCode=pt(t)}}var Da={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 La(e){let t=e,{root:n}=Ta(t);for(;;){if(Rn(ft(t,"nebutra.config.json")))return t;if(t===n)return null;let r=ja(t);if(r===t)return null;t=r}}function Fa(e){let t=xn(e,"utf-8"),n=JSON.parse(t);if(!n||typeof n!="object"||Array.isArray(n))throw new oe({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 Ua(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,a=o.indexOf("=");if(a===-1)continue;let i=o.slice(0,a).trim();if(!i)continue;let s=o.slice(a+1).trim();(s.startsWith('"')&&s.endsWith('"')&&s.length>=2||s.startsWith("'")&&s.endsWith("'")&&s.length>=2)&&(s=s.slice(1,-1)),t[i]=s}return t}function Ba(e){let t={...process.env};for(let n of[".env",".env.local"]){let r=ft(e,n);if(Rn(r))try{let o=Ua(xn(r,"utf-8"));for(let[a,i]of Object.entries(o))process.env[a]===void 0&&(t[a]=i)}catch{}}return t}function Ga(e,t,n){let r=[],o=[];for(let a of t.providers){let i=a.envKeys.filter(s=>!n[s]);i.length===0?r.push(a.id):o.length===0&&a.envKeys.length>0&&(o=i)}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 Ma(e,t){switch(e){case"live":return de.green(t);case"local-fallback":return de.yellow(t);case"missing-key":return de.red(t);default:return t}}async function Va(e){let t=La(process.cwd());if(!t)throw new oe({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=Fa(n),o=Array.isArray(r.capabilities)?r.capabilities:[],a=Ba(t),i=a.NEBUTRA_LOCALE||"global",s=typeof r.stack=="string"?r.stack:"unknown",d=o.map(f=>{let v=Da[f];return v?Ga(f,v,a):{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"){h({stack:s,locale:i,capabilities:d},{format:"json"});return}let p=[];p.push(de.bold("nebutra status")),p.push(de.dim(`stack: ${s} locale: ${i} project: ${t}`)),p.push("");let g=Math.max(10,...d.map(f=>f.name.length)),E=Math.max(14,...d.map(f=>f.state.length));for(let f of d){let v=f.name.padEnd(g),B=Ma(f.state,f.state.padEnd(E)),K=f.provider.length>0?f.provider.join(", "):"-";p.push(`${v} ${B} ${de.dim(K)}`),f.state!=="live"&&p.push(`${" ".repeat(g)} ${de.dim(`\u2192 ${f.next}`)}`)}console.log(p.join(`
|
|
505
|
+
`))}function kn(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)=>Ae(async()=>{let r=n.optsWithGlobals?n.optsWithGlobals():{};await Va({json:t.json,format:r.format})}))}import*as N from"@clack/prompts";import x from"picocolors";function ae(e){if(e==="json"||e==="plain"||e==="table")return e}var gt=["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 Ka(e){let t=`@nebutra/${e}`;if(!gt.includes(e)){let n=x.yellow(`Valid apps: ${gt.join(", ")}`);throw new Error(`Invalid app: ${x.red(e)}
|
|
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
|
+
`)}function Ja(e,t="table"){let n=bt(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(`
|
|
508
|
+
`)}function Pn(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(Ha(Nn(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=Ja(n,Nn(r));o||(l.error(`Design language '${n}' not found. Run: nebutra theme list`),process.exit(c.NOT_FOUND)),console.log(o)})}import{existsSync as Tn,readFileSync as Dn}from"fs";import{resolve as $n,join as ht}from"path";function Ln(e={}){let t=e.manifestPath?$n(e.manifestPath):ht($n(e.root??process.cwd()),"apps","design-docs","public","agent-manifest.json");return{manifestPath:t,componentDir:ht(t,"..","agent","components")}}function Za(e){return e.trim().toLowerCase()}function Xa(e){let t=Za(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 Fn(e={}){let{manifestPath:t}=Ln(e);if(!Tn(t))throw new Error(`Missing Nebutra UI agent manifest at ${t}. Run pnpm --filter @nebutra/design-docs build:registry.`);return JSON.parse(Dn(t,"utf8"))}function vt(e,t={}){let n=Xa(e),{componentDir:r}=Ln(t),o=ht(r,`${n}.json`);if(!Tn(o))throw new Error(`UI component contract not found: ${n}`);return JSON.parse(Dn(o,"utf8"))}function Un(e,t="",n={}){let r=t.trim().toLowerCase(),o=jn(n.limit??20,1,100),a=jn(n.offset??0,0,Number.MAX_SAFE_INTEGER),i=n.tag?.trim().toLowerCase(),s=e.components.filter(p=>n.status&&p.status!==n.status||n.maturity&&p.maturity!==n.maturity||i&&!p.tags.includes(i)?!1:r?Qa(p).includes(r):!0).map(p=>({component:p,score:ei(p,r)})).sort((p,g)=>g.score-p.score||p.component.name.localeCompare(g.component.name)).map(({component:p})=>p),d=s.slice(a,a+o),m=a+d.length;return{query:t,total:s.length,count:d.length,offset:a,limit:o,hasMore:m<s.length,...m<s.length&&{nextOffset:m},items:d}}function Ct(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 Qa(e){return[e.name,e.title,e.description,e.status,e.maturity,e.layer,e.source,...e.tags].join(" ").toLowerCase()}function ei(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 jn(e,t,n){return Number.isFinite(e)?Math.min(Math.max(Math.trunc(e),t),n):t}function He(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??ti()}function ti(){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 St(e){let t=e.opts?e.opts():e;return{root:b(),manifestPath:t.manifest}}function Bn(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function ni(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(`
|
|
509
|
+
`)}return JSON.stringify(e,null,2)}function ri(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(`
|
|
510
|
+
`):JSON.stringify(e,null,2)}function oi(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(`
|
|
822
511
|
`)}return[`${e.name}: ${e.valid?"valid":"invalid"}`,...e.errors.map(n=>`error: ${n}`),...e.warnings.map(n=>`warning: ${n}`)].join(`
|
|
823
|
-
`)}return JSON.stringify(e,null,2)}function
|
|
824
|
-
`):JSON.stringify(n,null,2)}function
|
|
825
|
-
`),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):s.success("Unlinked from project")}function wo(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 Vl({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as td}from"child_process";import{promises as jt}from"fs";import{homedir as Kl}from"os";import{join as So}from"path";import ql from"p-timeout";import Ae from"picocolors";var zl=1440*60*1e3,Co=So(Kl(),".nebutra"),pn=So(Co,"update-check.json"),Yl="https://registry.npmjs.org/nebutra",Hl=5e3;async function Wl(){try{await jt.mkdir(Co,{recursive:!0})}catch{}}async function Jl(){try{let e=await jt.readFile(pn,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<zl?t:(await jt.unlink(pn).catch(r=>{s.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function Xl(e){try{await Wl();let t={timestamp:Date.now(),latestVersion:e};await jt.writeFile(pn,JSON.stringify(t,null,2),"utf-8")}catch{}}async function Ql(){try{let e=new AbortController,t=await ql(fetch(Yl,{signal:e.signal,headers:{Accept:"application/json"}}),{milliseconds:Hl,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 Ro(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function Zl(e,t){let n=Ro(e),r=Ro(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 fn(e){let t=await Jl(),n=null;return t?n=t.latestVersion:(n=await Ql(),n&&await Xl(n)),!n||!Zl(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function ed(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=[Ae.cyan("\u256D"+"\u2500".repeat(41)+"\u256E"),Ae.cyan("\u2502")+Ae.yellow(o+n+o)+Ae.cyan("\u2502"),Ae.cyan("\u2502")+Ae.gray(a+r+a)+Ae.cyan("\u2502"),Ae.cyan("\u2570"+"\u2500".repeat(41)+"\u256F")]}async function Eo(e){let t=null;return fn(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&ed(t))}}function nd(){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 rd(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"}}var je="0.1.0";async function od(e){let t=nd(),n=rd(t),r=e.format==="json",o=await fn(je),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:je,latestVersion:a,hasUpdate:i},null,2)):(s.info(`Detected installer: ${t}`),s.info(`Current: ${je}${a?` \u2192 Latest: ${a}`:""}`),s.info(`Upgrade command: ${n}`)),process.exit(c.DRY_RUN_OK)),!i&&a&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,alreadyLatest:!0,version:je},null,2)):s.success(`Already on the latest version (${je})`),process.exit(c.SUCCESS)),e.yes||(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,command_to_run:n,currentVersion:je,latestVersion:a,requiresConfirmation:!0},null,2)):(s.info(`Current: ${je}${a?` \u2192 Latest: ${a}`:""}`),s.info("To upgrade, run:"),s.info(` ${n}`),s.info("Or re-run this command with --yes to execute it now.")),process.exit(c.SUCCESS));let[l,...u]=n.split(" ");r||s.info(`Running: ${n}`);let m=td(l,u,{stdio:r?"pipe":"inherit"});m.status===0&&(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,ran:n},null,2)):s.success("Upgrade complete"),process.exit(c.SUCCESS));let f=m.stderr?.toString()||`Upgrade failed (exit ${m.status})`;r?console.log(JSON.stringify({command:"upgrade",success:!1,installer:t,ran:n,error:f},null,2)):s.error(f),process.exit(c.ERROR)}function ko(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return od({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 gn from"fs";import yn from"path";import sd from"picocolors";var hn=["inngest","n8n","pusher"],ad=`import { Inngest } from "inngest";
|
|
826
|
-
|
|
827
|
-
export const inngest = new Inngest({ id: "nebutra-sailor" });
|
|
828
|
-
|
|
829
|
-
export const exampleFn = inngest.createFunction(
|
|
830
|
-
{ id: "example-fn" },
|
|
831
|
-
{ event: "app/example.requested" },
|
|
832
|
-
async ({ event, step }) => {
|
|
833
|
-
await step.run("do-work", async () => {
|
|
834
|
-
return { ok: true, payload: event.data };
|
|
835
|
-
});
|
|
836
|
-
return { status: "completed" };
|
|
837
|
-
},
|
|
838
|
-
);
|
|
839
|
-
`,id=`# n8n Workflows (Self-hosted Convention)
|
|
840
|
-
|
|
841
|
-
Nebutra Sailor uses n8n in self-hosted mode for visual workflow orchestration.
|
|
842
|
-
|
|
843
|
-
## Convention
|
|
844
|
-
|
|
845
|
-
- Each workflow is exported as a JSON file in this directory: \`workflows/n8n/*.json\`
|
|
846
|
-
- File naming: \`<domain>.<verb>.json\` (e.g. \`billing.invoice-paid.json\`)
|
|
847
|
-
- Credentials live in n8n's encrypted store \u2014 never inline secrets in the JSON
|
|
848
|
-
- Import via n8n UI: Settings \u2192 Workflows \u2192 Import from File
|
|
849
|
-
|
|
850
|
-
## Running n8n locally
|
|
851
|
-
|
|
852
|
-
\`\`\`bash
|
|
853
|
-
docker run -it --rm \\
|
|
854
|
-
--name n8n \\
|
|
855
|
-
-p 5678:5678 \\
|
|
856
|
-
-v ~/.n8n:/home/node/.n8n \\
|
|
857
|
-
n8nio/n8n
|
|
858
|
-
\`\`\`
|
|
859
|
-
|
|
860
|
-
## Webhook endpoints
|
|
861
|
-
|
|
862
|
-
Production webhooks route through \`backends/gateway\` (see \`packages/integrations/webhooks\`).
|
|
863
|
-
`,cd=`{
|
|
864
|
-
"name": "example-workflow",
|
|
865
|
-
"nodes": [
|
|
866
|
-
{
|
|
867
|
-
"parameters": {},
|
|
868
|
-
"name": "Start",
|
|
869
|
-
"type": "n8n-nodes-base.start",
|
|
870
|
-
"typeVersion": 1,
|
|
871
|
-
"position": [240, 300]
|
|
872
|
-
}
|
|
873
|
-
],
|
|
874
|
-
"connections": {},
|
|
875
|
-
"active": false,
|
|
876
|
-
"settings": {},
|
|
877
|
-
"tags": []
|
|
878
|
-
}
|
|
879
|
-
`,ld=`import Pusher from "pusher";
|
|
880
|
-
|
|
881
|
-
export const pusher = new Pusher({
|
|
882
|
-
appId: process.env.PUSHER_APP_ID ?? "",
|
|
883
|
-
key: process.env.PUSHER_KEY ?? "",
|
|
884
|
-
secret: process.env.PUSHER_SECRET ?? "",
|
|
885
|
-
cluster: process.env.PUSHER_CLUSTER ?? "us2",
|
|
886
|
-
useTLS: true,
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
export async function publishExample(channel: string, event: string, data: unknown) {
|
|
890
|
-
if (!process.env.PUSHER_APP_ID) {
|
|
891
|
-
throw new Error("PUSHER_APP_ID not configured");
|
|
892
|
-
}
|
|
893
|
-
return pusher.trigger(channel, event, data);
|
|
894
|
-
}
|
|
895
|
-
`;function dd(e){switch(e){case"inngest":return[{relPath:"workflows/inngest/example.ts",content:ad}];case"n8n":return[{relPath:"workflows/n8n/README.md",content:id},{relPath:"workflows/n8n/example.json",content:cd}];case"pusher":return[{relPath:"workflows/pusher/example.ts",content:ld}]}}async function ud(e,t={}){hn.includes(e)||(s.error(`Invalid provider: ${sd.red(e)}. Valid: ${hn.join(", ")}`),process.exit(c.INVALID_ARGS));let n=h(),r=dd(e);t.dryRun&&(A({mode:"dry-run",command:`workflow init ${e}`,files:r.map(i=>({path:yn.join(n,i.relPath)}))}),process.exit(c.DRY_RUN_OK));let o=0,a=0;for(let i of r){let l=yn.join(n,i.relPath);if(gn.existsSync(l)){s.warn(`Skipping ${i.relPath} \u2014 already exists.`),a++;continue}gn.mkdirSync(yn.dirname(l),{recursive:!0}),gn.writeFileSync(l,i.content),t.quiet||s.success(`Created ${i.relPath}`),o++}o===0&&a>0&&(s.info(`No files created \u2014 ${e} scaffold already present.`),process.exit(c.CONFLICT)),process.exit(c.SUCCESS)}var xo=e=>{e.command("workflow").description("Manage workflow provider scaffolding (inngest | n8n | pusher)").command("init <provider>").description(`Scaffold a starter workflow file for a provider (${hn.join(" | ")})`).option("--dry-run","Preview files that would be created (exit code 10)").action(async(n,r,o)=>{let a=x(r,o);await ud(n,{dryRun:!!r.dryRun,quiet:!!a.quiet})})};var it=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 md(e){return e instanceof it}function pd(e){return md(e)?at({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?at({error:"unexpected_error",message:e.message,suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:c.ERROR,cause:e}):at({error:"unexpected_error",message:String(e),suggestion:"Re-run with NEBUTRA_DEBUG=1 for a stack trace.",exitCode:c.ERROR})}function bn(e){let t=pd(e);return ln(t),t.exitCode}async function vn(e){try{await e()}catch(t){process.exitCode=bn(t)}}import{existsSync as fd,mkdirSync as Ao,writeFileSync as _o}from"fs";import{homedir as Po,platform as gd}from"os";import{join as ct}from"path";var Oo={name:"Nebutra",nameCn:"\u4E91\u6BD3\u667A\u80FD",nameFull:"\u65E0\u9521\u4E91\u6BD3\u667A\u80FD\u79D1\u6280\u6709\u9650\u516C\u53F8",nameFullEn:"Wuxi Nebutra Intelligence Technology Co., Ltd.",tagline:"Ship AI products, not boilerplate.",taglineCn:"AI\u539F\u751F\xB7\u5FEB\u901F\u51FA\u6D77\xB7\u5373\u523B\u4EA4\u4ED8",description:"Production-ready Next.js monorepo template for AI SaaS products. Auth, billing, multi-tenancy, AI services, design system, and enterprise infrastructure \u2014 pre-configured.",descriptionCn:"\u9762\u5411AI\u521B\u4E1A\u8005\u7684\u4E00\u4F53\u5316SaaS\u57FA\u7840\u8BBE\u65BD\u6A21\u677F\uFF0C\u8986\u76D6\u8BA4\u8BC1\u3001\u8BA1\u8D39\u3001\u591A\u79DF\u6237\u3001AI\u670D\u52A1\u4E0E\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u5F00\u7BB1\u5373\u4EA7\u54C1",story:{concept:"Logo\u4EE5\u9996\u5B57\u6BCDN\u7684\u57FA\u7840\u9020\u578B\u6982\u5FF5\u4E3A\u4E3B\u8981\u8BBE\u8BA1\u6846\u67B6\uFF0C\u901A\u8FC7\u51E0\u4F55\u6B63\u8D1F\u7A7A\u95F4\u6784\u5EFA\u9690\u5F62'N'\uFF0C\u5F62\u6210\u8FD1\u4F3C\u516D\u8FB9\u5F62\u7684\u7A33\u5B9A\u7ED3\u6784",colorMeaning:"\u84DD\u7EFF\u6E10\u53D8\u4F53\u73B0\u672A\u6765\u611F\u4E0E\u79D1\u6280\u950B\u8292\uFF0C'\u4E91'\u4EE3\u8868\u4E91\u7AEF\u5E73\u53F0\uFF0C'\u6BD3'\u5BD3\u610F\u5B55\u80B2\u4E0E\u8F6C\u5316",values:["AI Native","Ship Fast","Open by Default","Global-Ready","Enterprise-Grade"],missionStatement:"Help AI founders and SaaS teams go from idea to production 10x faster by providing the infrastructure layer they shouldn't have to build."},domains:{landing:"nebutra.com",app:"app.nebutra.com",api:"api.nebutra.com",auth:"auth.nebutra.com",sso:"sso.nebutra.com",docs:"docs.nebutra.com",studio:"studio.nebutra.com",cdn:"cdn.nebutra.com",router:"router.nebutra.com",forge:"forge.nebutra.com",design:"design.nebutra.com",status:"status.nebutra.com",admin:"admin.nebutra.com",analytics:"analytics.nebutra.com",pebble:"pebble.nebutra.com",carina:"carina.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 yd(){if(gd()==="win32"){let t=process.env.LOCALAPPDATA||ct(Po(),"AppData","Local");return ct(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?ct(e,"nebutra"):ct(Po(),".config","nebutra")}function hd(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function Io(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=yd(),t=ct(e,"first-run-acked");try{if(fd(t))return}catch{return}if(hd()){try{Ao(e,{recursive:!0}),_o(t,"")}catch{}return}let n=[`\x1B[36m\u2139\x1B[0m ${Oo.name} collects anonymous usage analytics to improve the CLI.`," Opt out at any time: export NEBUTRA_TELEMETRY=0",` Privacy policy: ${Cn("landing")}/legal/cli-analytics`,""];try{process.stderr.write(n.join(`
|
|
896
|
-
`))}catch{}try{Ao(e,{recursive:!0}),_o(t,"")}catch{}}var Sd=wd(vd(wn(import.meta.url)),"..","package.json"),To=JSON.parse(bd(Sd,"utf8")).version;function Cd(e){let t=new Rd,n=e.isInteractive??(process.stdin.isTTY!==!1&&process.stdout.isTTY!==!1);return t.name("nebutra").description("Nebutra \u2014 governance-first CLI for topology scaffolding, registry features, and platform operations").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=>vn(async()=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Or({dryRun:r.dryRun||!1,yes:o.yes||!1,ifNotExists:r.ifNotExists||!1})})),t.command("add [components...]").description("Add a registry-backed platform feature or external UI component").option("--21st <id>","Fetch and install a component from 21st.dev").option("--v0 <url>","Fetch and install a component from v0.dev").option("--provider <id>","Specify a backend provider for a system feature (e.g. upstash)").option("--dry-run","Preview what would be installed without making changes (exit code 10)").option("--yes","Skip all interactive prompts and use defaults (Agent mode)").option("--if-not-exists","Skip installation if component already exists").action(async(r,o)=>{let a=o.optsWithGlobals?o.optsWithGlobals():o;await Ln(r,{...o,yes:a.yes||!n})}),cr(t),Lr(t),Gr(t),er(t),kr(t),xr(t),hr(t),Pr(t),zn(t),Yn(t),Qn(t),Xr(t),lr(t),Cr(t),dr(t),to(t),xo(t),Xn(t),pr(t),ao(t),ho(t),Mn(t),tr(t),Er(t),gr(t),Yr(t),Kr(t),qr(t),ir(t),jr(t),ko(t),$r(t),wo(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(()=>vn(async()=>{let{logger:r}=await import("./logger-WOLJCPZK.js"),{findMonorepoRoot:o}=await import("./delegate-7HQKV277.js"),a=await import("fs"),i=await import("path");r.info("Running project health check...");let l=!1,u=o(),m=process.version;parseInt(m.replace("v","").split(".")[0]??"0",10)<22?(r.error(`Node.js >= 22 required, found ${m}`),l=!0):r.success(`Node.js version OK (${m})`),a.existsSync(i.join(u,"nebutra.config.json"))?r.success("nebutra.config.json found"):r.warn("nebutra.config.json missing. Try running 'nebutra init'"),a.existsSync(i.join(u,"package.json"))?r.success("package.json found"):(r.error("No package.json found in root directory"),l=!0),a.existsSync(i.join(u,".env"))||a.existsSync(i.join(u,".env.local"))?r.success("Environment variables configured"):r.warn("No .env or .env.local found. Some features may not work properly.");let E=i.join(u,"apps/api-gateway");a.existsSync(E)&&r.warn("Legacy `apps/api-gateway/` present. Expected `backends/gateway/` \u2014 see CLAUDE.md for the W2.x restructure.");let D=i.join(u,"backends/gateway");a.existsSync(D)?r.success("backends/gateway/ present"):a.existsSync(i.join(u,"backends"));let F=i.join(u,"packages");if(a.existsSync(F)){let ue=new Set(["design","iam","commerce","integrations","platform","ops","ai"]);try{let _e=a.readdirSync(F,{withFileTypes:!0}),p=[];for(let B of _e){if(!B.isDirectory()||ue.has(B.name))continue;let Le=i.join(F,B.name,"package.json");a.existsSync(Le)&&p.push(B.name)}p.length>0?r.warn(`Found ${p.length} uncategorized package(s) under packages/: ${p.join(", ")}. Expected packages/<category>/<name>/ \u2014 see CLAUDE.md.`):r.success("Packages follow categorized layout")}catch{}}let q=i.join(u,".nebutra"),ye=i.join(q,"scaffold-meta.json");if(a.existsSync(ye)?r.success(".nebutra/scaffold-meta.json present (CLI-scaffolded project)"):a.existsSync(q)&&r.warn(".nebutra/ directory exists but scaffold-meta.json is missing. Harmless \u2014 the marker is provenance only and grants nothing."),l)throw new it({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",`
|
|
512
|
+
`)}return JSON.stringify(e,null,2)}function ai(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(`
|
|
513
|
+
`):JSON.stringify(n,null,2)}function wt(e,t){try{return vt(e,St(t))}catch{mt(`UI component contract not found: ${e}`,"Run `nebutra ui search <query> --format json` to discover available component ids.")}}function Gn(e){try{return Fn(St(e))}catch(t){mt(t instanceof Error?t.message:"UI agent manifest not found","Run `pnpm --filter @nebutra/design-docs build:registry` from the Nebutra monorepo.")}}function ii(e,t){let n=e.components.map(o=>Ct(vt(o.name,St(t)))),r=n.filter(o=>!o.valid).length;return{valid:r===0,total:n.length,invalid:r,results:n}}function Mn(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=Gn(r),a=Un(o,n??"",{limit:Bn(r.limit,20),offset:Bn(r.offset,0),tag:r.tag,status:r.status,maturity:r.maturity});console.log(ni(a,He(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=wt(n,r);console.log(ri(o,He(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?Ct(wt(n,r)):ii(Gn(r),r);console.log(oi(o,He(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=wt(n,r);console.log(ai(o,He(r)))})}import{existsSync as Vn,readFileSync as si,unlinkSync as ci,writeFileSync as li}from"fs";import{dirname as ui,join as Kn,parse as di}from"path";function mi(e){let t=e,{root:n}=di(t);for(;;){if(Vn(Kn(t,"package.json")))return t;if(t===n)return null;let r=ui(t);if(r===t)return null;t=r}}async function pi(e){let t=e.format==="json",n=mi(process.cwd())??process.cwd(),r=Kn(n,"nebutra.config.json");if(Vn(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{ci(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(si(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:a,...i}=o;li(r,JSON.stringify(i,null,2)+`
|
|
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{}nr(e,t)}var sr=Je();function Gi(e){let t=new Bi,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=>Ae(async()=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await on({dryRun:r.dryRun||!1,yes:o.yes||!1,ifNotExists:r.ifNotExists||!1})})),gn(t),Cn(t),$t(t),nn(t),rn(t),Ht(t),cn(t),Nt(t),Vt(t),tn(t),Kt(t),_n(t),Wt(t),Pn(t),Mn(t),En(t),wn(t),Ut(t),fn(t),Xn(t),dn(t),zn(t),kn(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(()=>Ae(async()=>{let{logger:r}=await import("./logger-QMYN56HK.js"),{findMonorepoRoot:o}=await import("./delegate-GIJ3G5CK.js"),a=await import("fs"),i=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})`),a.existsSync(i.join(d,"nebutra.config.json"))?r.success("nebutra.config.json found"):r.warn("nebutra.config.json missing. Try running 'nebutra init'"),a.existsSync(i.join(d,"package.json"))?r.success("package.json found"):(r.error("No package.json found in root directory"),s=!0),a.existsSync(i.join(d,".env"))||a.existsSync(i.join(d,".env.local"))?r.success("Environment variables configured"):r.warn("No .env or .env.local found. Some features may not work properly.");let E=i.join(d,"apps/api-gateway");a.existsSync(E)&&r.warn("Legacy `apps/api-gateway/` present. Expected `backends/gateway/` \u2014 see CLAUDE.md for the W2.x restructure.");let f=i.join(d,"backends/gateway");a.existsSync(f)?r.success("backends/gateway/ present"):a.existsSync(i.join(d,"backends"));let v=i.join(d,"packages");if(a.existsSync(v)){let X=new Set(["design","iam","commerce","integrations","platform","ops","ai"]);try{let be=a.readdirSync(v,{withFileTypes:!0}),z=[];for(let pe of be){if(!pe.isDirectory()||X.has(pe.name))continue;let _e=i.join(v,pe.name,"package.json");a.existsSync(_e)&&z.push(pe.name)}z.length>0?r.warn(`Found ${z.length} uncategorized package(s) under packages/: ${z.join(", ")}. Expected packages/<category>/<name>/ \u2014 see CLAUDE.md.`):r.success("Packages follow categorized layout")}catch{}}let B=i.join(d,".nebutra"),K=i.join(B,"scaffold-meta.json");if(a.existsSync(K)?r.success(".nebutra/scaffold-meta.json present (CLI-scaffolded project)"):a.existsSync(B)&&r.warn(".nebutra/ directory exists but scaffold-meta.json is missing. Harmless \u2014 the marker is provenance only and grants nothing."),(a.existsSync(K)||a.existsSync(i.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 oe({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",`
|
|
897
516
|
Examples:
|
|
898
517
|
$ nebutra init Initialize a new project
|
|
899
|
-
$ nebutra
|
|
900
|
-
$ nebutra
|
|
518
|
+
$ nebutra status Show capability readiness (live/local-fallback/missing-key)
|
|
519
|
+
$ nebutra status --json Machine-readable capability status
|
|
901
520
|
$ nebutra dev --app=web Start dev for the web app
|
|
902
521
|
$ nebutra db migrate Run pending database migrations
|
|
903
522
|
$ nebutra generate app blog Scaffold a new app
|
|
@@ -906,22 +525,10 @@ Examples:
|
|
|
906
525
|
$ nebutra theme inspect nebutra Inspect a theme governance manifest
|
|
907
526
|
$ nebutra infra up --lite Start PostgreSQL + Redis
|
|
908
527
|
$ nebutra test e2e Run Playwright E2E tests
|
|
909
|
-
$ nebutra stats Monorepo overview
|
|
910
528
|
$ nebutra schema --all Full CLI schema (for Agents)
|
|
911
529
|
|
|
912
|
-
Platform
|
|
913
|
-
$ nebutra admin tenants List all tenants
|
|
914
|
-
$ nebutra admin health Platform-wide health check
|
|
915
|
-
$ nebutra community health --period 30d Community health score
|
|
916
|
-
$ nebutra community showcase list Browse project showcase
|
|
917
|
-
$ nebutra growth dashboard Growth metrics overview
|
|
918
|
-
$ nebutra growth funnel --segment paid Conversion funnel by segment
|
|
919
|
-
$ nebutra growth pulse --focus retention AI growth insights
|
|
920
|
-
$ nebutra ecosystem status Ecosystem overview dashboard
|
|
921
|
-
$ nebutra ecosystem publish --tag latest Publish to template marketplace
|
|
922
|
-
$ nebutra ecosystem ideas list Browse ideas marketplace
|
|
530
|
+
Platform:
|
|
923
531
|
$ nebutra services status Microservice health overview
|
|
924
|
-
$ nebutra search reindex products Reindex search index
|
|
925
532
|
$ nebutra secrets list --tenant org_123 List encrypted secrets
|
|
926
533
|
|
|
927
534
|
Exit Codes:
|
|
@@ -938,4 +545,4 @@ Environment:
|
|
|
938
545
|
NEBUTRA_OUTPUT_FORMAT Output format (json|table|plain)
|
|
939
546
|
NO_COLOR Disable colored output
|
|
940
547
|
CI Auto-enable non-interactive mode
|
|
941
|
-
`),t}async function
|
|
548
|
+
`),t}async function Mi(){rr();let e=await Zn(sr),t=Gi({version:sr,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 Vi(){if(!process.argv[1])return!1;try{return or(ir(import.meta.url))===or(ar(process.argv[1]))}catch{return ir(import.meta.url)===ar(process.argv[1])}}var Ki=Vi();Ki&&Mi().catch(e=>{process.exitCode=pt(e)});export{Gi as buildProgram};
|