nebutra 0.1.1 → 0.3.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.
Files changed (49) hide show
  1. package/LICENSE +676 -0
  2. package/dist/chunk-I7AUKTXE.js +1 -0
  3. package/dist/delegate-YL6SAZNF.js +1 -0
  4. package/dist/index.js +323 -159
  5. package/dist/logger-KLED6BEE.js +1 -0
  6. package/package.json +16 -16
  7. package/dist/aws-kms-CYDJXAN2.js +0 -1
  8. package/dist/chunk-27HYVYB7.js +0 -1
  9. package/dist/chunk-7DCGNQSQ.js +0 -5
  10. package/dist/chunk-7HOF72FC.js +0 -1
  11. package/dist/chunk-7VJYOZUP.js +0 -2
  12. package/dist/chunk-A2KGYHAM.js +0 -1
  13. package/dist/chunk-B5RLHF2U.js +0 -40
  14. package/dist/chunk-DIXI4M5O.js +0 -1
  15. package/dist/chunk-ELIYZZ3E.js +0 -1
  16. package/dist/chunk-EXLRPVEX.js +0 -1
  17. package/dist/chunk-FGJ5K4WM.js +0 -1
  18. package/dist/chunk-FSRPMVAS.js +0 -1
  19. package/dist/chunk-HVYUAVRI.js +0 -9
  20. package/dist/chunk-LOQM6XQV.js +0 -1
  21. package/dist/chunk-M5MEP5J7.js +0 -20
  22. package/dist/chunk-OJM5Y4UT.js +0 -1
  23. package/dist/chunk-PXU2OOBT.js +0 -1
  24. package/dist/chunk-QEIMNOY2.js +0 -1
  25. package/dist/chunk-QMKVUKS6.js +0 -1
  26. package/dist/chunk-RR5R4AKJ.js +0 -1
  27. package/dist/chunk-SDX64WW4.js +0 -23
  28. package/dist/chunk-VOA5NGB4.js +0 -1
  29. package/dist/chunk-XSSPJU77.js +0 -1
  30. package/dist/credits-7QOXUUSW.js +0 -1787
  31. package/dist/delegate-AT4FVWBK.js +0 -1
  32. package/dist/dist-EDNC5USD.js +0 -5
  33. package/dist/dist-es-6FH6H7HO.js +0 -1
  34. package/dist/dist-es-7IMKW7US.js +0 -1
  35. package/dist/dist-es-GP7DK3S3.js +0 -5
  36. package/dist/dist-es-MB5QKMT4.js +0 -1
  37. package/dist/dist-es-MQVJCP43.js +0 -1
  38. package/dist/dist-es-ZA2NRM7G.js +0 -2
  39. package/dist/dist-es-ZN3KNHF5.js +0 -2
  40. package/dist/event-streams-T5RU6C4N.js +0 -1
  41. package/dist/loadSso-BNAQCJV4.js +0 -1
  42. package/dist/local-WW37QOXE.js +0 -1
  43. package/dist/logger-LKYUI2MJ.js +0 -1
  44. package/dist/query_compiler_fast_bg.postgresql-PN2AWLCP.js +0 -2
  45. package/dist/query_compiler_fast_bg.postgresql.wasm-base64-CASS54LO.js +0 -1
  46. package/dist/signin-S2JHPGGK.js +0 -1
  47. package/dist/src-N47JLVAD.js +0 -1
  48. package/dist/sso-oidc-CGZCRGZD.js +0 -1
  49. package/dist/sts-S4HBOJFJ.js +0 -6
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{b as s}from"./chunk-JDX5NXDX.js";import{a as R,b as A,c as _,d as pe,e as Oe,f as le}from"./chunk-LGUMYJ4Q.js";import{a as sr}from"./chunk-FSRPMVAS.js";import{Command as Ci}from"commander";import{execSync as ht}from"child_process";import{promises as we}from"fs";import V from"path";import*as S from"@clack/prompts";import Ne from"picocolors";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},Dt={[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 ar=`const featureEnvKeys = {{envKeysArray}} as const;
2
+ import{b as s}from"./chunk-JDX5NXDX.js";import{a as h,b as $,c as I,d as ge,e as $e,f as ue}from"./chunk-LGUMYJ4Q.js";import{a as eo}from"./chunk-I7AUKTXE.js";import{Command as $l}from"commander";import{execSync as Pt}from"child_process";import{promises as Ee}from"fs";import Y from"path";import*as R from"@clack/prompts";import Le from"picocolors";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},tn={[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"};import{existsSync as no,readdirSync as on,readFileSync as ro,statSync as oo}from"fs";import{dirname as rn,join as At,parse as so}from"path";import{fileURLToPath as ao}from"url";var to={"@nebutra/ui":"^0.1.0","@nebutra/tokens":"^0.1.0","@nebutra/icons":"^0.1.0","@nebutra/brand":"^0.1.0","@nebutra/design-tokens":"^0.1.0","@nebutra/design-sync":"^0.1.0","@nebutra/identity":"^0.1.0","@nebutra/tenant":"^0.1.0","@nebutra/permissions":"^0.1.0","@nebutra/vault":"^0.1.0","@nebutra/audit":"^0.1.0","@nebutra/billing":"^0.1.0","@nebutra/contracts":"^0.1.0","@nebutra/license":"^0.1.0","@nebutra/metering":"^0.1.0","@nebutra/queue":"^0.1.0","@nebutra/search":"^0.1.0","@nebutra/cache":"^0.1.0","@nebutra/notifications":"^0.1.0","@nebutra/webhooks":"^0.1.0","@nebutra/uploads":"^0.1.0","@nebutra/email":"^0.1.0","@nebutra/agents":"^0.1.0","@nebutra/mcp":"^0.1.0","@nebutra/logger":"^0.1.0"};function nn(e){return to[e]??null}var io=`const featureEnvKeys = {{envKeysArray}} as const;
3
3
 
4
4
  export const platformFeature = {
5
5
  name: "{{feature}}",
@@ -19,7 +19,7 @@ export function getFeatureProvider() {
19
19
  envKeys: featureEnvKeys,
20
20
  };
21
21
  }
22
- `,ir=`# {{feature}} Feature
22
+ `,co=`# {{feature}} Feature
23
23
 
24
24
  Installed by \`nebutra add {{feature}}\`.
25
25
 
@@ -31,7 +31,7 @@ Next steps:
31
31
  1. Set the required environment variables in \`{{envFile}}\`.
32
32
  2. Wire this starter into the generated package or app surface.
33
33
  3. Replace the placeholder helper with your production adapter.
34
- `;function xe(e){return[{path:`packages/${e}/src/index.ts`,content:ar},{path:`packages/${e}/README.md`,content:ir}]}var Lt={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/queue/src/index.ts",content:`const queueEnvKeys = {{envKeysArray}} as const;
34
+ `,lo="integrations";function Pe(e,t=lo){let n=`packages/${t}/${e}`;return[{path:`${n}/src/index.ts`,content:io},{path:`${n}/README.md`,content:co}]}var uo={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
35
 
36
36
  export const queueFeature = {
37
37
  name: "queue",
@@ -51,7 +51,7 @@ export function getQueueProvider() {
51
51
  envKeys: queueEnvKeys,
52
52
  };
53
53
  }
54
- `},{path:"packages/queue/README.md",content:`# Queue Feature
54
+ `},{path:"packages/integrations/queue/README.md",content:`# Queue Feature
55
55
 
56
56
  Installed by \`nebutra add queue\`.
57
57
 
@@ -63,7 +63,7 @@ Next steps:
63
63
  1. Set the required environment variables in \`{{envFile}}\`.
64
64
  2. Wire this starter into your app or worker runtime.
65
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/search/src/index.ts",content:`const searchEnvKeys = {{envKeysArray}} as const;
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
67
 
68
68
  export const searchFeature = {
69
69
  name: "search",
@@ -83,7 +83,7 @@ export function getSearchProvider() {
83
83
  envKeys: searchEnvKeys,
84
84
  };
85
85
  }
86
- `},{path:"packages/search/README.md",content:`# Search Feature
86
+ `},{path:"packages/integrations/search/README.md",content:`# Search Feature
87
87
 
88
88
  Installed by \`nebutra add search\`.
89
89
 
@@ -95,47 +95,143 @@ Next steps:
95
95
  1. Add credentials to \`{{envFile}}\`.
96
96
  2. Point your indexing jobs at the configured provider.
97
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:xe("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:xe("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:xe("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:xe("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:xe("feature-flags")},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:xe("captcha")}};function Ft(){return Object.values(Lt)}async function Mt(e){return Lt[e]??null}function yt(e){return e instanceof Error&&e.message.startsWith("EXIT:")}function Gt(e){try{return ht(`npm list ${e}`,{stdio:"pipe"}),!0}catch{return!1}}function Kt(e){process.stdout.write(`${JSON.stringify(e,null,2)}
99
- `)}function cr(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 qt(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 Vt(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 lr(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 Be(e){try{return await we.readFile(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}async function dr(e,t){if(t)return V.join(e,t);let n=[".env.local",".env"];for(let r of n)try{return await we.access(V.join(e,r)),V.join(e,r)}catch{}return V.join(e,".env.local")}function ur(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 mr(e){return e?Object.fromEntries(Object.entries(e).sort(([t],[n])=>t.localeCompare(n))):{}}function Wt(e,t){if(!(!e.providers||e.providers.length===0))return t?e.providers.find(n=>n.id===t):e.providers[0]}async function pr(e,t,n){let r=V.join(t,"package.json"),o=await Be(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=Vt(e.flatMap(g=>[...g.descriptor.env??[],...g.provider?.env??[]])),l=await dr(t,e[0]?.descriptor.envFile),u=await Be(l)??"",p=ur(u),y=i.filter(g=>!p.has(g.key)),m=i.filter(g=>p.has(g.key)),h=[];for(let g of e){let ee=Vt([...g.descriptor.env??[],...g.provider?.env??[]]),Ve={feature:g.name,provider:g.provider?.id,providerDescription:g.provider?.description,envFile:V.relative(t,l)||V.basename(l),envEntries:ee};for(let ft of g.descriptor.files??[]){let gt=V.join(t,ft.path),or=V.relative(t,gt)||ft.path,jt=lr(ft.content,Ve),Ut=await Be(gt),We,ze;Ut===null?(We="create",ze="file missing"):Ut===jt?(We="skip",ze="already matches registry template"):(We="conflict",ze="file exists with different content"),h.push({type:"write-file",feature:g.name,path:gt,relativePath:or,status:We,reason:ze,content:jt})}}let M=qt("dependencies",e.flatMap(g=>[...g.descriptor.dependencies??[],...g.provider?.dependencies??[]])),Y=qt("devDependencies",e.flatMap(g=>[...g.descriptor.devDependencies??[],...g.provider?.devDependencies??[]])),H=[];for(let g of M){let ee=a.dependencies?.[g.name];H.push({section:"dependencies",name:g.name,action:ee?ee===g.version?"keep":"update":"add",from:ee,to:g.version})}for(let g of Y){let ee=a.devDependencies?.[g.name];H.push({section:"devDependencies",name:g.name,action:ee?ee===g.version?"keep":"update":"add",from:ee,to:g.version})}let ve={type:"merge-env",path:l,relativePath:V.relative(t,l)||V.basename(l),created:u.length===0,add:y,keep:m},me={type:"update-package-json",path:r,relativePath:V.relative(t,r)||"package.json",changes:H},Ie={create:h.filter(g=>g.status==="create").length,update:H.filter(g=>g.action==="add"||g.action==="update").length,append:y.length,skip:h.filter(g=>g.status==="skip").length+H.filter(g=>g.action==="keep").length+m.length,conflict:h.filter(g=>g.status==="conflict").length};return{mode:n,planType:"local-feature-install",cwd:t,timestamp:new Date().toISOString(),features:e.map(g=>({name:g.name,description:g.descriptor.description,provider:g.provider?.id,providerDescription:g.provider?.description})),operations:[...h,ve,me],summary:Ie}}function zt(e){return e.summary.create>0||e.summary.update>0||e.summary.append>0}function fr(e){return e.summary.conflict>0}async function gr(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 we.mkdir(V.dirname(o.path),{recursive:!0}),await we.writeFile(o.path,o.content,"utf8"));if(n&&n.add.length>0){let o=await Be(n.path)??"",a=n.add.map(u=>`# ${u.description}
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:Pe("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:Pe("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:Pe("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:Pe("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:Pe("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:Pe("captcha","iam")}},mo=["iam","commerce","integrations","ai","design","platform","ops"];function po(){let e;try{e=rn(ao(import.meta.url))}catch{e=process.cwd()}for(;e&&e!==so(e).root;){try{let t=on(e);if(t.includes("pnpm-workspace.yaml")||t.includes("packages")){let n=At(e,"packages");if(no(n)&&oo(n).isDirectory())return n}}catch{}e=rn(e)}return null}function fo(e,t,n,r,o){let a=(t.env??[]).map(l=>({key:l,description:`${l} (declared by ${o})`})),i=nn(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 et=null;function go(){if(et)return et;let e={},t=po();if(!t)return et=e,e;for(let n of mo){let r=At(t,n),o;try{o=on(r)}catch{continue}for(let a of o){let i=At(r,a,"package.json"),l;try{l=ro(i,"utf-8")}catch{continue}let u;try{u=JSON.parse(l)}catch{continue}let m=u.nebutra,g=m?.featureId;!m||!g||!u.name||(e[g]=fo(g,m,u,n,u.name))}}return et=e,e}function sn(){return{...go(),...uo}}function an(){return Object.values(sn())}async function cn(e){return sn()[e]??null}function $t(e){return e instanceof Error&&e.message.startsWith("EXIT:")}function ln(e){try{return Pt(`npm list ${e}`,{stdio:"pipe"}),!0}catch{return!1}}function dn(e){process.stdout.write(`${JSON.stringify(e,null,2)}
99
+ `)}function yo(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 un(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 mn(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 ho(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 tt(e){try{return await Ee.readFile(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}async function bo(e,t){if(t)return Y.join(e,t);let n=[".env.local",".env"];for(let r of n)try{return await Ee.access(Y.join(e,r)),Y.join(e,r)}catch{}return Y.join(e,".env.local")}function vo(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 wo(e){return e?Object.fromEntries(Object.entries(e).sort(([t],[n])=>t.localeCompare(n))):{}}function pn(e,t){if(!(!e.providers||e.providers.length===0))return t?e.providers.find(n=>n.id===t):e.providers[0]}async function So(e,t,n){let r=Y.join(t,"package.json"),o=await tt(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=mn(e.flatMap(f=>[...f.descriptor.env??[],...f.provider?.env??[]])),l=await bo(t,e[0]?.descriptor.envFile),u=await tt(l)??"",m=vo(u),g=i.filter(f=>!m.has(f.key)),p=i.filter(f=>m.has(f.key)),b=[];for(let f of e){let ne=mn([...f.descriptor.env??[],...f.provider?.env??[]]),Xe={feature:f.name,provider:f.provider?.id,providerDescription:f.provider?.description,envFile:Y.relative(t,l)||Y.basename(l),envEntries:ne};for(let xt of f.descriptor.files??[]){let _t=Y.join(t,xt.path),Zr=Y.relative(t,_t)||xt.path,Zt=ho(xt.content,Xe),en=await tt(_t),Qe,Ze;en===null?(Qe="create",Ze="file missing"):en===Zt?(Qe="skip",Ze="already matches registry template"):(Qe="conflict",Ze="file exists with different content"),b.push({type:"write-file",feature:f.name,path:_t,relativePath:Zr,status:Qe,reason:Ze,content:Zt})}}let K=un("dependencies",e.flatMap(f=>[...f.descriptor.dependencies??[],...f.provider?.dependencies??[]])),X=un("devDependencies",e.flatMap(f=>[...f.descriptor.devDependencies??[],...f.provider?.devDependencies??[]])),Q=[];for(let f of K){let ne=a.dependencies?.[f.name];Q.push({section:"dependencies",name:f.name,action:ne?ne===f.version?"keep":"update":"add",from:ne,to:f.version})}for(let f of X){let ne=a.devDependencies?.[f.name];Q.push({section:"devDependencies",name:f.name,action:ne?ne===f.version?"keep":"update":"add",from:ne,to:f.version})}let Re={type:"merge-env",path:l,relativePath:Y.relative(t,l)||Y.basename(l),created:u.length===0,add:g,keep:p},fe={type:"update-package-json",path:r,relativePath:Y.relative(t,r)||"package.json",changes:Q},je={create:b.filter(f=>f.status==="create").length,update:Q.filter(f=>f.action==="add"||f.action==="update").length,append:g.length,skip:b.filter(f=>f.status==="skip").length+Q.filter(f=>f.action==="keep").length+p.length,conflict:b.filter(f=>f.status==="conflict").length};return{mode:n,planType:"local-feature-install",cwd:t,timestamp:new Date().toISOString(),features:e.map(f=>({name:f.name,description:f.descriptor.description,provider:f.provider?.id,providerDescription:f.provider?.description})),operations:[...b,Re,fe],summary:je}}function fn(e){return e.summary.create>0||e.summary.update>0||e.summary.append>0}function Ro(e){return e.summary.conflict>0}async function Eo(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 Ee.mkdir(Y.dirname(o.path),{recursive:!0}),await Ee.writeFile(o.path,o.content,"utf8"));if(n&&n.add.length>0){let o=await tt(n.path)??"",a=n.add.map(u=>`# ${u.description}
100
100
  ${u.key}=`),i=o.trim().length>0?`
101
101
 
102
102
  `:"",l=`${o.replace(/\s+$/,"")}${i}${a.join(`
103
103
 
104
104
  `)}
105
- `;await we.writeFile(n.path,l,"utf8")}if(t){let o=await we.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]=mr(a[l])}await we.writeFile(t.path,`${JSON.stringify(a,null,2)}
106
- `,"utf8")}}async function yr(e,t,n){let r=[];for(let o of e){let a=await Mt(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=Wt(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 S.select({message:`Select a provider for ${o}`,options:a.providers.map(u=>({value:u.id,label:u.id,hint:u.description}))});S.isCancel(l)&&(S.log.info("Installation cancelled."),process.exit(c.CANCELLED)),i=Wt(a,String(l))}r.push({name:o,descriptor:a,provider:i})}return r}function hr(e){S.log.info(Ne.yellow("Planned local install:"));for(let t of e.features)S.log.message(` - ${t.name}${t.provider?` (${t.provider})`:""}: ${t.description}`);for(let t of e.operations)if(t.type==="write-file"&&S.log.message(` - ${t.status.toUpperCase()} ${t.relativePath}`),t.type==="merge-env"&&t.add.length>0&&S.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&&S.log.message(` - UPDATE ${t.relativePath}: ${n.map(r=>`${r.name}@${r.to}`).join(", ")}`)}}async function Bt(e,t){t.dryRun||S.intro(Ne.bgCyan(Ne.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."):(S.log.warn("No components specified."),S.outro("Operation aborted.")),process.exit(c.INVALID_ARGS)),t.dryRun&&(t["21st"]||t.v0)&&(Kt(cr(e,t)),process.exit(c.DRY_RUN_OK)),t.ifNotExists&&(t["21st"]||t.v0)&&(t["21st"]&&Gt(t["21st"])||t.v0&&Gt("shadcn-component"))&&(s.info("Component already exists. Skipping installation."),process.exit(c.SUCCESS)),t["21st"]){let r=n||await S.confirm({message:`Install 21st.dev component: ${t["21st"]}?`,initialValue:!0});(S.isCancel(r)||!r)&&(S.log.info("Installation cancelled."),process.exit(c.CANCELLED)),S.log.info(Ne.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}`;ht(`pnpm dlx shadcn@latest add "${a}"`,{stdio:"inherit"}),s.success(`Successfully installed ${o}`),process.exit(c.SUCCESS)}catch(o){if(yt(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 S.confirm({message:`Install v0 component from: ${t.v0}?`,initialValue:!0});(S.isCancel(r)||!r)&&(S.log.info("Installation cancelled."),process.exit(c.CANCELLED)),S.log.info(Ne.cyan(`Invoking shadcn integration for v0 URL: ${t.v0}...`));try{ht(`pnpm dlx shadcn@latest add "${t.v0}"`,{stdio:"inherit"}),s.success("Successfully installed v0 component"),process.exit(c.SUCCESS)}catch(o){if(yt(o))throw o;s.error(`Failed to install component: ${o instanceof Error?o.message:"Unknown error"}`),process.exit(c.ERROR)}}try{let r=await yr(e,t,n),o=await pr(r,process.cwd(),t.dryRun?"dry-run":"apply");if(t.dryRun&&(Kt(o),process.exit(c.DRY_RUN_OK)),fr(o)){let i=o.operations.filter(l=>l.type==="write-file"&&l.status==="conflict").map(l=>l.relativePath);t.ifNotExists&&!zt(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)}zt(o)||(s.info("Feature install already satisfied. No files, env keys, or dependencies needed changes."),process.exit(c.SUCCESS)),hr(o);let a=n||await S.confirm({message:`Proceed with installing ${o.features.map(i=>i.name).join(", ")}?`,initialValue:!0});(S.isCancel(a)||!a)&&(S.log.info("Installation cancelled."),process.exit(c.CANCELLED)),await gr(o),s.success(`Installed ${o.features.map(i=>i.name).join(", ")} into ${o.cwd}`),process.exit(c.SUCCESS)}catch(r){if(yt(r))throw r;s.error(r instanceof Error?r.message:String(r)),process.exit(c.CONFIG_ERROR)}}import N from"picocolors";async function W(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 console.log(JSON.stringify(l,null,2)),{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);return l.ok?{ok:!0,status:l.status,data:u}:{ok:!1,status:l.status,error:u?.error||`HTTP ${l.status}`}}catch(l){return{ok:!1,status:0,error:`Network error: ${l instanceof Error?l.message:String(l)}`}}}function C(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))}async function br(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 W(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch tenants: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){C(r.data,e.format,"admin:tenants");return}let o={tenants:r.data?.tenants||[],total:r.data?.total||0,limit:r.data?.limit,offset:r.data?.offset};e.format==="json"?C(o,e.format,"admin:tenants"):(s.info(`Found ${o.total} tenant(s)`),o.tenants.length>0&&(console.log(`
107
- Tenants:`),o.tenants.forEach(a=>{console.log(` ${N.blue(a.id)} \u2014 ${a.name||"(unnamed)"}`),console.log(` Status: ${a.status}`),a.plan&&console.log(` Plan: ${a.plan}`)})))}async function vr(e,t){s.info(`Fetching tenant ${e}...`);let n=await W(`/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){C(n.data,t.format,"admin:tenant");return}if(t.format==="json")C({tenant:n.data},t.format,"admin:tenant");else{let r=n.data;s.success(`Tenant ${N.blue(r.id)}`),console.log(` Name: ${r.name}`),console.log(` Status: ${r.status}`),console.log(` Plan: ${r.plan}`),console.log(` Created: ${r.createdAt}`),r.suspendedAt&&console.log(` Suspended: ${r.suspendedAt}`)}}async function wr(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 W(`/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){C(n.data,t.format,"admin:suspend");return}s.success(`Tenant ${N.blue(e)} suspended`),t.format==="json"&&C({suspended:!0,tenantId:e},t.format,"admin:suspend")}async function Rr(e,t){s.info(`Unsuspending tenant ${e}...`);let n=await W(`/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){C(n.data,t.format,"admin:unsuspend");return}s.success(`Tenant ${N.blue(e)} unsuspended`),t.format==="json"&&C({unsuspended:!0,tenantId:e},t.format,"admin:unsuspend")}async function Sr(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 W(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch usage report: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){C(r.data,e.format,"admin:usage");return}let o={period:r.data?.period,topTenants:r.data?.topTenants||[],totalUsage:r.data?.totalUsage};e.format==="json"?C(o,e.format,"admin:usage"):(s.info(`Usage report for period: ${o.period}`),console.log(`Total usage: ${o.totalUsage}`),o.topTenants.length>0&&(console.log(`
108
- Top tenants:`),o.topTenants.forEach((a,i)=>{console.log(` ${i+1}. ${a.tenantName||a.tenantId} \u2014 ${a.usage}`)})))}async function Cr(e){s.info("Fetching dead letter queue...");let t=await W("/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){C(t.data,e.format,"admin:dlq:list");return}let n={messages:t.data?.messages||[],count:t.data?.count||0};e.format==="json"?C(n,e.format,"admin:dlq:list"):(s.info(`Found ${n.count} message(s) in DLQ`),n.messages.length>0&&(console.log(`
109
- Messages:`),n.messages.forEach(r=>{console.log(` ${N.blue(r.id)}`),console.log(` Type: ${r.type}`),console.log(` Error: ${r.error}`),console.log(` Created: ${r.createdAt}`)})))}async function Er(e,t){s.info(`Replaying DLQ message ${e}...`);let n=await W(`/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){C(n.data,t.format,"admin:dlq:replay");return}s.success(`Message ${N.blue(e)} replayed`),t.format==="json"&&C({replayed:!0,messageId:e},t.format,"admin:dlq:replay")}async function kr(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 W("/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){C(t.data,e.format,"admin:dlq:purge");return}s.success("DLQ purged"),e.format==="json"&&C({purged:!0,count:t.data?.count},e.format,"admin:dlq:purge")}async function Or(e){s.info("Fetching feature flags...");let t=await W("/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){C(t.data,e.format,"admin:flags:list");return}let n={flags:t.data?.flags||[],total:t.data?.total||0};e.format==="json"?C(n,e.format,"admin:flags:list"):(s.info(`Found ${n.total} flag(s)`),n.flags.length>0&&(console.log(`
110
- Flags:`),n.flags.forEach(r=>{let o=r.override!==void 0?N.yellow(String(r.override)):N.gray(String(r.default));console.log(` ${N.blue(r.name)} = ${o}`)})))}async function xr(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 W(`/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){C(o.data,n.format,"admin:flags:set");return}s.success(`Flag ${N.blue(e)} set to ${r}`),n.format==="json"&&C({flag:e,value:r},n.format,"admin:flags:set")}async function $r(e,t){s.info(`Unsetting flag ${e}...`);let n=await W(`/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){C(n.data,t.format,"admin:flags:unset");return}s.success(`Flag ${N.blue(e)} unset`),t.format==="json"&&C({flag:e,unset:!0},t.format,"admin:flags:unset")}async function Ar(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 W(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch audit log: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){C(r.data,e.format,"admin:audit");return}let o={entries:r.data?.entries||[],total:r.data?.total||0};e.format==="json"?C(o,e.format,"admin:audit"):(s.info(`Found ${o.total} audit log entries`),o.entries.length>0&&(console.log(`
111
- Audit entries:`),o.entries.forEach(a=>{console.log(` ${a.timestamp} \u2014 ${N.blue(a.action)} by ${a.actor}`),a.details&&console.log(` ${a.details}`)})))}async function _r(e){s.info("Running platform health check...");let t=await W("/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){C(t.data,e.format,"admin:health");return}let n={status:t.data?.status||"unknown",services:t.data?.services||{},timestamp:t.data?.timestamp};if(e.format==="json")C(n,e.format,"admin:health");else{let r=n.status==="healthy"?N.green:n.status==="degraded"?N.yellow:N.red;s.info(`Platform status: ${r(n.status)}`),n.services&&Object.keys(n.services).length>0&&(console.log(`
112
- Services:`),Object.entries(n.services).forEach(([o,a])=>{let i=a.status==="healthy"?N.green("\u2713"):N.red("\u2717");console.log(` ${i} ${o}: ${a.status}`),a.latency&&console.log(` Latency: ${a.latency}ms`),a.error&&console.log(` Error: ${a.error}`)}))}}function Yt(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 br({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 vr(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 wr(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 Rr(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 Sr({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 Cr({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 Er(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 kr({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 Or({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 xr(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 $r(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 Ar({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 _r({format:o.format||a.format,dryRun:o.dryRun||a.dryRun})})}import{existsSync as Ir,readFileSync as Nr,writeFileSync as Tr}from"fs";import{resolve as bt}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"]},Pr=[{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)"}],fe={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:Pr,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:"preset",description:"List and apply topology presets for governed SaaS projects",usage:"nebutra preset [subcommand]"},{name:"dev",description:"Start development workflows for selected Nebutra apps or presets",usage:"nebutra dev [options]"},{name:"test",description:"Run unit, architecture, and E2E verification workflows",usage:"nebutra test [scope]"},{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:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var Jt="nebutra.config.json",jr=b.ai.filter(e=>e!=="none"),Ht={"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 ne(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 Ur(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function Dr(e){return Ht[e]?Ht[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function Ye(){return Object.fromEntries(jr.map(e=>[e,{id:e,name:Ur(e),envVars:Dr(e)}]))}function oe(){return bt(process.cwd(),Jt)}function Re(){let e=oe();if(!Ir(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(Nr(e,"utf-8"))}catch(t){s.error(`Failed to parse ${Jt}: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}function He(e){Tr(oe(),`${JSON.stringify(e,null,2)}
113
- `)}function ge(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function Qt(e){let t=Ye(),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 Lr(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 Xt(e){let t=ge(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,a])=>a.enabled).map(([a])=>a);return{path:oe(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function te(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??Fr();return{...n,...t,...r?{format:r}:{}}}function Fr(){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 Te(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function Mr(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:Te(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`)),ne(n,e.format,"ai:models")}async function Gr(e){e.format!=="json"&&s.info("Scanning for available agents...");try{let t=bt(process.cwd(),"apps/api-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:`apps/api-gateway/src/routes/agents/${i}`})))}catch{n=[]}let r={agents:n.length>0?n:[{name:"No agents found",path:"create agents in apps/api-gateway/src/routes/agents/"}],count:n.length};e.dryRun||(r.count===0?s.info("No agents configured. Create agents in apps/api-gateway/src/routes/agents/"):s.success(`Found ${r.count} agent(s)`)),ne(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 Kr(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/api-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/api-gateway dev"),ne(n,t.format,"ai:test")}async function qr(e){e.format!=="json"&&s.info("Checking AI configuration...");let t={providers:{openai:{key:Te(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:Te(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:Te(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=bt(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(", ")}`)),ne(t,e.format,"ai:config")}async function Vr(e){let t=Re(),n=ge(t),r=Ye(),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:Te(process.env[u])}))}}),a={configPath:oe(),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(", ")}`)}ne(a,e.format,"ai:provider:list")}async function Wr(e,t){let n=Qt(e),r=Re(),o=ge(r),a=Ye(),i=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!0,envVars:a[u].envVars,enabledAt:o.providers?.[u]?.enabledAt??i};He(r);let l={configPath:oe(),enabled:n,env:t.env===!0?n.flatMap(u=>a[u].envVars.map(p=>({provider:u,name:p,example:`${p}=`}))):void 0,ai:Xt(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 p of a[u].envVars)console.log(`${p}=`)}ne(l,t.format,"ai:provider:enable")}async function zr(e,t){let n=Qt(e),r=Re(),o=ge(r),a=Ye(),i=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!1,envVars:o.providers?.[u]?.envVars??a[u].envVars,disabledAt:i};He(r);let l={configPath:oe(),disabled:n,ai:Xt(r)};t.format!=="json"&&s.success(`Disabled AI provider(s): ${n.join(", ")}`),ne(l,t.format,"ai:provider:disable")}async function Br(e){let t=Re(),n=ge(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},He(t);let o={configPath:oe(),gateway:n.gateway};e.format!=="json"&&s.success("AI gateway governance initialized in nebutra.config.json"),ne(o,e.format,"ai:gateway:init")}async function Yr(e){let t=Re(),n=ge(t),r={configPath:oe(),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")),ne(r,e.format,"ai:gateway:status")}async function Hr(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=Lr(t.fallback),r=Re(),o=ge(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},He(r);let a={configPath:oe(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&s.success(`AI route '${e}' set with policy '${t.policy}'`),ne(a,t.format,"ai:route:set")}async function Jr(e){let t=Re(),n=ge(t),r=Object.entries(n.routes??{}).map(([a,i])=>({name:a,...i})),o={configPath:oe(),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(", ")}`)),ne(o,e.format,"ai:route:list")}function Zt(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=te(a);await Vr({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=te(i);await Wr(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=te(i);await zr(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=te(a);await Br({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=te(a);await Yr({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=te(i);await Hr(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=te(a);await Jr({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=te(a);await Mr({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=te(a);await Gr({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=te(i);await Kr(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=te(a);await qr({dryRun:i.dryRun===!0,format:i.format,interactive:i.yes!==!0})})}import{resolve as Qr}from"path";function vt(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 se(e,t){return e?e.length<=8?"***":`${e.substring(0,8)}*** (${t||e.length} chars)`:"not set"}function Xr(){try{let e=Qr(process.cwd(),"nebutra.config.ts"),t=sr("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"}}catch{}return"clerk"}async function Zr(e){s.info("Checking authentication configuration...");let t=Xr(),n={provider:t,configured:!1,keys:{}};t==="clerk"?(n.keys={CLERK_SECRET_KEY:se(process.env.CLERK_SECRET_KEY,"secret"),NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:se(process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,"publishable"),CLERK_WEBHOOK_SECRET:se(process.env.CLERK_WEBHOOK_SECRET,"webhook")},n.configured=!!process.env.CLERK_SECRET_KEY&&!!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY):(n.keys={BETTER_AUTH_SECRET:se(process.env.BETTER_AUTH_SECRET,"secret"),BETTER_AUTH_URL:process.env.BETTER_AUTH_URL||"not set"},n.configured=!!process.env.BETTER_AUTH_SECRET),e.dryRun||(n.configured?s.success(`Auth provider configured: ${t}`):s.warn(`Auth provider ${t} is not fully configured`)),vt(n,e.format,"auth:status")}async function eo(e,t){let n=["clerk","better-auth"];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_..."')):(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")),t.dryRun||s.success(`Setup instructions for ${r} displayed above`),vt({provider:r,setupGuide:"Complete setup by following the instructions above",documentationUrl:r==="clerk"?"https://clerk.com/docs":"https://www.better-auth.com"},t.format,"auth:setup")}async function to(e){s.info("Checking authentication keys and secrets...");let n={keys:{clerk:{CLERK_SECRET_KEY:se(process.env.CLERK_SECRET_KEY,"secret key"),NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:se(process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,"publishable key"),CLERK_WEBHOOK_SECRET:se(process.env.CLERK_WEBHOOK_SECRET,"webhook secret")},betterAuth:{BETTER_AUTH_SECRET:se(process.env.BETTER_AUTH_SECRET,"secret"),BETTER_AUTH_URL:process.env.BETTER_AUTH_URL||"not set"},common:{DATABASE_URL:se(process.env.DATABASE_URL,"database url"),JWT_SECRET:se(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}}};if(!e.dryRun){let r=n.configured.clerk.secret&&n.configured.clerk.publishable,o=n.configured.betterAuth.secret&&n.configured.betterAuth.url;!r&&!o?s.warn("No authentication keys configured"):(s.info("Auth keys status:"),r&&s.success("Clerk configured"),o&&s.success("Better Auth configured"))}vt(n,e.format,"auth:keys")}function en(e){let t=e.command("auth").description("Manage authentication configuration (Clerk or Better Auth)");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 Zr({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})}),t.command("setup <provider>").description("Configure Clerk or Better Auth (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 eo(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 to({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}function wt(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 no(e,t){return e?e.length<=8?"***":`${e.substring(0,8)}*** (${t||e.length} chars)`:"not set"}var Je={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 ro(e){s.info("Checking payment provider configuration...");let t=Object.entries(Je).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:no(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`)),wt(r,e.format,"billing:status")}async function oo(e,t){let n=Object.keys(Je);n.includes(e.toLowerCase())||(s.error(`Invalid provider: ${e}. Choose from: ${n.join(", ")}`),process.exit(c.INVALID_ARGS));let r=e.toLowerCase(),o=Je[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};wt(a,t.format,"billing:setup")}async function so(e){s.info("Checking billing webhook configuration...");let t=process.env.NEXT_PUBLIC_APP_URL||"https://yourdomain.com",n=Object.entries(Je).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)`)})),wt(r,e.format,"billing:webhooks")}function tn(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 ro({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 oo(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 so({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}function je(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 nn(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function ao(e){s.info("Initializing brand system...");let t=await _("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});je(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand system initialized successfully")}async function io(e){s.info("Applying brand configuration...");let t=await _("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});je(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand applied successfully")}async function co(e){let t=[];e.primary&&(nn(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&&(nn(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 A({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});je(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||s.success("Color palette generated successfully")}async function lo(e){s.info("Syncing brand tokens across packages...");let t=await _("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});je(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand tokens synced successfully")}async function uo(e){s.info("Verifying brand token consistency...");let t=await _("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});je(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 rn(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 ao({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 io({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 co({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 lo({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 uo({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import de from"picocolors";var mo=process.env.NEBUTRA_API_URL||"http://localhost:3001/api";async function T(e,t={}){let n=`${mo}${e}`,r=await fetch(n,{...t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${process.env.NEBUTRA_ADMIN_TOKEN||""}`,...t.headers}});if(!r.ok){let o=await r.text().catch(()=>r.statusText);throw new Error(`API Error (${r.status}): ${o}`)}return r.json()}function po(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 fo(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 T(`/community/showcase?${t.toString()}`);if(!n.submissions||n.submissions.length===0)return s.warn("No showcase submissions found"),c.SUCCESS;s.info(`
105
+ `;await Ee.writeFile(n.path,l,"utf8")}if(t){let o=await Ee.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]=wo(a[l])}await Ee.writeFile(t.path,`${JSON.stringify(a,null,2)}
106
+ `,"utf8")}}async function Co(e,t,n){let r=[];for(let o of e){let a=await cn(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=pn(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 R.select({message:`Select a provider for ${o}`,options:a.providers.map(u=>({value:u.id,label:u.id,hint:u.description}))});R.isCancel(l)&&(R.log.info("Installation cancelled."),process.exit(c.CANCELLED)),i=pn(a,String(l))}r.push({name:o,descriptor:a,provider:i})}return r}function ko(e){R.log.info(Le.yellow("Planned local install:"));for(let t of e.features)R.log.message(` - ${t.name}${t.provider?` (${t.provider})`:""}: ${t.description}`);for(let t of e.operations)if(t.type==="write-file"&&R.log.message(` - ${t.status.toUpperCase()} ${t.relativePath}`),t.type==="merge-env"&&t.add.length>0&&R.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&&R.log.message(` - UPDATE ${t.relativePath}: ${n.map(r=>`${r.name}@${r.to}`).join(", ")}`)}}async function gn(e,t){t.dryRun||R.intro(Le.bgCyan(Le.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."):(R.log.warn("No components specified."),R.outro("Operation aborted.")),process.exit(c.INVALID_ARGS)),t.dryRun&&(t["21st"]||t.v0)&&(dn(yo(e,t)),process.exit(c.DRY_RUN_OK)),t.ifNotExists&&(t["21st"]||t.v0)&&(t["21st"]&&ln(t["21st"])||t.v0&&ln("shadcn-component"))&&(s.info("Component already exists. Skipping installation."),process.exit(c.SUCCESS)),t["21st"]){let r=n||await R.confirm({message:`Install 21st.dev component: ${t["21st"]}?`,initialValue:!0});(R.isCancel(r)||!r)&&(R.log.info("Installation cancelled."),process.exit(c.CANCELLED)),R.log.info(Le.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}`;Pt(`pnpm dlx shadcn@latest add "${a}"`,{stdio:"inherit"}),s.success(`Successfully installed ${o}`),process.exit(c.SUCCESS)}catch(o){if($t(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 R.confirm({message:`Install v0 component from: ${t.v0}?`,initialValue:!0});(R.isCancel(r)||!r)&&(R.log.info("Installation cancelled."),process.exit(c.CANCELLED)),R.log.info(Le.cyan(`Invoking shadcn integration for v0 URL: ${t.v0}...`));try{Pt(`pnpm dlx shadcn@latest add "${t.v0}"`,{stdio:"inherit"}),s.success("Successfully installed v0 component"),process.exit(c.SUCCESS)}catch(o){if($t(o))throw o;s.error(`Failed to install component: ${o instanceof Error?o.message:"Unknown error"}`),process.exit(c.ERROR)}}try{let r=await Co(e,t,n),o=await So(r,process.cwd(),t.dryRun?"dry-run":"apply");if(t.dryRun&&(dn(o),process.exit(c.DRY_RUN_OK)),Ro(o)){let i=o.operations.filter(l=>l.type==="write-file"&&l.status==="conflict").map(l=>l.relativePath);t.ifNotExists&&!fn(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)}fn(o)||(s.info("Feature install already satisfied. No files, env keys, or dependencies needed changes."),process.exit(c.SUCCESS)),ko(o);let a=n||await R.confirm({message:`Proceed with installing ${o.features.map(i=>i.name).join(", ")}?`,initialValue:!0});(R.isCancel(a)||!a)&&(R.log.info("Installation cancelled."),process.exit(c.CANCELLED)),await Eo(o),s.success(`Installed ${o.features.map(i=>i.name).join(", ")} into ${o.cwd}`),process.exit(c.SUCCESS)}catch(r){if($t(r))throw r;s.error(r instanceof Error?r.message:String(r)),process.exit(c.CONFIG_ERROR)}}import j from"picocolors";import{stderr as ye,stdout as yn}from"process";import ie from"picocolors";function Oo(){return process.env.NEBUTRA_NON_TTY||process.env.CI||process.env.GITHUB_ACTIONS?!1:process.stderr.isTTY===!0}function hn(e){if(e)return e;let t=process.env.NEBUTRA_OUTPUT_FORMAT;return t&&["json","table","plain"].includes(t)?t:Oo()?"plain":"json"}function xo(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 _o(e){return JSON.stringify(e)}function bn(e){if(!Array.isArray(e))return Nt(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return Nt(e);let t=xo(e);return ie.gray(t)}function Nt(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 O(e,t){let n=hn(t?.format),r=t?.stream==="stderr"?ye:yn,o;switch(n){case"json":o=_o(e);break;case"table":o=bn(e);break;default:o=Nt(e);break}r.write(o+`
108
+ `)}function x(e,t={}){let n=hn(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}yn.write(r+`
109
+ `)}function d(e,t="info"){let n;switch(t){case"error":n=ie.red("\u2716");break;case"warn":n=ie.yellow("\u26A0");break;case"success":n=ie.green("\u2713");break;default:n=ie.blue("\u2139");break}let r=`${n} ${e}`;ye.write(r+`
110
+ `)}function _(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=ie.dim(`[debug] ${e}`);ye.write(r+`
111
+ `),t&&Object.keys(t).length>0&&ye.write(ie.dim(JSON.stringify(t,null,2))+`
112
+ `)}function nt(e){ye.write(`
113
+ `),ye.write(ie.bold(ie.cyan(e))+`
114
+ `),ye.write(ie.gray("-".repeat(e.length))+`
115
+ `),ye.write(`
116
+ `)}async function H(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 x(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);return l.ok?{ok:!0,status:l.status,data:u}:{ok:!1,status:l.status,error:u?.error||`HTTP ${l.status}`}}catch(l){return{ok:!1,status:0,error:`Network error: ${l instanceof Error?l.message:String(l)}`}}}function E(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))}async function Ao(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 H(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch tenants: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){E(r.data,e.format,"admin:tenants");return}let o={tenants:r.data?.tenants||[],total:r.data?.total||0,limit:r.data?.limit,offset:r.data?.offset};e.format==="json"?E(o,e.format,"admin:tenants"):(s.info(`Found ${o.total} tenant(s)`),o.tenants.length>0&&(console.log(`
117
+ Tenants:`),o.tenants.forEach(a=>{console.log(` ${j.blue(a.id)} \u2014 ${a.name||"(unnamed)"}`),console.log(` Status: ${a.status}`),a.plan&&console.log(` Plan: ${a.plan}`)})))}async function $o(e,t){s.info(`Fetching tenant ${e}...`);let n=await H(`/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){E(n.data,t.format,"admin:tenant");return}if(t.format==="json")E({tenant:n.data},t.format,"admin:tenant");else{let r=n.data;s.success(`Tenant ${j.blue(r.id)}`),console.log(` Name: ${r.name}`),console.log(` Status: ${r.status}`),console.log(` Plan: ${r.plan}`),console.log(` Created: ${r.createdAt}`),r.suspendedAt&&console.log(` Suspended: ${r.suspendedAt}`)}}async function Po(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 H(`/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){E(n.data,t.format,"admin:suspend");return}s.success(`Tenant ${j.blue(e)} suspended`),t.format==="json"&&E({suspended:!0,tenantId:e},t.format,"admin:suspend")}async function No(e,t){s.info(`Unsuspending tenant ${e}...`);let n=await H(`/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){E(n.data,t.format,"admin:unsuspend");return}s.success(`Tenant ${j.blue(e)} unsuspended`),t.format==="json"&&E({unsuspended:!0,tenantId:e},t.format,"admin:unsuspend")}async function Io(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 H(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch usage report: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){E(r.data,e.format,"admin:usage");return}let o={period:r.data?.period,topTenants:r.data?.topTenants||[],totalUsage:r.data?.totalUsage};e.format==="json"?E(o,e.format,"admin:usage"):(s.info(`Usage report for period: ${o.period}`),console.log(`Total usage: ${o.totalUsage}`),o.topTenants.length>0&&(console.log(`
118
+ Top tenants:`),o.topTenants.forEach((a,i)=>{console.log(` ${i+1}. ${a.tenantName||a.tenantId} \u2014 ${a.usage}`)})))}async function To(e){s.info("Fetching dead letter queue...");let t=await H("/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){E(t.data,e.format,"admin:dlq:list");return}let n={messages:t.data?.messages||[],count:t.data?.count||0};e.format==="json"?E(n,e.format,"admin:dlq:list"):(s.info(`Found ${n.count} message(s) in DLQ`),n.messages.length>0&&(console.log(`
119
+ Messages:`),n.messages.forEach(r=>{console.log(` ${j.blue(r.id)}`),console.log(` Type: ${r.type}`),console.log(` Error: ${r.error}`),console.log(` Created: ${r.createdAt}`)})))}async function Uo(e,t){s.info(`Replaying DLQ message ${e}...`);let n=await H(`/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){E(n.data,t.format,"admin:dlq:replay");return}s.success(`Message ${j.blue(e)} replayed`),t.format==="json"&&E({replayed:!0,messageId:e},t.format,"admin:dlq:replay")}async function jo(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 H("/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){E(t.data,e.format,"admin:dlq:purge");return}s.success("DLQ purged"),e.format==="json"&&E({purged:!0,count:t.data?.count},e.format,"admin:dlq:purge")}async function Lo(e){s.info("Fetching feature flags...");let t=await H("/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){E(t.data,e.format,"admin:flags:list");return}let n={flags:t.data?.flags||[],total:t.data?.total||0};e.format==="json"?E(n,e.format,"admin:flags:list"):(s.info(`Found ${n.total} flag(s)`),n.flags.length>0&&(console.log(`
120
+ Flags:`),n.flags.forEach(r=>{let o=r.override!==void 0?j.yellow(String(r.override)):j.gray(String(r.default));console.log(` ${j.blue(r.name)} = ${o}`)})))}async function Do(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 H(`/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){E(o.data,n.format,"admin:flags:set");return}s.success(`Flag ${j.blue(e)} set to ${r}`),n.format==="json"&&E({flag:e,value:r},n.format,"admin:flags:set")}async function Fo(e,t){s.info(`Unsetting flag ${e}...`);let n=await H(`/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){E(n.data,t.format,"admin:flags:unset");return}s.success(`Flag ${j.blue(e)} unset`),t.format==="json"&&E({flag:e,unset:!0},t.format,"admin:flags:unset")}async function Mo(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 H(n,{dryRun:e.dryRun});if(r.ok||(s.error(`Failed to fetch audit log: ${r.error}`),process.exit(c.NETWORK_ERROR)),e.dryRun){E(r.data,e.format,"admin:audit");return}let o={entries:r.data?.entries||[],total:r.data?.total||0};e.format==="json"?E(o,e.format,"admin:audit"):(s.info(`Found ${o.total} audit log entries`),o.entries.length>0&&(console.log(`
121
+ Audit entries:`),o.entries.forEach(a=>{console.log(` ${a.timestamp} \u2014 ${j.blue(a.action)} by ${a.actor}`),a.details&&console.log(` ${a.details}`)})))}async function Go(e){s.info("Running platform health check...");let t=await H("/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){E(t.data,e.format,"admin:health");return}let n={status:t.data?.status||"unknown",services:t.data?.services||{},timestamp:t.data?.timestamp};if(e.format==="json")E(n,e.format,"admin:health");else{let r=n.status==="healthy"?j.green:n.status==="degraded"?j.yellow:j.red;s.info(`Platform status: ${r(n.status)}`),n.services&&Object.keys(n.services).length>0&&(console.log(`
122
+ Services:`),Object.entries(n.services).forEach(([o,a])=>{let i=a.status==="healthy"?j.green("\u2713"):j.red("\u2717");console.log(` ${i} ${o}: ${a.status}`),a.latency&&console.log(` Latency: ${a.latency}ms`),a.error&&console.log(` Error: ${a.error}`)}))}}function vn(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 Ao({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 $o(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 Po(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 No(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 Io({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 To({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 Uo(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 jo({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 Lo({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 Do(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 Fo(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 Mo({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 Go({format:o.format||a.format,dryRun:o.dryRun||a.dryRun})})}import{existsSync as Ko,readFileSync as Bo,writeFileSync as qo}from"fs";import{resolve as It}from"path";var v={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"]},Vo=[{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)"}],he={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:Vo,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:"preset",description:"List and apply topology presets for governed SaaS projects",usage:"nebutra preset [subcommand]"},{name:"dev",description:"Start development workflows for selected Nebutra apps or presets",usage:"nebutra dev [options]"},{name:"test",description:"Run unit, architecture, and E2E verification workflows",usage:"nebutra test [scope]"},{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:"doctor",description:"Check local project setup and common Nebutra configuration issues",usage:"nebutra doctor"}]};var Sn="nebutra.config.json",Wo=v.ai.filter(e=>e!=="none"),wn={"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 oe(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 Yo(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function Ho(e){return wn[e]?wn[e]:[`${e.replace(/-/g,"_").toUpperCase()}_API_KEY`]}function rt(){return Object.fromEntries(Wo.map(e=>[e,{id:e,name:Yo(e),envVars:Ho(e)}]))}function ce(){return It(process.cwd(),Sn)}function Ce(){let e=ce();if(!Ko(e))return{$schema:"https://nebutra.com/schema.json"};try{return JSON.parse(Bo(e,"utf-8"))}catch(t){s.error(`Failed to parse ${Sn}: ${t instanceof Error?t.message:String(t)}`),process.exit(c.ERROR)}}function ot(e){qo(ce(),`${JSON.stringify(e,null,2)}
123
+ `)}function be(e){return e.ai={providers:{},routes:{},...e.ai},e.ai.providers={...e.ai.providers},e.ai.routes={...e.ai.routes},e.ai}function Rn(e){let t=rt(),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 zo(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 En(e){let t=be(e),n=t.providers??{},r=t.routes??{},o=Object.entries(n).filter(([,a])=>a.enabled).map(([a])=>a);return{path:ce(),gateway:t.gateway??null,providers:n,enabledProviders:o,routes:r}}function re(e){let t=typeof e.opts=="function"?e.opts():e,n=typeof e.optsWithGlobals=="function"?e.optsWithGlobals():t,r=t.format??n.format??Jo();return{...n,...t,...r?{format:r}:{}}}function Jo(){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 De(e){return e?e.length<=8?"***":`${e.substring(0,8)}***`:"not set"}async function Xo(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:De(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`)),oe(n,e.format,"ai:models")}async function Qo(e){e.format!=="json"&&s.info("Scanning for available agents...");try{let t=It(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)`)),oe(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 Zo(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"),oe(n,t.format,"ai:test")}async function es(e){e.format!=="json"&&s.info("Checking AI configuration...");let t={providers:{openai:{key:De(process.env.OPENAI_API_KEY),configured:!!process.env.OPENAI_API_KEY},anthropic:{key:De(process.env.ANTHROPIC_API_KEY),configured:!!process.env.ANTHROPIC_API_KEY},openrouter:{key:De(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=It(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(", ")}`)),oe(t,e.format,"ai:config")}async function ts(e){let t=Ce(),n=be(t),r=rt(),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:De(process.env[u])}))}}),a={configPath:ce(),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(", ")}`)}oe(a,e.format,"ai:provider:list")}async function ns(e,t){let n=Rn(e),r=Ce(),o=be(r),a=rt(),i=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!0,envVars:a[u].envVars,enabledAt:o.providers?.[u]?.enabledAt??i};ot(r);let l={configPath:ce(),enabled:n,env:t.env===!0?n.flatMap(u=>a[u].envVars.map(m=>({provider:u,name:m,example:`${m}=`}))):void 0,ai:En(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}=`)}oe(l,t.format,"ai:provider:enable")}async function rs(e,t){let n=Rn(e),r=Ce(),o=be(r),a=rt(),i=new Date().toISOString();for(let u of n)o.providers[u]={enabled:!1,envVars:o.providers?.[u]?.envVars??a[u].envVars,disabledAt:i};ot(r);let l={configPath:ce(),disabled:n,ai:En(r)};t.format!=="json"&&s.success(`Disabled AI provider(s): ${n.join(", ")}`),oe(l,t.format,"ai:provider:disable")}async function os(e){let t=Ce(),n=be(t),r=new Date().toISOString();n.gateway={enabled:!0,mode:"local",initializedAt:n.gateway?.initializedAt??r,updatedAt:r},ot(t);let o={configPath:ce(),gateway:n.gateway};e.format!=="json"&&s.success("AI gateway governance initialized in nebutra.config.json"),oe(o,e.format,"ai:gateway:init")}async function ss(e){let t=Ce(),n=be(t),r={configPath:ce(),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")),oe(r,e.format,"ai:gateway:status")}async function as(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=zo(t.fallback),r=Ce(),o=be(r);o.routes[e]={policy:t.policy,fallback:n,updatedAt:new Date().toISOString()},ot(r);let a={configPath:ce(),route:{name:e,...o.routes[e]},routes:o.routes};t.format!=="json"&&s.success(`AI route '${e}' set with policy '${t.policy}'`),oe(a,t.format,"ai:route:set")}async function is(e){let t=Ce(),n=be(t),r=Object.entries(n.routes??{}).map(([a,i])=>({name:a,...i})),o={configPath:ce(),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(", ")}`)),oe(o,e.format,"ai:route:list")}function Cn(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=re(a);await ts({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=re(i);await ns(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=re(i);await rs(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=re(a);await os({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=re(a);await ss({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=re(i);await as(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=re(a);await is({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=re(a);await Xo({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=re(a);await Qo({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=re(i);await Zo(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=re(a);await es({dryRun:i.dryRun===!0,format:i.format,interactive:i.yes!==!0})})}import{resolve as cs}from"path";function Tt(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 C(e,t){return e?e.length<=8?"***":`${e.substring(0,8)}*** (${t||e.length} chars)`:"not set"}function ls(){try{let e=cs(process.cwd(),"nebutra.config.ts"),t=eo("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 ds(e){s.info("Checking authentication configuration...");let t=ls(),n={provider:t,configured:!1,keys:{}};t==="clerk"?(n.keys={CLERK_SECRET_KEY:C(process.env.CLERK_SECRET_KEY,"secret"),NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:C(process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,"publishable"),CLERK_WEBHOOK_SECRET:C(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:C(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:C(process.env.AUTH_SECRET,"secret"),NEXTAUTH_SECRET:C(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:C(process.env.GOOGLE_CLIENT_ID,"google client"),GITHUB_CLIENT_ID:C(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_ANON_KEY:C(process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,"anon"),SUPABASE_URL:process.env.SUPABASE_URL||"not set",SUPABASE_ANON_KEY:C(process.env.SUPABASE_ANON_KEY,"anon"),SUPABASE_SERVICE_ROLE_KEY:C(process.env.SUPABASE_SERVICE_ROLE_KEY,"service role"),SUPABASE_WEBHOOK_SECRET:C(process.env.SUPABASE_WEBHOOK_SECRET,"webhook")},n.configured=!!((process.env.SUPABASE_URL||process.env.NEXT_PUBLIC_SUPABASE_URL)&&(process.env.SUPABASE_ANON_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`)),Tt(n,e.format,"auth:status")}async function us(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_ANON_KEY="..."'),s.info(' SUPABASE_URL="https://xxx.supabase.co"'),s.info(' SUPABASE_ANON_KEY="..."'),s.info(' SUPABASE_SERVICE_ROLE_KEY="..."')),t.dryRun||s.success(`Setup instructions for ${r} displayed above`),Tt({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 ms(e){s.info("Checking authentication keys and secrets...");let n={keys:{clerk:{CLERK_SECRET_KEY:C(process.env.CLERK_SECRET_KEY,"secret key"),NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:C(process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,"publishable key"),CLERK_WEBHOOK_SECRET:C(process.env.CLERK_WEBHOOK_SECRET,"webhook secret")},betterAuth:{BETTER_AUTH_SECRET:C(process.env.BETTER_AUTH_SECRET,"secret"),BETTER_AUTH_URL:process.env.BETTER_AUTH_URL||"not set"},nextAuth:{AUTH_SECRET:C(process.env.AUTH_SECRET,"secret"),NEXTAUTH_SECRET:C(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:C(process.env.GOOGLE_CLIENT_ID,"google client"),GITHUB_CLIENT_ID:C(process.env.GITHUB_CLIENT_ID,"github client")},supabase:{NEXT_PUBLIC_SUPABASE_URL:process.env.NEXT_PUBLIC_SUPABASE_URL||"not set",NEXT_PUBLIC_SUPABASE_ANON_KEY:C(process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,"anon"),SUPABASE_URL:process.env.SUPABASE_URL||"not set",SUPABASE_ANON_KEY:C(process.env.SUPABASE_ANON_KEY,"anon"),SUPABASE_SERVICE_ROLE_KEY:C(process.env.SUPABASE_SERVICE_ROLE_KEY,"service role")},common:{DATABASE_URL:C(process.env.DATABASE_URL,"database url"),JWT_SECRET:C(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),anonKey:!!(process.env.SUPABASE_ANON_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.anonKey&&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"))}Tt(n,e.format,"auth:keys")}function kn(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 ds({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 us(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 ms({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import ve from"fs";import se from"path";import*as st from"@clack/prompts";import _n from"picocolors";var On=["ts","py"],ps=`{
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
+ `,fs=`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
+ `,gs=`# @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 ys(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 hs(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 bs=`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 vs(e,t){let n=se.join(e,"backends/gateway");ve.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)),ve.mkdirSync(se.join(n,"src"),{recursive:!0}),ve.writeFileSync(se.join(n,"package.json"),ps),ve.writeFileSync(se.join(n,"src/index.ts"),fs),ve.writeFileSync(se.join(n,"README.md"),gs),s.success("Created backends/gateway scaffold"),process.exit(c.SUCCESS)}function xn(e){return/^[a-z][a-z0-9_-]{0,40}$/.test(e)}async function ws(e,t){let n=t.name,r=process.stdout.isTTY===!0&&!t.yes;if(!n&&r){let i=await st.text({message:"Service name (lowercase, hyphens or underscores):",placeholder:"translator",validate:l=>xn(l)?void 0:"Invalid name"});st.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)),xn(n)||(s.error(`Invalid name: ${_n.red(n)}. Use lowercase letters, digits, hyphen, underscore.`),process.exit(c.INVALID_ARGS));let o=se.join(e,"backends/python",n);ve.existsSync(o)&&(s.error(`backends/python/${n} already exists \u2014 refusing to overwrite.`),process.exit(c.CONFLICT));let a=[[se.join(o,"pyproject.toml"),ys(n)],[se.join(o,"README.md"),hs(n)],[se.join(o,"src/main.py"),bs],[se.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)ve.mkdirSync(se.dirname(i),{recursive:!0}),ve.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 Ss(e,t={}){On.includes(e)||(s.error(`Invalid runtime: ${_n.red(e)}. Valid: ${On.join(", ")}`),process.exit(c.INVALID_ARGS));let n=h();e==="ts"?await vs(n,t):await ws(n,t)}function An(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)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Ss(n,{name:r.name,dryRun:r.dryRun||!1,yes:o.yes||!1,quiet:o.quiet||!1})})}function Ut(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 Rs(e,t){return e?e.length<=8?"***":`${e.substring(0,8)}*** (${t||e.length} chars)`:"not set"}var at={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 Es(e){s.info("Checking payment provider configuration...");let t=Object.entries(at).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:Rs(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`)),Ut(r,e.format,"billing:status")}async function Cs(e,t){let n=Object.keys(at);n.includes(e.toLowerCase())||(s.error(`Invalid provider: ${e}. Choose from: ${n.join(", ")}`),process.exit(c.INVALID_ARGS));let r=e.toLowerCase(),o=at[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};Ut(a,t.format,"billing:setup")}async function ks(e){s.info("Checking billing webhook configuration...");let t=process.env.NEXT_PUBLIC_APP_URL||"https://yourdomain.com",n=Object.entries(at).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)`)})),Ut(r,e.format,"billing:webhooks")}function $n(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 Es({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 Cs(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 ks({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}function Fe(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 Pn(e){return/^#[0-9A-Fa-f]{6}$/.test(e)}async function Os(e){s.info("Initializing brand system...");let t=await I("brand:init",{dryRun:e.dryRun,interactive:e.interactive??!0});Fe(t,e.format,"brand:init"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand system initialized successfully")}async function xs(e){s.info("Applying brand configuration...");let t=await I("brand:apply",{dryRun:e.dryRun,interactive:e.interactive??!0});Fe(t,e.format,"brand:apply"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand applied successfully")}async function _s(e){let t=[];e.primary&&(Pn(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&&(Pn(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 $({command:"node",args:["scripts/generate-palette.mjs",...t],dryRun:e.dryRun,interactive:e.interactive??!0,label:"Generate brand palette"});Fe(n,e.format,"brand:palette"),n.exitCode!==0&&process.exit(n.exitCode),e.dryRun||s.success("Color palette generated successfully")}async function As(e){s.info("Syncing brand tokens across packages...");let t=await I("brand:sync",{dryRun:e.dryRun,interactive:e.interactive??!0});Fe(t,e.format,"brand:sync"),t.exitCode!==0&&process.exit(t.exitCode),e.dryRun||s.success("Brand tokens synced successfully")}async function $s(e){s.info("Verifying brand token consistency...");let t=await I("brand:verify-tokens",{dryRun:e.dryRun,interactive:e.interactive??!0});Fe(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 Nn(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 Os({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 xs({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 _s({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 As({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 $s({dryRun:n.dryRun||!1,format:n.format||r.format,interactive:r.yes!==!0})})}import me from"picocolors";var Ps=process.env.NEBUTRA_API_URL||"http://localhost:3001/api";async function L(e,t={}){let n=`${Ps}${e}`,r=await fetch(n,{...t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${process.env.NEBUTRA_ADMIN_TOKEN||""}`,...t.headers}});if(!r.ok){let o=await r.text().catch(()=>r.statusText);throw new Error(`API Error (${r.status}): ${o}`)}return r.json()}function Ns(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 Is(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 L(`/community/showcase?${t.toString()}`);if(!n.submissions||n.submissions.length===0)return s.warn("No showcase submissions found"),c.SUCCESS;s.info(`
114
210
  Showcase Submissions (${n.submissions.length})
115
- `);for(let r of n.submissions);return c.SUCCESS}catch(t){return s.error(`Failed to list showcase: ${t.message}`),c.ERROR}}async function go(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 T(`/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 yo(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 T(`/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 ho(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 T(`/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 bo(e){try{s.info("Fetching showcase statistics...");let t=await T("/community/showcase/stats");return s.info(`
211
+ `);for(let r of n.submissions);return c.SUCCESS}catch(t){return s.error(`Failed to list showcase: ${t.message}`),c.ERROR}}async function Ts(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 L(`/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 Us(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 L(`/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 js(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 L(`/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 Ls(e){try{s.info("Fetching showcase statistics...");let t=await L("/community/showcase/stats");return s.info(`
116
212
  Showcase Statistics
117
- `),c.SUCCESS}catch(t){return s.error(`Failed to fetch showcase stats: ${t.message}`),c.ERROR}}async function vo(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 T(`/community/content?${t.toString()}`);if(!n.items||n.items.length===0)return s.warn("No content found"),c.SUCCESS;s.info(`
213
+ `),c.SUCCESS}catch(t){return s.error(`Failed to fetch showcase stats: ${t.message}`),c.ERROR}}async function Ds(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 L(`/community/content?${t.toString()}`);if(!n.items||n.items.length===0)return s.warn("No content found"),c.SUCCESS;s.info(`
118
214
  Community Content (${n.items.length})
119
- `);for(let r of n.items);return c.SUCCESS}catch(t){return s.error(`Failed to list content: ${t.message}`),c.ERROR}}async function wo(e,t){try{let n=["approve","flag","archive","delete"];if(!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 T(`/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 Ro(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 T(`/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 So(e){try{s.info("Fetching content analytics...");let t=await T("/community/content/analytics");s.info(`
215
+ `);for(let r of n.items);return c.SUCCESS}catch(t){return s.error(`Failed to list content: ${t.message}`),c.ERROR}}async function Fs(e,t){try{let n=["approve","flag","archive","delete"];if(!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 L(`/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 Ms(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 L(`/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 Gs(e){try{s.info("Fetching content analytics...");let t=await L("/community/content/analytics");s.info(`
120
216
  Content Performance Metrics
121
- `);for(let n of 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 Co(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 T(`/community/members?${t.toString()}`);if(!n.members||n.members.length===0)return s.warn("No members found"),c.SUCCESS;s.info(`
217
+ `);for(let n of 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 Vs(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 L(`/community/members?${t.toString()}`);if(!n.members||n.members.length===0)return s.warn("No members found"),c.SUCCESS;s.info(`
122
218
  Community Members (${n.members.length})
123
- `);for(let r of n.members){let a={owner:de.red,admin:de.yellow,moderator:de.blue,member:de.gray}[String(r.role)]??de.gray}return c.SUCCESS}catch(t){return s.error(`Failed to list members: ${t.message}`),c.ERROR}}async function Eo(e,t){try{s.info(`Fetching profile for ${e}...`);let n=await T(`/community/members/${e}`);return s.info(`
219
+ `);for(let r of n.members){let a={owner:me.red,admin:me.yellow,moderator:me.blue,member:me.gray}[String(r.role)]??me.gray}return c.SUCCESS}catch(t){return s.error(`Failed to list members: ${t.message}`),c.ERROR}}async function Ks(e,t){try{s.info(`Fetching profile for ${e}...`);let n=await L(`/community/members/${e}`);return s.info(`
124
220
  Member Profile
125
- `),c.SUCCESS}catch(n){return s.error(`Failed to fetch member profile: ${n.message}`),c.ERROR}}async function ko(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 T(`/community/members/${e}/role`,{method:"POST",body:JSON.stringify({role:t})});return s.success(`Updated ${o.name} \u2192 ${de.bold(t)}`),c.SUCCESS}catch(r){return s.error(`Failed to update member role: ${r.message}`),c.ERROR}}async function Oo(e,t){try{s.info(`Sending invite to ${e}...`);let n=await T("/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 xo(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 T(`/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 $o(e){try{s.info("Computing community health score...");let t=e.period||"30d",n=await T(`/community/health?period=${t}`),{score:r,breakdown:o}=po(n.metrics);s.info(`
221
+ `),c.SUCCESS}catch(n){return s.error(`Failed to fetch member profile: ${n.message}`),c.ERROR}}async function Bs(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 L(`/community/members/${e}/role`,{method:"POST",body:JSON.stringify({role:t})});return s.success(`Updated ${o.name} \u2192 ${me.bold(t)}`),c.SUCCESS}catch(r){return s.error(`Failed to update member role: ${r.message}`),c.ERROR}}async function qs(e,t){try{s.info(`Sending invite to ${e}...`);let n=await L("/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 Ws(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 L(`/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 Ys(e){try{s.info("Computing community health score...");let t=e.period||"30d",n=await L(`/community/health?period=${t}`),{score:r,breakdown:o}=Ns(n.metrics);s.info(`
126
222
  Community Health Report (${t})
127
- `);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))}return e.format,c.SUCCESS}catch(t){return s.error(`Failed to compute health: ${t.message}`),c.ERROR}}async function Ao(e){try{s.info("Fetching moderation queue...");let t=await T("/community/moderation/queue");if(!t.items||t.items.length===0)return s.success("No pending moderation items"),c.SUCCESS;s.info(`
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))}return e.format,c.SUCCESS}catch(t){return s.error(`Failed to compute health: ${t.message}`),c.ERROR}}async function Hs(e){try{s.info("Fetching moderation queue...");let t=await L("/community/moderation/queue");if(!t.items||t.items.length===0)return s.success("No pending moderation items"),c.SUCCESS;s.info(`
128
224
  Moderation Queue (${t.items.length} pending)
129
- `);for(let n of t.items){let o={low:de.gray("\u25CF"),medium:de.yellow("\u25CF"),high:de.red("\u25CF")}[String(n.severity)]??"\u25CF"}return c.SUCCESS}catch(t){return s.error(`Failed to fetch queue: ${t.message}`),c.ERROR}}async function _o(e){try{s.info("Running AI-assisted moderation sweep..."),e.dryRun&&s.warn("DRY RUN MODE - no changes will be made");let t=await T("/community/moderation/auto",{method:"POST",body:JSON.stringify({dryRun:e.dryRun||!1})});return s.info(`
225
+ `);for(let n of t.items){let o={low:me.gray("\u25CF"),medium:me.yellow("\u25CF"),high:me.red("\u25CF")}[String(n.severity)]??"\u25CF"}return c.SUCCESS}catch(t){return s.error(`Failed to fetch queue: ${t.message}`),c.ERROR}}async function zs(e){try{s.info("Running AI-assisted moderation sweep..."),e.dryRun&&s.warn("DRY RUN MODE - no changes will be made");let t=await L("/community/moderation/auto",{method:"POST",body:JSON.stringify({dryRun:e.dryRun||!1})});return s.info(`
130
226
  Moderation Results
131
- `),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 on(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=>fo(i).then(process.exit)),n.command("approve <id>").description("Approve a showcase submission").option("--yes","Skip confirmation").action((i,l)=>go(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)=>yo(i,l).then(process.exit)),n.command("feature <id>").description("Mark as featured").option("--yes","Skip confirmation").action((i,l)=>ho(i,l).then(process.exit)),n.command("stats").description("Showcase engagement metrics").action(i=>bo(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=>vo(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)=>wo(i,l).then(process.exit)),r.command("publish <id>").description("Publish approved content").option("--yes","Skip confirmation").action((i,l)=>Ro(i,l).then(process.exit)),r.command("analytics").description("Content performance metrics").option("--format <format>","Output format (json|text)").action(i=>So(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=>Co(i).then(process.exit)),o.command("profile <userId>").description("View member profile + activity").action((i,l)=>Eo(i,l).then(process.exit)),o.command("role <userId> <role>").description("Update member role").option("--yes","Skip confirmation").action((i,l,u)=>ko(i,l,u).then(process.exit)),o.command("invite <email>").description("Invite to community").action((i,l)=>Oo(i,l).then(process.exit)),o.command("ban <userId>").description("Ban member").option("--reason <text>","Ban reason").option("--yes","Skip confirmation").action((i,l)=>xo(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=>$o(i).then(process.exit));let a=t.command("moderate").description("AI-assisted moderation queue");a.command("queue").description("Show pending moderation items").action(i=>Ao(i).then(process.exit)),a.command("auto").description("Run AI moderation sweep").option("--dry-run","Preview without committing").action(i=>_o(i).then(process.exit))}import{appendFileSync as Po,existsSync as Io,readFileSync as No,writeFileSync as To}from"fs";import{homedir as Ue}from"os";import{join as $e}from"path";import*as K from"@clack/prompts";import G from"picocolors";var Qe=["init","add","create","mcp","schema","brand","i18n","infra","env","license","ai","auth","billing","stats","db","generate","preset","dev","test","admin","community","growth","ecosystem","services","search","secrets","completions","doctor"],sn={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",preset:"List and apply SaaS presets",dev:"Start development server",test:"Run unit and E2E tests",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"},jo=["--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"],Rt=["-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"],Uo={"-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},Do=Object.entries(Uo).map(([e,t])=>` ${e})
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 In(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=>Is(i).then(process.exit)),n.command("approve <id>").description("Approve a showcase submission").option("--yes","Skip confirmation").action((i,l)=>Ts(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)=>Us(i,l).then(process.exit)),n.command("feature <id>").description("Mark as featured").option("--yes","Skip confirmation").action((i,l)=>js(i,l).then(process.exit)),n.command("stats").description("Showcase engagement metrics").action(i=>Ls(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=>Ds(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)=>Fs(i,l).then(process.exit)),r.command("publish <id>").description("Publish approved content").option("--yes","Skip confirmation").action((i,l)=>Ms(i,l).then(process.exit)),r.command("analytics").description("Content performance metrics").option("--format <format>","Output format (json|text)").action(i=>Gs(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=>Vs(i).then(process.exit)),o.command("profile <userId>").description("View member profile + activity").action((i,l)=>Ks(i,l).then(process.exit)),o.command("role <userId> <role>").description("Update member role").option("--yes","Skip confirmation").action((i,l,u)=>Bs(i,l,u).then(process.exit)),o.command("invite <email>").description("Invite to community").action((i,l)=>qs(i,l).then(process.exit)),o.command("ban <userId>").description("Ban member").option("--reason <text>","Ban reason").option("--yes","Skip confirmation").action((i,l)=>Ws(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=>Ys(i).then(process.exit));let a=t.command("moderate").description("AI-assisted moderation queue");a.command("queue").description("Show pending moderation items").action(i=>Hs(i).then(process.exit)),a.command("auto").description("Run AI moderation sweep").option("--dry-run","Preview without committing").action(i=>zs(i).then(process.exit))}import{appendFileSync as Js,existsSync as Xs,readFileSync as Qs,writeFileSync as Zs}from"fs";import{homedir as Me}from"os";import{join as Ne}from"path";import*as q from"@clack/prompts";import B from"picocolors";var it=["init","add","create","mcp","schema","brand","i18n","infra","env","license","ai","auth","billing","stats","db","generate","preset","dev","test","admin","community","growth","ecosystem","services","search","secrets","completions","doctor"],Tn={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",preset:"List and apply SaaS presets",dev:"Start development server",test:"Run unit and E2E tests",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"},ea=["--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"],jt=["-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"],ta={"-p":v.pm,"--pm":v.pm,"--region":v.region,"--orm":v.orm,"--db":v.db,"--auth":v.auth,"--payment":v.payment,"--deploy":v.deploy,"--docs":v.docs,"--email":v.email,"--storage":v.storage,"--monitoring":v.monitoring,"--analytics":v.analytics,"--sms":v.sms,"--queue":v.queue,"--search":v.search,"--cache":v.cache,"--notifications":v.notifications,"--webhooks":v.webhooks,"--cms":v.cms,"--feature-flags":v.featureFlags,"--captcha":v.captcha,"--mcp":v.mcp,"--metering":v.metering,"--billing-mode":v.billingMode,"--idp":v.idp},na=Object.entries(ta).map(([e,t])=>` ${e})
132
228
  COMPREPLY=( $(compgen -W "${t.join(" ")}" -- \${cur}) )
133
229
  return 0
134
230
  ;;`).join(`
135
- `),Lo=Rt.map(e=>` "${e}"`).join(`
136
- `),Fo=Qe.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${sn[e]}"`).join(`
137
- `),Mo=Rt.map(e=>`complete -c nebutra -n "__fish_seen_subcommand_from create" -f -a "${e}" -d "create-sailor option"`).join(`
138
- `);function an(){return`#!/usr/bin/env bash
231
+ `),ra=jt.map(e=>` "${e}"`).join(`
232
+ `),oa=it.map(e=>`complete -c nebutra -n "__fish_use_subcommand_only" -f -a "${e}" -d "${Tn[e]}"`).join(`
233
+ `),sa=jt.map(e=>`complete -c nebutra -n "__fish_seen_subcommand_from create" -f -a "${e}" -d "create-sailor option"`).join(`
234
+ `);function Un(){return`#!/usr/bin/env bash
139
235
 
140
236
  _nebutra_completions() {
141
237
  local cur prev opts cmd
@@ -144,13 +240,13 @@ _nebutra_completions() {
144
240
  prev="\${COMP_WORDS[COMP_CWORD-1]}"
145
241
 
146
242
  # Subcommands
147
- local subcommands="${Qe.join(" ")}"
243
+ local subcommands="${it.join(" ")}"
148
244
 
149
245
  # Flags
150
- local flags="${jo.join(" ")}"
246
+ local flags="${ea.join(" ")}"
151
247
 
152
248
  case "\${prev}" in
153
- ${Do}
249
+ ${na}
154
250
  esac
155
251
 
156
252
  if [[ \${cur} == -* ]]; then
@@ -164,7 +260,7 @@ ${Do}
164
260
  COMPREPLY=( $(compgen -W "--21st --v0 --provider --dry-run --yes --if-not-exists" -- \${cur}) )
165
261
  elif [[ "\${prev}" == "create" ]]; then
166
262
  # create delegates to create-sailor
167
- COMPREPLY=( $(compgen -W "${Rt.join(" ")}" -- \${cur}) )
263
+ COMPREPLY=( $(compgen -W "${jt.join(" ")}" -- \${cur}) )
168
264
  elif [[ "\${prev}" == "completions" ]]; then
169
265
  # completions command takes shell type
170
266
  COMPREPLY=( $(compgen -W "bash zsh fish install" -- \${cur}) )
@@ -174,11 +270,11 @@ ${Do}
174
270
  }
175
271
 
176
272
  complete -o bashdefault -o default -o nospace -F _nebutra_completions nebutra
177
- `}function cn(){return`#compdef nebutra
273
+ `}function jn(){return`#compdef nebutra
178
274
 
179
275
  _nebutra() {
180
276
  local -a commands=(
181
- ${Qe.map(e=>`"${e}:${sn[e]}"`).join(`
277
+ ${it.map(e=>`"${e}:${Tn[e]}"`).join(`
182
278
  `)}
183
279
  )
184
280
 
@@ -195,7 +291,7 @@ _nebutra() {
195
291
  )
196
292
 
197
293
  local -a create_flags=(
198
- ${Lo}
294
+ ${ra}
199
295
  )
200
296
 
201
297
  local -a mcp_flags=(
@@ -236,12 +332,12 @@ ${Lo}
236
332
  }
237
333
 
238
334
  _nebutra
239
- `}function ln(){return`# Fish shell completions for nebutra
335
+ `}function Ln(){return`# Fish shell completions for nebutra
240
336
 
241
- complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${Qe.join(" ")}" -d "Nebutra governance CLI"
337
+ complete -c nebutra -f -n "__fish_seen_subcommand_from; and not __fish_seen_subcommand_from ${it.join(" ")}" -d "Nebutra governance CLI"
242
338
 
243
339
  # Subcommands
244
- ${Fo}
340
+ ${oa}
245
341
 
246
342
  # Flags
247
343
  complete -c nebutra -f -a "--help" -d "Show help message"
@@ -253,7 +349,7 @@ complete -c nebutra -n "__fish_seen_subcommand_from add" -f -a "--v0" -d "Fetch
253
349
  complete -c nebutra -n "__fish_seen_subcommand_from add" -f -a "--provider" -d "Specify a backend provider"
254
350
 
255
351
  # create command flags
256
- ${Mo}
352
+ ${sa}
257
353
 
258
354
  # mcp command flags
259
355
  complete -c nebutra -n "__fish_seen_subcommand_from mcp" -f -a "--stdio" -d "Use stdio transport (default)"
@@ -268,25 +364,16 @@ complete -c nebutra -n "__fish_seen_subcommand_from completions" -f -a "install"
268
364
  complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--all" -d "Show full schema for all commands"
269
365
  complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--list" -d "List all available command names"
270
366
  complete -c nebutra -n "__fish_seen_subcommand_from schema" -f -a "--exit-codes" -d "Show exit codes reference"
271
- `}function dn(e){let n={bash:an,zsh:cn,fish:ln}[e.toLowerCase()];n||(console.error(G.red(`Error: Unknown shell '${e}'. Supported: bash, zsh, fish`)),process.exit(1)),console.log(n())}async function Go(){let t=(process.env.SHELL||"/bin/bash").split("/").pop()||"bash";K.intro(G.bgCyan(G.black(" nebutra completions install ")));let n=K.spinner();n.start(G.cyan(`Detecting shell: ${t}...`));try{let r=null,o=null,a=null;if(t==="bash"?(r=$e(Ue(),".bashrc"),o=$e(Ue(),".bash_completion.d"),a="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=$e(Ue(),".zshrc"),o=$e(Ue(),".zsh/completions"),a="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=$e(Ue(),".config/fish/completions"),a="# Completions installed to ~/.config/fish/completions/nebutra.fish"):(n.stop(),K.log.warn(G.yellow(`Warning: Unsupported shell '${t}'. Please install completions manually.`)),dn("bash"),K.outro(G.cyan("Run 'nebutra completions bash' (or zsh/fish) to generate completions for your shell.")),process.exit(0)),o){(await import("fs")).mkdirSync(o,{recursive:!0});let l=$e(o,t==="fish"?"nebutra.fish":"nebutra"),u=t==="bash"?an():t==="zsh"?cn():ln();To(l,u),n.stop(G.green(`Completion script installed to ${l}`))}r&&a&&t!=="fish"&&(!Io(r)||!No(r,"utf8").includes("nebutra"))&&(Po(r,(t==="bash"?`
367
+ `}function Dn(e){let n={bash:Un,zsh:jn,fish:Ln}[e.toLowerCase()];n||(console.error(B.red(`Error: Unknown shell '${e}'. Supported: bash, zsh, fish`)),process.exit(c.INVALID_ARGS)),console.log(n())}async function aa(){let t=(process.env.SHELL||"/bin/bash").split("/").pop()||"bash";q.intro(B.bgCyan(B.black(" nebutra completions install ")));let n=q.spinner();n.start(B.cyan(`Detecting shell: ${t}...`));try{let r=null,o=null,a=null;if(t==="bash"?(r=Ne(Me(),".bashrc"),o=Ne(Me(),".bash_completion.d"),a="source ~/.bash_completion.d/nebutra"):t==="zsh"?(r=Ne(Me(),".zshrc"),o=Ne(Me(),".zsh/completions"),a="fpath=(~/.zsh/completions $fpath)"):t==="fish"?(o=Ne(Me(),".config/fish/completions"),a="# Completions installed to ~/.config/fish/completions/nebutra.fish"):(n.stop(),q.log.warn(B.yellow(`Warning: Unsupported shell '${t}'. Please install completions manually.`)),Dn("bash"),q.outro(B.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 l=Ne(o,t==="fish"?"nebutra.fish":"nebutra"),u=t==="bash"?Un():t==="zsh"?jn():Ln();Zs(l,u),n.stop(B.green(`Completion script installed to ${l}`))}r&&a&&t!=="fish"&&(!Xs(r)||!Qs(r,"utf8").includes("nebutra"))&&(Js(r,(t==="bash"?`
272
368
  # nebutra completions
273
369
  [[ -f ~/.bash_completion.d/nebutra ]] && source ~/.bash_completion.d/nebutra`:`
274
370
  # nebutra completions
275
371
  fpath=(~/.zsh/completions $fpath)
276
372
  autoload -Uz compinit && compinit`)+`
277
- `),K.log.info(G.green(`Added nebutra completions to ${r}`))),K.log.info(G.cyan("Completions installed! Restart your shell or run:")),K.log.info(G.dim(` source "${t==="bash"?"~/.bashrc":"~/.zshrc"}"`)),K.outro(G.green("Installation complete!"))}catch(r){n.stop(),K.log.error(G.red("Error installing completions. You can manually add them by running:")),K.log.info(G.cyan(` nebutra completions ${t} >> ~/.${t}rc`)),r instanceof Error&&console.error(G.dim(r.message)),process.exit(1)}}function un(e){e.command("completions [shell]").description("Generate or install shell completions").action(async t=>{!t||t==="install"?await Go():dn(t)})}import{spawn as Ko}from"child_process";import{dirname as qo,resolve as Vo}from"path";import{fileURLToPath as Wo}from"url";import*as ye from"@clack/prompts";import De from"picocolors";var zo=qo(Wo(import.meta.url));function Bo(){let e=[()=>Vo(zo,"../../../create-sailor/dist/index.js")];for(let t of e)try{return t()}catch(n){s.debug("create-sailor binary resolution strategy failed",{error:n})}return"create-sailor"}function mn(e){e.command("create [dir]").description("Scaffold a new Nebutra-Sailor project").allowUnknownOption(!0).action(async(t,n,r)=>{ye.intro(De.bgCyan(De.black(" nebutra create ")));try{let o=Bo(),a=t?[t]:[];if(r.args&&r.args.length>(t?1:0)){let u=r.args.slice(t?1:0);a.push(...u)}let i=ye.spinner();i.start(De.cyan(`Launching create-sailor${t?` in ${t}`:""}...`));let l=Ko(process.execPath,[o,...a],{stdio:"inherit",env:{...process.env}});l.on("close",u=>{i.stop(),u===0&&ye.outro(De.green("Project created successfully! Run 'npm install && npm run dev' to get started.")),process.exit(u??0)}),l.on("error",u=>{i.stop(),s.error(`
373
+ `),q.log.info(B.green(`Added nebutra completions to ${r}`))),q.log.info(B.cyan("Completions installed! Restart your shell or run:")),q.log.info(B.dim(` source "${t==="bash"?"~/.bashrc":"~/.zshrc"}"`)),q.outro(B.green("Installation complete!"))}catch(r){n.stop(),q.log.error(B.red("Error installing completions. You can manually add them by running:")),q.log.info(B.cyan(` nebutra completions ${t} >> ~/.${t}rc`)),r instanceof Error&&console.error(B.dim(r.message)),process.exit(c.ERROR)}}function Fn(e){e.command("completions [shell]").description("Generate or install shell completions").action(async t=>{!t||t==="install"?await aa():Dn(t)})}import{spawn as ia}from"child_process";import{dirname as ca,resolve as la}from"path";import{fileURLToPath as da}from"url";import*as we from"@clack/prompts";import Ge from"picocolors";var ua=ca(da(import.meta.url));function ma(){let e=[()=>la(ua,"../../../create-sailor/dist/index.js")];for(let t of e)try{return t()}catch(n){s.debug("create-sailor binary resolution strategy failed",{error:n})}return"create-sailor"}function Mn(e){e.command("create [dir]").description("Scaffold a new Nebutra-Sailor project").allowUnknownOption(!0).action(async(t,n,r)=>{we.intro(Ge.bgCyan(Ge.black(" nebutra create ")));try{let o=ma(),a=t?[t]:[];if(r.args&&r.args.length>(t?1:0)){let u=r.args.slice(t?1:0);a.push(...u)}let i=we.spinner();i.start(Ge.cyan(`Launching create-sailor${t?` in ${t}`:""}...`));let l=ia(process.execPath,[o,...a],{stdio:"inherit",env:{...process.env}});l.on("close",u=>{i.stop(),u===0&&we.outro(Ge.green("Project created successfully! Run 'npm install && npm run dev' to get started.")),process.exit(u??0)}),l.on("error",u=>{i.stop(),s.error(`
278
374
  Failed to launch create-sailor: ${u.message}`),u.code==="ENOENT"&&(s.warn(`
279
- Tip: Ensure create-sailor is installed or available in your PATH.`),s.info(" Install globally: npm install -g create-sailor")),process.exit(1)})}catch(o){ye.log.error(De.red("Error: Unable to start create-sailor. Ensure it is properly installed.")),o instanceof Error&&s.error(o.message),process.exit(1)}})}import*as Ze from"@clack/prompts";import{stderr as he,stdout as Yo}from"process";import ae from"picocolors";function Ho(){return process.env.NEBUTRA_NON_TTY||process.env.CI||process.env.GITHUB_ACTIONS?!1:process.stderr.isTTY===!0}function Jo(e){if(e)return e;let t=process.env.NEBUTRA_OUTPUT_FORMAT;return t&&["json","table","plain"].includes(t)?t:Ho()?"plain":"json"}function Qo(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 p=String(u[l]??"");r[String(l)]=Math.max(r[String(l)],p.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(p=>String(l[p]??"").padEnd(r[String(p)])).join(" | ");i.push(u)}return i.join(`
280
- `)}function Xo(e){return JSON.stringify(e)}function Zo(e){if(!Array.isArray(e))return St(e);if(e.length===0)return"(empty)";if(typeof e[0]!="object"||e[0]===null)return St(e);let t=Qo(e);return ae.gray(t)}function St(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 E(e,t){let n=Jo(t?.format),r=t?.stream==="stderr"?he:Yo,o;switch(n){case"json":o=Xo(e);break;case"table":o=Zo(e);break;default:o=St(e);break}r.write(o+`
281
- `)}function d(e,t="info"){let n;switch(t){case"error":n=ae.red("\u2716");break;case"warn":n=ae.yellow("\u26A0");break;case"success":n=ae.green("\u2713");break;default:n=ae.blue("\u2139");break}let r=`${n} ${e}`;he.write(r+`
282
- `)}function k(e,t){if(!(process.env.NEBUTRA_DEBUG||process.argv.includes("--debug")))return;let r=ae.dim(`[debug] ${e}`);he.write(r+`
283
- `),t&&Object.keys(t).length>0&&he.write(ae.dim(JSON.stringify(t,null,2))+`
284
- `)}function Xe(e){he.write(`
285
- `),he.write(ae.bold(ae.cyan(e))+`
286
- `),he.write(ae.gray("-".repeat(e.length))+`
287
- `),he.write(`
288
- `)}async function es(e){d("Generating Prisma client"+"...","info");let n=await le("generate",{dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?d("Prisma client generated successfully","success"):(d("Failed to generate Prisma client","error"),process.exit(n.exitCode||1))}async function Ct(e,t){let n=t||{};if(e){d(`Creating migration: ${e}`,"info");let r=await le("migrate",{args:["dev","--name",e],dryRun:n.dryRun,interactive:!n.dryRun});r.exitCode===0?d(`Migration '${e}' created successfully`,"success"):(d(`Failed to create migration '${e}'`,"error"),process.exit(r.exitCode||1))}else{d("Running pending migrations...","info");let r=await le("migrate",{args:["deploy"],dryRun:n.dryRun,interactive:!n.dryRun});r.exitCode===0?d("All pending migrations completed","success"):(d("Migration deployment failed","error"),process.exit(r.exitCode||1))}}async function ts(e){d("Pushing schema to database...","info");let t=await le("db",{args:["push"],dryRun:e.dryRun,interactive:!e.dryRun});t.exitCode===0?d("Schema pushed successfully","success"):(d("Failed to push schema","error"),process.exit(t.exitCode||1))}async function ns(e){d("Seeding database...","info");let t=await le("db",{args:["seed"],dryRun:e.dryRun,interactive:!e.dryRun});t.exitCode===0?d("Database seeded successfully","success"):(d("Failed to seed database","error"),process.exit(t.exitCode||1))}async function rs(e){d("Launching Prisma Studio...","info");let t=await le("studio",{dryRun:e.dryRun,interactive:!0});t.exitCode!==0&&(d("Failed to launch Prisma Studio","error"),process.exit(t.exitCode||1))}async function os(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await Ze.confirm({message:"Reset database? This will delete all data.",initialValue:!1});(Ze.isCancel(r)||!r)&&(d("Reset cancelled","warn"),process.exit(0))}else d("Database reset requires explicit --yes confirmation (use: nebutra db reset --yes)","error"),process.exit(1);d("Resetting database...","warn");let n=await le("migrate",{args:["reset",...e.yes?["--force"]:[]],dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?d("Database reset successfully","success"):(d("Failed to reset database","error"),process.exit(n.exitCode||1))}async function ss(e){d("Checking migration status...","info");let t=await le("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)+`
289
- `)}catch{process.stdout.write(t.stdout)}}else d("Failed to check migration status","error"),process.exit(t.exitCode||1)}function pn(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 es(i);break;case"migrate":r.length>0?r[0]==="create"&&r[1]?await Ct(r[1],i):await Ct(r[0],i):await Ct(void 0,i);break;case"push":await ts(i);break;case"seed":await ns(i);break;case"studio":await rs(i);break;case"reset":await os(i);break;case"status":await ss(i);break;default:d(`Unknown db subcommand: ${n}. Valid commands: generate, migrate, migrate create, push, seed, studio, reset, status`,"error"),process.exit(1)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Database command failed: ${u}`,"error"),k("Full error",{error:l}),process.exit(1)}}).addHelpText("after",`
375
+ Tip: Ensure create-sailor is installed or available in your PATH.`),s.info(" Install globally: npm install -g create-sailor"),process.exit(c.NOT_FOUND)),process.exit(c.ERROR)})}catch(o){we.log.error(Ge.red("Error: Unable to start create-sailor. Ensure it is properly installed.")),o instanceof Error&&s.error(o.message),process.exit(c.ERROR)}})}import*as ct from"@clack/prompts";async function pa(e){d("Generating Prisma client"+"...","info");let n=await ue("generate",{dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?d("Prisma client generated successfully","success"):(d("Failed to generate Prisma client","error"),process.exit(n.exitCode||1))}async function Lt(e,t){let n=t||{};if(e){d(`Creating migration: ${e}`,"info");let r=await ue("migrate",{args:["dev","--name",e],dryRun:n.dryRun,interactive:!n.dryRun});r.exitCode===0?d(`Migration '${e}' created successfully`,"success"):(d(`Failed to create migration '${e}'`,"error"),process.exit(r.exitCode||1))}else{d("Running pending migrations...","info");let r=await ue("migrate",{args:["deploy"],dryRun:n.dryRun,interactive:!n.dryRun});r.exitCode===0?d("All pending migrations completed","success"):(d("Migration deployment failed","error"),process.exit(r.exitCode||1))}}async function fa(e){d("Pushing schema to database...","info");let t=await ue("db",{args:["push"],dryRun:e.dryRun,interactive:!e.dryRun});t.exitCode===0?d("Schema pushed successfully","success"):(d("Failed to push schema","error"),process.exit(t.exitCode||1))}async function ga(e){d("Seeding database...","info");let t=await ue("db",{args:["seed"],dryRun:e.dryRun,interactive:!e.dryRun});t.exitCode===0?d("Database seeded successfully","success"):(d("Failed to seed database","error"),process.exit(t.exitCode||1))}async function ya(e){d("Launching Prisma Studio...","info");let t=await ue("studio",{dryRun:e.dryRun,interactive:!0});t.exitCode!==0&&(d("Failed to launch Prisma Studio","error"),process.exit(t.exitCode||1))}async function ha(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await ct.confirm({message:"Reset database? This will delete all data.",initialValue:!1});(ct.isCancel(r)||!r)&&(d("Reset cancelled","warn"),process.exit(c.CANCELLED))}else d("Database reset requires explicit --yes confirmation (use: nebutra db reset --yes)","error"),process.exit(c.INVALID_ARGS);d("Resetting database...","warn");let n=await ue("migrate",{args:["reset",...e.yes?["--force"]:[]],dryRun:e.dryRun,interactive:!e.dryRun});n.exitCode===0?d("Database reset successfully","success"):(d("Failed to reset database","error"),process.exit(n.exitCode||1))}async function ba(e){d("Checking migration status...","info");let t=await ue("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)+`
376
+ `)}catch{process.stdout.write(t.stdout)}}else d("Failed to check migration status","error"),process.exit(t.exitCode||1)}function Gn(e){e.command("db <verb> [args...]").description("Manage database schema, migrations, and state").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations (especially for reset)").option("--format <type>","Output format: json, plain","plain").action(async(n,r,o)=>{let 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 pa(i);break;case"migrate":r.length>0?r[0]==="create"&&r[1]?await Lt(r[1],i):await Lt(r[0],i):await Lt(void 0,i);break;case"push":await fa(i);break;case"seed":await ga(i);break;case"studio":await ya(i);break;case"reset":await ha(i);break;case"status":await ba(i);break;default:d(`Unknown db subcommand: ${n}. Valid commands: generate, migrate, migrate create, push, seed, studio, reset, status`,"error"),process.exit(c.INVALID_ARGS)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Database command failed: ${u}`,"error"),_("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
290
377
  Examples:
291
378
  nebutra db generate Generate Prisma client
292
379
  nebutra db migrate Run all pending migrations
@@ -301,64 +388,54 @@ Flags:
301
388
  --dry-run Show what would be run without executing
302
389
  --yes Skip confirmations
303
390
  --format <type> Output format: json, plain (default: plain)
304
- `)}import*as O from"@clack/prompts";import w from"picocolors";var Ae=["landing-page","web","storybook","api-gateway","design-docs","studio","docs"],Et=["ai-saas","marketing","dashboard","growth","enterprise"];function et(e){let t=`@nebutra/${e}`;if(!Ae.includes(e)){let n=w.yellow(`Valid apps: ${Ae.join(", ")}`);throw new Error(`Invalid app: ${w.red(e)}
305
- ${n}`)}return t}function as(e){if(!Et.includes(e)){let t=w.yellow(`Valid presets: ${Et.join(", ")}`);throw new Error(`Invalid preset: ${w.red(e)}
306
- ${t}`)}return e}async function is(e){if(e.dryRun){let t={mode:"dry-run",timestamp:new Date().toISOString(),command:"dev",options:{app:e.app,preset:e.preset},task:e.app?"turbo dev":e.preset?"pnpm dev":"turbo dev (all apps)"};process.stdout.write(JSON.stringify(t,null,2)+`
307
- `),process.exit(c.DRY_RUN_OK)}try{if(e.app&&e.preset&&(O.log.error(w.red("Cannot specify both --app and --preset")),process.exit(c.INVALID_ARGS)),e.app){et(e.app);let n=`@nebutra/${e.app}`;e.quiet||O.log.info(w.cyan(`Starting dev server for ${w.bold(n)}...`));let r=await pe("dev",{filter:n});process.exit(r.exitCode)}if(e.preset){as(e.preset),e.quiet||O.log.info(w.cyan(`Starting dev with preset ${w.bold(e.preset)}...`));let n=await _(`dev:${e.preset}`,{interactive:!0});process.exit(n.exitCode)}e.quiet||O.log.info(w.cyan("Starting dev servers for all apps..."));let t=await pe("dev");process.exit(t.exitCode)}catch(t){t instanceof Error?O.log.error(w.red(t.message)):O.log.error(w.red("Unknown error occurred")),process.exit(c.ERROR)}}async function cs(e){if(e.dryRun){let 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"};process.stdout.write(JSON.stringify(t,null,2)+`
308
- `),process.exit(c.DRY_RUN_OK)}try{if(e.app&&e.strict&&(O.log.error(w.red("Cannot use --strict with --app filter")),process.exit(c.INVALID_ARGS)),e.app){et(e.app);let r=`@nebutra/${e.app}`;e.quiet||O.log.info(w.cyan(`Building ${w.bold(r)}...`));let o=await pe("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...";O.log.info(w.cyan(r))}let n=await _(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?O.log.error(w.red(t.message)):O.log.error(w.red("Unknown error occurred")),process.exit(c.ERROR)}}async function ls(e){if(e.dryRun){let 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"};process.stdout.write(JSON.stringify(t,null,2)+`
309
- `),process.exit(c.DRY_RUN_OK)}try{if(e.app&&e.fix&&(O.log.error(w.red("Cannot use --fix with --app filter (lint:fix is global only)")),process.exit(c.INVALID_ARGS)),e.app){et(e.app);let r=`@nebutra/${e.app}`;e.quiet||O.log.info(w.cyan(`Linting ${w.bold(r)}...`));let o=await A({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...";O.log.info(w.cyan(r))}let n=await _(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?O.log.error(w.red(t.message)):O.log.error(w.red("Unknown error occurred")),process.exit(c.ERROR)}}async function ds(e){if(e.dryRun){let t={mode:"dry-run",timestamp:new Date().toISOString(),command:"typecheck",options:{app:e.app},task:"turbo typecheck"};process.stdout.write(JSON.stringify(t,null,2)+`
310
- `),process.exit(c.DRY_RUN_OK)}try{if(e.app){et(e.app);let n=`@nebutra/${e.app}`;e.quiet||O.log.info(w.cyan(`Type-checking ${w.bold(n)}...`));let r=await pe("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||O.log.info(w.cyan("Type-checking all packages..."));let t=await pe("typecheck");process.exit(t.exitCode)}catch(t){t instanceof Error?O.log.error(w.red(t.message)):O.log.error(w.red("Unknown error occurred")),process.exit(c.ERROR)}}function fn(e){e.command("dev").description("Start development servers (turbo dev)").option("--app <name>",`App to run: ${Ae.join(", ")}`).option("--preset <name>",`Preset to use: ${Et.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await is({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})}),e.command("build").description("Build all apps (pnpm build or turbo build)").option("--app <name>",`App to build: ${Ae.join(", ")}`).option("--strict","Run strict build with UI governance verification (pnpm build:strict)").option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await cs({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})}),e.command("lint").description("Lint with Biome (pnpm lint or pnpm lint:fix)").option("--app <name>",`App to lint: ${Ae.join(", ")}`).option("--fix","Fix linting issues automatically").option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await ls({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})}),e.command("typecheck").description("Type-check with TypeScript (turbo typecheck)").option("--app <name>",`App to typecheck: ${Ae.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await ds({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})})}import f from"picocolors";var us=process.env.NEBUTRA_ECOSYSTEM_URL||"https://api.nebutra.com/ecosystem",gn=process.env.NEBUTRA_ECOSYSTEM_TOKEN||"";async function x(e,t={}){let{method:n="GET",body:r,dryRun:o=!1,token:a=gn}=t,i=`${us}${e}`;if(o)return s.info(`[DRY RUN] ${n} ${i}`),r&&s.info(`Body: ${JSON.stringify(r,null,2)}`),{ok:!0,status:200,json:async()=>({dryRun:!0})};let l={"Content-Type":"application/json"};a&&(l.Authorization=`Bearer ${a}`);try{let u=await fetch(i,{method:n,headers:l,...r&&{body:JSON.stringify(r)}});if(!u.ok){let p=await u.text();throw new Error(`${u.status}: ${p}`)}return u}catch(u){throw s.error(`Ecosystem API error: ${u}`),u}}function ms(e={}){let t=[{name:"README.md exists",pass:!0},{name:"License file exists",pass:!0},{name:"package.json has description",pass:!0},{name:"No security vulnerabilities",pass:!0},{name:"TypeScript passes",pass:!0}];return e.skipChecks?{valid:!0,checks:t}:{valid:t.every(r=>r.pass),checks:t}}async function ps(e){s.info(f.cyan(`\u{1F4CA} Ecosystem Status Dashboard
311
- `));try{let n=await(await x("/status")).json();return e.format,c.SUCCESS}catch(t){return s.error(`Failed to fetch ecosystem status: ${t}`),c.ERROR}}async function fs(e){s.info(f.cyan(`\u{1F517} Connect to Nebutra Ecosystem
312
- `));let t=e.token||gn;!t&&!e.yes&&(s.warn(`No NEBUTRA_ECOSYSTEM_TOKEN found. Starting OAuth flow...
313
- `),s.info("Visit: "+f.blue("https://nebutra.com/oauth/authorize?scope=ecosystem")),s.info("Then paste your token below:"),t="token_example_"+Math.random().toString(36).slice(2));let n=e.org||"org_default";try{let o=await(await x("/projects/connect",{method:"POST",body:{projectName:"My Project",repository:"https://github.com/user/project",orgId:n},dryRun:e.dryRun,token:t})).json();return e.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would connect project to ecosystem
314
- `)),c.SUCCESS):(s.success(`\u2713 Connected to Nebutra Ecosystem
315
- `),s.info(`Project ID: ${f.cyan(o.projectId)}`),s.info(`Organization: ${f.cyan(n)}`),s.info(`Ecosystem Config: ${f.cyan(".nebutra/ecosystem.json")}
316
- `),s.info(`Next steps: Run ${f.yellow("nebutra ecosystem publish")} to share your project`),c.SUCCESS)}catch(r){return s.error(`Connection failed: ${r}`),c.ERROR}}async function gs(e){s.info(f.cyan(`\u{1F4E4} Publish to Ecosystem Marketplace
317
- `));let t=e.tag||"latest",n=e.visibility||"public",r=ms();s.info(`${f.bold("Pre-Publish Checklist")}
318
- `);for(let o of r.checks){let a=o.pass?f.green("\u2713"):f.red("\u2717")}if(!r.valid)return s.error(`
319
- Fix the checks above before publishing`),c.ERROR;if(n==="public"&&!e.yes&&(s.info(`This project will be ${f.yellow("publicly listed")} in the ecosystem`),s.info(`Continue? Run with ${f.yellow("--yes")} to skip confirmation`),!e.yes))return c.CANCELLED;try{let a=await(await x("/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?(s.info(f.green(`\u2713 [DRY RUN] Would publish to ecosystem
320
- `)),c.SUCCESS):(s.success(`\u2713 Published successfully!
321
- `),s.info(`Marketplace URL: ${f.blue(`https://nebutra.com/templates/${a.projectId}`)}`),s.info(`Visibility: ${n}`),s.info(`Tag: ${t}
322
- `),c.SUCCESS)}catch(o){return s.error(`Publish failed: ${o}`),c.ERROR}}async function ys(e){s.info(f.cyan(`\u{1F4DA} Template Marketplace
323
- `));try{let n=await(await x(`/templates?category=${e.category||""}&sort=${e.sort||"downloads"}`)).json();return e.format==="json"||s.info(`Run ${f.yellow("nebutra ecosystem templates info <id>")} for details`),c.SUCCESS}catch(t){return s.error(`Failed to list templates: ${t}`),c.ERROR}}async function hs(e,t){s.info(f.cyan(`\u{1F50D} Searching templates for "${e}"
324
- `));try{let r=await(await x(`/templates/search?q=${encodeURIComponent(e)}`)).json();return t.format,c.SUCCESS}catch(n){return s.error(`Search failed: ${n}`),c.ERROR}}async function bs(e){s.info(f.cyan(`\u{1F4D6} Template Details
325
- `));try{let n=await(await x(`/templates/${e}`)).json();return s.info(`Install: ${f.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 vs(e,t){s.info(f.cyan(`\u2B07\uFE0F Installing template "${e}"
326
- `));try{let n=await x(`/templates/${e}/install`,{method:"POST",body:{projectName:"my-saas"},dryRun:t.dryRun});return t.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would install template
327
- `)),c.SUCCESS):(s.success(`\u2713 Template installed!
328
- `),s.info("Project: ./my-saas"),s.info(`Next: ${f.yellow("cd my-saas && pnpm install && pnpm dev")}`),c.SUCCESS)}catch(n){return s.error(`Installation failed: ${n}`),c.ERROR}}async function ws(e){s.info(f.cyan(`\u{1F4A1} Ideas Marketplace
329
- `));try{let n=await(await x(`/ideas?status=${e.status||""}&sort=${e.sort||"recent"}`)).json();return e.format==="json"||(s.info(`Vote: ${f.yellow("nebutra ecosystem ideas vote <id>")}`),s.info(`Claim: ${f.yellow("nebutra ecosystem ideas claim <id>")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list ideas: ${t}`),c.ERROR}}async function Rs(e){if(s.info(f.cyan(`\u2728 Submit New Idea
330
- `)),!e.title||!e.description)return s.error("Missing required fields: --title and --description"),c.INVALID_ARGS;try{let n=await(await x("/ideas",{method:"POST",body:{title:e.title,description:e.description,tags:e.tags?.split(",")||[],authorId:"user_current"},dryRun:e.dryRun})).json();return e.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would submit idea
331
- `)),c.SUCCESS):(s.success(`\u2713 Idea submitted!
332
- `),s.info(`Idea URL: ${f.blue(`https://nebutra.com/ideas/${n.ideaId}`)}`),s.info(`Start voting and discussing! Community will help shape it.
333
- `),c.SUCCESS)}catch(t){return s.error(`Submission failed: ${t}`),c.ERROR}}async function Ss(e,t){s.info(f.cyan(`\u{1F44D} Voting on idea "${e}"
334
- `));try{let n=await x(`/ideas/${e}/vote`,{method:"POST",body:{action:"upvote"},dryRun:t.dryRun});return t.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would upvote idea
335
- `)),c.SUCCESS):(s.success(`\u2713 Vote recorded! This idea now has more momentum.
336
- `),c.SUCCESS)}catch(n){return s.error(`Vote failed: ${n}`),c.ERROR}}async function Cs(e,t){s.info(f.cyan(`\u{1F3AF} Claiming idea "${e}"
337
- `));try{let n=await x(`/ideas/${e}/claim`,{method:"POST",body:{claimerId:"user_current",status:"in-progress"},dryRun:t.dryRun});return t.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would claim idea
338
- `)),c.SUCCESS):(s.success(`\u2713 Idea claimed! You're now working on this.
339
- `),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 Es(e,t){if(s.info(f.cyan(`\u{1F4AC} Adding comment to idea "${e}"
340
- `)),!t.message)return s.error("Missing --message parameter"),c.INVALID_ARGS;try{let n=await x(`/ideas/${e}/comments`,{method:"POST",body:{authorId:"user_current",message:t.message},dryRun:t.dryRun});return t.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would post comment
341
- `)),c.SUCCESS):(s.success(`\u2713 Comment posted!
342
- `),c.SUCCESS)}catch(n){return s.error(`Comment failed: ${n}`),c.ERROR}}async function ks(e){s.info(f.cyan(`\u{1F465} Legacy Member Directory
343
- `));try{let n=await(await x(`/opc?skill=${e.skill||""}&industry=${e.industry||""}&sort=${e.sort||"active"}`)).json();return e.format==="json"||(s.info(`View profile: ${f.yellow("nebutra ecosystem opc profile <handle>")}`),s.info(`Register: ${f.yellow("nebutra ecosystem opc register")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list members: ${t}`),c.ERROR}}async function Os(){s.info(f.cyan(`\u{1F464} Legacy Member Profile
344
- `));try{let t=await(await x("/opc/me")).json();return s.info(`Edit profile: ${f.yellow("nebutra ecosystem opc register")}`),c.SUCCESS}catch(e){return s.error(`Failed to load profile: ${e}`),c.ERROR}}async function xs(e){s.info(f.cyan(`\u{1F4DD} Register Legacy Member Profile
391
+ `)}import*as A from"@clack/prompts";import S from"picocolors";var Ie=["landing-page","web","storybook","design-docs","sailor-docs","studio","docs","idp","mail-preview","gateway"],Dt=["ai-saas","marketing","dashboard","growth","enterprise"];function lt(e){let t=`@nebutra/${e}`;if(!Ie.includes(e)){let n=S.yellow(`Valid apps: ${Ie.join(", ")}`);throw new Error(`Invalid app: ${S.red(e)}
392
+ ${n}`)}return t}function va(e){if(!Dt.includes(e)){let t=S.yellow(`Valid presets: ${Dt.join(", ")}`);throw new Error(`Invalid preset: ${S.red(e)}
393
+ ${t}`)}return e}async function wa(e){e.dryRun&&(x({mode:"dry-run",timestamp:new Date().toISOString(),command:"dev",options:{app:e.app,preset:e.preset},task:e.app?"turbo dev":e.preset?"pnpm dev":"turbo dev (all apps)"},{format:e.format}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.preset&&(A.log.error(S.red("Cannot specify both --app and --preset")),process.exit(c.INVALID_ARGS)),e.app){lt(e.app);let n=`@nebutra/${e.app}`;e.quiet||A.log.info(S.cyan(`Starting dev server for ${S.bold(n)}...`));let r=await ge("dev",{filter:n});process.exit(r.exitCode)}if(e.preset){va(e.preset),e.quiet||A.log.info(S.cyan(`Starting dev with preset ${S.bold(e.preset)}...`));let n=await I(`dev:${e.preset}`,{interactive:!0});process.exit(n.exitCode)}e.quiet||A.log.info(S.cyan("Starting dev servers for all apps..."));let t=await ge("dev");process.exit(t.exitCode)}catch(t){t instanceof Error?A.log.error(S.red(t.message)):A.log.error(S.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Sa(e){e.dryRun&&(x({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:e.format}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.strict&&(A.log.error(S.red("Cannot use --strict with --app filter")),process.exit(c.INVALID_ARGS)),e.app){lt(e.app);let r=`@nebutra/${e.app}`;e.quiet||A.log.info(S.cyan(`Building ${S.bold(r)}...`));let o=await ge("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...";A.log.info(S.cyan(r))}let n=await I(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?A.log.error(S.red(t.message)):A.log.error(S.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Ra(e){e.dryRun&&(x({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:e.format}),process.exit(c.DRY_RUN_OK));try{if(e.app&&e.fix&&(A.log.error(S.red("Cannot use --fix with --app filter (lint:fix is global only)")),process.exit(c.INVALID_ARGS)),e.app){lt(e.app);let r=`@nebutra/${e.app}`;e.quiet||A.log.info(S.cyan(`Linting ${S.bold(r)}...`));let o=await $({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...";A.log.info(S.cyan(r))}let n=await I(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?A.log.error(S.red(t.message)):A.log.error(S.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Ea(e){e.dryRun&&(x({mode:"dry-run",timestamp:new Date().toISOString(),command:"typecheck",options:{app:e.app},task:"turbo typecheck"},{format:e.format}),process.exit(c.DRY_RUN_OK));try{if(e.app){lt(e.app);let n=`@nebutra/${e.app}`;e.quiet||A.log.info(S.cyan(`Type-checking ${S.bold(n)}...`));let r=await ge("typecheck",{filter:n});process.exit(r.exitCode)}e.quiet||A.log.info(S.cyan("Type-checking all packages..."));let t=await ge("typecheck");process.exit(t.exitCode)}catch(t){t instanceof Error?A.log.error(S.red(t.message)):A.log.error(S.red("Unknown error occurred")),process.exit(c.ERROR)}}function Vn(e){e.command("dev").description("Start development servers (turbo dev)").option("--app <name>",`App to run: ${Ie.join(", ")}`).option("--preset <name>",`Preset to use: ${Dt.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await wa({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})}),e.command("build").description("Build all apps (pnpm build or turbo build)").option("--app <name>",`App to build: ${Ie.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=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await Sa({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})}),e.command("lint").description("Lint with Biome (pnpm lint or pnpm lint:fix)").option("--app <name>",`App to lint: ${Ie.join(", ")}`).option("--fix","Fix linting issues automatically").option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await Ra({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})}),e.command("typecheck").description("Type-check with TypeScript (turbo typecheck)").option("--app <name>",`App to typecheck: ${Ie.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async t=>{let n=t.optsWithGlobals?t.optsWithGlobals():t;await Ea({...t,quiet:n.quiet||!1,verbose:n.verbose||!1,format:n.format})})}import Kn from"fs";import Bn from"path";import Ft from"picocolors";var Mt=["smoke","golden","sleptons"],Ca={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 ka(e,t={}){Mt.includes(e)||(s.error(`Invalid suite: ${Ft.red(e)}. Valid: ${Mt.join(", ")}`),process.exit(c.INVALID_ARGS));let n=h(),{config:r,suiteDir:o}=Ca[e],a=Bn.join(n,r),i=Bn.join(n,o);(!Kn.existsSync(i)||!Kn.existsSync(a))&&(s.error(`Suite ${Ft.red(e)} not found at ${o}.
394
+ Expected config: ${r}
395
+ Remediation: scaffold the suite (analogous to 'nebutra workflow init <provider>')
396
+ or restore the directory from git.`),process.exit(c.NOT_FOUND)),t.dryRun&&(x({mode:"dry-run",command:`e2e ${e}`,task:`pnpm exec playwright test --config ${r}`}),process.exit(c.DRY_RUN_OK)),t.quiet||s.info(`Running Playwright suite: ${Ft.bold(e)}`);let l=await $({command:"pnpm",args:["exec","playwright","test","--config",r],interactive:!0,label:`playwright ${e}`});process.exit(l.exitCode)}function qn(e){e.command("e2e <suite>").description(`Run a Playwright suite (${Mt.join(" | ")})`).option("--dry-run","Preview the command that would run (exit code 10)").action(async(t,n)=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await ka(t,{dryRun:n.dryRun||!1,quiet:r.quiet||!1})})}import y from"picocolors";var Oa=process.env.NEBUTRA_ECOSYSTEM_URL||"https://api.nebutra.com/ecosystem",Wn=process.env.NEBUTRA_ECOSYSTEM_TOKEN||"";async function P(e,t={}){let{method:n="GET",body:r,dryRun:o=!1,token:a=Wn}=t,i=`${Oa}${e}`;if(o)return d(`[DRY RUN] ${n} ${i}`),r&&d(`Body: ${JSON.stringify(r)}`),x({mode:"dry-run",method:n,url:i,...r&&{body:r}}),{ok:!0,status:200,json:async()=>({dryRun:!0})};let l={"Content-Type":"application/json"};a&&(l.Authorization=`Bearer ${a}`);try{let u=await fetch(i,{method:n,headers:l,...r&&{body:JSON.stringify(r)}});if(!u.ok){let m=await u.text();throw new Error(`${u.status}: ${m}`)}return u}catch(u){throw s.error(`Ecosystem API error: ${u}`),u}}function xa(e={}){let t=[{name:"README.md exists",pass:!0},{name:"License file exists",pass:!0},{name:"package.json has description",pass:!0},{name:"No security vulnerabilities",pass:!0},{name:"TypeScript passes",pass:!0}];return e.skipChecks?{valid:!0,checks:t}:{valid:t.every(r=>r.pass),checks:t}}async function _a(e){s.info(y.cyan(`\u{1F4CA} Ecosystem Status Dashboard
397
+ `));try{let n=await(await P("/status")).json();return e.format,c.SUCCESS}catch(t){return s.error(`Failed to fetch ecosystem status: ${t}`),c.ERROR}}async function Aa(e){s.info(y.cyan(`\u{1F517} Connect to Nebutra Ecosystem
398
+ `));let t=e.token||Wn;!t&&!e.yes&&(s.warn(`No NEBUTRA_ECOSYSTEM_TOKEN found. Starting OAuth flow...
399
+ `),s.info("Visit: "+y.blue("https://nebutra.com/oauth/authorize?scope=ecosystem")),s.info("Then paste your token below:"),t="token_example_"+Math.random().toString(36).slice(2));let n=e.org||"org_default";try{let o=await(await P("/projects/connect",{method:"POST",body:{projectName:"My Project",repository:"https://github.com/user/project",orgId:n},dryRun:e.dryRun,token:t})).json();return e.dryRun?(d("[DRY RUN] Would connect project to ecosystem","success"),c.SUCCESS):(s.success(`\u2713 Connected to Nebutra Ecosystem
400
+ `),s.info(`Project ID: ${y.cyan(o.projectId)}`),s.info(`Organization: ${y.cyan(n)}`),s.info(`Ecosystem Config: ${y.cyan(".nebutra/ecosystem.json")}
401
+ `),s.info(`Next steps: Run ${y.yellow("nebutra ecosystem publish")} to share your project`),c.SUCCESS)}catch(r){return s.error(`Connection failed: ${r}`),c.ERROR}}async function $a(e){s.info(y.cyan(`\u{1F4E4} Publish to Ecosystem Marketplace
402
+ `));let t=e.tag||"latest",n=e.visibility||"public",r=xa();s.info(`${y.bold("Pre-Publish Checklist")}
403
+ `);for(let o of r.checks){let a=o.pass?y.green("\u2713"):y.red("\u2717")}if(!r.valid)return s.error(`
404
+ Fix the checks above before publishing`),c.ERROR;if(n==="public"&&!e.yes&&(s.info(`This project will be ${y.yellow("publicly listed")} in the ecosystem`),s.info(`Continue? Run with ${y.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!
405
+ `),s.info(`Marketplace URL: ${y.blue(`https://nebutra.com/templates/${a.projectId}`)}`),s.info(`Visibility: ${n}`),s.info(`Tag: ${t}
406
+ `),c.SUCCESS)}catch(o){return s.error(`Publish failed: ${o}`),c.ERROR}}async function Pa(e){s.info(y.cyan(`\u{1F4DA} Template Marketplace
407
+ `));try{let n=await(await P(`/templates?category=${e.category||""}&sort=${e.sort||"downloads"}`)).json();return e.format==="json"||s.info(`Run ${y.yellow("nebutra ecosystem templates info <id>")} for details`),c.SUCCESS}catch(t){return s.error(`Failed to list templates: ${t}`),c.ERROR}}async function Na(e,t){s.info(y.cyan(`\u{1F50D} Searching templates for "${e}"
408
+ `));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 Ia(e){s.info(y.cyan(`\u{1F4D6} Template Details
409
+ `));try{let n=await(await P(`/templates/${e}`)).json();return s.info(`Install: ${y.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 Ta(e,t){s.info(y.cyan(`\u2B07\uFE0F Installing template "${e}"
410
+ `));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!
411
+ `),s.info("Project: ./my-saas"),s.info(`Next: ${y.yellow("cd my-saas && pnpm install && pnpm dev")}`),c.SUCCESS)}catch(n){return s.error(`Installation failed: ${n}`),c.ERROR}}async function Ua(e){s.info(y.cyan(`\u{1F4A1} Ideas Marketplace
412
+ `));try{let n=await(await P(`/ideas?status=${e.status||""}&sort=${e.sort||"recent"}`)).json();return e.format==="json"||(s.info(`Vote: ${y.yellow("nebutra ecosystem ideas vote <id>")}`),s.info(`Claim: ${y.yellow("nebutra ecosystem ideas claim <id>")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list ideas: ${t}`),c.ERROR}}async function ja(e){if(s.info(y.cyan(`\u2728 Submit New Idea
413
+ `)),!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!
414
+ `),s.info(`Idea URL: ${y.blue(`https://nebutra.com/ideas/${n.ideaId}`)}`),s.info(`Start voting and discussing! Community will help shape it.
415
+ `),c.SUCCESS)}catch(t){return s.error(`Submission failed: ${t}`),c.ERROR}}async function La(e,t){s.info(y.cyan(`\u{1F44D} Voting on idea "${e}"
416
+ `));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.
417
+ `),c.SUCCESS)}catch(n){return s.error(`Vote failed: ${n}`),c.ERROR}}async function Da(e,t){s.info(y.cyan(`\u{1F3AF} Claiming idea "${e}"
418
+ `));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.
419
+ `),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 Fa(e,t){if(s.info(y.cyan(`\u{1F4AC} Adding comment to idea "${e}"
420
+ `)),!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!
421
+ `),c.SUCCESS)}catch(n){return s.error(`Comment failed: ${n}`),c.ERROR}}async function Ma(e){s.info(y.cyan(`\u{1F465} Legacy Member Directory
422
+ `));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: ${y.yellow("nebutra ecosystem opc profile <handle>")}`),s.info(`Register: ${y.yellow("nebutra ecosystem opc register")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list members: ${t}`),c.ERROR}}async function Ga(){s.info(y.cyan(`\u{1F464} Legacy Member Profile
423
+ `));try{let t=await(await P("/opc/me")).json();return s.info(`Edit profile: ${y.yellow("nebutra ecosystem opc register")}`),c.SUCCESS}catch(e){return s.error(`Failed to load profile: ${e}`),c.ERROR}}async function Va(e){s.info(y.cyan(`\u{1F4DD} Register Legacy Member Profile
345
424
  `));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:
346
- `),c.SUCCESS;if(!e.yes)return s.info("This will create your public legacy member profile."),s.info(`Run with ${f.yellow("--yes")} to confirm`),c.CANCELLED;try{let n=await x("/opc/register",{method:"POST",body:t});return s.success(`\u2713 Legacy member profile created!
347
- `),s.info(`View at: ${f.blue("https://nebutra.com/members/your-handle")}`),s.info(`Compatibility command: ${f.yellow("nebutra ecosystem opc profile --share")}`),c.SUCCESS}catch(n){return s.error(`Registration failed: ${n}`),c.ERROR}}async function $s(e){s.info(f.cyan(`\u2B50 Project Showcase
348
- `));try{let n=await(await x(`/showcase?category=${e.category||""}&featured=${e.featured?"true":""}`)).json();return e.format==="json"||(s.info(`Vote: ${f.yellow("nebutra ecosystem showcase vote <id>")}`),s.info(`Submit yours: ${f.yellow("nebutra ecosystem showcase submit")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list showcase: ${t}`),c.ERROR}}async function As(e){s.info(f.cyan(`\u{1F389} Submit Project to Showcase
349
- `));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 ${f.yellow("--yes")} to confirm`),c.CANCELLED;try{let n=await x("/showcase/submit",{method:"POST",body:t,dryRun:e.dryRun});return e.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would submit to showcase
350
- `)),c.SUCCESS):(s.success(`\u2713 Project added to showcase!
351
- `),s.info(`View at: ${f.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 _s(e,t){s.info(f.cyan(`\u{1F44D} Voting on showcase project "${e}"
352
- `));try{let n=await x(`/showcase/${e}/vote`,{method:"POST",body:{action:"upvote"},dryRun:t.dryRun});return t.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would upvote project
353
- `)),c.SUCCESS):(s.success(`\u2713 Vote recorded! You're supporting this project.
354
- `),c.SUCCESS)}catch(n){return s.error(`Vote failed: ${n}`),c.ERROR}}async function Ps(e){s.info(f.cyan(`\u{1F504} Sync with Ecosystem
355
- `));let t=!e.push,n=e.push?"push":"pull";try{let r=await x("/sync",{method:"POST",body:{direction:n,timestamp:new Date().toISOString()},dryRun:e.dryRun});return e.dryRun?(s.info(f.green(`\u2713 [DRY RUN] Would sync (${n})
425
+ `),c.SUCCESS;if(!e.yes)return s.info("This will create your public legacy member profile."),s.info(`Run with ${y.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!
426
+ `),s.info(`View at: ${y.blue("https://nebutra.com/members/your-handle")}`),s.info(`Compatibility command: ${y.yellow("nebutra ecosystem opc profile --share")}`),c.SUCCESS}catch(n){return s.error(`Registration failed: ${n}`),c.ERROR}}async function Ka(e){s.info(y.cyan(`\u2B50 Project Showcase
427
+ `));try{let n=await(await P(`/showcase?category=${e.category||""}&featured=${e.featured?"true":""}`)).json();return e.format==="json"||(s.info(`Vote: ${y.yellow("nebutra ecosystem showcase vote <id>")}`),s.info(`Submit yours: ${y.yellow("nebutra ecosystem showcase submit")}`)),c.SUCCESS}catch(t){return s.error(`Failed to list showcase: ${t}`),c.ERROR}}async function Ba(e){s.info(y.cyan(`\u{1F389} Submit Project to Showcase
428
+ `));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 ${y.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!
429
+ `),s.info(`View at: ${y.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 qa(e,t){s.info(y.cyan(`\u{1F44D} Voting on showcase project "${e}"
430
+ `));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.
431
+ `),c.SUCCESS)}catch(n){return s.error(`Vote failed: ${n}`),c.ERROR}}async function Wa(e){s.info(y.cyan(`\u{1F504} Sync with Ecosystem
432
+ `));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(y.green(`\u2713 [DRY RUN] Would sync (${n})
356
433
  `)),c.SUCCESS):(s.success(`\u2713 Synced!
357
- `),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 yn(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 ps(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 fs(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 gs(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 ys(i)}),n.command("search <query>").description("Search templates").option("--format <format>","Output format","text").action(async(i,l)=>{await hs(i,l)}),n.command("info <id>").description("Template details").action(async i=>{await bs(i)}),n.command("install <id>").description("Install/fork a template").option("--dry-run","Preview without making changes").action(async(i,l)=>{await vs(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 ws(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 Rs(i)}),r.command("vote <id>").description("Upvote an idea").option("--dry-run","Preview without making changes").action(async(i,l)=>{await Ss(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 Cs(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 Es(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 ks(i)}),o.command("profile").description("View/edit your legacy member profile").action(async()=>{await Os()}),o.command("register").description("Register a legacy member profile").option("--yes","Skip confirmations").option("--dry-run","Preview without making changes").action(async i=>{await xs(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 $s(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 As(i)}),a.command("vote <id>").description("Upvote a project (Product Hunt style)").option("--dry-run","Preview without making changes").action(async(i,l)=>{await _s(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 Ps(i)})}import{existsSync as tt,readFileSync as hn,writeFileSync as Is}from"fs";import{resolve as nt}from"path";import*as Se from"@clack/prompts";import Ns from"picocolors";function rt(e){let t=nt(e,".env.example");if(!tt(t))throw new Error(`.env.example not found at ${t}`);let n=hn(t,"utf-8"),r={};for(let o of n.split(`
358
- `)){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 kt(e){let t=nt(e,".env.local"),n=nt(e,".env"),r=tt(t)?t:n;if(!tt(r))return{};let o=hn(r,"utf-8"),a={};for(let i of o.split(`
359
- `)){if(i.trim().startsWith("#")||!i.trim())continue;let l=i.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(l){let[,u,p]=l;a[u]=p.replace(/^["'](.*)["']$/,"$1")}}return a}function Ts(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function js(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 Us(e){d("Validating environment variables...","info");let t=R(),n=rt(t),r=kt(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")E({valid:i,checked:Object.keys(n).length,missing:Object.entries(a).filter(([,l])=>!l).map(([l])=>l)},{format:"json"});else{Xe("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(1)}async function Ds(e){let t=R(),n=rt(t),r=nt(t,".env.local");if(tt(r)&&!e.yes&&!e.dryRun){let u=await Se.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(Se.isCancel(u)||!u)&&(d("Template generation cancelled","warn"),process.exit(0))}d("Generating .env.local from template...","info");let o={},a=0,i=Object.keys(n).length;for(let[u,p]of Object.entries(n))if(a++,e.yes)o[u]=p;else if(process.stdin.isTTY===!0){let y=`[${a}/${i}] ${u}`,m=await Se.text({message:y,defaultValue:p});Se.isCancel(m)&&(d("Template generation cancelled","warn"),process.exit(0)),o[u]=m}else o[u]=p;let l=Object.entries(o).map(([u,p])=>{let m=/[\s=]/.test(p)?`"${p}"`:p;return`${u}=${m}`}).join(`
360
- `);e.dryRun?(d("Dry-run: would write .env.local","info"),E(l,{format:"plain"})):(Is(r,l+`
361
- `),d(`Environment template written to ${r}`,"success"))}async function Ls(e){d("Comparing environment variables...","info");let t=R(),n=rt(t),r=kt(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")E({matching:i.length,missing:o.length,extra:a.length,missing_vars:o,extra_vars:a},{format:"json"});else{if(Xe("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 Fs(e){d("Reading environment variables...","info");let t=R(),n=kt(t),r=rt(t),o={};for(let a of Object.keys(r))if(a in n){let i=n[a];o[a]=Ts(a,i)?js(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;E(a,{format:"json"})}else{Xe("Current Environment Variables");let a=Object.entries(o).map(([i,l])=>({Variable:Ns.cyan(i),Value:l}));E(a,{format:"table"}),d("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function bn(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 Us(a);break;case"template":await Ds(a);break;case"diff":await Ls(a);break;case"show":await Fs(a);break;default:d(`Unknown env subcommand: ${n}. Valid commands: validate, template, diff, show`,"error"),process.exit(1)}}catch(i){let l=i instanceof Error?i.message:String(i);d(`Environment command failed: ${l}`,"error"),k("Full error",{error:i}),process.exit(1)}}).addHelpText("after",`
434
+ `),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 Yn(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 _a(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 Aa(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 $a(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 Pa(i)}),n.command("search <query>").description("Search templates").option("--format <format>","Output format","text").action(async(i,l)=>{await Na(i,l)}),n.command("info <id>").description("Template details").action(async i=>{await Ia(i)}),n.command("install <id>").description("Install/fork a template").option("--dry-run","Preview without making changes").action(async(i,l)=>{await Ta(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 Ua(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 ja(i)}),r.command("vote <id>").description("Upvote an idea").option("--dry-run","Preview without making changes").action(async(i,l)=>{await La(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 Da(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 Fa(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 Ma(i)}),o.command("profile").description("View/edit your legacy member profile").action(async()=>{await Ga()}),o.command("register").description("Register a legacy member profile").option("--yes","Skip confirmations").option("--dry-run","Preview without making changes").action(async i=>{await Va(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 Ka(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 Ba(i)}),a.command("vote <id>").description("Upvote a project (Product Hunt style)").option("--dry-run","Preview without making changes").action(async(i,l)=>{await qa(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 Wa(i)})}import{existsSync as dt,readFileSync as Hn,writeFileSync as Ya}from"fs";import{resolve as ut}from"path";import*as ke from"@clack/prompts";import Ha from"picocolors";function mt(e){let t=ut(e,".env.example");if(!dt(t))throw new Error(`.env.example not found at ${t}`);let n=Hn(t,"utf-8"),r={};for(let o of n.split(`
435
+ `)){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 Gt(e){let t=ut(e,".env.local"),n=ut(e,".env"),r=dt(t)?t:n;if(!dt(r))return{};let o=Hn(r,"utf-8"),a={};for(let i of o.split(`
436
+ `)){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 za(e,t){return["SECRET","KEY","TOKEN","PASSWORD"].some(o=>e.toUpperCase().includes(o))&&t.length>0}function Ja(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 Xa(e){d("Validating environment variables...","info");let t=h(),n=mt(t),r=Gt(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")O({valid:i,checked:Object.keys(n).length,missing:Object.entries(a).filter(([,l])=>!l).map(([l])=>l)},{format:"json"});else{nt("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 Qa(e){let t=h(),n=mt(t),r=ut(t,".env.local");if(dt(r)&&!e.yes&&!e.dryRun){let u=await ke.confirm({message:".env.local already exists. Overwrite?",initialValue:!1});(ke.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 g=`[${a}/${i}] ${u}`,p=await ke.text({message:g,defaultValue:m});ke.isCancel(p)&&(d("Template generation cancelled","warn"),process.exit(c.CANCELLED)),o[u]=p}else o[u]=m;let l=Object.entries(o).map(([u,m])=>{let p=/[\s=]/.test(m)?`"${m}"`:m;return`${u}=${p}`}).join(`
437
+ `);e.dryRun?(d("Dry-run: would write .env.local","info"),O(l,{format:"plain"})):(Ya(r,l+`
438
+ `),d(`Environment template written to ${r}`,"success"))}async function Za(e){d("Comparing environment variables...","info");let t=h(),n=mt(t),r=Gt(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")O({matching:i.length,missing:o.length,extra:a.length,missing_vars:o,extra_vars:a},{format:"json"});else{if(nt("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 ei(e){d("Reading environment variables...","info");let t=h(),n=Gt(t),r=mt(t),o={};for(let a of Object.keys(r))if(a in n){let i=n[a];o[a]=za(a,i)?Ja(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;O(a,{format:"json"})}else{nt("Current Environment Variables");let a=Object.entries(o).map(([i,l])=>({Variable:Ha.cyan(i),Value:l}));O(a,{format:"table"}),d("Note: Sensitive values (KEY, TOKEN, SECRET, PASSWORD) are masked","info")}}function zn(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 Xa(a);break;case"template":await Qa(a);break;case"diff":await Za(a);break;case"show":await ei(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"),_("Full error",{error:i}),process.exit(c.ERROR)}}).addHelpText("after",`
362
439
  Examples:
363
440
  nebutra env validate Check all required vars are set
364
441
  nebutra env template Generate .env.local from .env.example with prompts
@@ -375,7 +452,7 @@ Flags:
375
452
  Sensitive Variables:
376
453
  Variables with KEY, TOKEN, SECRET, PASSWORD in their names are masked in output.
377
454
  This prevents accidental exposure of credentials.
378
- `)}import{promises as vn}from"fs";import{join as Ce}from"path";import*as Le from"@clack/prompts";import j from"picocolors";function wn(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
455
+ `)}import{promises as Jn}from"fs";import{join as Oe}from"path";import*as Ve from"@clack/prompts";import D from"picocolors";function Xn(e){let t=e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("");return{"package.json":`{
379
456
  "name": "@nebutra/${e}",
380
457
  "version": "0.0.0",
381
458
  "private": true,
@@ -460,7 +537,7 @@ export default function RootLayout({
460
537
 
461
538
  @theme {
462
539
  --color-*: var(--neutral-*);
463
- }`}}function Rn(e){return{"package.json":`{
540
+ }`}}function Qn(e){return{"package.json":`{
464
541
  "name": "@nebutra/${e}",
465
542
  "version": "0.0.0",
466
543
  "type": "module",
@@ -497,7 +574,7 @@ export default function RootLayout({
497
574
 
498
575
  export function hello(name: string): string {
499
576
  return \`Hello, \${name}!\`;
500
- }`}}function Sn(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
577
+ }`}}function Zn(e){let t=e.replace(/\//g,"_").replace(/-/g,"_");return{[`src/routes/${e}.ts`]:`import { Hono } from "hono";
501
578
  import { z } from "zod";
502
579
 
503
580
  type Env = {
@@ -548,7 +625,7 @@ app.post("/", async (c) => {
548
625
  );
549
626
  });
550
627
 
551
- export default app;`}}function Cn(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
+ export default app;`}}function er(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";
552
629
  import { cn } from "@nebutra/ui/utils";
553
630
 
554
631
  const ${t}Variants = cva(
@@ -622,13 +699,13 @@ export const AllSizes: Story = {
622
699
  <${n} size="lg">Large</\${pascalCase}>
623
700
  </div>
624
701
  ),
625
- };`}}async function ot(e,t,n){let r=R(),o=[],a={};switch(e){case"app":a=wn(t);break;case"package":a=Rn(t);break;case"route":a=Sn(t);break;case"component":a=Cn(t);break;default:throw new Error(`Unknown generate type: ${e}`)}for(let[i,l]of Object.entries(a)){let u=e==="app"?Ce(r,"apps",t,i):e==="package"?Ce(r,"packages",t,i):Ce(r,"apps/api-gateway",i);o.push({path:u,size:Buffer.byteLength(l)})}return o}async function st(e,t){let n=R(),r=[],o={};switch(e){case"app":o=wn(t);break;case"package":o=Rn(t);break;case"route":o=Sn(t);break;case"component":o=Cn(t);break;default:throw new Error(`Unknown generate type: ${e}`)}for(let[a,i]of Object.entries(o)){let l;e==="app"?l=Ce(n,"apps",t,a):e==="package"?l=Ce(n,"packages",t,a):e==="component"?l=Ce(n,"packages/ui",a):l=Ce(n,"apps/api-gateway",a);let u=l.substring(0,l.lastIndexOf("/"));await vn.mkdir(u,{recursive:!0}),await vn.writeFile(l,i,"utf-8"),r.push(l)}return r}async function Ms(e,t){if(t.dryRun){let r=await ot("app",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"app",name:e,location:`apps/${e}`,files:r.map(a=>({path:a.path,sizeBytes:a.size})),instructions:[`cd apps/${e}`,"pnpm install","pnpm run dev"]};process.stdout.write(JSON.stringify(o,null,2)+`
626
- `),process.exit(c.DRY_RUN_OK)}Le.intro(j.bgCyan(j.black(" nebutra generate app ")));let n=s.spinner();try{n.start(`Generating app ${j.cyan(e)}...`);let r=await st("app",e);n.stop(`Created app ${j.cyan(e)}`,0),s.success(`App created with ${r.length} files`),s.info("Next steps:"),s.info(` cd apps/${e}`),s.info(" pnpm install"),s.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 Gs(e,t){if(t.dryRun){let r=await ot("package",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"package",name:e,location:`packages/${e}`,files:r.map(a=>({path:a.path,sizeBytes:a.size}))};process.stdout.write(JSON.stringify(o,null,2)+`
627
- `),process.exit(c.DRY_RUN_OK)}Le.intro(j.bgCyan(j.black(" nebutra generate package ")));let n=s.spinner();try{n.start(`Generating package ${j.cyan(e)}...`);let r=await st("package",e);n.stop(`Created package ${j.cyan(e)}`,0),s.success(`Package created with ${r.length} files`),s.info("Next steps:"),s.info(` Edit packages/${e}/src/index.ts`),s.info(` Run: pnpm --filter @nebutra/${e} build`),process.exit(c.SUCCESS)}catch(r){n.stop(`Failed to generate package: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function Ks(e,t){if(t.dryRun){let r=await ot("route",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"route",path:e,location:`apps/api-gateway/src/routes/${e}.ts`,files:r.map(a=>({path:a.path,sizeBytes:a.size}))};process.stdout.write(JSON.stringify(o,null,2)+`
628
- `),process.exit(c.DRY_RUN_OK)}Le.intro(j.bgCyan(j.black(" nebutra generate route ")));let n=s.spinner();try{n.start(`Generating route ${j.cyan(e)}...`);let r=await st("route",e);n.stop(`Created route ${j.cyan(e)}`,0),s.success(`Route created with ${r.length} files`),s.info(`File: apps/api-gateway/src/routes/${e}.ts`),s.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 qs(e,t){if(t.dryRun){let r=await ot("component",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"component",name:e,location:"packages/ui/src/components/",files:r.map(a=>({path:a.path,sizeBytes:a.size})),nextSteps:["Add export to packages/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)+`
629
- `),process.exit(c.DRY_RUN_OK)}Le.intro(j.bgCyan(j.black(" nebutra generate component ")));let n=s.spinner();try{n.start(`Generating component ${j.cyan(e)}...`);let r=await st("component",e);n.stop(`Created component ${j.cyan(e)}`,0),s.success(`Component created with ${r.length} files`),s.info("Files created in packages/ui/src/components/"),s.info("Next steps:"),s.info(" 1. Add export to packages/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)}}function En(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)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Ms(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1,interactive:process.stdin.isTTY})}),t.command("package <name>").description("Scaffold a new package (@nebutra/<name>)").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Gs(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1})}),t.command("route <path>").description("Scaffold a Hono API route in api-gateway").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Ks(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1})}),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)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await qs(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1,variants:r.variants,sizes:r.sizes})})}import _e from"picocolors";async function q(e,t){let n=await R(),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 Vs(e){try{let t=e.period||"7d",n=e.compare;s.info(`Fetching growth metrics for ${t}...`);let r=await q("/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 Ws(e){try{let t=e.period||"7d",n=e.segment||"all";s.info(`Fetching funnel data for ${t} (${n})...`);let r=await q("/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)),p=i<r.length-1?_e.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 zs(e){try{let t=e.period||"weekly",n=parseInt(e.cohorts,10)||8;s.info(`Fetching ${t} cohort data (${n} cohorts)...`);let r=await q("/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 p=a[u];if(typeof p=="number"){let y=p/100,m=String(Math.round(p)).padEnd(8);y>=.7?m=_e.green(m):y>=.4?m=_e.yellow(m):m=_e.red(m),l+=m+" "}})}),c.SUCCESS}catch(t){return s.error(`Cohort error: ${t instanceof Error?t.message:String(t)}`),c.ERROR}}async function Bs(e,t){try{if(e==="stats"){s.info("Fetching newsletter stats...");let n=await q("/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 q("/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 q("/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 Ys(e,t){try{if(e==="status"){s.info("Fetching referral program status...");let n=await q("/referral/status");return c.SUCCESS}if(e==="config"){s.info("Fetching referral config...");let n=await q("/referral/config");return Object.entries(n).forEach(([r,o])=>{}),c.SUCCESS}return e==="leaderboard"?(s.info("Fetching referral leaderboard..."),(await q("/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 Hs(e,t){try{if(e==="list"){s.info("Fetching active experiments...");let n=await q("/experiment");return n.length===0?c.SUCCESS:(n.forEach(r=>{let o=r.status==="running"?_e.yellow("\u25CF"):_e.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 q("/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 q(`/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 q(`/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 Js(e){try{let t=e.focus||"activation",n=e.depth||"quick";s.info(`Generating growth insights (focus: ${t}, depth: ${n})...`);let r=await q("/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 kn(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 Vs(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 Ws(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 zs(a))}),t.command("newsletter <subcommand>").description("Newsletter management").action(async(a,i)=>{process.exit(await Bs(a,i))}),t.command("referral <subcommand>").description("Referral program management").action(async(a,i)=>{process.exit(await Ys(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 Hs(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 Js(a))}),t.option("--dry-run","Preview changes without applying them").option("--format <json|text>","Output format","text").option("--yes","Skip confirmation prompts")}import Ot,{lstatSync as Qs,readdirSync as xt,readFileSync as Xs,writeFileSync as Zs}from"fs";import ie from"path";import{fileURLToPath as ea}from"url";import z from"picocolors";var ta=ie.dirname(ea(import.meta.url));function $t(){let e=new Map,t=ie.join(ta,"../../../apps");if(!Ot.existsSync(t))return e;try{let n=xt(t);for(let r of n){let o=ie.join(t,r),a=ie.join(o,"messages");Ot.existsSync(a)&&Qs(a).isDirectory()&&e.set(r,a)}}catch(n){s.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function Fe(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=Fe(o,a);for(let l of i)n.add(l)}else n.add(a)}return n}function Me(e){try{let t=Xs(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 na(e){if(s.info("Syncing language files across the project..."),(await _("translate",{filter:"landing-page",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 A({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 ra(e){s.info("Validating translation files...");let t=$t();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=xt(a).filter(m=>m.endsWith(".json"));if(l.length===0)continue;let u=ie.join(a,"en.json"),p=Me(u);if(!p){s.warn(`Could not load reference locale en.json from ${o}`);continue}let y=Fe(p);for(let m of l){if(m==="en.json")continue;let h=m.replace(".json",""),M=ie.join(a,m),Y=Me(M);if(!Y){s.debug(`Could not parse ${m}`);continue}let H=Fe(Y),ve=Array.from(y).filter(g=>!H.has(g)),me=Array.from(H).filter(g=>!y.has(g)),Ie=y.size>0?(y.size-ve.length)/y.size*100:100;(ve.length>0||me.length>0)&&(r=!0),i.push({locale:h,totalKeys:y.size,missingKeys:ve,extraKeys:me,coverage:Math.round(Ie*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(`${z.bold(o)}:`);for(let i of a){let u=(i.coverage>=100?z.green:i.coverage>=80?z.yellow:z.red)(`${i.coverage}%`);s.info(` ${z.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 oa(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=$t();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=ie.join(l,`${e}.json`);if(Ot.existsSync(u)){s.warn(`Locale ${e} already exists in ${i}`);continue}try{let h=function(M){for(let Y in M)typeof M[Y]=="string"?M[Y]="":typeof M[Y]=="object"&&M[Y]!==null&&h(M[Y])};var a=h;let p=ie.join(l,"en.json"),y=Me(p);if(!y){s.warn(`Could not load reference en.json from ${i}, skipping...`);continue}let m=JSON.parse(JSON.stringify(y));h(m),t.dryRun?s.info(`Would create ${e} locale in ${i}`):(Zs(u,JSON.stringify(m,null,2)+`
630
- `),r.push({app:i,path:u}),s.success(`Created ${e} locale in ${i}`))}catch(p){s.error(`Failed to create locale in ${i}: ${p instanceof Error?p.message:String(p)}`),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||s.success(`Locale '${e}' added to ${r.length} app(s)`),o&&process.exit(c.ERROR)}async function sa(e){s.info("Checking translation coverage...");let t=$t();t.size===0&&(s.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 l=[];try{let u=xt(i).filter(h=>h.endsWith(".json"));if(u.length===0)continue;let p=ie.join(i,"en.json"),y=Me(p);if(!y){s.debug(`Could not load reference locale from ${a}`);continue}let m=Fe(y);for(let h of u){let M=h.replace(".json",""),Y=ie.join(i,h),H=Me(Y);if(!H)continue;let ve=Fe(H),me=Array.from(ve).filter(ee=>{let Ve=H[ee.split(".")[0]];return Ve!==void 0&&Ve!==""}).length,Ie=m.size-me,g=m.size>0?me/m.size*100:0;l.push({locale:M,coverage:Math.round(g*100)/100,totalKeys:m.size,translatedKeys:me,missingKeys:Ie})}l.length>0&&(n.set(a,l),o++,r+=l.reduce((h,M)=>h+M.coverage,0)/l.length)}catch(u){s.debug(`Error checking status for ${a}: ${u instanceof Error?u.message:String(u)}`)}}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,[l,u])=>(i[l]=u,i),{})};console.log(JSON.stringify(a,null,2))}else{for(let[a,i]of n){s.info(`${z.bold(a)}:`);for(let l of i){let u="",y=Math.round(l.coverage/100*20);u="\u2588".repeat(y)+"\u2591".repeat(20-y);let h=(l.coverage>=100?z.green:l.coverage>=80?z.yellow:z.red)(`${l.coverage.toFixed(1)}%`);s.info(` ${z.cyan(l.locale.padEnd(5))} [${u}] ${h}`),s.info(` ${l.translatedKeys}/${l.totalKeys} keys (${l.missingKeys} missing)`)}}if(o>0){let a=r/o,i=a>=100?z.green:a>=80?z.yellow:z.red;s.info(`
631
- Average coverage: ${i(a.toFixed(1)+"%")}`)}}}function On(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 na({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 ra({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 oa(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 sa({format:n.format||r.format,interactive:r.yes!==!0})})}import*as at from"@clack/prompts";async function aa(e){let t=e.lite?"docker-compose.lite.yml":void 0,n=e.lite?"Starting lite stack (PostgreSQL + Redis)":"Starting full stack";d(n+"...","info");let r=await Oe("up -d",{file:t,profile:e.profile,dryRun:e.dryRun});r.exitCode===0?d("Infrastructure stack started successfully","success"):(d("Failed to start infrastructure stack","error"),k("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function ia(e){d("Stopping infrastructure stack...","info");let t=await Oe("down",{dryRun:e.dryRun});t.exitCode===0?d("Infrastructure stack stopped","success"):(d("Failed to stop infrastructure stack","error"),k("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}async function ca(e){d("Checking infrastructure status...","info");let t=await Oe("ps --format json",{dryRun:e.dryRun});if(t.exitCode===0)try{let n=JSON.parse(t.stdout);if(e.format==="json")E(n,{format:"json"});else{let r=n.map(o=>({name:o.Name,status:o.Status,ports:o.Ports||"-"}));E(r,{format:"table"})}}catch{E(t.stdout,{format:"plain"})}else d("Failed to check infrastructure status","error"),k("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}async function la(e,t){let n=t||{},r=e?`Fetching logs for ${e}...`:"Fetching infrastructure logs...";d(r,"info");let o=["logs","--tail","50"];e&&o.push(e);let a=await Oe(o.join(" "),{dryRun:n.dryRun});a.exitCode===0?E(a.stdout,{format:"plain"}):(d("Failed to fetch logs","error"),k("Docker compose output",{stderr:a.stderr}),process.exit(a.exitCode||1))}async function da(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await at.confirm({message:"Reset infrastructure? This will remove all containers and volumes.",initialValue:!1});(at.isCancel(r)||!r)&&(d("Reset cancelled","warn"),process.exit(0))}else d("Infrastructure reset requires explicit --yes confirmation (use: nebutra infra reset --yes)","error"),process.exit(1);d("Resetting infrastructure stack...","warn");let n=await Oe("down -v",{dryRun:e.dryRun});n.exitCode===0?d("Infrastructure reset successfully","success"):(d("Failed to reset infrastructure","error"),k("Docker compose output",{stderr:n.stderr}),process.exit(n.exitCode||1))}function xn(e){e.command("infra <verb> [service]").description("Manage Docker Compose infrastructure (PostgreSQL, Redis, Meilisearch, 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 aa(i);break;case"down":await ia(i);break;case"status":await ca(i);break;case"logs":await la(r,i);break;case"reset":await da(i);break;default:d(`Unknown infra subcommand: ${n}. Valid commands: up, down, status, logs, reset`,"error"),process.exit(1)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Infrastructure command failed: ${u}`,"error"),k("Full error",{error:l}),process.exit(1)}}).addHelpText("after",`
702
+ };`}}async function pt(e,t,n){let r=h(),o=[],a={};switch(e){case"app":a=Xn(t);break;case"package":a=Qn(t);break;case"route":a=Zn(t);break;case"component":a=er(t);break;default:throw new Error(`Unknown generate type: ${e}`)}for(let[i,l]of Object.entries(a)){let u=e==="app"?Oe(r,"apps",t,i):e==="package"?Oe(r,"packages",t,i):Oe(r,"backends/gateway",i);o.push({path:u,size:Buffer.byteLength(l)})}return o}async function ft(e,t){let n=h(),r=[],o={};switch(e){case"app":o=Xn(t);break;case"package":o=Qn(t);break;case"route":o=Zn(t);break;case"component":o=er(t);break;default:throw new Error(`Unknown generate type: ${e}`)}for(let[a,i]of Object.entries(o)){let l;e==="app"?l=Oe(n,"apps",t,a):e==="package"?l=Oe(n,"packages",t,a):e==="component"?l=Oe(n,"packages/ui",a):l=Oe(n,"backends/gateway",a);let u=l.substring(0,l.lastIndexOf("/"));await Jn.mkdir(u,{recursive:!0}),await Jn.writeFile(l,i,"utf-8"),r.push(l)}return r}async function ti(e,t){if(t.dryRun){let r=await pt("app",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"app",name:e,location:`apps/${e}`,files:r.map(a=>({path:a.path,sizeBytes:a.size})),instructions:[`cd apps/${e}`,"pnpm install","pnpm run dev"]};process.stdout.write(JSON.stringify(o,null,2)+`
703
+ `),process.exit(c.DRY_RUN_OK)}Ve.intro(D.bgCyan(D.black(" nebutra generate app ")));let n=s.spinner();try{n.start(`Generating app ${D.cyan(e)}...`);let r=await ft("app",e);n.stop(`Created app ${D.cyan(e)}`,0),s.success(`App created with ${r.length} files`),s.info("Next steps:"),s.info(` cd apps/${e}`),s.info(" pnpm install"),s.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 ni(e,t){if(t.dryRun){let r=await pt("package",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"package",name:e,location:`packages/${e}`,files:r.map(a=>({path:a.path,sizeBytes:a.size}))};process.stdout.write(JSON.stringify(o,null,2)+`
704
+ `),process.exit(c.DRY_RUN_OK)}Ve.intro(D.bgCyan(D.black(" nebutra generate package ")));let n=s.spinner();try{n.start(`Generating package ${D.cyan(e)}...`);let r=await ft("package",e);n.stop(`Created package ${D.cyan(e)}`,0),s.success(`Package created with ${r.length} files`),s.info("Next steps:"),s.info(` Edit packages/${e}/src/index.ts`),s.info(` Run: pnpm --filter @nebutra/${e} build`),process.exit(c.SUCCESS)}catch(r){n.stop(`Failed to generate package: ${r instanceof Error?r.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function ri(e,t){if(t.dryRun){let r=await pt("route",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"route",path:e,location:`backends/gateway/src/routes/${e}.ts`,files:r.map(a=>({path:a.path,sizeBytes:a.size}))};process.stdout.write(JSON.stringify(o,null,2)+`
705
+ `),process.exit(c.DRY_RUN_OK)}Ve.intro(D.bgCyan(D.black(" nebutra generate route ")));let n=s.spinner();try{n.start(`Generating route ${D.cyan(e)}...`);let r=await ft("route",e);n.stop(`Created route ${D.cyan(e)}`,0),s.success(`Route created with ${r.length} files`),s.info(`File: backends/gateway/src/routes/${e}.ts`),s.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 oi(e,t){if(t.dryRun){let r=await pt("component",e,t),o={mode:"dry-run",timestamp:new Date().toISOString(),type:"component",name:e,location:"packages/design/ui/src/components/",files:r.map(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)+`
706
+ `),process.exit(c.DRY_RUN_OK)}Ve.intro(D.bgCyan(D.black(" nebutra generate component ")));let n=s.spinner();try{n.start(`Generating component ${D.cyan(e)}...`);let r=await ft("component",e);n.stop(`Created component ${D.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)}}function tr(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)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await ti(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1,interactive:process.stdin.isTTY})}),t.command("package <name>").description("Scaffold a new package (@nebutra/<name>)").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await ni(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1})}),t.command("route <path>").description("Scaffold a Hono API route in api-gateway").option("--dry-run","Preview changes without writing files").option("--yes","Skip all prompts").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await ri(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1})}),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)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await oi(n,{...r,dryRun:r.dryRun||!1,yes:o.yes||!1,variants:r.variants,sizes:r.sizes})})}import Te from"picocolors";async function W(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 si(e){try{let t=e.period||"7d",n=e.compare;s.info(`Fetching growth metrics for ${t}...`);let r=await W("/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 ai(e){try{let t=e.period||"7d",n=e.segment||"all";s.info(`Fetching funnel data for ${t} (${n})...`);let r=await W("/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?Te.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 ii(e){try{let t=e.period||"weekly",n=parseInt(e.cohorts,10)||8;s.info(`Fetching ${t} cohort data (${n} cohorts)...`);let r=await W("/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 g=m/100,p=String(Math.round(m)).padEnd(8);g>=.7?p=Te.green(p):g>=.4?p=Te.yellow(p):p=Te.red(p),l+=p+" "}})}),c.SUCCESS}catch(t){return s.error(`Cohort error: ${t instanceof Error?t.message:String(t)}`),c.ERROR}}async function ci(e,t){try{if(e==="stats"){s.info("Fetching newsletter stats...");let n=await W("/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 W("/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 W("/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 li(e,t){try{if(e==="status"){s.info("Fetching referral program status...");let n=await W("/referral/status");return c.SUCCESS}if(e==="config"){s.info("Fetching referral config...");let n=await W("/referral/config");return Object.entries(n).forEach(([r,o])=>{}),c.SUCCESS}return e==="leaderboard"?(s.info("Fetching referral leaderboard..."),(await W("/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 di(e,t){try{if(e==="list"){s.info("Fetching active experiments...");let n=await W("/experiment");return n.length===0?c.SUCCESS:(n.forEach(r=>{let o=r.status==="running"?Te.yellow("\u25CF"):Te.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 W("/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 W(`/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 W(`/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 ui(e){try{let t=e.focus||"activation",n=e.depth||"quick";s.info(`Generating growth insights (focus: ${t}, depth: ${n})...`);let r=await W("/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 nr(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 si(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 ai(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 ii(a))}),t.command("newsletter <subcommand>").description("Newsletter management").action(async(a,i)=>{process.exit(await ci(a,i))}),t.command("referral <subcommand>").description("Referral program management").action(async(a,i)=>{process.exit(await li(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 di(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 ui(a))}),t.option("--dry-run","Preview changes without applying them").option("--format <json|text>","Output format","text").option("--yes","Skip confirmation prompts")}import Vt,{lstatSync as mi,readdirSync as Kt,readFileSync as pi,writeFileSync as fi}from"fs";import le from"path";import{fileURLToPath as gi}from"url";import z from"picocolors";var yi=le.dirname(gi(import.meta.url));function Bt(){let e=new Map,t=le.join(yi,"../../../apps");if(!Vt.existsSync(t))return e;try{let n=Kt(t);for(let r of n){let o=le.join(t,r),a=le.join(o,"messages");Vt.existsSync(a)&&mi(a).isDirectory()&&e.set(r,a)}}catch(n){s.debug(`Error scanning apps directory: ${n instanceof Error?n.message:String(n)}`)}return e}function Ke(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=Ke(o,a);for(let l of i)n.add(l)}else n.add(a)}return n}function Be(e){try{let t=pi(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 hi(e){if(s.info("Syncing language files across the project..."),(await I("translate",{filter:"landing-page",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 $({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 bi(e){s.info("Validating translation files...");let t=Bt();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=Kt(a).filter(p=>p.endsWith(".json"));if(l.length===0)continue;let u=le.join(a,"en.json"),m=Be(u);if(!m){s.warn(`Could not load reference locale en.json from ${o}`);continue}let g=Ke(m);for(let p of l){if(p==="en.json")continue;let b=p.replace(".json",""),K=le.join(a,p),X=Be(K);if(!X){s.debug(`Could not parse ${p}`);continue}let Q=Ke(X),Re=Array.from(g).filter(f=>!Q.has(f)),fe=Array.from(Q).filter(f=>!g.has(f)),je=g.size>0?(g.size-Re.length)/g.size*100:100;(Re.length>0||fe.length>0)&&(r=!0),i.push({locale:b,totalKeys:g.size,missingKeys:Re,extraKeys:fe,coverage:Math.round(je*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(`${z.bold(o)}:`);for(let i of a){let u=(i.coverage>=100?z.green:i.coverage>=80?z.yellow:z.red)(`${i.coverage}%`);s.info(` ${z.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 vi(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=Bt();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=le.join(l,`${e}.json`);if(Vt.existsSync(u)){s.warn(`Locale ${e} already exists in ${i}`);continue}try{let b=function(K){for(let X in K)typeof K[X]=="string"?K[X]="":typeof K[X]=="object"&&K[X]!==null&&b(K[X])};var a=b;let m=le.join(l,"en.json"),g=Be(m);if(!g){s.warn(`Could not load reference en.json from ${i}, skipping...`);continue}let p=JSON.parse(JSON.stringify(g));b(p),t.dryRun?s.info(`Would create ${e} locale in ${i}`):(fi(u,JSON.stringify(p,null,2)+`
707
+ `),r.push({app:i,path:u}),s.success(`Created ${e} locale in ${i}`))}catch(m){s.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||s.success(`Locale '${e}' added to ${r.length} app(s)`),o&&process.exit(c.ERROR)}async function wi(e){s.info("Checking translation coverage...");let t=Bt();t.size===0&&(s.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 l=[];try{let u=Kt(i).filter(b=>b.endsWith(".json"));if(u.length===0)continue;let m=le.join(i,"en.json"),g=Be(m);if(!g){s.debug(`Could not load reference locale from ${a}`);continue}let p=Ke(g);for(let b of u){let K=b.replace(".json",""),X=le.join(i,b),Q=Be(X);if(!Q)continue;let Re=Ke(Q),fe=Array.from(Re).filter(ne=>{let Xe=Q[ne.split(".")[0]];return Xe!==void 0&&Xe!==""}).length,je=p.size-fe,f=p.size>0?fe/p.size*100:0;l.push({locale:K,coverage:Math.round(f*100)/100,totalKeys:p.size,translatedKeys:fe,missingKeys:je})}l.length>0&&(n.set(a,l),o++,r+=l.reduce((b,K)=>b+K.coverage,0)/l.length)}catch(u){s.debug(`Error checking status for ${a}: ${u instanceof Error?u.message:String(u)}`)}}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,[l,u])=>(i[l]=u,i),{})};console.log(JSON.stringify(a,null,2))}else{for(let[a,i]of n){s.info(`${z.bold(a)}:`);for(let l of i){let u="",g=Math.round(l.coverage/100*20);u="\u2588".repeat(g)+"\u2591".repeat(20-g);let b=(l.coverage>=100?z.green:l.coverage>=80?z.yellow:z.red)(`${l.coverage.toFixed(1)}%`);s.info(` ${z.cyan(l.locale.padEnd(5))} [${u}] ${b}`),s.info(` ${l.translatedKeys}/${l.totalKeys} keys (${l.missingKeys} missing)`)}}if(o>0){let a=r/o,i=a>=100?z.green:a>=80?z.yellow:z.red;s.info(`
708
+ Average coverage: ${i(a.toFixed(1)+"%")}`)}}}function rr(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 hi({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 bi({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 vi(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 wi({format:n.format||r.format,interactive:r.yes!==!0})})}import*as gt from"@clack/prompts";async function Si(e){let t=e.lite?"docker-compose.lite.yml":void 0,n=e.lite?"Starting lite stack (PostgreSQL + Redis)":"Starting full stack";d(n+"...","info");let r=await $e("up -d",{file:t,profile:e.profile,dryRun:e.dryRun});r.exitCode===0?d("Infrastructure stack started successfully","success"):(d("Failed to start infrastructure stack","error"),_("Docker compose output",{stderr:r.stderr}),process.exit(r.exitCode||1))}async function Ri(e){d("Stopping infrastructure stack...","info");let t=await $e("down",{dryRun:e.dryRun});t.exitCode===0?d("Infrastructure stack stopped","success"):(d("Failed to stop infrastructure stack","error"),_("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1))}async function Ei(e){d("Checking infrastructure status...","info");let t=await $e("ps --format json",{dryRun:e.dryRun});if(t.exitCode===0)try{let n=JSON.parse(t.stdout);if(e.format==="json")O(n,{format:"json"});else{let r=n.map(o=>({name:o.Name,status:o.Status,ports:o.Ports||"-"}));O(r,{format:"table"})}}catch{O(t.stdout,{format:"plain"})}else d("Failed to check infrastructure status","error"),_("Docker compose output",{stderr:t.stderr}),process.exit(t.exitCode||1)}async function Ci(e,t){let n=t||{},r=e?`Fetching logs for ${e}...`:"Fetching infrastructure logs...";d(r,"info");let o=["logs","--tail","50"];e&&o.push(e);let a=await $e(o.join(" "),{dryRun:n.dryRun});a.exitCode===0?O(a.stdout,{format:"plain"}):(d("Failed to fetch logs","error"),_("Docker compose output",{stderr:a.stderr}),process.exit(a.exitCode||1))}async function ki(e){let t=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e.yes&&!e.dryRun)if(t){let r=await gt.confirm({message:"Reset infrastructure? This will remove all containers and volumes.",initialValue:!1});(gt.isCancel(r)||!r)&&(d("Reset cancelled","warn"),process.exit(c.CANCELLED))}else d("Infrastructure reset requires explicit --yes confirmation (use: nebutra infra reset --yes)","error"),process.exit(c.INVALID_ARGS);d("Resetting infrastructure stack...","warn");let n=await $e("down -v",{dryRun:e.dryRun});n.exitCode===0?d("Infrastructure reset successfully","success"):(d("Failed to reset infrastructure","error"),_("Docker compose output",{stderr:n.stderr}),process.exit(n.exitCode||1))}function or(e){e.command("infra <verb> [service]").description("Manage Docker Compose infrastructure (PostgreSQL, Redis, Meilisearch, 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 Si(i);break;case"down":await Ri(i);break;case"status":await Ei(i);break;case"logs":await Ci(r,i);break;case"reset":await ki(i);break;default:d(`Unknown infra subcommand: ${n}. Valid commands: up, down, status, logs, reset`,"error"),process.exit(c.INVALID_ARGS)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Infrastructure command failed: ${u}`,"error"),_("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
632
709
  Examples:
633
710
  nebutra infra up Start full stack
634
711
  nebutra infra up --lite Start lite stack (PostgreSQL + Redis)
@@ -645,36 +722,46 @@ Flags:
645
722
  --lite Use docker-compose.lite.yml (PostgreSQL + Redis only)
646
723
  --profile <name> Enable Docker Compose profile (search, notifications, etc.)
647
724
  --format <type> Output format: json, plain (default: plain, auto-json in non-TTY)
648
- `)}import At from"fs";import ua from"path";import*as J from"@clack/prompts";import it from"picocolors";var ma={$schema:"https://nebutra.com/schema.json",componentsDirectory:"packages/ui/src/components",tailwind:{config:"tailwind.config.ts",css:"packages/tokens/styles.css",baseColor:"slate",cssVariables:!0},aliases:{components:"@nebutra/ui",utils:"@nebutra/ui/utils"}};function pa(){return process.stdout.isTTY===!0}function fa(e){return e.yes===!0||e.dryRun===!0||!pa()}function ga(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function $n(e={}){let t=process.cwd(),n=ua.join(t,"nebutra.config.json"),r=At.existsSync(n);e.ifNotExists&&r&&(s.info("nebutra.config.json already exists, skipping initialization."),process.exit(c.SUCCESS));let o=fa(e);o||J.intro(it.bgCyan(it.black(" nebutra init "))),r&&!o&&(J.log.warn("nebutra.config.json already exists in this directory."),await J.confirm({message:"Do you want to overwrite it?",initialValue:!1})||(J.outro("Operation aborted."),process.exit(c.CANCELLED)));let a={...ma};if(e.dryRun){let i=r?JSON.parse(At.readFileSync(n,"utf-8")):void 0,l=ga(n,a,i);console.log(JSON.stringify(l,null,2)),s.info("Dry-run completed. No changes made."),process.exit(c.DRY_RUN_OK)}o?s.info("Initializing Nebutra CLI configuration..."):J.spinner().start("Initializing Nebutra CLI configuration..."),At.writeFileSync(n,JSON.stringify(a,null,2)+`
649
- `),o?(s.success("Configuration saved to nebutra.config.json"),s.info('Initialization complete! You can now use "nebutra add" to start injecting components.')):(await new Promise(i=>setTimeout(i,800)),J.spinner().stop(it.green("Configuration saved to nebutra.config.json")),J.outro(it.cyan('Initialization complete! You can now use "nebutra add" to start injecting components.'))),process.exit(c.SUCCESS)}import _t from"fs/promises";import ba from"os";import Pt from"path";import*as $ from"@clack/prompts";import Q from"picocolors";var ya="https://analytics.nebutra.com";function ha(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function ct(e,t={}){ha(t)||(async()=>{try{let n=await import("./dist-EDNC5USD.js");if(typeof n.createAnalyticsClient!="function")return;let r=n.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??ya},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",e);o&&typeof o.then=="function"&&await o.catch(()=>{})}catch{}})()}var An=process.env.NEBUTRA_LICENSE_API_URL??"https://nebutra.com";async function _n(){let e=ba.homedir(),t=Pt.join(e,".config","nebutra");try{await _t.mkdir(t,{recursive:!0})}catch{}return t}async function va(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 wa(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 Ra(e,t){let n=t.quiet===!0;n||$.intro(Q.bgCyan(Q.black(" Nebutra License Activation "))),ct({action:"activate_attempted"});try{if(e.length<10)throw new Error("Invalid license key format.");n||$.log.step("Validating license key with Nebutra...");let{tier:r,type:o}=await va(e),a=await _n(),i=Pt.join(a,"license.json");await _t.writeFile(i,JSON.stringify({licenseKey:e,tier:r,type:o,activatedAt:new Date().toISOString()},null,2),"utf-8"),n||($.log.success(Q.green(`${r} license activated and saved to ${i}`)),$.outro(Q.cyan("Premium CLI capabilities are now unlocked!"))),ct({action:"activated",tier:r,type:o})}catch(r){ct({action:"failed",error_code:wa(r)}),n||($.log.error(Q.red("Activation failed")),s.error(r instanceof Error?r.message:String(r)),$.outro("Please check your key and try again.")),process.exit(1)}}async function Sa(e){let t=e.quiet===!0;t||$.intro(Q.bgCyan(Q.black(" Nebutra License Status ")));try{let n=await _n(),r=Pt.join(n,"license.json"),o=await _t.readFile(r,"utf-8"),a=JSON.parse(o);if(a.licenseKey)t||($.log.success(Q.green("License is active!")),$.log.info(`Key: ${a.licenseKey.substring(0,8)}...`),a.tier&&$.log.info(`Tier: ${Q.bold(a.tier)}`),a.type&&$.log.info(`Type: ${a.type}`),$.log.info(`Activated: ${new Date(a.activatedAt).toLocaleString()}`),$.outro(Q.cyan("You are ready to use premium features.")));else throw new Error("License key not found in config.")}catch{t||($.log.warn(Q.yellow("No active license found locally.")),$.log.message(Q.dim("Run `nebutra license activate <key>` to unlock premium features.")),$.outro("")),process.exit(1)}}function Pn(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 Ra(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await Sa(n)})}import{spawn as Ca}from"child_process";import{dirname as Ea,resolve as ka}from"path";import{fileURLToPath as Oa}from"url";import*as re from"@clack/prompts";import ue from"picocolors";var xa=Ea(Oa(import.meta.url));function $a(){let e=[()=>ka(xa,"../../../mcp/dist/server/contextServer.js")];for(let t of e)try{return t()}catch(n){s.debug("MCP server binary resolution strategy failed",{error:n})}return"nebutra-mcp"}function In(e){e.command("mcp").description("Start the Nebutra MCP server for Cursor/Windsurf").option("--stdio","Use stdio transport (default)",!0).action(async t=>{re.intro(ue.bgCyan(ue.black(" nebutra mcp ")));try{let n=$a();re.log.info(ue.cyan("Starting Nebutra MCP server for Cursor/Windsurf integration...")),re.log.info(ue.dim(`Press Ctrl+C to stop the server.
650
- `));let r=Ca(process.execPath,[n],{stdio:"inherit",env:{...process.env}});r.on("close",o=>{o===0?re.outro(ue.green("MCP server stopped gracefully.")):o===null&&re.outro(ue.yellow("MCP server terminated.")),process.exit(o??0)}),r.on("error",o=>{s.error(`
725
+ `)}import qt from"fs";import Oi from"path";import*as Z from"@clack/prompts";import yt from"picocolors";var xi={$schema:"https://nebutra.com/schema.json",componentsDirectory:"packages/design/ui/src/components",tailwind:{config:"tailwind.config.ts",css:"packages/design/tokens/styles.css",baseColor:"slate",cssVariables:!0},aliases:{components:"@nebutra/ui",utils:"@nebutra/ui/utils"}};function _i(){return process.stdout.isTTY===!0}function Ai(e){return e.yes===!0||e.dryRun===!0||!_i()}function $i(e,t,n){return{operation:n?"update":"create",path:e,...n&&{before:n},after:t}}async function sr(e={}){let t=process.cwd(),n=Oi.join(t,"nebutra.config.json"),r=qt.existsSync(n);e.ifNotExists&&r&&(s.info("nebutra.config.json already exists, skipping initialization."),process.exit(c.SUCCESS));let o=Ai(e);o||Z.intro(yt.bgCyan(yt.black(" nebutra init "))),r&&!o&&(Z.log.warn("nebutra.config.json already exists in this directory."),await Z.confirm({message:"Do you want to overwrite it?",initialValue:!1})||(Z.outro("Operation aborted."),process.exit(c.CANCELLED)));let a={...xi};if(e.dryRun){let i=r?JSON.parse(qt.readFileSync(n,"utf-8")):void 0,l=$i(n,a,i);x(l),d("Dry-run completed. No changes made."),process.exit(c.DRY_RUN_OK)}o?s.info("Initializing Nebutra CLI configuration..."):Z.spinner().start("Initializing Nebutra CLI configuration..."),qt.writeFileSync(n,JSON.stringify(a,null,2)+`
726
+ `),o?(s.success("Configuration saved to nebutra.config.json"),s.info('Initialization complete! You can now use "nebutra add" to start injecting components.')):(await new Promise(i=>setTimeout(i,800)),Z.spinner().stop(yt.green("Configuration saved to nebutra.config.json")),Z.outro(yt.cyan('Initialization complete! You can now use "nebutra add" to start injecting components.'))),process.exit(c.SUCCESS)}import vt from"fs/promises";import Di from"os";import qe from"path";import*as N from"@clack/prompts";import k from"picocolors";var Pi="https://analytics.nebutra.com";function Ni(e={}){if(e.noTelemetry===!0)return!0;let t=process.env.NEBUTRA_TELEMETRY;return t==="0"||t==="false"}function ht(e,t={}){Ni(t)||(async()=>{try{let n=await import("@nebutra/analytics");if(typeof n.createAnalyticsClient!="function")return;let r=n.createAnalyticsClient({posthog:{apiKey:process.env.NEBUTRA_POSTHOG_KEY??"",host:process.env.NEBUTRA_POSTHOG_HOST??Pi},onError:()=>{}});if(typeof r?.track!="function")return;let o=r.track("license.cli",e);o&&typeof o.then=="function"&&await o.catch(()=>{})}catch{}})()}import{createHmac as Ii}from"crypto";var Ti=[{id:"v1",key:"nebutra-sailor:scaffold-marker:v1"}],Ui="v1";function ji(e){if(e)return Ti.find(t=>t.id===e)}function Li(e,t){let n=`${e.cliVersion}|${e.scaffoldedAt}|${e.projectName}|${e.nonce}`;return Ii("sha256",t).update(n).digest("hex")}function ar(e){if(!e)return{valid:!1,reason:"missing_meta"};if(e.schemaVersion!==1)return{valid:!1,reason:"schema_mismatch"};if(typeof e.cliVersion!="string"||typeof e.scaffoldedAt!="string"||typeof e.projectName!="string"||typeof e.nonce!="string"||typeof e.signature!="string")return{valid:!1,reason:"schema_mismatch"};let t=e.signingKeyId??Ui,n=ji(t);return n?Li({cliVersion:e.cliVersion,scaffoldedAt:e.scaffoldedAt,projectName:e.projectName,nonce:e.nonce},n.key)!==e.signature?{valid:!1,reason:"signature_mismatch"}:{valid:!0,reason:"ok"}:{valid:!1,reason:"unknown_signing_key"}}var bt={ok:"valid",missing_meta:".nebutra/scaffold-meta.json not found",schema_mismatch:"scaffold-meta.json schema mismatch (corrupt or future format)",unknown_signing_key:"signed with an unknown key \u2014 upgrade `nebutra` to a newer release that recognises it",signature_mismatch:"signature does not match \u2014 file has been tampered with or hand-edited"};var ir=process.env.NEBUTRA_LICENSE_API_URL??"https://nebutra.com";async function cr(){let e=Di.homedir(),t=qe.join(e,".config","nebutra");try{await vt.mkdir(t,{recursive:!0})}catch{}return t}async function Fi(e){let t=`${ir}/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 (${ir}). 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 Mi(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 Gi(e,t){let n=t.quiet===!0;n||N.intro(k.bgCyan(k.black(" Nebutra License Activation "))),ht({action:"activate_attempted"});try{if(e.length<10)throw new Error("Invalid license key format.");n||N.log.step("Validating license key with Nebutra...");let{tier:r,type:o}=await Fi(e),a=await cr(),i=qe.join(a,"license.json");await vt.writeFile(i,JSON.stringify({licenseKey:e,tier:r,type:o,activatedAt:new Date().toISOString()},null,2),"utf-8"),n||(N.log.success(k.green(`${r} license activated and saved to ${i}`)),N.outro(k.cyan("Premium CLI capabilities are now unlocked!"))),ht({action:"activated",tier:r,type:o})}catch(r){ht({action:"failed",error_code:Mi(r)}),n||(N.log.error(k.red("Activation failed")),s.error(r instanceof Error?r.message:String(r)),N.outro("Please check your key and try again.")),process.exit(c.ERROR)}}async function Vi(e){let t=e.quiet===!0;t||N.intro(k.bgCyan(k.black(" Nebutra License Status ")));try{let n=await cr(),r=qe.join(n,"license.json"),o=await vt.readFile(r,"utf-8"),a=JSON.parse(o);if(a.licenseKey)t||(N.log.success(k.green("License is active!")),N.log.info(`Key: ${a.licenseKey.substring(0,8)}...`),a.tier&&N.log.info(`Tier: ${k.bold(a.tier)}`),a.type&&N.log.info(`Type: ${a.type}`),N.log.info(`Activated: ${new Date(a.activatedAt).toLocaleString()}`),N.outro(k.cyan("You are ready to use premium features.")));else throw new Error("License key not found in config.")}catch{t||(N.log.warn(k.yellow("No active license found locally.")),N.log.message(k.dim("Run `nebutra license activate <key>` to unlock premium features.")),N.outro("")),process.exit(c.NOT_FOUND)}}async function Ki(e,t){let n=t.format==="json",r=t.quiet===!0,o=e?qe.resolve(process.cwd(),e):process.cwd(),a=qe.join(o,".nebutra","scaffold-meta.json"),i;try{i=await vt.readFile(a,"utf-8")}catch{let p={valid:!1,tier:null,cliVersion:null,scaffoldedAt:null,projectName:null,reason:"missing_meta",reasonText:bt.missing_meta,path:a};n?process.stdout.write(`${JSON.stringify(p,null,2)}
727
+ `):r||process.stderr.write(`${k.red("\u2718")} No scaffold marker found at ${k.dim(a)}.
728
+ This project does not appear to be scaffolded by ${k.bold("create-sailor")}.
729
+ Run ${k.cyan("npm create sailor@latest")} to scaffold a licensed project.
730
+ `),process.exit(c.NOT_FOUND)}let l=null;try{l=JSON.parse(i)}catch{}let u=ar(l),m={valid:u.valid,tier:l?.license?.tier??null,cliVersion:l?.cliVersion??null,scaffoldedAt:l?.scaffoldedAt??null,projectName:l?.projectName??null,signingKeyId:l?.signingKeyId??null,reason:u.reason,reasonText:bt[u.reason],path:a};if(n&&(process.stdout.write(`${JSON.stringify(m,null,2)}
731
+ `),process.exit(u.valid?c.SUCCESS:c.INCOMPATIBLE)),!r)if(u.valid&&l){let g=new Date(l.scaffoldedAt).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"}),p=[`${k.green("\u2713")} Project "${k.bold(l.projectName)}" scaffolded with ${k.cyan(`create-sailor@${l.cliVersion}`)} on ${g}`,` Signing key: ${k.dim(l.signingKeyId??"v1 (legacy, no keyId)")}`,` Tier: ${k.bold(l.license?.tier??"independent")}`,` ${k.green("Independent Developer License valid.")}`];process.stderr.write(`${p.join(`
732
+ `)}
733
+ `)}else{let g=bt[u.reason];process.stderr.write(`${k.red("\u2718")} Invalid scaffold marker.
734
+ Reason: ${k.yellow(g)}
735
+ File: ${k.dim(a)}
736
+ `)}process.exit(u.valid?c.SUCCESS:c.INCOMPATIBLE)}function lr(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 Gi(n,r)}),t.command("status").description("Check the locally configured license status").option("--quiet","Suppress output").action(async n=>{await Vi(n)}),t.command("verify [path]").description("Verify the scaffold-meta HMAC signature in a create-sailor project (defaults to cwd)").option("--format <type>","Output format: json | plain (default: plain)").option("--quiet","Suppress non-essential output").action(async function(n,r,o){let a=o&&typeof o.optsWithGlobals=="function"?o.optsWithGlobals()??{}:{...r},i=typeof r?.format=="string"?r.format:typeof a.format=="string"?a.format:void 0,l=!!r?.quiet||!!a.quiet;await Ki(n,{format:i,quiet:l})})}import{existsSync as dr,readFileSync as Bi,writeFileSync as qi}from"fs";import{dirname as Wi,join as ur,parse as Yi}from"path";import*as wt from"@clack/prompts";function Hi(e){let t=e,{root:n}=Yi(t);for(;;){if(dr(ur(t,"package.json")))return t;if(t===n)return null;let r=Wi(t);if(r===t)return null;t=r}}function zi(e){if(!dr(e))return{};try{return JSON.parse(Bi(e,"utf-8"))}catch{return{}}}function Ji(e,t){qi(e,JSON.stringify(t,null,2)+`
737
+ `)}async function Xi(e,t){let n=t.format==="json",r=Hi(process.cwd());r||(n?console.log(JSON.stringify({command:"link",success:!1,error:"No package.json found upstream"},null,2)):s.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)):s.error("project-id is required when running with --yes / non-interactive."),process.exit(c.INVALID_ARGS));let u=await wt.text({message:"Project ID to link to:",placeholder:"proj_abc123",validate:m=>m&&m.trim().length>0?void 0:"Project ID cannot be empty"});wt.isCancel(u)&&(s.warn("Cancelled"),process.exit(c.CANCELLED)),o=String(u).trim()}let a=ur(r,"nebutra.config.json"),l={...zi(a),projectId:o};Ji(a,l),n?console.log(JSON.stringify({command:"link",success:!0,projectId:o,configPath:a},null,2)):s.success(`Linked to project: ${o}`)}function mr(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 Xi(t,{yes:o.yes||!1,format:n.format||o.format})})}import{existsSync as pr,rmSync as Qi,unlinkSync as Zi}from"fs";import{homedir as fr,platform as ec}from"os";import{join as We}from"path";function tc(){if(ec()==="win32"){let t=process.env.LOCALAPPDATA||We(fr(),"AppData","Local");return We(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?We(e,"nebutra"):We(fr(),".config","nebutra")}var nc=["auth.json","session.json","token","credentials.json"];async function rc(e){let t=tc(),n=e.format==="json",r=0,o=[];if(e.all){if(pr(t))try{Qi(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)):s.error(`Failed to clear config directory: ${i}`),process.exit(c.PERMISSION_DENIED)}}else for(let a of nc){let i=We(t,a);if(pr(i))try{Zi(i),r++,o.push(i)}catch{}}r===0&&(n?console.log(JSON.stringify({command:"logout",success:!0,alreadyLoggedOut:!0,removed:[]},null,2)):s.info("Already logged out"),process.exit(c.SUCCESS)),n?console.log(JSON.stringify({command:"logout",success:!0,removed:o,clearedAll:!!e.all},null,2)):s.success(e.all?"Cleared all nebutra config":"Logged out of nebutra.com")}function gr(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 rc({all:t.all||!1,format:t.format||r.format})})}import{spawn as oc}from"child_process";import{dirname as sc,resolve as ac}from"path";import{fileURLToPath as ic}from"url";import*as ae from"@clack/prompts";import pe from"picocolors";var cc=sc(ic(import.meta.url));function lc(){let e=[()=>ac(cc,"../../../mcp/dist/server/contextServer.js")];for(let t of e)try{return t()}catch(n){s.debug("MCP server binary resolution strategy failed",{error:n})}return"nebutra-mcp"}function yr(e){e.command("mcp").description("Start the Nebutra MCP server for Cursor/Windsurf").option("--stdio","Use stdio transport (default)",!0).action(async t=>{ae.intro(pe.bgCyan(pe.black(" nebutra mcp ")));try{let n=lc();ae.log.info(pe.cyan("Starting Nebutra MCP server for Cursor/Windsurf integration...")),ae.log.info(pe.dim(`Press Ctrl+C to stop the server.
738
+ `));let r=oc(process.execPath,[n],{stdio:"inherit",env:{...process.env}});r.on("close",o=>{o===0?ae.outro(pe.green("MCP server stopped gracefully.")):o===null&&ae.outro(pe.yellow("MCP server terminated.")),process.exit(o??0)}),r.on("error",o=>{s.error(`
651
739
  Failed to start MCP server: ${o.message}`),o.code==="ENOENT"&&(s.warn(`
652
- Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),s.info(" Install globally: npm install -g @nebutra/mcp")),process.exit(1)}),process.on("SIGINT",()=>{re.log.info(ue.yellow(`
653
- Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{re.log.info(ue.yellow("Terminating MCP server...")),r.kill("SIGTERM")})}catch(n){re.log.error(ue.red("Error: Unable to start MCP server. Ensure @nebutra/mcp is properly installed.")),n instanceof Error&&s.error(n.message),process.exit(1)}})}import{promises as It}from"fs";import{resolve as Nn}from"path";import*as Ee from"@clack/prompts";import v from"picocolors";var ce={"ai-saas":{name:"ai-saas",description:"Full-stack AI SaaS platform with auth, billing, and analytics",apps:["web","landing-page","api-gateway","studio","admin"],features:["billing","ai","search","analytics","sso"],theme:"vibrant",stack:["Next.js 16","Hono","Prisma","PostgreSQL","OpenAI API"]},marketing:{name:"marketing",description:"Marketing website with blog and CMS integration",apps:["landing-page","blog","studio"],features:["blog","growth","analytics","newsletter"],theme:"minimal",stack:["Next.js 16","Sanity CMS","Mailgun"]},dashboard:{name:"dashboard",description:"Enterprise dashboard with admin panel and RBAC",apps:["web","admin","api-gateway"],features:["billing","admin","analytics","sso"],theme:"dark-dense",stack:["Next.js 16","Hono","Prisma","PostgreSQL"]},overseas:{name:"overseas",description:"Global SaaS with multi-language and localization support",apps:["web","landing-page","api-gateway","blog"],features:["billing","ai","search","i18n"],theme:"ocean",stack:["Next.js 16","i18next","Hono"]},growth:{name:"growth",description:"Growth-focused platform with community and content",apps:["web","landing-page","blog"],features:["growth","analytics","newsletter","community"],theme:"vibrant",stack:["Next.js 16","Mailgun","Mixpanel"]},creative:{name:"creative",description:"Creative portfolio and landing page builder",apps:["landing-page","blog"],features:["blog","growth"],theme:"gradient",stack:["Next.js 16","Framer Motion"]},"blog-portfolio":{name:"blog-portfolio",description:"Personal blog and portfolio site",apps:["landing-page","blog"],features:["blog"],theme:"minimal",stack:["Next.js 16"]},community:{name:"community",description:"Community platform with real-time features",apps:["web","landing-page"],features:["community","growth","realtime"],theme:"vibrant",stack:["Next.js 16","Hono","Redis","Socket.io"]},"one-person":{name:"one-person",description:"Solo founder landing page and quick launch",apps:["landing-page"],features:["blog"],theme:"minimal",stack:["Next.js 16"]},full:{name:"full",description:"Everything included - all apps and all features",apps:["web","landing-page","api-gateway","studio","admin","blog","storybook","design-docs","docs"],features:["billing","ai","ecommerce","web3","community","blog","growth","search","sso","admin","analytics","newsletter","realtime","upload"],theme:"vibrant",stack:["Next.js 16","Hono","Prisma","PostgreSQL","Redis","OpenAI","Web3"]}};async function Aa(e){if(e.format==="json"){let t={presets:Object.values(ce).map(n=>({name:n.name,description:n.description,appsCount:n.apps.length,featuresCount:n.features.length,apps:n.apps,features:n.features,theme:n.theme}))};process.stdout.write(JSON.stringify(t,null,2)+`
654
- `),process.exit(c.SUCCESS)}Ee.intro(v.bgCyan(v.black(" nebutra preset list "))),s.info(`Available presets:
655
- `);for(let t of Object.values(ce)){let n=v.bold(t.name),r=v.dim(t.description),o=v.gray(`(${t.apps.length} apps, ${t.features.length} features)`);s.info(`${n} ${o}`),s.info(` ${r}`)}process.exit(c.SUCCESS)}async function _a(e,t){e||(s.error("Please specify a preset name"),s.info("Available presets: "+Object.keys(ce).join(", ")),process.exit(c.INVALID_ARGS));let n=ce[e];n||(s.error(`Preset not found: ${e}`),s.info("Available presets: "+Object.keys(ce).join(", ")),process.exit(c.NOT_FOUND)),t.format==="json"&&(process.stdout.write(JSON.stringify(n,null,2)+`
656
- `),process.exit(c.SUCCESS)),Ee.intro(v.bgCyan(v.black(` nebutra preset show ${e} `))),s.info(`
657
- ${v.bold(n.name)}`),s.info(n.description),s.info(`
658
- ${v.bold("Apps:")}`),n.apps.forEach(r=>{s.info(` \u2022 ${r}`)}),s.info(`
659
- ${v.bold("Features:")}`),n.features.forEach(r=>{s.info(` \u2022 ${r}`)}),n.theme&&(s.info(`
660
- ${v.bold("Theme:")}`),s.info(` ${n.theme}`)),n.stack&&(s.info(`
661
- ${v.bold("Recommended Stack:")}`),n.stack.forEach(r=>{s.info(` \u2022 ${r}`)})),process.exit(c.SUCCESS)}async function Pa(e,t){let n=ce[e];n||(s.error(`Preset not found: ${e}`),s.info("Available presets: "+Object.keys(ce).join(", ")),process.exit(c.NOT_FOUND));let r=R(),o=Nn(r,"nebutra.config.ts");if(t.dryRun){let i={mode:"dry-run",timestamp:new Date().toISOString(),action:"preset.apply",preset:e,configFile:o,changes:{preset:e,apps:n.apps,features:n.features,theme:n.theme||"default"}};process.stdout.write(JSON.stringify(i,null,2)+`
662
- `),process.exit(c.DRY_RUN_OK)}Ee.intro(v.bgCyan(v.black(" nebutra preset apply ")));let a=s.spinner();try{let i;try{i=await It.readFile(o,"utf-8")}catch{i=`export default {
740
+ Tip: Ensure @nebutra/mcp is installed or available in your PATH.`),s.info(" Install globally: npm install -g @nebutra/mcp"),process.exit(c.NOT_FOUND)),process.exit(c.ERROR)}),process.on("SIGINT",()=>{ae.log.info(pe.yellow(`
741
+ Shutting down MCP server...`)),r.kill("SIGINT")}),process.on("SIGTERM",()=>{ae.log.info(pe.yellow("Terminating MCP server...")),r.kill("SIGTERM")})}catch(n){ae.log.error(pe.red("Error: Unable to start MCP server. Ensure @nebutra/mcp is properly installed.")),n instanceof Error&&s.error(n.message),process.exit(c.ERROR)}})}import{promises as Wt}from"fs";import{resolve as hr}from"path";import*as xe from"@clack/prompts";import w from"picocolors";var de={"ai-saas":{name:"ai-saas",description:"Full-stack AI SaaS platform with auth, billing, and analytics",apps:["web","landing-page","api-gateway","studio","admin"],features:["billing","ai","search","analytics","sso"],theme:"vibrant",stack:["Next.js 16","Hono","Prisma","PostgreSQL","OpenAI API"]},marketing:{name:"marketing",description:"Marketing website with blog and CMS integration",apps:["landing-page","blog","studio"],features:["blog","growth","analytics","newsletter"],theme:"minimal",stack:["Next.js 16","Sanity CMS","Mailgun"]},dashboard:{name:"dashboard",description:"Enterprise dashboard with admin panel and RBAC",apps:["web","admin","api-gateway"],features:["billing","admin","analytics","sso"],theme:"dark-dense",stack:["Next.js 16","Hono","Prisma","PostgreSQL"]},overseas:{name:"overseas",description:"Global SaaS with multi-language and localization support",apps:["web","landing-page","api-gateway","blog"],features:["billing","ai","search","i18n"],theme:"ocean",stack:["Next.js 16","i18next","Hono"]},growth:{name:"growth",description:"Growth-focused platform with community and content",apps:["web","landing-page","blog"],features:["growth","analytics","newsletter","community"],theme:"vibrant",stack:["Next.js 16","Mailgun","Mixpanel"]},creative:{name:"creative",description:"Creative portfolio and landing page builder",apps:["landing-page","blog"],features:["blog","growth"],theme:"gradient",stack:["Next.js 16","Framer Motion"]},"blog-portfolio":{name:"blog-portfolio",description:"Personal blog and portfolio site",apps:["landing-page","blog"],features:["blog"],theme:"minimal",stack:["Next.js 16"]},community:{name:"community",description:"Community platform with real-time features",apps:["web","landing-page"],features:["community","growth","realtime"],theme:"vibrant",stack:["Next.js 16","Hono","Redis","Socket.io"]},"one-person":{name:"one-person",description:"Solo founder landing page and quick launch",apps:["landing-page"],features:["blog"],theme:"minimal",stack:["Next.js 16"]},full:{name:"full",description:"Everything included - all apps and all features",apps:["web","landing-page","api-gateway","studio","admin","blog","storybook","design-docs","docs"],features:["billing","ai","ecommerce","web3","community","blog","growth","search","sso","admin","analytics","newsletter","realtime","upload"],theme:"vibrant",stack:["Next.js 16","Hono","Prisma","PostgreSQL","Redis","OpenAI","Web3"]}};async function dc(e){if(e.format==="json"){let t={presets:Object.values(de).map(n=>({name:n.name,description:n.description,appsCount:n.apps.length,featuresCount:n.features.length,apps:n.apps,features:n.features,theme:n.theme}))};process.stdout.write(JSON.stringify(t,null,2)+`
742
+ `),process.exit(c.SUCCESS)}xe.intro(w.bgCyan(w.black(" nebutra preset list "))),s.info(`Available presets:
743
+ `);for(let t of Object.values(de)){let n=w.bold(t.name),r=w.dim(t.description),o=w.gray(`(${t.apps.length} apps, ${t.features.length} features)`);s.info(`${n} ${o}`),s.info(` ${r}`)}process.exit(c.SUCCESS)}async function uc(e,t){e||(s.error("Please specify a preset name"),s.info("Available presets: "+Object.keys(de).join(", ")),process.exit(c.INVALID_ARGS));let n=de[e];n||(s.error(`Preset not found: ${e}`),s.info("Available presets: "+Object.keys(de).join(", ")),process.exit(c.NOT_FOUND)),t.format==="json"&&(process.stdout.write(JSON.stringify(n,null,2)+`
744
+ `),process.exit(c.SUCCESS)),xe.intro(w.bgCyan(w.black(` nebutra preset show ${e} `))),s.info(`
745
+ ${w.bold(n.name)}`),s.info(n.description),s.info(`
746
+ ${w.bold("Apps:")}`),n.apps.forEach(r=>{s.info(` \u2022 ${r}`)}),s.info(`
747
+ ${w.bold("Features:")}`),n.features.forEach(r=>{s.info(` \u2022 ${r}`)}),n.theme&&(s.info(`
748
+ ${w.bold("Theme:")}`),s.info(` ${n.theme}`)),n.stack&&(s.info(`
749
+ ${w.bold("Recommended Stack:")}`),n.stack.forEach(r=>{s.info(` \u2022 ${r}`)})),process.exit(c.SUCCESS)}async function mc(e,t){let n=de[e];n||(s.error(`Preset not found: ${e}`),s.info("Available presets: "+Object.keys(de).join(", ")),process.exit(c.NOT_FOUND));let r=h(),o=hr(r,"nebutra.config.ts");t.dryRun&&(x({mode:"dry-run",timestamp:new Date().toISOString(),action:"preset.apply",preset:e,configFile:o,changes:{preset:e,apps:n.apps,features:n.features,theme:n.theme||"default"}},{format:t.format}),process.exit(c.DRY_RUN_OK)),xe.intro(w.bgCyan(w.black(" nebutra preset apply ")));let a=s.spinner();try{let i;try{i=await Wt.readFile(o,"utf-8")}catch{i=`export default {
663
750
  preset: "${e}",
664
751
  apps: ${JSON.stringify(n.apps,null,2).replace(/\n/g,`
665
752
  `)},
666
753
  features: ${JSON.stringify(n.features,null,2).replace(/\n/g,`
667
754
  `)},
668
755
  theme: "${n.theme||"default"}",
669
- };`}let l=i.replace(/preset:\s*"[^"]*"/,`preset: "${e}"`);t.dryRun===!1&&(a.start(`Applying preset ${v.cyan(e)}...`),await It.writeFile(o,l,"utf-8"),a.stop(`Applied preset ${v.cyan(e)}`,0),s.success("Preset applied successfully"),s.info(`${n.apps.length} apps enabled`),s.info(`${n.features.length} features enabled`),s.info(`Theme: ${n.theme||"default"}`)),process.exit(c.SUCCESS)}catch(i){a.stop(`Failed to apply preset: ${i instanceof Error?i.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function Ia(e){Ee.intro(v.bgCyan(v.black(" nebutra preset env ")));let t=R();try{let n=await _("preset:env",{dryRun:e.dryRun,interactive:!1});n.exitCode===0?(n.stdout&&process.stdout.write(n.stdout),process.exit(c.SUCCESS)):(s.error("Failed to get environment variables"),n.stderr&&process.stderr.write(n.stderr),process.exit(c.ERROR))}catch(n){s.error(`Failed: ${n instanceof Error?n.message:"Unknown error"}`),process.exit(c.ERROR)}}async function Na(e){Ee.intro(v.bgCyan(v.black(" nebutra preset features ")));let t=R(),n=Nn(t,"nebutra.config.ts");try{let o=(await It.readFile(n,"utf-8")).match(/features:\s*\[([\s\S]*?)\]/);o||(s.warn("No features found in nebutra.config.ts"),process.exit(c.CONFIG_ERROR));let i=o[1].split(",").map(l=>l.trim().replace(/['"]/g,"")).filter(l=>l.length>0);if(e.format==="json"){let l={features:i,count:i.length};process.stdout.write(JSON.stringify(l,null,2)+`
756
+ };`}let l=i.replace(/preset:\s*"[^"]*"/,`preset: "${e}"`);t.dryRun===!1&&(a.start(`Applying preset ${w.cyan(e)}...`),await Wt.writeFile(o,l,"utf-8"),a.stop(`Applied preset ${w.cyan(e)}`,0),s.success("Preset applied successfully"),s.info(`${n.apps.length} apps enabled`),s.info(`${n.features.length} features enabled`),s.info(`Theme: ${n.theme||"default"}`)),process.exit(c.SUCCESS)}catch(i){a.stop(`Failed to apply preset: ${i instanceof Error?i.message:"Unknown error"}`,1),process.exit(c.ERROR)}}async function pc(e){xe.intro(w.bgCyan(w.black(" nebutra preset env ")));let t=h();try{let n=await I("preset:env",{dryRun:e.dryRun,interactive:!1});n.exitCode===0?(n.stdout&&process.stdout.write(n.stdout),process.exit(c.SUCCESS)):(s.error("Failed to get environment variables"),n.stderr&&process.stderr.write(n.stderr),process.exit(c.ERROR))}catch(n){s.error(`Failed: ${n instanceof Error?n.message:"Unknown error"}`),process.exit(c.ERROR)}}async function fc(e){xe.intro(w.bgCyan(w.black(" nebutra preset features ")));let t=h(),n=hr(t,"nebutra.config.ts");try{let o=(await Wt.readFile(n,"utf-8")).match(/features:\s*\[([\s\S]*?)\]/);o||(s.warn("No features found in nebutra.config.ts"),process.exit(c.CONFIG_ERROR));let i=o[1].split(",").map(l=>l.trim().replace(/['"]/g,"")).filter(l=>l.length>0);if(e.format==="json"){let l={features:i,count:i.length};process.stdout.write(JSON.stringify(l,null,2)+`
670
757
  `),process.exit(c.SUCCESS)}s.info(`Features in current preset:
671
758
  `),i.forEach(l=>{s.info(` \u2713 ${l}`)}),s.info(`
672
- Total: ${i.length} features`),process.exit(c.SUCCESS)}catch(r){s.error(`Failed to read config: ${r instanceof Error?r.message:"Unknown error"}`),process.exit(c.ERROR)}}async function Ta(e,t,n){(!e||!t)&&(s.error("Please specify two preset names to compare"),s.info("Available presets: "+Object.keys(ce).join(", ")),process.exit(c.INVALID_ARGS));let r=ce[e],o=ce[t];if(r||(s.error(`Preset not found: ${e}`),process.exit(c.NOT_FOUND)),o||(s.error(`Preset not found: ${t}`),process.exit(c.NOT_FOUND)),n.format==="json"){let m={comparison:{presetA:e,presetB:t,appsOnly1:r.apps.filter(h=>!o.apps.includes(h)),appsOnly2:o.apps.filter(h=>!r.apps.includes(h)),appsCommon:r.apps.filter(h=>o.apps.includes(h)),featuresOnly1:r.features.filter(h=>!o.features.includes(h)),featuresOnly2:o.features.filter(h=>!r.features.includes(h)),featuresCommon:r.features.filter(h=>o.features.includes(h))}};process.stdout.write(JSON.stringify(m,null,2)+`
673
- `),process.exit(c.SUCCESS)}Ee.intro(v.bgCyan(v.black(" nebutra preset diff "))),s.info(`
674
- ${v.bold("Preset Comparison: "+e+" vs "+t)}
675
- `);let a=r.apps.filter(m=>!o.apps.includes(m)),i=o.apps.filter(m=>!r.apps.includes(m)),l=r.apps.filter(m=>o.apps.includes(m));s.info(v.bold("Apps:")),a.length>0&&(s.info(` Only in ${v.cyan(e)}:`),a.forEach(m=>s.info(` \u2022 ${m}`))),i.length>0&&(s.info(` Only in ${v.cyan(t)}:`),i.forEach(m=>s.info(` \u2022 ${m}`))),l.length>0&&(s.info(` ${v.green("Common")}:`),l.forEach(m=>s.info(` \u2713 ${m}`)));let u=r.features.filter(m=>!o.features.includes(m)),p=o.features.filter(m=>!r.features.includes(m)),y=r.features.filter(m=>o.features.includes(m));s.info(`
676
- ${v.bold("Features:")}`),u.length>0&&(s.info(` Only in ${v.cyan(e)}:`),u.forEach(m=>s.info(` \u2022 ${m}`))),p.length>0&&(s.info(` Only in ${v.cyan(t)}:`),p.forEach(m=>s.info(` \u2022 ${m}`))),y.length>0&&(s.info(` ${v.green("Common")}:`),y.forEach(m=>s.info(` \u2713 ${m}`))),process.exit(c.SUCCESS)}function Tn(e){let t=e.command("preset").description("Manage Nebutra presets");t.command("list").description("List all available presets").option("--format <type>","Output format: json, plain (default: plain)").action(async n=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Aa({format:n.format,yes:r.yes||!1})}),t.command("show [name]").description("Show details of a specific preset").option("--format <type>","Output format: json, plain (default: plain)").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await _a(n,{format:r.format,yes:o.yes||!1})}),t.command("apply <name>").description("Apply a preset to nebutra.config.ts").option("--dry-run","Preview changes without writing files").option("--yes","Skip confirmation prompts").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await Pa(n,{dryRun:r.dryRun||!1,yes:o.yes||!1})}),t.command("env").description("Show environment variables for current preset").option("--dry-run","Preview without executing").action(async n=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Ia({dryRun:n.dryRun||!1,yes:r.yes||!1})}),t.command("features").description("List features enabled in current preset").option("--format <type>","Output format: json, plain (default: plain)").action(async n=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Na({format:n.format,yes:r.yes||!1})}),t.command("diff <a> <b>").description("Compare two presets side by side").option("--format <type>","Output format: json, plain (default: plain)").action(async(n,r,o)=>{let a=o.optsWithGlobals?o.optsWithGlobals():o;await Ta(n,r,{format:o.format,yes:a.yes||!1})})}import*as U from"@clack/prompts";import X from"picocolors";var Un=Object.fromEntries(Object.entries(Dt).map(([e,t])=>[e,t]));function Dn(e){return typeof e=="boolean"?"boolean":"string"}function ja(){let e=Ft().map(n=>({name:n.name,description:n.description,envFile:n.envFile??".env.local",providers:(n.providers??[]).map(r=>({id:r.id,description:r.description,dependencies:r.dependencies??[],devDependencies:r.devDependencies??[],env:r.env??[]})),files:(n.files??[]).map(r=>r.path)})),t=Array.from(new Set(e.flatMap(n=>n.providers.map(r=>r.id))));return{localFeatures:e,valueDomains:{components:e.map(n=>n.name),provider:t}}}function Ua(e){let t=e.arguments.map(a=>a.name==="components"?{...a,description:"Local feature names to install from the Nebutra registry"}:a),r=e.options.some(a=>a.flags.includes("--provider"))?e.options:[...e.options,{flags:"--provider <id>",description:"Specify a provider for a local feature install",required:!1,type:"string"}],o=[{command:"nebutra add queue --provider upstash",description:"Install the local queue feature starter with the Upstash provider"},{command:"nebutra add search --provider meilisearch --dry-run",description:"Preview the local search feature install plan as JSON"},...e.examples.filter(a=>a.command.includes("--21st")||a.command.includes("--v0"))];return{...e,arguments:t,options:r,examples:o,extensions:ja()}}function Da(e){return{...e,extensions:{valueDomains:b,aliases:{storage:{supabase:"supabase-storage"},payment:{lemonsqueezy:"lemon"}}}}}function Ln(e){let t={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:Dn(n.default)})),examples:e.examples||[]};return e.name==="add"?Ua(t):e.name==="create"?Da(t):t}function La(e){let n=(fe.subcommands||[]).find(r=>r.name===e);return n?Ln(n):null}function Fa(){return(fe.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:Dn(e.default)}))}function Ma(e){let t=fe.subcommands||[];return{name:fe.name,version:e,description:fe.description,usage:fe.usage||"nebutra [command] [options]",globalOptions:Fa(),commands:t.map(Ln),exitCodes:Un,timestamp:new Date().toISOString()}}function jn(){return(fe.subcommands||[]).map(t=>t.name)}function lt(e){process.stdout.write(`${JSON.stringify(e,null,2)}
677
- `)}function Ga(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function Ka(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(lt(Ma(r)),process.exit(0)),t.list===!0&&(lt(jn()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(lt(Un),process.exit(0)),e){let o=La(e);o||(n||(s.error(`Unknown command '${e}'`),s.info(`Available commands: ${jn().join(", ")}`)),process.exit(2)),lt(o),process.exit(0)}n||(U.intro(X.bgCyan(X.black(" nebutra schema "))),U.log.info(X.cyan("Agent-friendly introspection of CLI commands, arguments, and value domains.")),U.log.message(""),U.log.info(X.bold("Usage:")),U.log.message(X.dim(" nebutra schema --all Show full command tree as JSON")),U.log.message(X.dim(" nebutra schema <command> Show schema for a specific command")),U.log.message(X.dim(" nebutra schema --list List available command names")),U.log.message(X.dim(" nebutra schema --exit-codes Show exit codes reference")),U.log.message(""),U.log.info(X.bold("Example:")),U.log.message(X.dim(" nebutra schema add")),U.log.message(X.dim(" nebutra schema --all | jq '.commands[0]'")),U.outro(X.cyan("All output is JSON for easy parsing by agents and automation tools."))),process.exit(0)}catch(o){if(Ga(o))throw o;n||s.error(o instanceof Error?o.message:String(o)),process.exit(1)}}function Fn(e){e.command("schema [command]").description("Show command schema and argument documentation (Agent-friendly JSON output)").option("--all","Show full schema for all commands").option("--list","List all available command names").option("--exit-codes","Show exit codes reference").action(async(t,n)=>{await Ka(t,n)})}import*as dt from"@clack/prompts";import Z from"picocolors";function Ge(){let e=process.env.MEILISEARCH_URL,t=process.env.TYPESENSE_URL,n=process.env.ALGOLIA_APP_ID;return e?{type:"meilisearch",url:e,health:!0,message:"Meilisearch configured"}:t?{type:"typesense",url:t,health:!0,message:"Typesense configured"}:n?{type:"algolia",health:!0,message:"Algolia configured"}:{type:"none",health:!1,message:"No search provider configured"}}async function qa(e){d("Detecting search provider...","info");let t=Ge();t.type==="none"&&(d("No search provider is configured","warn"),d("Set one of: MEILISEARCH_URL, TYPESENSE_URL, or ALGOLIA_APP_ID","info"),process.exit(0));let n={provider:t.type,configured:!0,url:t.url||"managed",health:t.health,message:t.message};e.format==="json"?E(n,{format:"json"}):(d(`Search Provider: ${Z.cyan(t.type.toUpperCase())}`,"success"),d(`Status: ${t.health?Z.green("Healthy"):Z.red("Unhealthy")}`,t.health?"success":"error"),t.url&&d(`URL: ${t.url}`,"info"))}async function Va(e){d("Fetching search indexes...","info"),Ge().type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let n=[{name:"products",documentCount:15420,size:"2.4 MB",lastUpdated:"2 hours ago"},{name:"articles",documentCount:3240,size:"1.1 MB",lastUpdated:"1 day ago"},{name:"users",documentCount:8900,size:"0.8 MB",lastUpdated:"30 minutes ago"}];if(e.format==="json")E(n,{format:"json"});else{d("Search Indexes","info");for(let r of n)d(`${Z.cyan(r.name)}: ${r.documentCount} documents (${r.size})`,"info")}}async function Mn(e,t){let n=t||{},r=Ge();r.type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let o=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e&&!n.force&&!n.dryRun&&o){let i=await dt.confirm({message:"Reindex ALL indexes? This will recreate all indexes from scratch.",initialValue:!1});(dt.isCancel(i)||!i)&&(d("Reindex cancelled","warn"),process.exit(0))}!n.yes&&!n.dryRun&&!e&&(d("Full reindex requires --yes confirmation","error"),process.exit(c.INVALID_ARGS));let a=e||"all";if(d(`Reindexing ${Z.cyan(a)}...`,"info"),n.dryRun){d(`Would reindex ${a} with provider ${r.type}`,"info");return}d(`Reindexing ${a} on ${r.type}...`,"info"),d(`Index ${Z.cyan(a)} reindexed successfully`,"success")}async function Wa(e,t,n){d(`Querying ${Z.cyan(e)} for "${Z.yellow(t)}"...`,"info");let r=Ge();r.type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let o=[{id:"1",title:"Sample Result 1",score:.95,_formatted:{title:"Sample <mark>Result</mark> 1",content:"Contains search term..."}},{id:"2",title:"Another Result",score:.87,_formatted:{title:"Another <mark>Result</mark>",content:"Also matches search..."}}],a={index:e,query:t,provider:r.type,hits:o.length,limit:n.limit||10,results:o};if(n.format==="json")E(a,{format:"json"});else{d(`Found ${Z.cyan(String(o.length))} results for "${t}"`,"success");for(let i of o)d(`${Z.dim(String(i.score))}: ${i.title}`,"info")}}async function za(e){d("Fetching search statistics...","info");let t=Ge();t.type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let n={provider:t.type,indexes:[{name:"products",documents:15420,size:24e5,lastUpdated:"2024-03-30T14:22:00Z"},{name:"articles",documents:3240,size:11e5,lastUpdated:"2024-03-29T08:15:00Z"},{name:"users",documents:8900,size:8e5,lastUpdated:"2024-03-30T14:52:00Z"}],totalDocuments:27560,totalSize:43e5};if(e.format==="json")E(n,{format:"json"});else{d("Search Statistics","info"),d(`Provider: ${Z.cyan(n.provider)}`,"info"),d(`Total Indexes: ${n.indexes.length}`,"info"),d(`Total Documents: ${n.totalDocuments.toLocaleString()}`,"info"),d(`Total Size: ${(n.totalSize/1024/1024).toFixed(2)} MB`,"info"),d("Index Breakdown:","info");for(let r of n.indexes)d(` ${Z.cyan(r.name)}: ${r.documents.toLocaleString()} docs (${(r.size/1024/1024).toFixed(2)} MB)`,"info")}}function Gn(e){e.command("search <verb> [args...]").description("Manage search engine (Meilisearch, Typesense, or Algolia)").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations").option("--format <type>","Output format: json, plain, table","plain").option("--force","Force operation (e.g., recreate index)").option("--limit <n>","Result limit for queries").option("--filters <json>","Filters for search query (JSON)").option("--tenant <id>","Tenant ID for multi-tenant queries").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,force:o.force||!1,limit:o.limit??10,filters:o.filters,tenant:o.tenant};try{switch(n){case"status":await qa(i);break;case"indexes":await Va(i);break;case"reindex":r.length>0?await Mn(r[0],i):await Mn(void 0,i);break;case"query":r.length<2&&(d("query requires an index and search term: nebutra search query <index> <query>","error"),process.exit(c.INVALID_ARGS)),await Wa(r[0],r.slice(1).join(" "),i);break;case"stats":await za(i);break;default:d(`Unknown search subcommand: ${n}. Valid commands: status, indexes, reindex, query, stats`,"error"),process.exit(c.ERROR)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Search command failed: ${u}`,"error"),k("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
759
+ Total: ${i.length} features`),process.exit(c.SUCCESS)}catch(r){s.error(`Failed to read config: ${r instanceof Error?r.message:"Unknown error"}`),process.exit(c.ERROR)}}async function gc(e,t,n){(!e||!t)&&(s.error("Please specify two preset names to compare"),s.info("Available presets: "+Object.keys(de).join(", ")),process.exit(c.INVALID_ARGS));let r=de[e],o=de[t];if(r||(s.error(`Preset not found: ${e}`),process.exit(c.NOT_FOUND)),o||(s.error(`Preset not found: ${t}`),process.exit(c.NOT_FOUND)),n.format==="json"){let p={comparison:{presetA:e,presetB:t,appsOnly1:r.apps.filter(b=>!o.apps.includes(b)),appsOnly2:o.apps.filter(b=>!r.apps.includes(b)),appsCommon:r.apps.filter(b=>o.apps.includes(b)),featuresOnly1:r.features.filter(b=>!o.features.includes(b)),featuresOnly2:o.features.filter(b=>!r.features.includes(b)),featuresCommon:r.features.filter(b=>o.features.includes(b))}};process.stdout.write(JSON.stringify(p,null,2)+`
760
+ `),process.exit(c.SUCCESS)}xe.intro(w.bgCyan(w.black(" nebutra preset diff "))),s.info(`
761
+ ${w.bold("Preset Comparison: "+e+" vs "+t)}
762
+ `);let a=r.apps.filter(p=>!o.apps.includes(p)),i=o.apps.filter(p=>!r.apps.includes(p)),l=r.apps.filter(p=>o.apps.includes(p));s.info(w.bold("Apps:")),a.length>0&&(s.info(` Only in ${w.cyan(e)}:`),a.forEach(p=>s.info(` \u2022 ${p}`))),i.length>0&&(s.info(` Only in ${w.cyan(t)}:`),i.forEach(p=>s.info(` \u2022 ${p}`))),l.length>0&&(s.info(` ${w.green("Common")}:`),l.forEach(p=>s.info(` \u2713 ${p}`)));let u=r.features.filter(p=>!o.features.includes(p)),m=o.features.filter(p=>!r.features.includes(p)),g=r.features.filter(p=>o.features.includes(p));s.info(`
763
+ ${w.bold("Features:")}`),u.length>0&&(s.info(` Only in ${w.cyan(e)}:`),u.forEach(p=>s.info(` \u2022 ${p}`))),m.length>0&&(s.info(` Only in ${w.cyan(t)}:`),m.forEach(p=>s.info(` \u2022 ${p}`))),g.length>0&&(s.info(` ${w.green("Common")}:`),g.forEach(p=>s.info(` \u2713 ${p}`))),process.exit(c.SUCCESS)}function br(e){let t=e.command("preset").description("Manage Nebutra presets");t.command("list").description("List all available presets").option("--format <type>","Output format: json, plain (default: plain)").action(async n=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await dc({format:n.format,yes:r.yes||!1})}),t.command("show [name]").description("Show details of a specific preset").option("--format <type>","Output format: json, plain (default: plain)").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await uc(n,{format:r.format,yes:o.yes||!1})}),t.command("apply <name>").description("Apply a preset to nebutra.config.ts").option("--dry-run","Preview changes without writing files").option("--yes","Skip confirmation prompts").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await mc(n,{dryRun:r.dryRun||!1,yes:o.yes||!1})}),t.command("env").description("Show environment variables for current preset").option("--dry-run","Preview without executing").action(async n=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await pc({dryRun:n.dryRun||!1,yes:r.yes||!1})}),t.command("features").description("List features enabled in current preset").option("--format <type>","Output format: json, plain (default: plain)").action(async n=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await fc({format:n.format,yes:r.yes||!1})}),t.command("diff <a> <b>").description("Compare two presets side by side").option("--format <type>","Output format: json, plain (default: plain)").action(async(n,r,o)=>{let a=o.optsWithGlobals?o.optsWithGlobals():o;await gc(n,r,{format:o.format,yes:a.yes||!1})})}import*as F from"@clack/prompts";import ee from"picocolors";var wr=Object.fromEntries(Object.entries(tn).map(([e,t])=>[e,t]));function Sr(e){return typeof e=="boolean"?"boolean":"string"}function yc(){let e=an().map(n=>({name:n.name,description:n.description,envFile:n.envFile??".env.local",providers:(n.providers??[]).map(r=>({id:r.id,description:r.description,dependencies:r.dependencies??[],devDependencies:r.devDependencies??[],env:r.env??[]})),files:(n.files??[]).map(r=>r.path)})),t=Array.from(new Set(e.flatMap(n=>n.providers.map(r=>r.id))));return{localFeatures:e,valueDomains:{components:e.map(n=>n.name),provider:t}}}function hc(e){let t=e.arguments.map(a=>a.name==="components"?{...a,description:"Local feature names to install from the Nebutra registry"}:a),r=e.options.some(a=>a.flags.includes("--provider"))?e.options:[...e.options,{flags:"--provider <id>",description:"Specify a provider for a local feature install",required:!1,type:"string"}],o=[{command:"nebutra add queue --provider upstash",description:"Install the local queue feature starter with the Upstash provider"},{command:"nebutra add search --provider meilisearch --dry-run",description:"Preview the local search feature install plan as JSON"},...e.examples.filter(a=>a.command.includes("--21st")||a.command.includes("--v0"))];return{...e,arguments:t,options:r,examples:o,extensions:yc()}}function bc(e){return{...e,extensions:{valueDomains:v,aliases:{storage:{supabase:"supabase-storage"},payment:{lemonsqueezy:"lemon"}}}}}function Rr(e){let t={name:e.name,description:e.description,usage:e.usage,arguments:e.arguments||[],options:(e.options||[]).map(n=>({flags:n.flags,description:n.description,default:n.default,required:!1,type:Sr(n.default)})),examples:e.examples||[]};return e.name==="add"?hc(t):e.name==="create"?bc(t):t}function vc(e){let n=(he.subcommands||[]).find(r=>r.name===e);return n?Rr(n):null}function wc(){return(he.options??[]).map(e=>({flags:e.flags,description:e.description,required:!1,type:Sr(e.default)}))}function Sc(e){let t=he.subcommands||[];return{name:he.name,version:e,description:he.description,usage:he.usage||"nebutra [command] [options]",globalOptions:wc(),commands:t.map(Rr),exitCodes:wr,timestamp:new Date().toISOString()}}function vr(){return(he.subcommands||[]).map(t=>t.name)}function St(e){process.stdout.write(`${JSON.stringify(e,null,2)}
764
+ `)}function Rc(e){return e instanceof Error&&e.message.startsWith("EXIT:")}async function Ec(e,t){let n=t.quiet===!0,r="0.1.0";try{if(t.all===!0&&(St(Sc(r)),process.exit(0)),t.list===!0&&(St(vr()),process.exit(0)),(t.exitCodes===!0||t["exit-codes"]===!0)&&(St(wr),process.exit(0)),e){let o=vc(e);o||(n||(s.error(`Unknown command '${e}'`),s.info(`Available commands: ${vr().join(", ")}`)),process.exit(c.NOT_FOUND)),St(o),process.exit(0)}n||(F.intro(ee.bgCyan(ee.black(" nebutra schema "))),F.log.info(ee.cyan("Agent-friendly introspection of CLI commands, arguments, and value domains.")),F.log.message(""),F.log.info(ee.bold("Usage:")),F.log.message(ee.dim(" nebutra schema --all Show full command tree as JSON")),F.log.message(ee.dim(" nebutra schema <command> Show schema for a specific command")),F.log.message(ee.dim(" nebutra schema --list List available command names")),F.log.message(ee.dim(" nebutra schema --exit-codes Show exit codes reference")),F.log.message(""),F.log.info(ee.bold("Example:")),F.log.message(ee.dim(" nebutra schema add")),F.log.message(ee.dim(" nebutra schema --all | jq '.commands[0]'")),F.outro(ee.cyan("All output is JSON for easy parsing by agents and automation tools."))),process.exit(0)}catch(o){if(Rc(o))throw o;n||s.error(o instanceof Error?o.message:String(o)),process.exit(c.ERROR)}}function Er(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 Ec(t,n)})}import*as Rt from"@clack/prompts";import te from"picocolors";function Ye(){let e=process.env.MEILISEARCH_URL,t=process.env.TYPESENSE_URL,n=process.env.ALGOLIA_APP_ID;return e?{type:"meilisearch",url:e,health:!0,message:"Meilisearch configured"}:t?{type:"typesense",url:t,health:!0,message:"Typesense configured"}:n?{type:"algolia",health:!0,message:"Algolia configured"}:{type:"none",health:!1,message:"No search provider configured"}}async function Cc(e){d("Detecting search provider...","info");let t=Ye();t.type==="none"&&(d("No search provider is configured","warn"),d("Set one of: MEILISEARCH_URL, TYPESENSE_URL, or ALGOLIA_APP_ID","info"),process.exit(0));let n={provider:t.type,configured:!0,url:t.url||"managed",health:t.health,message:t.message};e.format==="json"?O(n,{format:"json"}):(d(`Search Provider: ${te.cyan(t.type.toUpperCase())}`,"success"),d(`Status: ${t.health?te.green("Healthy"):te.red("Unhealthy")}`,t.health?"success":"error"),t.url&&d(`URL: ${t.url}`,"info"))}async function kc(e){d("Fetching search indexes...","info"),Ye().type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let n=[{name:"products",documentCount:15420,size:"2.4 MB",lastUpdated:"2 hours ago"},{name:"articles",documentCount:3240,size:"1.1 MB",lastUpdated:"1 day ago"},{name:"users",documentCount:8900,size:"0.8 MB",lastUpdated:"30 minutes ago"}];if(e.format==="json")O(n,{format:"json"});else{d("Search Indexes","info");for(let r of n)d(`${te.cyan(r.name)}: ${r.documentCount} documents (${r.size})`,"info")}}async function Cr(e,t){let n=t||{},r=Ye();r.type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let o=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!e&&!n.force&&!n.dryRun&&o){let i=await Rt.confirm({message:"Reindex ALL indexes? This will recreate all indexes from scratch.",initialValue:!1});(Rt.isCancel(i)||!i)&&(d("Reindex cancelled","warn"),process.exit(c.CANCELLED))}!n.yes&&!n.dryRun&&!e&&(d("Full reindex requires --yes confirmation","error"),process.exit(c.INVALID_ARGS));let a=e||"all";if(d(`Reindexing ${te.cyan(a)}...`,"info"),n.dryRun){d(`Would reindex ${a} with provider ${r.type}`,"info");return}d(`Reindexing ${a} on ${r.type}...`,"info"),d(`Index ${te.cyan(a)} reindexed successfully`,"success")}async function Oc(e,t,n){d(`Querying ${te.cyan(e)} for "${te.yellow(t)}"...`,"info");let r=Ye();r.type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let o=[{id:"1",title:"Sample Result 1",score:.95,_formatted:{title:"Sample <mark>Result</mark> 1",content:"Contains search term..."}},{id:"2",title:"Another Result",score:.87,_formatted:{title:"Another <mark>Result</mark>",content:"Also matches search..."}}],a={index:e,query:t,provider:r.type,hits:o.length,limit:n.limit||10,results:o};if(n.format==="json")O(a,{format:"json"});else{d(`Found ${te.cyan(String(o.length))} results for "${t}"`,"success");for(let i of o)d(`${te.dim(String(i.score))}: ${i.title}`,"info")}}async function xc(e){d("Fetching search statistics...","info");let t=Ye();t.type==="none"&&(d("No search provider configured","error"),process.exit(c.CONFIG_ERROR));let n={provider:t.type,indexes:[{name:"products",documents:15420,size:24e5,lastUpdated:"2024-03-30T14:22:00Z"},{name:"articles",documents:3240,size:11e5,lastUpdated:"2024-03-29T08:15:00Z"},{name:"users",documents:8900,size:8e5,lastUpdated:"2024-03-30T14:52:00Z"}],totalDocuments:27560,totalSize:43e5};if(e.format==="json")O(n,{format:"json"});else{d("Search Statistics","info"),d(`Provider: ${te.cyan(n.provider)}`,"info"),d(`Total Indexes: ${n.indexes.length}`,"info"),d(`Total Documents: ${n.totalDocuments.toLocaleString()}`,"info"),d(`Total Size: ${(n.totalSize/1024/1024).toFixed(2)} MB`,"info"),d("Index Breakdown:","info");for(let r of n.indexes)d(` ${te.cyan(r.name)}: ${r.documents.toLocaleString()} docs (${(r.size/1024/1024).toFixed(2)} MB)`,"info")}}function kr(e){e.command("search <verb> [args...]").description("Manage search engine (Meilisearch, Typesense, or Algolia)").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations").option("--format <type>","Output format: json, plain, table","plain").option("--force","Force operation (e.g., recreate index)").option("--limit <n>","Result limit for queries").option("--filters <json>","Filters for search query (JSON)").option("--tenant <id>","Tenant ID for multi-tenant queries").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,force:o.force||!1,limit:o.limit??10,filters:o.filters,tenant:o.tenant};try{switch(n){case"status":await Cc(i);break;case"indexes":await kc(i);break;case"reindex":r.length>0?await Cr(r[0],i):await Cr(void 0,i);break;case"query":r.length<2&&(d("query requires an index and search term: nebutra search query <index> <query>","error"),process.exit(c.INVALID_ARGS)),await Oc(r[0],r.slice(1).join(" "),i);break;case"stats":await xc(i);break;default:d(`Unknown search subcommand: ${n}. Valid commands: status, indexes, reindex, query, stats`,"error"),process.exit(c.ERROR)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Search command failed: ${u}`,"error"),_("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
678
765
  Examples:
679
766
  nebutra search status Show search provider status
680
767
  nebutra search indexes List all indexes
@@ -697,7 +784,7 @@ Flags:
697
784
  --limit <n> Result limit for queries (default: 10)
698
785
  --filters <json> Filters for search query
699
786
  --tenant <id> Tenant ID for multi-tenant searches
700
- `)}import{stdin as Ke}from"process";import*as ut from"@clack/prompts";import P from"picocolors";async function Ba(){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 Ya(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")E(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(`${P.cyan(n.key)}${P.gray(r)}`,"info"),d(` Updated: ${n.updatedAt}`,"info")}}}async function Ha(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 Ba()}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 ${P.cyan(e)}...`,"info"),t.dryRun){d(`Would encrypt and store secret ${e} for tenant ${t.tenant||"org_123"}`,"info");return}d(`Secret ${P.cyan(e)} encrypted and stored successfully`,"success"),t.description&&d(`Description: ${t.description}`,"info")}async function Ja(e,t){e||(d("Secret key is required: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),d(`Retrieving secret ${P.cyan(e)}...`,"info");let r=t.unmask?"sk_live_abc123xyz789...":"***masked***";t.unmask||d(`Secret value is ${P.yellow("masked")}. Use --unmask to display.`,"warn");let o={key:e,tenant:t.tenant||"org_123",value:r,encrypted:!0};t.format==="json"?E(o,{format:"json"}):d(`${P.cyan(e)}: ${r}`,"info")}async function Qa(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 ut.confirm({message:`Rotate encryption key for ${P.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});(ut.isCancel(r)||!r)&&(d("Rotation cancelled","warn"),process.exit(0))}if(!t.yes&&!t.dryRun&&!n&&(d("Key rotation requires --yes confirmation","error"),process.exit(c.INVALID_ARGS)),d(`Rotating encryption key for ${P.cyan(e)}...`,"info"),t.dryRun){d(`Would rotate encryption key for ${e}`,"info");return}d(`Encryption key for ${P.cyan(e)} rotated successfully`,"success"),d(`New key version: ${P.dim("v2")}`,"info")}async function Xa(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")E(n,{format:"json"});else{d("Secret Access Audit Log","info");for(let r of n){let o=r.success?P.green("\u2713"):P.red("\u2716");d(`${o} ${r.timestamp} ${P.cyan(r.action)} ${r.key}`,r.success?"success":"error"),d(` Actor: ${r.actor}${r.message?` \u2014 ${r.message}`:""}`,"info")}}}async function Za(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")E(t,{format:"json"});else{d("Vault Configuration Check","info");for(let r of t){let o=r.healthy?P.green("\u2713"):P.red("\u2716");d(`${o} ${r.name}: ${r.message}`,r.healthy?"success":"error")}let n=t.every(r=>r.healthy);d(`Overall: ${n?P.green("HEALTHY"):P.red("UNHEALTHY")}`,n?"success":"error")}}function Kn(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 Ya(i);break;case"set":r.length===0&&(d("set requires a secret key: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS)),await Ha(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 Ja(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 Qa(r[0],i);break;case"audit":await Xa(i);break;case"verify":await Za(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",`
787
+ `)}import{stdin as He}from"process";import*as Et from"@clack/prompts";import T from"picocolors";async function _c(){return new Promise((e,t)=>{let n="";He.setEncoding("utf8"),He.on("readable",()=>{let r;for(;(r=He.read())!==null;)n+=r}),He.on("end",()=>{e(n.trim())}),He.on("error",t)})}async function Ac(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")O(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(`${T.cyan(n.key)}${T.gray(r)}`,"info"),d(` Updated: ${n.updatedAt}`,"info")}}}async function $c(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 _c()}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 ${T.cyan(e)}...`,"info"),t.dryRun){d(`Would encrypt and store secret ${e} for tenant ${t.tenant||"org_123"}`,"info");return}d(`Secret ${T.cyan(e)} encrypted and stored successfully`,"success"),t.description&&d(`Description: ${t.description}`,"info")}async function Pc(e,t){e||(d("Secret key is required: nebutra secrets get <key>","error"),process.exit(c.INVALID_ARGS)),d(`Retrieving secret ${T.cyan(e)}...`,"info");let r=t.unmask?"sk_live_abc123xyz789...":"***masked***";t.unmask||d(`Secret value is ${T.yellow("masked")}. Use --unmask to display.`,"warn");let o={key:e,tenant:t.tenant||"org_123",value:r,encrypted:!0};t.format==="json"?O(o,{format:"json"}):d(`${T.cyan(e)}: ${r}`,"info")}async function Nc(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 Et.confirm({message:`Rotate encryption key for ${T.cyan(e)}? This will re-encrypt with new key material.`,initialValue:!1});(Et.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 ${T.cyan(e)}...`,"info"),t.dryRun){d(`Would rotate encryption key for ${e}`,"info");return}d(`Encryption key for ${T.cyan(e)} rotated successfully`,"success"),d(`New key version: ${T.dim("v2")}`,"info")}async function Ic(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")O(n,{format:"json"});else{d("Secret Access Audit Log","info");for(let r of n){let o=r.success?T.green("\u2713"):T.red("\u2716");d(`${o} ${r.timestamp} ${T.cyan(r.action)} ${r.key}`,r.success?"success":"error"),d(` Actor: ${r.actor}${r.message?` \u2014 ${r.message}`:""}`,"info")}}}async function Tc(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")O(t,{format:"json"});else{d("Vault Configuration Check","info");for(let r of t){let o=r.healthy?T.green("\u2713"):T.red("\u2716");d(`${o} ${r.name}: ${r.message}`,r.healthy?"success":"error")}let n=t.every(r=>r.healthy);d(`Overall: ${n?T.green("HEALTHY"):T.red("UNHEALTHY")}`,n?"success":"error")}}function Or(e){e.command("secrets <verb> [args...]").description("Manage encrypted secrets via @nebutra/vault (AWS KMS + HKDF envelope encryption)").option("--dry-run","Show what would be run without executing").option("--yes","Skip confirmations").option("--format <type>","Output format: json, plain, table","plain").option("--tenant <id>","Tenant ID for multi-tenant access").option("--unmask","Unmask secret values (required to view)").option("--description <text>","Description for secret").option("--value <text>","Secret value (prefer stdin for security)").option("--since <date>","Audit log start date (ISO 8601)").option("--limit <n>","Maximum audit log entries (default: 50)").action(async(n,r,o)=>{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 Ac(i);break;case"set":r.length===0&&(d("set requires a secret key: nebutra secrets set <key>","error"),process.exit(c.INVALID_ARGS)),await $c(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 Pc(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 Nc(r[0],i);break;case"audit":await Ic(i);break;case"verify":await Tc(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"),_("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
701
788
  Examples:
702
789
  nebutra secrets list List all secrets (metadata only)
703
790
  nebutra secrets list --tenant org_456 List secrets for specific tenant
@@ -732,7 +819,7 @@ Security Notes:
732
819
  - Never use --value in production (visible in shell history)
733
820
  - Always use --unmask when viewing secrets in scripts
734
821
  - Audit log tracks all access and modifications
735
- `)}import*as mt from"@clack/prompts";import D from"picocolors";function qn(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function ei(e){switch(e){case"running":return D.green("\u25CF");case"exited":return D.red("\u25CF");case"restarting":return D.yellow("\u25CF");case"paused":return D.gray("\u25CF");default:return D.gray("\u25CF")}}async function ti(e){d("Checking service status...","info");let t=await A({command:"docker",args:["compose","ps","--format","json"],cwd:R(),interactive:!1,label:"Docker Compose PS",dryRun:e.dryRun});t.exitCode!==0&&(d("Failed to fetch service status","error"),k("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:qn(o.State),exitCode:o.ExitCode}));E(r,{format:"json"})}else{d("Service Status","info");let r=n.map(o=>({Service:ei(qn(o.State))+" "+o.Name,Status:o.State,"Exit Code":o.ExitCode||"\u2014"}));for(let o of r)d(`${o.Service} (${o.Status})`,"info")}}catch(n){d("Failed to parse service status","error"),k("Parse error",{error:String(n)}),process.exit(c.ERROR)}}async function ni(e,t){d(`Streaming logs for ${D.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 A({command:"docker",args:n,cwd:R(),interactive:!0,label:`Docker Compose Logs (${e})`,dryRun:t.dryRun})).exitCode!==0&&(d(`Failed to stream logs for ${e}`,"error"),process.exit(c.ERROR))}async function ri(e,t){let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let a=await mt.confirm({message:`Restart service ${D.cyan(e)}?`,initialValue:!1});(mt.isCancel(a)||!a)&&(d("Restart cancelled","warn"),process.exit(0))}d(`Restarting service ${D.cyan(e)}...`,"info");let r=["compose","restart"];t.timeout&&r.push("--timeout",String(t.timeout)),r.push(e);let o=await A({command:"docker",args:r,cwd:R(),interactive:!1,label:`Docker Compose Restart (${e})`,dryRun:t.dryRun});o.exitCode===0?d(`Service ${D.cyan(e)} restarted successfully`,"success"):(d(`Failed to restart service ${e}`,"error"),k("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}async function oi(e){d("Running deep health check...","info");let t=[],n=await A({command:"docker",args:["compose","exec","-T","postgres","pg_isready"],cwd:R(),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 A({command:"docker",args:["compose","exec","-T","redis","redis-cli","ping"],cwd:R(),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 A({command:"docker",args:["compose","exec","-T","clickhouse","curl","-s","http://localhost:8123/ping"],cwd:R(),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 A({command:"docker",args:["compose","exec","-T","meilisearch","curl","-s","http://localhost:7700/health"],cwd:R(),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")E(t,{format:"json"});else{for(let l of t){let u=l.healthy?D.green("\u2713"):D.red("\u2716");d(`${u} ${l.service}: ${l.message}`,l.healthy?"success":"error")}let i=t.every(l=>l.healthy);d(`Overall health: ${i?D.green("HEALTHY"):D.red("UNHEALTHY")}`,i?"success":"error")}}async function si(e,t,n){let r=parseInt(t,10);(Number.isNaN(r)||r<0)&&(d("Invalid replica count (must be a non-negative number)","error"),process.exit(c.INVALID_ARGS)),d(`Scaling ${D.cyan(e)} to ${D.cyan(String(r))} replicas...`,"info");let o=await A({command:"docker",args:["compose","up","-d","--scale",`${e}=${r}`],cwd:R(),interactive:!1,label:`Docker Compose Scale (${e})`,dryRun:n.dryRun});o.exitCode===0?d(`Service ${D.cyan(e)} scaled to ${r} replicas`,"success"):(d(`Failed to scale service ${e}`,"error"),k("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}function Vn(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 ti(i);break;case"logs":r.length===0&&(d("logs requires a service name: nebutra services logs <service>","error"),process.exit(c.INVALID_ARGS)),await ni(r[0],i);break;case"restart":r.length===0&&(d("restart requires a service name: nebutra services restart <service>","error"),process.exit(c.INVALID_ARGS)),await ri(r[0],i);break;case"health":await oi(i);break;case"scale":r.length<2&&(d("scale requires a service name and replica count: nebutra services scale <service> <count>","error"),process.exit(c.INVALID_ARGS)),await si(r[0],r[1],i);break;default:d(`Unknown services subcommand: ${n}. Valid commands: status, logs, restart, health, scale`,"error"),process.exit(c.ERROR)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Services command failed: ${u}`,"error"),k("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
822
+ `)}import*as Ct from"@clack/prompts";import M from"picocolors";function xr(e){switch(e.toLowerCase()){case"running":return"running";case"exited":return"exited";case"restarting":return"restarting";case"paused":return"paused";default:return"exited"}}function Uc(e){switch(e){case"running":return M.green("\u25CF");case"exited":return M.red("\u25CF");case"restarting":return M.yellow("\u25CF");case"paused":return M.gray("\u25CF");default:return M.gray("\u25CF")}}async function jc(e){d("Checking service status...","info");let t=await $({command:"docker",args:["compose","ps","--format","json"],cwd:h(),interactive:!1,label:"Docker Compose PS",dryRun:e.dryRun});t.exitCode!==0&&(d("Failed to fetch service status","error"),_("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:xr(o.State),exitCode:o.ExitCode}));O(r,{format:"json"})}else{d("Service Status","info");let r=n.map(o=>({Service:Uc(xr(o.State))+" "+o.Name,Status:o.State,"Exit Code":o.ExitCode||"\u2014"}));for(let o of r)d(`${o.Service} (${o.Status})`,"info")}}catch(n){d("Failed to parse service status","error"),_("Parse error",{error:String(n)}),process.exit(c.ERROR)}}async function Lc(e,t){d(`Streaming logs for ${M.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 $({command:"docker",args:n,cwd:h(),interactive:!0,label:`Docker Compose Logs (${e})`,dryRun:t.dryRun})).exitCode!==0&&(d(`Failed to stream logs for ${e}`,"error"),process.exit(c.ERROR))}async function Dc(e,t){let n=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;if(!t.yes&&!t.dryRun&&n){let a=await Ct.confirm({message:`Restart service ${M.cyan(e)}?`,initialValue:!1});(Ct.isCancel(a)||!a)&&(d("Restart cancelled","warn"),process.exit(c.CANCELLED))}d(`Restarting service ${M.cyan(e)}...`,"info");let r=["compose","restart"];t.timeout&&r.push("--timeout",String(t.timeout)),r.push(e);let o=await $({command:"docker",args:r,cwd:h(),interactive:!1,label:`Docker Compose Restart (${e})`,dryRun:t.dryRun});o.exitCode===0?d(`Service ${M.cyan(e)} restarted successfully`,"success"):(d(`Failed to restart service ${e}`,"error"),_("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}async function Fc(e){d("Running deep health check...","info");let t=[],n=await $({command:"docker",args:["compose","exec","-T","postgres","pg_isready"],cwd:h(),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 $({command:"docker",args:["compose","exec","-T","redis","redis-cli","ping"],cwd:h(),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 $({command:"docker",args:["compose","exec","-T","clickhouse","curl","-s","http://localhost:8123/ping"],cwd:h(),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 $({command:"docker",args:["compose","exec","-T","meilisearch","curl","-s","http://localhost:7700/health"],cwd:h(),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")O(t,{format:"json"});else{for(let l of t){let u=l.healthy?M.green("\u2713"):M.red("\u2716");d(`${u} ${l.service}: ${l.message}`,l.healthy?"success":"error")}let i=t.every(l=>l.healthy);d(`Overall health: ${i?M.green("HEALTHY"):M.red("UNHEALTHY")}`,i?"success":"error")}}async function Mc(e,t,n){let r=parseInt(t,10);(Number.isNaN(r)||r<0)&&(d("Invalid replica count (must be a non-negative number)","error"),process.exit(c.INVALID_ARGS)),d(`Scaling ${M.cyan(e)} to ${M.cyan(String(r))} replicas...`,"info");let o=await $({command:"docker",args:["compose","up","-d","--scale",`${e}=${r}`],cwd:h(),interactive:!1,label:`Docker Compose Scale (${e})`,dryRun:n.dryRun});o.exitCode===0?d(`Service ${M.cyan(e)} scaled to ${r} replicas`,"success"):(d(`Failed to scale service ${e}`,"error"),_("Docker error",{stderr:o.stderr}),process.exit(c.ERROR))}function _r(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 jc(i);break;case"logs":r.length===0&&(d("logs requires a service name: nebutra services logs <service>","error"),process.exit(c.INVALID_ARGS)),await Lc(r[0],i);break;case"restart":r.length===0&&(d("restart requires a service name: nebutra services restart <service>","error"),process.exit(c.INVALID_ARGS)),await Dc(r[0],i);break;case"health":await Fc(i);break;case"scale":r.length<2&&(d("scale requires a service name and replica count: nebutra services scale <service> <count>","error"),process.exit(c.INVALID_ARGS)),await Mc(r[0],r[1],i);break;default:d(`Unknown services subcommand: ${n}. Valid commands: status, logs, restart, health, scale`,"error"),process.exit(c.ERROR)}}catch(l){let u=l instanceof Error?l.message:String(l);d(`Services command failed: ${u}`,"error"),_("Full error",{error:l}),process.exit(c.ERROR)}}).addHelpText("after",`
736
823
  Examples:
737
824
  nebutra services status Show all service status
738
825
  nebutra services logs postgres Stream postgres logs
@@ -753,16 +840,86 @@ Flags:
753
840
  --tail <n> Log lines to show (default: 100)
754
841
  --since <duration> Show logs since (e.g., 10m, 1h)
755
842
  --timeout <seconds> Timeout for restart
756
- `)}import{existsSync as B,readdirSync as qe,readFileSync as Wn}from"fs";import{resolve as L}from"path";import Pe from"picocolors";function ke(e,t,n){if(t==="json"){let r={command:n||"stats",...e};console.log(JSON.stringify(r,null,2))}else e.stdout&&(console.log(e.stdout),delete e.stdout),Object.keys(e).length>0&&console.log(JSON.stringify(e,null,2))}function zn(e){try{let t=Wn(L(e,"package.json"),"utf-8");return JSON.parse(t)}catch{return{}}}function Bn(e){try{return qe(e,{recursive:!0}).length}catch{return 0}}async function ai(e){s.info("Gathering monorepo statistics...");let t=R(),n=L(t,"packages"),r=L(t,"apps"),o=[],a=[],i=0,l="unknown";try{B(n)&&(o=qe(n).filter(y=>!y.startsWith(".")&&B(L(n,y,"package.json")))),B(r)&&(a=qe(r).filter(y=>!y.startsWith(".")&&B(L(r,y,"package.json"))));let p=L(t,"nebutra.config.ts");if(B(p)){let m=Wn(p,"utf-8").match(/preset:\s*["']([^"']+)["']/);m&&(l=m[1])}}catch(p){s.warn(`Failed to read monorepo structure: ${p instanceof Error?p.message:String(p)}`)}let u={monorepo:{root:t,packages:o.length,apps:a.length,preset:l},statistics:{totalWorkspaces:o.length+a.length,packageCount:o.length,appCount:a.length}};e.dryRun||(s.success(`Found ${u.statistics.totalWorkspaces} workspaces`),s.info(`Packages: ${u.statistics.packageCount}, Apps: ${u.statistics.appCount}`),s.info(`Preset: ${l}`)),ke(u,e.format,"stats")}async function ii(e){s.info("Analyzing bundle and dependency sizes...");let t=await A({command:"pnpm",args:["size"],interactive:!1,label:"Analyze package sizes",dryRun:e.dryRun}),n={analysis:"pnpm size",exitCode:t.exitCode,...t.stdout&&{stdout:t.stdout},...t.stderr&&{stderr:t.stderr}};t.exitCode!==0&&s.warn("Size analysis failed. Ensure your project is built."),ke(n,e.format,"stats:size")}async function ci(e){s.info("Analyzing dependencies...");let t=await A({command:"npx",args:["knip","--no-progress"],interactive:!1,label:"Analyze dependencies",dryRun:e.dryRun}),n={analysis:"knip (unused dependencies)",exitCode:t.exitCode,command:"npx knip",...t.stdout&&{stdout:t.stdout.substring(0,500)}};e.dryRun||(t.exitCode===0?s.success("No unused dependencies detected"):s.info("Run 'npx knip' to see detailed dependency analysis")),ke(n,e.format,"stats:deps")}async function li(e){s.info("Listing packages...");let t=R(),n=L(t,"packages"),r=[];try{B(n)&&(r=qe(n).filter(i=>!i.startsWith(".")&&B(L(n,i,"package.json"))).map(i=>{let l=L(n,i),u=zn(l);return{name:u.name||i,version:u.version,description:u.description,files:Bn(l)}}))}catch(a){s.error(`Failed to list packages: ${a instanceof Error?a.message:String(a)}`),process.exit(c.ERROR)}let o={packages:r,total:r.length};e.dryRun||e.format==="json"?ke(o,e.format,"stats:packages"):(console.log(`
757
- ${Pe.cyan("Packages")} (${r.length} total)
758
- `),r.forEach(a=>{console.log(` ${Pe.blue(a.name)}`),a.version&&console.log(` version: ${a.version}`),a.description&&console.log(` ${a.description}`),console.log(` files: ${a.files}`)}),console.log(""))}async function di(e){s.info("Listing apps...");let t=R(),n=L(t,"apps"),r=[];try{B(n)&&(r=qe(n).filter(i=>!i.startsWith(".")&&B(L(n,i,"package.json"))).map(i=>{let l=L(n,i),u=zn(l),p=B(L(l,"next.config.ts"))||B(L(l,"next.config.js")),y=B(L(l,"server.ts"))||B(L(l,"server.js"));return{name:u.name||i,version:u.version,description:u.description,files:Bn(l),status:p||y?"ready":"unknown"}}))}catch(a){s.error(`Failed to list apps: ${a instanceof Error?a.message:String(a)}`),process.exit(c.ERROR)}let o={apps:r,total:r.length,ready:r.filter(a=>a.status==="ready").length};e.dryRun||e.format==="json"?ke(o,e.format,"stats:apps"):(console.log(`
759
- ${Pe.cyan("Apps")} (${r.length} total, ${o.ready} ready)
760
- `),r.forEach(a=>{let i=a.status==="ready"?Pe.green("\u2713"):Pe.gray("\u25CB");console.log(` ${i} ${Pe.blue(a.name)}`),a.version&&console.log(` version: ${a.version}`),a.description&&console.log(` ${a.description}`),console.log(` files: ${a.files}`)}),console.log(""))}function Yn(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=n.optsWithGlobals?.()||n;await ai({format:n.format||r.format})}),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 ii({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 ci({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 li({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 di({format:n.format||r.format})})}import*as F from"@clack/prompts";import I from"picocolors";var Nt=["landing-page","web","storybook","api-gateway","design-docs","studio","docs","ui","tokens","brand","theme","icons","preset","queue","search","notifications","permissions","webhooks","metering","uploads","vault","tenant"];function ui(e){let t=`@nebutra/${e}`;if(!Nt.includes(e)){let n=I.yellow(`Valid apps: ${Nt.join(", ")}`);throw new Error(`Invalid app: ${I.red(e)}
761
- ${n}`)}return t}async function mi(e){if(e.dryRun){let 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"};process.stdout.write(JSON.stringify(t,null,2)+`
762
- `),process.exit(c.DRY_RUN_OK)}try{if(e.app&&(e.watch||e.coverage)&&(F.log.error(I.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(c.INVALID_ARGS)),e.app){ui(e.app);let r=`@nebutra/${e.app}`;e.quiet||F.log.info(I.cyan(`Running tests for ${I.bold(r)}...`));let o=await pe("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...";F.log.info(I.cyan(r))}let n=await _(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?F.log.error(I.red(t.message)):F.log.error(I.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Hn(e){if(e.dryRun){let 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"};process.stdout.write(JSON.stringify(t,null,2)+`
763
- `),process.exit(c.DRY_RUN_OK)}try{(e.ui&&e.ci||e.ui&&e.ci)&&(F.log.error(I.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...";F.log.info(I.cyan(r))}let n=await _(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?F.log.error(I.red(t.message)):F.log.error(I.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Jn(e){if(e.dryRun){let t={mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"};process.stdout.write(JSON.stringify(t,null,2)+`
764
- `),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...";F.log.info(I.cyan(r))}let n=await _(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?F.log.error(I.red(t.message)):F.log.error(I.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Qn(e){if(e.dryRun){let t={mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"};process.stdout.write(JSON.stringify(t,null,2)+`
765
- `),process.exit(c.DRY_RUN_OK)}try{e.quiet||F.log.info(I.cyan("Running architecture tests..."));let t=await _("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?F.log.error(I.red(t.message)):F.log.error(I.red("Unknown error occurred")),process.exit(c.ERROR)}}function Xn(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: ${Nt.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;n==="e2e"?await Hn({ui:r.ui||!1,ci:r.ci||!1,dryRun:r.dryRun||!1,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format}):n==="size"?await Jn({why:r.why||!1,dryRun:r.dryRun||!1,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format}):n==="arch"?await Qn({dryRun:r.dryRun||!1,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format}):await mi({...r,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format})});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=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Hn({...n,quiet:r.quiet||!1,verbose:r.verbose||!1,format:r.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=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Jn({...n,quiet:r.quiet||!1,verbose:r.verbose||!1,format:r.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=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Qn({dryRun:n.dryRun||!1,quiet:r.quiet||!1,verbose:r.verbose||!1,format:r.format})})}import{promises as pt}from"fs";import{homedir as pi}from"os";import{join as er}from"path";import be from"picocolors";var fi=1440*60*1e3,tr=er(pi(),".nebutra"),Tt=er(tr,"update-check.json"),gi="https://registry.npmjs.org/nebutra";async function yi(){try{await pt.mkdir(tr,{recursive:!0})}catch{}}async function hi(){try{let e=await pt.readFile(Tt,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<fi?t:(await pt.unlink(Tt).catch(r=>{s.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function bi(e){try{await yi();let t={timestamp:Date.now(),latestVersion:e};await pt.writeFile(Tt,JSON.stringify(t,null,2),"utf-8")}catch{}}async function vi(){try{let e=new AbortController,t=setTimeout(()=>e.abort(),5e3),n=await fetch(gi,{signal:e.signal,headers:{Accept:"application/json"}});if(clearTimeout(t),!n.ok)return null;let o=(await n.json())["dist-tags"];return!o||typeof o.latest!="string"?null:o.latest}catch{return null}}function Zn(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function wi(e,t){let n=Zn(e),r=Zn(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 Ri(e){let t=await hi(),n=null;return t?n=t.latestVersion:(n=await vi(),n&&await bi(n)),!n||!wi(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function Si(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=[be.cyan("\u256D"+"\u2500".repeat(41)+"\u256E"),be.cyan("\u2502")+be.yellow(o+n+o)+be.cyan("\u2502"),be.cyan("\u2502")+be.gray(a+r+a)+be.cyan("\u2502"),be.cyan("\u2570"+"\u2500".repeat(41)+"\u256F")]}async function nr(e){let t=null;return Ri(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&Si(t))}}var rr="0.1.0";async function Ei(){let e=await nr(rr),t=new Ci,n=process.stdin.isTTY!==!1&&process.stdout.isTTY!==!1;t.name("nebutra").description("Nebutra \u2014 governance-first CLI for topology scaffolding, registry features, and platform operations").version(rr).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(async r=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await $n({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 Bt(r,{...o,yes:a.yes||!n})}),mn(t),In(t),Fn(t),rn(t),On(t),xn(t),bn(t),Pn(t),Zt(t),en(t),tn(t),Yn(t),pn(t),En(t),Tn(t),fn(t),Xn(t),Yt(t),on(t),kn(t),yn(t),Vn(t),Gn(t),Kn(t),un(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(async()=>{let{logger:r}=await import("./logger-LKYUI2MJ.js"),{findMonorepoRoot:o}=await import("./delegate-AT4FVWBK.js"),a=await import("fs"),i=await import("path");r.info("Running project health check...");let l=!1,u=o(),p=process.version;parseInt(p.replace("v","").split(".")[0],10)<22?(r.error(`Node.js >= 22 required, found ${p}`),l=!0):r.success(`Node.js version OK (${p})`),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."),l?(r.error("Doctor found critical issues that require your attention."),process.exit(1)):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",`
843
+ `)}import{existsSync as J,readdirSync as ze,readFileSync as Ar}from"fs";import{resolve as G}from"path";import Ue from"picocolors";function _e(e,t,n){if(t==="json"){let r={command:n||"stats",...e};console.log(JSON.stringify(r,null,2))}else e.stdout&&(console.log(e.stdout),delete e.stdout),Object.keys(e).length>0&&console.log(JSON.stringify(e,null,2))}function $r(e){try{let t=Ar(G(e,"package.json"),"utf-8");return JSON.parse(t)}catch{return{}}}function Pr(e){try{return ze(e,{recursive:!0}).length}catch{return 0}}async function Gc(e){s.info("Gathering monorepo statistics...");let t=h(),n=G(t,"packages"),r=G(t,"apps"),o=[],a=[],i=0,l="unknown";try{J(n)&&(o=ze(n).filter(g=>!g.startsWith(".")&&J(G(n,g,"package.json")))),J(r)&&(a=ze(r).filter(g=>!g.startsWith(".")&&J(G(r,g,"package.json"))));let m=G(t,"nebutra.config.ts");if(J(m)){let p=Ar(m,"utf-8").match(/preset:\s*["']([^"']+)["']/);p&&(l=p[1])}}catch(m){s.warn(`Failed to read monorepo structure: ${m instanceof Error?m.message:String(m)}`)}let u={monorepo:{root:t,packages:o.length,apps:a.length,preset:l},statistics:{totalWorkspaces:o.length+a.length,packageCount:o.length,appCount:a.length}};e.dryRun||(s.success(`Found ${u.statistics.totalWorkspaces} workspaces`),s.info(`Packages: ${u.statistics.packageCount}, Apps: ${u.statistics.appCount}`),s.info(`Preset: ${l}`)),_e(u,e.format,"stats")}async function Vc(e){s.info("Analyzing bundle and dependency sizes...");let t=await $({command:"pnpm",args:["size"],interactive:!1,label:"Analyze package sizes",dryRun:e.dryRun}),n={analysis:"pnpm size",exitCode:t.exitCode,...t.stdout&&{stdout:t.stdout},...t.stderr&&{stderr:t.stderr}};t.exitCode!==0&&s.warn("Size analysis failed. Ensure your project is built."),_e(n,e.format,"stats:size")}async function Kc(e){s.info("Analyzing dependencies...");let t=await $({command:"npx",args:["knip","--no-progress"],interactive:!1,label:"Analyze dependencies",dryRun:e.dryRun}),n={analysis:"knip (unused dependencies)",exitCode:t.exitCode,command:"npx knip",...t.stdout&&{stdout:t.stdout.substring(0,500)}};e.dryRun||(t.exitCode===0?s.success("No unused dependencies detected"):s.info("Run 'npx knip' to see detailed dependency analysis")),_e(n,e.format,"stats:deps")}async function Bc(e){s.info("Listing packages...");let t=h(),n=G(t,"packages"),r=[];try{J(n)&&(r=ze(n).filter(i=>!i.startsWith(".")&&J(G(n,i,"package.json"))).map(i=>{let l=G(n,i),u=$r(l);return{name:u.name||i,version:u.version,description:u.description,files:Pr(l)}}))}catch(a){s.error(`Failed to list packages: ${a instanceof Error?a.message:String(a)}`),process.exit(c.ERROR)}let o={packages:r,total:r.length};e.dryRun||e.format==="json"?_e(o,e.format,"stats:packages"):(console.log(`
844
+ ${Ue.cyan("Packages")} (${r.length} total)
845
+ `),r.forEach(a=>{console.log(` ${Ue.blue(a.name)}`),a.version&&console.log(` version: ${a.version}`),a.description&&console.log(` ${a.description}`),console.log(` files: ${a.files}`)}),console.log(""))}async function qc(e){s.info("Listing apps...");let t=h(),n=G(t,"apps"),r=[];try{J(n)&&(r=ze(n).filter(i=>!i.startsWith(".")&&J(G(n,i,"package.json"))).map(i=>{let l=G(n,i),u=$r(l),m=J(G(l,"next.config.ts"))||J(G(l,"next.config.js")),g=J(G(l,"server.ts"))||J(G(l,"server.js"));return{name:u.name||i,version:u.version,description:u.description,files:Pr(l),status:m||g?"ready":"unknown"}}))}catch(a){s.error(`Failed to list apps: ${a instanceof Error?a.message:String(a)}`),process.exit(c.ERROR)}let o={apps:r,total:r.length,ready:r.filter(a=>a.status==="ready").length};e.dryRun||e.format==="json"?_e(o,e.format,"stats:apps"):(console.log(`
846
+ ${Ue.cyan("Apps")} (${r.length} total, ${o.ready} ready)
847
+ `),r.forEach(a=>{let i=a.status==="ready"?Ue.green("\u2713"):Ue.gray("\u25CB");console.log(` ${i} ${Ue.blue(a.name)}`),a.version&&console.log(` version: ${a.version}`),a.description&&console.log(` ${a.description}`),console.log(` files: ${a.files}`)}),console.log(""))}function Nr(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=n.optsWithGlobals?.()||n;await Gc({format:n.format||r.format})}),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 Vc({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 Kc({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 Bc({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 qc({format:n.format||r.format})})}import*as V from"@clack/prompts";import U from"picocolors";var Yt=["landing-page","web","storybook","api-gateway","design-docs","studio","docs","ui","tokens","brand","theme","icons","preset","queue","search","notifications","permissions","webhooks","metering","uploads","vault","tenant"];function Wc(e){let t=`@nebutra/${e}`;if(!Yt.includes(e)){let n=U.yellow(`Valid apps: ${Yt.join(", ")}`);throw new Error(`Invalid app: ${U.red(e)}
848
+ ${n}`)}return t}async function Yc(e){e.dryRun&&(x({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:e.format}),process.exit(c.DRY_RUN_OK));try{if(e.app&&(e.watch||e.coverage)&&(V.log.error(U.red("Cannot use --watch or --coverage with --app filter (app-level tests use turbo)")),process.exit(c.INVALID_ARGS)),e.app){Wc(e.app);let r=`@nebutra/${e.app}`;e.quiet||V.log.info(U.cyan(`Running tests for ${U.bold(r)}...`));let o=await ge("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...";V.log.info(U.cyan(r))}let n=await I(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?V.log.error(U.red(t.message)):V.log.error(U.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Ir(e){e.dryRun&&(x({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:e.format}),process.exit(c.DRY_RUN_OK));try{(e.ui&&e.ci||e.ui&&e.ci)&&(V.log.error(U.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...";V.log.info(U.cyan(r))}let n=await I(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?V.log.error(U.red(t.message)):V.log.error(U.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Tr(e){e.dryRun&&(x({mode:"dry-run",timestamp:new Date().toISOString(),command:"test size",options:{why:e.why},task:e.why?"pnpm size:why":"pnpm size"},{format: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...";V.log.info(U.cyan(r))}let n=await I(t,{interactive:!0});process.exit(n.exitCode)}catch(t){t instanceof Error?V.log.error(U.red(t.message)):V.log.error(U.red("Unknown error occurred")),process.exit(c.ERROR)}}async function Ur(e){e.dryRun&&(x({mode:"dry-run",timestamp:new Date().toISOString(),command:"test arch",task:"pnpm test:arch"},{format:e.format}),process.exit(c.DRY_RUN_OK));try{e.quiet||V.log.info(U.cyan("Running architecture tests..."));let t=await I("test:arch",{interactive:!0});process.exit(t.exitCode)}catch(t){t instanceof Error?V.log.error(U.red(t.message)):V.log.error(U.red("Unknown error occurred")),process.exit(c.ERROR)}}function jr(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: ${Yt.join(", ")}`).option("--dry-run","Preview what would run (exit code 10)").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;n==="e2e"?await Ir({ui:r.ui||!1,ci:r.ci||!1,dryRun:r.dryRun||!1,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format}):n==="size"?await Tr({why:r.why||!1,dryRun:r.dryRun||!1,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format}):n==="arch"?await Ur({dryRun:r.dryRun||!1,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format}):await Yc({...r,quiet:o.quiet||!1,verbose:o.verbose||!1,format:o.format})});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=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Ir({...n,quiet:r.quiet||!1,verbose:r.verbose||!1,format:r.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=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Tr({...n,quiet:r.quiet||!1,verbose:r.verbose||!1,format:r.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=>{let r=n.optsWithGlobals?n.optsWithGlobals():n;await Ur({dryRun:n.dryRun||!1,quiet:r.quiet||!1,verbose:r.verbose||!1,format:r.format})})}import{getThemeById as Hc,THEME_REGISTRY as kt}from"@nebutra/theme/registry";function Lr(e){let t=e.opts?e.opts():e,n=e.optsWithGlobals?e.optsWithGlobals():e;return t.format??n.format??zc()}function zc(){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 Jc(e){return{id:e.id,name:e.name,category:e.category,mood:e.mood,tokenPath:e.tokenPath,installCommand:e.install.command,registryUrl:e.install.registryUrl,wcag:e.governance.wcag,visualSuites:e.governance.visualSuites}}function Xc(e="table"){let t=kt.themes.map(Jc);return e==="json"?JSON.stringify({version:kt.version,defaultTheme:kt.defaultTheme,count:t.length,themes:t},null,2):[`Nebutra themes (${t.length})`,`Default: ${kt.defaultTheme}`,"",...t.map(r=>`${r.id.padEnd(12)} ${r.category.padEnd(14)} ${r.tokenPath.padEnd(34)} ${r.mood}`)].join(`
849
+ `)}function Qc(e,t="table"){let n=Hc(e);if(n)return t==="json"?JSON.stringify(n,null,2):[`${n.name} (${n.id})`,`Category: ${n.category}`,`Mood: ${n.mood}`,`Token path: ${n.tokenPath}`,`Install: ${n.install.command}`,`Registry: ${n.install.registryUrl}`,`WCAG: ${n.governance.wcag}`,`Visual suites: ${n.governance.visualSuites.join(", ")}`,`Required tokens: ${n.governance.requiredTokens.join(", ")}`].join(`
850
+ `)}function Dr(e){let t=e.command("theme").description("Inspect registry-backed Nebutra themes and governance metadata");t.command("list").description("List built-in themes from the shared theme registry").option("--format <type>","Output format: json or table").action(n=>{console.log(Xc(Lr(n)))}),t.command("inspect <id>").description("Show governance metadata for one theme").option("--format <type>","Output format: json or table").action((n,r)=>{let o=Qc(n,Lr(r));o||(s.error(`Theme '${n}' was not found in the Nebutra theme registry.`),process.exit(c.NOT_FOUND)),console.log(o)})}import{existsSync as Fr,readFileSync as Zc,unlinkSync as el,writeFileSync as tl}from"fs";import{dirname as nl,join as Mr,parse as rl}from"path";function ol(e){let t=e,{root:n}=rl(t);for(;;){if(Fr(Mr(t,"package.json")))return t;if(t===n)return null;let r=nl(t);if(r===t)return null;t=r}}async function sl(e){let t=e.format==="json",n=ol(process.cwd())??process.cwd(),r=Mr(n,"nebutra.config.json");if(Fr(r)||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):s.info("Already unlinked"),process.exit(c.SUCCESS)),e.force){try{el(r)}catch(l){let u=l instanceof Error?l.message:String(l);t?console.log(JSON.stringify({command:"unlink",success:!1,error:u},null,2)):s.error(`Failed to delete config: ${u}`),process.exit(c.PERMISSION_DENIED)}t?console.log(JSON.stringify({command:"unlink",success:!0,deletedConfig:!0,configPath:r},null,2)):s.success("Removed nebutra.config.json");return}let o={};try{o=JSON.parse(Zc(r,"utf-8"))}catch{o={}}"projectId"in o||(t?console.log(JSON.stringify({command:"unlink",success:!0,alreadyUnlinked:!0},null,2)):s.info("Already unlinked"),process.exit(c.SUCCESS));let{projectId:a,...i}=o;tl(r,JSON.stringify(i,null,2)+`
851
+ `),t?console.log(JSON.stringify({command:"unlink",success:!0,configPath:r},null,2)):s.success("Unlinked from project")}function Gr(e){e.command("unlink").description("Remove the project link from nebutra.config.json").option("--force","Delete the entire nebutra.config.json").option("--format <type>","Output format: json or plain").action(async(t,n)=>{let r=n?.optsWithGlobals?.()||t;await sl({force:t.force||!1,format:t.format||r.format})})}import{spawnSync as gl}from"child_process";import{promises as Ot}from"fs";import{homedir as al}from"os";import{join as Kr}from"path";import Se from"picocolors";var il=1440*60*1e3,Br=Kr(al(),".nebutra"),Ht=Kr(Br,"update-check.json"),cl="https://registry.npmjs.org/nebutra";async function ll(){try{await Ot.mkdir(Br,{recursive:!0})}catch{}}async function dl(){try{let e=await Ot.readFile(Ht,"utf-8"),t=JSON.parse(e);return Date.now()-t.timestamp<il?t:(await Ot.unlink(Ht).catch(r=>{s.debug("Failed to remove expired update cache file",{error:r})}),null)}catch{return null}}async function ul(e){try{await ll();let t={timestamp:Date.now(),latestVersion:e};await Ot.writeFile(Ht,JSON.stringify(t,null,2),"utf-8")}catch{}}async function ml(){try{let e=new AbortController,t=setTimeout(()=>e.abort(),5e3),n=await fetch(cl,{signal:e.signal,headers:{Accept:"application/json"}});if(clearTimeout(t),!n.ok)return null;let o=(await n.json())["dist-tags"];return!o||typeof o.latest!="string"?null:o.latest}catch{return null}}function Vr(e){return e.split(".").map(t=>parseInt(t.replace(/[^0-9]/g,""),10)||0).slice(0,3)}function pl(e,t){let n=Vr(e),r=Vr(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 zt(e){let t=await dl(),n=null;return t?n=t.latestVersion:(n=await ml(),n&&await ul(n)),!n||!pl(e,n)?null:{currentVersion:e,latestVersion:n,isUpdate:!0}}function fl(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 qr(e){let t=null;return zt(e).then(n=>{t=n}),async()=>{!process.stdout.isTTY||process.env.CI||(t||await new Promise(n=>setTimeout(n,100)),t&&fl(t))}}function yl(){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 hl(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 Ae="0.1.0";async function bl(e){let t=yl(),n=hl(t),r=e.format==="json",o=await zt(Ae),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:Ae,latestVersion:a,hasUpdate:i},null,2)):(s.info(`Detected installer: ${t}`),s.info(`Current: ${Ae}${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:Ae},null,2)):s.success(`Already on the latest version (${Ae})`),process.exit(c.SUCCESS)),e.yes||(r?console.log(JSON.stringify({command:"upgrade",success:!0,installer:t,command_to_run:n,currentVersion:Ae,latestVersion:a,requiresConfirmation:!0},null,2)):(s.info(`Current: ${Ae}${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=gl(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 g=m.stderr?.toString()||`Upgrade failed (exit ${m.status})`;r?console.log(JSON.stringify({command:"upgrade",success:!1,installer:t,ran:n,error:g},null,2)):s.error(g),process.exit(c.ERROR)}function Wr(e){let t=(n,r)=>{let o=r?.optsWithGlobals?.()||n;return bl({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 Jt from"fs";import Xt from"path";import vl from"picocolors";var Qt=["inngest","n8n","pusher"],wl=`import { Inngest } from "inngest";
852
+
853
+ export const inngest = new Inngest({ id: "nebutra-sailor" });
854
+
855
+ export const exampleFn = inngest.createFunction(
856
+ { id: "example-fn" },
857
+ { event: "app/example.requested" },
858
+ async ({ event, step }) => {
859
+ await step.run("do-work", async () => {
860
+ return { ok: true, payload: event.data };
861
+ });
862
+ return { status: "completed" };
863
+ },
864
+ );
865
+ `,Sl=`# n8n Workflows (Self-hosted Convention)
866
+
867
+ Nebutra Sailor uses n8n in self-hosted mode for visual workflow orchestration.
868
+
869
+ ## Convention
870
+
871
+ - Each workflow is exported as a JSON file in this directory: \`workflows/n8n/*.json\`
872
+ - File naming: \`<domain>.<verb>.json\` (e.g. \`billing.invoice-paid.json\`)
873
+ - Credentials live in n8n's encrypted store \u2014 never inline secrets in the JSON
874
+ - Import via n8n UI: Settings \u2192 Workflows \u2192 Import from File
875
+
876
+ ## Running n8n locally
877
+
878
+ \`\`\`bash
879
+ docker run -it --rm \\
880
+ --name n8n \\
881
+ -p 5678:5678 \\
882
+ -v ~/.n8n:/home/node/.n8n \\
883
+ n8nio/n8n
884
+ \`\`\`
885
+
886
+ ## Webhook endpoints
887
+
888
+ Production webhooks route through \`backends/gateway\` (see \`packages/integrations/webhooks\`).
889
+ `,Rl=`{
890
+ "name": "example-workflow",
891
+ "nodes": [
892
+ {
893
+ "parameters": {},
894
+ "name": "Start",
895
+ "type": "n8n-nodes-base.start",
896
+ "typeVersion": 1,
897
+ "position": [240, 300]
898
+ }
899
+ ],
900
+ "connections": {},
901
+ "active": false,
902
+ "settings": {},
903
+ "tags": []
904
+ }
905
+ `,El=`import Pusher from "pusher";
906
+
907
+ export const pusher = new Pusher({
908
+ appId: process.env.PUSHER_APP_ID ?? "",
909
+ key: process.env.PUSHER_KEY ?? "",
910
+ secret: process.env.PUSHER_SECRET ?? "",
911
+ cluster: process.env.PUSHER_CLUSTER ?? "us2",
912
+ useTLS: true,
913
+ });
914
+
915
+ export async function publishExample(channel: string, event: string, data: unknown) {
916
+ if (!process.env.PUSHER_APP_ID) {
917
+ throw new Error("PUSHER_APP_ID not configured");
918
+ }
919
+ return pusher.trigger(channel, event, data);
920
+ }
921
+ `;function Cl(e){switch(e){case"inngest":return[{relPath:"workflows/inngest/example.ts",content:wl}];case"n8n":return[{relPath:"workflows/n8n/README.md",content:Sl},{relPath:"workflows/n8n/example.json",content:Rl}];case"pusher":return[{relPath:"workflows/pusher/example.ts",content:El}]}}async function kl(e,t={}){Qt.includes(e)||(s.error(`Invalid provider: ${vl.red(e)}. Valid: ${Qt.join(", ")}`),process.exit(c.INVALID_ARGS));let n=h(),r=Cl(e);t.dryRun&&(x({mode:"dry-run",command:`workflow init ${e}`,files:r.map(i=>({path:Xt.join(n,i.relPath)}))}),process.exit(c.DRY_RUN_OK));let o=0,a=0;for(let i of r){let l=Xt.join(n,i.relPath);if(Jt.existsSync(l)){s.warn(`Skipping ${i.relPath} \u2014 already exists.`),a++;continue}Jt.mkdirSync(Xt.dirname(l),{recursive:!0}),Jt.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)}function Yr(e){e.command("workflow").description("Manage workflow provider scaffolding (inngest | n8n | pusher)").command("init <provider>").description(`Scaffold a starter workflow file for a provider (${Qt.join(" | ")})`).option("--dry-run","Preview files that would be created (exit code 10)").action(async(n,r)=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await kl(n,{dryRun:r.dryRun||!1,quiet:o.quiet||!1})})}import{existsSync as Ol,mkdirSync as Hr,writeFileSync as zr}from"fs";import{homedir as Jr,platform as xl}from"os";import{join as Je}from"path";function _l(){if(xl()==="win32"){let t=process.env.LOCALAPPDATA||Je(Jr(),"AppData","Local");return Je(t,"nebutra")}let e=process.env.XDG_CONFIG_HOME;return e?Je(e,"nebutra"):Je(Jr(),".config","nebutra")}function Al(){let e=process.env.NEBUTRA_TELEMETRY;return e==="0"||e==="false"||e==="no"}function Xr(){if(!process.stderr.isTTY||!process.stdin.isTTY||process.env.CI)return;let e=_l(),t=Je(e,"first-run-acked");try{if(Ol(t))return}catch{return}if(Al()){try{Hr(e,{recursive:!0}),zr(t,"")}catch{}return}let n=["\x1B[36m\u2139\x1B[0m Nebutra collects anonymous usage analytics to improve the CLI."," Opt out at any time: export NEBUTRA_TELEMETRY=0"," Privacy policy: https://nebutra.com/legal/cli-analytics",""];try{process.stderr.write(n.join(`
922
+ `))}catch{}try{Hr(e,{recursive:!0}),zr(t,"")}catch{}}var Qr="0.1.0";async function Pl(){Xr();let e=await qr(Qr),t=new $l,n=process.stdin.isTTY!==!1&&process.stdout.isTTY!==!1;t.name("nebutra").description("Nebutra \u2014 governance-first CLI for topology scaffolding, registry features, and platform operations").version(Qr).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(async r=>{let o=r.optsWithGlobals?r.optsWithGlobals():r;await sr({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 gn(r,{...o,yes:a.yes||!n})}),Mn(t),yr(t),Er(t),Nn(t),rr(t),or(t),zn(t),lr(t),Cn(t),kn(t),$n(t),Nr(t),Gn(t),tr(t),br(t),Vn(t),jr(t),Yr(t),An(t),qn(t),Dr(t),vn(t),In(t),nr(t),Yn(t),_r(t),kr(t),Or(t),Fn(t),gr(t),Wr(t),mr(t),Gr(t),t.command("doctor").description("Check your Nebutra project setup for common issues").action(async()=>{let{logger:r}=await import("./logger-KLED6BEE.js"),{findMonorepoRoot:o}=await import("./delegate-YL6SAZNF.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."),l?(r.error("Doctor found critical issues that require your attention."),process.exit(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",`
766
923
  Examples:
767
924
  $ nebutra init Initialize a new project
768
925
  $ nebutra add cache --provider upstash-redis --yes Install a registry feature
@@ -771,11 +928,15 @@ Examples:
771
928
  $ nebutra db migrate Run pending database migrations
772
929
  $ nebutra generate app blog Scaffold a new app
773
930
  $ nebutra brand palette --primary=#0047FF Generate token-aligned blue palette
931
+ $ nebutra theme list --format json List registry-backed themes
932
+ $ nebutra theme inspect neon Inspect a theme governance manifest
774
933
  $ nebutra preset list --format json List available presets
775
934
  $ nebutra infra up --lite Start PostgreSQL + Redis
776
935
  $ nebutra test e2e Run Playwright E2E tests
777
936
  $ nebutra stats Monorepo overview
778
937
  $ nebutra schema --all Full CLI schema (for Agents)
938
+ $ nebutra license verify Verify the scaffold-meta HMAC signature
939
+ $ nebutra license verify --format json Same, in JSON for Agents
779
940
 
780
941
  Platform & Ecosystem:
781
942
  $ nebutra admin tenants List all tenants
@@ -793,14 +954,17 @@ Examples:
793
954
  $ nebutra secrets list --tenant org_123 List encrypted secrets
794
955
 
795
956
  Exit Codes:
796
- 0 Success 2 Invalid arguments
797
- 1 General error 3 Resource not found
798
- 4 Permission denied 5 Conflict/exists
799
- 6 Network error (retryable) 10 Dry-run OK
957
+ 0 Success 2 Invalid arguments
958
+ 1 General error 3 Resource not found
959
+ 4 Permission denied 5 Conflict/exists
960
+ 6 Network error (retryable) 7 Timeout (retryable)
961
+ 8 Cancelled by user 9 Config error
962
+ 10 Dry-run OK 11 Incompatible
963
+ 12 Resource exhausted
800
964
 
801
965
  Environment:
802
966
  NEBUTRA_LOG_LEVEL Log level (debug|info|warn|error)
803
967
  NEBUTRA_OUTPUT_FORMAT Output format (json|table|plain)
804
968
  NO_COLOR Disable colored output
805
969
  CI Auto-enable non-interactive mode
806
- `),process.argv.length<=2&&(t.outputHelp(),process.exit(0)),await t.parseAsync(process.argv),await e()}Ei().catch(e=>s.error(e instanceof Error?e.message:String(e)));
970
+ `),process.argv.length<=2&&(t.outputHelp(),process.exit(c.SUCCESS)),await t.parseAsync(process.argv),await e()}Pl().catch(e=>s.error(e instanceof Error?e.message:String(e)));